@olympusoss/canvas 2.6.19

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.
Files changed (128) hide show
  1. package/package.json +179 -0
  2. package/src/components/atoms/README.md +11 -0
  3. package/src/components/atoms/aspect-ratio.tsx +32 -0
  4. package/src/components/atoms/avatar.tsx +98 -0
  5. package/src/components/atoms/badge.tsx +44 -0
  6. package/src/components/atoms/brand-mark.tsx +74 -0
  7. package/src/components/atoms/button.tsx +104 -0
  8. package/src/components/atoms/checkbox.tsx +63 -0
  9. package/src/components/atoms/flex-box.tsx +105 -0
  10. package/src/components/atoms/icon.tsx +34 -0
  11. package/src/components/atoms/input.tsx +91 -0
  12. package/src/components/atoms/label.tsx +41 -0
  13. package/src/components/atoms/logo.tsx +89 -0
  14. package/src/components/atoms/progress.tsx +55 -0
  15. package/src/components/atoms/radio-group.tsx +122 -0
  16. package/src/components/atoms/scroll-area.tsx +106 -0
  17. package/src/components/atoms/section.tsx +48 -0
  18. package/src/components/atoms/separator.tsx +45 -0
  19. package/src/components/atoms/skeleton.tsx +17 -0
  20. package/src/components/atoms/slider.tsx +93 -0
  21. package/src/components/atoms/switch.tsx +60 -0
  22. package/src/components/atoms/textarea.tsx +78 -0
  23. package/src/components/atoms/toggle.tsx +80 -0
  24. package/src/components/charts/activity-heatmap.tsx +96 -0
  25. package/src/components/charts/axes.tsx +21 -0
  26. package/src/components/charts/chart-container.tsx +195 -0
  27. package/src/components/charts/chart-legend.tsx +67 -0
  28. package/src/components/charts/chart-tooltip.tsx +161 -0
  29. package/src/components/charts/chart-types.tsx +49 -0
  30. package/src/components/charts/containers.tsx +11 -0
  31. package/src/components/charts/data.tsx +16 -0
  32. package/src/components/charts/details.tsx +25 -0
  33. package/src/components/charts/gauge.tsx +106 -0
  34. package/src/components/charts/grids.tsx +8 -0
  35. package/src/components/charts/index.ts +62 -0
  36. package/src/components/charts/labeled-bar-list.tsx +85 -0
  37. package/src/components/charts/references.tsx +8 -0
  38. package/src/components/charts/service-health-list.tsx +73 -0
  39. package/src/components/charts/sparkline.tsx +52 -0
  40. package/src/components/charts/stacked-bar.tsx +104 -0
  41. package/src/components/charts/text.tsx +10 -0
  42. package/src/components/charts/world-heat-map-inner.tsx +317 -0
  43. package/src/components/charts/world-heat-map.tsx +184 -0
  44. package/src/components/molecules/README.md +12 -0
  45. package/src/components/molecules/action-bar.tsx +73 -0
  46. package/src/components/molecules/activity-item.tsx +74 -0
  47. package/src/components/molecules/alert.tsx +80 -0
  48. package/src/components/molecules/animated-background.tsx +92 -0
  49. package/src/components/molecules/brand-lockup.tsx +48 -0
  50. package/src/components/molecules/breadcrumb.tsx +161 -0
  51. package/src/components/molecules/button-group.tsx +104 -0
  52. package/src/components/molecules/calendar.tsx +216 -0
  53. package/src/components/molecules/card.tsx +101 -0
  54. package/src/components/molecules/code-block.tsx +48 -0
  55. package/src/components/molecules/empty-state.tsx +55 -0
  56. package/src/components/molecules/error-state.tsx +42 -0
  57. package/src/components/molecules/field-display.tsx +35 -0
  58. package/src/components/molecules/input-otp.tsx +74 -0
  59. package/src/components/molecules/loading-state.tsx +36 -0
  60. package/src/components/molecules/notification-item.tsx +67 -0
  61. package/src/components/molecules/notification-list.tsx +45 -0
  62. package/src/components/molecules/number-badge.tsx +53 -0
  63. package/src/components/molecules/page-header.tsx +88 -0
  64. package/src/components/molecules/page-tabs.tsx +94 -0
  65. package/src/components/molecules/pagination.tsx +150 -0
  66. package/src/components/molecules/phone-input.tsx +200 -0
  67. package/src/components/molecules/search-bar.tsx +64 -0
  68. package/src/components/molecules/secret-field.tsx +158 -0
  69. package/src/components/molecules/section-card.tsx +91 -0
  70. package/src/components/molecules/stat-card.tsx +96 -0
  71. package/src/components/molecules/status-badge.tsx +42 -0
  72. package/src/components/molecules/stepper.tsx +96 -0
  73. package/src/components/molecules/table.tsx +157 -0
  74. package/src/components/molecules/toggle-group.tsx +145 -0
  75. package/src/components/molecules/tooltip.tsx +150 -0
  76. package/src/components/molecules/user-avatar-chip.tsx +71 -0
  77. package/src/components/organisms/README.md +14 -0
  78. package/src/components/organisms/accordion.tsx +149 -0
  79. package/src/components/organisms/alert-dialog.tsx +269 -0
  80. package/src/components/organisms/carousel.tsx +244 -0
  81. package/src/components/organisms/collapsible.tsx +69 -0
  82. package/src/components/organisms/command.tsx +143 -0
  83. package/src/components/organisms/context-menu.tsx +333 -0
  84. package/src/components/organisms/dashboard-grid.tsx +360 -0
  85. package/src/components/organisms/data-table.tsx +330 -0
  86. package/src/components/organisms/dialog.tsx +304 -0
  87. package/src/components/organisms/drawer.tsx +100 -0
  88. package/src/components/organisms/dropdown-menu.tsx +434 -0
  89. package/src/components/organisms/editors/code-editor.tsx +144 -0
  90. package/src/components/organisms/editors/index.ts +4 -0
  91. package/src/components/organisms/editors/markdown-editor.tsx +153 -0
  92. package/src/components/organisms/editors/markdown-renderer.ts +27 -0
  93. package/src/components/organisms/editors/prose-canvas-classes.ts +45 -0
  94. package/src/components/organisms/editors/rich-text-editor.tsx +126 -0
  95. package/src/components/organisms/editors/toolbar/md-toolbar.tsx +129 -0
  96. package/src/components/organisms/editors/toolbar/rte-toolbar.tsx +211 -0
  97. package/src/components/organisms/editors/toolbar/toolbar-shell.tsx +45 -0
  98. package/src/components/organisms/editors/use-codemirror-theme.ts +61 -0
  99. package/src/components/organisms/error-boundary.tsx +61 -0
  100. package/src/components/organisms/form.tsx +174 -0
  101. package/src/components/organisms/hover-card.tsx +114 -0
  102. package/src/components/organisms/menubar.tsx +491 -0
  103. package/src/components/organisms/navbar.tsx +101 -0
  104. package/src/components/organisms/navigation-menu.tsx +234 -0
  105. package/src/components/organisms/popover.tsx +144 -0
  106. package/src/components/organisms/resizable.tsx +39 -0
  107. package/src/components/organisms/schema-form.tsx +232 -0
  108. package/src/components/organisms/select.tsx +303 -0
  109. package/src/components/organisms/sheet.tsx +256 -0
  110. package/src/components/organisms/sidebar.tsx +1037 -0
  111. package/src/components/organisms/sonner.tsx +96 -0
  112. package/src/components/organisms/tabs.tsx +132 -0
  113. package/src/components/organisms/theme-provider.tsx +101 -0
  114. package/src/hooks/use-mobile.tsx +19 -0
  115. package/src/index.ts +547 -0
  116. package/src/lib/portal-container.tsx +35 -0
  117. package/src/lib/utils.ts +6 -0
  118. package/src/native.ts +23 -0
  119. package/src/tokens/colors.ts +91 -0
  120. package/src/tokens/index.ts +3 -0
  121. package/src/tokens/spacing.ts +55 -0
  122. package/src/tokens/typography.ts +27 -0
  123. package/styles/canvas.css +55 -0
  124. package/styles/dashboard-grid.css +47 -0
  125. package/styles/leaflet.css +13 -0
  126. package/styles/tokens.css +234 -0
  127. package/tailwind.config.ts +70 -0
  128. package/tsconfig.json +23 -0
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Olympus spacing scale — platform-agnostic design tokens.
3
+ * Values in pixels, convertible to rem (web) or dp (React Native).
4
+ */
5
+
6
+ export const spacing = {
7
+ 0: 0,
8
+ 0.5: 2,
9
+ 1: 4,
10
+ 1.5: 6,
11
+ 2: 8,
12
+ 2.5: 10,
13
+ 3: 12,
14
+ 3.5: 14,
15
+ 4: 16,
16
+ 5: 20,
17
+ 6: 24,
18
+ 7: 28,
19
+ 8: 32,
20
+ 9: 36,
21
+ 10: 40,
22
+ 11: 44,
23
+ 12: 48,
24
+ 14: 56,
25
+ 16: 64,
26
+ 20: 80,
27
+ 24: 96,
28
+ 28: 112,
29
+ 32: 128,
30
+ 36: 144,
31
+ 40: 160,
32
+ 44: 176,
33
+ 48: 192,
34
+ 52: 208,
35
+ 56: 224,
36
+ 60: 240,
37
+ 64: 256,
38
+ 72: 288,
39
+ 80: 320,
40
+ 96: 384,
41
+ } as const;
42
+
43
+ export const radius = {
44
+ none: 0,
45
+ sm: 4,
46
+ md: 6,
47
+ lg: 8,
48
+ xl: 12,
49
+ "2xl": 16,
50
+ "3xl": 24,
51
+ full: 9999,
52
+ } as const;
53
+
54
+ /** Default border radius used across components (0.5rem = 8px) */
55
+ export const defaultRadius = "0.5rem";
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Olympus typography tokens — platform-agnostic design tokens.
3
+ * Font families, sizes, weights, and line heights.
4
+ */
5
+
6
+ export const fontFamily = {
7
+ sans: ["Inter", "system-ui", "-apple-system", "sans-serif"],
8
+ mono: ["JetBrains Mono", "Fira Code", "monospace"],
9
+ } as const;
10
+
11
+ export const fontSize = {
12
+ xs: { size: 12, lineHeight: 16 },
13
+ sm: { size: 14, lineHeight: 20 },
14
+ base: { size: 16, lineHeight: 24 },
15
+ lg: { size: 18, lineHeight: 28 },
16
+ xl: { size: 20, lineHeight: 28 },
17
+ "2xl": { size: 24, lineHeight: 32 },
18
+ "3xl": { size: 30, lineHeight: 36 },
19
+ "4xl": { size: 36, lineHeight: 40 },
20
+ } as const;
21
+
22
+ export const fontWeight = {
23
+ normal: 400,
24
+ medium: 500,
25
+ semibold: 600,
26
+ bold: 700,
27
+ } as const;
@@ -0,0 +1,55 @@
1
+ /* ---------- Canvas lib runtime entry ----------
2
+ *
3
+ * The single CSS import that gives a consumer Canvas's full styling contract:
4
+ * - Tailwind v4 with @source pointed at canvas/src
5
+ * - Canonical design tokens (light + dark, tiered surfaces, sidebar, stat-card)
6
+ * - @theme inline mapping so `bg-card`, `text-foreground`, etc. resolve
7
+ * - Leaflet defaults for canvas/components/molecules/leaflet-map and scalable-globe
8
+ *
9
+ * Consumers (athena/hera/site/daedalus) and the canvas-docs site both import
10
+ * this file. Inside canvas-docs, the per-example iframe filters parent
11
+ * stylesheets down to ONLY this one — the sentinel rule below
12
+ * (`--canvas-runtime`) is what the filter looks for. Keep that rule.
13
+ */
14
+
15
+ @import "tailwindcss";
16
+ @source "../src/**/*.{ts,tsx}";
17
+ @import "./tokens.css";
18
+ @import "./leaflet.css";
19
+ @import "./dashboard-grid.css";
20
+
21
+ @theme inline {
22
+ --color-background: hsl(var(--background));
23
+ --color-foreground: hsl(var(--foreground));
24
+ --color-card: hsl(var(--card));
25
+ --color-card-foreground: hsl(var(--card-foreground));
26
+ --color-popover: hsl(var(--popover));
27
+ --color-popover-foreground: hsl(var(--popover-foreground));
28
+ --color-primary: hsl(var(--primary));
29
+ --color-primary-foreground: hsl(var(--primary-foreground));
30
+ --color-secondary: hsl(var(--secondary));
31
+ --color-secondary-foreground: hsl(var(--secondary-foreground));
32
+ --color-muted: hsl(var(--muted));
33
+ --color-muted-foreground: hsl(var(--muted-foreground));
34
+ --color-accent: hsl(var(--accent));
35
+ --color-accent-foreground: hsl(var(--accent-foreground));
36
+ --color-destructive: hsl(var(--destructive));
37
+ --color-destructive-foreground: hsl(var(--destructive-foreground));
38
+ --color-brand: hsl(var(--brand));
39
+ --color-brand-foreground: hsl(var(--brand-foreground));
40
+ --color-border: hsl(var(--border));
41
+ --color-input: hsl(var(--input));
42
+ --color-ring: hsl(var(--ring));
43
+ }
44
+
45
+ /* ---------- Iframe-filter sentinel ----------
46
+ * Do NOT remove. The canvas-docs Example wrapper uses this token to identify
47
+ * the canvas-runtime stylesheet among all parent-document styles when cloning
48
+ * into the per-example iframe. Stripping this rule will cause example
49
+ * components to render unstyled inside the docs preview.
50
+ */
51
+ @layer canvas-runtime {
52
+ :root {
53
+ --canvas-runtime: 1;
54
+ }
55
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Re-export of react-grid-layout's base stylesheets.
3
+ *
4
+ * Consumers of `<DashboardGrid>` import this once at app entry:
5
+ *
6
+ * import "@olympusoss/canvas/styles/dashboard-grid.css";
7
+ *
8
+ * The actual imports resolve through the consumer's bundler. Both
9
+ * `react-grid-layout` and `react-resizable` are direct dependencies of
10
+ * canvas; if either isn't installed (e.g. peer-only consumer) the @import
11
+ * errors at build time, which is the right signal.
12
+ *
13
+ * On top of the lib's stock styles, the rules below recolour the placeholder
14
+ * (drop-target hint) and resize handles to match canvas tokens — the lib
15
+ * defaults are bright red / blue and don't fit the design system.
16
+ */
17
+ @import "react-grid-layout/css/styles.css";
18
+ @import "react-resizable/css/styles.css";
19
+
20
+ .react-grid-item.react-grid-placeholder {
21
+ background: hsl(var(--accent));
22
+ opacity: 0.45;
23
+ border-radius: 0.75rem;
24
+ transition-property: transform;
25
+ }
26
+
27
+ .react-grid-item > .react-resizable-handle {
28
+ opacity: 0;
29
+ transition: opacity 150ms ease;
30
+ }
31
+
32
+ .react-grid-item:hover > .react-resizable-handle,
33
+ .react-grid-item.react-draggable-dragging > .react-resizable-handle {
34
+ opacity: 1;
35
+ }
36
+
37
+ /* Recolour the corner glyph the lib draws via ::after */
38
+ .react-grid-item > .react-resizable-handle::after {
39
+ border-color: hsl(var(--muted-foreground));
40
+ }
41
+
42
+ /* When DashboardGrid is in view-mode (`editing=false`) we hide handles
43
+ * entirely — the cursor never tells the user "you can resize this".
44
+ */
45
+ [data-dashboard-grid-editing="false"] .react-grid-item > .react-resizable-handle {
46
+ display: none;
47
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Re-export of Leaflet's base stylesheet.
3
+ *
4
+ * Consumers of `<WorldHeatMap>` import this once at app entry:
5
+ *
6
+ * import "@olympusoss/canvas/styles/leaflet.css";
7
+ *
8
+ * The actual import resolves through the consumer's bundler — `leaflet` is a
9
+ * peer-optional dependency, so an app that doesn't use the map doesn't
10
+ * incur this stylesheet. If `leaflet` isn't installed, the @import errors at
11
+ * build time, which is the right signal.
12
+ */
13
+ @import "leaflet/dist/leaflet.css";
@@ -0,0 +1,234 @@
1
+ /* ---------- Canvas tokens — single source of truth ----------
2
+ *
3
+ * Surface elevation (dark mode):
4
+ * L0 body background `--background` deepest
5
+ * L1 sidebar chrome `--sidebar-background` subtle lift, distinct hue
6
+ * L2 cards + popovers `--card` / `--popover` clearly elevated
7
+ * L3 inside-card chips `--muted` / `--secondary` / `--accent` topmost
8
+ *
9
+ * In light mode the canonical shadcn convention keeps body and cards both
10
+ * pure white — surfaces are differentiated by borders + 1px shadow rather
11
+ * than tone. That's intentional.
12
+ *
13
+ * Dual-form sidebar declaration (load-bearing — do NOT remove either form):
14
+ * - Raw HSL triplets like `--sidebar-background: 230 25% 97%` are consumed
15
+ * by `hsl(var(--…))` patterns inside component CSS / inline styles.
16
+ * - Resolved `hsl()` forms like `--sidebar: hsl(230 25% 97%)` feed Tailwind
17
+ * v4's `@theme inline { --color-sidebar: var(--sidebar) }` mapping so
18
+ * `bg-sidebar` / `text-sidebar-foreground` utilities resolve.
19
+ *
20
+ * Typography canonical: Inter for surfaces, JetBrains Mono for code.
21
+ */
22
+
23
+ @layer base {
24
+ :root {
25
+ /* ── Base palette (light) ───────────────────────────────────
26
+ * Light mode keeps body and surfaces both white — borders +
27
+ * shadow define cards. */
28
+ --background: 0 0% 100%;
29
+ --foreground: 240 10% 3.9%;
30
+ --card: 0 0% 100%;
31
+ --card-foreground: 240 10% 3.9%;
32
+ --popover: 0 0% 100%;
33
+ --popover-foreground: 240 10% 3.9%;
34
+ --primary: 240 5.9% 10%;
35
+ --primary-foreground: 0 0% 98%;
36
+ --secondary: 240 4.8% 95.9%;
37
+ --secondary-foreground: 240 5.9% 10%;
38
+ --muted: 240 4.8% 95.9%;
39
+ --muted-foreground: 240 3.8% 46.1%;
40
+ --accent: 240 4.8% 95.9%;
41
+ --accent-foreground: 240 5.9% 10%;
42
+ --destructive: 0 84.2% 60.2%;
43
+ --destructive-foreground: 0 0% 98%;
44
+ --brand: 213 94% 68%;
45
+ --brand-foreground: 0 0% 100%;
46
+ --border: 240 5.9% 90%;
47
+ --input: 240 5.9% 90%;
48
+ --ring: 240 5.9% 10%;
49
+ --radius: 0.5rem;
50
+
51
+ /* ── Chart palette ─────────────────────────────────────────── */
52
+ --chart-1: 12 76% 61%;
53
+ --chart-2: 173 58% 39%;
54
+ --chart-3: 197 37% 24%;
55
+ --chart-4: 43 74% 66%;
56
+ --chart-5: 27 87% 67%;
57
+ /* Sixth slot added for Athena dashboard charts (CHARTS.md). The 1-5
58
+ * triplets above are canonical canvas values and intentionally diverge
59
+ * from CHARTS.md's recommended palette per the "Canvas wins" rule —
60
+ * flagged in PR. */
61
+ --chart-6: 173 70% 42%;
62
+
63
+ /* ── Sidebar — blue-tinted gray (hue 230) per handoff ──────── */
64
+ --sidebar-background: 230 25% 97%;
65
+ --sidebar-foreground: 230 15% 40%;
66
+ --sidebar-primary: 230 45% 25%;
67
+ --sidebar-primary-foreground: 0 0% 98%;
68
+ --sidebar-accent: 230 40% 92%;
69
+ --sidebar-accent-foreground: 230 45% 25%;
70
+ --sidebar-border: 230 20% 90%;
71
+ --sidebar-ring: 217.2 91.2% 59.8%;
72
+
73
+ /* ── StatCard variant tokens ───────────────────────────────── *
74
+ * Used by molecules/stat-card.tsx via
75
+ * bg-[hsl(var(--stat-blue)/0.1)] text-[hsl(var(--stat-blue))]
76
+ * to render a 10%-tint background with full-saturation icon. */
77
+ --stat-blue: 217 91% 60%; /* #3b82f6 */
78
+ --stat-success: 160 84% 39%; /* #10b981 */
79
+ --stat-purple: 258 90% 66%; /* #8b5cf6 */
80
+ --stat-destructive: 0 84% 60%; /* #ef4444 */
81
+ --stat-amber: 38 92% 50%; /* #f59e0b */
82
+
83
+ /* ── Typography ────────────────────────────────────────────── */
84
+ --font-sans: "Inter", system-ui, -apple-system, sans-serif;
85
+ --font-mono: "JetBrains Mono", "Fira Code", ui-monospace, monospace;
86
+
87
+ /* ── Letter-spacing scale ──────────────────────────────────── *
88
+ * Used by display, h2, page title, stat-card.value. */
89
+ --tracking-tighter: -0.02em;
90
+ --tracking-tight: -0.015em;
91
+ --tracking-normal: 0;
92
+ }
93
+
94
+ .dark {
95
+ /* ── Base palette (dark) — tiered elevation ─────────────────
96
+ * L0: body L1: sidebar L2: card/popover L3: muted/secondary/accent
97
+ * All tiers share hue 225 (slight blue-cool) and step lightness
98
+ * by ~4-6% so surfaces visually lift above the body. */
99
+
100
+ /* L0 — deepest body */
101
+ --background: 225 24% 6%;
102
+ --foreground: 220 14% 92%;
103
+
104
+ /* L2 — cards & popovers (clearly lifted above body) */
105
+ --card: 225 18% 13%;
106
+ --card-foreground: 220 14% 92%;
107
+ --popover: 225 18% 13%;
108
+ --popover-foreground: 220 14% 92%;
109
+
110
+ /* Primary action — keep light text on dark accent */
111
+ --primary: 220 14% 95%;
112
+ --primary-foreground: 225 24% 6%;
113
+
114
+ /* L3 — chips/inputs/hover surfaces inside cards */
115
+ --secondary: 225 14% 19%;
116
+ --secondary-foreground: 220 14% 92%;
117
+ --muted: 225 14% 19%;
118
+ --muted-foreground: 225 9% 64%;
119
+ --accent: 225 14% 22%;
120
+ --accent-foreground: 220 14% 92%;
121
+
122
+ --destructive: 0 70% 45%;
123
+ --destructive-foreground: 0 0% 98%;
124
+ --brand: 213 94% 68%;
125
+ --brand-foreground: 0 0% 100%;
126
+
127
+ /* Borders — visible but subtle separation */
128
+ --border: 225 14% 22%;
129
+ --input: 225 14% 22%;
130
+ --ring: 217 91% 60%;
131
+
132
+ /* Chart palette */
133
+ --chart-1: 220 70% 50%;
134
+ --chart-2: 160 60% 45%;
135
+ --chart-3: 30 80% 55%;
136
+ --chart-4: 280 65% 60%;
137
+ --chart-5: 340 75% 55%;
138
+ --chart-6: 173 70% 50%;
139
+
140
+ /* L1 — sidebar (between body and cards, distinct hue 225) */
141
+ --sidebar-background: 225 16% 10%;
142
+ --sidebar-foreground: 220 14% 80%;
143
+ --sidebar-primary: 217 91% 65%;
144
+ --sidebar-primary-foreground: 0 0% 100%;
145
+ --sidebar-accent: 225 22% 16%;
146
+ --sidebar-accent-foreground: 220 14% 92%;
147
+ --sidebar-border: 225 14% 18%;
148
+ --sidebar-ring: 217.2 91.2% 59.8%;
149
+
150
+ /* StatCard variants — same hex; 10% tint reads on dark via opacity */
151
+ --stat-blue: 217 91% 60%;
152
+ --stat-success: 160 84% 39%;
153
+ --stat-purple: 258 90% 66%;
154
+ --stat-destructive: 0 84% 60%;
155
+ --stat-amber: 38 92% 50%;
156
+ }
157
+
158
+ * {
159
+ border-color: hsl(var(--border));
160
+ }
161
+
162
+ body {
163
+ background: hsl(var(--background));
164
+ color: hsl(var(--foreground));
165
+ }
166
+ }
167
+
168
+ @custom-variant dark (&:is(.dark *));
169
+
170
+ /* ---------- Resolved hsl() forms ----------
171
+ * These feed Tailwind v4's `@theme inline { --color-sidebar: var(--sidebar) }`
172
+ * mapping. They mirror the raw HSL triplets above; keep the two in sync.
173
+ */
174
+ :root {
175
+ --sidebar: hsl(230 25% 97%);
176
+ --sidebar-foreground: hsl(230 15% 40%);
177
+ --sidebar-primary: hsl(230 45% 25%);
178
+ --sidebar-primary-foreground: hsl(0 0% 98%);
179
+ --sidebar-accent: hsl(230 40% 92%);
180
+ --sidebar-accent-foreground: hsl(230 45% 25%);
181
+ --sidebar-border: hsl(230 20% 90%);
182
+ --sidebar-ring: hsl(217.2 91.2% 59.8%);
183
+ }
184
+
185
+ .dark {
186
+ --sidebar: hsl(225 16% 10%);
187
+ --sidebar-foreground: hsl(220 14% 80%);
188
+ --sidebar-primary: hsl(217 91% 65%);
189
+ --sidebar-primary-foreground: hsl(0 0% 100%);
190
+ --sidebar-accent: hsl(225 22% 16%);
191
+ --sidebar-accent-foreground: hsl(220 14% 92%);
192
+ --sidebar-border: hsl(225 14% 18%);
193
+ --sidebar-ring: hsl(217.2 91.2% 59.8%);
194
+ }
195
+
196
+ @theme inline {
197
+ --color-sidebar: var(--sidebar);
198
+ --color-sidebar-foreground: var(--sidebar-foreground);
199
+ --color-sidebar-primary: var(--sidebar-primary);
200
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
201
+ --color-sidebar-accent: var(--sidebar-accent);
202
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
203
+ --color-sidebar-border: var(--sidebar-border);
204
+ --color-sidebar-ring: var(--sidebar-ring);
205
+
206
+ /* StatCard variant colors — exposed as Tailwind utilities
207
+ * (e.g. text-stat-blue, bg-stat-success) for ergonomic access. */
208
+ --color-stat-blue: hsl(var(--stat-blue));
209
+ --color-stat-success: hsl(var(--stat-success));
210
+ --color-stat-purple: hsl(var(--stat-purple));
211
+ --color-stat-destructive: hsl(var(--stat-destructive));
212
+ --color-stat-amber: hsl(var(--stat-amber));
213
+ }
214
+
215
+ @keyframes orb-float-1 {
216
+ 0%, 100% {
217
+ transform: translate3d(0, 0, 0) scale(1);
218
+ }
219
+ 33% {
220
+ transform: translate3d(40px, -30px, 0) scale(1.05);
221
+ }
222
+ 66% {
223
+ transform: translate3d(-20px, 20px, 0) scale(0.95);
224
+ }
225
+ }
226
+
227
+ @keyframes orb-float-2 {
228
+ 0%, 100% {
229
+ transform: translate3d(0, 0, 0) scale(1);
230
+ }
231
+ 50% {
232
+ transform: translate3d(-30px, -40px, 0) scale(1.08);
233
+ }
234
+ }
@@ -0,0 +1,70 @@
1
+ import type { Config } from "tailwindcss";
2
+
3
+ const config: Config = {
4
+ content: ["./src/**/*.{ts,tsx}"],
5
+ darkMode: "class",
6
+ theme: {
7
+ extend: {
8
+ colors: {
9
+ background: "hsl(var(--background))",
10
+ foreground: "hsl(var(--foreground))",
11
+ card: {
12
+ DEFAULT: "hsl(var(--card))",
13
+ foreground: "hsl(var(--card-foreground))",
14
+ },
15
+ popover: {
16
+ DEFAULT: "hsl(var(--popover))",
17
+ foreground: "hsl(var(--popover-foreground))",
18
+ },
19
+ primary: {
20
+ DEFAULT: "hsl(var(--primary))",
21
+ foreground: "hsl(var(--primary-foreground))",
22
+ },
23
+ secondary: {
24
+ DEFAULT: "hsl(var(--secondary))",
25
+ foreground: "hsl(var(--secondary-foreground))",
26
+ },
27
+ muted: {
28
+ DEFAULT: "hsl(var(--muted))",
29
+ foreground: "hsl(var(--muted-foreground))",
30
+ },
31
+ accent: {
32
+ DEFAULT: "hsl(var(--accent))",
33
+ foreground: "hsl(var(--accent-foreground))",
34
+ },
35
+ destructive: {
36
+ DEFAULT: "hsl(var(--destructive))",
37
+ foreground: "hsl(var(--destructive-foreground))",
38
+ },
39
+ border: "hsl(var(--border))",
40
+ input: "hsl(var(--input))",
41
+ ring: "hsl(var(--ring))",
42
+ chart: {
43
+ "1": "hsl(var(--chart-1))",
44
+ "2": "hsl(var(--chart-2))",
45
+ "3": "hsl(var(--chart-3))",
46
+ "4": "hsl(var(--chart-4))",
47
+ "5": "hsl(var(--chart-5))",
48
+ },
49
+ sidebar: {
50
+ DEFAULT: "hsl(var(--sidebar-background))",
51
+ foreground: "hsl(var(--sidebar-foreground))",
52
+ primary: "hsl(var(--sidebar-primary))",
53
+ "primary-foreground": "hsl(var(--sidebar-primary-foreground))",
54
+ accent: "hsl(var(--sidebar-accent))",
55
+ "accent-foreground": "hsl(var(--sidebar-accent-foreground))",
56
+ border: "hsl(var(--sidebar-border))",
57
+ ring: "hsl(var(--sidebar-ring))",
58
+ },
59
+ },
60
+ borderRadius: {
61
+ lg: "var(--radius)",
62
+ md: "calc(var(--radius) - 2px)",
63
+ sm: "calc(var(--radius) - 4px)",
64
+ },
65
+ },
66
+ },
67
+ plugins: [],
68
+ };
69
+
70
+ export default config;
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "jsx": "react-jsx",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "resolveJsonModule": true,
12
+ "isolatedModules": true,
13
+ "declaration": true,
14
+ "declarationMap": true,
15
+ "outDir": "./dist",
16
+ "baseUrl": ".",
17
+ "paths": {
18
+ "@/*": ["./src/*"]
19
+ }
20
+ },
21
+ "include": ["src/**/*.ts", "src/**/*.tsx"],
22
+ "exclude": ["node_modules", "dist"]
23
+ }