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"
 16import { icon_button } from "../component/icon_button"
 17export default function workspace(colorScheme: ColorScheme) {
 18    const layer = colorScheme.lowest
 19    const isLight = colorScheme.isLight
 20    const itemSpacing = 8
 21    const titlebarButton = toggleable({
 22        base: 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    const signInButton = toggleable({
 63        base: interactive({
 64            base: {
 65                cornerRadius: 6,
 66                padding: {
 67                    top: 1,
 68                    bottom: 1,
 69                    left: 8,
 70                    right: 8,
 71                },
 72                ...text(layer, "sans", "variant", { size: "xs" }),
 73                background: background(layer, "variant"),
 74            },
 75            state: {
 76                hovered: {
 77                    ...text(layer, "sans", "variant", "hovered", { size: "xs" }),
 78                    background: background(layer, "variant", "hovered"),
 79                    //border: border(layer, "variant", "hovered"),
 80                },
 81                clicked: {
 82                    ...text(layer, "sans", "variant", "pressed", { size: "xs" }),
 83                    background: background(layer, "variant", "pressed"),
 84                    //border: border(layer, "variant", "pressed"),
 85                }
 86            }
 87        }),
 88        state: {
 89            active: {
 90                default: {
 91                    ...text(layer, "sans", "variant", "active", { size: "xs" }),
 92                    background: background(layer, "variant", "active"),
 93                    //border: border(layer, "variant", "active"),
 94                }
 95            },
 96        }
 97    });
 98    const avatarWidth = 18
 99    const avatarOuterWidth = avatarWidth + 4
100    const followerAvatarWidth = 14
101    const followerAvatarOuterWidth = followerAvatarWidth + 4
102
103    return {
104        background: background(colorScheme.lowest),
105        blankPane: {
106            logoContainer: {
107                width: 256,
108                height: 256,
109            },
110            logo: svg(
111                withOpacity("#000000", colorScheme.isLight ? 0.6 : 0.8),
112                "icons/logo_96.svg",
113                256,
114                256
115            ),
116
117            logoShadow: svg(
118                withOpacity(
119                    colorScheme.isLight
120                        ? "#FFFFFF"
121                        : colorScheme.lowest.base.default.background,
122                    colorScheme.isLight ? 1 : 0.6
123                ),
124                "icons/logo_96.svg",
125                256,
126                256
127            ),
128            keyboardHints: {
129                margin: {
130                    top: 96,
131                },
132                cornerRadius: 4,
133            },
134            keyboardHint: interactive({
135                base: {
136                    ...text(layer, "sans", "variant", { size: "sm" }),
137                    padding: {
138                        top: 3,
139                        left: 8,
140                        right: 8,
141                        bottom: 3,
142                    },
143                    cornerRadius: 8,
144                },
145                state: {
146                    hovered: {
147                        ...text(layer, "sans", "active", { size: "sm" }),
148                    },
149                },
150            }),
151
152            keyboardHintWidth: 320,
153        },
154        joiningProjectAvatar: {
155            cornerRadius: 40,
156            width: 80,
157        },
158        joiningProjectMessage: {
159            padding: 12,
160            ...text(layer, "sans", { size: "lg" }),
161        },
162        externalLocationMessage: {
163            background: background(colorScheme.middle, "accent"),
164            border: border(colorScheme.middle, "accent"),
165            cornerRadius: 6,
166            padding: 12,
167            margin: { bottom: 8, right: 8 },
168            ...text(colorScheme.middle, "sans", "accent", { size: "xs" }),
169        },
170        leaderBorderOpacity: 0.7,
171        leaderBorderWidth: 2.0,
172        tabBar: tabBar(colorScheme),
173        modal: {
174            margin: {
175                bottom: 52,
176                top: 52,
177            },
178            cursor: "Arrow",
179        },
180        zoomedBackground: {
181            cursor: "Arrow",
182            background: isLight
183                ? withOpacity(background(colorScheme.lowest), 0.8)
184                : withOpacity(background(colorScheme.highest), 0.6),
185        },
186        zoomedPaneForeground: {
187            margin: 16,
188            shadow: colorScheme.modalShadow,
189            border: border(colorScheme.lowest, { overlay: true }),
190        },
191        zoomedPanelForeground: {
192            margin: 16,
193            border: border(colorScheme.lowest, { overlay: true }),
194        },
195        dock: {
196            left: {
197                border: border(layer, { right: true }),
198            },
199            bottom: {
200                border: border(layer, { top: true }),
201            },
202            right: {
203                border: border(layer, { left: true }),
204            },
205        },
206        paneDivider: {
207            color: borderColor(layer),
208            width: 1,
209        },
210        statusBar: statusBar(colorScheme),
211        titlebar: {
212            itemSpacing,
213            facePileSpacing: 2,
214            height: 33, // 32px + 1px border. It's important the content area of the titlebar is evenly sized to vertically center avatar images.
215            background: background(layer),
216            border: border(layer, { bottom: true }),
217            padding: {
218                left: 80,
219                right: itemSpacing,
220            },
221
222            // Project
223            title: text(layer, "sans", "variant"),
224            highlight_color: text(layer, "sans", "active").color,
225
226            // Collaborators
227            leaderAvatar: {
228                width: avatarWidth,
229                outerWidth: avatarOuterWidth,
230                cornerRadius: avatarWidth / 2,
231                outerCornerRadius: avatarOuterWidth / 2,
232            },
233            followerAvatar: {
234                width: followerAvatarWidth,
235                outerWidth: followerAvatarOuterWidth,
236                cornerRadius: followerAvatarWidth / 2,
237                outerCornerRadius: followerAvatarOuterWidth / 2,
238            },
239            inactiveAvatarGrayscale: true,
240            followerAvatarOverlap: 8,
241            leaderSelection: {
242                margin: {
243                    top: 4,
244                    bottom: 4,
245                },
246                padding: {
247                    left: 2,
248                    right: 2,
249                    top: 2,
250                    bottom: 2,
251                },
252                cornerRadius: 6,
253            },
254            avatarRibbon: {
255                height: 3,
256                width: 11,
257                // TODO: Chore: Make avatarRibbon colors driven by the theme rather than being hard coded.
258            },
259
260            // Sign in buttom
261            // FlatButton, Variant
262            signInPrompt: merge(titlebarButton, {
263                inactive: {
264                    default: {
265                        margin: {
266                            left: itemSpacing,
267                        },
268                    },
269                },
270
271                signInButton,
272
273            }),
274
275            // Offline Indicator
276            offlineIcon: {
277                color: foreground(layer, "variant"),
278                width: 16,
279                margin: {
280                    left: itemSpacing,
281                },
282                padding: {
283                    right: 4,
284                },
285            },
286
287            // Notice that the collaboration server is out of date
288            outdatedWarning: {
289                ...text(layer, "sans", "warning", { size: "xs" }),
290                background: withOpacity(background(layer, "warning"), 0.3),
291                border: border(layer, "warning"),
292                margin: {
293                    left: itemSpacing,
294                },
295                padding: {
296                    left: 8,
297                    right: 8,
298                },
299                cornerRadius: 6,
300            },
301            callControl: interactive({
302                base: {
303                    cornerRadius: 6,
304                    color: foreground(layer, "variant"),
305                    iconWidth: 12,
306                    buttonWidth: 20,
307                },
308                state: {
309                    hovered: {
310                        background: background(layer, "variant", "hovered"),
311                        color: foreground(layer, "variant", "hovered"),
312                    },
313                },
314            }),
315            toggleContactsButton: toggleable({
316                base: interactive({
317                    base: {
318                        margin: { left: itemSpacing },
319                        cornerRadius: 6,
320                        color: foreground(layer, "variant"),
321                        iconWidth: 14,
322                        buttonWidth: 20,
323                    },
324                    state: {
325                        clicked: {
326                            background: background(layer, "variant", "pressed"),
327                        },
328                        hovered: {
329                            background: background(layer, "variant", "hovered"),
330                        },
331                    },
332                }),
333                state: {
334                    active: {
335                        default: {
336                            background: background(layer, "on", "default"),
337                        },
338                        hovered: {
339                            background: background(layer, "on", "hovered"),
340                        },
341                        clicked: {
342                            background: background(layer, "on", "pressed"),
343                        },
344                    },
345                },
346            }),
347            toggleMicrophoneButton: toggleable({
348                base: interactive({
349                    base: {
350                        margin: { left: itemSpacing },
351                        cornerRadius: 6,
352                        color: foreground(layer, "variant"),
353                        iconWidth: 14,
354                        buttonWidth: 20,
355                    },
356                    state: {
357                        clicked: {
358                            background: background(layer, "variant", "pressed"),
359                        },
360                        hovered: {
361                            background: background(layer, "variant", "hovered"),
362                        },
363                    },
364                }),
365                state: {
366                    active: {
367                        default: {
368                            background: background(layer, "on", "default"),
369                        },
370                        hovered: {
371                            background: background(layer, "on", "hovered"),
372                        },
373                        clicked: {
374                            background: background(layer, "on", "pressed"),
375                        },
376                    },
377                },
378            }),
379            toggleSpeakersButton: toggleable({
380                base: interactive({
381                    base: {
382                        margin: { left: itemSpacing },
383                        cornerRadius: 6,
384                        color: foreground(layer, "variant"),
385                        iconWidth: 14,
386                        buttonWidth: 20,
387                    },
388                    state: {
389                        clicked: {
390                            background: background(layer, "variant", "pressed"),
391                        },
392                        hovered: {
393                            background: background(layer, "variant", "hovered"),
394                        },
395                    },
396                }),
397                state: {
398                    active: {
399                        default: {
400                            background: background(layer, "on", "default"),
401                        },
402                        hovered: {
403                            background: background(layer, "on", "hovered"),
404                        },
405                        clicked: {
406                            background: background(layer, "on", "pressed"),
407                        },
408                    },
409                },
410            }),
411
412            leaveCallButton: icon_button(colorScheme, {
413                margin: { left: itemSpacing },
414            }),
415
416            userMenuButton: merge(titlebarButton, {
417                inactive: {
418                    default: {
419                        buttonWidth: 20,
420                        iconWidth: 12,
421                    },
422                },
423                active: {
424                    default: {
425                        iconWidth: 12,
426                        button_width: 20,
427                        background: background(layer, "variant", "active"),
428                        color: foreground(layer, "variant", "active"),
429                    }
430                },
431            }),
432
433            toggleContactsBadge: {
434                cornerRadius: 3,
435                padding: 2,
436                margin: { top: 3, left: 3 },
437                border: border(layer),
438                background: foreground(layer, "accent"),
439            },
440            shareButton: {
441                ...titlebarButton,
442            },
443        },
444
445        toolbar: {
446            height: 34,
447            background: background(colorScheme.highest),
448            border: border(colorScheme.highest, { bottom: true }),
449            itemSpacing: 8,
450            navButton: interactive({
451                base: {
452                    color: foreground(colorScheme.highest, "on"),
453                    iconWidth: 12,
454                    buttonWidth: 24,
455                    cornerRadius: 6,
456                },
457                state: {
458                    hovered: {
459                        color: foreground(colorScheme.highest, "on", "hovered"),
460                        background: background(
461                            colorScheme.highest,
462                            "on",
463                            "hovered"
464                        ),
465                    },
466                    disabled: {
467                        color: foreground(
468                            colorScheme.highest,
469                            "on",
470                            "disabled"
471                        ),
472                    },
473                },
474            }),
475            padding: { left: 8, right: 8, top: 4, bottom: 4 },
476        },
477        breadcrumbHeight: 24,
478        breadcrumbs: interactive({
479            base: {
480                ...text(colorScheme.highest, "sans", "variant"),
481                cornerRadius: 6,
482                padding: {
483                    left: 6,
484                    right: 6,
485                },
486            },
487            state: {
488                hovered: {
489                    color: foreground(colorScheme.highest, "on", "hovered"),
490                    background: background(
491                        colorScheme.highest,
492                        "on",
493                        "hovered"
494                    ),
495                },
496            },
497        }),
498        disconnectedOverlay: {
499            ...text(layer, "sans"),
500            background: withOpacity(background(layer), 0.8),
501        },
502        notification: {
503            margin: { top: 10 },
504            background: background(colorScheme.middle),
505            cornerRadius: 6,
506            padding: 12,
507            border: border(colorScheme.middle),
508            shadow: colorScheme.popoverShadow,
509        },
510        notifications: {
511            width: 400,
512            margin: { right: 10, bottom: 10 },
513        },
514        dropTargetOverlayColor: withOpacity(foreground(layer, "variant"), 0.5),
515    }
516}