@srcroot/ui 0.0.37 → 0.0.40

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/dist/index.js CHANGED
@@ -22,7 +22,12 @@ var THEME_METADATA = {
22
22
  neutral: { name: "Neutral", description: "Pure gray, no undertones" },
23
23
  stone: { name: "Stone", description: "Warm gray with brown undertones" },
24
24
  zinc: { name: "Zinc", description: "Cool gray with subtle blue undertones" },
25
- gray: { name: "Gray", description: "True neutral gray" }
25
+ gray: { name: "Gray", description: "True neutral gray" },
26
+ violet: { name: "Violet", description: "Vibrant purple and magenta" },
27
+ rose: { name: "Rose", description: "Soft and elegant pinkish-red" },
28
+ blue: { name: "Blue", description: "Trustworthy corporate blue" },
29
+ green: { name: "Green", description: "Nature and success green" },
30
+ orange: { name: "Orange", description: "Energetic and creative orange" }
26
31
  };
27
32
  var ThemeService = class {
28
33
  registryThemesPath;
@@ -367,11 +372,12 @@ async function init(options) {
367
372
  await initializer.run();
368
373
  }
369
374
 
370
- // src/cli/commands/add.ts
375
+ // src/cli/services/component-adder.ts
371
376
  import fs4 from "fs-extra";
372
377
  import path4 from "path";
373
378
  import ora2 from "ora";
374
379
  import prompts2 from "prompts";
380
+ import { execa as execa2 } from "execa";
375
381
  import { fileURLToPath as fileURLToPath3 } from "url";
376
382
 
377
383
  // src/cli/registry.ts
@@ -750,121 +756,192 @@ var REGISTRY = {
750
756
  description: "AI chat interface",
751
757
  category: "Data Display",
752
758
  dependencies: ["button", "input", "scroll-area", "avatar"]
759
+ },
760
+ chart: {
761
+ file: "ui/chart.tsx",
762
+ description: "Charts using Recharts",
763
+ category: "Data Display",
764
+ dependencies: [],
765
+ registryDependencies: ["recharts"]
753
766
  }
754
767
  };
755
768
 
756
- // src/cli/commands/add.ts
769
+ // src/cli/services/component-adder.ts
757
770
  var __dirname4 = path4.dirname(fileURLToPath3(import.meta.url));
