@soulbatical/tetra-ui 0.1.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.

Potentially problematic release.


This version of @soulbatical/tetra-ui might be problematic. Click here for more details.

Files changed (123) hide show
  1. package/dist/components/AutoCard.d.ts +41 -0
  2. package/dist/components/AutoCard.d.ts.map +1 -0
  3. package/dist/components/AutoCard.js +73 -0
  4. package/dist/components/AutoCard.js.map +1 -0
  5. package/dist/components/CookieConsent.d.ts +15 -0
  6. package/dist/components/CookieConsent.d.ts.map +1 -0
  7. package/dist/components/CookieConsent.js +27 -0
  8. package/dist/components/CookieConsent.js.map +1 -0
  9. package/dist/components/GenericListLayout.d.ts +48 -0
  10. package/dist/components/GenericListLayout.d.ts.map +1 -0
  11. package/dist/components/GenericListLayout.js +18 -0
  12. package/dist/components/GenericListLayout.js.map +1 -0
  13. package/dist/components/ListGenerator.d.ts +41 -0
  14. package/dist/components/ListGenerator.d.ts.map +1 -0
  15. package/dist/components/ListGenerator.js +40 -0
  16. package/dist/components/ListGenerator.js.map +1 -0
  17. package/dist/components/LoadingStates.d.ts +38 -0
  18. package/dist/components/LoadingStates.d.ts.map +1 -0
  19. package/dist/components/LoadingStates.js +51 -0
  20. package/dist/components/LoadingStates.js.map +1 -0
  21. package/dist/components/OrgSwitcher.d.ts +15 -0
  22. package/dist/components/OrgSwitcher.d.ts.map +1 -0
  23. package/dist/components/OrgSwitcher.js +36 -0
  24. package/dist/components/OrgSwitcher.js.map +1 -0
  25. package/dist/components/PageHeader.d.ts +16 -0
  26. package/dist/components/PageHeader.d.ts.map +1 -0
  27. package/dist/components/PageHeader.js +10 -0
  28. package/dist/components/PageHeader.js.map +1 -0
  29. package/dist/components/ProtectedRoute.d.ts +9 -0
  30. package/dist/components/ProtectedRoute.d.ts.map +1 -0
  31. package/dist/components/ProtectedRoute.js +30 -0
  32. package/dist/components/ProtectedRoute.js.map +1 -0
  33. package/dist/components/StatusBadge.d.ts +15 -0
  34. package/dist/components/StatusBadge.d.ts.map +1 -0
  35. package/dist/components/StatusBadge.js +79 -0
  36. package/dist/components/StatusBadge.js.map +1 -0
  37. package/dist/components/ThemeToggle.d.ts +14 -0
  38. package/dist/components/ThemeToggle.d.ts.map +1 -0
  39. package/dist/components/ThemeToggle.js +20 -0
  40. package/dist/components/ThemeToggle.js.map +1 -0
  41. package/dist/hooks/use-mobile.d.ts +2 -0
  42. package/dist/hooks/use-mobile.d.ts.map +1 -0
  43. package/dist/hooks/use-mobile.js +17 -0
  44. package/dist/hooks/use-mobile.js.map +1 -0
  45. package/dist/hooks/useAuth.d.ts +34 -0
  46. package/dist/hooks/useAuth.d.ts.map +1 -0
  47. package/dist/hooks/useAuth.js +156 -0
  48. package/dist/hooks/useAuth.js.map +1 -0
  49. package/dist/hooks/useCacheInvalidation.d.ts +25 -0
  50. package/dist/hooks/useCacheInvalidation.d.ts.map +1 -0
  51. package/dist/hooks/useCacheInvalidation.js +57 -0
  52. package/dist/hooks/useCacheInvalidation.js.map +1 -0
  53. package/dist/hooks/useDebounce.d.ts +2 -0
  54. package/dist/hooks/useDebounce.d.ts.map +1 -0
  55. package/dist/hooks/useDebounce.js +15 -0
  56. package/dist/hooks/useDebounce.js.map +1 -0
  57. package/dist/hooks/useDialog.d.ts +26 -0
  58. package/dist/hooks/useDialog.d.ts.map +1 -0
  59. package/dist/hooks/useDialog.js +37 -0
  60. package/dist/hooks/useDialog.js.map +1 -0
  61. package/dist/hooks/useFilterConfigs.d.ts +81 -0
  62. package/dist/hooks/useFilterConfigs.d.ts.map +1 -0
  63. package/dist/hooks/useFilterConfigs.js +68 -0
  64. package/dist/hooks/useFilterConfigs.js.map +1 -0
  65. package/dist/hooks/useFormSubmit.d.ts +79 -0
  66. package/dist/hooks/useFormSubmit.d.ts.map +1 -0
  67. package/dist/hooks/useFormSubmit.js +57 -0
  68. package/dist/hooks/useFormSubmit.js.map +1 -0
  69. package/dist/hooks/useGenericList.d.ts +62 -0
  70. package/dist/hooks/useGenericList.d.ts.map +1 -0
  71. package/dist/hooks/useGenericList.js +75 -0
  72. package/dist/hooks/useGenericList.js.map +1 -0
  73. package/dist/hooks/useGenericListWithConfig.d.ts +65 -0
  74. package/dist/hooks/useGenericListWithConfig.d.ts.map +1 -0
  75. package/dist/hooks/useGenericListWithConfig.js +98 -0
  76. package/dist/hooks/useGenericListWithConfig.js.map +1 -0
  77. package/dist/hooks/useInfiniteScroll.d.ts +11 -0
  78. package/dist/hooks/useInfiniteScroll.d.ts.map +1 -0
  79. package/dist/hooks/useInfiniteScroll.js +63 -0
  80. package/dist/hooks/useInfiniteScroll.js.map +1 -0
  81. package/dist/hooks/useOrganizations.d.ts +27 -0
  82. package/dist/hooks/useOrganizations.d.ts.map +1 -0
  83. package/dist/hooks/useOrganizations.js +56 -0
  84. package/dist/hooks/useOrganizations.js.map +1 -0
  85. package/dist/hooks/usePageContext.d.ts +29 -0
  86. package/dist/hooks/usePageContext.d.ts.map +1 -0
  87. package/dist/hooks/usePageContext.js +32 -0
  88. package/dist/hooks/usePageContext.js.map +1 -0
  89. package/dist/hooks/usePersistedQueryState.d.ts +35 -0
  90. package/dist/hooks/usePersistedQueryState.d.ts.map +1 -0
  91. package/dist/hooks/usePersistedQueryState.js +187 -0
  92. package/dist/hooks/usePersistedQueryState.js.map +1 -0
  93. package/dist/hooks/useQueryState.d.ts +40 -0
  94. package/dist/hooks/useQueryState.d.ts.map +1 -0
  95. package/dist/hooks/useQueryState.js +246 -0
  96. package/dist/hooks/useQueryState.js.map +1 -0
  97. package/dist/index.d.ts +30 -0
  98. package/dist/index.d.ts.map +1 -0
  99. package/dist/index.js +43 -0
  100. package/dist/index.js.map +1 -0
  101. package/dist/lib/utils.d.ts +3 -0
  102. package/dist/lib/utils.d.ts.map +1 -0
  103. package/dist/lib/utils.js +6 -0
  104. package/dist/lib/utils.js.map +1 -0
  105. package/dist/providers/QueryProvider.d.ts +9 -0
  106. package/dist/providers/QueryProvider.d.ts.map +1 -0
  107. package/dist/providers/QueryProvider.js +20 -0
  108. package/dist/providers/QueryProvider.js.map +1 -0
  109. package/dist/providers/ThemeProvider.d.ts +15 -0
  110. package/dist/providers/ThemeProvider.d.ts.map +1 -0
  111. package/dist/providers/ThemeProvider.js +13 -0
  112. package/dist/providers/ThemeProvider.js.map +1 -0
  113. package/dist/services/apiClient.d.ts +20 -0
  114. package/dist/services/apiClient.d.ts.map +1 -0
  115. package/dist/services/apiClient.js +85 -0
  116. package/dist/services/apiClient.js.map +1 -0
  117. package/dist/types/index.d.ts +119 -0
  118. package/dist/types/index.d.ts.map +1 -0
  119. package/dist/types/index.js +5 -0
  120. package/dist/types/index.js.map +1 -0
  121. package/package.json +68 -0
  122. package/src/styles/dark-mode.css +135 -0
  123. package/src/styles/theme.css +105 -0
