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