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}