@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.
- package/package.json +179 -0
- package/src/components/atoms/README.md +11 -0
- package/src/components/atoms/aspect-ratio.tsx +32 -0
- package/src/components/atoms/avatar.tsx +98 -0
- package/src/components/atoms/badge.tsx +44 -0
- package/src/components/atoms/brand-mark.tsx +74 -0
- package/src/components/atoms/button.tsx +104 -0
- package/src/components/atoms/checkbox.tsx +63 -0
- package/src/components/atoms/flex-box.tsx +105 -0
- package/src/components/atoms/icon.tsx +34 -0
- package/src/components/atoms/input.tsx +91 -0
- package/src/components/atoms/label.tsx +41 -0
- package/src/components/atoms/logo.tsx +89 -0
- package/src/components/atoms/progress.tsx +55 -0
- package/src/components/atoms/radio-group.tsx +122 -0
- package/src/components/atoms/scroll-area.tsx +106 -0
- package/src/components/atoms/section.tsx +48 -0
- package/src/components/atoms/separator.tsx +45 -0
- package/src/components/atoms/skeleton.tsx +17 -0
- package/src/components/atoms/slider.tsx +93 -0
- package/src/components/atoms/switch.tsx +60 -0
- package/src/components/atoms/textarea.tsx +78 -0
- package/src/components/atoms/toggle.tsx +80 -0
- package/src/components/charts/activity-heatmap.tsx +96 -0
- package/src/components/charts/axes.tsx +21 -0
- package/src/components/charts/chart-container.tsx +195 -0
- package/src/components/charts/chart-legend.tsx +67 -0
- package/src/components/charts/chart-tooltip.tsx +161 -0
- package/src/components/charts/chart-types.tsx +49 -0
- package/src/components/charts/containers.tsx +11 -0
- package/src/components/charts/data.tsx +16 -0
- package/src/components/charts/details.tsx +25 -0
- package/src/components/charts/gauge.tsx +106 -0
- package/src/components/charts/grids.tsx +8 -0
- package/src/components/charts/index.ts +62 -0
- package/src/components/charts/labeled-bar-list.tsx +85 -0
- package/src/components/charts/references.tsx +8 -0
- package/src/components/charts/service-health-list.tsx +73 -0
- package/src/components/charts/sparkline.tsx +52 -0
- package/src/components/charts/stacked-bar.tsx +104 -0
- package/src/components/charts/text.tsx +10 -0
- package/src/components/charts/world-heat-map-inner.tsx +317 -0
- package/src/components/charts/world-heat-map.tsx +184 -0
- package/src/components/molecules/README.md +12 -0
- package/src/components/molecules/action-bar.tsx +73 -0
- package/src/components/molecules/activity-item.tsx +74 -0
- package/src/components/molecules/alert.tsx +80 -0
- package/src/components/molecules/animated-background.tsx +92 -0
- package/src/components/molecules/brand-lockup.tsx +48 -0
- package/src/components/molecules/breadcrumb.tsx +161 -0
- package/src/components/molecules/button-group.tsx +104 -0
- package/src/components/molecules/calendar.tsx +216 -0
- package/src/components/molecules/card.tsx +101 -0
- package/src/components/molecules/code-block.tsx +48 -0
- package/src/components/molecules/empty-state.tsx +55 -0
- package/src/components/molecules/error-state.tsx +42 -0
- package/src/components/molecules/field-display.tsx +35 -0
- package/src/components/molecules/input-otp.tsx +74 -0
- package/src/components/molecules/loading-state.tsx +36 -0
- package/src/components/molecules/notification-item.tsx +67 -0
- package/src/components/molecules/notification-list.tsx +45 -0
- package/src/components/molecules/number-badge.tsx +53 -0
- package/src/components/molecules/page-header.tsx +88 -0
- package/src/components/molecules/page-tabs.tsx +94 -0
- package/src/components/molecules/pagination.tsx +150 -0
- package/src/components/molecules/phone-input.tsx +200 -0
- package/src/components/molecules/search-bar.tsx +64 -0
- package/src/components/molecules/secret-field.tsx +158 -0
- package/src/components/molecules/section-card.tsx +91 -0
- package/src/components/molecules/stat-card.tsx +96 -0
- package/src/components/molecules/status-badge.tsx +42 -0
- package/src/components/molecules/stepper.tsx +96 -0
- package/src/components/molecules/table.tsx +157 -0
- package/src/components/molecules/toggle-group.tsx +145 -0
- package/src/components/molecules/tooltip.tsx +150 -0
- package/src/components/molecules/user-avatar-chip.tsx +71 -0
- package/src/components/organisms/README.md +14 -0
- package/src/components/organisms/accordion.tsx +149 -0
- package/src/components/organisms/alert-dialog.tsx +269 -0
- package/src/components/organisms/carousel.tsx +244 -0
- package/src/components/organisms/collapsible.tsx +69 -0
- package/src/components/organisms/command.tsx +143 -0
- package/src/components/organisms/context-menu.tsx +333 -0
- package/src/components/organisms/dashboard-grid.tsx +360 -0
- package/src/components/organisms/data-table.tsx +330 -0
- package/src/components/organisms/dialog.tsx +304 -0
- package/src/components/organisms/drawer.tsx +100 -0
- package/src/components/organisms/dropdown-menu.tsx +434 -0
- package/src/components/organisms/editors/code-editor.tsx +144 -0
- package/src/components/organisms/editors/index.ts +4 -0
- package/src/components/organisms/editors/markdown-editor.tsx +153 -0
- package/src/components/organisms/editors/markdown-renderer.ts +27 -0
- package/src/components/organisms/editors/prose-canvas-classes.ts +45 -0
- package/src/components/organisms/editors/rich-text-editor.tsx +126 -0
- package/src/components/organisms/editors/toolbar/md-toolbar.tsx +129 -0
- package/src/components/organisms/editors/toolbar/rte-toolbar.tsx +211 -0
- package/src/components/organisms/editors/toolbar/toolbar-shell.tsx +45 -0
- package/src/components/organisms/editors/use-codemirror-theme.ts +61 -0
- package/src/components/organisms/error-boundary.tsx +61 -0
- package/src/components/organisms/form.tsx +174 -0
- package/src/components/organisms/hover-card.tsx +114 -0
- package/src/components/organisms/menubar.tsx +491 -0
- package/src/components/organisms/navbar.tsx +101 -0
- package/src/components/organisms/navigation-menu.tsx +234 -0
- package/src/components/organisms/popover.tsx +144 -0
- package/src/components/organisms/resizable.tsx +39 -0
- package/src/components/organisms/schema-form.tsx +232 -0
- package/src/components/organisms/select.tsx +303 -0
- package/src/components/organisms/sheet.tsx +256 -0
- package/src/components/organisms/sidebar.tsx +1037 -0
- package/src/components/organisms/sonner.tsx +96 -0
- package/src/components/organisms/tabs.tsx +132 -0
- package/src/components/organisms/theme-provider.tsx +101 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/index.ts +547 -0
- package/src/lib/portal-container.tsx +35 -0
- package/src/lib/utils.ts +6 -0
- package/src/native.ts +23 -0
- package/src/tokens/colors.ts +91 -0
- package/src/tokens/index.ts +3 -0
- package/src/tokens/spacing.ts +55 -0
- package/src/tokens/typography.ts +27 -0
- package/styles/canvas.css +55 -0
- package/styles/dashboard-grid.css +47 -0
- package/styles/leaflet.css +13 -0
- package/styles/tokens.css +234 -0
- package/tailwind.config.ts +70 -0
- 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
|
+
}
|