@@ -0,0 +1,119 @@
1
+ /** Configuration for the tetra UI framework */
2
+ export interface TetraConfig {
3
+ /** API base URL (e.g., "http://localhost:3003") */
4
+ apiBaseUrl: string;
5
+ /** API prefix for admin routes (default: "api/admin") */
6
+ apiPrefix?: string;
7
+ /** Storage key prefix for localStorage/sessionStorage (default: "tetra") */
8
+ storagePrefix?: string;
9
+ /** Auth provider: JWT (custom backend) or Supabase */
10
+ authProvider: "jwt" | "supabase";
11
+ /** Function to get access token for API calls */
12
+ getAccessToken: () => Promise<string | null>;
13
+ }
14
+ /** Authenticated user */
15
+ export interface AuthUser {
16
+ id: string;
17
+ email: string;
18
+ name?: string;
19
+ role?: string;
20
+ organizationId?: string;
21
+ }
22
+ /** Organization for multi-tenant */
23
+ export interface Organization {
24
+ id: string;
25
+ name: string;
26
+ slug?: string;
27
+ role?: string;
28
+ }
29
+ /** Filter config from backend */
30
+ export interface FilterConfig {
31
+ name: string;
32
+ type: "search" | "enum" | "boolean" | "date_range" | "related";
33
+ label?: string;
34
+ rpcParam?: string;
35
+ options?: Array<{
36
+ value: string;
37
+ label: string;
38
+ count?: number;
39
+ }>;
40
+ placeholder?: string;
41
+ }
42
+ /** Sort field config from backend */
43
+ export interface SortFieldConfig {
44
+ field: string;
45
+ label: string;
46
+ defaultDirection?: "asc" | "desc";
47
+ }
48
+ /** Display config from backend /filters endpoint */
49
+ export interface FeatureDisplayConfig {
50
+ filters: FilterConfig[];
51
+ sortFields?: SortFieldConfig[];
52
+ defaultSort?: string;
53
+ defaultSortOrder?: "asc" | "desc";
54
+ defaultLimit?: number;
55
+ display?: {
56
+ page?: PageDisplayConfig;
57
+ list?: ListDisplayConfig;
58
+ card?: CardDisplayConfig;
59
+ };
60
+ counts?: Record<string, {
61
+ total_count: number;
62
+ }>;
63
+ }
64
+ /** Page-level display config */
65
+ export interface PageDisplayConfig {
66
+ title?: string;
67
+ icon?: string;
68
+ createButton?: {
69
+ label: string;
70
+ action?: string;
71
+ };
72
+ }
73
+ /** List-level display config */
74
+ export interface ListDisplayConfig {
75
+ emptyState?: {
76
+ title: string;
77
+ description?: string;
78
+ };
79
+ }
80
+ /** Card display config */
81
+ export interface CardDisplayConfig {
82
+ titleField?: string;
83
+ titleTemplate?: string;
84
+ imageField?: string;
85
+ badges?: Array<{
86
+ field: string;
87
+ variantMap?: Record<string, string>;
88
+ }>;
89
+ metadataRows?: Array<{
90
+ type: string;
91
+ icon?: string;
92
+ field?: string;
93
+ label?: string;
94
+ template?: string;
95
+ }>;
96
+ actions?: Array<{
97
+ type: string;
98
+ label: string;
99
+ endpoint?: string;
100
+ method?: string;
101
+ navigateTo?: string;
102
+ }>;
103
+ }
104
+ /** API response wrapper */
105
+ export interface ApiResponse<T> {
106
+ data: T;
107
+ totalCount?: number;
108
+ error?: string;
109
+ }
110
+ /** Paginated list params */
111
+ export interface ListParams {
112
+ offset?: number;
113
+ limit?: number;
114
+ sort?: string;
115
+ sortOrder?: "asc" | "desc";
116
+ search?: string;
117
+ [key: string]: string | number | boolean | undefined;
118
+ }
119
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ // ============================================
2
+ // Core types for @tetra/ui
3
+ // ============================================
4
+ export {};
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,2BAA2B;AAC3B,+CAA+C"}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@soulbatical/tetra-ui",
3
+ "private": false,
4
+ "publishConfig": {
5
+ "access": "restricted"
6
+ },
7
+ "version": "0.1.0",
8
+ "description": "Shared React frontend framework for VCA platform projects — config-driven components, hooks, providers, and styling",
9
+ "type": "module",
10
+ "main": "dist/index.js",
11
+ "types": "dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js",
16
+ "default": "./dist/index.js"
17
+ },
18
+ "./styles": {
19
+ "import": "./dist/styles/index.css",
20
+ "default": "./dist/styles/index.css"
21
+ },
22
+ "./styles/*": {
23
+ "import": "./src/styles/*",
24
+ "default": "./src/styles/*"
25
+ }
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "src/styles"
30
+ ],
31
+ "scripts": {
32
+ "build": "tsc",
33
+ "typecheck": "tsc --noEmit",
34
+ "prepublishOnly": "npm run build"
35
+ },
36
+ "peerDependencies": {
37
+ "react": "^18.0.0 || ^19.0.0",
38
+ "react-dom": "^18.0.0 || ^19.0.0",
39
+ "next": "^14.0.0 || ^15.0.0",
40
+ "@tanstack/react-query": "^5.0.0",
41
+ "next-themes": "^0.4.0"
42
+ },
43
+ "dependencies": {
44
+ "clsx": "^2.1.0",
45
+ "tailwind-merge": "^2.6.0"
46
+ },
47
+ "devDependencies": {
48
+ "@types/react": "^19.0.0",
49
+ "@types/react-dom": "^19.0.0",
50
+ "react": "^19.0.0",
51
+ "react-dom": "^19.0.0",
52
+ "@tanstack/react-query": "^5.0.0",
53
+ "next": "^15.0.0",
54
+ "next-themes": "^0.4.0",
55
+ "typescript": "^5.7.3"
56
+ },
57
+ "keywords": [
58
+ "tetra",
59
+ "ui",
60
+ "react",
61
+ "config-driven",
62
+ "multi-tenant",
63
+ "components",
64
+ "hooks"
65
+ ],
66
+ "author": "Albert Barth",
67
+ "license": "MIT"
68
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * DARK MODE OVERRIDES — STANDARD FOR ALL VCA PROJECTS
3
+ * Remaps light Tailwind utilities to dark equivalents when .dark is on <html>.
4
+ *
5
+ * This allows pages built with bg-gray-50/bg-white to automatically
6
+ * convert to dark backgrounds without adding dark: variants everywhere.
7
+ *
8
+ * Import in your project's globals.css AFTER tailwind:
9
+ * @import "tailwindcss";
10
+ * @custom-variant dark (&:where(.dark, .dark *));
11
+ * @import "@tetra/ui/styles/theme.css";
12
+ * @import "@tetra/ui/styles/dark-mode.css";
13
+ */
14
+
15
+ /* ─── Page backgrounds ─────────────────────────────── */
16
+
17
+ .dark .bg-gray-50 {
18
+ --tw-bg-opacity: 1;
19
+ background-color: rgb(3 7 18 / var(--tw-bg-opacity)) !important; /* gray-950 */
20
+ }
21
+
22
+ .dark main .bg-white {
23
+ --tw-bg-opacity: 1;
24
+ background-color: rgb(17 24 39 / var(--tw-bg-opacity)) !important; /* gray-900 */
25
+ }
26
+
27
+ /* ─── Borders ──────────────────────────────────────── */
28
+
29
+ .dark main .border-gray-100 {
30
+ --tw-border-opacity: 1;
31
+ border-color: rgb(55 65 81 / var(--tw-border-opacity)) !important; /* gray-700 */
32
+ }
33
+ .dark main .border-gray-200 {
34
+ --tw-border-opacity: 1;
35
+ border-color: rgb(55 65 81 / var(--tw-border-opacity)) !important; /* gray-700 */
36
+ }
37
+ .dark main .border-gray-300 {
38
+ --tw-border-opacity: 1;
39
+ border-color: rgb(75 85 99 / var(--tw-border-opacity)) !important; /* gray-600 */
40
+ }
41
+
42
+ /* ─── Text ─────────────────────────────────────────── */
43
+
44
+ .dark main .text-gray-900 {
45
+ --tw-text-opacity: 1;
46
+ color: rgb(243 244 246 / var(--tw-text-opacity)) !important; /* gray-100 */
47
+ }
48
+ .dark main .text-gray-800 {
49
+ --tw-text-opacity: 1;
50
+ color: rgb(229 231 235 / var(--tw-text-opacity)) !important; /* gray-200 */
51
+ }
52
+ .dark main .text-gray-700 {
53
+ --tw-text-opacity: 1;
54
+ color: rgb(209 213 219 / var(--tw-text-opacity)) !important; /* gray-300 */
55
+ }
56
+ .dark main .text-gray-600 {
57
+ --tw-text-opacity: 1;
58
+ color: rgb(156 163 175 / var(--tw-text-opacity)) !important; /* gray-400 */
59
+ }
60
+
61
+ /* ─── Inputs ───────────────────────────────────────── */
62
+
63
+ .dark main input.bg-white,
64
+ .dark main select.bg-white,
65
+ .dark main textarea.bg-white {
66
+ --tw-bg-opacity: 1;
67
+ background-color: rgb(31 41 55 / var(--tw-bg-opacity)) !important; /* gray-800 */
68
+ --tw-text-opacity: 1;
69
+ color: rgb(243 244 246 / var(--tw-text-opacity)) !important; /* gray-100 */
70
+ }
71
+
72
+ /* ─── Hover states ─────────────────────────────────── */
73
+
74
+ .dark main .hover\:bg-gray-50:hover {
75
+ background-color: rgb(31 41 55 / 1) !important; /* gray-800 */
76
+ }
77
+
78
+ /* ─── Badge colors (green) ─────────────────────────── */
79
+
80
+ .dark main .bg-green-100 {
81
+ background-color: rgb(6 78 59 / 0.3) !important;
82
+ }
83
+ .dark main .text-green-700,
84
+ .dark main .text-green-800 {
85
+ color: rgb(74 222 128) !important; /* green-400 */
86
+ }
87
+
88
+ /* ─── Badge colors (yellow) ────────────────────────── */
89
+
90
+ .dark main .bg-yellow-100 {
91
+ background-color: rgb(113 63 18 / 0.3) !important;
92
+ }
93
+ .dark main .text-yellow-700,
94
+ .dark main .text-yellow-800 {
95
+ color: rgb(250 204 21) !important; /* yellow-400 */
96
+ }
97
+
98
+ /* ─── Badge colors (blue) ──────────────────────────── */
99
+
100
+ .dark main .bg-blue-100 {
101
+ background-color: rgb(30 58 138 / 0.3) !important;
102
+ }
103
+ .dark main .text-blue-700,
104
+ .dark main .text-blue-800 {
105
+ color: rgb(96 165 250) !important; /* blue-400 */
106
+ }
107
+
108
+ /* ─── Badge colors (red) ───────────────────────────── */
109
+
110
+ .dark main .bg-red-100 {
111
+ background-color: rgb(127 29 29 / 0.3) !important;
112
+ }
113
+ .dark main .text-red-700,
114
+ .dark main .text-red-800 {
115
+ color: rgb(248 113 113) !important; /* red-400 */
116
+ }
117
+
118
+ /* ─── Badge colors (indigo) ────────────────────────── */
119
+
120
+ .dark main .bg-indigo-100 {
121
+ background-color: rgb(49 46 129 / 0.3) !important;
122
+ }
123
+ .dark main .text-indigo-700,
124
+ .dark main .text-indigo-800 {
125
+ color: rgb(129 140 248) !important; /* indigo-400 */
126
+ }
127
+
128
+ /* ─── Badge colors (gray) ──────────────────────────── */
129
+
130
+ .dark main .bg-gray-100 {
131
+ background-color: rgb(31 41 55 / 0.5) !important; /* gray-800/50 */
132
+ }
133
+ .dark main .bg-gray-200 {
134
+ background-color: rgb(55 65 81) !important; /* gray-700 */
135
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * SHADCN/UI THEME — STANDARD FOR ALL VCA PROJECTS
3
+ * HSL space-separated values (shadcn convention)
4
+ * Usage: hsl(var(--background)) or hsl(var(--foreground))
5
+ *
6
+ * Import this in your project's globals.css:
7
+ * @import "@tetra/ui/styles/theme.css";
8
+ */
9
+
10
+ @layer base {
11
+ :root {
12
+ --background: 0 0% 100%;
13
+ --foreground: 222.2 84% 4.9%;
14
+
15
+ --card: 0 0% 100%;
16
+ --card-foreground: 222.2 84% 4.9%;
17
+
18
+ --popover: 0 0% 100%;
19
+ --popover-foreground: 222.2 84% 4.9%;
20
+
21
+ --primary: 222.2 47.4% 11.2%;
22
+ --primary-foreground: 210 40% 98%;
23
+
24
+ --secondary: 210 40% 96.1%;
25
+ --secondary-foreground: 222.2 47.4% 11.2%;
26
+
27
+ --muted: 210 40% 96.1%;
28
+ --muted-foreground: 215.4 16.3% 46.9%;
29
+
30
+ --accent: 210 40% 96.1%;
31
+ --accent-foreground: 222.2 47.4% 11.2%;
32
+
33
+ --destructive: 0 84.2% 60.2%;
34
+ --destructive-foreground: 210 40% 98%;
35
+
36
+ --border: 214.3 31.8% 91.4%;
37
+ --input: 214.3 31.8% 91.4%;
38
+ --ring: 222.2 84% 4.9%;
39
+
40
+ --radius: 0.5rem;
41
+
42
+ --sidebar-background: 0 0% 98%;
43
+ --sidebar-foreground: 240 5.3% 26.1%;
44
+ --sidebar-primary: 240 5.9% 10%;
45
+ --sidebar-primary-foreground: 0 0% 98%;
46
+ --sidebar-accent: 240 4.8% 95.9%;
47
+ --sidebar-accent-foreground: 240 5.9% 10%;
48
+ --sidebar-border: 220 13% 91%;
49
+ --sidebar-ring: 217.2 91.2% 59.8%;
50
+ }
51
+
52
+ .dark {
53
+ --background: 222.2 84% 4.9%;
54
+ --foreground: 210 40% 98%;
55
+
56
+ --card: 222.2 84% 4.9%;
57
+ --card-foreground: 210 40% 98%;
58
+
59
+ --popover: 222.2 84% 4.9%;
60
+ --popover-foreground: 210 40% 98%;
61
+
62
+ --primary: 210 40% 98%;
63
+ --primary-foreground: 222.2 47.4% 11.2%;
64
+
65
+ --secondary: 217.2 32.6% 17.5%;
66
+ --secondary-foreground: 210 40% 98%;
67
+
68
+ --muted: 217.2 32.6% 17.5%;
69
+ --muted-foreground: 215 20.2% 65.1%;
70
+
71
+ --accent: 217.2 32.6% 17.5%;
72
+ --accent-foreground: 210 40% 98%;
73
+
74
+ --destructive: 0 62.8% 30.6%;
75
+ --destructive-foreground: 210 40% 98%;
76
+
77
+ --border: 217.2 32.6% 12%;
78
+ --input: 217.2 32.6% 17.5%;
79
+ --ring: 212.7 26.8% 83.9%;
80
+
81
+ --sidebar-background: 222.2 84% 4.9%;
82
+ --sidebar-foreground: 210 40% 98%;
83
+ --sidebar-primary: 210 40% 98%;
84
+ --sidebar-primary-foreground: 222.2 47.4% 11.2%;
85
+ --sidebar-accent: 217.2 32.6% 17.5%;
86
+ --sidebar-accent-foreground: 210 40% 98%;
87
+ --sidebar-border: 217.2 32.6% 12%;
88
+ --sidebar-ring: 212.7 26.8% 83.9%;
89
+ }
90
+ }
91
+
92
+ @layer base {
93
+ * {
94
+ border-color: hsl(var(--border));
95
+ }
96
+
97
+ body {
98
+ @apply bg-background text-foreground;
99
+ }
100
+
101
+ input::placeholder,
102
+ textarea::placeholder {
103
+ @apply text-muted-foreground/40;
104
+ }
105
+ }