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 signInPrompt: 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 screen_share_button: icon_button(colorScheme, {
304 margin: { left: itemSpacing / 2 },
305 }),
306
307 toggle_contacts_button: toggleable_icon_button(colorScheme, {
308 margin: { left: itemSpacing }
309 }),
310
311 toggle_microphone_button: toggleable_icon_button(colorScheme, {
312 margin: { left: itemSpacing },
313 active_color: 'negative'
314 }),
315
316 toggle_speakers_button: toggleable_icon_button(colorScheme, {
317 margin: { left: itemSpacing / 2 },
318 }),
319
320 leave_call_button: icon_button(colorScheme, {
321 margin: { left: itemSpacing },
322 }),
323
324 user_menu_button:
325 merge(titlebarButton, {
326 inactive: {
327 default: {
328 buttonWidth: 20,
329 iconWidth: 12,
330 },
331 },
332 active: {
333 default: {
334 iconWidth: 12,
335 button_width: 20,
336 background: background(layer, "variant", "active"),
337 color: foreground(layer, "variant", "active"),
338 }
339 },
340 }),
341
342 toggleContactsBadge: {
343 cornerRadius: 3,
344 padding: 2,
345 margin: { top: 3, left: 3 },
346 border: border(layer),
347 background: foreground(layer, "accent"),
348 },
349 shareButton: toggleable_text_button(colorScheme, {}),
350 },
351
352 toolbar: {
353 height: 34,
354 background: background(colorScheme.highest),
355 border: border(colorScheme.highest, { bottom: true }),
356 itemSpacing: 8,
357 navButton: interactive({
358 base: {
359 color: foreground(colorScheme.highest, "on"),
360 iconWidth: 12,
361 buttonWidth: 24,
362 cornerRadius: 6,
363 },
364 state: {
365 hovered: {
366 color: foreground(colorScheme.highest, "on", "hovered"),
367 background: background(
368 colorScheme.highest,
369 "on",
370 "hovered"
371 ),
372 },
373 disabled: {
374 color: foreground(
375 colorScheme.highest,
376 "on",
377 "disabled"
378 ),
379 },
380 },
381 }),
382 padding: { left: 8, right: 8, top: 4, bottom: 4 },
383 },
384 breadcrumbHeight: 24,
385 breadcrumbs: interactive({
386 base: {
387 ...text(colorScheme.highest, "sans", "variant"),
388 cornerRadius: 6,
389 padding: {
390 left: 6,
391 right: 6,
392 },
393 },
394 state: {
395 hovered: {
396 color: foreground(colorScheme.highest, "on", "hovered"),
397 background: background(
398 colorScheme.highest,
399 "on",
400 "hovered"
401 ),
402 },
403 },
404 }),
405 disconnectedOverlay: {
406 ...text(layer, "sans"),
407 background: withOpacity(background(layer), 0.8),
408 },
409 notification: {
410 margin: { top: 10 },
411 background: background(colorScheme.middle),
412 cornerRadius: 6,
413 padding: 12,
414 border: border(colorScheme.middle),
415 shadow: colorScheme.popoverShadow,
416 },
417 notifications: {
418 width: 400,
419 margin: { right: 10, bottom: 10 },
420 },
421 dropTargetOverlayColor: withOpacity(foreground(layer, "variant"), 0.5),
422 }
423}