An ATproto social media client -- with an independent Appview.
1import {atoms} from '#/alf/atoms'
2import {mocha} from '#/alf/catppuccin/palette'
3import {type Palette, type Theme} from '#/alf/types'
4import {
5 BLUE_HUE,
6 defaultScale,
7 dimScale,
8 GREEN_HUE,
9 RED_HUE,
10} from '#/alf/util/colorGeneration'
11import {fade} from '#/alf/util/colors'
12
13const themes = createThemes({
14 hues: {
15 primary: BLUE_HUE,
16 negative: RED_HUE,
17 positive: GREEN_HUE,
18 },
19})
20
21/**
22 * @deprecated use ALF and access palette from `useTheme()`
23 */
24export const lightPalette = themes.lightPalette
25/**
26 * @deprecated use ALF and access palette from `useTheme()`
27 */
28export const darkPalette = themes.darkPalette
29/**
30 * @deprecated use ALF and access palette from `useTheme()`
31 */
32export const dimPalette = themes.dimPalette
33/**
34 * @deprecated use ALF and access theme from `useTheme()`
35 */
36export const light = themes.light
37/**
38 * @deprecated use ALF and access theme from `useTheme()`
39 */
40export const dark = themes.dark
41/**
42 * @deprecated use ALF and access theme from `useTheme()`
43 */
44export const dim = themes.dim
45
46export const defaultTheme = themes.light
47
48export function createThemes({
49 hues,
50}: {
51 hues: {
52 primary: number
53 negative: number
54 positive: number
55 }
56}): {
57 lightPalette: Palette
58 darkPalette: Palette
59 dimPalette: Palette
60 light: Theme
61 dark: Theme
62 dim: Theme
63} {
64 const accent = mocha.mauve
65 const color = {
66 like: '#ec4899',
67 trueBlack: '#000000',
68
69 gray_0: `hsl(${hues.primary}, 20%, ${defaultScale[14]}%)`,
70 gray_25: `hsl(${hues.primary}, 20%, ${defaultScale[13]}%)`,
71 gray_50: `hsl(${hues.primary}, 20%, ${defaultScale[12]}%)`,
72 gray_100: `hsl(${hues.primary}, 20%, ${defaultScale[11]}%)`,
73 gray_200: `hsl(${hues.primary}, 20%, ${defaultScale[10]}%)`,
74 gray_300: `hsl(${hues.primary}, 20%, ${defaultScale[9]}%)`,
75 gray_400: `hsl(${hues.primary}, 20%, ${defaultScale[8]}%)`,
76 gray_500: `hsl(${hues.primary}, 20%, ${defaultScale[7]}%)`,
77 gray_600: `hsl(${hues.primary}, 24%, ${defaultScale[6]}%)`,
78 gray_700: `hsl(${hues.primary}, 24%, ${defaultScale[5]}%)`,
79 gray_800: `hsl(${hues.primary}, 28%, ${defaultScale[4]}%)`,
80 gray_900: `hsl(${hues.primary}, 28%, ${defaultScale[3]}%)`,
81 gray_950: `hsl(${hues.primary}, 28%, ${defaultScale[2]}%)`,
82 gray_975: `hsl(${hues.primary}, 28%, ${defaultScale[1]}%)`,
83 gray_1000: `hsl(${hues.primary}, 28%, ${defaultScale[0]}%)`,
84
85 primary_25: `hsl(${hues.primary}, 99%, 97%)`,
86 primary_50: `hsl(${hues.primary}, 99%, 95%)`,
87 primary_100: `hsl(${hues.primary}, 99%, 90%)`,
88 primary_200: `hsl(${hues.primary}, 99%, 80%)`,
89 primary_300: `hsl(${hues.primary}, 99%, 70%)`,
90 primary_400: `hsl(${hues.primary}, 99%, 60%)`,
91 primary_500: `hsl(${hues.primary}, 99%, 53%)`,
92 primary_600: `hsl(${hues.primary}, 99%, 42%)`,
93 primary_700: `hsl(${hues.primary}, 99%, 34%)`,
94 primary_800: `hsl(${hues.primary}, 99%, 26%)`,
95 primary_900: `hsl(${hues.primary}, 99%, 18%)`,
96 primary_950: `hsl(${hues.primary}, 99%, 10%)`,
97 primary_975: `hsl(${hues.primary}, 99%, 7%)`,
98
99 green_25: `hsl(${hues.positive}, 82%, 97%)`,
100 green_50: `hsl(${hues.positive}, 82%, 95%)`,
101 green_100: `hsl(${hues.positive}, 82%, 90%)`,
102 green_200: `hsl(${hues.positive}, 82%, 80%)`,
103 green_300: `hsl(${hues.positive}, 82%, 70%)`,
104 green_400: `hsl(${hues.positive}, 82%, 60%)`,
105 green_500: `hsl(${hues.positive}, 82%, 50%)`,
106 green_600: `hsl(${hues.positive}, 82%, 42%)`,
107 green_700: `hsl(${hues.positive}, 82%, 34%)`,
108 green_800: `hsl(${hues.positive}, 82%, 26%)`,
109 green_900: `hsl(${hues.positive}, 82%, 18%)`,
110 green_950: `hsl(${hues.positive}, 82%, 10%)`,
111 green_975: `hsl(${hues.positive}, 82%, 7%)`,
112
113 red_25: `hsl(${hues.negative}, 91%, 97%)`,
114 red_50: `hsl(${hues.negative}, 91%, 95%)`,
115 red_100: `hsl(${hues.negative}, 91%, 90%)`,
116 red_200: `hsl(${hues.negative}, 91%, 80%)`,
117 red_300: `hsl(${hues.negative}, 91%, 70%)`,
118 red_400: `hsl(${hues.negative}, 91%, 60%)`,
119 red_500: mocha.red,
120 red_600: `hsl(${hues.negative}, 91%, 42%)`,
121 red_700: `hsl(${hues.negative}, 91%, 34%)`,
122 red_800: `hsl(${hues.negative}, 91%, 26%)`,
123 red_900: `hsl(${hues.negative}, 91%, 18%)`,
124 red_950: `hsl(${hues.negative}, 91%, 10%)`,
125 red_975: `hsl(${hues.negative}, 91%, 7%)`,
126 } as const
127
128 const lightPalette = {
129 white: color.gray_0,
130 black: color.gray_1000,
131 like: color.like,
132
133 contrast_25: color.gray_25,
134 contrast_50: color.gray_50,
135 contrast_100: color.gray_100,
136 contrast_200: color.gray_200,
137 contrast_300: color.gray_300,
138 contrast_400: color.gray_400,
139 contrast_500: color.gray_500,
140 contrast_600: color.gray_600,
141 contrast_700: color.gray_700,
142 contrast_800: color.gray_800,
143 contrast_900: color.gray_900,
144 contrast_950: color.gray_950,
145 contrast_975: color.gray_975,
146
147 primary_25: color.primary_25,
148 primary_50: color.primary_50,
149 primary_100: color.primary_100,
150 primary_200: color.primary_200,
151 primary_300: color.primary_300,
152 primary_400: color.primary_400,
153 primary_500: color.primary_500,
154 primary_600: color.primary_600,
155 primary_700: color.primary_700,
156 primary_800: color.primary_800,
157 primary_900: color.primary_900,
158 primary_950: color.primary_950,
159 primary_975: color.primary_975,
160
161 positive_25: color.green_25,
162 positive_50: color.green_50,
163 positive_100: color.green_100,
164 positive_200: color.green_200,
165 positive_300: color.green_300,
166 positive_400: color.green_400,
167 positive_500: color.green_500,
168 positive_600: color.green_600,
169 positive_700: color.green_700,
170 positive_800: color.green_800,
171 positive_900: color.green_900,
172 positive_950: color.green_950,
173 positive_975: color.green_975,
174
175 negative_25: color.red_25,
176 negative_50: color.red_50,
177 negative_100: color.red_100,
178 negative_200: color.red_200,
179 negative_300: color.red_300,
180 negative_400: color.red_400,
181 negative_500: color.red_500,
182 negative_600: color.red_600,
183 negative_700: color.red_700,
184 negative_800: color.red_800,
185 negative_900: color.red_900,
186 negative_950: color.red_950,
187 negative_975: color.red_975,
188 } as const
189
190 const darkPalette: Palette = {
191 white: mocha.text,
192 black: color.trueBlack,
193 like: color.like,
194
195 contrast_25: color.gray_975,
196 contrast_50: color.gray_950,
197 contrast_100: color.gray_900,
198 contrast_200: color.gray_800,
199 contrast_300: color.gray_700,
200 contrast_400: color.gray_600,
201 contrast_500: color.gray_500,
202 contrast_600: color.gray_400,
203 contrast_700: color.gray_300,
204 contrast_800: color.gray_200,
205 contrast_900: color.gray_100,
206 contrast_950: color.gray_50,
207 contrast_975: color.gray_25,
208
209 primary_25: color.primary_975,
210 primary_50: color.primary_950,
211 primary_100: color.primary_900,
212 primary_200: color.primary_800,
213 primary_300: color.primary_700,
214 primary_400: color.primary_600,
215 primary_500: color.primary_500,
216 primary_600: color.primary_400,
217 primary_700: color.primary_300,
218 primary_800: color.primary_200,
219 primary_900: color.primary_100,
220 primary_950: color.primary_50,
221 primary_975: color.primary_25,
222
223 positive_25: color.green_975,
224 positive_50: color.green_950,
225 positive_100: color.green_900,
226 positive_200: color.green_800,
227 positive_300: color.green_700,
228 positive_400: color.green_600,
229 positive_500: color.green_500,
230 positive_600: color.green_400,
231 positive_700: color.green_300,
232 positive_800: color.green_200,
233 positive_900: color.green_100,
234 positive_950: color.green_50,
235 positive_975: color.green_25,
236
237 negative_25: color.red_975,
238 negative_50: color.red_950,
239 negative_100: color.red_900,
240 negative_200: color.red_800,
241 negative_300: color.red_700,
242 negative_400: color.red_600,
243 negative_500: color.red_500,
244 negative_600: color.red_400,
245 negative_700: color.red_300,
246 negative_800: color.red_200,
247 negative_900: color.red_100,
248 negative_950: color.red_50,
249 negative_975: color.red_25,
250 } as const
251
252 const dimPalette: Palette = {
253 ...darkPalette,
254 black: mocha.base,
255 like: mocha.red,
256
257 contrast_25: mocha.mantle,
258 contrast_50: mocha.mantle,
259 contrast_100: mocha.surface1,
260 contrast_200: mocha.surface1,
261 contrast_300: `hsl(${hues.primary}, 24%, ${dimScale[5]}%)`,
262 contrast_400: `hsl(${hues.primary}, 24%, ${dimScale[6]}%)`,
263 contrast_500: `hsl(${hues.primary}, 20%, ${dimScale[7]}%)`,
264 contrast_600: `hsl(${hues.primary}, 20%, ${dimScale[8]}%)`,
265 contrast_700: `hsl(${hues.primary}, 20%, ${dimScale[9]}%)`,
266 contrast_800: `hsl(${hues.primary}, 20%, ${dimScale[10]}%)`,
267 contrast_900: `hsl(${hues.primary}, 20%, ${dimScale[11]}%)`,
268 contrast_950: `hsl(${hues.primary}, 20%, ${dimScale[12]}%)`,
269 contrast_975: `hsl(${hues.primary}, 20%, ${dimScale[13]}%)`,
270
271 primary_25: `hsl(${hues.primary}, 50%, ${dimScale[1]}%)`,
272 primary_50: fade(accent, 15),
273 primary_100: `hsl(${hues.primary}, 70%, ${dimScale[3]}%)`,
274 primary_200: `hsl(${hues.primary}, 82%, ${dimScale[4]}%)`,
275 primary_300: `hsl(${hues.primary}, 90%, ${dimScale[5]}%)`,
276 primary_400: `hsl(${hues.primary}, 95%, ${dimScale[6]}%)`,
277 primary_500: accent,
278 primary_600: `hsl(${hues.primary}, 99%, ${dimScale[8]}%)`,
279 primary_700: `hsl(${hues.primary}, 99%, ${dimScale[9]}%)`,
280 primary_800: `hsl(${hues.primary}, 99%, ${dimScale[10]}%)`,
281 primary_900: `hsl(${hues.primary}, 99%, ${dimScale[11]}%)`,
282 primary_950: `hsl(${hues.primary}, 99%, ${dimScale[12]}%)`,
283 primary_975: `hsl(${hues.primary}, 99%, ${dimScale[13]}%)`,
284
285 positive_25: `hsl(${hues.positive}, 50%, ${dimScale[1]}%)`,
286 positive_50: `hsl(${hues.positive}, 60%, ${dimScale[2]}%)`,
287 positive_100: `hsl(${hues.positive}, 70%, ${dimScale[3]}%)`,
288 positive_200: `hsl(${hues.positive}, 82%, ${dimScale[4]}%)`,
289 positive_300: `hsl(${hues.positive}, 82%, ${dimScale[5]}%)`,
290 positive_400: mocha.green,
291 positive_500: mocha.green,
292 positive_600: mocha.green,
293 positive_700: `hsl(${hues.positive}, 82%, ${dimScale[9]}%)`,
294 positive_800: `hsl(${hues.positive}, 82%, ${dimScale[10]}%)`,
295 positive_900: `hsl(${hues.positive}, 82%, ${dimScale[11]}%)`,
296 positive_950: `hsl(${hues.positive}, 82%, ${dimScale[12]}%)`,
297 positive_975: `hsl(${hues.positive}, 82%, ${dimScale[13]}%)`,
298
299 negative_25: `hsl(${hues.negative}, 70%, ${dimScale[1]}%)`,
300 negative_50: `hsl(${hues.negative}, 80%, ${dimScale[2]}%)`,
301 negative_100: `hsl(${hues.negative}, 84%, ${dimScale[3]}%)`,
302 negative_200: `hsl(${hues.negative}, 88%, ${dimScale[4]}%)`,
303 negative_300: `hsl(${hues.negative}, 91%, ${dimScale[5]}%)`,
304 negative_400: mocha.red,
305 negative_500: mocha.red,
306 negative_600: mocha.red,
307 negative_700: `hsl(${hues.negative}, 91%, ${dimScale[9]}%)`,
308 negative_800: `hsl(${hues.negative}, 91%, ${dimScale[10]}%)`,
309 negative_900: `hsl(${hues.negative}, 91%, ${dimScale[11]}%)`,
310 negative_950: `hsl(${hues.negative}, 91%, ${dimScale[12]}%)`,
311 negative_975: `hsl(${hues.negative}, 91%, ${dimScale[13]}%)`,
312 } as const
313
314 const light: Theme = {
315 scheme: 'light',
316 name: 'light',
317 palette: lightPalette,
318 atoms: {
319 text: {
320 color: lightPalette.black,
321 },
322 text_contrast_low: {
323 color: lightPalette.contrast_400,
324 },
325 text_contrast_medium: {
326 color: lightPalette.contrast_700,
327 },
328 text_contrast_high: {
329 color: lightPalette.contrast_900,
330 },
331 text_inverted: {
332 color: lightPalette.white,
333 },
334 bg: {
335 backgroundColor: lightPalette.white,
336 },
337 bg_contrast_25: {
338 backgroundColor: lightPalette.contrast_25,
339 },
340 bg_contrast_50: {
341 backgroundColor: lightPalette.contrast_50,
342 },
343 bg_contrast_100: {
344 backgroundColor: lightPalette.contrast_100,
345 },
346 bg_contrast_200: {
347 backgroundColor: lightPalette.contrast_200,
348 },
349 bg_contrast_300: {
350 backgroundColor: lightPalette.contrast_300,
351 },
352 bg_contrast_400: {
353 backgroundColor: lightPalette.contrast_400,
354 },
355 bg_contrast_500: {
356 backgroundColor: lightPalette.contrast_500,
357 },
358 bg_contrast_600: {
359 backgroundColor: lightPalette.contrast_600,
360 },
361 bg_contrast_700: {
362 backgroundColor: lightPalette.contrast_700,
363 },
364 bg_contrast_800: {
365 backgroundColor: lightPalette.contrast_800,
366 },
367 bg_contrast_900: {
368 backgroundColor: lightPalette.contrast_900,
369 },
370 bg_contrast_950: {
371 backgroundColor: lightPalette.contrast_950,
372 },
373 bg_contrast_975: {
374 backgroundColor: lightPalette.contrast_975,
375 },
376 border_contrast_low: {
377 borderColor: lightPalette.contrast_100,
378 },
379 border_contrast_medium: {
380 borderColor: lightPalette.contrast_200,
381 },
382 border_contrast_high: {
383 borderColor: lightPalette.contrast_300,
384 },
385 shadow_sm: {
386 ...atoms.shadow_sm,
387 shadowColor: lightPalette.black,
388 },
389 shadow_md: {
390 ...atoms.shadow_md,
391 shadowColor: lightPalette.black,
392 },
393 shadow_lg: {
394 ...atoms.shadow_lg,
395 shadowColor: lightPalette.black,
396 }, // TODO: probably delete this when we shift to setting CTP colours.
397 trending_hot: {
398 color: '#FFFFFF',
399 backgroundColor: 'red',
400 },
401 trending_new: {
402 color: '#FFFFFF',
403 backgroundColor: 'green',
404 },
405 },
406 }
407
408 const dark: Theme = {
409 scheme: 'dark',
410 name: 'dark',
411 palette: darkPalette,
412 atoms: {
413 text: {
414 color: darkPalette.white,
415 },
416 text_contrast_low: {
417 color: darkPalette.contrast_400,
418 },
419 text_contrast_medium: {
420 color: darkPalette.contrast_600,
421 },
422 text_contrast_high: {
423 color: darkPalette.contrast_900,
424 },
425 text_inverted: {
426 color: darkPalette.black,
427 },
428 bg: {
429 backgroundColor: darkPalette.black,
430 },
431 bg_contrast_25: {
432 backgroundColor: darkPalette.contrast_25,
433 },
434 bg_contrast_50: {
435 backgroundColor: darkPalette.contrast_50,
436 },
437 bg_contrast_100: {
438 backgroundColor: darkPalette.contrast_100,
439 },
440 bg_contrast_200: {
441 backgroundColor: darkPalette.contrast_200,
442 },
443 bg_contrast_300: {
444 backgroundColor: darkPalette.contrast_300,
445 },
446 bg_contrast_400: {
447 backgroundColor: darkPalette.contrast_400,
448 },
449 bg_contrast_500: {
450 backgroundColor: darkPalette.contrast_500,
451 },
452 bg_contrast_600: {
453 backgroundColor: darkPalette.contrast_600,
454 },
455 bg_contrast_700: {
456 backgroundColor: darkPalette.contrast_700,
457 },
458 bg_contrast_800: {
459 backgroundColor: darkPalette.contrast_800,
460 },
461 bg_contrast_900: {
462 backgroundColor: darkPalette.contrast_900,
463 },
464 bg_contrast_950: {
465 backgroundColor: darkPalette.contrast_950,
466 },
467 bg_contrast_975: {
468 backgroundColor: darkPalette.contrast_975,
469 },
470 border_contrast_low: {
471 borderColor: darkPalette.contrast_100,
472 },
473 border_contrast_medium: {
474 borderColor: darkPalette.contrast_200,
475 },
476 border_contrast_high: {
477 borderColor: darkPalette.contrast_300,
478 },
479 shadow_sm: {
480 ...atoms.shadow_sm,
481 shadowOpacity: 0.7,
482 shadowColor: color.trueBlack,
483 },
484 shadow_md: {
485 ...atoms.shadow_md,
486 shadowOpacity: 0.7,
487 shadowColor: color.trueBlack,
488 },
489 shadow_lg: {
490 ...atoms.shadow_lg,
491 shadowOpacity: 0.7,
492 shadowColor: color.trueBlack,
493 },
494 // TODO: probably delete this when we shift to setting CTP colours.
495 trending_hot: {
496 color: '#FFFFFF',
497 backgroundColor: 'red',
498 },
499 trending_new: {
500 color: '#FFFFFF',
501 backgroundColor: 'green',
502 },
503 },
504 }
505
506 const dim: Theme = {
507 ...dark,
508 scheme: 'dark',
509 name: 'dim',
510 palette: dimPalette,
511 atoms: {
512 ...dark.atoms,
513 text: {
514 color: mocha.text,
515 },
516 text_contrast_low: {
517 color: mocha.overlay0,
518 },
519 text_contrast_medium: {
520 color: mocha.overlay2,
521 },
522 text_contrast_high: {
523 color: mocha.subtext0,
524 },
525 text_inverted: {
526 color: mocha.crust,
527 },
528 bg: {
529 backgroundColor: dimPalette.black,
530 },
531 bg_contrast_25: {
532 backgroundColor: dimPalette.contrast_25,
533 },
534 bg_contrast_50: {
535 backgroundColor: dimPalette.contrast_50,
536 },
537 bg_contrast_100: {
538 backgroundColor: dimPalette.contrast_100,
539 },
540 bg_contrast_200: {
541 backgroundColor: dimPalette.contrast_200,
542 },
543 bg_contrast_300: {
544 backgroundColor: dimPalette.contrast_300,
545 },
546 bg_contrast_400: {
547 backgroundColor: dimPalette.contrast_400,
548 },
549 bg_contrast_500: {
550 backgroundColor: dimPalette.contrast_500,
551 },
552 bg_contrast_600: {
553 backgroundColor: dimPalette.contrast_600,
554 },
555 bg_contrast_700: {
556 backgroundColor: dimPalette.contrast_700,
557 },
558 bg_contrast_800: {
559 backgroundColor: dimPalette.contrast_800,
560 },
561 bg_contrast_900: {
562 backgroundColor: dimPalette.contrast_900,
563 },
564 bg_contrast_950: {
565 backgroundColor: dimPalette.contrast_950,
566 },
567 bg_contrast_975: {
568 backgroundColor: dimPalette.contrast_975,
569 },
570 border_contrast_low: {
571 borderColor: dimPalette.contrast_100,
572 },
573 border_contrast_medium: {
574 borderColor: dimPalette.contrast_200,
575 },
576 border_contrast_high: {
577 borderColor: dimPalette.contrast_300,
578 },
579 shadow_sm: {
580 ...atoms.shadow_sm,
581 shadowOpacity: 0.7,
582 shadowColor: `hsl(${hues.primary}, 28%, 6%)`,
583 },
584 shadow_md: {
585 ...atoms.shadow_md,
586 shadowOpacity: 0.7,
587 shadowColor: `hsl(${hues.primary}, 28%, 6%)`,
588 },
589 shadow_lg: {
590 ...atoms.shadow_lg,
591 shadowOpacity: 0.7,
592 shadowColor: `hsl(${hues.primary}, 28%, 6%)`,
593 },
594 trending_hot: {
595 color: mocha.crust,
596 backgroundColor: mocha.red,
597 },
598 trending_new: {
599 color: mocha.crust,
600 backgroundColor: mocha.green,
601 },
602 },
603 }
604
605 return {
606 lightPalette,
607 darkPalette,
608 dimPalette,
609 light,
610 dark,
611 dim,
612 }
613}