@work-rjkashyap/unified-ui 0.3.2 → 0.3.4
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/CHANGELOG.md +7 -0
- package/bin/cli.mjs +248 -3
- package/dist/{chunk-ZBGR7MUW.cjs → chunk-6ZZZBOCH.cjs} +136 -1
- package/dist/{chunk-IVZAB7BV.mjs → chunk-AAEWG5VR.mjs} +128 -2
- package/dist/{chunk-EQWESXRH.mjs → chunk-BJ55D5IK.mjs} +800 -102
- package/dist/{chunk-5TP7J7T4.cjs → chunk-RUG3BW2B.cjs} +862 -157
- package/dist/index.cjs +74 -50
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/theme.cjs +60 -32
- package/dist/theme.d.cts +28 -2
- package/dist/theme.d.ts +28 -2
- package/dist/theme.mjs +2 -2
- package/dist/tokens.cjs +19 -19
- package/dist/tokens.d.cts +1 -1
- package/dist/tokens.d.ts +1 -1
- package/dist/tokens.mjs +1 -1
- package/dist/{z-index-Dd8IllRx.d.cts → z-index-DmLl6FUD.d.cts} +117 -0
- package/dist/{z-index-Dd8IllRx.d.ts → z-index-DmLl6FUD.d.ts} +117 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { blue, red, amber, green, zinc, slate, gray, teal, brand, zIndex, shadow, radius, semanticLight, shadowDark, semanticDark } from './chunk-
|
|
1
|
+
import { blue, red, amber, green, zinc, slate, gray, teal, brand, indigo, purple, pink, cyan, emerald, yellow, fuchsia, sky, lime, zIndex, shadow, radius, semanticLight, shadowDark, semanticDark } from './chunk-AAEWG5VR.mjs';
|
|
2
2
|
import { fontFamily } from './chunk-ITBG42M5.mjs';
|
|
3
3
|
import { easingCSS, durationCSS } from './chunk-EZ2L3XPS.mjs';
|
|
4
4
|
import { cn } from './chunk-ZT3PCXDF.mjs';
|
|
@@ -578,6 +578,46 @@ var COLOR_PRESETS = [
|
|
|
578
578
|
{
|
|
579
579
|
swatch: brand[600],
|
|
580
580
|
...buildChromaticPreset("Brand", "brand", brand)
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
swatch: indigo[600],
|
|
584
|
+
...buildChromaticPreset("Indigo", "indigo", indigo)
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
swatch: purple[600],
|
|
588
|
+
...buildChromaticPreset("Purple", "purple", purple)
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
swatch: pink[600],
|
|
592
|
+
...buildChromaticPreset("Pink", "pink", pink)
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
swatch: cyan[600],
|
|
596
|
+
...buildChromaticPreset("Cyan", "cyan", cyan)
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
swatch: emerald[600],
|
|
600
|
+
...buildChromaticPreset("Emerald", "emerald", emerald)
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
swatch: yellow[600],
|
|
604
|
+
...buildChromaticPreset("Yellow", "yellow", yellow)
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
swatch: fuchsia[600],
|
|
608
|
+
...buildChromaticPreset("Fuchsia", "fuchsia", fuchsia)
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
swatch: sky[600],
|
|
612
|
+
...buildChromaticPreset("Sky", "sky", sky)
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
swatch: lime[600],
|
|
616
|
+
...buildChromaticPreset("Lime", "lime", lime)
|
|
617
|
+
},
|
|
618
|
+
{
|
|
619
|
+
swatch: amber[600],
|
|
620
|
+
...buildChromaticPreset("Amber", "amber", amber)
|
|
581
621
|
}
|
|
582
622
|
];
|
|
583
623
|
function getColorPreset(key) {
|
|
@@ -598,6 +638,7 @@ function getRadiusPreset(key) {
|
|
|
598
638
|
return RADIUS_PRESETS.find((r) => r.key === key) ?? RADIUS_PRESETS[4];
|
|
599
639
|
}
|
|
600
640
|
var FONT_PRESETS = [
|
|
641
|
+
// ---- Built-in fonts (loaded via next/font in the docs app) ----
|
|
601
642
|
{
|
|
602
643
|
name: "Outfit",
|
|
603
644
|
key: "outfit",
|
|
@@ -610,6 +651,164 @@ var FONT_PRESETS = [
|
|
|
610
651
|
value: 'var(--font-inter), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
611
652
|
sample: "Aa"
|
|
612
653
|
},
|
|
654
|
+
{
|
|
655
|
+
name: "Geist Sans",
|
|
656
|
+
key: "geist-sans",
|
|
657
|
+
value: 'var(--font-geist-sans), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
658
|
+
sample: "Aa"
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
name: "DM Sans",
|
|
662
|
+
key: "dm-sans",
|
|
663
|
+
value: 'var(--font-dm-sans), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
664
|
+
sample: "Aa"
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
name: "Plus Jakarta Sans",
|
|
668
|
+
key: "plus-jakarta-sans",
|
|
669
|
+
value: 'var(--font-plus-jakarta-sans), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
670
|
+
sample: "Aa"
|
|
671
|
+
},
|
|
672
|
+
{
|
|
673
|
+
name: "Open Sans",
|
|
674
|
+
key: "open-sans",
|
|
675
|
+
value: 'var(--font-open-sans), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
676
|
+
sample: "Aa"
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
name: "Poppins",
|
|
680
|
+
key: "poppins",
|
|
681
|
+
value: 'var(--font-poppins), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
682
|
+
sample: "Aa"
|
|
683
|
+
},
|
|
684
|
+
{
|
|
685
|
+
name: "Montserrat",
|
|
686
|
+
key: "montserrat",
|
|
687
|
+
value: 'var(--font-montserrat), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
688
|
+
sample: "Aa"
|
|
689
|
+
},
|
|
690
|
+
{
|
|
691
|
+
name: "Lato",
|
|
692
|
+
key: "lato",
|
|
693
|
+
value: 'var(--font-lato), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
694
|
+
sample: "Aa"
|
|
695
|
+
},
|
|
696
|
+
{
|
|
697
|
+
name: "Nunito",
|
|
698
|
+
key: "nunito",
|
|
699
|
+
value: 'var(--font-nunito), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
700
|
+
sample: "Aa"
|
|
701
|
+
},
|
|
702
|
+
{
|
|
703
|
+
name: "Raleway",
|
|
704
|
+
key: "raleway",
|
|
705
|
+
value: 'var(--font-raleway), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
706
|
+
sample: "Aa"
|
|
707
|
+
},
|
|
708
|
+
{
|
|
709
|
+
name: "Rubik",
|
|
710
|
+
key: "rubik",
|
|
711
|
+
value: 'var(--font-rubik), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
712
|
+
sample: "Aa"
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
name: "Source Sans 3",
|
|
716
|
+
key: "source-sans-3",
|
|
717
|
+
value: 'var(--font-source-sans-3), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
718
|
+
sample: "Aa"
|
|
719
|
+
},
|
|
720
|
+
{
|
|
721
|
+
name: "Work Sans",
|
|
722
|
+
key: "work-sans",
|
|
723
|
+
value: 'var(--font-work-sans), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
724
|
+
sample: "Aa"
|
|
725
|
+
},
|
|
726
|
+
{
|
|
727
|
+
name: "Manrope",
|
|
728
|
+
key: "manrope",
|
|
729
|
+
value: 'var(--font-manrope), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
730
|
+
sample: "Aa"
|
|
731
|
+
},
|
|
732
|
+
{
|
|
733
|
+
name: "Space Grotesk",
|
|
734
|
+
key: "space-grotesk",
|
|
735
|
+
value: 'var(--font-space-grotesk), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
736
|
+
sample: "Aa"
|
|
737
|
+
},
|
|
738
|
+
// ---- Additional popular fonts ----
|
|
739
|
+
{
|
|
740
|
+
name: "Figtree",
|
|
741
|
+
key: "figtree",
|
|
742
|
+
value: 'var(--font-figtree), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
743
|
+
sample: "Aa"
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
name: "IBM Plex Sans",
|
|
747
|
+
key: "ibm-plex-sans",
|
|
748
|
+
value: 'var(--font-ibm-plex-sans), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
749
|
+
sample: "Aa"
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
name: "Quicksand",
|
|
753
|
+
key: "quicksand",
|
|
754
|
+
value: 'var(--font-quicksand), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
755
|
+
sample: "Aa"
|
|
756
|
+
},
|
|
757
|
+
{
|
|
758
|
+
name: "Cabin",
|
|
759
|
+
key: "cabin",
|
|
760
|
+
value: 'var(--font-cabin), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
761
|
+
sample: "Aa"
|
|
762
|
+
},
|
|
763
|
+
{
|
|
764
|
+
name: "Barlow",
|
|
765
|
+
key: "barlow",
|
|
766
|
+
value: 'var(--font-barlow), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
767
|
+
sample: "Aa"
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
name: "Josefin Sans",
|
|
771
|
+
key: "josefin-sans",
|
|
772
|
+
value: 'var(--font-josefin-sans), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
773
|
+
sample: "Aa"
|
|
774
|
+
},
|
|
775
|
+
{
|
|
776
|
+
name: "Karla",
|
|
777
|
+
key: "karla",
|
|
778
|
+
value: 'var(--font-karla), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
779
|
+
sample: "Aa"
|
|
780
|
+
},
|
|
781
|
+
{
|
|
782
|
+
name: "Mulish",
|
|
783
|
+
key: "mulish",
|
|
784
|
+
value: 'var(--font-mulish), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
785
|
+
sample: "Aa"
|
|
786
|
+
},
|
|
787
|
+
{
|
|
788
|
+
name: "Noto Sans",
|
|
789
|
+
key: "noto-sans",
|
|
790
|
+
value: 'var(--font-noto-sans), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
791
|
+
sample: "Aa"
|
|
792
|
+
},
|
|
793
|
+
{
|
|
794
|
+
name: "Ubuntu",
|
|
795
|
+
key: "ubuntu",
|
|
796
|
+
value: 'var(--font-ubuntu), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
797
|
+
sample: "Aa"
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
name: "Sora",
|
|
801
|
+
key: "sora",
|
|
802
|
+
value: 'var(--font-sora), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
803
|
+
sample: "Aa"
|
|
804
|
+
},
|
|
805
|
+
{
|
|
806
|
+
name: "Lexend",
|
|
807
|
+
key: "lexend",
|
|
808
|
+
value: 'var(--font-lexend), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
809
|
+
sample: "Aa"
|
|
810
|
+
},
|
|
811
|
+
// ---- Generic stacks ----
|
|
613
812
|
{
|
|
614
813
|
name: "System",
|
|
615
814
|
key: "system",
|
|
@@ -749,6 +948,53 @@ var SURFACE_STYLE_PRESETS = [
|
|
|
749
948
|
}
|
|
750
949
|
];
|
|
751
950
|
var DEFAULT_SURFACE_STYLE_KEY = "bordered";
|
|
951
|
+
var MENU_COLOR_PRESETS = [
|
|
952
|
+
{
|
|
953
|
+
name: "Default",
|
|
954
|
+
key: "default",
|
|
955
|
+
description: "Uses the color preset's built-in sidebar colors"
|
|
956
|
+
},
|
|
957
|
+
{
|
|
958
|
+
name: "Muted",
|
|
959
|
+
key: "muted",
|
|
960
|
+
description: "Sidebar matches the muted/surface tone \u2014 blends with content"
|
|
961
|
+
},
|
|
962
|
+
{
|
|
963
|
+
name: "Inverted",
|
|
964
|
+
key: "inverted",
|
|
965
|
+
description: "Dark sidebar in light mode, lighter sidebar in dark mode for contrast"
|
|
966
|
+
},
|
|
967
|
+
{
|
|
968
|
+
name: "Primary",
|
|
969
|
+
key: "primary",
|
|
970
|
+
description: "Sidebar uses the primary color as its background"
|
|
971
|
+
}
|
|
972
|
+
];
|
|
973
|
+
var DEFAULT_MENU_COLOR_KEY = "default";
|
|
974
|
+
function getMenuColorPreset(key) {
|
|
975
|
+
return MENU_COLOR_PRESETS.find((p) => p.key === key) ?? MENU_COLOR_PRESETS[0];
|
|
976
|
+
}
|
|
977
|
+
var MENU_ACCENT_PRESETS = [
|
|
978
|
+
{
|
|
979
|
+
name: "None",
|
|
980
|
+
key: "none",
|
|
981
|
+
description: "No visual accent highlight on sidebar items"
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
name: "Subtle",
|
|
985
|
+
key: "subtle",
|
|
986
|
+
description: "Soft background tint on hover and active sidebar items"
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
name: "Bold",
|
|
990
|
+
key: "bold",
|
|
991
|
+
description: "Prominent primary-colored accent on active sidebar items"
|
|
992
|
+
}
|
|
993
|
+
];
|
|
994
|
+
var DEFAULT_MENU_ACCENT_KEY = "subtle";
|
|
995
|
+
function getMenuAccentPreset(key) {
|
|
996
|
+
return MENU_ACCENT_PRESETS.find((p) => p.key === key) ?? MENU_ACCENT_PRESETS[1];
|
|
997
|
+
}
|
|
752
998
|
var STYLE_PRESETS = [
|
|
753
999
|
{
|
|
754
1000
|
name: "Vega",
|
|
@@ -866,7 +1112,9 @@ var DEFAULT_THEME_CONFIG = {
|
|
|
866
1112
|
radius: DEFAULT_RADIUS_KEY,
|
|
867
1113
|
font: DEFAULT_FONT_KEY,
|
|
868
1114
|
shadow: DEFAULT_SHADOW_KEY,
|
|
869
|
-
surfaceStyle: DEFAULT_SURFACE_STYLE_KEY
|
|
1115
|
+
surfaceStyle: DEFAULT_SURFACE_STYLE_KEY,
|
|
1116
|
+
menuColor: DEFAULT_MENU_COLOR_KEY,
|
|
1117
|
+
menuAccent: DEFAULT_MENU_ACCENT_KEY
|
|
870
1118
|
};
|
|
871
1119
|
function buildThemeOverrides(config, mode) {
|
|
872
1120
|
const vars = {};
|
|
@@ -976,6 +1224,76 @@ function buildThemeOverrides(config, mode) {
|
|
|
976
1224
|
vars["--ds-gap-default"] = sv.gapDefault;
|
|
977
1225
|
vars["--ds-border-width"] = sv.borderWidth;
|
|
978
1226
|
vars["--ds-control-height"] = sv.controlHeight;
|
|
1227
|
+
const colorPresetObj = getColorPreset(config.colorPreset);
|
|
1228
|
+
const presetColors = mode === "dark" ? colorPresetObj.dark : colorPresetObj.light;
|
|
1229
|
+
if (config.menuColor === "muted") {
|
|
1230
|
+
if (mode === "light") {
|
|
1231
|
+
vars["--sidebar"] = presetColors.muted;
|
|
1232
|
+
vars["--sidebar-foreground"] = presetColors.foreground;
|
|
1233
|
+
vars["--sidebar-border"] = presetColors.border;
|
|
1234
|
+
} else {
|
|
1235
|
+
vars["--sidebar"] = presetColors.muted;
|
|
1236
|
+
vars["--sidebar-foreground"] = presetColors.foreground;
|
|
1237
|
+
vars["--sidebar-border"] = presetColors.border;
|
|
1238
|
+
}
|
|
1239
|
+
} else if (config.menuColor === "inverted") {
|
|
1240
|
+
if (mode === "light") {
|
|
1241
|
+
vars["--sidebar"] = "oklch(0.205 0 0)";
|
|
1242
|
+
vars["--sidebar-foreground"] = "oklch(0.95 0 0)";
|
|
1243
|
+
vars["--sidebar-primary"] = presetColors.primary;
|
|
1244
|
+
vars["--sidebar-primary-foreground"] = "oklch(0.985 0 0)";
|
|
1245
|
+
vars["--sidebar-border"] = "oklch(1 0 0 / 10%)";
|
|
1246
|
+
vars["--sidebar-ring"] = "oklch(0.439 0 0)";
|
|
1247
|
+
} else {
|
|
1248
|
+
vars["--sidebar"] = "oklch(0.269 0 0)";
|
|
1249
|
+
vars["--sidebar-foreground"] = "oklch(0.95 0 0)";
|
|
1250
|
+
vars["--sidebar-primary"] = presetColors.primary;
|
|
1251
|
+
vars["--sidebar-primary-foreground"] = "oklch(0.985 0 0)";
|
|
1252
|
+
vars["--sidebar-border"] = "oklch(1 0 0 / 8%)";
|
|
1253
|
+
vars["--sidebar-ring"] = "oklch(0.5 0 0)";
|
|
1254
|
+
}
|
|
1255
|
+
} else if (config.menuColor === "primary") {
|
|
1256
|
+
if (mode === "light") {
|
|
1257
|
+
vars["--sidebar"] = presetColors.primary;
|
|
1258
|
+
vars["--sidebar-foreground"] = presetColors.primaryForeground;
|
|
1259
|
+
vars["--sidebar-primary"] = presetColors.primaryForeground;
|
|
1260
|
+
vars["--sidebar-primary-foreground"] = presetColors.primary;
|
|
1261
|
+
vars["--sidebar-border"] = `color-mix(in oklch, ${presetColors.primaryForeground} 15%, transparent)`;
|
|
1262
|
+
vars["--sidebar-ring"] = presetColors.primaryForeground;
|
|
1263
|
+
} else {
|
|
1264
|
+
vars["--sidebar"] = presetColors.primary;
|
|
1265
|
+
vars["--sidebar-foreground"] = presetColors.primaryForeground;
|
|
1266
|
+
vars["--sidebar-primary"] = presetColors.primaryForeground;
|
|
1267
|
+
vars["--sidebar-primary-foreground"] = presetColors.primary;
|
|
1268
|
+
vars["--sidebar-border"] = `color-mix(in oklch, ${presetColors.primaryForeground} 15%, transparent)`;
|
|
1269
|
+
vars["--sidebar-ring"] = presetColors.primaryForeground;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
if (config.menuAccent === "none") {
|
|
1273
|
+
vars["--sidebar-accent"] = "transparent";
|
|
1274
|
+
vars["--sidebar-accent-foreground"] = vars["--sidebar-foreground"] ?? presetColors.sidebarForeground;
|
|
1275
|
+
} else if (config.menuAccent === "bold") {
|
|
1276
|
+
if (config.menuColor === "primary") {
|
|
1277
|
+
if (mode === "light") {
|
|
1278
|
+
vars["--sidebar-accent"] = `color-mix(in oklch, ${presetColors.primaryForeground} 20%, transparent)`;
|
|
1279
|
+
vars["--sidebar-accent-foreground"] = presetColors.primaryForeground;
|
|
1280
|
+
} else {
|
|
1281
|
+
vars["--sidebar-accent"] = `color-mix(in oklch, ${presetColors.primaryForeground} 20%, transparent)`;
|
|
1282
|
+
vars["--sidebar-accent-foreground"] = presetColors.primaryForeground;
|
|
1283
|
+
}
|
|
1284
|
+
} else if (config.menuColor === "inverted") {
|
|
1285
|
+
vars["--sidebar-accent"] = presetColors.primary;
|
|
1286
|
+
vars["--sidebar-accent-foreground"] = presetColors.primaryForeground;
|
|
1287
|
+
} else {
|
|
1288
|
+
if (mode === "light") {
|
|
1289
|
+
vars["--sidebar-accent"] = presetColors.primaryMuted;
|
|
1290
|
+
vars["--sidebar-accent-foreground"] = presetColors.primary;
|
|
1291
|
+
} else {
|
|
1292
|
+
vars["--sidebar-accent"] = presetColors.primaryMuted;
|
|
1293
|
+
vars["--sidebar-accent-foreground"] = presetColors.primaryMutedForeground;
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
979
1297
|
if (config.surfaceStyle === "elevated") {
|
|
980
1298
|
vars["--card"] = mode === "dark" ? "oklch(0.205 0 0)" : "oklch(1 0 0)";
|
|
981
1299
|
vars["--border"] = mode === "dark" ? "oklch(0.205 0 0 / 0)" : "oklch(0.922 0 0 / 0)";
|
|
@@ -998,6 +1316,8 @@ function generateThemeCSS(config) {
|
|
|
998
1316
|
` * Radius: ${getRadiusPreset(config.radius).label}`,
|
|
999
1317
|
` * Font: ${getFontPreset(config.font).name}`,
|
|
1000
1318
|
` * Shadows: ${getShadowPreset(config.shadow).name}`,
|
|
1319
|
+
` * Menu Color: ${getMenuColorPreset(config.menuColor).name}`,
|
|
1320
|
+
` * Menu Accent: ${getMenuAccentPreset(config.menuAccent).name}`,
|
|
1001
1321
|
" * ============================================ */",
|
|
1002
1322
|
"",
|
|
1003
1323
|
":root {",
|
|
@@ -1007,7 +1327,7 @@ function generateThemeCSS(config) {
|
|
|
1007
1327
|
".dark {",
|
|
1008
1328
|
formatVars(darkVars),
|
|
1009
1329
|
"}"
|
|
1010
|
-
].join("\n");
|
|
1330
|
+
].filter(Boolean).join("\n");
|
|
1011
1331
|
}
|
|
1012
1332
|
var STORAGE_KEY = "ds-theme-customizer";
|
|
1013
1333
|
var STYLE_ELEMENT_ID = "ds-theme-customizer";
|
|
@@ -1035,7 +1355,9 @@ function loadConfig() {
|
|
|
1035
1355
|
shadow: SHADOW_PRESETS.some((s) => s.key === parsed.shadow) ? parsed.shadow : DEFAULT_THEME_CONFIG.shadow,
|
|
1036
1356
|
surfaceStyle: SURFACE_STYLE_PRESETS.some(
|
|
1037
1357
|
(s) => s.key === parsed.surfaceStyle
|
|
1038
|
-
) ? parsed.surfaceStyle : DEFAULT_THEME_CONFIG.surfaceStyle
|
|
1358
|
+
) ? parsed.surfaceStyle : DEFAULT_THEME_CONFIG.surfaceStyle,
|
|
1359
|
+
menuColor: MENU_COLOR_PRESETS.some((p) => p.key === parsed.menuColor) ? parsed.menuColor : DEFAULT_THEME_CONFIG.menuColor,
|
|
1360
|
+
menuAccent: MENU_ACCENT_PRESETS.some((p) => p.key === parsed.menuAccent) ? parsed.menuAccent : DEFAULT_THEME_CONFIG.menuAccent
|
|
1039
1361
|
};
|
|
1040
1362
|
} catch {
|
|
1041
1363
|
return DEFAULT_THEME_CONFIG;
|
|
@@ -1079,7 +1401,7 @@ function removeStyles() {
|
|
|
1079
1401
|
}
|
|
1080
1402
|
}
|
|
1081
1403
|
function configsEqual(a, b) {
|
|
1082
|
-
return a.style === b.style && a.colorPreset === b.colorPreset && a.radius === b.radius && a.font === b.font && a.shadow === b.shadow && a.surfaceStyle === b.surfaceStyle;
|
|
1404
|
+
return a.style === b.style && a.colorPreset === b.colorPreset && a.radius === b.radius && a.font === b.font && a.shadow === b.shadow && a.surfaceStyle === b.surfaceStyle && a.menuColor === b.menuColor && a.menuAccent === b.menuAccent;
|
|
1083
1405
|
}
|
|
1084
1406
|
function ThemeCustomizerProvider({
|
|
1085
1407
|
children,
|
|
@@ -1185,6 +1507,18 @@ function ThemeCustomizerProvider({
|
|
|
1185
1507
|
return { ...prev, surfaceStyle: key };
|
|
1186
1508
|
});
|
|
1187
1509
|
}, []);
|
|
1510
|
+
const setMenuColor = useCallback((key) => {
|
|
1511
|
+
setConfigState((prev) => {
|
|
1512
|
+
if (prev.menuColor === key) return prev;
|
|
1513
|
+
return { ...prev, menuColor: key };
|
|
1514
|
+
});
|
|
1515
|
+
}, []);
|
|
1516
|
+
const setMenuAccent = useCallback((key) => {
|
|
1517
|
+
setConfigState((prev) => {
|
|
1518
|
+
if (prev.menuAccent === key) return prev;
|
|
1519
|
+
return { ...prev, menuAccent: key };
|
|
1520
|
+
});
|
|
1521
|
+
}, []);
|
|
1188
1522
|
const resetConfig = useCallback(() => {
|
|
1189
1523
|
setConfigState(DEFAULT_THEME_CONFIG);
|
|
1190
1524
|
}, []);
|
|
@@ -1202,6 +1536,8 @@ function ThemeCustomizerProvider({
|
|
|
1202
1536
|
setFont,
|
|
1203
1537
|
setShadow,
|
|
1204
1538
|
setSurfaceStyle,
|
|
1539
|
+
setMenuColor,
|
|
1540
|
+
setMenuAccent,
|
|
1205
1541
|
resetConfig,
|
|
1206
1542
|
isDefault,
|
|
1207
1543
|
generateCSS: generateCSSFn
|
|
@@ -1215,6 +1551,8 @@ function ThemeCustomizerProvider({
|
|
|
1215
1551
|
setFont,
|
|
1216
1552
|
setShadow,
|
|
1217
1553
|
setSurfaceStyle,
|
|
1554
|
+
setMenuColor,
|
|
1555
|
+
setMenuAccent,
|
|
1218
1556
|
resetConfig,
|
|
1219
1557
|
isDefault,
|
|
1220
1558
|
generateCSSFn
|
|
@@ -1249,50 +1587,6 @@ function CheckIcon({ className }) {
|
|
|
1249
1587
|
}
|
|
1250
1588
|
);
|
|
1251
1589
|
}
|
|
1252
|
-
function ColorSwatch({
|
|
1253
|
-
preset,
|
|
1254
|
-
isActive,
|
|
1255
|
-
onClick
|
|
1256
|
-
}) {
|
|
1257
|
-
return /* @__PURE__ */ jsxs(
|
|
1258
|
-
"button",
|
|
1259
|
-
{
|
|
1260
|
-
type: "button",
|
|
1261
|
-
onClick,
|
|
1262
|
-
className: cn(
|
|
1263
|
-
"group relative flex items-center gap-2 rounded-md border px-3 py-2 text-left text-sm transition-all duration-fast ease-standard",
|
|
1264
|
-
"hover:border-border-strong hover:bg-muted/50",
|
|
1265
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
1266
|
-
isActive ? "border-primary bg-muted/60 shadow-sm" : "border-border bg-transparent"
|
|
1267
|
-
),
|
|
1268
|
-
title: preset.name,
|
|
1269
|
-
children: [
|
|
1270
|
-
/* @__PURE__ */ jsx(
|
|
1271
|
-
"span",
|
|
1272
|
-
{
|
|
1273
|
-
className: cn(
|
|
1274
|
-
"size-5 shrink-0 rounded-full border shadow-xs",
|
|
1275
|
-
isActive ? "border-primary/50 ring-2 ring-primary/20" : "border-border"
|
|
1276
|
-
),
|
|
1277
|
-
style: { backgroundColor: preset.swatch },
|
|
1278
|
-
"aria-hidden": "true"
|
|
1279
|
-
}
|
|
1280
|
-
),
|
|
1281
|
-
/* @__PURE__ */ jsx(
|
|
1282
|
-
"span",
|
|
1283
|
-
{
|
|
1284
|
-
className: cn(
|
|
1285
|
-
"text-sm font-medium",
|
|
1286
|
-
isActive ? "text-foreground" : "text-muted-foreground"
|
|
1287
|
-
),
|
|
1288
|
-
children: preset.name
|
|
1289
|
-
}
|
|
1290
|
-
),
|
|
1291
|
-
isActive && /* @__PURE__ */ jsx(CheckIcon, { className: "ml-auto text-primary" })
|
|
1292
|
-
]
|
|
1293
|
-
}
|
|
1294
|
-
);
|
|
1295
|
-
}
|
|
1296
1590
|
function RadiusOption({
|
|
1297
1591
|
preset,
|
|
1298
1592
|
isActive,
|
|
@@ -1333,49 +1627,433 @@ function RadiusOption({
|
|
|
1333
1627
|
}
|
|
1334
1628
|
);
|
|
1335
1629
|
}
|
|
1336
|
-
function
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1630
|
+
function ChevronDownIcon({ className }) {
|
|
1631
|
+
return /* @__PURE__ */ jsx(
|
|
1632
|
+
"svg",
|
|
1633
|
+
{
|
|
1634
|
+
className: cn("size-4 shrink-0", className),
|
|
1635
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1636
|
+
viewBox: "0 0 24 24",
|
|
1637
|
+
fill: "none",
|
|
1638
|
+
stroke: "currentColor",
|
|
1639
|
+
strokeWidth: "2",
|
|
1640
|
+
strokeLinecap: "round",
|
|
1641
|
+
strokeLinejoin: "round",
|
|
1642
|
+
"aria-hidden": "true",
|
|
1643
|
+
children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" })
|
|
1644
|
+
}
|
|
1645
|
+
);
|
|
1646
|
+
}
|
|
1647
|
+
function SearchIcon({ className }) {
|
|
1341
1648
|
return /* @__PURE__ */ jsxs(
|
|
1342
|
-
"
|
|
1649
|
+
"svg",
|
|
1343
1650
|
{
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1651
|
+
className: cn("size-4 shrink-0", className),
|
|
1652
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1653
|
+
viewBox: "0 0 24 24",
|
|
1654
|
+
fill: "none",
|
|
1655
|
+
stroke: "currentColor",
|
|
1656
|
+
strokeWidth: "2",
|
|
1657
|
+
strokeLinecap: "round",
|
|
1658
|
+
strokeLinejoin: "round",
|
|
1659
|
+
"aria-hidden": "true",
|
|
1353
1660
|
children: [
|
|
1354
|
-
/* @__PURE__ */ jsx(
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1661
|
+
/* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "8" }),
|
|
1662
|
+
/* @__PURE__ */ jsx("path", { d: "m21 21-4.3-4.3" })
|
|
1663
|
+
]
|
|
1664
|
+
}
|
|
1665
|
+
);
|
|
1666
|
+
}
|
|
1667
|
+
function FontCombobox({
|
|
1668
|
+
presets,
|
|
1669
|
+
activeKey,
|
|
1670
|
+
onSelect
|
|
1671
|
+
}) {
|
|
1672
|
+
const [open, setOpen] = useState(false);
|
|
1673
|
+
const [search, setSearch] = useState("");
|
|
1674
|
+
const [highlightIndex, setHighlightIndex] = useState(-1);
|
|
1675
|
+
const containerRef = useRef(null);
|
|
1676
|
+
const listRef = useRef(null);
|
|
1677
|
+
const inputRef = useRef(null);
|
|
1678
|
+
const activePreset = useMemo(
|
|
1679
|
+
() => presets.find((p) => p.key === activeKey) ?? presets[0],
|
|
1680
|
+
[presets, activeKey]
|
|
1681
|
+
);
|
|
1682
|
+
const filtered = useMemo(() => {
|
|
1683
|
+
if (!search.trim()) return presets;
|
|
1684
|
+
const q = search.toLowerCase();
|
|
1685
|
+
return presets.filter((p) => p.name.toLowerCase().includes(q));
|
|
1686
|
+
}, [presets, search]);
|
|
1687
|
+
useEffect(() => {
|
|
1688
|
+
setHighlightIndex(0);
|
|
1689
|
+
}, [filtered]);
|
|
1690
|
+
useEffect(() => {
|
|
1691
|
+
if (!open) return;
|
|
1692
|
+
function handleClick(e) {
|
|
1693
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
1694
|
+
setOpen(false);
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
document.addEventListener("mousedown", handleClick);
|
|
1698
|
+
return () => document.removeEventListener("mousedown", handleClick);
|
|
1699
|
+
}, [open]);
|
|
1700
|
+
useEffect(() => {
|
|
1701
|
+
if (!open) return;
|
|
1702
|
+
function handleKey(e) {
|
|
1703
|
+
if (e.key === "Escape") {
|
|
1704
|
+
setOpen(false);
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
document.addEventListener("keydown", handleKey);
|
|
1708
|
+
return () => document.removeEventListener("keydown", handleKey);
|
|
1709
|
+
}, [open]);
|
|
1710
|
+
useEffect(() => {
|
|
1711
|
+
if (open) {
|
|
1712
|
+
requestAnimationFrame(() => inputRef.current?.focus());
|
|
1713
|
+
} else {
|
|
1714
|
+
setSearch("");
|
|
1715
|
+
setHighlightIndex(-1);
|
|
1716
|
+
}
|
|
1717
|
+
}, [open]);
|
|
1718
|
+
useEffect(() => {
|
|
1719
|
+
if (!open || highlightIndex < 0 || !listRef.current) return;
|
|
1720
|
+
const items = listRef.current.querySelectorAll("[data-font-item]");
|
|
1721
|
+
items[highlightIndex]?.scrollIntoView({ block: "nearest" });
|
|
1722
|
+
}, [highlightIndex, open]);
|
|
1723
|
+
const handleSelect = useCallback(
|
|
1724
|
+
(key) => {
|
|
1725
|
+
onSelect(key);
|
|
1726
|
+
setOpen(false);
|
|
1727
|
+
},
|
|
1728
|
+
[onSelect]
|
|
1729
|
+
);
|
|
1730
|
+
const handleKeyDown = useCallback(
|
|
1731
|
+
(e) => {
|
|
1732
|
+
if (e.key === "ArrowDown") {
|
|
1733
|
+
e.preventDefault();
|
|
1734
|
+
setHighlightIndex((i) => Math.min(i + 1, filtered.length - 1));
|
|
1735
|
+
} else if (e.key === "ArrowUp") {
|
|
1736
|
+
e.preventDefault();
|
|
1737
|
+
setHighlightIndex((i) => Math.max(i - 1, 0));
|
|
1738
|
+
} else if (e.key === "Enter") {
|
|
1739
|
+
e.preventDefault();
|
|
1740
|
+
if (highlightIndex >= 0 && highlightIndex < filtered.length) {
|
|
1741
|
+
handleSelect(filtered[highlightIndex].key);
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
},
|
|
1745
|
+
[filtered, highlightIndex, handleSelect]
|
|
1746
|
+
);
|
|
1747
|
+
return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: "relative", children: [
|
|
1748
|
+
/* @__PURE__ */ jsxs(
|
|
1749
|
+
"button",
|
|
1750
|
+
{
|
|
1751
|
+
type: "button",
|
|
1752
|
+
onClick: () => setOpen((prev) => !prev),
|
|
1753
|
+
className: cn(
|
|
1754
|
+
"flex w-full items-center gap-2 rounded-md border px-3 py-2 text-left text-sm transition-all duration-fast ease-standard",
|
|
1755
|
+
"hover:border-border-strong hover:bg-muted/50",
|
|
1756
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
1757
|
+
open ? "border-primary shadow-sm" : "border-border"
|
|
1364
1758
|
),
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1759
|
+
"aria-haspopup": "listbox",
|
|
1760
|
+
"aria-expanded": open,
|
|
1761
|
+
children: [
|
|
1762
|
+
/* @__PURE__ */ jsx(
|
|
1763
|
+
"span",
|
|
1764
|
+
{
|
|
1765
|
+
className: "text-sm font-semibold leading-none text-muted-foreground",
|
|
1766
|
+
style: { fontFamily: activePreset.value },
|
|
1767
|
+
children: activePreset.sample
|
|
1768
|
+
}
|
|
1769
|
+
),
|
|
1770
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate font-medium text-foreground", children: activePreset.name }),
|
|
1771
|
+
/* @__PURE__ */ jsx(
|
|
1772
|
+
ChevronDownIcon,
|
|
1773
|
+
{
|
|
1774
|
+
className: cn(
|
|
1775
|
+
"text-muted-foreground transition-transform duration-fast",
|
|
1776
|
+
open && "rotate-180"
|
|
1777
|
+
)
|
|
1778
|
+
}
|
|
1779
|
+
)
|
|
1780
|
+
]
|
|
1781
|
+
}
|
|
1782
|
+
),
|
|
1783
|
+
open && /* @__PURE__ */ jsxs(
|
|
1784
|
+
"div",
|
|
1785
|
+
{
|
|
1786
|
+
className: cn(
|
|
1787
|
+
"absolute left-0 z-50 mt-1 w-full rounded-md border border-border bg-popover shadow-md",
|
|
1788
|
+
"animate-in fade-in-0 zoom-in-95 slide-in-from-top-2"
|
|
1374
1789
|
),
|
|
1375
|
-
|
|
1376
|
-
|
|
1790
|
+
role: "dialog",
|
|
1791
|
+
"aria-label": "Select font",
|
|
1792
|
+
children: [
|
|
1793
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-border px-3 py-2", children: [
|
|
1794
|
+
/* @__PURE__ */ jsx(SearchIcon, { className: "text-muted-foreground" }),
|
|
1795
|
+
/* @__PURE__ */ jsx(
|
|
1796
|
+
"input",
|
|
1797
|
+
{
|
|
1798
|
+
ref: inputRef,
|
|
1799
|
+
type: "text",
|
|
1800
|
+
value: search,
|
|
1801
|
+
onChange: (e) => setSearch(e.target.value),
|
|
1802
|
+
onKeyDown: handleKeyDown,
|
|
1803
|
+
placeholder: "Search fonts\u2026",
|
|
1804
|
+
className: "flex-1 bg-transparent text-sm text-foreground placeholder:text-muted-foreground outline-none",
|
|
1805
|
+
"aria-label": "Search fonts",
|
|
1806
|
+
autoComplete: "off",
|
|
1807
|
+
spellCheck: false
|
|
1808
|
+
}
|
|
1809
|
+
)
|
|
1810
|
+
] }),
|
|
1811
|
+
/* @__PURE__ */ jsx(
|
|
1812
|
+
"div",
|
|
1813
|
+
{
|
|
1814
|
+
ref: listRef,
|
|
1815
|
+
className: "max-h-52 overflow-y-auto overscroll-contain p-1",
|
|
1816
|
+
role: "listbox",
|
|
1817
|
+
children: filtered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No fonts found" }) : filtered.map((preset, index) => {
|
|
1818
|
+
const isActive = preset.key === activeKey;
|
|
1819
|
+
const isHighlighted = index === highlightIndex;
|
|
1820
|
+
return /* @__PURE__ */ jsxs(
|
|
1821
|
+
"button",
|
|
1822
|
+
{
|
|
1823
|
+
type: "button",
|
|
1824
|
+
"data-font-item": "",
|
|
1825
|
+
role: "option",
|
|
1826
|
+
"aria-selected": isActive,
|
|
1827
|
+
onClick: () => handleSelect(preset.key),
|
|
1828
|
+
onMouseEnter: () => setHighlightIndex(index),
|
|
1829
|
+
className: cn(
|
|
1830
|
+
"flex w-full items-center gap-2.5 rounded-sm px-2.5 py-1.5 text-left text-sm transition-colors",
|
|
1831
|
+
"outline-none",
|
|
1832
|
+
isHighlighted && "bg-muted",
|
|
1833
|
+
isActive && "text-foreground font-medium",
|
|
1834
|
+
!isActive && "text-muted-foreground"
|
|
1835
|
+
),
|
|
1836
|
+
children: [
|
|
1837
|
+
/* @__PURE__ */ jsx(
|
|
1838
|
+
"span",
|
|
1839
|
+
{
|
|
1840
|
+
className: "w-6 text-center text-base font-semibold leading-none",
|
|
1841
|
+
style: { fontFamily: preset.value },
|
|
1842
|
+
"aria-hidden": "true",
|
|
1843
|
+
children: preset.sample
|
|
1844
|
+
}
|
|
1845
|
+
),
|
|
1846
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: preset.name }),
|
|
1847
|
+
isActive && /* @__PURE__ */ jsx(CheckIcon, { className: "text-primary shrink-0" })
|
|
1848
|
+
]
|
|
1849
|
+
},
|
|
1850
|
+
preset.key
|
|
1851
|
+
);
|
|
1852
|
+
})
|
|
1853
|
+
}
|
|
1854
|
+
)
|
|
1855
|
+
]
|
|
1856
|
+
}
|
|
1857
|
+
)
|
|
1858
|
+
] });
|
|
1859
|
+
}
|
|
1860
|
+
function ColorCombobox({
|
|
1861
|
+
presets,
|
|
1862
|
+
activeKey,
|
|
1863
|
+
onSelect
|
|
1864
|
+
}) {
|
|
1865
|
+
const [open, setOpen] = useState(false);
|
|
1866
|
+
const [search, setSearch] = useState("");
|
|
1867
|
+
const [highlightIndex, setHighlightIndex] = useState(-1);
|
|
1868
|
+
const containerRef = useRef(null);
|
|
1869
|
+
const listRef = useRef(null);
|
|
1870
|
+
const inputRef = useRef(null);
|
|
1871
|
+
const activePreset = useMemo(
|
|
1872
|
+
() => presets.find((p) => p.key === activeKey) ?? presets[0],
|
|
1873
|
+
[presets, activeKey]
|
|
1874
|
+
);
|
|
1875
|
+
const filtered = useMemo(() => {
|
|
1876
|
+
if (!search.trim()) return presets;
|
|
1877
|
+
const q = search.toLowerCase();
|
|
1878
|
+
return presets.filter((p) => p.name.toLowerCase().includes(q));
|
|
1879
|
+
}, [presets, search]);
|
|
1880
|
+
useEffect(() => {
|
|
1881
|
+
setHighlightIndex(0);
|
|
1882
|
+
}, [filtered]);
|
|
1883
|
+
useEffect(() => {
|
|
1884
|
+
if (!open) return;
|
|
1885
|
+
function handleClick(e) {
|
|
1886
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
1887
|
+
setOpen(false);
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
document.addEventListener("mousedown", handleClick);
|
|
1891
|
+
return () => document.removeEventListener("mousedown", handleClick);
|
|
1892
|
+
}, [open]);
|
|
1893
|
+
useEffect(() => {
|
|
1894
|
+
if (!open) return;
|
|
1895
|
+
function handleKey(e) {
|
|
1896
|
+
if (e.key === "Escape") {
|
|
1897
|
+
setOpen(false);
|
|
1898
|
+
}
|
|
1377
1899
|
}
|
|
1900
|
+
document.addEventListener("keydown", handleKey);
|
|
1901
|
+
return () => document.removeEventListener("keydown", handleKey);
|
|
1902
|
+
}, [open]);
|
|
1903
|
+
useEffect(() => {
|
|
1904
|
+
if (open) {
|
|
1905
|
+
requestAnimationFrame(() => inputRef.current?.focus());
|
|
1906
|
+
} else {
|
|
1907
|
+
setSearch("");
|
|
1908
|
+
setHighlightIndex(-1);
|
|
1909
|
+
}
|
|
1910
|
+
}, [open]);
|
|
1911
|
+
useEffect(() => {
|
|
1912
|
+
if (!open || highlightIndex < 0 || !listRef.current) return;
|
|
1913
|
+
const items = listRef.current.querySelectorAll("[data-color-item]");
|
|
1914
|
+
items[highlightIndex]?.scrollIntoView({ block: "nearest" });
|
|
1915
|
+
}, [highlightIndex, open]);
|
|
1916
|
+
const handleSelect = useCallback(
|
|
1917
|
+
(key) => {
|
|
1918
|
+
onSelect(key);
|
|
1919
|
+
setOpen(false);
|
|
1920
|
+
},
|
|
1921
|
+
[onSelect]
|
|
1378
1922
|
);
|
|
1923
|
+
const handleKeyDown = useCallback(
|
|
1924
|
+
(e) => {
|
|
1925
|
+
if (e.key === "ArrowDown") {
|
|
1926
|
+
e.preventDefault();
|
|
1927
|
+
setHighlightIndex((i) => Math.min(i + 1, filtered.length - 1));
|
|
1928
|
+
} else if (e.key === "ArrowUp") {
|
|
1929
|
+
e.preventDefault();
|
|
1930
|
+
setHighlightIndex((i) => Math.max(i - 1, 0));
|
|
1931
|
+
} else if (e.key === "Enter") {
|
|
1932
|
+
e.preventDefault();
|
|
1933
|
+
if (highlightIndex >= 0 && highlightIndex < filtered.length) {
|
|
1934
|
+
handleSelect(filtered[highlightIndex].key);
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
},
|
|
1938
|
+
[filtered, highlightIndex, handleSelect]
|
|
1939
|
+
);
|
|
1940
|
+
return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: "relative", children: [
|
|
1941
|
+
/* @__PURE__ */ jsxs(
|
|
1942
|
+
"button",
|
|
1943
|
+
{
|
|
1944
|
+
type: "button",
|
|
1945
|
+
onClick: () => setOpen((prev) => !prev),
|
|
1946
|
+
className: cn(
|
|
1947
|
+
"flex w-full items-center gap-2 rounded-md border px-3 py-2 text-left text-sm transition-all duration-fast ease-standard",
|
|
1948
|
+
"hover:border-border-strong hover:bg-muted/50",
|
|
1949
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
1950
|
+
open ? "border-primary shadow-sm" : "border-border"
|
|
1951
|
+
),
|
|
1952
|
+
"aria-haspopup": "listbox",
|
|
1953
|
+
"aria-expanded": open,
|
|
1954
|
+
children: [
|
|
1955
|
+
/* @__PURE__ */ jsx(
|
|
1956
|
+
"span",
|
|
1957
|
+
{
|
|
1958
|
+
className: cn(
|
|
1959
|
+
"size-5 shrink-0 rounded-full border shadow-xs",
|
|
1960
|
+
"border-border"
|
|
1961
|
+
),
|
|
1962
|
+
style: { backgroundColor: activePreset.swatch },
|
|
1963
|
+
"aria-hidden": "true"
|
|
1964
|
+
}
|
|
1965
|
+
),
|
|
1966
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate font-medium text-foreground", children: activePreset.name }),
|
|
1967
|
+
/* @__PURE__ */ jsx(
|
|
1968
|
+
ChevronDownIcon,
|
|
1969
|
+
{
|
|
1970
|
+
className: cn(
|
|
1971
|
+
"text-muted-foreground transition-transform duration-fast",
|
|
1972
|
+
open && "rotate-180"
|
|
1973
|
+
)
|
|
1974
|
+
}
|
|
1975
|
+
)
|
|
1976
|
+
]
|
|
1977
|
+
}
|
|
1978
|
+
),
|
|
1979
|
+
open && /* @__PURE__ */ jsxs(
|
|
1980
|
+
"div",
|
|
1981
|
+
{
|
|
1982
|
+
className: cn(
|
|
1983
|
+
"absolute left-0 z-50 mt-1 w-full rounded-md border border-border bg-popover shadow-md",
|
|
1984
|
+
"animate-in fade-in-0 zoom-in-95 slide-in-from-top-2"
|
|
1985
|
+
),
|
|
1986
|
+
role: "dialog",
|
|
1987
|
+
"aria-label": "Select color",
|
|
1988
|
+
children: [
|
|
1989
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-border px-3 py-2", children: [
|
|
1990
|
+
/* @__PURE__ */ jsx(SearchIcon, { className: "text-muted-foreground" }),
|
|
1991
|
+
/* @__PURE__ */ jsx(
|
|
1992
|
+
"input",
|
|
1993
|
+
{
|
|
1994
|
+
ref: inputRef,
|
|
1995
|
+
type: "text",
|
|
1996
|
+
value: search,
|
|
1997
|
+
onChange: (e) => setSearch(e.target.value),
|
|
1998
|
+
onKeyDown: handleKeyDown,
|
|
1999
|
+
placeholder: "Search colors\u2026",
|
|
2000
|
+
className: "flex-1 bg-transparent text-sm text-foreground placeholder:text-muted-foreground outline-none",
|
|
2001
|
+
"aria-label": "Search colors",
|
|
2002
|
+
autoComplete: "off",
|
|
2003
|
+
spellCheck: false
|
|
2004
|
+
}
|
|
2005
|
+
)
|
|
2006
|
+
] }),
|
|
2007
|
+
/* @__PURE__ */ jsx(
|
|
2008
|
+
"div",
|
|
2009
|
+
{
|
|
2010
|
+
ref: listRef,
|
|
2011
|
+
className: "max-h-52 overflow-y-auto overscroll-contain p-1",
|
|
2012
|
+
role: "listbox",
|
|
2013
|
+
children: filtered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No colors found" }) : filtered.map((preset, index) => {
|
|
2014
|
+
const isActive = preset.key === activeKey;
|
|
2015
|
+
const isHighlighted = index === highlightIndex;
|
|
2016
|
+
return /* @__PURE__ */ jsxs(
|
|
2017
|
+
"button",
|
|
2018
|
+
{
|
|
2019
|
+
type: "button",
|
|
2020
|
+
"data-color-item": "",
|
|
2021
|
+
role: "option",
|
|
2022
|
+
"aria-selected": isActive,
|
|
2023
|
+
onClick: () => handleSelect(preset.key),
|
|
2024
|
+
onMouseEnter: () => setHighlightIndex(index),
|
|
2025
|
+
className: cn(
|
|
2026
|
+
"flex w-full items-center gap-2.5 rounded-sm px-2.5 py-1.5 text-left text-sm transition-colors",
|
|
2027
|
+
"outline-none",
|
|
2028
|
+
isHighlighted && "bg-muted",
|
|
2029
|
+
isActive && "text-foreground font-medium",
|
|
2030
|
+
!isActive && "text-muted-foreground"
|
|
2031
|
+
),
|
|
2032
|
+
children: [
|
|
2033
|
+
/* @__PURE__ */ jsx(
|
|
2034
|
+
"span",
|
|
2035
|
+
{
|
|
2036
|
+
className: cn(
|
|
2037
|
+
"size-4 shrink-0 rounded-full border shadow-xs",
|
|
2038
|
+
isActive ? "border-primary/50 ring-2 ring-primary/20" : "border-border"
|
|
2039
|
+
),
|
|
2040
|
+
style: { backgroundColor: preset.swatch },
|
|
2041
|
+
"aria-hidden": "true"
|
|
2042
|
+
}
|
|
2043
|
+
),
|
|
2044
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: preset.name }),
|
|
2045
|
+
isActive && /* @__PURE__ */ jsx(CheckIcon, { className: "text-primary shrink-0" })
|
|
2046
|
+
]
|
|
2047
|
+
},
|
|
2048
|
+
preset.key
|
|
2049
|
+
);
|
|
2050
|
+
})
|
|
2051
|
+
}
|
|
2052
|
+
)
|
|
2053
|
+
]
|
|
2054
|
+
}
|
|
2055
|
+
)
|
|
2056
|
+
] });
|
|
1379
2057
|
}
|
|
1380
2058
|
function PillToggle({
|
|
1381
2059
|
label,
|
|
@@ -1533,6 +2211,8 @@ function ThemeCustomizer({
|
|
|
1533
2211
|
setFont,
|
|
1534
2212
|
setShadow,
|
|
1535
2213
|
setSurfaceStyle,
|
|
2214
|
+
setMenuColor,
|
|
2215
|
+
setMenuAccent,
|
|
1536
2216
|
resetConfig,
|
|
1537
2217
|
isDefault,
|
|
1538
2218
|
generateCSS
|
|
@@ -1553,15 +2233,14 @@ function ThemeCustomizer({
|
|
|
1553
2233
|
},
|
|
1554
2234
|
preset.key
|
|
1555
2235
|
)) }) }),
|
|
1556
|
-
/* @__PURE__ */ jsx(Section, { title: "Color", children: /* @__PURE__ */ jsx(
|
|
1557
|
-
|
|
2236
|
+
/* @__PURE__ */ jsx(Section, { title: "Color", children: /* @__PURE__ */ jsx(
|
|
2237
|
+
ColorCombobox,
|
|
1558
2238
|
{
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
}
|
|
1563
|
-
|
|
1564
|
-
)) }) }),
|
|
2239
|
+
presets: COLOR_PRESETS,
|
|
2240
|
+
activeKey: config.colorPreset,
|
|
2241
|
+
onSelect: setColorPreset
|
|
2242
|
+
}
|
|
2243
|
+
) }),
|
|
1565
2244
|
/* @__PURE__ */ jsx(Section, { title: "Radius", children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: RADIUS_PRESETS.map((preset) => /* @__PURE__ */ jsx(
|
|
1566
2245
|
RadiusOption,
|
|
1567
2246
|
{
|
|
@@ -1571,15 +2250,14 @@ function ThemeCustomizer({
|
|
|
1571
2250
|
},
|
|
1572
2251
|
preset.key
|
|
1573
2252
|
)) }) }),
|
|
1574
|
-
/* @__PURE__ */ jsx(Section, { title: "Font", children: /* @__PURE__ */ jsx(
|
|
1575
|
-
|
|
2253
|
+
/* @__PURE__ */ jsx(Section, { title: "Font", children: /* @__PURE__ */ jsx(
|
|
2254
|
+
FontCombobox,
|
|
1576
2255
|
{
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
|
-
)) }) }),
|
|
2256
|
+
presets: FONT_PRESETS,
|
|
2257
|
+
activeKey: config.font,
|
|
2258
|
+
onSelect: setFont
|
|
2259
|
+
}
|
|
2260
|
+
) }),
|
|
1583
2261
|
/* @__PURE__ */ jsx(Section, { title: "Shadow", children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: SHADOW_PRESETS.map((preset) => /* @__PURE__ */ jsx(
|
|
1584
2262
|
PillToggle,
|
|
1585
2263
|
{
|
|
@@ -1600,6 +2278,26 @@ function ThemeCustomizer({
|
|
|
1600
2278
|
},
|
|
1601
2279
|
preset.key
|
|
1602
2280
|
)) }) }),
|
|
2281
|
+
/* @__PURE__ */ jsx(Section, { title: "Menu Color", children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: MENU_COLOR_PRESETS.map((preset) => /* @__PURE__ */ jsx(
|
|
2282
|
+
PillToggle,
|
|
2283
|
+
{
|
|
2284
|
+
label: preset.name,
|
|
2285
|
+
isActive: config.menuColor === preset.key,
|
|
2286
|
+
onClick: () => setMenuColor(preset.key),
|
|
2287
|
+
description: preset.description
|
|
2288
|
+
},
|
|
2289
|
+
preset.key
|
|
2290
|
+
)) }) }),
|
|
2291
|
+
/* @__PURE__ */ jsx(Section, { title: "Menu Accent", children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: MENU_ACCENT_PRESETS.map((preset) => /* @__PURE__ */ jsx(
|
|
2292
|
+
PillToggle,
|
|
2293
|
+
{
|
|
2294
|
+
label: preset.name,
|
|
2295
|
+
isActive: config.menuAccent === preset.key,
|
|
2296
|
+
onClick: () => setMenuAccent(preset.key),
|
|
2297
|
+
description: preset.description
|
|
2298
|
+
},
|
|
2299
|
+
preset.key
|
|
2300
|
+
)) }) }),
|
|
1603
2301
|
(showCopyButton || showResetButton) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-t border-border pt-4", children: [
|
|
1604
2302
|
showCopyButton && /* @__PURE__ */ jsx(CopyButton, { getText: generateCSS, className: "flex-1" }),
|
|
1605
2303
|
showResetButton && !isDefault && /* @__PURE__ */ jsxs(
|
|
@@ -1732,4 +2430,4 @@ function DSThemeProvider({
|
|
|
1732
2430
|
return /* @__PURE__ */ jsx(DSThemeContext.Provider, { value, children });
|
|
1733
2431
|
}
|
|
1734
2432
|
|
|
1735
|
-
export { COLOR_PRESETS, COLOR_PRESET_KEYS, DEFAULT_FONT_KEY, DEFAULT_RADIUS_KEY, DEFAULT_SHADOW_KEY, DEFAULT_STYLE_KEY, DEFAULT_SURFACE_STYLE_KEY, DEFAULT_THEME_CONFIG, DSThemeProvider, FONT_PRESETS, RADIUS_PRESETS, SHADOW_PRESETS, STYLE_PRESETS, SURFACE_STYLE_PRESETS, ThemeCustomizer, ThemeCustomizerProvider, buildDarkThemeVars, buildLightThemeVars, buildThemeCSS, buildThemeOverrides, contract, cssVar, generateThemeCSS, getColorPreset, getFontPreset, getRadiusPreset, getShadowPreset, getStylePreset, useDSTheme, useThemeCustomizer };
|
|
2433
|
+
export { COLOR_PRESETS, COLOR_PRESET_KEYS, DEFAULT_FONT_KEY, DEFAULT_MENU_ACCENT_KEY, DEFAULT_MENU_COLOR_KEY, DEFAULT_RADIUS_KEY, DEFAULT_SHADOW_KEY, DEFAULT_STYLE_KEY, DEFAULT_SURFACE_STYLE_KEY, DEFAULT_THEME_CONFIG, DSThemeProvider, FONT_PRESETS, MENU_ACCENT_PRESETS, MENU_COLOR_PRESETS, RADIUS_PRESETS, SHADOW_PRESETS, STYLE_PRESETS, SURFACE_STYLE_PRESETS, ThemeCustomizer, ThemeCustomizerContext, ThemeCustomizerProvider, buildDarkThemeVars, buildLightThemeVars, buildThemeCSS, buildThemeOverrides, contract, cssVar, generateThemeCSS, getColorPreset, getFontPreset, getMenuAccentPreset, getMenuColorPreset, getRadiusPreset, getShadowPreset, getStylePreset, useDSTheme, useThemeCustomizer };
|