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