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 userMenuButton: merge(titlebarButton, {
347 inactive: {
348 default: {
349 buttonWidth: 20,
350 iconWidth: 12,
351 },
352 },
353 active: {
354 default: {
355 iconWidth: 12,
356 button_width: 20,
357 background: background(layer, "variant", "active"),
358 color: foreground(layer, "variant", "active"),
359 }
360 },
361 }),
362
363 toggleContactsBadge: {
364 cornerRadius: 3,
365 padding: 2,
366 margin: { top: 3, left: 3 },
367 border: border(layer),
368 background: foreground(layer, "accent"),
369 },
370 shareButton: {
371 ...titlebarButton,
372 },
373 },
374
375 toolbar: {
376 height: 34,
377 background: background(colorScheme.highest),
378 border: border(colorScheme.highest, { bottom: true }),
379 itemSpacing: 8,
380 navButton: interactive({
381 base: {
382 color: foreground(colorScheme.highest, "on"),
383 iconWidth: 12,
384 buttonWidth: 24,
385 cornerRadius: 6,
386 },
387 state: {
388 hovered: {
389 color: foreground(colorScheme.highest, "on", "hovered"),
390 background: background(
391 colorScheme.highest,
392 "on",
393 "hovered"
394 ),
395 },
396 disabled: {
397 color: foreground(
398 colorScheme.highest,
399 "on",
400 "disabled"
401 ),
402 },
403 },
404 }),
405 padding: { left: 8, right: 8, top: 4, bottom: 4 },
406 },
407 breadcrumbHeight: 24,
408 breadcrumbs: interactive({
409 base: {
410 ...text(colorScheme.highest, "sans", "variant"),
411 cornerRadius: 6,
412 padding: {
413 left: 6,
414 right: 6,
415 },
416 },
417 state: {
418 hovered: {
419 color: foreground(colorScheme.highest, "on", "hovered"),
420 background: background(
421 colorScheme.highest,
422 "on",
423 "hovered"
424 ),
425 },
426 },
427 }),
428 disconnectedOverlay: {
429 ...text(layer, "sans"),
430 background: withOpacity(background(layer), 0.8),
431 },
432 notification: {
433 margin: { top: 10 },
434 background: background(colorScheme.middle),
435 cornerRadius: 6,
436 padding: 12,
437 border: border(colorScheme.middle),
438 shadow: colorScheme.popoverShadow,
439 },
440 notifications: {
441 width: 400,
442 margin: { right: 10, bottom: 10 },
443 },
444 dropTargetOverlayColor: withOpacity(foreground(layer, "variant"), 0.5),
445 }
446}