7
7
*/
8
8
9
9
import {
10
- Brand as BrandJson ,
10
+ BrandColorLightDark ,
11
11
BrandFont ,
12
12
BrandLogoExplicitResource ,
13
13
BrandNamedThemeColor ,
14
- BrandTypography ,
14
+ BrandSingle ,
15
15
BrandTypographyOptionsBase ,
16
- BrandTypographyOptionsHeadings ,
16
+ BrandTypographyOptionsHeadingsSingle ,
17
+ BrandTypographySingle ,
18
+ BrandTypographyUnified ,
19
+ BrandUnified ,
17
20
Zod ,
18
21
} from "../../resources/types/zod/schema-types.ts" ;
19
22
import { InternalError } from "../lib/error.ts" ;
@@ -53,7 +56,7 @@ type CanonicalLogoInfo = {
53
56
54
57
type ProcessedBrandData = {
55
58
color : Record < string , string > ;
56
- typography : BrandTypography ;
59
+ typography : BrandTypographySingle ;
57
60
logo : {
58
61
small ?: CanonicalLogoInfo ;
59
62
medium ?: CanonicalLogoInfo ;
@@ -63,7 +66,7 @@ type ProcessedBrandData = {
63
66
} ;
64
67
65
68
export class Brand {
66
- data : BrandJson ;
69
+ data : BrandSingle ;
67
70
brandDir : string ;
68
71
projectDir : string ;
69
72
processedData : ProcessedBrandData ;
@@ -73,13 +76,13 @@ export class Brand {
73
76
brandDir : string ,
74
77
projectDir : string ,
75
78
) {
76
- this . data = Zod . Brand . parse ( brand ) ;
79
+ this . data = Zod . BrandSingle . parse ( brand ) ;
77
80
this . brandDir = brandDir ;
78
81
this . projectDir = projectDir ;
79
82
this . processedData = this . processData ( this . data ) ;
80
83
}
81
84
82
- processData ( data : BrandJson ) : ProcessedBrandData {
85
+ processData ( data : BrandSingle ) : ProcessedBrandData {
83
86
const color : Record < string , string > = { } ;
84
87
for ( const colorName of Object . keys ( data . color ?. palette ?? { } ) ) {
85
88
color [ colorName ] = this . getColor ( colorName ) ;
@@ -91,7 +94,7 @@ export class Brand {
91
94
color [ colorName ] = this . getColor ( colorName ) ;
92
95
}
93
96
94
- const typography : BrandTypography = { } ;
97
+ const typography : BrandTypographySingle = { } ;
95
98
const base = this . getFont ( "base" ) ;
96
99
if ( base ) {
97
100
typography . base = base ;
@@ -221,7 +224,10 @@ export class Brand {
221
224
222
225
getFont (
223
226
name : string ,
224
- ) : BrandTypographyOptionsBase | BrandTypographyOptionsHeadings | undefined {
227
+ ) :
228
+ | BrandTypographyOptionsBase
229
+ | BrandTypographyOptionsHeadingsSingle
230
+ | undefined {
225
231
if ( ! this . data . typography ) {
226
232
return undefined ;
227
233
}
@@ -304,10 +310,253 @@ export type LightDarkBrand = {
304
310
dark ?: Brand ;
305
311
} ;
306
312
313
+ export type LightDarkColor = {
314
+ light ?: string ;
315
+ dark ?: string ;
316
+ } ;
317
+
307
318
export const getFavicon = ( brand : Brand ) : string | undefined => {
308
319
const logoInfo = brand . getLogo ( "small" ) ;
309
320
if ( ! logoInfo ) {
310
321
return undefined ;
311
322
}
312
323
return logoInfo . light . path ;
313
324
} ;
325
+
326
+ function splitColorLightDark (
327
+ bcld : BrandColorLightDark ,
328
+ ) : LightDarkColor {
329
+ if ( typeof bcld === "string" ) {
330
+ return { light : bcld , dark : bcld } ;
331
+ }
332
+ return bcld ;
333
+ }
334
+ function colorIsUnified ( blcd : BrandColorLightDark ) {
335
+ return typeof blcd === "object" && "dark" in blcd ;
336
+ }
337
+ export function brandIsUnified ( brand : BrandUnified ) : boolean {
338
+ if ( brand . color ) {
339
+ for ( const colorName of Zod . BrandNamedThemeColor . options ) {
340
+ if ( ! brand . color [ colorName ] ) {
341
+ continue ;
342
+ }
343
+ if ( colorIsUnified ( brand . color ! [ colorName ] ) ) {
344
+ return true ;
345
+ }
346
+ }
347
+ }
348
+ if ( brand . typography ) {
349
+ for ( const elementName of Zod . BrandNamedTypographyElements . options ) {
350
+ const element = brand . typography ! [ elementName ] ;
351
+ if ( ! element || typeof element === "string" ) {
352
+ continue ;
353
+ }
354
+ if (
355
+ "background-color" in element && element [ "background-color" ] &&
356
+ colorIsUnified ( element [ "background-color" ] )
357
+ ) {
358
+ return true ;
359
+ }
360
+ if (
361
+ "color" in element && element [ "color" ] &&
362
+ colorIsUnified ( element [ "color" ] )
363
+ ) {
364
+ return true ;
365
+ }
366
+ }
367
+ }
368
+ return false ;
369
+ }
370
+ function sharedTypography (
371
+ unified : BrandTypographyUnified ,
372
+ ) : BrandTypographySingle {
373
+ const ret : BrandTypographySingle = {
374
+ fonts : unified . fonts ,
375
+ } ;
376
+ for ( const elementName of Zod . BrandNamedTypographyElements . options ) {
377
+ if ( ! unified [ elementName ] ) {
378
+ continue ;
379
+ }
380
+ if ( typeof unified [ elementName ] === "string" ) {
381
+ ret [ elementName ] = unified [ elementName ] ;
382
+ continue ;
383
+ }
384
+ ret [ elementName ] = Object . fromEntries (
385
+ Object . entries ( unified [ elementName ] ) . filter (
386
+ ( [ key , _ ] ) => ! [ "color" , "background-color" ] . includes ( key ) ,
387
+ ) ,
388
+ ) ;
389
+ }
390
+ return ret ;
391
+ }
392
+ export function splitUnifiedBrand (
393
+ unified : unknown ,
394
+ brandDir : string ,
395
+ projectDir : string ,
396
+ ) : LightDarkBrand {
397
+ const unifiedBrand : BrandUnified = Zod . BrandUnified . parse ( unified ) ;
398
+ let typography : BrandTypographySingle | undefined = undefined ;
399
+ let headingsColor : LightDarkColor | undefined = undefined ;
400
+ let monospaceColor : LightDarkColor | undefined = undefined ;
401
+ let monospaceBackgroundColor : LightDarkColor | undefined = undefined ;
402
+ let monospaceInlineColor : LightDarkColor | undefined = undefined ;
403
+ let monospaceInlineBackgroundColor : LightDarkColor | undefined = undefined ;
404
+ let monospaceBlockColor : LightDarkColor | undefined = undefined ;
405
+ let monospaceBlockBackgroundColor : LightDarkColor | undefined = undefined ;
406
+ let linkColor : LightDarkColor | undefined = undefined ;
407
+ let linkBackgroundColor : LightDarkColor | undefined = undefined ;
408
+ if ( unifiedBrand . typography ) {
409
+ typography = sharedTypography ( unifiedBrand . typography ) ;
410
+ if (
411
+ unifiedBrand . typography . headings &&
412
+ typeof unifiedBrand . typography . headings !== "string" &&
413
+ unifiedBrand . typography . headings . color
414
+ ) {
415
+ headingsColor = splitColorLightDark (
416
+ unifiedBrand . typography . headings . color ,
417
+ ) ;
418
+ }
419
+ if (
420
+ unifiedBrand . typography . monospace &&
421
+ typeof unifiedBrand . typography . monospace !== "string"
422
+ ) {
423
+ if ( unifiedBrand . typography . monospace . color ) {
424
+ monospaceColor = splitColorLightDark (
425
+ unifiedBrand . typography . monospace . color ,
426
+ ) ;
427
+ }
428
+ if ( unifiedBrand . typography . monospace [ "background-color" ] ) {
429
+ monospaceBackgroundColor = splitColorLightDark (
430
+ unifiedBrand . typography . monospace [ "background-color" ] ,
431
+ ) ;
432
+ }
433
+ }
434
+ if (
435
+ unifiedBrand . typography [ "monospace-inline" ] &&
436
+ typeof unifiedBrand . typography [ "monospace-inline" ] !== "string"
437
+ ) {
438
+ if ( unifiedBrand . typography [ "monospace-inline" ] . color ) {
439
+ monospaceInlineColor = splitColorLightDark (
440
+ unifiedBrand . typography [ "monospace-inline" ] . color ,
441
+ ) ;
442
+ }
443
+ if ( unifiedBrand . typography [ "monospace-inline" ] [ "background-color" ] ) {
444
+ monospaceInlineBackgroundColor = splitColorLightDark (
445
+ unifiedBrand . typography [ "monospace-inline" ] [ "background-color" ] ,
446
+ ) ;
447
+ }
448
+ }
449
+ if (
450
+ unifiedBrand . typography [ "monospace-block" ] &&
451
+ typeof unifiedBrand . typography [ "monospace-block" ] !== "string"
452
+ ) {
453
+ if ( unifiedBrand . typography [ "monospace-block" ] . color ) {
454
+ monospaceBlockColor = splitColorLightDark (
455
+ unifiedBrand . typography [ "monospace-block" ] . color ,
456
+ ) ;
457
+ }
458
+ if ( unifiedBrand . typography [ "monospace-block" ] [ "background-color" ] ) {
459
+ monospaceBlockBackgroundColor = splitColorLightDark (
460
+ unifiedBrand . typography [ "monospace-block" ] [ "background-color" ] ,
461
+ ) ;
462
+ }
463
+ }
464
+ if (
465
+ unifiedBrand . typography . link &&
466
+ typeof unifiedBrand . typography . link !== "string"
467
+ ) {
468
+ if ( unifiedBrand . typography . link . color ) {
469
+ linkColor = splitColorLightDark (
470
+ unifiedBrand . typography . link . color ,
471
+ ) ;
472
+ }
473
+ if ( unifiedBrand . typography . link [ "background-color" ] ) {
474
+ linkBackgroundColor = splitColorLightDark (
475
+ unifiedBrand . typography . link [ "background-color" ] ,
476
+ ) ;
477
+ }
478
+ }
479
+ }
480
+ const specializeTypography = (
481
+ typography : BrandTypographySingle ,
482
+ mode : "light" | "dark" ,
483
+ ) =>
484
+ typography && {
485
+ fonts : typography . fonts && [ ...typography . fonts ] ,
486
+ base : ! typography . base || typeof typography . base === "string"
487
+ ? typography . base
488
+ : { ...typography . base } ,
489
+ headings : ! typography . headings || typeof typography . headings === "string"
490
+ ? typography . headings
491
+ : {
492
+ ...typography . headings ,
493
+ color : headingsColor && headingsColor [ mode ] ,
494
+ } ,
495
+ monospace :
496
+ ! typography . monospace || typeof typography . monospace === "string"
497
+ ? typography . monospace
498
+ : {
499
+ ...typography . monospace ,
500
+ color : monospaceColor && monospaceColor [ mode ] ,
501
+ "background-color" : monospaceBackgroundColor &&
502
+ monospaceBackgroundColor [ mode ] ,
503
+ } ,
504
+ "monospace-inline" : ! typography [ "monospace-inline" ] ||
505
+ typeof typography [ "monospace-inline" ] === "string"
506
+ ? typography [ "monospace-inline" ]
507
+ : {
508
+ ...typography [ "monospace-inline" ] ,
509
+ color : monospaceInlineColor && monospaceInlineColor [ mode ] ,
510
+ "background-color" : monospaceInlineBackgroundColor &&
511
+ monospaceInlineBackgroundColor [ mode ] ,
512
+ } ,
513
+ "monospace-block" : ! typography [ "monospace-block" ] ||
514
+ typeof typography [ "monospace-block" ] === "string"
515
+ ? typography [ "monospace-block" ]
516
+ : {
517
+ ...typography [ "monospace-block" ] ,
518
+ color : monospaceBlockColor && monospaceBlockColor [ mode ] ,
519
+ "background-color" : monospaceBlockBackgroundColor &&
520
+ monospaceBlockBackgroundColor [ mode ] ,
521
+ } ,
522
+ link : ! typography . link || typeof typography . link === "string"
523
+ ? typography . link
524
+ : {
525
+ ...typography . link ,
526
+ color : linkColor && linkColor [ mode ] ,
527
+ "background-color" : linkBackgroundColor &&
528
+ linkBackgroundColor [ mode ] ,
529
+ } ,
530
+ } ;
531
+ const lightBrand : BrandSingle = {
532
+ meta : unifiedBrand . meta ,
533
+ color : { palette : unifiedBrand . color && { ...unifiedBrand . color . palette } } ,
534
+ typography : typography && specializeTypography ( typography , "light" ) ,
535
+ logo : unifiedBrand . logo ,
536
+ defaults : unifiedBrand . defaults ,
537
+ } ;
538
+ const darkBrand : BrandSingle = {
539
+ meta : unifiedBrand . meta ,
540
+ color : { palette : unifiedBrand . color && { ...unifiedBrand . color . palette } } ,
541
+ typography : typography && specializeTypography ( typography , "dark" ) ,
542
+ logo : unifiedBrand . logo ,
543
+ defaults : unifiedBrand . defaults ,
544
+ } ;
545
+ if ( unifiedBrand . color ) {
546
+ for ( const colorName of Zod . BrandNamedThemeColor . options ) {
547
+ if ( ! unifiedBrand . color [ colorName ] ) {
548
+ continue ;
549
+ }
550
+ ( {
551
+ light : lightBrand . color ! [ colorName ] ,
552
+ dark : darkBrand . color ! [ colorName ] ,
553
+ } = splitColorLightDark ( unifiedBrand . color ! [ colorName ] ) ) ;
554
+ }
555
+ }
556
+ return {
557
+ light : new Brand ( lightBrand , brandDir , projectDir ) ,
558
+ dark : brandIsUnified ( unifiedBrand )
559
+ ? new Brand ( darkBrand , brandDir , projectDir )
560
+ : undefined ,
561
+ } ;
562
+ }
0 commit comments