@almadar/ui 6.5.0 → 6.7.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.
- package/dist/{EntityBindingContext-0Evn_LcT.d.cts → EntityBindingContext-Bn3ePJQC.d.cts} +1 -1
- package/dist/{EntityBindingContext-0Evn_LcT.d.ts → EntityBindingContext-Bn3ePJQC.d.ts} +1 -1
- package/dist/{GameAudioProvider-B48iXwz3.d.ts → GameAudioProvider-Ctceau1s.d.ts} +6 -18
- package/dist/{GameAudioProvider-CQAdPreB.d.cts → GameAudioProvider-Dk_Y3LN3.d.cts} +6 -18
- package/dist/avl/index.cjs +1268 -220
- package/dist/avl/index.js +1269 -221
- package/dist/{avl-schema-parser-dvJKXn-o.d.ts → avl-schema-parser-DncJLEn9.d.ts} +18 -0
- package/dist/{avl-schema-parser-Bt4NzAam.d.cts → avl-schema-parser-FQ1474v8.d.cts} +18 -0
- package/dist/{cn-DJSBBm5W.d.cts → cn-CCjFspAo.d.cts} +25 -1
- package/dist/{cn-BbhJq_nr.d.ts → cn-sgpqpN0U.d.ts} +25 -1
- package/dist/components/index.cjs +1092 -249
- package/dist/components/index.d.cts +193 -23
- package/dist/components/index.d.ts +193 -23
- package/dist/components/index.js +1089 -250
- package/dist/context/index.cjs +10 -13
- package/dist/context/index.js +10 -13
- package/dist/hooks/index.cjs +63 -13
- package/dist/hooks/index.d.cts +2 -2
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.js +64 -15
- package/dist/lib/drawable/three/index.cjs +126 -13
- package/dist/lib/drawable/three/index.d.cts +2 -2
- package/dist/lib/drawable/three/index.d.ts +2 -2
- package/dist/lib/drawable/three/index.js +127 -14
- package/dist/lib/index.cjs +180 -0
- package/dist/lib/index.d.cts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +178 -1
- package/dist/locales/index.cjs +6 -3
- package/dist/locales/index.js +6 -3
- package/dist/providers/index.cjs +974 -202
- package/dist/providers/index.d.cts +2 -2
- package/dist/providers/index.d.ts +2 -2
- package/dist/providers/index.js +974 -202
- package/dist/runtime/index.cjs +1594 -196
- package/dist/runtime/index.d.cts +79 -6
- package/dist/runtime/index.d.ts +79 -6
- package/dist/runtime/index.js +1592 -198
- package/dist/slot-host-Czc2JAxo.d.cts +47 -0
- package/dist/slot-host-Czc2JAxo.d.ts +47 -0
- package/dist/{useEventBus-CQWyAWpK.d.ts → useKeyboardRouter-D84cNWmA.d.ts} +31 -1
- package/dist/{useEventBus-Ckr4wqW3.d.cts → useKeyboardRouter-DQEE_9mq.d.cts} +31 -1
- package/locales/ar.json +2 -1
- package/locales/en.json +2 -1
- package/locales/sl.json +2 -1
- package/package.json +4 -4
- package/themes/comic.css +437 -0
- package/themes/index.css +1 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { UISlot } from '@almadar/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Slot-host manifest types (Studio V4 §14, Part I1/I2).
|
|
5
|
+
*
|
|
6
|
+
* A "slot-host" is any shell that lays out named regions and mounts each
|
|
7
|
+
* one through `UISlotComponent` — e.g. a persona workspace declaring
|
|
8
|
+
* `sidebar`/`main`/`drawer`/... A manifest is the declarative region → slot
|
|
9
|
+
* binding for such a host: which compiler `UISlot` each region mounts, and
|
|
10
|
+
* whether the host's own stock content is replaced by slot content or the
|
|
11
|
+
* two are shown together (`UISlotComponent`'s `mode` prop). Substrate
|
|
12
|
+
* (lives in `@almadar/ui`, re-exported by `@almadar/sdk`) so any host — the
|
|
13
|
+
* studio's three persona shells or an embedding app — describes its
|
|
14
|
+
* regions the same way.
|
|
15
|
+
*
|
|
16
|
+
* @packageDocumentation
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* One host region's binding to a compiler slot. Mirrors `UISlotComponent`'s
|
|
21
|
+
* `mode` prop exactly — a manifest is just that prop's value, keyed by
|
|
22
|
+
* region, declared as data instead of scattered across JSX call sites.
|
|
23
|
+
*/
|
|
24
|
+
interface SlotHostRegion {
|
|
25
|
+
slot: UISlot;
|
|
26
|
+
mode: "replace" | "append";
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A host's full region map, keyed by the host's own region ids (e.g. a
|
|
30
|
+
* persona shell's `activityBar`/`sidebar`/`main`/...). `RegionId` is left
|
|
31
|
+
* generic so each host supplies its own literal union.
|
|
32
|
+
*/
|
|
33
|
+
interface SlotHostManifest<RegionId extends string = string> {
|
|
34
|
+
regions: Record<RegionId, SlotHostRegion>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Guards the invariant a slot-host manifest depends on: each `UISlot` may
|
|
38
|
+
* be mounted by at most one region. Two regions sharing a slot would mount
|
|
39
|
+
* `UISlotComponent` twice for the same slot — the second mount clears/reads
|
|
40
|
+
* the same context entry the first one owns, so one of the two regions
|
|
41
|
+
* silently loses its content (or, for a portal slot, double-portals it).
|
|
42
|
+
* Throws naming the two offending regions so the host can find the
|
|
43
|
+
* conflict without re-deriving it from the manifest.
|
|
44
|
+
*/
|
|
45
|
+
declare function assertUniqueSlotsPerHost<RegionId extends string>(manifest: SlotHostManifest<RegionId>): void;
|
|
46
|
+
|
|
47
|
+
export { type SlotHostManifest as S, type SlotHostRegion as a, assertUniqueSlotsPerHost as b };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { UISlot } from '@almadar/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Slot-host manifest types (Studio V4 §14, Part I1/I2).
|
|
5
|
+
*
|
|
6
|
+
* A "slot-host" is any shell that lays out named regions and mounts each
|
|
7
|
+
* one through `UISlotComponent` — e.g. a persona workspace declaring
|
|
8
|
+
* `sidebar`/`main`/`drawer`/... A manifest is the declarative region → slot
|
|
9
|
+
* binding for such a host: which compiler `UISlot` each region mounts, and
|
|
10
|
+
* whether the host's own stock content is replaced by slot content or the
|
|
11
|
+
* two are shown together (`UISlotComponent`'s `mode` prop). Substrate
|
|
12
|
+
* (lives in `@almadar/ui`, re-exported by `@almadar/sdk`) so any host — the
|
|
13
|
+
* studio's three persona shells or an embedding app — describes its
|
|
14
|
+
* regions the same way.
|
|
15
|
+
*
|
|
16
|
+
* @packageDocumentation
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* One host region's binding to a compiler slot. Mirrors `UISlotComponent`'s
|
|
21
|
+
* `mode` prop exactly — a manifest is just that prop's value, keyed by
|
|
22
|
+
* region, declared as data instead of scattered across JSX call sites.
|
|
23
|
+
*/
|
|
24
|
+
interface SlotHostRegion {
|
|
25
|
+
slot: UISlot;
|
|
26
|
+
mode: "replace" | "append";
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A host's full region map, keyed by the host's own region ids (e.g. a
|
|
30
|
+
* persona shell's `activityBar`/`sidebar`/`main`/...). `RegionId` is left
|
|
31
|
+
* generic so each host supplies its own literal union.
|
|
32
|
+
*/
|
|
33
|
+
interface SlotHostManifest<RegionId extends string = string> {
|
|
34
|
+
regions: Record<RegionId, SlotHostRegion>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Guards the invariant a slot-host manifest depends on: each `UISlot` may
|
|
38
|
+
* be mounted by at most one region. Two regions sharing a slot would mount
|
|
39
|
+
* `UISlotComponent` twice for the same slot — the second mount clears/reads
|
|
40
|
+
* the same context entry the first one owns, so one of the two regions
|
|
41
|
+
* silently loses its content (or, for a portal slot, double-portals it).
|
|
42
|
+
* Throws naming the two offending regions so the host can find the
|
|
43
|
+
* conflict without re-deriving it from the manifest.
|
|
44
|
+
*/
|
|
45
|
+
declare function assertUniqueSlotsPerHost<RegionId extends string>(manifest: SlotHostManifest<RegionId>): void;
|
|
46
|
+
|
|
47
|
+
export { type SlotHostManifest as S, type SlotHostRegion as a, assertUniqueSlotsPerHost as b };
|
|
@@ -62,4 +62,34 @@ declare function useEventListener(event: string, handler: BusEventListener): voi
|
|
|
62
62
|
*/
|
|
63
63
|
declare function useEmitEvent(): (type: string, payload?: EventPayload, source?: BusEventSource) => void;
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
interface KeyCaptureEntry {
|
|
66
|
+
mode: string;
|
|
67
|
+
keys: ReadonlySet<string>;
|
|
68
|
+
}
|
|
69
|
+
/** keyed by editorId, or the literal 'shell' for chrome-level bindings */
|
|
70
|
+
type KeyCaptureTable = Readonly<Record<string, KeyCaptureEntry>>;
|
|
71
|
+
interface EditorKeyEvent {
|
|
72
|
+
editorId: string;
|
|
73
|
+
key: string;
|
|
74
|
+
code: string;
|
|
75
|
+
ctrl: boolean;
|
|
76
|
+
alt: boolean;
|
|
77
|
+
shift: boolean;
|
|
78
|
+
meta: boolean;
|
|
79
|
+
repeat: boolean;
|
|
80
|
+
}
|
|
81
|
+
interface UseKeyboardRouterOptions {
|
|
82
|
+
/** declared data; caller owns it; re-read on every keydown (kept in a ref) */
|
|
83
|
+
captureTable: KeyCaptureTable;
|
|
84
|
+
/** default 'EDITOR_FOCUS' -> subscribes UI:EDITOR_FOCUS {editorId} */
|
|
85
|
+
editorFocusEvent?: string;
|
|
86
|
+
/** default 'EDITOR_BLUR' */
|
|
87
|
+
editorBlurEvent?: string;
|
|
88
|
+
/** default 'KEY' -> emits UI:KEY */
|
|
89
|
+
keyEvent?: string;
|
|
90
|
+
/** default true */
|
|
91
|
+
enabled?: boolean;
|
|
92
|
+
}
|
|
93
|
+
declare function useKeyboardRouter(options: UseKeyboardRouterOptions): void;
|
|
94
|
+
|
|
95
|
+
export { type EditorKeyEvent as E, type KeyCaptureTable as K, type UseKeyboardRouterOptions as U, type KeyCaptureEntry as a, useEventBus as b, useEventListener as c, useKeyboardRouter as d, useEmitEvent as u };
|
|
@@ -62,4 +62,34 @@ declare function useEventListener(event: string, handler: BusEventListener): voi
|
|
|
62
62
|
*/
|
|
63
63
|
declare function useEmitEvent(): (type: string, payload?: EventPayload, source?: BusEventSource) => void;
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
interface KeyCaptureEntry {
|
|
66
|
+
mode: string;
|
|
67
|
+
keys: ReadonlySet<string>;
|
|
68
|
+
}
|
|
69
|
+
/** keyed by editorId, or the literal 'shell' for chrome-level bindings */
|
|
70
|
+
type KeyCaptureTable = Readonly<Record<string, KeyCaptureEntry>>;
|
|
71
|
+
interface EditorKeyEvent {
|
|
72
|
+
editorId: string;
|
|
73
|
+
key: string;
|
|
74
|
+
code: string;
|
|
75
|
+
ctrl: boolean;
|
|
76
|
+
alt: boolean;
|
|
77
|
+
shift: boolean;
|
|
78
|
+
meta: boolean;
|
|
79
|
+
repeat: boolean;
|
|
80
|
+
}
|
|
81
|
+
interface UseKeyboardRouterOptions {
|
|
82
|
+
/** declared data; caller owns it; re-read on every keydown (kept in a ref) */
|
|
83
|
+
captureTable: KeyCaptureTable;
|
|
84
|
+
/** default 'EDITOR_FOCUS' -> subscribes UI:EDITOR_FOCUS {editorId} */
|
|
85
|
+
editorFocusEvent?: string;
|
|
86
|
+
/** default 'EDITOR_BLUR' */
|
|
87
|
+
editorBlurEvent?: string;
|
|
88
|
+
/** default 'KEY' -> emits UI:KEY */
|
|
89
|
+
keyEvent?: string;
|
|
90
|
+
/** default true */
|
|
91
|
+
enabled?: boolean;
|
|
92
|
+
}
|
|
93
|
+
declare function useKeyboardRouter(options: UseKeyboardRouterOptions): void;
|
|
94
|
+
|
|
95
|
+
export { type EditorKeyEvent as E, type KeyCaptureTable as K, type UseKeyboardRouterOptions as U, type KeyCaptureEntry as a, useEventBus as b, useEventListener as c, useKeyboardRouter as d, useEmitEvent as u };
|
package/locales/ar.json
CHANGED
|
@@ -553,5 +553,6 @@
|
|
|
553
553
|
"richTextEditor.image": "إدراج صورة",
|
|
554
554
|
"richTextEditor.imagePrompt": "رابط الصورة",
|
|
555
555
|
"richTextEditor.placeholder": "ابدأ الكتابة…",
|
|
556
|
-
"form.imageUrlFallback": "…أو الصق رابط الصورة"
|
|
556
|
+
"form.imageUrlFallback": "…أو الصق رابط الصورة",
|
|
557
|
+
"mermaid.unrenderable": "تعذر عرض هذا المخطط. يظهر مصدره أدناه."
|
|
557
558
|
}
|
package/locales/en.json
CHANGED
|
@@ -553,5 +553,6 @@
|
|
|
553
553
|
"richTextEditor.image": "Insert image",
|
|
554
554
|
"richTextEditor.imagePrompt": "Image URL",
|
|
555
555
|
"richTextEditor.placeholder": "Start writing…",
|
|
556
|
-
"form.imageUrlFallback": "…or paste an image address"
|
|
556
|
+
"form.imageUrlFallback": "…or paste an image address",
|
|
557
|
+
"mermaid.unrenderable": "This diagram could not be displayed. Its source is shown below."
|
|
557
558
|
}
|
package/locales/sl.json
CHANGED
|
@@ -553,5 +553,6 @@
|
|
|
553
553
|
"richTextEditor.image": "Vstavi sliko",
|
|
554
554
|
"richTextEditor.imagePrompt": "URL slike",
|
|
555
555
|
"richTextEditor.placeholder": "Začnite pisati …",
|
|
556
|
-
"form.imageUrlFallback": "…ali prilepite naslov slike"
|
|
556
|
+
"form.imageUrlFallback": "…ali prilepite naslov slike",
|
|
557
|
+
"mermaid.unrenderable": "Tega diagrama ni bilo mogoče prikazati. Njegova izvorna koda je prikazana spodaj."
|
|
557
558
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@almadar/ui",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.7.0",
|
|
4
4
|
"description": "React UI components, hooks, and providers for Almadar",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -118,11 +118,11 @@
|
|
|
118
118
|
"access": "public"
|
|
119
119
|
},
|
|
120
120
|
"dependencies": {
|
|
121
|
-
"@almadar/core": "^10.
|
|
121
|
+
"@almadar/core": "^10.84.0",
|
|
122
122
|
"@almadar/evaluator": "^2.44.0",
|
|
123
123
|
"@almadar/logger": "^1.12.0",
|
|
124
|
-
"@almadar/runtime": "^6.
|
|
125
|
-
"@almadar/std": "^16.
|
|
124
|
+
"@almadar/runtime": "^6.71.0",
|
|
125
|
+
"@almadar/std": "^16.204.0",
|
|
126
126
|
"@almadar/syntax": "^1.16.0",
|
|
127
127
|
"@dnd-kit/core": "^6.3.1",
|
|
128
128
|
"@dnd-kit/sortable": "^10.0.0",
|
package/themes/comic.css
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comic Theme — "Comic Studio"
|
|
3
|
+
*
|
|
4
|
+
* Fun, light, cartoonish comic-book-art skin for the game-studio editor:
|
|
5
|
+
* bold black-ink outlines, hard offset drop shadows (no blur, like
|
|
6
|
+
* screen-printed panel borders), chunky rounded corners, a bright sunny
|
|
7
|
+
* paper palette with a subtle halftone-dot texture, and snappy springy
|
|
8
|
+
* transitions. Dark mode ("night ink") inverts the ink onto a deep indigo
|
|
9
|
+
* page while keeping the same accent hues, brightened.
|
|
10
|
+
*
|
|
11
|
+
* Halftone texture: applied to `body` (descendant of the themed root, which
|
|
12
|
+
* carries [data-theme] on <html>) rather than baked into --color-background,
|
|
13
|
+
* because --color-background must stay a flat parseable color for
|
|
14
|
+
* scripts/theme-contrast-audit.mjs.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/* ==========================================================================
|
|
18
|
+
* LIGHT MODE — sunny paper + ink
|
|
19
|
+
* ========================================================================== */
|
|
20
|
+
[data-theme="comic-light"] {
|
|
21
|
+
/* Shadows - Hard offset ink silhouette, no blur */
|
|
22
|
+
--shadow-main: 4px 4px 0 0 #1c1c28;
|
|
23
|
+
--shadow-sm: 2px 2px 0 0 #1c1c28;
|
|
24
|
+
--shadow-lg: 6px 6px 0 0 #1c1c28;
|
|
25
|
+
--shadow-inner: inset 2px 2px 0 0 rgba(28, 28, 40, 0.15);
|
|
26
|
+
--shadow-none: none;
|
|
27
|
+
--shadow-hover: 6px 6px 0 0 #1c1c28;
|
|
28
|
+
--shadow-active: 1px 1px 0 0 #1c1c28;
|
|
29
|
+
|
|
30
|
+
/* Border radius - Chunky, friendly, rounded-panel corners */
|
|
31
|
+
--radius-none: 0px;
|
|
32
|
+
--radius-sm: 8px;
|
|
33
|
+
--radius-md: 14px;
|
|
34
|
+
--radius-lg: 20px;
|
|
35
|
+
--radius-xl: 28px;
|
|
36
|
+
--radius-full: 9999px;
|
|
37
|
+
|
|
38
|
+
/* Border width - Bold inked outline */
|
|
39
|
+
--border-width: 3px;
|
|
40
|
+
--border-width-thin: 2px;
|
|
41
|
+
--border-width-thick: 4px;
|
|
42
|
+
|
|
43
|
+
/* Colors - Sunny cream paper, comic red-orange primary, mint + yellow pop */
|
|
44
|
+
--color-primary: #c2301b;
|
|
45
|
+
--color-primary-hover: #a92814;
|
|
46
|
+
--color-primary-foreground: #fff8e7;
|
|
47
|
+
|
|
48
|
+
--color-secondary: #a9e8d3;
|
|
49
|
+
--color-secondary-hover: #8fdcc1;
|
|
50
|
+
--color-secondary-foreground: #0f3d2c;
|
|
51
|
+
|
|
52
|
+
--color-accent: #8f6300;
|
|
53
|
+
--color-accent-foreground: #fff8e7;
|
|
54
|
+
|
|
55
|
+
--color-muted: #f5e9c9;
|
|
56
|
+
--color-muted-foreground: #6b5a34;
|
|
57
|
+
|
|
58
|
+
--color-background: #fff8e7;
|
|
59
|
+
--color-foreground: #1c1c28;
|
|
60
|
+
--color-card: #ffffff;
|
|
61
|
+
--color-card-foreground: #1c1c28;
|
|
62
|
+
--color-surface: #fff1d6;
|
|
63
|
+
--color-border: #1c1c28;
|
|
64
|
+
--color-input: #2b2b3d;
|
|
65
|
+
--color-ring: #2f6fed;
|
|
66
|
+
|
|
67
|
+
--color-table-header: #fff1d6;
|
|
68
|
+
--color-table-border: #1c1c28;
|
|
69
|
+
--color-table-row-hover: #fff8e7;
|
|
70
|
+
--color-surface-hover: #ffe9bc;
|
|
71
|
+
--color-border-hover: #c2301b;
|
|
72
|
+
--color-placeholder: #8a7a54;
|
|
73
|
+
|
|
74
|
+
/* Semantic colors */
|
|
75
|
+
--color-error: #e0293b;
|
|
76
|
+
--color-error-foreground: #ffffff;
|
|
77
|
+
--color-success: #12874f;
|
|
78
|
+
--color-success-foreground: #ffffff;
|
|
79
|
+
--color-warning: #f5a623;
|
|
80
|
+
--color-warning-foreground: #2a1a00;
|
|
81
|
+
--color-info: #2f6fed;
|
|
82
|
+
--color-info-foreground: #ffffff;
|
|
83
|
+
|
|
84
|
+
/* Typography - Rounded friendly display + body, generous line-height */
|
|
85
|
+
--font-family:
|
|
86
|
+
"Fredoka", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
87
|
+
--font-weight-normal: 400;
|
|
88
|
+
--font-weight-medium: 500;
|
|
89
|
+
--font-weight-bold: 700;
|
|
90
|
+
--letter-spacing: 0em;
|
|
91
|
+
--line-height: 1.55;
|
|
92
|
+
|
|
93
|
+
/* Icon styling - Thick cartoon strokes */
|
|
94
|
+
--icon-stroke-width: 2.5;
|
|
95
|
+
--icon-color: #c2301b;
|
|
96
|
+
|
|
97
|
+
/* Transitions - Snappy + springy, bouncy overshoot */
|
|
98
|
+
--transition-fast: 120ms;
|
|
99
|
+
--transition-normal: 200ms;
|
|
100
|
+
--transition-slow: 320ms;
|
|
101
|
+
--transition-timing: cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
102
|
+
|
|
103
|
+
/* Hover/Active transforms - Peel-off-the-page lift / press-into-page */
|
|
104
|
+
--hover-scale: 1.03;
|
|
105
|
+
--hover-translate-y: -2px;
|
|
106
|
+
--hover-translate-x: -1px;
|
|
107
|
+
--active-scale: 0.97;
|
|
108
|
+
--active-translate-y: 1px;
|
|
109
|
+
|
|
110
|
+
/* Focus ring - Electric blue pop */
|
|
111
|
+
--focus-ring-width: 3px;
|
|
112
|
+
--focus-ring-offset: 2px;
|
|
113
|
+
--focus-ring-color: #2f6fed;
|
|
114
|
+
|
|
115
|
+
/* Layer 1 — Density axis (spacing scale) */
|
|
116
|
+
--space-0: 0px;
|
|
117
|
+
--space-1: 4px;
|
|
118
|
+
--space-2: 8px;
|
|
119
|
+
--space-3: 12px;
|
|
120
|
+
--space-4: 16px;
|
|
121
|
+
--space-5: 20px;
|
|
122
|
+
--space-6: 24px;
|
|
123
|
+
--space-7: 28px;
|
|
124
|
+
--space-8: 32px;
|
|
125
|
+
--space-9: 36px;
|
|
126
|
+
--space-10: 40px;
|
|
127
|
+
--space-11: 44px;
|
|
128
|
+
--space-12: 48px;
|
|
129
|
+
/* Density axis — per-element heights */
|
|
130
|
+
--button-height-sm: 30px;
|
|
131
|
+
--button-height-md: 40px;
|
|
132
|
+
--button-height-lg: 48px;
|
|
133
|
+
--input-height-sm: 30px;
|
|
134
|
+
--input-height-md: 40px;
|
|
135
|
+
--input-height-lg: 48px;
|
|
136
|
+
--row-height-compact: 32px;
|
|
137
|
+
--row-height-normal: 40px;
|
|
138
|
+
--row-height-spacious: 48px;
|
|
139
|
+
/* Density axis — per-element padding */
|
|
140
|
+
--card-padding-sm: 12px;
|
|
141
|
+
--card-padding-md: 18px;
|
|
142
|
+
--card-padding-lg: 24px;
|
|
143
|
+
--dialog-padding: 24px;
|
|
144
|
+
--section-gap: 32px;
|
|
145
|
+
/* Type axis — family triplet */
|
|
146
|
+
--font-family-display: "Fredoka", "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
147
|
+
--font-family-body: var(--font-family);
|
|
148
|
+
--font-family-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
149
|
+
/* Type axis — size scale */
|
|
150
|
+
--text-xs: 12px;
|
|
151
|
+
--leading-xs: 16px;
|
|
152
|
+
--text-sm: 14px;
|
|
153
|
+
--leading-sm: 20px;
|
|
154
|
+
--text-base: 16px;
|
|
155
|
+
--leading-base: 24px;
|
|
156
|
+
--text-lg: 18px;
|
|
157
|
+
--leading-lg: 28px;
|
|
158
|
+
--text-xl: 20px;
|
|
159
|
+
--leading-xl: 28px;
|
|
160
|
+
--text-2xl: 24px;
|
|
161
|
+
--leading-2xl: 32px;
|
|
162
|
+
--text-3xl: 30px;
|
|
163
|
+
--leading-3xl: 36px;
|
|
164
|
+
--text-4xl: 36px;
|
|
165
|
+
--leading-4xl: 40px;
|
|
166
|
+
--text-display-1: 48px;
|
|
167
|
+
--leading-display-1: 52px;
|
|
168
|
+
--text-display-2: 60px;
|
|
169
|
+
--leading-display-2: 64px;
|
|
170
|
+
/* Type axis — intent mapping */
|
|
171
|
+
--intent-heading-major-size: var(--text-2xl);
|
|
172
|
+
--intent-heading-major-weight: var(--font-weight-bold);
|
|
173
|
+
--intent-heading-major-leading: var(--leading-2xl);
|
|
174
|
+
--intent-heading-minor-size: var(--text-lg);
|
|
175
|
+
--intent-heading-minor-weight: var(--font-weight-bold);
|
|
176
|
+
--intent-heading-minor-leading: var(--leading-lg);
|
|
177
|
+
--intent-body-emphasis-size: var(--text-base);
|
|
178
|
+
--intent-body-emphasis-weight: var(--font-weight-medium);
|
|
179
|
+
--intent-body-emphasis-leading: var(--leading-base);
|
|
180
|
+
--intent-body-default-size: var(--text-sm);
|
|
181
|
+
--intent-body-default-weight: var(--font-weight-normal);
|
|
182
|
+
--intent-body-default-leading: var(--leading-sm);
|
|
183
|
+
--intent-body-quiet-size: var(--text-sm);
|
|
184
|
+
--intent-body-quiet-weight: var(--font-weight-normal);
|
|
185
|
+
--intent-body-quiet-leading: var(--leading-sm);
|
|
186
|
+
--intent-caption-size: var(--text-xs);
|
|
187
|
+
--intent-caption-weight: var(--font-weight-normal);
|
|
188
|
+
--intent-caption-leading: var(--leading-xs);
|
|
189
|
+
--intent-numeric-size: var(--text-sm);
|
|
190
|
+
--intent-numeric-weight: var(--font-weight-medium);
|
|
191
|
+
--intent-numeric-leading: var(--leading-sm);
|
|
192
|
+
/* Motion axis — duration palette */
|
|
193
|
+
--duration-instant: 0ms;
|
|
194
|
+
--duration-fast: var(--transition-fast);
|
|
195
|
+
--duration-normal: var(--transition-normal);
|
|
196
|
+
--duration-slow: var(--transition-slow);
|
|
197
|
+
--duration-dramatic: 600ms;
|
|
198
|
+
/* Motion axis — easing palette */
|
|
199
|
+
--easing-linear: linear;
|
|
200
|
+
--easing-standard: var(--transition-timing);
|
|
201
|
+
--easing-emphasized: cubic-bezier(0.2, 0, 0, 1);
|
|
202
|
+
--easing-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
203
|
+
/* Iconography axis */
|
|
204
|
+
--icon-family: lucide;
|
|
205
|
+
--icon-default-size: 16px;
|
|
206
|
+
/* Elevation axis — per-layer mapping */
|
|
207
|
+
--elevation-card: var(--shadow-sm);
|
|
208
|
+
--elevation-popover: var(--shadow-main);
|
|
209
|
+
--elevation-dialog: var(--shadow-lg);
|
|
210
|
+
--elevation-toast: var(--shadow-main);
|
|
211
|
+
/* Geometry axis — radius rhythm with intent */
|
|
212
|
+
--radius-container: var(--radius-md);
|
|
213
|
+
--radius-interactive: var(--radius-md);
|
|
214
|
+
--radius-pill: var(--radius-full);
|
|
215
|
+
/* Geometry axis — border-width rhythm */
|
|
216
|
+
--border-hairline: 1px;
|
|
217
|
+
--border-standard: var(--border-width);
|
|
218
|
+
--border-heavy: var(--border-width-thick);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/* Halftone-dot paper texture — subtle, doesn't fight card/panel contrast. */
|
|
222
|
+
[data-theme="comic-light"] body {
|
|
223
|
+
background-color: var(--color-background);
|
|
224
|
+
background-image: radial-gradient(circle at 1px 1px, rgba(28, 28, 40, 0.07) 1.2px, transparent 0);
|
|
225
|
+
background-size: 14px 14px;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* ==========================================================================
|
|
229
|
+
* DARK MODE — "Night Ink": deep indigo paper, cream ink outlines
|
|
230
|
+
* ========================================================================== */
|
|
231
|
+
[data-theme="comic-dark"] {
|
|
232
|
+
/* Shadows - Hard offset cream-ink silhouette, no blur */
|
|
233
|
+
--shadow-main: 4px 4px 0 0 #f0e9d8;
|
|
234
|
+
--shadow-sm: 2px 2px 0 0 #f0e9d8;
|
|
235
|
+
--shadow-lg: 6px 6px 0 0 #f0e9d8;
|
|
236
|
+
--shadow-inner: inset 2px 2px 0 0 rgba(240, 233, 216, 0.15);
|
|
237
|
+
--shadow-none: none;
|
|
238
|
+
--shadow-hover: 6px 6px 0 0 #f0e9d8;
|
|
239
|
+
--shadow-active: 1px 1px 0 0 #f0e9d8;
|
|
240
|
+
|
|
241
|
+
/* Border radius - Chunky, friendly, rounded-panel corners */
|
|
242
|
+
--radius-none: 0px;
|
|
243
|
+
--radius-sm: 8px;
|
|
244
|
+
--radius-md: 14px;
|
|
245
|
+
--radius-lg: 20px;
|
|
246
|
+
--radius-xl: 28px;
|
|
247
|
+
--radius-full: 9999px;
|
|
248
|
+
|
|
249
|
+
/* Border width - Bold inked outline */
|
|
250
|
+
--border-width: 3px;
|
|
251
|
+
--border-width-thin: 2px;
|
|
252
|
+
--border-width-thick: 4px;
|
|
253
|
+
|
|
254
|
+
/* Colors - Deep indigo night paper, brightened comic accents */
|
|
255
|
+
--color-primary: #ff7a5c;
|
|
256
|
+
--color-primary-hover: #ff9174;
|
|
257
|
+
--color-primary-foreground: #180a05;
|
|
258
|
+
|
|
259
|
+
--color-secondary: #6fe3c4;
|
|
260
|
+
--color-secondary-hover: #8ceccf;
|
|
261
|
+
--color-secondary-foreground: #062a1e;
|
|
262
|
+
|
|
263
|
+
--color-accent: #ffdd57;
|
|
264
|
+
--color-accent-foreground: #2a1e00;
|
|
265
|
+
|
|
266
|
+
--color-muted: #262a4d;
|
|
267
|
+
--color-muted-foreground: #b7bbe3;
|
|
268
|
+
|
|
269
|
+
--color-background: #14162c;
|
|
270
|
+
--color-foreground: #f5efe0;
|
|
271
|
+
--color-card: #1d2044;
|
|
272
|
+
--color-card-foreground: #f5efe0;
|
|
273
|
+
--color-surface: #1a1d3c;
|
|
274
|
+
--color-border: #f0e9d8;
|
|
275
|
+
--color-input: #c9c2a9;
|
|
276
|
+
--color-ring: #6fa8ff;
|
|
277
|
+
|
|
278
|
+
--color-table-header: #1a1d3c;
|
|
279
|
+
--color-table-border: #f0e9d8;
|
|
280
|
+
--color-table-row-hover: #20244a;
|
|
281
|
+
--color-surface-hover: #262a52;
|
|
282
|
+
--color-border-hover: #ff7a5c;
|
|
283
|
+
--color-placeholder: #8e92c0;
|
|
284
|
+
|
|
285
|
+
/* Semantic colors - Brightened for dark ground */
|
|
286
|
+
--color-error: #ff6b6b;
|
|
287
|
+
--color-error-foreground: #180505;
|
|
288
|
+
--color-success: #4ede93;
|
|
289
|
+
--color-success-foreground: #04210f;
|
|
290
|
+
--color-warning: #ffc24c;
|
|
291
|
+
--color-warning-foreground: #2a1a00;
|
|
292
|
+
--color-info: #6fa8ff;
|
|
293
|
+
--color-info-foreground: #071b3d;
|
|
294
|
+
|
|
295
|
+
/* Typography - Rounded friendly display + body, generous line-height */
|
|
296
|
+
--font-family:
|
|
297
|
+
"Fredoka", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
298
|
+
--font-weight-normal: 400;
|
|
299
|
+
--font-weight-medium: 500;
|
|
300
|
+
--font-weight-bold: 700;
|
|
301
|
+
--letter-spacing: 0em;
|
|
302
|
+
--line-height: 1.55;
|
|
303
|
+
|
|
304
|
+
/* Icon styling - Thick cartoon strokes */
|
|
305
|
+
--icon-stroke-width: 2.5;
|
|
306
|
+
--icon-color: #ff7a5c;
|
|
307
|
+
|
|
308
|
+
/* Transitions - Snappy + springy, bouncy overshoot */
|
|
309
|
+
--transition-fast: 120ms;
|
|
310
|
+
--transition-normal: 200ms;
|
|
311
|
+
--transition-slow: 320ms;
|
|
312
|
+
--transition-timing: cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
313
|
+
|
|
314
|
+
/* Hover/Active transforms - Peel-off-the-page lift / press-into-page */
|
|
315
|
+
--hover-scale: 1.03;
|
|
316
|
+
--hover-translate-y: -2px;
|
|
317
|
+
--hover-translate-x: -1px;
|
|
318
|
+
--active-scale: 0.97;
|
|
319
|
+
--active-translate-y: 1px;
|
|
320
|
+
|
|
321
|
+
/* Focus ring - Electric blue pop */
|
|
322
|
+
--focus-ring-width: 3px;
|
|
323
|
+
--focus-ring-offset: 2px;
|
|
324
|
+
--focus-ring-color: #6fa8ff;
|
|
325
|
+
|
|
326
|
+
/* Layer 1 — Density axis (spacing scale) */
|
|
327
|
+
--space-0: 0px;
|
|
328
|
+
--space-1: 4px;
|
|
329
|
+
--space-2: 8px;
|
|
330
|
+
--space-3: 12px;
|
|
331
|
+
--space-4: 16px;
|
|
332
|
+
--space-5: 20px;
|
|
333
|
+
--space-6: 24px;
|
|
334
|
+
--space-7: 28px;
|
|
335
|
+
--space-8: 32px;
|
|
336
|
+
--space-9: 36px;
|
|
337
|
+
--space-10: 40px;
|
|
338
|
+
--space-11: 44px;
|
|
339
|
+
--space-12: 48px;
|
|
340
|
+
/* Density axis — per-element heights */
|
|
341
|
+
--button-height-sm: 30px;
|
|
342
|
+
--button-height-md: 40px;
|
|
343
|
+
--button-height-lg: 48px;
|
|
344
|
+
--input-height-sm: 30px;
|
|
345
|
+
--input-height-md: 40px;
|
|
346
|
+
--input-height-lg: 48px;
|
|
347
|
+
--row-height-compact: 32px;
|
|
348
|
+
--row-height-normal: 40px;
|
|
349
|
+
--row-height-spacious: 48px;
|
|
350
|
+
/* Density axis — per-element padding */
|
|
351
|
+
--card-padding-sm: 12px;
|
|
352
|
+
--card-padding-md: 18px;
|
|
353
|
+
--card-padding-lg: 24px;
|
|
354
|
+
--dialog-padding: 24px;
|
|
355
|
+
--section-gap: 32px;
|
|
356
|
+
/* Type axis — family triplet */
|
|
357
|
+
--font-family-display: "Fredoka", "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
|
|
358
|
+
--font-family-body: var(--font-family);
|
|
359
|
+
--font-family-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
360
|
+
/* Type axis — size scale */
|
|
361
|
+
--text-xs: 12px;
|
|
362
|
+
--leading-xs: 16px;
|
|
363
|
+
--text-sm: 14px;
|
|
364
|
+
--leading-sm: 20px;
|
|
365
|
+
--text-base: 16px;
|
|
366
|
+
--leading-base: 24px;
|
|
367
|
+
--text-lg: 18px;
|
|
368
|
+
--leading-lg: 28px;
|
|
369
|
+
--text-xl: 20px;
|
|
370
|
+
--leading-xl: 28px;
|
|
371
|
+
--text-2xl: 24px;
|
|
372
|
+
--leading-2xl: 32px;
|
|
373
|
+
--text-3xl: 30px;
|
|
374
|
+
--leading-3xl: 36px;
|
|
375
|
+
--text-4xl: 36px;
|
|
376
|
+
--leading-4xl: 40px;
|
|
377
|
+
--text-display-1: 48px;
|
|
378
|
+
--leading-display-1: 52px;
|
|
379
|
+
--text-display-2: 60px;
|
|
380
|
+
--leading-display-2: 64px;
|
|
381
|
+
/* Type axis — intent mapping */
|
|
382
|
+
--intent-heading-major-size: var(--text-2xl);
|
|
383
|
+
--intent-heading-major-weight: var(--font-weight-bold);
|
|
384
|
+
--intent-heading-major-leading: var(--leading-2xl);
|
|
385
|
+
--intent-heading-minor-size: var(--text-lg);
|
|
386
|
+
--intent-heading-minor-weight: var(--font-weight-bold);
|
|
387
|
+
--intent-heading-minor-leading: var(--leading-lg);
|
|
388
|
+
--intent-body-emphasis-size: var(--text-base);
|
|
389
|
+
--intent-body-emphasis-weight: var(--font-weight-medium);
|
|
390
|
+
--intent-body-emphasis-leading: var(--leading-base);
|
|
391
|
+
--intent-body-default-size: var(--text-sm);
|
|
392
|
+
--intent-body-default-weight: var(--font-weight-normal);
|
|
393
|
+
--intent-body-default-leading: var(--leading-sm);
|
|
394
|
+
--intent-body-quiet-size: var(--text-sm);
|
|
395
|
+
--intent-body-quiet-weight: var(--font-weight-normal);
|
|
396
|
+
--intent-body-quiet-leading: var(--leading-sm);
|
|
397
|
+
--intent-caption-size: var(--text-xs);
|
|
398
|
+
--intent-caption-weight: var(--font-weight-normal);
|
|
399
|
+
--intent-caption-leading: var(--leading-xs);
|
|
400
|
+
--intent-numeric-size: var(--text-sm);
|
|
401
|
+
--intent-numeric-weight: var(--font-weight-medium);
|
|
402
|
+
--intent-numeric-leading: var(--leading-sm);
|
|
403
|
+
/* Motion axis — duration palette */
|
|
404
|
+
--duration-instant: 0ms;
|
|
405
|
+
--duration-fast: var(--transition-fast);
|
|
406
|
+
--duration-normal: var(--transition-normal);
|
|
407
|
+
--duration-slow: var(--transition-slow);
|
|
408
|
+
--duration-dramatic: 600ms;
|
|
409
|
+
/* Motion axis — easing palette */
|
|
410
|
+
--easing-linear: linear;
|
|
411
|
+
--easing-standard: var(--transition-timing);
|
|
412
|
+
--easing-emphasized: cubic-bezier(0.2, 0, 0, 1);
|
|
413
|
+
--easing-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
414
|
+
/* Iconography axis */
|
|
415
|
+
--icon-family: lucide;
|
|
416
|
+
--icon-default-size: 16px;
|
|
417
|
+
/* Elevation axis — per-layer mapping */
|
|
418
|
+
--elevation-card: var(--shadow-sm);
|
|
419
|
+
--elevation-popover: var(--shadow-main);
|
|
420
|
+
--elevation-dialog: var(--shadow-lg);
|
|
421
|
+
--elevation-toast: var(--shadow-main);
|
|
422
|
+
/* Geometry axis — radius rhythm with intent */
|
|
423
|
+
--radius-container: var(--radius-md);
|
|
424
|
+
--radius-interactive: var(--radius-md);
|
|
425
|
+
--radius-pill: var(--radius-full);
|
|
426
|
+
/* Geometry axis — border-width rhythm */
|
|
427
|
+
--border-hairline: 1px;
|
|
428
|
+
--border-standard: var(--border-width);
|
|
429
|
+
--border-heavy: var(--border-width-thick);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/* Halftone-dot paper texture — subtle, doesn't fight card/panel contrast. */
|
|
433
|
+
[data-theme="comic-dark"] body {
|
|
434
|
+
background-color: var(--color-background);
|
|
435
|
+
background-image: radial-gradient(circle at 1px 1px, rgba(240, 233, 216, 0.05) 1.2px, transparent 0);
|
|
436
|
+
background-size: 14px 14px;
|
|
437
|
+
}
|