dsh-theme-gallery 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -4
- package/lib/client.js +1887 -235
- package/lib/index.js +12 -2
- package/lib/themes/pei-an-jie-xin.json +290 -0
- package/lib/themes/ying-mu-cai-yun.json +290 -0
- package/package.json +3 -2
- package/schema/theme.schema.json +33 -3
package/lib/client.js
CHANGED
|
@@ -105,6 +105,21 @@ window.__ModuleLoader__.load({
|
|
|
105
105
|
*/
|
|
106
106
|
const READING = { bg: '#FFFFFF', alpha: 0.62, blur: 3, maxWidth: 640 }
|
|
107
107
|
|
|
108
|
+
/**
|
|
109
|
+
* The package version this bundle was built from.
|
|
110
|
+
*
|
|
111
|
+
* Written by `scripts/embed-themes.mjs` from package.json, because the browser
|
|
112
|
+
* half cannot read its own manifest: the client module system resolves `require`
|
|
113
|
+
* against the platform seed table and other plugins' boot-graph rows, not
|
|
114
|
+
* against this package's files. The panel shows it so a reader can compare what
|
|
115
|
+
* they have with what npm publishes.
|
|
116
|
+
*
|
|
117
|
+
* Kept honest by two checks: `scripts/publish-check.mjs` compares it with
|
|
118
|
+
* package.json, and the release workflow fails when re-running the embed step
|
|
119
|
+
* changes a tracked file.
|
|
120
|
+
*/
|
|
121
|
+
const BUNDLED_VERSION = '0.2.0'
|
|
122
|
+
|
|
108
123
|
/**
|
|
109
124
|
* Themes this package contributes, inlined from lib/themes/*.json.
|
|
110
125
|
*
|
|
@@ -406,6 +421,294 @@ window.__ModuleLoader__.load({
|
|
|
406
421
|
"fish": 3
|
|
407
422
|
}
|
|
408
423
|
},
|
|
424
|
+
{
|
|
425
|
+
"id": "pei-an-jie-xin",
|
|
426
|
+
"label": "佩安杰心",
|
|
427
|
+
"description": "檀香禅影,自在安顿 —— 复刻自电商新零售系统管理后台同名主题",
|
|
428
|
+
"colorScheme": "light",
|
|
429
|
+
"tokens": {
|
|
430
|
+
"--dsw-alias-bg-base": {
|
|
431
|
+
"light": "linear-gradient(to bottom,#FCFAF5 0%,#F8F3E9 55%,#F3ECDD 100%)",
|
|
432
|
+
"dark": "linear-gradient(to bottom,#FCFAF5 0%,#F8F3E9 55%,#F3ECDD 100%)"
|
|
433
|
+
},
|
|
434
|
+
"--dsw-alias-bg-layer-1": {
|
|
435
|
+
"light": "#FDFBF7",
|
|
436
|
+
"dark": "#FDFBF7"
|
|
437
|
+
},
|
|
438
|
+
"--dsw-alias-bg-layer-2": {
|
|
439
|
+
"light": "#FFFFFF",
|
|
440
|
+
"dark": "#FFFFFF"
|
|
441
|
+
},
|
|
442
|
+
"--dsw-alias-bg-layer-3": {
|
|
443
|
+
"light": "#FFFFFF",
|
|
444
|
+
"dark": "#FFFFFF"
|
|
445
|
+
},
|
|
446
|
+
"--dsw-alias-bg-overlay": {
|
|
447
|
+
"light": "#EFE7D7",
|
|
448
|
+
"dark": "#EFE7D7"
|
|
449
|
+
},
|
|
450
|
+
"--dsw-alias-bg-skeleton": {
|
|
451
|
+
"light": "#7A5C3E14",
|
|
452
|
+
"dark": "#7A5C3E14"
|
|
453
|
+
},
|
|
454
|
+
"--dsw-alias-bg-module-platform": {
|
|
455
|
+
"light": "#F3EBDD",
|
|
456
|
+
"dark": "#F3EBDD"
|
|
457
|
+
},
|
|
458
|
+
"--dsw-alias-bg-multi-select": {
|
|
459
|
+
"light": "#F3EBDD",
|
|
460
|
+
"dark": "#F3EBDD"
|
|
461
|
+
},
|
|
462
|
+
"--dsw-alias-border-l1": {
|
|
463
|
+
"light": "#7A5C3E0F",
|
|
464
|
+
"dark": "#7A5C3E0F"
|
|
465
|
+
},
|
|
466
|
+
"--dsw-alias-border-l2": {
|
|
467
|
+
"light": "#7A5C3E21",
|
|
468
|
+
"dark": "#7A5C3E21"
|
|
469
|
+
},
|
|
470
|
+
"--dsw-alias-border-l3": {
|
|
471
|
+
"light": "#7A5C3E2E",
|
|
472
|
+
"dark": "#7A5C3E2E"
|
|
473
|
+
},
|
|
474
|
+
"--dsw-alias-border-l4": {
|
|
475
|
+
"light": "#7A5C3E3D",
|
|
476
|
+
"dark": "#7A5C3E3D"
|
|
477
|
+
},
|
|
478
|
+
"--dsw-alias-brand-primary": {
|
|
479
|
+
"light": "#7A5C3E",
|
|
480
|
+
"dark": "#7A5C3E"
|
|
481
|
+
},
|
|
482
|
+
"--dsw-alias-brand-primary-invert": {
|
|
483
|
+
"light": "#FFFFFF",
|
|
484
|
+
"dark": "#FFFFFF"
|
|
485
|
+
},
|
|
486
|
+
"--dsw-alias-brand-text": {
|
|
487
|
+
"light": "#7A5C3E",
|
|
488
|
+
"dark": "#7A5C3E"
|
|
489
|
+
},
|
|
490
|
+
"--dsw-alias-label-primary": {
|
|
491
|
+
"light": "#3F3222",
|
|
492
|
+
"dark": "#3F3222"
|
|
493
|
+
},
|
|
494
|
+
"--dsw-alias-label-primary-bluish": {
|
|
495
|
+
"light": "#3F3222",
|
|
496
|
+
"dark": "#3F3222"
|
|
497
|
+
},
|
|
498
|
+
"--dsw-alias-label-secondary": {
|
|
499
|
+
"light": "#5E4A38",
|
|
500
|
+
"dark": "#5E4A38"
|
|
501
|
+
},
|
|
502
|
+
"--dsw-alias-label-tertiary": {
|
|
503
|
+
"light": "#85705A",
|
|
504
|
+
"dark": "#85705A"
|
|
505
|
+
},
|
|
506
|
+
"--dsw-alias-label-caption": {
|
|
507
|
+
"light": "#85705A",
|
|
508
|
+
"dark": "#85705A"
|
|
509
|
+
},
|
|
510
|
+
"--dsw-alias-label-dimmed": {
|
|
511
|
+
"light": "#AC9C86",
|
|
512
|
+
"dark": "#AC9C86"
|
|
513
|
+
},
|
|
514
|
+
"--dsw-alias-label-primary-dimmed": {
|
|
515
|
+
"light": "#5E4A38",
|
|
516
|
+
"dark": "#5E4A38"
|
|
517
|
+
},
|
|
518
|
+
"--dsw-alias-label-primary-foreground": {
|
|
519
|
+
"light": "#FFFFFF",
|
|
520
|
+
"dark": "#FFFFFF"
|
|
521
|
+
},
|
|
522
|
+
"--dsw-alias-label-primary-inverted": {
|
|
523
|
+
"light": "#FFFFFF",
|
|
524
|
+
"dark": "#FFFFFF"
|
|
525
|
+
},
|
|
526
|
+
"--dsw-alias-link": {
|
|
527
|
+
"light": "#B4653A",
|
|
528
|
+
"dark": "#B4653A"
|
|
529
|
+
},
|
|
530
|
+
"--dsw-alias-interactive-bg-hover": {
|
|
531
|
+
"light": "#9C7B5814",
|
|
532
|
+
"dark": "#9C7B5814"
|
|
533
|
+
},
|
|
534
|
+
"--dsw-alias-interactive-bg-active": {
|
|
535
|
+
"light": "#B4653A2E",
|
|
536
|
+
"dark": "#B4653A2E"
|
|
537
|
+
},
|
|
538
|
+
"--dsw-alias-interactive-bg-hover-solid": {
|
|
539
|
+
"light": "#F3EBDD",
|
|
540
|
+
"dark": "#F3EBDD"
|
|
541
|
+
},
|
|
542
|
+
"--dsw-alias-interactive-bg-hover-accent": {
|
|
543
|
+
"light": "#B4653A3D",
|
|
544
|
+
"dark": "#B4653A3D"
|
|
545
|
+
},
|
|
546
|
+
"--dsw-alias-button-primary-fill": {
|
|
547
|
+
"light": "#7A5C3E",
|
|
548
|
+
"dark": "#7A5C3E"
|
|
549
|
+
},
|
|
550
|
+
"--dsw-alias-button-primary-hover": {
|
|
551
|
+
"light": "#9C7B58",
|
|
552
|
+
"dark": "#9C7B58"
|
|
553
|
+
},
|
|
554
|
+
"--dsw-alias-button-primary-dimmed": {
|
|
555
|
+
"light": "#7A5C3E47",
|
|
556
|
+
"dark": "#7A5C3E47"
|
|
557
|
+
},
|
|
558
|
+
"--dsw-alias-button-ghost-active-fill": {
|
|
559
|
+
"light": "#B4653A29",
|
|
560
|
+
"dark": "#B4653A29"
|
|
561
|
+
},
|
|
562
|
+
"--dsw-alias-button-ghost-active-border": {
|
|
563
|
+
"light": "#B4653A",
|
|
564
|
+
"dark": "#B4653A"
|
|
565
|
+
},
|
|
566
|
+
"--dsw-alias-button-ghost-active-hover": {
|
|
567
|
+
"light": "#B4653A47",
|
|
568
|
+
"dark": "#B4653A47"
|
|
569
|
+
},
|
|
570
|
+
"--dsw-alias-button-info-fill": {
|
|
571
|
+
"light": "#9C7B58",
|
|
572
|
+
"dark": "#9C7B58"
|
|
573
|
+
},
|
|
574
|
+
"--dsw-alias-button-info-hover": {
|
|
575
|
+
"light": "#8A6E52",
|
|
576
|
+
"dark": "#8A6E52"
|
|
577
|
+
},
|
|
578
|
+
"--dsw-alias-button-elevated-fill": {
|
|
579
|
+
"light": "#FFFFFF",
|
|
580
|
+
"dark": "#FFFFFF"
|
|
581
|
+
},
|
|
582
|
+
"--dsw-alias-button-floating-fill": {
|
|
583
|
+
"light": "#FFFFFF",
|
|
584
|
+
"dark": "#FFFFFF"
|
|
585
|
+
},
|
|
586
|
+
"--dsw-alias-button-floating-hover": {
|
|
587
|
+
"light": "#FAF6EE",
|
|
588
|
+
"dark": "#FAF6EE"
|
|
589
|
+
},
|
|
590
|
+
"--dsw-alias-button-contrast-fill": {
|
|
591
|
+
"light": "#3F3222",
|
|
592
|
+
"dark": "#3F3222"
|
|
593
|
+
},
|
|
594
|
+
"--dsw-alias-markdown-code-block": {
|
|
595
|
+
"light": "#F5EFE3",
|
|
596
|
+
"dark": "#F5EFE3"
|
|
597
|
+
},
|
|
598
|
+
"--dsw-alias-markdown-code-block-banner": {
|
|
599
|
+
"light": "#EDE4D2",
|
|
600
|
+
"dark": "#EDE4D2"
|
|
601
|
+
},
|
|
602
|
+
"--dsw-alias-markdown-inline-code": {
|
|
603
|
+
"light": "#F3EBDD",
|
|
604
|
+
"dark": "#F3EBDD"
|
|
605
|
+
},
|
|
606
|
+
"--dsw-alias-markdown-citation": {
|
|
607
|
+
"light": "#F3EBDD",
|
|
608
|
+
"dark": "#F3EBDD"
|
|
609
|
+
},
|
|
610
|
+
"--dsw-alias-markdown-tag": {
|
|
611
|
+
"light": "#F3EBDD",
|
|
612
|
+
"dark": "#F3EBDD"
|
|
613
|
+
},
|
|
614
|
+
"--dsw-alias-markdown-placeholder": {
|
|
615
|
+
"light": "#EDE4D2",
|
|
616
|
+
"dark": "#EDE4D2"
|
|
617
|
+
},
|
|
618
|
+
"--dsw-alias-markdown-code-segment-selected": {
|
|
619
|
+
"light": "#B4653A29",
|
|
620
|
+
"dark": "#B4653A29"
|
|
621
|
+
},
|
|
622
|
+
"--dsw-alias-markdown-code-segment-unselected": {
|
|
623
|
+
"light": "#F5EFE3",
|
|
624
|
+
"dark": "#F5EFE3"
|
|
625
|
+
},
|
|
626
|
+
"--dsw-alias-scrollbar-bg-l1": {
|
|
627
|
+
"light": "#7A5C3E29",
|
|
628
|
+
"dark": "#7A5C3E29"
|
|
629
|
+
},
|
|
630
|
+
"--dsw-alias-scrollbar-bg-l2": {
|
|
631
|
+
"light": "#7A5C3E38",
|
|
632
|
+
"dark": "#7A5C3E38"
|
|
633
|
+
},
|
|
634
|
+
"--dsw-alias-scrollbar-hover-l1": {
|
|
635
|
+
"light": "#7A5C3E52",
|
|
636
|
+
"dark": "#7A5C3E52"
|
|
637
|
+
},
|
|
638
|
+
"--dsw-alias-scrollbar-hover-l2": {
|
|
639
|
+
"light": "#7A5C3E66",
|
|
640
|
+
"dark": "#7A5C3E66"
|
|
641
|
+
},
|
|
642
|
+
"--dsw-alias-tooltip-bg": {
|
|
643
|
+
"light": "#3F3222",
|
|
644
|
+
"dark": "#3F3222"
|
|
645
|
+
},
|
|
646
|
+
"--dsw-alias-toast-bg": {
|
|
647
|
+
"light": "#FFFFFF",
|
|
648
|
+
"dark": "#FFFFFF"
|
|
649
|
+
},
|
|
650
|
+
"--dsw-alias-state-error-primary": {
|
|
651
|
+
"light": "#C65B6A",
|
|
652
|
+
"dark": "#C65B6A"
|
|
653
|
+
},
|
|
654
|
+
"--dsw-alias-state-error-secondary": {
|
|
655
|
+
"light": "#DB5A6B",
|
|
656
|
+
"dark": "#DB5A6B"
|
|
657
|
+
},
|
|
658
|
+
"--dsw-alias-state-success-primary": {
|
|
659
|
+
"light": "#21A675",
|
|
660
|
+
"dark": "#21A675"
|
|
661
|
+
},
|
|
662
|
+
"--dsw-alias-state-success-secondary": {
|
|
663
|
+
"light": "#7A5C3E",
|
|
664
|
+
"dark": "#7A5C3E"
|
|
665
|
+
},
|
|
666
|
+
"--dsw-alias-state-success-tertiary": {
|
|
667
|
+
"light": "#C4B39A",
|
|
668
|
+
"dark": "#C4B39A"
|
|
669
|
+
},
|
|
670
|
+
"--dsw-alias-state-warn-primary": {
|
|
671
|
+
"light": "#B97F3A",
|
|
672
|
+
"dark": "#B97F3A"
|
|
673
|
+
},
|
|
674
|
+
"--dsw-alias-state-warn-secondary": {
|
|
675
|
+
"light": "#D9A45E",
|
|
676
|
+
"dark": "#D9A45E"
|
|
677
|
+
},
|
|
678
|
+
"--dsw-alias-state-warn-tertiary": {
|
|
679
|
+
"light": "#EFDCC0",
|
|
680
|
+
"dark": "#EFDCC0"
|
|
681
|
+
},
|
|
682
|
+
"--dsw-alias-state-warn-label": {
|
|
683
|
+
"light": "#8A5A22",
|
|
684
|
+
"dark": "#8A5A22"
|
|
685
|
+
},
|
|
686
|
+
"--dsw-alias-state-business-primary": {
|
|
687
|
+
"light": "#B4653A",
|
|
688
|
+
"dark": "#B4653A"
|
|
689
|
+
},
|
|
690
|
+
"--dsw-alias-state-business-tertiary": {
|
|
691
|
+
"light": "#D08A5C",
|
|
692
|
+
"dark": "#D08A5C"
|
|
693
|
+
},
|
|
694
|
+
"--dsw-specific-sidebar-fill": {
|
|
695
|
+
"light": "linear-gradient(to bottom,#F2E8D8 0%,#EBDCC4 22%,#E0CDAD 42%,#D4BC98 60%,#C3A87F 78%,#A98D6B 100%)",
|
|
696
|
+
"dark": "linear-gradient(to bottom,#F2E8D8 0%,#EBDCC4 22%,#E0CDAD 42%,#D4BC98 60%,#C3A87F 78%,#A98D6B 100%)"
|
|
697
|
+
}
|
|
698
|
+
},
|
|
699
|
+
"reading": {
|
|
700
|
+
"colorScheme": "light",
|
|
701
|
+
"bg": "#FFFFFF",
|
|
702
|
+
"alpha": 0.62,
|
|
703
|
+
"blur": 3,
|
|
704
|
+
"maxWidth": 640
|
|
705
|
+
},
|
|
706
|
+
"accent": "#B4653A",
|
|
707
|
+
"ambient": {
|
|
708
|
+
"kind": "jiexin",
|
|
709
|
+
"dust": 4
|
|
710
|
+
}
|
|
711
|
+
},
|
|
409
712
|
{
|
|
410
713
|
"id": "shan-qing-ting-cai",
|
|
411
714
|
"label": "山青婷彩",
|
|
@@ -693,79 +996,367 @@ window.__ModuleLoader__.load({
|
|
|
693
996
|
"kind": "shan",
|
|
694
997
|
"petals": 7
|
|
695
998
|
}
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
999
|
+
},
|
|
1000
|
+
{
|
|
1001
|
+
"id": "ying-mu-cai-yun",
|
|
1002
|
+
"label": "营慕彩云",
|
|
1003
|
+
"description": "营幕之下,彩云为伴 —— 复刻自电商新零售系统管理后台同名主题",
|
|
1004
|
+
"colorScheme": "light",
|
|
1005
|
+
"tokens": {
|
|
1006
|
+
"--dsw-alias-bg-base": {
|
|
1007
|
+
"light": "linear-gradient(to bottom,#FBFCF8 0%,#F5F8EF 55%,#EEF3E4 100%)",
|
|
1008
|
+
"dark": "linear-gradient(to bottom,#FBFCF8 0%,#F5F8EF 55%,#EEF3E4 100%)"
|
|
1009
|
+
},
|
|
1010
|
+
"--dsw-alias-bg-layer-1": {
|
|
1011
|
+
"light": "#FBFDF7",
|
|
1012
|
+
"dark": "#FBFDF7"
|
|
1013
|
+
},
|
|
1014
|
+
"--dsw-alias-bg-layer-2": {
|
|
1015
|
+
"light": "#FFFFFF",
|
|
1016
|
+
"dark": "#FFFFFF"
|
|
1017
|
+
},
|
|
1018
|
+
"--dsw-alias-bg-layer-3": {
|
|
1019
|
+
"light": "#FFFFFF",
|
|
1020
|
+
"dark": "#FFFFFF"
|
|
1021
|
+
},
|
|
1022
|
+
"--dsw-alias-bg-overlay": {
|
|
1023
|
+
"light": "#E7EFE0",
|
|
1024
|
+
"dark": "#E7EFE0"
|
|
1025
|
+
},
|
|
1026
|
+
"--dsw-alias-bg-skeleton": {
|
|
1027
|
+
"light": "#2D5A3D14",
|
|
1028
|
+
"dark": "#2D5A3D14"
|
|
1029
|
+
},
|
|
1030
|
+
"--dsw-alias-bg-module-platform": {
|
|
1031
|
+
"light": "#ECF3E6",
|
|
1032
|
+
"dark": "#ECF3E6"
|
|
1033
|
+
},
|
|
1034
|
+
"--dsw-alias-bg-multi-select": {
|
|
1035
|
+
"light": "#ECF3E6",
|
|
1036
|
+
"dark": "#ECF3E6"
|
|
1037
|
+
},
|
|
1038
|
+
"--dsw-alias-border-l1": {
|
|
1039
|
+
"light": "#2D5A3D0F",
|
|
1040
|
+
"dark": "#2D5A3D0F"
|
|
1041
|
+
},
|
|
1042
|
+
"--dsw-alias-border-l2": {
|
|
1043
|
+
"light": "#2D5A3D21",
|
|
1044
|
+
"dark": "#2D5A3D21"
|
|
1045
|
+
},
|
|
1046
|
+
"--dsw-alias-border-l3": {
|
|
1047
|
+
"light": "#2D5A3D2E",
|
|
1048
|
+
"dark": "#2D5A3D2E"
|
|
1049
|
+
},
|
|
1050
|
+
"--dsw-alias-border-l4": {
|
|
1051
|
+
"light": "#2D5A3D3D",
|
|
1052
|
+
"dark": "#2D5A3D3D"
|
|
1053
|
+
},
|
|
1054
|
+
"--dsw-alias-brand-primary": {
|
|
1055
|
+
"light": "#2D5A3D",
|
|
1056
|
+
"dark": "#2D5A3D"
|
|
1057
|
+
},
|
|
1058
|
+
"--dsw-alias-brand-primary-invert": {
|
|
1059
|
+
"light": "#FFFFFF",
|
|
1060
|
+
"dark": "#FFFFFF"
|
|
1061
|
+
},
|
|
1062
|
+
"--dsw-alias-brand-text": {
|
|
1063
|
+
"light": "#2D5A3D",
|
|
1064
|
+
"dark": "#2D5A3D"
|
|
1065
|
+
},
|
|
1066
|
+
"--dsw-alias-label-primary": {
|
|
1067
|
+
"light": "#234030",
|
|
1068
|
+
"dark": "#234030"
|
|
1069
|
+
},
|
|
1070
|
+
"--dsw-alias-label-primary-bluish": {
|
|
1071
|
+
"light": "#234030",
|
|
1072
|
+
"dark": "#234030"
|
|
1073
|
+
},
|
|
1074
|
+
"--dsw-alias-label-secondary": {
|
|
1075
|
+
"light": "#3E6B4A",
|
|
1076
|
+
"dark": "#3E6B4A"
|
|
1077
|
+
},
|
|
1078
|
+
"--dsw-alias-label-tertiary": {
|
|
1079
|
+
"light": "#62816C",
|
|
1080
|
+
"dark": "#62816C"
|
|
1081
|
+
},
|
|
1082
|
+
"--dsw-alias-label-caption": {
|
|
1083
|
+
"light": "#62816C",
|
|
1084
|
+
"dark": "#62816C"
|
|
1085
|
+
},
|
|
1086
|
+
"--dsw-alias-label-dimmed": {
|
|
1087
|
+
"light": "#93A996",
|
|
1088
|
+
"dark": "#93A996"
|
|
1089
|
+
},
|
|
1090
|
+
"--dsw-alias-label-primary-dimmed": {
|
|
1091
|
+
"light": "#3E6B4A",
|
|
1092
|
+
"dark": "#3E6B4A"
|
|
1093
|
+
},
|
|
1094
|
+
"--dsw-alias-label-primary-foreground": {
|
|
1095
|
+
"light": "#FFFFFF",
|
|
1096
|
+
"dark": "#FFFFFF"
|
|
1097
|
+
},
|
|
1098
|
+
"--dsw-alias-label-primary-inverted": {
|
|
1099
|
+
"light": "#FFFFFF",
|
|
1100
|
+
"dark": "#FFFFFF"
|
|
1101
|
+
},
|
|
1102
|
+
"--dsw-alias-link": {
|
|
1103
|
+
"light": "#C4899F",
|
|
1104
|
+
"dark": "#C4899F"
|
|
1105
|
+
},
|
|
1106
|
+
"--dsw-alias-interactive-bg-hover": {
|
|
1107
|
+
"light": "#3E6B4A14",
|
|
1108
|
+
"dark": "#3E6B4A14"
|
|
1109
|
+
},
|
|
1110
|
+
"--dsw-alias-interactive-bg-active": {
|
|
1111
|
+
"light": "#FFB3472E",
|
|
1112
|
+
"dark": "#FFB3472E"
|
|
1113
|
+
},
|
|
1114
|
+
"--dsw-alias-interactive-bg-hover-solid": {
|
|
1115
|
+
"light": "#ECF3E6",
|
|
1116
|
+
"dark": "#ECF3E6"
|
|
1117
|
+
},
|
|
1118
|
+
"--dsw-alias-interactive-bg-hover-accent": {
|
|
1119
|
+
"light": "#FFB3473D",
|
|
1120
|
+
"dark": "#FFB3473D"
|
|
1121
|
+
},
|
|
1122
|
+
"--dsw-alias-button-primary-fill": {
|
|
1123
|
+
"light": "#2D5A3D",
|
|
1124
|
+
"dark": "#2D5A3D"
|
|
1125
|
+
},
|
|
1126
|
+
"--dsw-alias-button-primary-hover": {
|
|
1127
|
+
"light": "#3E6B4A",
|
|
1128
|
+
"dark": "#3E6B4A"
|
|
1129
|
+
},
|
|
1130
|
+
"--dsw-alias-button-primary-dimmed": {
|
|
1131
|
+
"light": "#2D5A3D47",
|
|
1132
|
+
"dark": "#2D5A3D47"
|
|
1133
|
+
},
|
|
1134
|
+
"--dsw-alias-button-ghost-active-fill": {
|
|
1135
|
+
"light": "#FFB34729",
|
|
1136
|
+
"dark": "#FFB34729"
|
|
1137
|
+
},
|
|
1138
|
+
"--dsw-alias-button-ghost-active-border": {
|
|
1139
|
+
"light": "#FFB347",
|
|
1140
|
+
"dark": "#FFB347"
|
|
1141
|
+
},
|
|
1142
|
+
"--dsw-alias-button-ghost-active-hover": {
|
|
1143
|
+
"light": "#FFB34747",
|
|
1144
|
+
"dark": "#FFB34747"
|
|
1145
|
+
},
|
|
1146
|
+
"--dsw-alias-button-info-fill": {
|
|
1147
|
+
"light": "#3E6B4A",
|
|
1148
|
+
"dark": "#3E6B4A"
|
|
1149
|
+
},
|
|
1150
|
+
"--dsw-alias-button-info-hover": {
|
|
1151
|
+
"light": "#4A7D58",
|
|
1152
|
+
"dark": "#4A7D58"
|
|
1153
|
+
},
|
|
1154
|
+
"--dsw-alias-button-elevated-fill": {
|
|
1155
|
+
"light": "#FFFFFF",
|
|
1156
|
+
"dark": "#FFFFFF"
|
|
1157
|
+
},
|
|
1158
|
+
"--dsw-alias-button-floating-fill": {
|
|
1159
|
+
"light": "#FFFFFF",
|
|
1160
|
+
"dark": "#FFFFFF"
|
|
1161
|
+
},
|
|
1162
|
+
"--dsw-alias-button-floating-hover": {
|
|
1163
|
+
"light": "#F6FAF2",
|
|
1164
|
+
"dark": "#F6FAF2"
|
|
1165
|
+
},
|
|
1166
|
+
"--dsw-alias-button-contrast-fill": {
|
|
1167
|
+
"light": "#234030",
|
|
1168
|
+
"dark": "#234030"
|
|
1169
|
+
},
|
|
1170
|
+
"--dsw-alias-markdown-code-block": {
|
|
1171
|
+
"light": "#EFF6EA",
|
|
1172
|
+
"dark": "#EFF6EA"
|
|
1173
|
+
},
|
|
1174
|
+
"--dsw-alias-markdown-code-block-banner": {
|
|
1175
|
+
"light": "#E3EEDC",
|
|
1176
|
+
"dark": "#E3EEDC"
|
|
1177
|
+
},
|
|
1178
|
+
"--dsw-alias-markdown-inline-code": {
|
|
1179
|
+
"light": "#ECF3E6",
|
|
1180
|
+
"dark": "#ECF3E6"
|
|
1181
|
+
},
|
|
1182
|
+
"--dsw-alias-markdown-citation": {
|
|
1183
|
+
"light": "#ECF3E6",
|
|
1184
|
+
"dark": "#ECF3E6"
|
|
1185
|
+
},
|
|
1186
|
+
"--dsw-alias-markdown-tag": {
|
|
1187
|
+
"light": "#ECF3E6",
|
|
1188
|
+
"dark": "#ECF3E6"
|
|
1189
|
+
},
|
|
1190
|
+
"--dsw-alias-markdown-placeholder": {
|
|
1191
|
+
"light": "#E3EEDC",
|
|
1192
|
+
"dark": "#E3EEDC"
|
|
1193
|
+
},
|
|
1194
|
+
"--dsw-alias-markdown-code-segment-selected": {
|
|
1195
|
+
"light": "#FFB34729",
|
|
1196
|
+
"dark": "#FFB34729"
|
|
1197
|
+
},
|
|
1198
|
+
"--dsw-alias-markdown-code-segment-unselected": {
|
|
1199
|
+
"light": "#EFF6EA",
|
|
1200
|
+
"dark": "#EFF6EA"
|
|
1201
|
+
},
|
|
1202
|
+
"--dsw-alias-scrollbar-bg-l1": {
|
|
1203
|
+
"light": "#2D5A3D29",
|
|
1204
|
+
"dark": "#2D5A3D29"
|
|
1205
|
+
},
|
|
1206
|
+
"--dsw-alias-scrollbar-bg-l2": {
|
|
1207
|
+
"light": "#2D5A3D38",
|
|
1208
|
+
"dark": "#2D5A3D38"
|
|
1209
|
+
},
|
|
1210
|
+
"--dsw-alias-scrollbar-hover-l1": {
|
|
1211
|
+
"light": "#2D5A3D52",
|
|
1212
|
+
"dark": "#2D5A3D52"
|
|
1213
|
+
},
|
|
1214
|
+
"--dsw-alias-scrollbar-hover-l2": {
|
|
1215
|
+
"light": "#2D5A3D66",
|
|
1216
|
+
"dark": "#2D5A3D66"
|
|
1217
|
+
},
|
|
1218
|
+
"--dsw-alias-tooltip-bg": {
|
|
1219
|
+
"light": "#234030",
|
|
1220
|
+
"dark": "#234030"
|
|
1221
|
+
},
|
|
1222
|
+
"--dsw-alias-toast-bg": {
|
|
1223
|
+
"light": "#FFFFFF",
|
|
1224
|
+
"dark": "#FFFFFF"
|
|
1225
|
+
},
|
|
1226
|
+
"--dsw-alias-state-error-primary": {
|
|
1227
|
+
"light": "#C65B6A",
|
|
1228
|
+
"dark": "#C65B6A"
|
|
1229
|
+
},
|
|
1230
|
+
"--dsw-alias-state-error-secondary": {
|
|
1231
|
+
"light": "#DB5A6B",
|
|
1232
|
+
"dark": "#DB5A6B"
|
|
1233
|
+
},
|
|
1234
|
+
"--dsw-alias-state-success-primary": {
|
|
1235
|
+
"light": "#21A675",
|
|
1236
|
+
"dark": "#21A675"
|
|
1237
|
+
},
|
|
1238
|
+
"--dsw-alias-state-success-secondary": {
|
|
1239
|
+
"light": "#2D5A3D",
|
|
1240
|
+
"dark": "#2D5A3D"
|
|
1241
|
+
},
|
|
1242
|
+
"--dsw-alias-state-success-tertiary": {
|
|
1243
|
+
"light": "#A8C8B2",
|
|
1244
|
+
"dark": "#A8C8B2"
|
|
1245
|
+
},
|
|
1246
|
+
"--dsw-alias-state-warn-primary": {
|
|
1247
|
+
"light": "#B97F3A",
|
|
1248
|
+
"dark": "#B97F3A"
|
|
1249
|
+
},
|
|
1250
|
+
"--dsw-alias-state-warn-secondary": {
|
|
1251
|
+
"light": "#D9A45E",
|
|
1252
|
+
"dark": "#D9A45E"
|
|
1253
|
+
},
|
|
1254
|
+
"--dsw-alias-state-warn-tertiary": {
|
|
1255
|
+
"light": "#EFDCC0",
|
|
1256
|
+
"dark": "#EFDCC0"
|
|
1257
|
+
},
|
|
1258
|
+
"--dsw-alias-state-warn-label": {
|
|
1259
|
+
"light": "#8A5A22",
|
|
1260
|
+
"dark": "#8A5A22"
|
|
1261
|
+
},
|
|
1262
|
+
"--dsw-alias-state-business-primary": {
|
|
1263
|
+
"light": "#FFB347",
|
|
1264
|
+
"dark": "#FFB347"
|
|
1265
|
+
},
|
|
1266
|
+
"--dsw-alias-state-business-tertiary": {
|
|
1267
|
+
"light": "#FFD08A",
|
|
1268
|
+
"dark": "#FFD08A"
|
|
1269
|
+
},
|
|
1270
|
+
"--dsw-specific-sidebar-fill": {
|
|
1271
|
+
"light": "linear-gradient(160deg,#D9E8DC 0%,#E6D9C6 28%,#F2E0BE 58%,#F6E1EE 88%,#DCD5F0 100%)",
|
|
1272
|
+
"dark": "linear-gradient(160deg,#D9E8DC 0%,#E6D9C6 28%,#F2E0BE 58%,#F6E1EE 88%,#DCD5F0 100%)"
|
|
1273
|
+
}
|
|
1274
|
+
},
|
|
1275
|
+
"reading": {
|
|
1276
|
+
"colorScheme": "light",
|
|
1277
|
+
"bg": "#FFFFFF",
|
|
1278
|
+
"alpha": 0.62,
|
|
1279
|
+
"blur": 3,
|
|
1280
|
+
"maxWidth": 640
|
|
1281
|
+
},
|
|
1282
|
+
"accent": "#FFB347",
|
|
1283
|
+
"ambient": {
|
|
1284
|
+
"kind": "caiyun",
|
|
1285
|
+
"stars": 12
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
]
|
|
1289
|
+
|
|
1290
|
+
/**
|
|
1291
|
+
* Marks the ambient nodes this run created.
|
|
1292
|
+
*
|
|
1293
|
+
* The layer lives on the document body, so parentage can no longer identify
|
|
1294
|
+
* ownership. Anything found without this stamp is debris from an earlier build —
|
|
1295
|
+
* and because the shell keeps its DOM across a plugin reload, such nodes outlive
|
|
1296
|
+
* the code that made them.
|
|
1297
|
+
*/
|
|
1298
|
+
const AMBIENT_OWNER = 'theme-gallery'
|
|
1299
|
+
|
|
1300
|
+
/**
|
|
1301
|
+
* Ambient scenery drawn inside the sidebar column.
|
|
1302
|
+
*
|
|
1303
|
+
* Ported from the source admin system, where each theme carried its own
|
|
1304
|
+
* animation component mounted into a `left-sidebar-theme-container`. The
|
|
1305
|
+
* artwork is reproduced here (mountains, mist, water, dragonflies, falling
|
|
1306
|
+
* petals for 山青婷彩; corner glow, rising bubbles, swaying seaweed for
|
|
1307
|
+
* 梦海游鱼) with two deliberate changes:
|
|
1308
|
+
*
|
|
1309
|
+
* - sizes are expressed in **percentages and em**, not the source system's
|
|
1310
|
+
* fixed 223 px sidebar width, so the scene scales to whatever width the
|
|
1311
|
+
* user drags the sidebar to;
|
|
1312
|
+
* - nothing here carries colour of its own beyond the ported artwork, and the
|
|
1313
|
+
* layer is `pointer-events:none` / `z-index:0`, so it can never intercept a
|
|
1314
|
+
* click or cover a menu item. The source system has the same rule, and a
|
|
1315
|
+
* bug note there records opaque mountains hiding the bottom menu rows.
|
|
1316
|
+
*
|
|
1317
|
+
* `#dsh-theme-ambient` is a seat this plugin injects into the sidebar column;
|
|
1318
|
+
* `syncAmbient()` fills it, and each theme chooses its scene by `ambient.kind`.
|
|
1319
|
+
*/
|
|
1320
|
+
const AMBIENT_CSS = [
|
|
1321
|
+
/* The layer, arranged exactly like the working `dsh-theme-firefly` ambient layer:
|
|
1322
|
+
a full-viewport fixed element styled by a CLASS, appended to `document.body`, at
|
|
1323
|
+
`z-index: 60`.
|
|
1324
|
+
Every other arrangement of this layer failed to paint on this machine — precise
|
|
1325
|
+
inline geometry, maximum z-index, `documentElement` as the parent, inline styles
|
|
1326
|
+
per element. The firefly plugin uses this one and renders, so this is now the
|
|
1327
|
+
layer's arrangement. The scenery is placed INSIDE it (`.dsh-ambient-scene`). */
|
|
1328
|
+
'#dsh-theme-ambient{position:fixed;inset:0;pointer-events:none;overflow:hidden;z-index:60}',
|
|
1329
|
+
'.dsh-ambient-scene{overflow:hidden}',
|
|
1330
|
+
/* The scene roots carry their own positioning inline too; the selectors below are
|
|
1331
|
+
kept only where a rule cannot be inlined (`@keyframes`) or where they must reach
|
|
1332
|
+
a shell element. */
|
|
1333
|
+
'.ZTP-Xa_sidebarCol{position:relative}',
|
|
1334
|
+
|
|
1335
|
+
/* BRING-UP PROBE — remove with the rest of the diagnostics.
|
|
1336
|
+
The control layer, copied rule-for-rule from the working `dsh-theme-firefly`
|
|
1337
|
+
plugin: geometry and stacking from a class, motion from `@keyframes`, and only
|
|
1338
|
+
the per-element random values inline. */
|
|
1339
|
+
'.dsh-amb-control{position:fixed;inset:0;pointer-events:none;z-index:60;overflow:hidden}',
|
|
1340
|
+
/* BRING-UP PROBE — the scene box inside the proven layer. No `pointer-events` here on
|
|
1341
|
+
purpose: the layer above already disables it, and this box is the thing being
|
|
1342
|
+
tested rather than a decoration that must stay click-through. */
|
|
1343
|
+
'.dsh-amb-control-scene{overflow:hidden}',
|
|
1344
|
+
|
|
1345
|
+
/* The scenery's own geometry. These live here rather than inline because the scene
|
|
1346
|
+
markup is built as a string, and they must reach it wherever it is mounted — which
|
|
1347
|
+
is now inside the proven layer rather than a layer of its own. */
|
|
1348
|
+
'.dsh-amb-control-scene .sta-mountains{position:absolute;left:0;right:0;bottom:0;height:46%;z-index:3}',
|
|
1349
|
+
'.dsh-amb-control-scene .sta-mountains svg{display:block;width:100%;height:100%}',
|
|
1350
|
+
'.dsh-amb-control-scene .sta-mist{position:absolute;height:1.6em;border-radius:1000px;z-index:4;',
|
|
1351
|
+
'background:linear-gradient(90deg,transparent,rgba(255,255,255,.75),transparent);',
|
|
1352
|
+
'filter:blur(5px);opacity:.85;animation:dsh-amb-mist 26s ease-in-out infinite alternate}',
|
|
1353
|
+
'.dsh-amb-control-scene .sta-mist-1{width:62%;top:56%;left:12%}',
|
|
1354
|
+
'.dsh-amb-control-scene .sta-mist-2{width:44%;top:61%;left:38%;opacity:.6;',
|
|
1355
|
+
'animation-duration:32s;animation-delay:-9s}',
|
|
1356
|
+
'.dsh-amb-control-scene .sta-pond{position:absolute;left:0;right:0;bottom:0;height:13%;z-index:5;',
|
|
1357
|
+
'background:linear-gradient(to bottom,rgba(104,178,150,.62),rgba(66,141,113,.78))}',
|
|
1358
|
+
'.dsh-amb-control-scene .sta-pond-line{position:absolute;top:0;left:0;right:0;height:1.2px;opacity:.6;',
|
|
1359
|
+
'background:linear-gradient(90deg,transparent,rgba(255,255,255,.9),transparent)}',
|
|
769
1360
|
'.dsh-amb-control-scene .sta-ripple{position:absolute;z-index:6;width:.55em;height:.55em}',
|
|
770
1361
|
'.dsh-amb-control-scene .sta-ripple span{position:absolute;inset:0;',
|
|
771
1362
|
'border:1.6px solid rgba(217,123,164,.9);border-radius:50%;',
|
|
@@ -958,6 +1549,67 @@ window.__ModuleLoader__.load({
|
|
|
958
1549
|
'box-shadow:0 0 10px 3px rgba(122,205,255,.55),0 0 22px 6px rgba(122,205,255,.22);',
|
|
959
1550
|
'animation:dsh-amb-mote linear infinite}',
|
|
960
1551
|
|
|
1552
|
+
/* ── 营慕彩云 / 江畔冬云 / 徐山军月 / 佩安杰心 / 光彩凤晨 ─────────────
|
|
1553
|
+
The five scenes ported alongside shan and dream. Their element geometry,
|
|
1554
|
+
colour and per-element timing are INLINE in the scene builders (same rule
|
|
1555
|
+
as shan: a stylesheet that never applies cannot silently collapse them),
|
|
1556
|
+
so the only things that must live here are the `@keyframes` — the one
|
|
1557
|
+
construct that cannot be expressed inline. Each scene prefixes its own
|
|
1558
|
+
keyframe names (ym / jp / xs / pj / gc) so they cannot collide. */
|
|
1559
|
+
'@keyframes dsh-amb-ym-star{0%{opacity:.35;transform:scale(1)}100%{opacity:1;transform:scale(1.25)}}',
|
|
1560
|
+
'@keyframes dsh-amb-ym-drift{from{transform:translateX(0)}to{transform:translateX(24em)}}',
|
|
1561
|
+
'@keyframes dsh-amb-ym-sea{from{transform:translateX(0)}to{transform:translateX(-50%)}}',
|
|
1562
|
+
'@keyframes dsh-amb-ym-bob{0%,100%{transform:translateY(0) rotate(-2.5deg)}50%{transform:translateY(-9px) rotate(2.5deg)}}',
|
|
1563
|
+
/* The balloons' wide round-trip paths. Deliberately two distinct keyframes, so the
|
|
1564
|
+
two never move as a pair: the lower sidebar rows are covered and exposed in turn
|
|
1565
|
+
rather than blocked by one stationary balloon.
|
|
1566
|
+
The main balloon's loop is (0, +1.5em) → (7em, +0.5em) → back: the START and END
|
|
1567
|
+
sit 1.5em below its resting line and the rightmost apex sits 0.5em below it, so the
|
|
1568
|
+
path rises while travelling right and falls while returning — up, down, left and
|
|
1569
|
+
right — while the apex itself stays exactly where it was accepted.
|
|
1570
|
+
EVERY vertical term is at or below the resting baseline (y >= 0), and that is a
|
|
1571
|
+
requirement, not taste: the scene box clips at its own top edge (`overflow:hidden`),
|
|
1572
|
+
so any stop above y=0 slices the envelope's crown off at the apex, which is the hard
|
|
1573
|
+
crop the user reported. */
|
|
1574
|
+
'@keyframes dsh-amb-ym-wander{0%{transform:translate(0,1.5em)}50%{transform:translate(7em,0.5em)}100%{transform:translate(0,1.5em)}}',
|
|
1575
|
+
'@keyframes dsh-amb-ym-wander-2{0%{transform:translate(0,0)}50%{transform:translate(-5em,1.6em)}100%{transform:translate(0,0)}}',
|
|
1576
|
+
'@keyframes dsh-amb-jp-cloud{from{transform:translateX(0)}to{transform:translateX(22em)}}',
|
|
1577
|
+
'@keyframes dsh-amb-jp-snow{0%{transform:translate(0,-0.5em);opacity:0}8%{opacity:.9}'
|
|
1578
|
+
+ '50%{transform:translate(0.9em,9em)}92%{opacity:.9}100%{transform:translate(-0.5em,19em);opacity:0}}',
|
|
1579
|
+
'@keyframes dsh-amb-jp-ripple{from{transform:translateX(0)}to{transform:translateX(25em)}}',
|
|
1580
|
+
'@keyframes dsh-amb-jp-glint{0%{opacity:.25;transform:scale(.8)}100%{opacity:.95;transform:scale(1.3)}}',
|
|
1581
|
+
'@keyframes dsh-amb-jp-boat{from{transform:translateX(0)}to{transform:translateX(3em)}}',
|
|
1582
|
+
'@keyframes dsh-amb-jp-bob{0%,100%{transform:translateY(0) rotate(-1.2deg)}50%{transform:translateY(-3px) rotate(1.4deg)}}',
|
|
1583
|
+
'@keyframes dsh-amb-jp-sway{0%,100%{transform:rotate(0deg)}50%{transform:rotate(3deg)}}',
|
|
1584
|
+
'@keyframes dsh-amb-xs-star{0%{opacity:.3;transform:scale(.85)}100%{opacity:1;transform:scale(1.25)}}',
|
|
1585
|
+
'@keyframes dsh-amb-xs-night{from{transform:translateX(0)}to{transform:translateX(26em)}}',
|
|
1586
|
+
'@keyframes dsh-amb-xs-meteor{0%{transform:rotate(-32deg) translateX(0);opacity:0}3%{opacity:1}'
|
|
1587
|
+
+ '9%{transform:rotate(-32deg) translateX(-9em);opacity:0}'
|
|
1588
|
+
+ '100%{transform:rotate(-32deg) translateX(-9em);opacity:0}}',
|
|
1589
|
+
'@keyframes dsh-amb-pj-smoke{0%{stroke-dashoffset:90;opacity:0}12%{opacity:.7}70%{opacity:.45}'
|
|
1590
|
+
+ '100%{stroke-dashoffset:-20;opacity:0}}',
|
|
1591
|
+
'@keyframes dsh-amb-pj-dust{0%{transform:translate(0,0);opacity:0}15%{opacity:.9}'
|
|
1592
|
+
+ '55%{transform:translate(-0.6em,-1.9em);opacity:.5}100%{transform:translate(0.5em,-4em);opacity:0}}',
|
|
1593
|
+
'@keyframes dsh-amb-gc-ray{0%{transform:translateY(-40%);opacity:.3}50%{transform:translateY(30%);opacity:.8}'
|
|
1594
|
+
+ '100%{transform:translateY(90%);opacity:.3}}',
|
|
1595
|
+
'@keyframes dsh-amb-gc-feather{0%{transform:translate(0,0) rotate(0deg);opacity:0}10%{opacity:.85}'
|
|
1596
|
+
+ '25%{transform:translate(1.9em,6em) rotate(95deg)}50%{transform:translate(-1.9em,13em) rotate(190deg);opacity:.85}'
|
|
1597
|
+
+ '75%{transform:translate(1.9em,20em) rotate(285deg)}90%{opacity:.8}'
|
|
1598
|
+
+ '100%{transform:translate(0,26em) rotate(380deg);opacity:0}}',
|
|
1599
|
+
'@keyframes dsh-amb-gc-fly{0%{transform:translate(-11em,0.6em) scaleX(1);opacity:0}6%{opacity:.95}'
|
|
1600
|
+
+ '40%{transform:translate(-3em,-1.1em) scaleX(1);opacity:.95}'
|
|
1601
|
+
+ '46%{transform:translate(2.5em,-0.5em) scaleX(1);opacity:.85}'
|
|
1602
|
+
+ '50%{transform:translate(9em,0) scaleX(1);opacity:0}'
|
|
1603
|
+
+ '50.1%{transform:translate(9em,0) scaleX(-1);opacity:0}'
|
|
1604
|
+
+ '56%{transform:translate(2.5em,-0.6em) scaleX(-1);opacity:.9}'
|
|
1605
|
+
+ '90%{transform:translate(-9em,0.4em) scaleX(-1);opacity:.6}'
|
|
1606
|
+
+ '96%{transform:translate(-11em,0.7em) scaleX(-1);opacity:0}'
|
|
1607
|
+
+ '96.1%{transform:translate(-11em,0.7em) scaleX(1);opacity:0}'
|
|
1608
|
+
+ '100%{transform:translate(-11em,0.6em) scaleX(1);opacity:0}}',
|
|
1609
|
+
'@keyframes dsh-amb-gc-bob{0%,100%{transform:translateY(0) rotate(0deg)}50%{transform:translateY(-5px) rotate(-1.5deg)}}',
|
|
1610
|
+
'@keyframes dsh-amb-gc-wing{0%{transform:rotate(0deg)}40%{transform:rotate(-3.5deg)}60%{transform:rotate(2.5deg)}100%{transform:rotate(0deg)}}',
|
|
1611
|
+
'@keyframes dsh-amb-gc-dew{0%{opacity:.3;transform:scale(1)}100%{opacity:1;transform:scale(1.5)}}',
|
|
1612
|
+
|
|
961
1613
|
/* Respect a user who has asked the system for less motion: the scenery
|
|
962
1614
|
stays, the movement does not. */
|
|
963
1615
|
'@media (prefers-reduced-motion:reduce){#dsh-theme-ambient *{animation:none!important}}',
|
|
@@ -971,6 +1623,10 @@ window.__ModuleLoader__.load({
|
|
|
971
1623
|
current: '当前',
|
|
972
1624
|
applied: '已应用',
|
|
973
1625
|
empty: '正在读取官方主题注册表…',
|
|
1626
|
+
// The diagnostics below the cards are a FEATURE — a live reading of the active skin —
|
|
1627
|
+
// and a wall of monospace text reads as a fault unless the panel says otherwise.
|
|
1628
|
+
diagNote: '以下为有意设计的诊断信息,便于直观查看皮肤的实时运行状态,并非系统报错;'
|
|
1629
|
+
+ '带 ⚠ 的行才表示装饰未生效',
|
|
974
1630
|
}
|
|
975
1631
|
const en = {
|
|
976
1632
|
title: 'Theme skins',
|
|
@@ -979,6 +1635,8 @@ window.__ModuleLoader__.load({
|
|
|
979
1635
|
current: 'Current',
|
|
980
1636
|
applied: 'Applied',
|
|
981
1637
|
empty: 'Reading the theme registry…',
|
|
1638
|
+
diagNote: 'The lines below are intentional diagnostics of the live skin state, '
|
|
1639
|
+
+ 'not an error report; only lines starting with ⚠ mean the scenery is not working',
|
|
982
1640
|
}
|
|
983
1641
|
|
|
984
1642
|
/**
|
|
@@ -1009,6 +1667,12 @@ window.__ModuleLoader__.load({
|
|
|
1009
1667
|
'background:var(--dsw-alias-bg-layer-3);border:.5px solid var(--dsw-alias-border-l3);',
|
|
1010
1668
|
'border-radius:8px;padding:8px 10px;word-break:break-all}',
|
|
1011
1669
|
'.tg-warn{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}',
|
|
1670
|
+
/* The diagnostics live BELOW the cards, set apart by their own margin and a divider,
|
|
1671
|
+
so they read as a separate reference block rather than as part of the picker — and
|
|
1672
|
+
so the picker itself stays the first thing the eye lands on. */
|
|
1673
|
+
'.tg-diag{margin-top:14px;padding-top:12px;border-top:.5px solid var(--dsw-alias-border-l2);',
|
|
1674
|
+
'display:flex;flex-direction:column;gap:10px}',
|
|
1675
|
+
'.tg-diag-note{font-size:12px;line-height:1.5;color:var(--dsw-alias-label-secondary)}',
|
|
1012
1676
|
'.tg-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px}',
|
|
1013
1677
|
'.tg-card{display:flex;flex-direction:column;gap:8px;padding:12px;text-align:left;cursor:pointer;',
|
|
1014
1678
|
'background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);',
|
|
@@ -1643,155 +2307,976 @@ window.__ModuleLoader__.load({
|
|
|
1643
2307
|
}
|
|
1644
2308
|
|
|
1645
2309
|
/**
|
|
1646
|
-
* One hovering dragonfly: an outer element on its flight path and an inner one
|
|
1647
|
-
* bobbing on the wingbeat, so the two motions compose.
|
|
1648
|
-
* @param suffix - gradient id suffix.
|
|
1649
|
-
* @param className - the positioning class.
|
|
1650
|
-
* @param position - inline position.
|
|
1651
|
-
* @param flight - animation shorthand for the flight path.
|
|
1652
|
-
* @param delay - animation delay.
|
|
1653
|
-
* @returns the dragonfly markup.
|
|
2310
|
+
* One hovering dragonfly: an outer element on its flight path and an inner one
|
|
2311
|
+
* bobbing on the wingbeat, so the two motions compose.
|
|
2312
|
+
* @param suffix - gradient id suffix.
|
|
2313
|
+
* @param className - the positioning class.
|
|
2314
|
+
* @param position - inline position.
|
|
2315
|
+
* @param flight - animation shorthand for the flight path.
|
|
2316
|
+
* @param delay - animation delay.
|
|
2317
|
+
* @returns the dragonfly markup.
|
|
2318
|
+
*/
|
|
2319
|
+
function dragonflyBlock(suffix, className, position, flight, delay) {
|
|
2320
|
+
return open('div', {
|
|
2321
|
+
class: `sta-dfly ${className}`,
|
|
2322
|
+
style: `position:absolute;z-index:8;will-change:transform;${position};`
|
|
2323
|
+
+ `animation:${flight};animation-delay:${delay}`,
|
|
2324
|
+
}) + open('div', {
|
|
2325
|
+
class: 'sta-bob',
|
|
2326
|
+
style: `animation:dsh-amb-bob ${suffix === '2' ? '1.1s' : '.9s'} ease-in-out infinite;`
|
|
2327
|
+
+ `animation-delay:${suffix === '2' ? '-.4s' : '0s'}`,
|
|
2328
|
+
}) + dragonflyMarkup(suffix) + '</div></div>'
|
|
2329
|
+
}
|
|
2330
|
+
|
|
2331
|
+
/**
|
|
2332
|
+
* One seaweed blade. The sway is applied to the group so the blades move from their
|
|
2333
|
+
* base, and each blade animates on its own phase.
|
|
2334
|
+
* @param key - blade index.
|
|
2335
|
+
* @param d - path data.
|
|
2336
|
+
* @param gradient - gradient id.
|
|
2337
|
+
* @param width - stroke width.
|
|
2338
|
+
* @param opacity - blade opacity.
|
|
2339
|
+
* @returns the blade markup.
|
|
2340
|
+
*/
|
|
2341
|
+
function bladeMarkup(key, d, gradient, width, opacity) {
|
|
2342
|
+
const durations = { 1: '6s', 2: '7.4s', 3: '5.2s', 4: '8.1s', 5: '6.6s' }
|
|
2343
|
+
const delays = { 1: '0s', 2: '-1.6s', 3: '-2.8s', 4: '-.9s', 5: '-3.4s' }
|
|
2344
|
+
return open('g', {
|
|
2345
|
+
class: `dof-blade dof-blade-${key}`,
|
|
2346
|
+
style: `transform-origin:50% 100%;animation:dsh-amb-sway ${durations[key]} ease-in-out infinite alternate;`
|
|
2347
|
+
+ `animation-delay:${delays[key]}`,
|
|
2348
|
+
}) + open('path', {
|
|
2349
|
+
d, fill: `url(#${gradient})`, stroke: `url(#${gradient})`, 'stroke-width': width, opacity,
|
|
2350
|
+
}) + '</path></g>'
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2353
|
+
function seaweedMarkup() {
|
|
2354
|
+
const blade = bladeMarkup
|
|
2355
|
+
|
|
2356
|
+
return open('svg', {
|
|
2357
|
+
viewBox: '0 0 140 120',
|
|
2358
|
+
preserveAspectRatio: 'none',
|
|
2359
|
+
style: 'display:block;width:100%;height:100%',
|
|
2360
|
+
})
|
|
2361
|
+
+ open('defs', {})
|
|
2362
|
+
+ open('linearGradient', { id: 'dsh-dof-weed-a', x1: '0', y1: '1', x2: '0', y2: '0' })
|
|
2363
|
+
+ open('stop', { offset: '0', 'stop-color': '#1E6E93' }) + '</stop>'
|
|
2364
|
+
+ open('stop', { offset: '0.55', 'stop-color': '#3E93BC' }) + '</stop>'
|
|
2365
|
+
+ open('stop', { offset: '1', 'stop-color': '#A5DEF0', 'stop-opacity': '0.85' }) + '</stop>'
|
|
2366
|
+
+ '</linearGradient>'
|
|
2367
|
+
+ open('linearGradient', { id: 'dsh-dof-weed-b', x1: '0', y1: '1', x2: '0', y2: '0' })
|
|
2368
|
+
+ open('stop', { offset: '0', 'stop-color': '#2B7FA6' }) + '</stop>'
|
|
2369
|
+
+ open('stop', { offset: '0.6', 'stop-color': '#4FA3C6' }) + '</stop>'
|
|
2370
|
+
+ open('stop', { offset: '1', 'stop-color': '#B8E2F2', 'stop-opacity': '0.85' }) + '</stop>'
|
|
2371
|
+
+ '</linearGradient>'
|
|
2372
|
+
+ open('linearGradient', { id: 'dsh-dof-weed-c', x1: '0', y1: '1', x2: '0', y2: '0' })
|
|
2373
|
+
+ open('stop', { offset: '0', 'stop-color': '#4A78A8' }) + '</stop>'
|
|
2374
|
+
+ open('stop', { offset: '0.6', 'stop-color': '#7FA9CE' }) + '</stop>'
|
|
2375
|
+
+ open('stop', { offset: '1', 'stop-color': '#CBE2F4', 'stop-opacity': '0.8' }) + '</stop>'
|
|
2376
|
+
+ '</linearGradient>'
|
|
2377
|
+
+ '</defs>'
|
|
2378
|
+
+ blade('1', 'M 22 120 C 12 96, 26 74, 18 48 C 15 38, 18 28, 24 20 C 20 34, 24 44, 30 60 C 36 80, 30 100, 32 120 Z', 'dsh-dof-weed-a', '2.2', '0.95')
|
|
2379
|
+
+ blade('2', 'M 48 120 C 40 98, 54 80, 46 56 C 42 44, 48 34, 56 24 C 50 40, 56 52, 60 68 C 64 88, 56 104, 58 120 Z', 'dsh-dof-weed-b', '2', '0.92')
|
|
2380
|
+
+ blade('3', 'M 74 120 C 68 102, 78 88, 72 68 C 69 58, 72 48, 78 40 C 74 52, 78 62, 82 76 C 86 94, 80 108, 82 120 Z', 'dsh-dof-weed-c', '1.8', '0.88')
|
|
2381
|
+
+ blade('4', 'M 96 120 C 92 104, 102 90, 96 72 C 93 62, 96 54, 102 46 C 98 58, 102 68, 106 82 C 110 98, 102 110, 104 120 Z', 'dsh-dof-weed-a', '1.6', '0.85')
|
|
2382
|
+
+ blade('5', 'M 118 120 C 114 108, 122 96, 117 82 C 115 74, 117 68, 121 62 C 118 72, 121 80, 124 92 C 127 104, 121 112, 123 120 Z', 'dsh-dof-weed-b', '1.4', '0.8')
|
|
2383
|
+
+ open('ellipse', { cx: '30', cy: '119', rx: '14', ry: '4', fill: '#7FAFC6', opacity: '0.55' }) + '</ellipse>'
|
|
2384
|
+
+ open('ellipse', { cx: '72', cy: '120', rx: '10', ry: '3.4', fill: '#8FB9CE', opacity: '0.5' }) + '</ellipse>'
|
|
2385
|
+
+ open('ellipse', { cx: '108', cy: '119.5', rx: '12', ry: '3.6', fill: '#7FAFC6', opacity: '0.45' }) + '</ellipse>'
|
|
2386
|
+
+ '</svg>'
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
/**
|
|
2390
|
+
* One cartoon fish, swimming across the water.
|
|
2391
|
+
*
|
|
2392
|
+
* Ported from the source system's separate `FishAnimation.vue`. That component drives the
|
|
2393
|
+
* fish from JavaScript through entering / bubbling / leaving phases on a 60-second cycle,
|
|
2394
|
+
* but this skin is a static bundle with no component runtime to host a script — so the
|
|
2395
|
+
* same artwork swims continuously instead, on a CSS `@keyframes` cross, with the tail and
|
|
2396
|
+
* the whole body on separate animations so it reads as swimming rather than sliding.
|
|
2397
|
+
*
|
|
2398
|
+
* The artwork is reproduced shape for shape: the body curve, tail, dorsal fin, pectoral
|
|
2399
|
+
* fin, and the three-part eye. The colours are retuned into the theme's blue family —
|
|
2400
|
+
* the source values (`#38bdf8` body, `#1d4ed8` fins) sat outside the dream palette and
|
|
2401
|
+
* read as a sticker, the same treatment shan's mountains got when their source greens
|
|
2402
|
+
* were darkened for this sidebar.
|
|
2403
|
+
* @param suffix - unique id suffix, so several fish can coexist.
|
|
2404
|
+
* @param size - rendered width in em.
|
|
2405
|
+
* @param top - vertical position within the water, as a percentage.
|
|
2406
|
+
* @param duration - seconds for one crossing.
|
|
2407
|
+
* @param delay - animation delay, so the fish do not move in lockstep.
|
|
2408
|
+
* @param flip - whether this fish swims right-to-left instead.
|
|
2409
|
+
* @returns the fish markup.
|
|
2410
|
+
*/
|
|
2411
|
+
function fishMarkup(suffix, size, top, duration, delay, flip) {
|
|
2412
|
+
const anim = flip ? 'dsh-amb-swim-back' : 'dsh-amb-swim'
|
|
2413
|
+
return open('div', {
|
|
2414
|
+
class: `dof-fish${flip ? ' dof-fish-flip' : ''}`,
|
|
2415
|
+
style: 'position:absolute;left:0;opacity:.94;'
|
|
2416
|
+
+ `top:${top}%;width:${size}em;`
|
|
2417
|
+
+ `animation:${anim} ${duration}s linear infinite;animation-delay:${delay}s`,
|
|
2418
|
+
})
|
|
2419
|
+
+ open('div', {
|
|
2420
|
+
class: 'dof-fish-bob',
|
|
2421
|
+
style: `animation-duration:${(duration / 8).toFixed(2)}s`,
|
|
2422
|
+
})
|
|
2423
|
+
+ open('svg', {
|
|
2424
|
+
viewBox: '0 0 50 18',
|
|
2425
|
+
preserveAspectRatio: 'xMidYMid meet',
|
|
2426
|
+
style: 'display:block;width:100%;height:auto;overflow:visible',
|
|
2427
|
+
})
|
|
2428
|
+
+ open('g', { class: 'dof-fish-body' })
|
|
2429
|
+
// Body — recoloured into the theme's own blue family. The source values
|
|
2430
|
+
// (`#38bdf8` body, `#1d4ed8` fins) sat outside the dream palette and read
|
|
2431
|
+
// as a sticker pasted on the water; the same treatment shan's mountains
|
|
2432
|
+
// got when their source greens were darkened for this sidebar.
|
|
2433
|
+
+ open('path', {
|
|
2434
|
+
d: 'M10 10 C20 5 35 5 45 10 C40 15 25 15 10 10 Z',
|
|
2435
|
+
fill: '#5FA5D6', stroke: '#2B6E9E', 'stroke-width': '1',
|
|
2436
|
+
}) + '</path>'
|
|
2437
|
+
// Tail
|
|
2438
|
+
+ open('path', {
|
|
2439
|
+
d: 'M10 10 L5 7 L5 13 Z',
|
|
2440
|
+
fill: '#2B6E9E', stroke: '#2B6E9E', 'stroke-width': '1', class: 'dof-fish-tail',
|
|
2441
|
+
}) + '</path>'
|
|
2442
|
+
// Dorsal fin
|
|
2443
|
+
+ open('path', {
|
|
2444
|
+
d: 'M20 7 L25 3 L30 7',
|
|
2445
|
+
fill: '#2B6E9E', stroke: '#2B6E9E', 'stroke-width': '1',
|
|
2446
|
+
}) + '</path>'
|
|
2447
|
+
// Pectoral fin
|
|
2448
|
+
+ open('path', {
|
|
2449
|
+
d: 'M35 9 L40 12 L45 9',
|
|
2450
|
+
fill: '#5FA5D6', stroke: '#2B6E9E', 'stroke-width': '1',
|
|
2451
|
+
}) + '</path>'
|
|
2452
|
+
// Eye: white, pupil, highlight
|
|
2453
|
+
+ open('circle', { cx: '40', cy: '8', r: '2', fill: '#FFFFFF' }) + '</circle>'
|
|
2454
|
+
+ open('circle', { cx: '41', cy: '8', r: '1', fill: '#16384F' }) + '</circle>'
|
|
2455
|
+
+ open('circle', { cx: '40.5', cy: '7.5', r: '0.5', fill: '#FFFFFF' }) + '</circle>'
|
|
2456
|
+
+ '</g>'
|
|
2457
|
+
+ '</svg>'
|
|
2458
|
+
+ '</div></div>'
|
|
2459
|
+
}
|
|
2460
|
+
|
|
2461
|
+
/**
|
|
2462
|
+
* One drifting cloud-sea copy for 营慕彩云, ported shape-for-shape from
|
|
2463
|
+
* `YingMuCaiYunAnimation.vue`. The source drifts a 200%-wide flex track holding
|
|
2464
|
+
* two copies of the same SVG, so one marquee keyframe loops seamlessly; each
|
|
2465
|
+
* copy carries its own gradient id because two tracks (back and front) and two
|
|
2466
|
+
* preview seats all live in one document.
|
|
2467
|
+
* @param variant - 'back' (deep purple, slow) or 'front' (pink-gold, quicker).
|
|
2468
|
+
* @param copy - unique id suffix for this copy's gradient.
|
|
2469
|
+
* @returns one sea-section SVG.
|
|
2470
|
+
*/
|
|
2471
|
+
function ymSeaSvg(variant, copy) {
|
|
2472
|
+
const back = variant === 'back'
|
|
2473
|
+
const gradient = `dsh-ym-sea-${variant}-${copy}`
|
|
2474
|
+
return open('svg', {
|
|
2475
|
+
viewBox: back ? '0 0 240 70' : '0 0 240 80',
|
|
2476
|
+
preserveAspectRatio: 'none',
|
|
2477
|
+
style: 'width:50%;height:100%;flex:none;display:block',
|
|
2478
|
+
})
|
|
2479
|
+
+ open('defs', {})
|
|
2480
|
+
+ open('linearGradient', { id: gradient, x1: '0', y1: '0', x2: '0', y2: '1' })
|
|
2481
|
+
+ open('stop', { offset: '0', 'stop-color': back ? '#C9B6E4' : '#FFF0F7' }) + '</stop>'
|
|
2482
|
+
+ open('stop', { offset: '1', 'stop-color': back ? '#A68FCA' : '#E8B4D6' }) + '</stop>'
|
|
2483
|
+
+ '</linearGradient>'
|
|
2484
|
+
+ '</defs>'
|
|
2485
|
+
+ open('path', {
|
|
2486
|
+
d: back
|
|
2487
|
+
? 'M0 70 L0 44 Q14 40 22 46 Q26 28 44 30 Q54 16 72 22 Q84 8 102 16 Q118 6 134 14 '
|
|
2488
|
+
+ 'Q150 8 164 18 Q178 12 190 24 Q206 20 216 34 Q230 32 240 42 L240 70 Z'
|
|
2489
|
+
: 'M0 80 L0 52 Q12 48 22 54 Q28 36 48 38 Q60 24 78 30 Q92 14 110 24 Q126 12 142 22 '
|
|
2490
|
+
+ 'Q158 14 172 26 Q188 22 198 36 Q214 34 224 48 Q234 50 240 56 L240 80 Z',
|
|
2491
|
+
fill: `url(#${gradient})`,
|
|
2492
|
+
}) + '</path>'
|
|
2493
|
+
+ '</svg>'
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
/**
|
|
2497
|
+
* One hot-air balloon for 营慕彩云, ported from the source component's two
|
|
2498
|
+
* inline SVGs: envelope with highlight, suspension ropes, and a basket.
|
|
2499
|
+
* @param variant - 'main' (orange-gold-pink, near) or 'mini' (pink-purple, far).
|
|
2500
|
+
* @returns the balloon SVG.
|
|
2501
|
+
*/
|
|
2502
|
+
function ymBalloonMarkup(variant) {
|
|
2503
|
+
const main = variant === 'main'
|
|
2504
|
+
const gradient = main ? 'dsh-ym-balloon-main' : 'dsh-ym-balloon-mini'
|
|
2505
|
+
const svg = open('svg', {
|
|
2506
|
+
viewBox: main ? '0 0 64 96' : '0 0 40 62',
|
|
2507
|
+
style: 'display:block;width:100%;height:auto;overflow:visible;'
|
|
2508
|
+
+ 'filter:drop-shadow(0 4px 6px rgba(90,58,90,.25))',
|
|
2509
|
+
})
|
|
2510
|
+
+ open('defs', {})
|
|
2511
|
+
+ open('linearGradient', { id: gradient, x1: '0', y1: '0', x2: '1', y2: '1' })
|
|
2512
|
+
+ (main
|
|
2513
|
+
? open('stop', { offset: '0', 'stop-color': '#FFC96B' }) + '</stop>'
|
|
2514
|
+
+ open('stop', { offset: '0.55', 'stop-color': '#FFB347' }) + '</stop>'
|
|
2515
|
+
+ open('stop', { offset: '1', 'stop-color': '#F08BB4' }) + '</stop>'
|
|
2516
|
+
: open('stop', { offset: '0', 'stop-color': '#F2C9E3' }) + '</stop>'
|
|
2517
|
+
+ open('stop', { offset: '1', 'stop-color': '#A68FCA' }) + '</stop>')
|
|
2518
|
+
+ '</linearGradient>'
|
|
2519
|
+
+ '</defs>'
|
|
2520
|
+
if (main) {
|
|
2521
|
+
return svg
|
|
2522
|
+
+ open('path', {
|
|
2523
|
+
d: 'M32 3 C48 3 59 15 59 30 C59 45 47 58 38 66 L26 66 C17 58 5 45 5 30 C5 15 16 3 32 3 Z',
|
|
2524
|
+
fill: `url(#${gradient})`,
|
|
2525
|
+
}) + '</path>'
|
|
2526
|
+
+ open('path', {
|
|
2527
|
+
d: 'M32 3 C36 3 39 15 39 30 C39 45 37 58 35.5 66 L28.5 66 C27 58 25 45 25 30 C25 15 28 3 32 3 Z',
|
|
2528
|
+
fill: '#FFE3B8', opacity: '0.85',
|
|
2529
|
+
}) + '</path>'
|
|
2530
|
+
+ open('path', { d: 'M13 13 C9 22 10 40 18 55', stroke: '#E88BB0', 'stroke-width': '1.4', fill: 'none', opacity: '0.55' }) + '</path>'
|
|
2531
|
+
+ open('path', { d: 'M51 13 C55 22 54 40 46 55', stroke: '#E88BB0', 'stroke-width': '1.4', fill: 'none', opacity: '0.55' }) + '</path>'
|
|
2532
|
+
+ open('path', { d: 'M27.5 66 L28.5 75 M36.5 66 L35.5 75', stroke: '#8A6A4A', 'stroke-width': '1.2' }) + '</path>'
|
|
2533
|
+
+ open('rect', { x: '25.5', y: '75', width: '13', height: '9', rx: '2.5', fill: '#9C7C5C' }) + '</rect>'
|
|
2534
|
+
+ open('path', { d: 'M25.5 78.5 L38.5 78.5', stroke: '#7E6146', 'stroke-width': '1.2' }) + '</path>'
|
|
2535
|
+
+ '</svg>'
|
|
2536
|
+
}
|
|
2537
|
+
return svg
|
|
2538
|
+
+ open('path', {
|
|
2539
|
+
d: 'M20 2 C30 2 36 10 36 19 C36 29 28 37 22.5 42 L17.5 42 C12 37 4 29 4 19 C4 10 10 2 20 2 Z',
|
|
2540
|
+
fill: `url(#${gradient})`,
|
|
2541
|
+
}) + '</path>'
|
|
2542
|
+
+ open('path', {
|
|
2543
|
+
d: 'M20 2 C23 2 25.5 10 25.5 19 C25.5 29 24 37 23 42 L17 42 C16 37 14.5 29 14.5 19 C14.5 10 17 2 20 2 Z',
|
|
2544
|
+
fill: '#F6E7F4', opacity: '0.9',
|
|
2545
|
+
}) + '</path>'
|
|
2546
|
+
+ open('path', { d: 'M17.5 42 L18 47 M22.5 42 L22 47', stroke: '#8A6A4A', 'stroke-width': '1' }) + '</path>'
|
|
2547
|
+
+ open('rect', { x: '16', y: '47', width: '8', height: '6', rx: '1.5', fill: '#8A6A4A' }) + '</rect>'
|
|
2548
|
+
+ '</svg>'
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2551
|
+
/**
|
|
2552
|
+
* The 营慕彩云 scene: a dusk glow, warm stars, blurred drifting clouds, two
|
|
2553
|
+
* marquee cloud-seas (deep purple behind, pink-gold in front) and two bobbing
|
|
2554
|
+
* hot-air balloons.
|
|
2555
|
+
*
|
|
2556
|
+
* Ported from `YingMuCaiYunAnimation.vue`. The source stars are white on a dusk
|
|
2557
|
+
* sky; on this sidebar's pastel gradient white would vanish, so they are retuned
|
|
2558
|
+
* into the theme's warm gold — the same treatment the dream fish got when their
|
|
2559
|
+
* sticker blues moved into the theme family.
|
|
2560
|
+
* @param stars - how many stars to seed.
|
|
2561
|
+
* @returns the scene markup.
|
|
2562
|
+
*/
|
|
2563
|
+
function caiyunAmbientScene(stars) {
|
|
2564
|
+
const count = Math.max(0, Math.min(30, stars ?? 12))
|
|
2565
|
+
let starNodes = ''
|
|
2566
|
+
for (let n = 1; n <= count; n += 1) {
|
|
2567
|
+
const size = 2 + ((n * 3) % 2)
|
|
2568
|
+
starNodes += open('div', {
|
|
2569
|
+
class: 'ym-star',
|
|
2570
|
+
style: 'position:absolute;border-radius:50%;'
|
|
2571
|
+
+ `left:${((n * 37) % 84) + 6}%;top:${((n * 23) % 44) + 4}%;`
|
|
2572
|
+
+ `width:${size}px;height:${size}px;`
|
|
2573
|
+
+ 'background:radial-gradient(circle,#FFF7E2 0%,rgba(255,232,190,.55) 100%);'
|
|
2574
|
+
+ 'box-shadow:0 0 4px rgba(255,224,160,.8);'
|
|
2575
|
+
+ 'animation:dsh-amb-ym-star 2.2s ease-in-out infinite alternate;'
|
|
2576
|
+
+ `animation-delay:${-(n * 0.37)}s`,
|
|
2577
|
+
}) + '</div>'
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2580
|
+
const DRIFTS = [
|
|
2581
|
+
['1', '18em', '5em', '8%', '70s', '-22s'],
|
|
2582
|
+
['2', '24em', '7em', '28%', '110s', '-44s'],
|
|
2583
|
+
['3', '16em', '4.5em', '52%', '90s', '-66s'],
|
|
2584
|
+
]
|
|
2585
|
+
let driftNodes = ''
|
|
2586
|
+
for (const [key, width, height, top, duration, delay] of DRIFTS) {
|
|
2587
|
+
driftNodes += open('div', {
|
|
2588
|
+
class: `ym-drift ym-drift-${key}`,
|
|
2589
|
+
style: `position:absolute;border-radius:1000px;left:-14em;top:${top};width:${width};height:${height};`
|
|
2590
|
+
+ 'background:radial-gradient(ellipse,rgba(232,180,214,.55) 0%,rgba(166,143,202,.3) 60%,rgba(166,143,202,0) 100%);'
|
|
2591
|
+
+ 'filter:blur(10px);'
|
|
2592
|
+
+ `animation:dsh-amb-ym-drift ${duration} linear infinite;animation-delay:${delay}`,
|
|
2593
|
+
}) + '</div>'
|
|
2594
|
+
}
|
|
2595
|
+
|
|
2596
|
+
const sea = (variant, bottom, height, zIndex, opacity, duration) => open('div', {
|
|
2597
|
+
class: `ym-sea ym-sea-${variant}`,
|
|
2598
|
+
style: `position:absolute;left:0;right:0;bottom:${bottom};height:${height};z-index:${zIndex};`
|
|
2599
|
+
+ `opacity:${opacity};overflow:hidden`,
|
|
2600
|
+
})
|
|
2601
|
+
+ open('div', {
|
|
2602
|
+
class: 'ym-sea-track',
|
|
2603
|
+
style: `position:absolute;left:0;top:0;width:200%;height:100%;display:flex;`
|
|
2604
|
+
+ `animation:dsh-amb-ym-sea ${duration} linear infinite`,
|
|
2605
|
+
})
|
|
2606
|
+
+ ymSeaSvg(variant, 'a') + ymSeaSvg(variant, 'b')
|
|
2607
|
+
+ '</div></div>'
|
|
2608
|
+
|
|
2609
|
+
// The outer element carries a WIDE WANDER and the inner one keeps the source's
|
|
2610
|
+
// small bob + sway. Two separate transforms on two elements, so they compose:
|
|
2611
|
+
// the balloon drifts across the band while still breathing.
|
|
2612
|
+
//
|
|
2613
|
+
// Why the wander: the balloons legitimately float over the sidebar's lower rows,
|
|
2614
|
+
// and a bigger path means they take turns covering and exposing that text instead
|
|
2615
|
+
// of hovering in one spot. The layer/z-index is deliberately NOT lowered — being
|
|
2616
|
+
// in front is what gives them depth, and they are never still for long.
|
|
2617
|
+
const balloon = (variant, position, size, duration, delay, zIndex, wander, wanderDelay) => open('div', {
|
|
2618
|
+
class: `ym-balloon ym-balloon-${variant}`,
|
|
2619
|
+
style: `position:absolute;pointer-events:none;${position}width:${size};z-index:${zIndex};`
|
|
2620
|
+
+ `animation:${wander} ease-in-out infinite;animation-delay:${wanderDelay}`,
|
|
2621
|
+
})
|
|
2622
|
+
+ open('div', {
|
|
2623
|
+
class: 'ym-bob',
|
|
2624
|
+
style: `transform-origin:50% 25%;animation:dsh-amb-ym-bob ${duration} ease-in-out infinite;`
|
|
2625
|
+
+ `animation-delay:${delay}`,
|
|
2626
|
+
})
|
|
2627
|
+
+ ymBalloonMarkup(variant)
|
|
2628
|
+
+ '</div></div>'
|
|
2629
|
+
|
|
2630
|
+
return open('div', { class: 'ym', style: 'position:absolute;inset:0;display:block' })
|
|
2631
|
+
+ open('div', {
|
|
2632
|
+
class: 'ym-glow',
|
|
2633
|
+
style: 'position:absolute;left:0;right:0;bottom:0;height:52%;z-index:1;'
|
|
2634
|
+
+ 'background:radial-gradient(ellipse at 35% 100%,rgba(255,214,170,.4) 0%,rgba(255,214,170,0) 70%)',
|
|
2635
|
+
}) + '</div>'
|
|
2636
|
+
+ starNodes
|
|
2637
|
+
+ driftNodes
|
|
2638
|
+
+ sea('back', '16%', '26%', 4, '0.75', '80s')
|
|
2639
|
+
+ balloon('mini', 'right:10%;bottom:56%;', '2.6em', '9.5s', '-3.5s', 5,
|
|
2640
|
+
'dsh-amb-ym-wander-2 38s', '-13s')
|
|
2641
|
+
+ sea('front', '0%', '32%', 6, '1', '50s')
|
|
2642
|
+
+ balloon('main', 'left:12%;bottom:38%;', '4.6em', '7s', '0s', 7,
|
|
2643
|
+
'dsh-amb-ym-wander 30s', '0s')
|
|
2644
|
+
+ '</div>'
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
/**
|
|
2648
|
+
* One 乌篷船 (black-awning boat) for 江畔冬云, ported from
|
|
2649
|
+
* `JiangPanDongYunAnimation.vue`: hull, awning, poling oar and a warm bow
|
|
2650
|
+
* lantern, plus its water reflection. The source carries the reflection as a
|
|
2651
|
+
* second SVG; here one SVG holds both, the mirror produced by a flipped
|
|
2652
|
+
* `<use>`, so there is no second element to keep in place.
|
|
2653
|
+
* @returns the boat SVG.
|
|
2654
|
+
*/
|
|
2655
|
+
function jpBoatMarkup() {
|
|
2656
|
+
return open('svg', { viewBox: '0 0 120 92', style: 'display:block;width:100%;height:auto' })
|
|
2657
|
+
+ open('defs', {})
|
|
2658
|
+
+ open('g', { id: 'dsh-jp-boat-art' })
|
|
2659
|
+
+ open('path', { d: 'M 6 24 Q 60 36 114 22 Q 106 36 62 40 Q 22 38 6 24 Z', fill: '#10222C' }) + '</path>'
|
|
2660
|
+
+ open('path', { d: 'M 38 24 C 44 10, 78 10, 88 23 Z', fill: '#0C1B24' }) + '</path>'
|
|
2661
|
+
+ open('path', { d: 'M 22 26 L 30 -4', stroke: '#0C1B24', 'stroke-width': '2', 'stroke-linecap': 'round', fill: 'none' }) + '</path>'
|
|
2662
|
+
+ open('circle', { cx: '14', cy: '21', r: '2.6', fill: '#F2C879' }) + '</circle>'
|
|
2663
|
+
+ open('circle', { cx: '14', cy: '21', r: '5.5', fill: '#F2C879', opacity: '0.25' }) + '</circle>'
|
|
2664
|
+
+ '</g>'
|
|
2665
|
+
+ '</defs>'
|
|
2666
|
+
+ open('use', { href: '#dsh-jp-boat-art' }) + '</use>'
|
|
2667
|
+
+ open('use', {
|
|
2668
|
+
href: '#dsh-jp-boat-art',
|
|
2669
|
+
transform: 'translate(0,90) scale(1,-1)',
|
|
2670
|
+
style: 'opacity:.22;filter:blur(2.5px)',
|
|
2671
|
+
}) + '</use>'
|
|
2672
|
+
+ '</svg>'
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2675
|
+
/**
|
|
2676
|
+
* The 江畔冬云 scene: a pale winter moon, slow drifting clouds, fine snow, and a
|
|
2677
|
+
* river band carrying a moonlight column, flowing ripples, twinkling wave
|
|
2678
|
+
* glints, a drifting sampan with its reflection, and swaying bank reeds.
|
|
2679
|
+
*
|
|
2680
|
+
* Ported from `JiangPanDongYunAnimation.vue`. The source moon and clouds sit on
|
|
2681
|
+
* a near-black sky; here they sit on the pastel one, so the moon keeps its
|
|
2682
|
+
* source colours but leans on its halo to separate, and the night clouds keep
|
|
2683
|
+
* their shape at a lighter opacity.
|
|
2684
|
+
* @param snow - how many snowflakes to seed.
|
|
2685
|
+
* @returns the scene markup.
|
|
2686
|
+
*/
|
|
2687
|
+
function dongyunAmbientScene(snow) {
|
|
2688
|
+
const count = Math.max(0, Math.min(30, snow ?? 8))
|
|
2689
|
+
let snowNodes = ''
|
|
2690
|
+
for (let n = 1; n <= count; n += 1) {
|
|
2691
|
+
const size = 2 + ((n * 3) % 3)
|
|
2692
|
+
snowNodes += open('div', {
|
|
2693
|
+
class: 'jp-snowflake',
|
|
2694
|
+
style: 'position:absolute;top:-0.5em;border-radius:50%;'
|
|
2695
|
+
+ `left:${((n * 29) % 88) + 5}%;width:${size}px;height:${size}px;`
|
|
2696
|
+
+ 'background:radial-gradient(circle,#FFFFFF 0%,rgba(255,255,255,.75) 100%);'
|
|
2697
|
+
+ 'box-shadow:0 0 4px rgba(255,255,255,.85);'
|
|
2698
|
+
+ `animation:dsh-amb-jp-snow ${9 + ((n * 7) % 8)}s linear infinite;`
|
|
2699
|
+
+ `animation-delay:${-(n * 1.9)}s`,
|
|
2700
|
+
}) + '</div>'
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2703
|
+
const CLOUDS = [
|
|
2704
|
+
['1', '12em', '3.2em', '10%', '95s', '0s'],
|
|
2705
|
+
['2', '15em', '4em', '27%', '130s', '-40s'],
|
|
2706
|
+
['3', '10.5em', '2.8em', '44%', '110s', '-70s'],
|
|
2707
|
+
]
|
|
2708
|
+
let cloudNodes = ''
|
|
2709
|
+
for (const [key, width, height, top, duration, delay] of CLOUDS) {
|
|
2710
|
+
cloudNodes += open('div', {
|
|
2711
|
+
class: `jp-cloud jp-cloud-${key}`,
|
|
2712
|
+
style: `position:absolute;border-radius:1000px;left:-16em;top:${top};width:${width};height:${height};z-index:3;`
|
|
2713
|
+
+ 'background:radial-gradient(ellipse,rgba(226,235,242,.85) 0%,rgba(190,206,220,.45) 60%,rgba(190,206,220,0) 100%);'
|
|
2714
|
+
+ 'filter:blur(10px);'
|
|
2715
|
+
+ `animation:dsh-amb-jp-cloud ${duration} linear infinite;animation-delay:${delay}`,
|
|
2716
|
+
}) + '</div>'
|
|
2717
|
+
}
|
|
2718
|
+
|
|
2719
|
+
const RIPPLES = [
|
|
2720
|
+
['1', '9em', '30%', '17s', '0s', '0.4'],
|
|
2721
|
+
['2', '7em', '55%', '23s', '-9s', '0.3'],
|
|
2722
|
+
['3', '10.5em', '78%', '14s', '-4s', '0.4'],
|
|
2723
|
+
]
|
|
2724
|
+
let rippleNodes = ''
|
|
2725
|
+
for (const [key, width, top, duration, delay, opacity] of RIPPLES) {
|
|
2726
|
+
rippleNodes += open('div', {
|
|
2727
|
+
class: `jp-ripple jp-ripple-${key}`,
|
|
2728
|
+
style: `position:absolute;height:2px;border-radius:2px;left:-10em;top:${top};width:${width};opacity:${opacity};`
|
|
2729
|
+
+ 'background:linear-gradient(90deg,transparent 0%,rgba(210,232,240,.9) 30%,rgba(210,232,240,.5) 60%,transparent 100%);'
|
|
2730
|
+
+ `animation:dsh-amb-jp-ripple ${duration} linear infinite;animation-delay:${delay}`,
|
|
2731
|
+
}) + '</div>'
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2734
|
+
let glintNodes = ''
|
|
2735
|
+
for (let n = 1; n <= 5; n += 1) {
|
|
2736
|
+
glintNodes += open('div', {
|
|
2737
|
+
class: 'jp-glint',
|
|
2738
|
+
style: 'position:absolute;width:3px;height:3px;border-radius:50%;'
|
|
2739
|
+
+ `left:${12 + ((n * 19) % 76)}%;top:${28 + ((n * 23) % 58)}%;`
|
|
2740
|
+
+ 'background:radial-gradient(circle,#EAF6FA 0%,rgba(234,246,250,.4) 100%);'
|
|
2741
|
+
+ 'box-shadow:0 0 6px rgba(220,240,250,.9);'
|
|
2742
|
+
+ 'animation:dsh-amb-jp-glint 2.6s ease-in-out infinite alternate;'
|
|
2743
|
+
+ `animation-delay:${-(n * 0.6)}s`,
|
|
2744
|
+
}) + '</div>'
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2747
|
+
const REEDS = [
|
|
2748
|
+
['1', 'M 14 120 C 15 92, 17 62, 24 34', 'M 26 27', '4.6', '13', '9 26 27', '5.2s', '0s'],
|
|
2749
|
+
['2', 'M 34 120 C 36 96, 42 66, 54 42', 'M 57 35', '4.2', '12', '16 57 35', '6.1s', '-2.1s'],
|
|
2750
|
+
['3', 'M 56 120 C 56 100, 58 78, 62 56', 'M 63 49', '3.8', '11', '5 63 49', '4.6s', '-1.2s'],
|
|
2751
|
+
['4', 'M 76 120 C 80 100, 90 78, 102 58', 'M 105 51', '3.6', '10.5', '22 105 51', '5.8s', '-3s'],
|
|
2752
|
+
]
|
|
2753
|
+
let reedNodes = ''
|
|
2754
|
+
for (const [key, stem, head, rx, ry, rot, duration, delay] of REEDS) {
|
|
2755
|
+
const [angle, cx, cy] = rot.split(' ')
|
|
2756
|
+
reedNodes += open('g', {
|
|
2757
|
+
class: `jp-reed jp-reed-${key}`,
|
|
2758
|
+
style: `transform-box:fill-box;transform-origin:50% 100%;`
|
|
2759
|
+
+ `animation:dsh-amb-jp-sway ${duration} ease-in-out infinite;animation-delay:${delay}`,
|
|
2760
|
+
})
|
|
2761
|
+
+ open('path', { d: stem, stroke: '#0E202A', 'stroke-width': '2.2', fill: 'none', 'stroke-linecap': 'round' }) + '</path>'
|
|
2762
|
+
+ open('ellipse', {
|
|
2763
|
+
cx, cy, rx, ry, fill: '#12242F',
|
|
2764
|
+
transform: `rotate(${angle} ${cx} ${cy})`,
|
|
2765
|
+
}) + '</ellipse>'
|
|
2766
|
+
+ '</g>'
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
return open('div', { class: 'jp', style: 'position:absolute;inset:0;display:block' })
|
|
2770
|
+
+ open('div', {
|
|
2771
|
+
class: 'jp-moon',
|
|
2772
|
+
style: 'position:absolute;top:5%;right:9%;width:3em;height:3em;border-radius:50%;z-index:2;opacity:.95;'
|
|
2773
|
+
+ 'background:radial-gradient(circle at 38% 34%,#FDFAF2 0%,#E8E4D4 55%,#CBD2D8 100%);'
|
|
2774
|
+
+ 'box-shadow:0 0 1.4em 0.35em rgba(240,244,240,.5),0 0 3.5em 1em rgba(190,210,225,.4)',
|
|
2775
|
+
}) + '</div>'
|
|
2776
|
+
+ cloudNodes
|
|
2777
|
+
+ snowNodes
|
|
2778
|
+
+ open('div', {
|
|
2779
|
+
class: 'jp-river',
|
|
2780
|
+
style: 'position:absolute;left:0;right:0;bottom:0;height:38%;z-index:7;'
|
|
2781
|
+
+ 'background:linear-gradient(to bottom,rgba(150,178,196,.4) 0%,rgba(110,142,164,.5) 100%);'
|
|
2782
|
+
+ 'box-shadow:inset 0 0.9em 1.1em -0.6em rgba(16,34,44,.5)',
|
|
2783
|
+
})
|
|
2784
|
+
+ open('div', {
|
|
2785
|
+
class: 'jp-waterline',
|
|
2786
|
+
style: 'position:absolute;top:0;left:0;right:0;height:1.5px;opacity:.5;'
|
|
2787
|
+
+ 'background:linear-gradient(90deg,transparent 0%,rgba(214,234,242,.9) 35%,rgba(214,234,242,.35) 70%,transparent 100%)',
|
|
2788
|
+
}) + '</div>'
|
|
2789
|
+
+ open('div', {
|
|
2790
|
+
class: 'jp-moonlight',
|
|
2791
|
+
style: 'position:absolute;top:4%;left:62%;width:3em;height:82%;border-radius:40%;filter:blur(5px);'
|
|
2792
|
+
+ 'background:linear-gradient(to bottom,rgba(226,240,246,.18) 0%,rgba(226,240,246,.06) 55%,transparent 100%)',
|
|
2793
|
+
}) + '</div>'
|
|
2794
|
+
+ rippleNodes
|
|
2795
|
+
+ glintNodes
|
|
2796
|
+
+ '</div>'
|
|
2797
|
+
+ open('div', {
|
|
2798
|
+
class: 'jp-boat',
|
|
2799
|
+
style: 'position:absolute;bottom:22%;left:13%;width:7em;z-index:8;'
|
|
2800
|
+
+ 'animation:dsh-amb-jp-boat 46s ease-in-out infinite alternate',
|
|
2801
|
+
})
|
|
2802
|
+
+ open('div', {
|
|
2803
|
+
class: 'jp-boat-bob',
|
|
2804
|
+
style: 'transform-origin:50% 100%;animation:dsh-amb-jp-bob 5.2s ease-in-out infinite',
|
|
2805
|
+
})
|
|
2806
|
+
+ jpBoatMarkup()
|
|
2807
|
+
+ '</div></div>'
|
|
2808
|
+
+ open('div', {
|
|
2809
|
+
class: 'jp-reeds',
|
|
2810
|
+
style: 'position:absolute;bottom:0;left:0;width:9em;z-index:9',
|
|
2811
|
+
})
|
|
2812
|
+
+ open('svg', { viewBox: '0 0 120 120', style: 'display:block;width:100%;height:auto' })
|
|
2813
|
+
+ reedNodes
|
|
2814
|
+
+ open('path', { d: 'M 2 120 C 20 118, 42 112, 62 103', stroke: '#0E202A', 'stroke-width': '2.4', fill: 'none', 'stroke-linecap': 'round' }) + '</path>'
|
|
2815
|
+
+ open('path', { d: 'M 6 120 C 28 118.5, 54 114, 82 108', stroke: '#0E202A', 'stroke-width': '2', fill: 'none', 'stroke-linecap': 'round', opacity: '0.85' }) + '</path>'
|
|
2816
|
+
+ open('path', { d: 'M 18 120 C 40 119, 64 116.5, 92 113', stroke: '#0E202A', 'stroke-width': '1.6', fill: 'none', 'stroke-linecap': 'round', opacity: '0.7' }) + '</path>'
|
|
2817
|
+
+ '</svg>'
|
|
2818
|
+
+ '</div>'
|
|
2819
|
+
+ '</div>'
|
|
2820
|
+
}
|
|
2821
|
+
|
|
2822
|
+
/**
|
|
2823
|
+
* One silhouette pine for 徐山军月, ported verbatim from
|
|
2824
|
+
* `XuShanJunYueAnimation.vue`'s `<defs>` art: a tiered pine over a short trunk.
|
|
2825
|
+
* @returns the pine group markup (a `<g>` for reuse inside one SVG).
|
|
2826
|
+
*/
|
|
2827
|
+
function xsPineMarkup() {
|
|
2828
|
+
return open('g', { id: 'dsh-xsj-pine-art' })
|
|
2829
|
+
+ open('path', {
|
|
2830
|
+
d: 'M 12 120 L 12 112 L 5 112 L 12 100 L 3 100 L 10 88 L 4 88 L 12 74 L 20 88 L 14 88 L 21 100 L 12 100 L 19 112 L 12 112 Z',
|
|
2831
|
+
fill: '#101A11',
|
|
2832
|
+
}) + '</path>'
|
|
2833
|
+
+ open('rect', { x: '10.6', y: '112', width: '2.8', height: '8', fill: '#101A11' }) + '</rect>'
|
|
2834
|
+
+ '</g>'
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2837
|
+
/**
|
|
2838
|
+
* The 徐山军月 scene: a starfield, a full moon veiled by slow night clouds, a
|
|
2839
|
+
* periodic meteor, two dark mountain ridges, and a row of standing pines.
|
|
2840
|
+
*
|
|
2841
|
+
* Ported from `XuShanJunYueAnimation.vue`. The source stars and moon are pale
|
|
2842
|
+
* cream on a near-black sky; on the pastel sidebar they would vanish, so they
|
|
2843
|
+
* are warmed into the theme's brass family (the same retune the dream fish and
|
|
2844
|
+
* the caiyun stars got), while the ridges and pines keep their verbatim dark
|
|
2845
|
+
* silhouettes — dark on light reads as the classic ink shape.
|
|
2846
|
+
* @param stars - how many stars to seed.
|
|
2847
|
+
* @returns the scene markup.
|
|
2848
|
+
*/
|
|
2849
|
+
function junyueAmbientScene(stars) {
|
|
2850
|
+
const count = Math.max(0, Math.min(30, stars ?? 12))
|
|
2851
|
+
let starNodes = ''
|
|
2852
|
+
for (let n = 1; n <= count; n += 1) {
|
|
2853
|
+
const size = 2 + ((n * 3) % 2)
|
|
2854
|
+
starNodes += open('div', {
|
|
2855
|
+
class: 'xs-star',
|
|
2856
|
+
style: 'position:absolute;border-radius:50%;'
|
|
2857
|
+
+ `left:${((n * 37) % 84) + 6}%;top:${((n * 23) % 48) + 4}%;`
|
|
2858
|
+
+ `width:${size}px;height:${size}px;`
|
|
2859
|
+
+ 'background:radial-gradient(circle,#F5EFD2 0%,rgba(212,178,102,.55) 100%);'
|
|
2860
|
+
+ 'box-shadow:0 0 5px rgba(212,178,102,.75);'
|
|
2861
|
+
+ 'animation:dsh-amb-xs-star 2.4s ease-in-out infinite alternate;'
|
|
2862
|
+
+ `animation-delay:${-(n * 0.7)}s`,
|
|
2863
|
+
}) + '</div>'
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2866
|
+
const CLOUDS = [
|
|
2867
|
+
['1', '10.5em', '1.6em', '12%', '90s', '0s'],
|
|
2868
|
+
['2', '8.5em', '1.25em', '26%', '120s', '-55s'],
|
|
2869
|
+
]
|
|
2870
|
+
let cloudNodes = ''
|
|
2871
|
+
for (const [key, width, height, top, duration, delay] of CLOUDS) {
|
|
2872
|
+
cloudNodes += open('div', {
|
|
2873
|
+
class: `xs-cloud xs-cloud-${key}`,
|
|
2874
|
+
style: `position:absolute;border-radius:1000px;left:-12em;top:${top};width:${width};height:${height};z-index:3;`
|
|
2875
|
+
+ 'background:linear-gradient(90deg,rgba(24,32,25,0) 0%,rgba(24,32,25,.22) 30%,rgba(24,32,25,.22) 70%,rgba(24,32,25,0) 100%);'
|
|
2876
|
+
+ 'filter:blur(5px);'
|
|
2877
|
+
+ `animation:dsh-amb-xs-night ${duration} linear infinite;animation-delay:${delay}`,
|
|
2878
|
+
}) + '</div>'
|
|
2879
|
+
}
|
|
2880
|
+
|
|
2881
|
+
return open('div', { class: 'xs', style: 'position:absolute;inset:0;display:block' })
|
|
2882
|
+
+ starNodes
|
|
2883
|
+
+ open('div', {
|
|
2884
|
+
class: 'xs-moon',
|
|
2885
|
+
style: 'position:absolute;top:7%;right:11%;width:3.6em;height:3.6em;border-radius:50%;z-index:2;'
|
|
2886
|
+
+ 'background:radial-gradient(circle at 36% 32%,#FBF6E4 0%,#EFE7CB 58%,#D6CCA8 100%);'
|
|
2887
|
+
+ 'box-shadow:0 0 1.6em 0.5em rgba(245,239,217,.5),0 0 4em 1.4em rgba(212,178,102,.22)',
|
|
2888
|
+
}) + '</div>'
|
|
2889
|
+
+ cloudNodes
|
|
2890
|
+
+ open('div', {
|
|
2891
|
+
class: 'xs-meteor',
|
|
2892
|
+
style: 'position:absolute;top:16%;left:66%;width:4.6em;height:2px;border-radius:2px;z-index:4;'
|
|
2893
|
+
+ 'background:linear-gradient(90deg,transparent,rgba(245,242,220,.95));'
|
|
2894
|
+
+ 'animation:dsh-amb-xs-meteor 9s ease-in infinite',
|
|
2895
|
+
})
|
|
2896
|
+
+ open('span', {
|
|
2897
|
+
style: 'position:absolute;right:-2px;top:-2.2px;width:5px;height:5px;border-radius:50%;'
|
|
2898
|
+
+ 'background:#FFFBEA;box-shadow:0 0 8px 2px rgba(255,251,234,.9)',
|
|
2899
|
+
}) + '</span>'
|
|
2900
|
+
+ '</div>'
|
|
2901
|
+
+ open('div', {
|
|
2902
|
+
class: 'xs-ridges',
|
|
2903
|
+
style: 'position:absolute;left:0;right:0;bottom:0;height:46%;z-index:5',
|
|
2904
|
+
})
|
|
2905
|
+
+ open('svg', { viewBox: '0 0 223 160', preserveAspectRatio: 'none', style: 'display:block;width:100%;height:100%' })
|
|
2906
|
+
+ open('defs', {})
|
|
2907
|
+
+ open('linearGradient', { id: 'dsh-xsj-ridge-back', x1: '0', y1: '0', x2: '0', y2: '1' })
|
|
2908
|
+
+ open('stop', { offset: '0', 'stop-color': '#31412F' }) + '</stop>'
|
|
2909
|
+
+ open('stop', { offset: '1', 'stop-color': '#273528' }) + '</stop>'
|
|
2910
|
+
+ '</linearGradient>'
|
|
2911
|
+
+ open('linearGradient', { id: 'dsh-xsj-ridge-front', x1: '0', y1: '0', x2: '0', y2: '1' })
|
|
2912
|
+
+ open('stop', { offset: '0', 'stop-color': '#1F2C1F' }) + '</stop>'
|
|
2913
|
+
+ open('stop', { offset: '1', 'stop-color': '#161F16' }) + '</stop>'
|
|
2914
|
+
+ '</linearGradient>'
|
|
2915
|
+
+ '</defs>'
|
|
2916
|
+
+ open('path', {
|
|
2917
|
+
d: 'M 0 62 Q 28 30 58 52 Q 92 18 126 46 Q 158 24 188 50 Q 206 38 223 46 L 223 160 L 0 160 Z',
|
|
2918
|
+
fill: 'url(#dsh-xsj-ridge-back)',
|
|
2919
|
+
}) + '</path>'
|
|
2920
|
+
+ open('path', {
|
|
2921
|
+
d: 'M 0 104 Q 34 72 68 94 Q 104 64 142 92 Q 176 74 223 100 L 223 160 L 0 160 Z',
|
|
2922
|
+
fill: 'url(#dsh-xsj-ridge-front)',
|
|
2923
|
+
}) + '</path>'
|
|
2924
|
+
+ '</svg>'
|
|
2925
|
+
+ '</div>'
|
|
2926
|
+
+ open('div', {
|
|
2927
|
+
class: 'xs-pines',
|
|
2928
|
+
style: 'position:absolute;bottom:0;left:3%;width:8.5em;z-index:6',
|
|
2929
|
+
})
|
|
2930
|
+
+ open('svg', { viewBox: '0 0 140 120', style: 'display:block;width:100%;height:auto' })
|
|
2931
|
+
+ open('defs', {}) + xsPineMarkup() + '</defs>'
|
|
2932
|
+
+ open('use', { href: '#dsh-xsj-pine-art', transform: 'translate(-4,-8) scale(1.35)' }) + '</use>'
|
|
2933
|
+
+ open('use', { href: '#dsh-xsj-pine-art', transform: 'translate(34,2) scale(1.0)' }) + '</use>'
|
|
2934
|
+
+ open('use', { href: '#dsh-xsj-pine-art', transform: 'translate(66,-4) scale(1.18)' }) + '</use>'
|
|
2935
|
+
+ open('use', { href: '#dsh-xsj-pine-art', transform: 'translate(102,6) scale(0.88)' }) + '</use>'
|
|
2936
|
+
+ open('use', { href: '#dsh-xsj-pine-art', transform: 'translate(126,0) scale(1.05)' }) + '</use>'
|
|
2937
|
+
+ '</svg>'
|
|
2938
|
+
+ '</div>'
|
|
2939
|
+
+ '</div>'
|
|
2940
|
+
}
|
|
2941
|
+
|
|
2942
|
+
/**
|
|
2943
|
+
* The 佩安杰心 scene: misty hills behind, a zen enso circle with a seated
|
|
2944
|
+
* meditator, an incense burner with two rising smoke threads, drifting dust
|
|
2945
|
+
* motes, and the theme's own words.
|
|
2946
|
+
*
|
|
2947
|
+
* Ported from `PeiAnJieXinAnimation.vue`. The artwork paths are verbatim; the
|
|
2948
|
+
* scene SVG's viewBox is cropped to the artwork (the source spans a full-height
|
|
2949
|
+
* sidebar and places the group far down inside it), which keeps the same drawing
|
|
2950
|
+
* coordinates while fitting the band.
|
|
2951
|
+
* @param dust - how many dust motes to seed.
|
|
2952
|
+
* @returns the scene markup.
|
|
1654
2953
|
*/
|
|
1655
|
-
function
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
2954
|
+
function jiexinAmbientScene(dust) {
|
|
2955
|
+
const count = Math.max(0, Math.min(20, dust ?? 4))
|
|
2956
|
+
let dustNodes = ''
|
|
2957
|
+
for (let n = 1; n <= count; n += 1) {
|
|
2958
|
+
const size = 2.5 + ((n * 5) % 4)
|
|
2959
|
+
dustNodes += open('div', {
|
|
2960
|
+
class: 'pj-dust',
|
|
2961
|
+
style: 'position:absolute;border-radius:50%;'
|
|
2962
|
+
+ `left:${((n * 17) % 50) + 26}%;top:${((n * 13) % 30) + 28}%;`
|
|
2963
|
+
+ `width:${size}px;height:${size}px;`
|
|
2964
|
+
+ 'background:radial-gradient(circle,rgba(255,244,214,.95) 0%,rgba(255,244,214,0) 100%);'
|
|
2965
|
+
+ 'box-shadow:0 0 6px rgba(255,236,190,.8);'
|
|
2966
|
+
+ `animation:dsh-amb-pj-dust ${8 + ((n * 5) % 5)}s linear infinite;`
|
|
2967
|
+
+ `animation-delay:${-(n * 2)}s`,
|
|
2968
|
+
}) + '</div>'
|
|
2969
|
+
}
|
|
2970
|
+
|
|
2971
|
+
return open('div', { class: 'pj', style: 'position:absolute;inset:0;display:block' })
|
|
2972
|
+
+ open('div', {
|
|
2973
|
+
class: 'pj-hills',
|
|
2974
|
+
style: 'position:absolute;left:0;right:0;top:8%;height:24%;z-index:2;opacity:.62',
|
|
2975
|
+
})
|
|
2976
|
+
+ open('svg', { viewBox: '0 0 223 80', preserveAspectRatio: 'none', style: 'display:block;width:100%;height:100%' })
|
|
2977
|
+
+ open('path', {
|
|
2978
|
+
d: 'M 0 60 Q 34 22 70 46 Q 108 14 146 44 Q 186 20 223 48 L 223 80 L 0 80 Z',
|
|
2979
|
+
fill: '#B49B78', opacity: '0.55',
|
|
2980
|
+
}) + '</path>'
|
|
2981
|
+
+ open('path', {
|
|
2982
|
+
d: 'M 0 72 Q 40 42 82 60 Q 126 34 168 58 Q 196 44 223 60 L 223 80 L 0 80 Z',
|
|
2983
|
+
fill: '#A08A67', opacity: '0.6',
|
|
2984
|
+
}) + '</path>'
|
|
2985
|
+
+ '</svg>'
|
|
2986
|
+
+ '</div>'
|
|
2987
|
+
+ open('div', {
|
|
2988
|
+
class: 'pj-zenscene',
|
|
2989
|
+
style: 'position:absolute;left:0;right:0;bottom:8%;height:62%;z-index:3',
|
|
2990
|
+
})
|
|
2991
|
+
+ open('svg', {
|
|
2992
|
+
viewBox: '0 480 200 175',
|
|
2993
|
+
preserveAspectRatio: 'xMidYMax meet',
|
|
2994
|
+
style: 'display:block;width:100%;height:100%',
|
|
2995
|
+
})
|
|
2996
|
+
+ open('defs', {})
|
|
2997
|
+
+ open('radialGradient', { id: 'dsh-pjx-fig-grad', cx: '50%', cy: '32%', r: '80%' })
|
|
2998
|
+
+ open('stop', { offset: '0%', 'stop-color': '#6B5238', 'stop-opacity': '0.9' }) + '</stop>'
|
|
2999
|
+
+ open('stop', { offset: '60%', 'stop-color': '#57432C', 'stop-opacity': '0.85' }) + '</stop>'
|
|
3000
|
+
+ open('stop', { offset: '100%', 'stop-color': '#4A3823', 'stop-opacity': '0.8' }) + '</stop>'
|
|
3001
|
+
+ '</radialGradient>'
|
|
3002
|
+
+ open('filter', { id: 'dsh-pjx-haze', x: '-30%', y: '-30%', width: '160%', height: '160%' })
|
|
3003
|
+
+ open('feGaussianBlur', { stdDeviation: '1.8' }) + '</feGaussianBlur>'
|
|
3004
|
+
+ '</filter>'
|
|
3005
|
+
+ open('filter', { id: 'dsh-pjx-soft-glow', x: '-60%', y: '-60%', width: '220%', height: '220%' })
|
|
3006
|
+
+ open('feGaussianBlur', { stdDeviation: '7' }) + '</feGaussianBlur>'
|
|
3007
|
+
+ '</filter>'
|
|
3008
|
+
+ open('g', { id: 'dsh-pjx-enso-art' })
|
|
3009
|
+
+ open('circle', {
|
|
3010
|
+
cx: '80', cy: '64', r: '56', fill: 'none', stroke: '#A87E4C', 'stroke-width': '5',
|
|
3011
|
+
'stroke-linecap': 'round', 'stroke-dasharray': '316 36',
|
|
3012
|
+
transform: 'rotate(-78 80 64)', opacity: '0.62',
|
|
3013
|
+
}) + '</circle>'
|
|
3014
|
+
+ open('circle', {
|
|
3015
|
+
cx: '80', cy: '64', r: '56', fill: 'none', stroke: '#D9B98C', 'stroke-width': '1.8',
|
|
3016
|
+
'stroke-linecap': 'round', 'stroke-dasharray': '255 92',
|
|
3017
|
+
transform: 'rotate(-60 80 64)', opacity: '0.5',
|
|
3018
|
+
}) + '</circle>'
|
|
3019
|
+
+ '</g>'
|
|
3020
|
+
+ open('g', { id: 'dsh-pjx-meditator-art' })
|
|
3021
|
+
+ open('g', { filter: 'url(#dsh-pjx-soft-glow)', opacity: '0.35' })
|
|
3022
|
+
+ open('path', {
|
|
3023
|
+
d: 'M 37 112 C 41 97, 58 90, 80 90 C 102 90, 119 97, 123 112 C 112 117.5, 96 119.5, 80 119.5 C 64 119.5, 48 117.5, 37 112 Z',
|
|
3024
|
+
fill: '#6B5238',
|
|
3025
|
+
}) + '</path>'
|
|
3026
|
+
+ open('circle', { cx: '80', cy: '33', r: '13.5', fill: '#6B5238' }) + '</circle>'
|
|
3027
|
+
+ open('path', {
|
|
3028
|
+
d: 'M 64 52 C 60 68, 62 80, 67 93 C 75 97.5, 85 97.5, 93 93 C 98 80, 100 68, 96 52 C 91 44.5, 69 44.5, 64 52 Z',
|
|
3029
|
+
fill: '#6B5238',
|
|
3030
|
+
}) + '</path>'
|
|
3031
|
+
+ '</g>'
|
|
3032
|
+
+ open('ellipse', {
|
|
3033
|
+
cx: '80', cy: '119', rx: '47', ry: '8.5', fill: '#8A6A46', opacity: '0.7',
|
|
3034
|
+
filter: 'url(#dsh-pjx-haze)',
|
|
3035
|
+
}) + '</ellipse>'
|
|
3036
|
+
+ open('g', { fill: 'url(#dsh-pjx-fig-grad)', filter: 'url(#dsh-pjx-haze)' })
|
|
3037
|
+
+ open('path', {
|
|
3038
|
+
d: 'M 37 112 C 41 97, 58 90, 80 90 C 102 90, 119 97, 123 112 C 112 117.5, 96 119.5, 80 119.5 C 64 119.5, 48 117.5, 37 112 Z',
|
|
3039
|
+
}) + '</path>'
|
|
3040
|
+
+ open('path', {
|
|
3041
|
+
d: 'M 64 52 C 60 68, 62 80, 67 93 C 75 97.5, 85 97.5, 93 93 C 98 80, 100 68, 96 52 C 91 44.5, 69 44.5, 64 52 Z',
|
|
3042
|
+
}) + '</path>'
|
|
3043
|
+
+ open('path', { d: 'M 64 54 C 55 62, 51 78, 53 93 C 56 99, 62 101, 67 99 C 62 85, 62 68, 67 56 Z' }) + '</path>'
|
|
3044
|
+
+ open('path', { d: 'M 96 54 C 105 62, 109 78, 107 93 C 104 99, 98 101, 93 99 C 98 85, 98 68, 93 56 Z' }) + '</path>'
|
|
3045
|
+
+ open('ellipse', { cx: '80', cy: '95', rx: '7', ry: '4.5' }) + '</ellipse>'
|
|
3046
|
+
+ open('circle', { cx: '80', cy: '33', r: '13.5' }) + '</circle>'
|
|
3047
|
+
+ '</g>'
|
|
3048
|
+
+ '</g>'
|
|
3049
|
+
+ '</defs>'
|
|
3050
|
+
+ open('g', { transform: 'translate(18, 492) scale(1.17)' })
|
|
3051
|
+
+ open('use', { href: '#dsh-pjx-enso-art' }) + '</use>'
|
|
3052
|
+
+ open('use', { href: '#dsh-pjx-meditator-art' }) + '</use>'
|
|
3053
|
+
+ '</g>'
|
|
3054
|
+
+ open('g', {})
|
|
3055
|
+
+ open('path', {
|
|
3056
|
+
d: 'M 20 631 C 20 623, 25 619, 32 619 C 39 619, 44 623, 44 631 Z',
|
|
3057
|
+
fill: '#6B5644', opacity: '0.8',
|
|
3058
|
+
}) + '</path>'
|
|
3059
|
+
+ open('ellipse', { cx: '32', cy: '620', rx: '11.7', ry: '3', fill: '#55432F', opacity: '0.9' }) + '</ellipse>'
|
|
3060
|
+
+ open('path', { d: 'M 32 620 L 32 604', stroke: '#8A6E52', 'stroke-width': '1.9', 'stroke-linecap': 'round', fill: 'none' }) + '</path>'
|
|
3061
|
+
+ open('circle', { cx: '32', cy: '603.5', r: '1.9', fill: '#E8A05A' }) + '</circle>'
|
|
3062
|
+
+ open('circle', { cx: '32', cy: '603.5', r: '4', fill: '#E8A05A', opacity: '0.3' }) + '</circle>'
|
|
3063
|
+
+ open('path', {
|
|
3064
|
+
class: 'pj-smoke pj-smoke-1',
|
|
3065
|
+
d: 'M 32 601 C 28 593, 36 586, 32 577 C 28 568, 35 561, 31 551',
|
|
3066
|
+
fill: 'none', stroke: '#FFFFFF', 'stroke-width': '2.4', 'stroke-linecap': 'round', opacity: '0.85',
|
|
3067
|
+
style: 'stroke-dasharray:90;stroke-dashoffset:90;filter:blur(1.4px);'
|
|
3068
|
+
+ 'animation:dsh-amb-pj-smoke 7s linear infinite',
|
|
3069
|
+
}) + '</path>'
|
|
3070
|
+
+ open('path', {
|
|
3071
|
+
class: 'pj-smoke pj-smoke-2',
|
|
3072
|
+
d: 'M 32 601 C 36 592, 28 584, 33 575 C 37 566, 30 558, 34 549',
|
|
3073
|
+
fill: 'none', stroke: '#FFF6E8', 'stroke-width': '1.9', 'stroke-linecap': 'round', opacity: '0.6',
|
|
3074
|
+
style: 'stroke-dasharray:90;stroke-dashoffset:90;filter:blur(1.6px);'
|
|
3075
|
+
+ 'animation:dsh-amb-pj-smoke 7s linear infinite;animation-delay:-3.5s',
|
|
3076
|
+
}) + '</path>'
|
|
3077
|
+
+ '</g>'
|
|
3078
|
+
+ '</svg>'
|
|
3079
|
+
+ '</div>'
|
|
3080
|
+
+ dustNodes
|
|
3081
|
+
+ open('div', {
|
|
3082
|
+
class: 'pj-words',
|
|
3083
|
+
style: 'position:absolute;left:0;right:0;bottom:2%;text-align:center;z-index:7;'
|
|
3084
|
+
+ "font-family:'KaiTi','STKaiti','SimSun',serif;font-size:1.05em;line-height:1;"
|
|
3085
|
+
+ 'color:#6B5233;letter-spacing:.45em;text-shadow:0 1px 0 rgba(255,250,240,.6)',
|
|
3086
|
+
})
|
|
3087
|
+
+ '自在<span style="color:#B08D5F;margin:0 2px"> · </span>安顿'
|
|
3088
|
+
+ '</div>'
|
|
3089
|
+
+ '</div>'
|
|
1665
3090
|
}
|
|
1666
3091
|
|
|
1667
3092
|
/**
|
|
1668
|
-
* One
|
|
1669
|
-
*
|
|
1670
|
-
*
|
|
1671
|
-
* @param
|
|
1672
|
-
* @
|
|
1673
|
-
* @param width - stroke width.
|
|
1674
|
-
* @param opacity - blade opacity.
|
|
1675
|
-
* @returns the blade markup.
|
|
3093
|
+
* One falling phoenix feather for 光彩凤晨, ported from
|
|
3094
|
+
* `GuangCaiFengChenAnimation.vue`: a full gradient vane over a gold rachis.
|
|
3095
|
+
* Each feather carries its own gradient id, the same rule the dragonflies follow.
|
|
3096
|
+
* @param key - unique id suffix for this feather's gradient.
|
|
3097
|
+
* @returns the feather SVG.
|
|
1676
3098
|
*/
|
|
1677
|
-
function
|
|
1678
|
-
const
|
|
1679
|
-
const delays = { 1: '0s', 2: '-1.6s', 3: '-2.8s', 4: '-.9s', 5: '-3.4s' }
|
|
1680
|
-
return open('g', {
|
|
1681
|
-
class: `dof-blade dof-blade-${key}`,
|
|
1682
|
-
style: `transform-origin:50% 100%;animation:dsh-amb-sway ${durations[key]} ease-in-out infinite alternate;`
|
|
1683
|
-
+ `animation-delay:${delays[key]}`,
|
|
1684
|
-
}) + open('path', {
|
|
1685
|
-
d, fill: `url(#${gradient})`, stroke: `url(#${gradient})`, 'stroke-width': width, opacity,
|
|
1686
|
-
}) + '</path></g>'
|
|
1687
|
-
}
|
|
1688
|
-
|
|
1689
|
-
function seaweedMarkup() {
|
|
1690
|
-
const blade = bladeMarkup
|
|
1691
|
-
|
|
3099
|
+
function gcFeatherMarkup(key) {
|
|
3100
|
+
const gradient = `dsh-gc-feather-${key}`
|
|
1692
3101
|
return open('svg', {
|
|
1693
|
-
viewBox: '0 0
|
|
1694
|
-
|
|
1695
|
-
|
|
3102
|
+
viewBox: '0 0 40 90',
|
|
3103
|
+
style: 'display:block;width:100%;height:auto;overflow:visible;'
|
|
3104
|
+
+ 'filter:drop-shadow(0 0 5px rgba(255,214,0,.3))',
|
|
1696
3105
|
})
|
|
1697
3106
|
+ open('defs', {})
|
|
1698
|
-
+ open('linearGradient', { id:
|
|
1699
|
-
+ open('stop', { offset: '0', 'stop-color': '#
|
|
1700
|
-
+ open('stop', { offset: '
|
|
1701
|
-
+ open('stop', { offset: '
|
|
1702
|
-
+ '</linearGradient>'
|
|
1703
|
-
+ open('linearGradient', { id: 'dsh-dof-weed-b', x1: '0', y1: '1', x2: '0', y2: '0' })
|
|
1704
|
-
+ open('stop', { offset: '0', 'stop-color': '#2B7FA6' }) + '</stop>'
|
|
1705
|
-
+ open('stop', { offset: '0.6', 'stop-color': '#4FA3C6' }) + '</stop>'
|
|
1706
|
-
+ open('stop', { offset: '1', 'stop-color': '#B8E2F2', 'stop-opacity': '0.85' }) + '</stop>'
|
|
1707
|
-
+ '</linearGradient>'
|
|
1708
|
-
+ open('linearGradient', { id: 'dsh-dof-weed-c', x1: '0', y1: '1', x2: '0', y2: '0' })
|
|
1709
|
-
+ open('stop', { offset: '0', 'stop-color': '#4A78A8' }) + '</stop>'
|
|
1710
|
-
+ open('stop', { offset: '0.6', 'stop-color': '#7FA9CE' }) + '</stop>'
|
|
1711
|
-
+ open('stop', { offset: '1', 'stop-color': '#CBE2F4', 'stop-opacity': '0.8' }) + '</stop>'
|
|
3107
|
+
+ open('linearGradient', { id: gradient, x1: '0', y1: '0', x2: '0', y2: '1' })
|
|
3108
|
+
+ open('stop', { offset: '0%', 'stop-color': '#FFEB3B', 'stop-opacity': '0.9' }) + '</stop>'
|
|
3109
|
+
+ open('stop', { offset: '60%', 'stop-color': '#FF6F00', 'stop-opacity': '0.8' }) + '</stop>'
|
|
3110
|
+
+ open('stop', { offset: '100%', 'stop-color': '#D50000', 'stop-opacity': '0' }) + '</stop>'
|
|
1712
3111
|
+ '</linearGradient>'
|
|
1713
3112
|
+ '</defs>'
|
|
1714
|
-
+
|
|
1715
|
-
+
|
|
1716
|
-
+ blade('3', 'M 74 120 C 68 102, 78 88, 72 68 C 69 58, 72 48, 78 40 C 74 52, 78 62, 82 76 C 86 94, 80 108, 82 120 Z', 'dsh-dof-weed-c', '1.8', '0.88')
|
|
1717
|
-
+ blade('4', 'M 96 120 C 92 104, 102 90, 96 72 C 93 62, 96 54, 102 46 C 98 58, 102 68, 106 82 C 110 98, 102 110, 104 120 Z', 'dsh-dof-weed-a', '1.6', '0.85')
|
|
1718
|
-
+ blade('5', 'M 118 120 C 114 108, 122 96, 117 82 C 115 74, 117 68, 121 62 C 118 72, 121 80, 124 92 C 127 104, 121 112, 123 120 Z', 'dsh-dof-weed-b', '1.4', '0.8')
|
|
1719
|
-
+ open('ellipse', { cx: '30', cy: '119', rx: '14', ry: '4', fill: '#7FAFC6', opacity: '0.55' }) + '</ellipse>'
|
|
1720
|
-
+ open('ellipse', { cx: '72', cy: '120', rx: '10', ry: '3.4', fill: '#8FB9CE', opacity: '0.5' }) + '</ellipse>'
|
|
1721
|
-
+ open('ellipse', { cx: '108', cy: '119.5', rx: '12', ry: '3.6', fill: '#7FAFC6', opacity: '0.45' }) + '</ellipse>'
|
|
3113
|
+
+ open('path', { d: 'M 20 4 C 27 22, 27 50, 20 86 C 13 50, 13 22, 20 4 Z', fill: `url(#${gradient})` }) + '</path>'
|
|
3114
|
+
+ open('path', { d: 'M 20 8 L 20 82', stroke: '#FFE082', 'stroke-width': '1.2', 'stroke-linecap': 'round', opacity: '0.55', fill: 'none' }) + '</path>'
|
|
1722
3115
|
+ '</svg>'
|
|
1723
3116
|
}
|
|
1724
3117
|
|
|
1725
3118
|
/**
|
|
1726
|
-
*
|
|
3119
|
+
* The 光彩凤晨 scene: sweeping dawn rays, falling phoenix feathers, a
|
|
3120
|
+
* brush-stroke phoenix flying out and back (the flip happens while transparent,
|
|
3121
|
+
* exactly as the source notes), and twinkling dew.
|
|
1727
3122
|
*
|
|
1728
|
-
* Ported from
|
|
1729
|
-
*
|
|
1730
|
-
*
|
|
1731
|
-
*
|
|
1732
|
-
*
|
|
1733
|
-
*
|
|
1734
|
-
*
|
|
1735
|
-
*
|
|
1736
|
-
* the source values (`#38bdf8` body, `#1d4ed8` fins) sat outside the dream palette and
|
|
1737
|
-
* read as a sticker, the same treatment shan's mountains got when their source greens
|
|
1738
|
-
* were darkened for this sidebar.
|
|
1739
|
-
* @param suffix - unique id suffix, so several fish can coexist.
|
|
1740
|
-
* @param size - rendered width in em.
|
|
1741
|
-
* @param top - vertical position within the water, as a percentage.
|
|
1742
|
-
* @param duration - seconds for one crossing.
|
|
1743
|
-
* @param delay - animation delay, so the fish do not move in lockstep.
|
|
1744
|
-
* @param flip - whether this fish swims right-to-left instead.
|
|
1745
|
-
* @returns the fish markup.
|
|
3123
|
+
* Ported from `GuangCaiFengChenAnimation.vue`. The source's fill path references
|
|
3124
|
+
* a gradient that file never defines, so the rendered phoenix is strokes only —
|
|
3125
|
+
* this port keeps that rendered look with `fill="none"` instead of inventing a
|
|
3126
|
+
* fill the source never showed. Stroke widths are the source's effective values
|
|
3127
|
+
* (its `!important` class overrides baked in).
|
|
3128
|
+
* @param feathers - how many feathers to seed.
|
|
3129
|
+
* @param dew - how many dew drops to seed.
|
|
3130
|
+
* @returns the scene markup.
|
|
1746
3131
|
*/
|
|
1747
|
-
function
|
|
1748
|
-
const
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
3132
|
+
function fengchenAmbientScene(feathers, dew) {
|
|
3133
|
+
const featherCount = Math.max(0, Math.min(16, feathers ?? 6))
|
|
3134
|
+
let featherNodes = ''
|
|
3135
|
+
for (let n = 1; n <= featherCount; n += 1) {
|
|
3136
|
+
featherNodes += open('div', {
|
|
3137
|
+
class: 'gc-feather',
|
|
3138
|
+
style: `position:absolute;top:-6em;left:${((n * 23) % 80) + 8}%;width:2.6em;opacity:0;`
|
|
3139
|
+
+ `animation:dsh-amb-gc-feather ${15 + ((n * 3) % 8)}s ease-in-out infinite;`
|
|
3140
|
+
+ `animation-delay:${-(n * 1.5)}s`,
|
|
3141
|
+
})
|
|
3142
|
+
+ open('div', {
|
|
3143
|
+
style: `transform:scale(${(0.5 + ((n * 7) % 6) / 10).toFixed(1)})`,
|
|
3144
|
+
})
|
|
3145
|
+
+ gcFeatherMarkup(String(n))
|
|
3146
|
+
+ '</div></div>'
|
|
3147
|
+
}
|
|
3148
|
+
|
|
3149
|
+
const dewCount = Math.max(0, Math.min(30, dew ?? 10))
|
|
3150
|
+
let dewNodes = ''
|
|
3151
|
+
for (let n = 1; n <= dewCount; n += 1) {
|
|
3152
|
+
dewNodes += open('div', {
|
|
3153
|
+
class: 'gc-dew',
|
|
3154
|
+
style: 'position:absolute;width:3px;height:3px;border-radius:50%;opacity:.5;'
|
|
3155
|
+
+ `left:${((n * 37) % 84) + 6}%;top:${((n * 29) % 62) + 6}%;`
|
|
3156
|
+
+ 'background:radial-gradient(circle,#FFFFFF 0%,rgba(255,214,0,.8) 100%);'
|
|
3157
|
+
+ 'box-shadow:0 0 8px rgba(255,214,0,.8);'
|
|
3158
|
+
+ 'animation:dsh-amb-gc-dew 3s ease-in-out infinite alternate;'
|
|
3159
|
+
+ `animation-delay:${-(n * 0.2)}s`,
|
|
3160
|
+
}) + '</div>'
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3163
|
+
const ray = (key, rotation, delay) => open('div', {
|
|
3164
|
+
class: `gc-ray gc-ray-${key}`,
|
|
3165
|
+
style: `position:absolute;top:26%;left:-30%;width:160%;height:46%;`
|
|
3166
|
+
+ `transform:rotate(${rotation}deg);opacity:.5;pointer-events:none`,
|
|
1754
3167
|
})
|
|
1755
3168
|
+ open('div', {
|
|
1756
|
-
|
|
1757
|
-
|
|
3169
|
+
style: 'position:absolute;inset:0;'
|
|
3170
|
+
+ 'background:linear-gradient(45deg,transparent 0%,rgba(255,214,0,.12) 30%,rgba(255,111,0,.06) 60%,transparent 100%);'
|
|
3171
|
+
+ `animation:dsh-amb-gc-ray 8s ease-in-out infinite alternate;animation-delay:${delay}`,
|
|
3172
|
+
}) + '</div>'
|
|
3173
|
+
+ '</div>'
|
|
3174
|
+
|
|
3175
|
+
return open('div', { class: 'gc', style: 'position:absolute;inset:0;display:block' })
|
|
3176
|
+
+ ray('1', '-18', '0s')
|
|
3177
|
+
+ ray('2', '-9', '-0.5s')
|
|
3178
|
+
+ ray('3', '0', '-1s')
|
|
3179
|
+
+ ray('4', '9', '-1.5s')
|
|
3180
|
+
+ ray('5', '18', '-2s')
|
|
3181
|
+
+ dewNodes
|
|
3182
|
+
+ featherNodes
|
|
3183
|
+
+ open('div', {
|
|
3184
|
+
class: 'gc-phoenix',
|
|
3185
|
+
style: 'position:absolute;top:14%;left:0;width:9.5em;z-index:8;will-change:transform;'
|
|
3186
|
+
+ 'animation:dsh-amb-gc-fly 28s linear infinite',
|
|
3187
|
+
})
|
|
3188
|
+
+ open('div', {
|
|
3189
|
+
class: 'gc-bob',
|
|
3190
|
+
style: 'animation:dsh-amb-gc-bob 3.4s ease-in-out infinite',
|
|
1758
3191
|
})
|
|
1759
3192
|
+ open('svg', {
|
|
1760
|
-
viewBox: '0 0
|
|
1761
|
-
|
|
1762
|
-
|
|
3193
|
+
viewBox: '0 0 800 600',
|
|
3194
|
+
style: 'display:block;width:100%;height:auto;overflow:visible;'
|
|
3195
|
+
+ 'filter:drop-shadow(0 0 18px rgba(255,214,0,.55))',
|
|
1763
3196
|
})
|
|
1764
|
-
+ open('
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
3197
|
+
+ open('defs', {})
|
|
3198
|
+
+ open('linearGradient', { id: 'dsh-gc-phoenix-stroke', x1: '0', y1: '0', x2: '1', y2: '0' })
|
|
3199
|
+
+ open('stop', { offset: '0%', 'stop-color': '#FFEB3B' }) + '</stop>'
|
|
3200
|
+
+ open('stop', { offset: '40%', 'stop-color': '#FF9800' }) + '</stop>'
|
|
3201
|
+
+ open('stop', { offset: '100%', 'stop-color': '#D50000' }) + '</stop>'
|
|
3202
|
+
+ '</linearGradient>'
|
|
3203
|
+
+ open('filter', { id: 'dsh-gc-glow' })
|
|
3204
|
+
+ open('feGaussianBlur', { stdDeviation: '2', result: 'coloredBlur' }) + '</feGaussianBlur>'
|
|
3205
|
+
+ open('feMerge', {})
|
|
3206
|
+
+ open('feMergeNode', { in: 'coloredBlur' }) + '</feMergeNode>'
|
|
3207
|
+
+ open('feMergeNode', { in: 'SourceGraphic' }) + '</feMergeNode>'
|
|
3208
|
+
+ '</feMerge>'
|
|
3209
|
+
+ '</filter>'
|
|
3210
|
+
+ '</defs>'
|
|
3211
|
+
+ open('g', { filter: 'url(#dsh-gc-glow)', transform: 'translate(100, 100) scale(1.2)' })
|
|
1769
3212
|
+ open('path', {
|
|
1770
|
-
d: '
|
|
1771
|
-
fill: '
|
|
3213
|
+
d: 'M 380 50 C 360 40 350 60 360 90 C 350 120 380 140 320 180 C 280 220 350 280 200 350 C 150 380 100 360 50 400 C 140 300 220 220 320 180 C 360 140 380 90 380 50 Z',
|
|
3214
|
+
fill: 'none',
|
|
1772
3215
|
}) + '</path>'
|
|
1773
|
-
// Tail
|
|
1774
3216
|
+ open('path', {
|
|
1775
|
-
|
|
1776
|
-
|
|
3217
|
+
class: 'gc-head',
|
|
3218
|
+
d: 'M 380 50 Q 360 40 346 58 T 358 90 L 374 86',
|
|
3219
|
+
stroke: 'url(#dsh-gc-phoenix-stroke)', 'stroke-width': '3.5', fill: 'none', 'stroke-linecap': 'round',
|
|
1777
3220
|
}) + '</path>'
|
|
1778
|
-
// Dorsal fin
|
|
1779
3221
|
+ open('path', {
|
|
1780
|
-
|
|
1781
|
-
|
|
3222
|
+
class: 'gc-crest',
|
|
3223
|
+
d: 'M 360 50 Q 340 20 310 30',
|
|
3224
|
+
stroke: 'url(#dsh-gc-phoenix-stroke)', 'stroke-width': '2.5', fill: 'none', 'stroke-linecap': 'round',
|
|
1782
3225
|
}) + '</path>'
|
|
1783
|
-
// Pectoral fin
|
|
1784
3226
|
+ open('path', {
|
|
1785
|
-
|
|
1786
|
-
|
|
3227
|
+
class: 'gc-crest',
|
|
3228
|
+
d: 'M 365 55 Q 355 35 330 40',
|
|
3229
|
+
stroke: 'url(#dsh-gc-phoenix-stroke)', 'stroke-width': '2.5', fill: 'none', 'stroke-linecap': 'round',
|
|
1787
3230
|
}) + '</path>'
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
3231
|
+
+ open('path', {
|
|
3232
|
+
class: 'gc-neck',
|
|
3233
|
+
d: 'M 360 90 C 350 120, 380 140, 320 180',
|
|
3234
|
+
stroke: 'url(#dsh-gc-phoenix-stroke)', 'stroke-width': '7', fill: 'none', 'stroke-linecap': 'round',
|
|
3235
|
+
}) + '</path>'
|
|
3236
|
+
+ open('path', {
|
|
3237
|
+
class: 'gc-wing gc-wing-main',
|
|
3238
|
+
d: 'M 340 110 C 260 70, 200 40, 140 90',
|
|
3239
|
+
stroke: 'url(#dsh-gc-phoenix-stroke)', 'stroke-width': '6', fill: 'none', 'stroke-linecap': 'round',
|
|
3240
|
+
style: 'transform-box:fill-box;transform-origin:30% 40%;animation:dsh-amb-gc-wing 3.4s ease-in-out infinite',
|
|
3241
|
+
}) + '</path>'
|
|
3242
|
+
+ open('path', {
|
|
3243
|
+
d: 'M 300 100 C 250 80, 180 80, 140 120',
|
|
3244
|
+
stroke: 'url(#dsh-gc-phoenix-stroke)', 'stroke-width': '3', fill: 'none', 'stroke-linecap': 'round',
|
|
3245
|
+
}) + '</path>'
|
|
3246
|
+
+ open('path', {
|
|
3247
|
+
d: 'M 280 110 C 240 100, 180 110, 150 140',
|
|
3248
|
+
stroke: 'url(#dsh-gc-phoenix-stroke)', 'stroke-width': '2', fill: 'none', 'stroke-linecap': 'round',
|
|
3249
|
+
}) + '</path>'
|
|
3250
|
+
+ open('path', {
|
|
3251
|
+
class: 'gc-wing gc-wing-back',
|
|
3252
|
+
d: 'M 360 100 C 400 78, 452 66, 490 92',
|
|
3253
|
+
stroke: 'url(#dsh-gc-phoenix-stroke)', 'stroke-width': '4', fill: 'none', 'stroke-linecap': 'round',
|
|
3254
|
+
style: 'transform-box:fill-box;transform-origin:30% 40%;animation:dsh-amb-gc-wing 3.4s ease-in-out infinite',
|
|
3255
|
+
}) + '</path>'
|
|
3256
|
+
+ open('path', {
|
|
3257
|
+
d: 'M 370 110 C 400 100, 430 95, 460 110',
|
|
3258
|
+
stroke: 'url(#dsh-gc-phoenix-stroke)', 'stroke-width': '2', fill: 'none', 'stroke-linecap': 'round',
|
|
3259
|
+
}) + '</path>'
|
|
3260
|
+
+ open('path', {
|
|
3261
|
+
class: 'gc-tail-1',
|
|
3262
|
+
d: 'M 320 180 C 280 220, 350 280, 200 350 C 150 380, 100 360, 50 400',
|
|
3263
|
+
stroke: 'url(#dsh-gc-phoenix-stroke)', 'stroke-width': '5', fill: 'none', 'stroke-linecap': 'round',
|
|
3264
|
+
}) + '</path>'
|
|
3265
|
+
+ open('path', {
|
|
3266
|
+
class: 'gc-tail-2',
|
|
3267
|
+
d: 'M 310 185 C 250 250, 200 280, 100 300',
|
|
3268
|
+
stroke: 'url(#dsh-gc-phoenix-stroke)', 'stroke-width': '4', fill: 'none', 'stroke-linecap': 'round',
|
|
3269
|
+
}) + '</path>'
|
|
3270
|
+
+ open('path', {
|
|
3271
|
+
class: 'gc-tail-3',
|
|
3272
|
+
d: 'M 330 175 C 300 220, 250 350, 150 420',
|
|
3273
|
+
stroke: 'url(#dsh-gc-phoenix-stroke)', 'stroke-width': '3', fill: 'none', 'stroke-linecap': 'round',
|
|
3274
|
+
}) + '</path>'
|
|
3275
|
+
+ open('circle', { cx: '365', cy: '70', r: '2.5', fill: '#FFE082' }) + '</circle>'
|
|
1792
3276
|
+ '</g>'
|
|
1793
3277
|
+ '</svg>'
|
|
1794
3278
|
+ '</div></div>'
|
|
3279
|
+
+ '</div>'
|
|
1795
3280
|
}
|
|
1796
3281
|
|
|
1797
3282
|
/**
|
|
@@ -1874,7 +3359,17 @@ window.__ModuleLoader__.load({
|
|
|
1874
3359
|
? shanAmbientScene(options?.petals)
|
|
1875
3360
|
: kind === 'dream'
|
|
1876
3361
|
? dreamAmbientScene(options?.bubbles, options?.motes, options?.fish)
|
|
1877
|
-
: ''
|
|
3362
|
+
: kind === 'caiyun'
|
|
3363
|
+
? caiyunAmbientScene(options?.stars)
|
|
3364
|
+
: kind === 'dongyun'
|
|
3365
|
+
? dongyunAmbientScene(options?.snow)
|
|
3366
|
+
: kind === 'junyue'
|
|
3367
|
+
? junyueAmbientScene(options?.stars)
|
|
3368
|
+
: kind === 'jiexin'
|
|
3369
|
+
? jiexinAmbientScene(options?.dust)
|
|
3370
|
+
: kind === 'fengchen'
|
|
3371
|
+
? fengchenAmbientScene(options?.feathers, options?.dew)
|
|
3372
|
+
: ''
|
|
1878
3373
|
// The builder is fed only attributes and hex values, but this is the one place
|
|
1879
3374
|
// markup from outside this file could ever arrive, so it refuses anyway.
|
|
1880
3375
|
if (/<script|\son[a-z]+\s*=/i.test(markup)) {
|
|
@@ -2633,7 +4128,9 @@ window.__ModuleLoader__.load({
|
|
|
2633
4128
|
// the two need different fixes.
|
|
2634
4129
|
const scene = seat.firstElementChild
|
|
2635
4130
|
const sceneRect = scene === null ? null : scene.getBoundingClientRect()
|
|
2636
|
-
const art = seat.querySelector(
|
|
4131
|
+
const art = seat.querySelector(
|
|
4132
|
+
'.sta-mountains, .dof-seaweed, .ym-sea-front, .jp-river, .xs-ridges, .pj-zenscene, .gc-phoenix',
|
|
4133
|
+
)
|
|
2637
4134
|
const artRect = art === null ? null : art.getBoundingClientRect()
|
|
2638
4135
|
return {
|
|
2639
4136
|
found: true,
|
|
@@ -2767,6 +4264,28 @@ window.__ModuleLoader__.load({
|
|
|
2767
4264
|
return BUNDLED_THEMES.find((theme) => theme.id === id)
|
|
2768
4265
|
}
|
|
2769
4266
|
|
|
4267
|
+
/**
|
|
4268
|
+
* Read one token out of a bundled skin, resolving the pair form to the skin's own scheme.
|
|
4269
|
+
*
|
|
4270
|
+
* The bundled skins store most tokens as `{ light, dark }` pairs even though a skin itself is
|
|
4271
|
+
* single-scheme. `flatten` collapses them for `register`; this is the same read, exposed
|
|
4272
|
+
* separately because the accent diagnostic needs ONE token's declared value without building
|
|
4273
|
+
* the whole registrable definition — and because that diagnostic lives at factory scope, where
|
|
4274
|
+
* `flatten` (declared inside `mountGallery`) is not reachable. Reaching for it from here is the
|
|
4275
|
+
* exact scope error `tests/check-scope-reach.mjs` exists to catch.
|
|
4276
|
+
* @param definition - a bundled skin.
|
|
4277
|
+
* @param name - the token name.
|
|
4278
|
+
* @returns the declared value, or undefined when the skin has no such token.
|
|
4279
|
+
*/
|
|
4280
|
+
function declaredToken(definition, name) {
|
|
4281
|
+
const raw = definition?.tokens?.[name]
|
|
4282
|
+
if (raw === undefined) return undefined
|
|
4283
|
+
// Deliberately not `raw?.[…]`: a skin whose token is neither a string nor a pair is a data
|
|
4284
|
+
// error, and `flatten` (the other caller) must keep failing loudly on it rather than
|
|
4285
|
+
// registering an unset variable that paints nothing.
|
|
4286
|
+
return typeof raw === 'string' ? raw : raw[definition.colorScheme]
|
|
4287
|
+
}
|
|
4288
|
+
|
|
2770
4289
|
/**
|
|
2771
4290
|
* Disposer of the active accent layer, when one is stacked.
|
|
2772
4291
|
*
|
|
@@ -2779,6 +4298,20 @@ window.__ModuleLoader__.load({
|
|
|
2779
4298
|
*/
|
|
2780
4299
|
let accentLayerDispose
|
|
2781
4300
|
|
|
4301
|
+
/**
|
|
4302
|
+
* The accent colour {@link accentLayerDispose} was built from.
|
|
4303
|
+
*
|
|
4304
|
+
* Declared here for the same reason as the disposer above: `syncAccent` both reads and writes
|
|
4305
|
+
* it, and it is called during mount, so a `let` initialised later in the body would be in its
|
|
4306
|
+
* temporal dead zone at the first call.
|
|
4307
|
+
*
|
|
4308
|
+
* It exists so that re-stacking can be skipped when the colour has not moved. Without it every
|
|
4309
|
+
* `theme/change` — including ones this plugin caused and ones caused by something else —
|
|
4310
|
+
* disposed and re-created the layer, which emits again.
|
|
4311
|
+
* @type {string|undefined}
|
|
4312
|
+
*/
|
|
4313
|
+
let stackedAccent
|
|
4314
|
+
|
|
2782
4315
|
/**
|
|
2783
4316
|
* The plugin context, published for the factory-level helpers.
|
|
2784
4317
|
*
|
|
@@ -2827,15 +4360,46 @@ window.__ModuleLoader__.load({
|
|
|
2827
4360
|
// `try` swallowed it, and the accent marker silently never appeared. The module-level `ctx`
|
|
2828
4361
|
// below is assigned at mount and read here.
|
|
2829
4362
|
if (ctx === undefined) return
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
4363
|
+
const wanted = typeof accent === 'string' && accent !== '' ? accent : undefined
|
|
4364
|
+
// ── WHY BOTH A SKIP AND THE SELF-EMIT GUARD ARE NEEDED ───────────────────────────────────
|
|
4365
|
+
//
|
|
4366
|
+
// `overrideTokens` and the disposer it returns BOTH emit `theme/change`, and this function
|
|
4367
|
+
// is reached from `publish()`, which is itself driven by that event:
|
|
4368
|
+
//
|
|
4369
|
+
// publish → syncSkin → syncAccent → overrideTokens → theme/change → publish → …
|
|
4370
|
+
//
|
|
4371
|
+
// Every level nests inside the previous CALL, so nothing ever yields to the event loop. The
|
|
4372
|
+
// stack therefore grows until the engine refuses to grow it further and throws
|
|
4373
|
+
// `RangeError: Maximum call stack size exceeded` — and because every level has its own
|
|
4374
|
+
// `try/catch` (see `syncSkin`), each one logs the SAME message on the way out. That is why
|
|
4375
|
+
// the console showed a flood of "could not stack the accent layer" lines rather than one
|
|
4376
|
+
// error: one flood, hundreds of identical lines, each from a different depth.
|
|
4377
|
+
//
|
|
4378
|
+
// Fixing it takes both halves, and they are not interchangeable:
|
|
4379
|
+
//
|
|
4380
|
+
// • the SKIP stops the churn — an accent that has not moved does not need a new layer, so
|
|
4381
|
+
// an unrelated `theme/change` (the shell's `adopt()`, a streamed render, another plugin)
|
|
4382
|
+
// no longer replaces the layer and causes a repaint;
|
|
4383
|
+
// • the GUARD stops the RE-ENTRY — it is what makes the `theme/change` emitted by our own
|
|
4384
|
+
// write invisible to the subscription, so the cycle cannot close even when the colour
|
|
4385
|
+
// genuinely did change.
|
|
4386
|
+
//
|
|
4387
|
+
// Only the guard is a correctness requirement; the skip is what keeps the layer stable. The
|
|
4388
|
+
// same shape is used by `stackSkinTokens` for the palette and by `syncReadingLayer`.
|
|
4389
|
+
if (wanted === stackedAccent) return
|
|
4390
|
+
emitting(() => {
|
|
4391
|
+
if (accentLayerDispose !== undefined) {
|
|
4392
|
+
accentLayerDispose()
|
|
4393
|
+
accentLayerDispose = undefined
|
|
4394
|
+
}
|
|
4395
|
+
stackedAccent = undefined
|
|
4396
|
+
if (wanted === undefined) return
|
|
4397
|
+
accentLayerDispose = ctx.theme.overrideTokens('theme-gallery: accent', {
|
|
4398
|
+
'--dsw-alias-button-ghost-active-fill': { light: `${wanted}29`, dark: `${wanted}29` },
|
|
4399
|
+
'--dsw-alias-button-ghost-active-border': { light: wanted, dark: wanted },
|
|
4400
|
+
'--dsw-alias-button-ghost-active-hover': { light: `${wanted}47`, dark: `${wanted}47` },
|
|
4401
|
+
})
|
|
4402
|
+
stackedAccent = wanted
|
|
2839
4403
|
})
|
|
2840
4404
|
}
|
|
2841
4405
|
|
|
@@ -2852,8 +4416,27 @@ window.__ModuleLoader__.load({
|
|
|
2852
4416
|
*
|
|
2853
4417
|
* The service makes this checkable without any guesswork: `composeActive` folds every
|
|
2854
4418
|
* override layer into `snapshot.active.tokens` before publishing, so the composed value is
|
|
2855
|
-
* readable straight off `getTheme()`.
|
|
2856
|
-
*
|
|
4419
|
+
* readable straight off `getTheme()`.
|
|
4420
|
+
*
|
|
4421
|
+
* ── WHAT CAN AND CANNOT PROVE IT ─────────────────────────────────────────
|
|
4422
|
+
*
|
|
4423
|
+
* The composed VALUE is the only channel that carries information, and only when it differs
|
|
4424
|
+
* from what the skin declares for that same token:
|
|
4425
|
+
*
|
|
4426
|
+
* • both bundled skins already ship `button-ghost-active-*` in their own palettes, AND the
|
|
4427
|
+
* palette layer supplies them too — so the token COUNT is 67 either way. An earlier
|
|
4428
|
+
* comment here claimed a count that "does not move" disproves the layer; for these skins
|
|
4429
|
+
* it cannot move, so the claim was wrong and the count is reported for context only;
|
|
4430
|
+
* • 梦海游鱼 declares `#2B74B5` for that token but its accent is `#FFD166`, so reading back
|
|
4431
|
+
* `#FFD166` proves the accent layer composed OVER the palette — the palette alone cannot
|
|
4432
|
+
* produce it;
|
|
4433
|
+
* • 山青婷彩's accent is `#E88BB0` and it declares `#E88BB0` for the same token, so its
|
|
4434
|
+
* reading is identical whether or not the layer is there. That is a property of the SKIN,
|
|
4435
|
+
* not of the layer, and the verdict below says so instead of implying the reading proved
|
|
4436
|
+
* something.
|
|
4437
|
+
*
|
|
4438
|
+
* The verdict is therefore computed, never asserted: it compares the composed value with the
|
|
4439
|
+
* skin's declared value and with the accent the layer was built from.
|
|
2857
4440
|
* @returns the reading, as one segment of the panel line.
|
|
2858
4441
|
*/
|
|
2859
4442
|
function describeAccentLayer() {
|
|
@@ -2864,16 +4447,31 @@ window.__ModuleLoader__.load({
|
|
|
2864
4447
|
const active = snapshot?.active
|
|
2865
4448
|
const tokens = active?.tokens ?? {}
|
|
2866
4449
|
const TOKEN = '--dsw-alias-button-ghost-active-border'
|
|
2867
|
-
const
|
|
4450
|
+
const composed = tokens[TOKEN]
|
|
4451
|
+
const definition = typeof active?.id === 'string' ? bundledTheme(active.id) : undefined
|
|
4452
|
+
const declared = declaredToken(definition, TOKEN)
|
|
4453
|
+
const accent = definition?.accent
|
|
2868
4454
|
const layers = snapshot?.overrides === undefined
|
|
2869
4455
|
? '(服务未暴露)'
|
|
2870
4456
|
: String(snapshot.overrides.size ?? snapshot.overrides.length ?? '?')
|
|
2871
|
-
//
|
|
2872
|
-
//
|
|
4457
|
+
// Computed, not assumed — see the note above. `不可分辨` is a real answer: it says this
|
|
4458
|
+
// skin's own value coincides with its accent, so this reading proves nothing either way.
|
|
4459
|
+
const verdict = accent === undefined
|
|
4460
|
+
? '非本包皮肤(无法判断)'
|
|
4461
|
+
: accent === declared
|
|
4462
|
+
? '不可分辨(强调色=皮肤自备值)'
|
|
4463
|
+
: composed === accent
|
|
4464
|
+
? '生效(强调色压过自备值)'
|
|
4465
|
+
: composed === declared
|
|
4466
|
+
? '未生效(仍是自备值)'
|
|
4467
|
+
: `未知(既非强调色也非自备值)`
|
|
2873
4468
|
return `激活层[id=${active?.id ?? '?'}`
|
|
2874
4469
|
+ ` 层数=${layers}`
|
|
2875
|
-
+ ` token数=${Object.keys(tokens).length}`
|
|
2876
|
-
+ ` ${TOKEN.replace('--dsw-alias-', '')}=${
|
|
4470
|
+
+ ` token数=${Object.keys(tokens).length}(自备同名令牌,不构成判据)`
|
|
4471
|
+
+ ` ${TOKEN.replace('--dsw-alias-', '')}=${composed === undefined ? '(缺失)' : String(composed)}`
|
|
4472
|
+
+ ` 自备=${declared === undefined ? '(无)' : String(declared)}`
|
|
4473
|
+
+ ` 强调色=${accent ?? '(无)'}`
|
|
4474
|
+
+ ` 判据=${verdict}]`
|
|
2877
4475
|
} catch (error) {
|
|
2878
4476
|
return `激活层[读取失败: ${String(error && error.message ? error.message : error)}]`
|
|
2879
4477
|
}
|
|
@@ -2922,18 +4520,11 @@ window.__ModuleLoader__.load({
|
|
|
2922
4520
|
jsx('span', { className: 'tg-title', children: t('title') }),
|
|
2923
4521
|
jsx('span', { className: 'tg-hint', children: t('hint') }),
|
|
2924
4522
|
jsx('span', { className: 'tg-hint', children: t('count', { count: ids.length }) }),
|
|
4523
|
+
// What this copy is, so a reader can compare it with the version npm
|
|
4524
|
+
// publishes without digging through the profile.
|
|
4525
|
+
jsx('span', { className: 'tg-hint', children: `v${BUNDLED_VERSION}` }),
|
|
2925
4526
|
],
|
|
2926
4527
|
}),
|
|
2927
|
-
debugEnabled() ? jsx('div', { className: 'tg-debug', children: themeDiagnostics(selected) }) : null,
|
|
2928
|
-
// Routine reports wait for the debug switch; warnings and errors print
|
|
2929
|
-
// regardless — when the active skin's decorations are missing, the reason
|
|
2930
|
-
// has to reach the person looking at the panel.
|
|
2931
|
-
showScenery
|
|
2932
|
-
? jsx('div', {
|
|
2933
|
-
className: `tg-debug${ambientWarning(selected) === null ? '' : ' tg-warn'}`,
|
|
2934
|
-
children: scenery,
|
|
2935
|
-
})
|
|
2936
|
-
: null,
|
|
2937
4528
|
jsx('div', {
|
|
2938
4529
|
className: 'tg-grid',
|
|
2939
4530
|
children: ids.map((id) => jsx(ThemeCard, {
|
|
@@ -2947,6 +4538,31 @@ window.__ModuleLoader__.load({
|
|
|
2947
4538
|
t,
|
|
2948
4539
|
}, id)),
|
|
2949
4540
|
}),
|
|
4541
|
+
// ── the diagnostics go BELOW the cards, set apart, behind a caption ──────
|
|
4542
|
+
//
|
|
4543
|
+
// They used to sit between the header and the picker, where a wall of monospace
|
|
4544
|
+
// text buried the thing the panel exists for. Below the cards they read as a
|
|
4545
|
+
// reference block — and the caption is what keeps them from being mistaken for a
|
|
4546
|
+
// malfunction, which is exactly how a user read them. They stay CONDITIONAL:
|
|
4547
|
+
// detail waits for the debug switch, while a warning or a failure always prints.
|
|
4548
|
+
(debugEnabled() || showScenery)
|
|
4549
|
+
? jsxs('div', {
|
|
4550
|
+
className: 'tg-diag',
|
|
4551
|
+
children: [
|
|
4552
|
+
jsx('div', { className: 'tg-diag-note', children: t('diagNote') }),
|
|
4553
|
+
debugEnabled() ? jsx('div', { className: 'tg-debug', children: themeDiagnostics(selected) }) : null,
|
|
4554
|
+
// Routine reports wait for the debug switch; warnings and errors print
|
|
4555
|
+
// regardless — when the active skin's decorations are missing, the reason
|
|
4556
|
+
// has to reach the person looking at the panel.
|
|
4557
|
+
showScenery
|
|
4558
|
+
? jsx('div', {
|
|
4559
|
+
className: `tg-debug${ambientWarning(selected) === null ? '' : ' tg-warn'}`,
|
|
4560
|
+
children: scenery,
|
|
4561
|
+
})
|
|
4562
|
+
: null,
|
|
4563
|
+
],
|
|
4564
|
+
})
|
|
4565
|
+
: null,
|
|
2950
4566
|
],
|
|
2951
4567
|
})
|
|
2952
4568
|
}
|
|
@@ -3725,8 +5341,10 @@ window.__ModuleLoader__.load({
|
|
|
3725
5341
|
*/
|
|
3726
5342
|
function flatten(definition) {
|
|
3727
5343
|
const tokens = {}
|
|
3728
|
-
for (const
|
|
3729
|
-
|
|
5344
|
+
for (const name of Object.keys(definition.tokens ?? {})) {
|
|
5345
|
+
// Delegated so the pair rule has exactly ONE implementation — the accent diagnostic reads
|
|
5346
|
+
// a single token through the same helper, and two copies of this rule would drift.
|
|
5347
|
+
tokens[name] = declaredToken(definition, name)
|
|
3730
5348
|
}
|
|
3731
5349
|
return { ...definition, tokens }
|
|
3732
5350
|
}
|
|
@@ -4101,6 +5719,17 @@ window.__ModuleLoader__.load({
|
|
|
4101
5719
|
let readingTag
|
|
4102
5720
|
/** Disposer of the active reading token layer, when one is stacked. */
|
|
4103
5721
|
let readingLayerDispose
|
|
5722
|
+
/**
|
|
5723
|
+
* The lightened ground {@link readingLayerDispose} was built from.
|
|
5724
|
+
*
|
|
5725
|
+
* Same role as `stackedAccent`: `syncReadingLayer` writes to the theme service, and it is
|
|
5726
|
+
* scheduled from a `MutationObserver` on `document.body` — so without this, every batch of
|
|
5727
|
+
* DOM mutations would replace the layer, which emits `theme/change`, which repaints the
|
|
5728
|
+
* shell, which mutates the DOM again. That is a loop through the microtask queue rather than
|
|
5729
|
+
* through the stack, so it would burn CPU steadily instead of throwing.
|
|
5730
|
+
* @type {string|undefined}
|
|
5731
|
+
*/
|
|
5732
|
+
let stackedReading
|
|
4104
5733
|
|
|
4105
5734
|
/**
|
|
4106
5735
|
* Install the reading rule, once per plugin lifetime.
|
|
@@ -4199,25 +5828,41 @@ window.__ModuleLoader__.load({
|
|
|
4199
5828
|
* `overrideTokens(source, tokens)` folds a `{ light, dark }`-shaped layer
|
|
4200
5829
|
* over the ACTIVE theme, so the lightening follows whichever skin and
|
|
4201
5830
|
* palette is in play and disappears cleanly when the transcript empties.
|
|
4202
|
-
*
|
|
4203
|
-
* source
|
|
5831
|
+
*
|
|
5832
|
+
* The source string is the layer's identity, so re-stacking the same source
|
|
5833
|
+
* REPLACES the layer instead of adding a second one. Replacement alone is not
|
|
5834
|
+
* idempotence: the call still emits `theme/change`, so it is the skip below
|
|
5835
|
+
* (`wanted === stackedReading`) that keeps an unchanged document from churning
|
|
5836
|
+
* the layer on every mutation batch.
|
|
4204
5837
|
*/
|
|
4205
5838
|
function syncReadingLayer() {
|
|
4206
5839
|
if (typeof document === 'undefined') return
|
|
4207
5840
|
const reading = document.body !== null && document.body.hasAttribute(READING_ATTRIBUTE)
|
|
4208
|
-
|
|
5841
|
+
// Computed before the skip test, because the skip compares VALUES. `lighten` is pure, so
|
|
5842
|
+
// the same document state always yields the same pair and the comparison is exact.
|
|
5843
|
+
const wanted = reading ? lighten(READING.bg, READING.alpha) : undefined
|
|
5844
|
+
const wantedDark = reading
|
|
5845
|
+
// Lightened ground for both palettes: a light theme wants a softer wash, a dark one a
|
|
5846
|
+
// slightly raised surface. Both keep the theme's hue.
|
|
5847
|
+
? lighten(READING.bg, Math.max(0, READING.alpha - 0.2))
|
|
5848
|
+
: undefined
|
|
5849
|
+
|
|
5850
|
+
// Both writes below emit `theme/change`, and this function is reached from a
|
|
5851
|
+
// `MutationObserver` on `document.body` — the same tree the shell repaints when the theme
|
|
5852
|
+
// changes. See the comment in `syncAccent` for the full shape; the short version is that
|
|
5853
|
+
// an unguarded write here lets the layer drive its own trigger.
|
|
5854
|
+
if (wanted === stackedReading) return
|
|
5855
|
+
emitting(() => {
|
|
4209
5856
|
if (readingLayerDispose !== undefined) {
|
|
4210
5857
|
readingLayerDispose()
|
|
4211
5858
|
readingLayerDispose = undefined
|
|
4212
5859
|
}
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
readingLayerDispose = ctx.theme.overrideTokens('theme-gallery: reading', {
|
|
4220
|
-
'--dsw-alias-bg-base': { light: lightened, dark: darkLightened },
|
|
5860
|
+
stackedReading = undefined
|
|
5861
|
+
if (wanted === undefined) return
|
|
5862
|
+
readingLayerDispose = ctx.theme.overrideTokens('theme-gallery: reading', {
|
|
5863
|
+
'--dsw-alias-bg-base': { light: wanted, dark: wantedDark },
|
|
5864
|
+
})
|
|
5865
|
+
stackedReading = wanted
|
|
4221
5866
|
})
|
|
4222
5867
|
}
|
|
4223
5868
|
|
|
@@ -4246,10 +5891,17 @@ window.__ModuleLoader__.load({
|
|
|
4246
5891
|
observer.disconnect()
|
|
4247
5892
|
if (readingTag !== undefined) readingTag.remove()
|
|
4248
5893
|
readingTag = undefined
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
5894
|
+
// Guarded for the same reason as the writes in `syncReadingLayer`, and the remembered
|
|
5895
|
+
// value is cleared with the layer: leaving it set would make that function's skip test
|
|
5896
|
+
// believe a layer is still stacked after this one removed it, and it would then refuse
|
|
5897
|
+
// to re-stack.
|
|
5898
|
+
emitting(() => {
|
|
5899
|
+
if (readingLayerDispose !== undefined) {
|
|
5900
|
+
readingLayerDispose()
|
|
5901
|
+
readingLayerDispose = undefined
|
|
5902
|
+
}
|
|
5903
|
+
stackedReading = undefined
|
|
5904
|
+
})
|
|
4253
5905
|
document.body.removeAttribute(READING_ATTRIBUTE)
|
|
4254
5906
|
const centre = centreColumn()
|
|
4255
5907
|
if (centre !== null) centre.style.removeProperty('--dsh-reading-width')
|