workspace.ts

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