workspace.ts

  1import { ColorScheme } from "../theme/colorScheme"
  2import { withOpacity } from "../theme/color"
  3import { toggleable } from "../element"
  4import {
  5  background,
  6  border,
  7  borderColor,
  8  foreground,
  9  svg,
 10  text,
 11} from "./components"
 12import statusBar from "./statusBar"
 13import tabBar from "./tabBar"
 14import { interactive } from "../element"
 15import merge from "ts-deepmerge"
 16export default function workspace(colorScheme: ColorScheme) {
 17  const layer = colorScheme.lowest
 18  const isLight = colorScheme.isLight
 19  const itemSpacing = 8
 20  const titlebarButton = toggleable({
 21    base:
 22      interactive({
 23        base: {
 24          cornerRadius: 6,
 25          padding: {
 26            top: 1,
 27            bottom: 1,
 28            left: 8,
 29            right: 8,
 30          },
 31          ...text(layer, "sans", "variant", { size: "xs" }),
 32          background: background(layer, "variant"),
 33          border: border(layer),
 34        },
 35        state: {
 36          hovered: {
 37            ...text(layer, "sans", "variant", "hovered", {
 38              size: "xs",
 39            }),
 40            background: background(layer, "variant", "hovered"),
 41            border: border(layer, "variant", "hovered"),
 42          },
 43          clicked: {
 44            ...text(layer, "sans", "variant", "pressed", {
 45              size: "xs",
 46            }),
 47            background: background(layer, "variant", "pressed"),
 48            border: border(layer, "variant", "pressed"),
 49          },
 50        },
 51      }),
 52    state: {
 53      active: {
 54        default: {
 55          ...text(layer, "sans", "variant", "active", { size: "xs" }),
 56          background: background(layer, "variant", "active"),
 57          border: border(layer, "variant", "active"),
 58        },
 59      }
 60    }
 61  }
 62  )
 63  const avatarWidth = 18
 64  const avatarOuterWidth = avatarWidth + 4
 65  const followerAvatarWidth = 14
 66  const followerAvatarOuterWidth = followerAvatarWidth + 4
 67
 68  return {
 69    background: background(colorScheme.lowest),
 70    blankPane: {
 71      logoContainer: {
 72        width: 256,
 73        height: 256,
 74      },
 75      logo: svg(
 76        withOpacity("#000000", colorScheme.isLight ? 0.6 : 0.8),
 77        "icons/logo_96.svg",
 78        256,
 79        256
 80      ),
 81
 82      logoShadow: svg(
 83        withOpacity(
 84          colorScheme.isLight
 85            ? "#FFFFFF"
 86            : colorScheme.lowest.base.default.background,
 87          colorScheme.isLight ? 1 : 0.6
 88        ),
 89        "icons/logo_96.svg",
 90        256,
 91        256
 92      ),
 93      keyboardHints: {
 94        margin: {
 95          top: 96,
 96        },
 97        cornerRadius: 4,
 98      },
 99      keyboardHint: interactive({
100        base: {
101          ...text(layer, "sans", "variant", { size: "sm" }),
102          padding: {
103            top: 3,
104            left: 8,
105            right: 8,
106            bottom: 3,
107          },
108          cornerRadius: 8,
109        },
110        state: {
111          hovered: {
112            ...text(layer, "sans", "active", { size: "sm" }),
113          },
114        },
115      }),
116
117      keyboardHintWidth: 320,
118    },
119    joiningProjectAvatar: {
120      cornerRadius: 40,
121      width: 80,
122    },
123    joiningProjectMessage: {
124      padding: 12,
125      ...text(layer, "sans", { size: "lg" }),
126    },
127    externalLocationMessage: {
128      background: background(colorScheme.middle, "accent"),
129      border: border(colorScheme.middle, "accent"),
130      cornerRadius: 6,
131      padding: 12,
132      margin: { bottom: 8, right: 8 },
133      ...text(colorScheme.middle, "sans", "accent", { size: "xs" }),
134    },
135    leaderBorderOpacity: 0.7,
136    leaderBorderWidth: 2.0,
137    tabBar: tabBar(colorScheme),
138    modal: {
139      margin: {
140        bottom: 52,
141        top: 52,
142      },
143      cursor: "Arrow",
144    },
145    zoomedBackground: {
146      cursor: "Arrow",
147      background: isLight
148        ? withOpacity(background(colorScheme.lowest), 0.8)
149        : withOpacity(background(colorScheme.highest), 0.6),
150    },
151    zoomedPaneForeground: {
152      margin: 16,
153      shadow: colorScheme.modalShadow,
154      border: border(colorScheme.lowest, { overlay: true }),
155    },
156    zoomedPanelForeground: {
157      margin: 16,
158      border: border(colorScheme.lowest, { overlay: true }),
159    },
160    dock: {
161      left: {
162        border: border(layer, { right: true }),
163      },
164      bottom: {
165        border: border(layer, { top: true }),
166      },
167      right: {
168        border: border(layer, { left: true }),
169      },
170    },
171    paneDivider: {
172      color: borderColor(layer),
173      width: 1,
174    },
175    statusBar: statusBar(colorScheme),
176    titlebar: {
177      itemSpacing,
178      facePileSpacing: 2,
179      height: 33, // 32px + 1px border. It's important the content area of the titlebar is evenly sized to vertically center avatar images.
180      background: background(layer),
181      border: border(layer, { bottom: true }),
182      padding: {
183        left: 80,
184        right: itemSpacing,
185      },
186
187      // Project
188      title: text(layer, "sans", "variant"),
189      highlight_color: text(layer, "sans", "active").color,
190
191      // Collaborators
192      leaderAvatar: {
193        width: avatarWidth,
194        outerWidth: avatarOuterWidth,
195        cornerRadius: avatarWidth / 2,
196        outerCornerRadius: avatarOuterWidth / 2,
197      },
198      followerAvatar: {
199        width: followerAvatarWidth,
200        outerWidth: followerAvatarOuterWidth,
201        cornerRadius: followerAvatarWidth / 2,
202        outerCornerRadius: followerAvatarOuterWidth / 2,
203      },
204      inactiveAvatarGrayscale: true,
205      followerAvatarOverlap: 8,
206      leaderSelection: {
207        margin: {
208          top: 4,
209          bottom: 4,
210        },
211        padding: {
212          left: 2,
213          right: 2,
214          top: 2,
215          bottom: 2,
216        },
217        cornerRadius: 6,
218      },
219      avatarRibbon: {
220        height: 3,
221        width: 12,
222        // TODO: Chore: Make avatarRibbon colors driven by the theme rather than being hard coded.
223      },
224
225      // Sign in buttom
226      // FlatButton, Variant
227      signInPrompt: merge(titlebarButton, {
228        inactive: {
229          default: {
230            margin: {
231              left: itemSpacing,
232            },
233          },
234        },
235      }),
236
237      // Offline Indicator
238      offlineIcon: {
239        color: foreground(layer, "variant"),
240        width: 16,
241        margin: {
242          left: itemSpacing,
243        },
244        padding: {
245          right: 4,
246        },
247      },
248
249      // Notice that the collaboration server is out of date
250      outdatedWarning: {
251        ...text(layer, "sans", "warning", { size: "xs" }),
252        background: withOpacity(background(layer, "warning"), 0.3),
253        border: border(layer, "warning"),
254        margin: {
255          left: itemSpacing,
256        },
257        padding: {
258          left: 8,
259          right: 8,
260        },
261        cornerRadius: 6,
262      },
263      callControl: interactive({
264        base: {
265          cornerRadius: 6,
266          color: foreground(layer, "variant"),
267          iconWidth: 12,
268          buttonWidth: 20,
269        },
270        state: {
271          hovered: {
272            background: background(layer, "variant", "hovered"),
273            color: foreground(layer, "variant", "hovered"),
274          },
275        },
276      }),
277      toggleContactsButton: toggleable({
278        base:
279          interactive({
280            base: {
281              margin: { left: itemSpacing },
282              cornerRadius: 6,
283              color: foreground(layer, "variant"),
284              iconWidth: 14,
285              buttonWidth: 20,
286            },
287            state: {
288              clicked: {
289                background: background(layer, "variant", "pressed"),
290                color: foreground(layer, "variant", "pressed"),
291              },
292              hovered: {
293                background: background(layer, "variant", "hovered"),
294                color: foreground(layer, "variant", "hovered"),
295              },
296            },
297          }), state:
298        {
299          active: {
300            default: {
301              background: background(layer, "variant", "active"),
302              color: foreground(layer, "variant", "active"),
303            },
304          }
305        }
306      }
307      ),
308      userMenuButton: merge(titlebarButton, {
309        inactive: {
310          default: {
311            buttonWidth: 20,
312            iconWidth: 12,
313          },
314        },
315        active: {
316          // posiewic: these properties are not currently set on main
317          default: {
318            iconWidth: 12,
319            button_width: 20,
320          },
321        },
322      }),
323
324      toggleContactsBadge: {
325        cornerRadius: 3,
326        padding: 2,
327        margin: { top: 3, left: 3 },
328        border: border(layer),
329        background: foreground(layer, "accent"),
330      },
331      shareButton: {
332        ...titlebarButton,
333      },
334    },
335
336    toolbar: {
337      height: 34,
338      background: background(colorScheme.highest),
339      border: border(colorScheme.highest, { bottom: true }),
340      itemSpacing: 8,
341      navButton: interactive({
342        base: {
343          color: foreground(colorScheme.highest, "on"),
344          iconWidth: 12,
345          buttonWidth: 24,
346          cornerRadius: 6,
347        },
348        state: {
349          hovered: {
350            color: foreground(colorScheme.highest, "on", "hovered"),
351            background: background(
352              colorScheme.highest,
353              "on",
354              "hovered"
355            ),
356          },
357          disabled: {
358            color: foreground(
359              colorScheme.highest,
360              "on",
361              "disabled"
362            ),
363          },
364        },
365      }),
366      padding: { left: 8, right: 8, top: 4, bottom: 4 },
367    },
368    breadcrumbHeight: 24,
369    breadcrumbs: interactive({
370      base: {
371        ...text(colorScheme.highest, "sans", "variant"),
372        cornerRadius: 6,
373        padding: {
374          left: 6,
375          right: 6,
376        },
377      },
378      state: {
379        hovered: {
380          color: foreground(colorScheme.highest, "on", "hovered"),
381          background: background(
382            colorScheme.highest,
383            "on",
384            "hovered"
385          ),
386        },
387      },
388    }),
389    disconnectedOverlay: {
390      ...text(layer, "sans"),
391      background: withOpacity(background(layer), 0.8),
392    },
393    notification: {
394      margin: { top: 10 },
395      background: background(colorScheme.middle),
396      cornerRadius: 6,
397      padding: 12,
398      border: border(colorScheme.middle),
399      shadow: colorScheme.popoverShadow,
400    },
401    notifications: {
402      width: 400,
403      margin: { right: 10, bottom: 10 },
404    },
405    dropTargetOverlayColor: withOpacity(foreground(layer, "variant"), 0.5),
406  }
407}