758
- async function add(components, options) {
759
- const cwd = path4.resolve(options.cwd);
760
- if (options.all) {
761
- components = Object.keys(REGISTRY);
771
+ var ComponentAdder = class {
772
+ cwd;
773
+ options;
774
+ constructor(cwd, options) {
775
+ this.cwd = cwd;
776
+ this.options = options;
762
777
  }
763
- if (components.length === 0) {
764
- const { items } = await prompts2({
765
- type: "multiselect",
766
- name: "items",
767
- message: "Which components would you like to add?",
768
- hint: "Space to select. A to toggle all. Enter to submit.",
769
- instructions: false,
770
- choices: Object.keys(REGISTRY).map((name) => ({
771
- title: name,
772
- value: name
773
- }))
774
- });
775
- if (!items || items.length === 0) {
776
- logger.warn("No components selected.");
777
- process.exit(0);
778
+ async add(components) {
779
+ components = await this.resolveComponents(components);
780
+ const { valid, invalid } = this.validateComponents(components);
781
+ if (invalid.length > 0) {
782
+ logger.error(`Unknown components: ${invalid.join(", ")}`);
783
+ console.log("\nRun '@srcroot/ui list' to see available components.");
784
+ process.exit(1);
778
785
  }
779
- components = items;
780
- }
781
- const validComponents = [];
782
- const invalidComponents = [];
783
- for (const comp of components) {
784
- if (comp in REGISTRY) {
785
- validComponents.push(comp);
786
- } else {
787
- invalidComponents.push(comp);
786
+ const { componentDeps, packageDeps } = this.resolveDependencies(valid);
787
+ this.logPlan(componentDeps, packageDeps);
788
+ if (packageDeps.size > 0) {
789
+ await this.installPackages(Array.from(packageDeps));
788
790
  }
791
+ await this.copyComponents(Array.from(componentDeps));
792
+ logger.success("\n\u2705 Components added successfully!\n");
789
793
  }
790
- if (invalidComponents.length > 0) {
791
- logger.error(`Unknown components: ${invalidComponents.join(", ")}`);
792
- console.log("\nRun '@srcroot/ui list' to see available components.");
793
- process.exit(1);
794
+ async resolveComponents(components) {
795
+ if (this.options.all) {
796
+ return Object.keys(REGISTRY);
797
+ }
798
+ if (components.length === 0) {
799
+ const { items } = await prompts2({
800
+ type: "multiselect",
801
+ name: "items",
802
+ message: "Which components would you like to add?",
803
+ hint: "Space to select. A to toggle all. Enter to submit.",
804
+ instructions: false,
805
+ choices: Object.keys(REGISTRY).map((name) => ({
806
+ title: name,
807
+ value: name
808
+ }))
809
+ });
810
+ if (!items || items.length === 0) {
811
+ logger.warn("No components selected.");
812
+ process.exit(0);
813
+ }
814
+ return items;
815
+ }
816
+ return components;
794
817
  }
795
- const toInstall = /* @__PURE__ */ new Set();
796
- function resolveDeps(name) {
797
- if (toInstall.has(name)) return;
798
- toInstall.add(name);
799
- const comp = REGISTRY[name];
800
- if (comp.dependencies) {
801
- for (const dep of comp.dependencies) {
802
- resolveDeps(dep);
818
+ validateComponents(components) {
819
+ const valid = [];
820
+ const invalid = [];
821
+ for (const comp of components) {
822
+ if (comp in REGISTRY) {
823
+ valid.push(comp);
824
+ } else {
825
+ invalid.push(comp);
803
826
  }
804
827
  }
828
+ return { valid, invalid };
805
829
  }
806
- for (const comp of validComponents) {
807
- resolveDeps(comp);
830
+ resolveDependencies(components) {
831
+ const componentDeps = /* @__PURE__ */ new Set();
832
+ const packageDeps = /* @__PURE__ */ new Set();
833
+ const resolve = (name) => {
834
+ if (componentDeps.has(name)) return;
835
+ componentDeps.add(name);
836
+ const comp = REGISTRY[name];
837
+ if (comp.dependencies) {
838
+ for (const dep of comp.dependencies) {
839
+ resolve(dep);
840
+ }
841
+ }
842
+ if (comp.registryDependencies) {
843
+ for (const pkg of comp.registryDependencies) {
844
+ packageDeps.add(pkg);
845
+ }
846
+ }
847
+ };
848
+ for (const comp of components) {
849
+ resolve(comp);
850
+ }
851
+ return { componentDeps, packageDeps };
808
852
  }
809
- const componentsToAdd = Array.from(toInstall);
810
- if (componentsToAdd.length > 10) {
811
- logger.info(`
853
+ logPlan(componentDeps, packageDeps) {
854
+ const componentsToAdd = Array.from(componentDeps);
855
+ const packagesToInstall = Array.from(packageDeps);
856
+ if (componentsToAdd.length > 10) {
857
+ logger.info(`
812
858
  \u{1F4E6} Adding ${componentsToAdd.length} components...
813
859
  `);
814
- } else {
815
- logger.info("\n\u{1F4E6} Adding components:\n");
816
- componentsToAdd.forEach((name) => {
817
- console.log(` - ${name}`);
818
- });
860
+ } else {
861
+ logger.info("\n\u{1F4E6} Adding components:\n");
862
+ componentsToAdd.forEach((name) => {
863
+ console.log(` - ${name}`);
864
+ });
865
+ }
866
+ if (packagesToInstall.length > 0) {
867
+ logger.info("\n\u{1F4E6} Installing dependencies:\n");
868
+ packagesToInstall.forEach((pkg) => {
869
+ console.log(` - ${pkg}`);
870
+ });
871
+ }
872
+ console.log();
819
873
  }
820
- console.log();
821
- const spinner = ora2("Adding components...").start();
822
- const hasSrc = fs4.existsSync(path4.join(cwd, "src"));
823
- const srcPath = hasSrc ? path4.join(cwd, "src") : cwd;
824
- const componentsDir = path4.join(srcPath, "components", "ui");
825
- try {
826
- await fs4.ensureDir(componentsDir);
827
- for (const name of componentsToAdd) {
828
- const comp = REGISTRY[name];
829
- const fileName = path4.basename(comp.file);
830
- const targetPath = path4.join(componentsDir, fileName);
831
- if (fs4.existsSync(targetPath) && !options.overwrite) {
832
- spinner.stop();
833
- const { overwrite } = await prompts2({
834
- type: "confirm",
835
- name: "overwrite",
836
- message: `${fileName} already exists. Overwrite?`,
837
- initial: false
838
- });
839
- if (!overwrite) {
840
- spinner.info(`Skipped ${fileName}`);
874
+ async installPackages(packages) {
875
+ const packageManager = getPackageManager(this.cwd);
876
+ const spinner = ora2("Installing dependencies...").start();
877
+ const installCmd = packageManager === "npm" ? "install" : "add";
878
+ try {
879
+ await execa2(packageManager, [installCmd, ...packages], {
880
+ cwd: this.cwd
881
+ });
882
+ spinner.succeed("Dependencies installed");
883
+ } catch (error) {
884
+ spinner.fail("Failed to install dependencies");
885
+ logger.error(error);
886
+ logger.warn(`
887
+ Please manually install: ${packages.join(" ")}`);
888
+ }
889
+ }
890
+ async copyComponents(components) {
891
+ const spinner = ora2("Adding components...").start();
892
+ const hasSrc = fs4.existsSync(path4.join(this.cwd, "src"));
893
+ const srcPath = hasSrc ? path4.join(this.cwd, "src") : this.cwd;
894
+ const componentsDir = path4.join(srcPath, "components", "ui");
895
+ try {
896
+ await fs4.ensureDir(componentsDir);
897
+ for (const name of components) {
898
+ const comp = REGISTRY[name];
899
+ const fileName = path4.basename(comp.file);
900
+ const targetPath = path4.join(componentsDir, fileName);
901
+ if (fs4.existsSync(targetPath) && !this.options.overwrite) {
902
+ spinner.stop();
903
+ const { overwrite } = await prompts2({
904
+ type: "confirm",
905
+ name: "overwrite",
906
+ message: `${fileName} already exists. Overwrite?`,
907
+ initial: false
908
+ });
909
+ if (!overwrite) {
910
+ spinner.info(`Skipped ${fileName}`);
911
+ spinner.start("Adding components...");
912
+ continue;
913
+ }
841
914
  spinner.start("Adding components...");
915
+ }
916
+ const registryPath = path4.resolve(__dirname4, "..", "..", "registry", comp.file);
917
+ if (!fs4.existsSync(registryPath)) {
918
+ spinner.warn(`Registry file not found for ${name}: ${registryPath}`);
842
919
  continue;
843
920
  }
844
- spinner.start("Adding components...");
845
- }
846
- const registryPath = path4.resolve(__dirname4, "..", "src", "registry", comp.file);
847
- if (!fs4.existsSync(registryPath)) {
848
- spinner.warn(`Registry file not found for ${name}: ${registryPath}`);
849
- continue;
921
+ const content = await fs4.readFile(registryPath, "utf-8");
922
+ await fs4.writeFile(targetPath, content);
923
+ if (components.length > 10) {
924
+ spinner.text = `Adding ${fileName}...`;
925
+ } else {
926
+ spinner.succeed(`Added ${fileName}`);
927
+ }
850
928
  }
851
- const content = await fs4.readFile(registryPath, "utf-8");
852
- await fs4.writeFile(targetPath, content);
853
- if (componentsToAdd.length > 10) {
854
- spinner.text = `Adding ${fileName}...`;
855
- } else {
856
- spinner.succeed(`Added ${fileName}`);
929
+ if (components.length > 10) {
930
+ spinner.succeed(`Added ${components.length} components`);
857
931
  }
932
+ } catch (error) {
933
+ spinner.fail("Failed to add components");
934
+ console.error(error);
935
+ process.exit(1);
858
936
  }
859
- if (componentsToAdd.length > 10) {
860
- spinner.succeed(`Added ${componentsToAdd.length} components`);
861
- }
862
- logger.success("\n\u2705 Components added successfully!\n");
863
- } catch (error) {
864
- spinner.fail("Failed to add components");
865
- console.error(error);
866
- process.exit(1);
867
937
  }
938
+ };
939
+
940
+ // src/cli/commands/add.ts
941
+ async function add(components, options) {
942
+ const cwd = process.cwd();
943
+ const adder = new ComponentAdder(cwd, options);
944
+ await adder.add(components);
868
945
  }
869
946
 
870
947
  // src/cli/commands/list.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@srcroot/ui",
3
- "version": "0.0.37",
3
+ "version": "0.0.40",
4
4
  "description": "A UI library with polymorphic, accessible React components",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,7 +11,7 @@ interface GoogleTagManagerProps {
11
11
  }
12
12
 
13
13
  const GoogleTagManager: FC<GoogleTagManagerProps> = ({ containers }) => {
14
- const defaultServer = 'https://www.googletagmanager.com/gtm.js';
14
+ const defaultServer = 'https://www.googletagmanager.com';
15
15
 
16
16
  // Group containers by tagServer to avoid duplicate script loads
17
17
  const scriptsMap = containers.reduce((map, container) => {
@@ -32,7 +32,7 @@ const GoogleTagManager: FC<GoogleTagManagerProps> = ({ containers }) => {
32
32
  __html: `
33
33
  ${ids
34
34
  .map(
35
- id => `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s);j.async=true;j.src="${server}?"+i;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','${id}');`
35
+ id => `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s);j.async=true;j.src="${server}/gtm.js?"+i;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','${id}');`
36
36
  )
37
37
  .join('')}
38
38
  `,
@@ -45,7 +45,7 @@ const GoogleTagManager: FC<GoogleTagManagerProps> = ({ containers }) => {
45
45
  {scriptElements}
46
46
 
47
47
  <noscript>
48
- {containers.map(({ gtmId, tagServer = defaultServer }) => (
48
+ {containers.map(({ gtmId, tagServerUrl = defaultServer }) => (
49
49
  <iframe
50
50
  key={gtmId}
51
51
  src={`${tagServer}/ns.html?id=${gtmId}`}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * @srcroot/ui - Blue Theme (Tailwind 3)
3
+ * Trustworthy corporate blue
4
+ */
5
+
6
+ @tailwind base;
7
+ @tailwind components;
8
+ @tailwind utilities;
9
+
10
+ @layer base {
11
+ :root {
12
+ --background: 0 0% 100%;
13
+ --foreground: 221.2 83.2% 53.3%;
14
+
15
+ --card: 0 0% 100%;
16
+ --card-foreground: 221.2 83.2% 53.3%;
17
+
18
+ --popover: 0 0% 100%;
19
+ --popover-foreground: 221.2 83.2% 53.3%;
20
+
21
+ --primary: 221.2 83.2% 53.3%;
22
+ --primary-foreground: 210 40% 98%;
23
+
24
+ --secondary: 221.2 30% 96.1%;
25
+ --secondary-foreground: 221.2 83.2% 53.3%;
26
+
27
+ --muted: 221.2 30% 96.1%;
28
+ --muted-foreground: 221.2 10% 45%;
29
+
30
+ --accent: 221.2 30% 96.1%;
31
+ --accent-foreground: 221.2 83.2% 53.3%;
32
+
33
+ --destructive: 0 84.2% 60.2%;
34
+ --destructive-foreground: 0 0% 98%;
35
+
36
+ --success: 142.1 76.2% 36.3%;
37
+ --success-foreground: 0 0% 98%;
38
+
39
+ --warning: 45.4 93.4% 47.5%;
40
+ --warning-foreground: 221.2 83.2% 53.3%;
41
+
42
+ --info: 201.3 96.3% 32.2%;
43
+ --info-foreground: 0 0% 98%;
44
+
45
+ --border: 221.2 20% 90%;
46
+ --input: 221.2 20% 90%;
47
+ --ring: 221.2 83.2% 53.3%;
48
+
49
+ --radius: 0.5rem;
50
+
51
+ --sidebar-width: 16rem;
52
+ --sidebar-width-mobile: 18rem;
53
+ --sidebar-width-collapsed: 3rem;
54
+ --sidebar-width-icon: 3rem;
55
+ --header-height: 3.5rem;
56
+
57
+ --sidebar-background: 0 0% 98%;
58
+ --sidebar-foreground: 221.2 83.2% 53.3%;
59
+ --sidebar-primary: 221.2 83.2% 53.3%;
60
+ --sidebar-primary-foreground: 210 40% 98%;
61
+ --sidebar-accent: 221.2 30% 96.1%;
62
+ --sidebar-accent-foreground: 221.2 83.2% 53.3%;
63
+ --sidebar-border: 221.2 20% 90%;
64
+ --sidebar-ring: 221.2 83.2% 53.3%;
65
+ }
66
+
67
+ .dark {
68
+ --background: 221.2 40% 6%;
69
+ --foreground: 210 40% 98%;
70
+
71
+ --card: 221.2 40% 8%;
72
+ --card-foreground: 210 40% 98%;
73
+
74
+ --popover: 221.2 40% 8%;
75
+ --popover-foreground: 210 40% 98%;
76
+
77
+ --primary: 221.2 83.2% 53.3%;
78
+ --primary-foreground: 210 40% 98%;
79
+
80
+ --secondary: 221.2 30% 15%;
81
+ --secondary-foreground: 210 40% 98%;
82
+
83
+ --muted: 221.2 30% 15%;
84
+ --muted-foreground: 221.2 20% 65%;
85
+
86
+ --accent: 221.2 30% 15%;
87
+ --accent-foreground: 210 40% 98%;
88
+
89
+ --destructive: 0 62.8% 30.6%;
90
+ --destructive-foreground: 0 0% 98%;
91
+
92
+ --success: 142.1 70.6% 45.3%;
93
+ --success-foreground: 221.2 83.2% 53.3%;
94
+
95
+ --warning: 48 96.5% 53.1%;
96
+ --warning-foreground: 221.2 83.2% 53.3%;
97
+
98
+ --info: 199.4 95.5% 53.8%;
99
+ --info-foreground: 221.2 83.2% 53.3%;
100
+
101
+ --border: 221.2 30% 18%;
102
+ --input: 221.2 30% 18%;
103
+ --ring: 221.2 83.2% 53.3%;
104
+
105
+ --sidebar-background: 221.2 40% 10%;
106
+ --sidebar-foreground: 210 40% 98%;
107
+ --sidebar-primary: 221.2 83.2% 53.3%;
108
+ --sidebar-primary-foreground: 210 40% 98%;
109
+ --sidebar-accent: 221.2 30% 15%;
110
+ --sidebar-accent-foreground: 210 40% 98%;
111
+ --sidebar-border: 221.2 30% 18%;
112
+ --sidebar-ring: 221.2 83.2% 53.3%;
113
+ }
114
+ }
115
+
116
+ @layer base {
117
+ * {
118
+ @apply border-border;
119
+ }
120
+
121
+ body {
122
+ @apply bg-background text-foreground;
123
+ }
124
+ }
125
+
126
+ @layer utilities {
127
+ @keyframes accordion-down {
128
+ from {
129
+ height: 0;
130
+ }
131
+
132
+ to {
133
+ height: var(--radix-accordion-content-height);
134
+ }
135
+ }
136
+
137
+ @keyframes accordion-up {
138
+ from {
139
+ height: var(--radix-accordion-content-height);
140
+ }
141
+
142
+ to {
143
+ height: 0;
144
+ }
145
+ }
146
+
147
+ .animate-accordion-down {
148
+ animation: accordion-down 0.2s ease-out;
149
+ }
150
+
151
+ .animate-accordion-up {
152
+ animation: accordion-up 0.2s ease-out;
153
+ }
154
+
155
+ .bg-gradient-brand {
156
+ background: linear-gradient(135deg, hsl(var(--primary)) 0%, hsl(var(--accent)) 100%);
157
+ }
158
+ }
@@ -151,4 +151,8 @@
151
151
  .animate-accordion-up {
152
152
  animation: accordion-up 0.2s ease-out;
153
153
  }
154
+
155
+ .bg-gradient-brand {
156
+ background: linear-gradient(135deg, hsl(var(--primary)) 0%, hsl(var(--accent)) 100%);
157
+ }
154
158
  }
@@ -0,0 +1,158 @@
1
+ /**
2
+ * @srcroot/ui - Green Theme (Tailwind 3)
3
+ * Nature and success green
4
+ */
5
+
6
+ @tailwind base;
7
+ @tailwind components;
8
+ @tailwind utilities;
9
+
10
+ @layer base {
11
+ :root {
12
+ --background: 0 0% 100%;
13
+ --foreground: 142.1 76.2% 36.3%;
14
+
15
+ --card: 0 0% 100%;
16
+ --card-foreground: 142.1 76.2% 36.3%;
17
+
18
+ --popover: 0 0% 100%;
19
+ --popover-foreground: 142.1 76.2% 36.3%;
20
+
21
+ --primary: 142.1 76.2% 36.3%;
22
+ --primary-foreground: 355.7 100% 97.3%;
23
+
24
+ --secondary: 142.1 30% 96.1%;
25
+ --secondary-foreground: 142.1 76.2% 36.3%;
26
+
27
+ --muted: 142.1 30% 96.1%;
28
+ --muted-foreground: 142.1 10% 45%;
29
+
30
+ --accent: 142.1 30% 96.1%;
31
+ --accent-foreground: 142.1 76.2% 36.3%;
32
+
33
+ --destructive: 0 84.2% 60.2%;
34
+ --destructive-foreground: 0 0% 98%;
35
+
36
+ --success: 142.1 76.2% 36.3%;
37
+ --success-foreground: 0 0% 98%;
38
+
39
+ --warning: 45.4 93.4% 47.5%;
40
+ --warning-foreground: 142.1 76.2% 36.3%;
41
+
42
+ --info: 201.3 96.3% 32.2%;
43
+ --info-foreground: 0 0% 98%;
44
+
45
+ --border: 142.1 20% 90%;
46
+ --input: 142.1 20% 90%;
47
+ --ring: 142.1 76.2% 36.3%;
48
+
49
+ --radius: 0.5rem;
50
+
51
+ --sidebar-width: 16rem;
52
+ --sidebar-width-mobile: 18rem;
53
+ --sidebar-width-collapsed: 3rem;
54
+ --sidebar-width-icon: 3rem;
55
+ --header-height: 3.5rem;
56
+
57
+ --sidebar-background: 0 0% 98%;
58
+ --sidebar-foreground: 142.1 76.2% 36.3%;
59
+ --sidebar-primary: 142.1 76.2% 36.3%;
60
+ --sidebar-primary-foreground: 355.7 100% 97.3%;
61
+ --sidebar-accent: 142.1 30% 96.1%;
62
+ --sidebar-accent-foreground: 142.1 76.2% 36.3%;
63
+ --sidebar-border: 142.1 20% 90%;
64
+ --sidebar-ring: 142.1 76.2% 36.3%;
65
+ }
66
+
67
+ .dark {
68
+ --background: 142.1 40% 6%;
69
+ --foreground: 355.7 100% 97.3%;
70
+
71
+ --card: 142.1 40% 8%;
72
+ --card-foreground: 355.7 100% 97.3%;
73
+
74
+ --popover: 142.1 40% 8%;
75
+ --popover-foreground: 355.7 100% 97.3%;
76
+
77
+ --primary: 142.1 76.2% 36.3%;
78
+ --primary-foreground: 355.7 100% 97.3%;
79
+
80
+ --secondary: 142.1 30% 15%;
81
+ --secondary-foreground: 355.7 100% 97.3%;
82
+
83
+ --muted: 142.1 30% 15%;
84
+ --muted-foreground: 142.1 20% 65%;
85
+
86
+ --accent: 142.1 30% 15%;
87
+ --accent-foreground: 355.7 100% 97.3%;
88
+
89
+ --destructive: 0 62.8% 30.6%;
90
+ --destructive-foreground: 0 0% 98%;
91
+
92
+ --success: 142.1 70.6% 45.3%;
93
+ --success-foreground: 142.1 76.2% 36.3%;
94
+
95
+ --warning: 48 96.5% 53.1%;
96
+ --warning-foreground: 142.1 76.2% 36.3%;
97
+
98
+ --info: 199.4 95.5% 53.8%;
99
+ --info-foreground: 142.1 76.2% 36.3%;
100
+
101
+ --border: 142.1 30% 18%;
102
+ --input: 142.1 30% 18%;
103
+ --ring: 142.1 76.2% 36.3%;
104
+
105
+ --sidebar-background: 142.1 40% 10%;
106
+ --sidebar-foreground: 355.7 100% 97.3%;
107
+ --sidebar-primary: 142.1 76.2% 36.3%;
108
+ --sidebar-primary-foreground: 355.7 100% 97.3%;
109
+ --sidebar-accent: 142.1 30% 15%;
110
+ --sidebar-accent-foreground: 355.7 100% 97.3%;
111
+ --sidebar-border: 142.1 30% 18%;
112
+ --sidebar-ring: 142.1 76.2% 36.3%;
113
+ }
114
+ }
115
+
116
+ @layer base {
117
+ * {
118
+ @apply border-border;
119
+ }
120
+
121
+ body {
122
+ @apply bg-background text-foreground;
123
+ }
124
+ }
125
+
126
+ @layer utilities {
127
+ @keyframes accordion-down {
128
+ from {
129
+ height: 0;
130
+ }
131
+
132
+ to {
133
+ height: var(--radix-accordion-content-height);
134
+ }
135
+ }
136
+
137
+ @keyframes accordion-up {
138
+ from {
139
+ height: var(--radix-accordion-content-height);
140
+ }
141
+
142
+ to {
143
+ height: 0;
144
+ }
145
+ }
146
+
147
+ .animate-accordion-down {
148
+ animation: accordion-down 0.2s ease-out;
149
+ }
150
+
151
+ .animate-accordion-up {
152
+ animation: accordion-up 0.2s ease-out;
153
+ }
154
+
155
+ .bg-gradient-brand {
156
+ background: linear-gradient(135deg, hsl(var(--primary)) 0%, hsl(var(--accent)) 100%);
157
+ }
158
+ }
@@ -151,4 +151,8 @@
151
151
  .animate-accordion-up {
152
152
  animation: accordion-up 0.2s ease-out;
153
153
  }
154
+
155
+ .bg-gradient-brand {
156
+ background: linear-gradient(135deg, hsl(var(--primary)) 0%, hsl(var(--accent)) 100%);
157
+ }
154
158
  }