@quilltap/theme-storybook 1.0.44 → 1.0.46
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/{chunk-77W5TNBS.mjs → chunk-ENP3AWD5.mjs} +675 -583
- package/dist/index.css +97 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +676 -583
- package/dist/index.mjs +4 -2
- package/dist/stories/index.d.mts +19 -1
- package/dist/stories/index.d.ts +19 -1
- package/dist/stories/index.js +678 -585
- package/dist/stories/index.mjs +5 -3
- package/package.json +4 -4
- package/src/css/qt-components.css +128 -0
- package/src/stories/components/Workspace.tsx +139 -0
- package/src/stories/index.ts +1 -0
package/dist/stories/index.mjs
CHANGED
|
@@ -19,8 +19,9 @@ import {
|
|
|
19
19
|
Tabs,
|
|
20
20
|
Terminal,
|
|
21
21
|
ThemeComparison,
|
|
22
|
-
Typography
|
|
23
|
-
|
|
22
|
+
Typography,
|
|
23
|
+
Workspace
|
|
24
|
+
} from "../chunk-ENP3AWD5.mjs";
|
|
24
25
|
import "../chunk-WUKYLWAZ.mjs";
|
|
25
26
|
export {
|
|
26
27
|
Avatars,
|
|
@@ -43,5 +44,6 @@ export {
|
|
|
43
44
|
Tabs,
|
|
44
45
|
Terminal,
|
|
45
46
|
ThemeComparison,
|
|
46
|
-
Typography
|
|
47
|
+
Typography,
|
|
48
|
+
Workspace
|
|
47
49
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quilltap/theme-storybook",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.46",
|
|
4
4
|
"description": "Storybook preset and stories for developing Quilltap theme plugins",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
"storybook": ">=8.0.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@storybook/react": "^10.4.
|
|
47
|
-
"@types/react": "^19.2.
|
|
46
|
+
"@storybook/react": "^10.4.6",
|
|
47
|
+
"@types/react": "^19.2.17",
|
|
48
48
|
"react": "^19.2.7",
|
|
49
|
-
"storybook": "^10.4.
|
|
49
|
+
"storybook": "^10.4.6",
|
|
50
50
|
"tsup": "^8.5.1",
|
|
51
51
|
"typescript": "^5.9.3"
|
|
52
52
|
},
|
|
@@ -2427,6 +2427,134 @@
|
|
|
2427
2427
|
border-top: 1px solid var(--qt-tab-divider-color);
|
|
2428
2428
|
}
|
|
2429
2429
|
|
|
2430
|
+
/* ==========================================================================
|
|
2431
|
+
WORKSPACE (tabbed two-pane shell — strip, divider, drop-zone)
|
|
2432
|
+
|
|
2433
|
+
Every accented surface derives from one hook, --qt-workspace-accent, which
|
|
2434
|
+
falls back to --color-primary. Set it at your [data-theme="…"] root to
|
|
2435
|
+
re-tint the active tab, the pane divider, and the split drop-zone in one
|
|
2436
|
+
move. Finer control: the individual --qt-workspace-tab-* / -divider-* /
|
|
2437
|
+
--qt-tab-drop-zone-* hooks below.
|
|
2438
|
+
========================================================================== */
|
|
2439
|
+
|
|
2440
|
+
.qt-tab-strip {
|
|
2441
|
+
display: flex;
|
|
2442
|
+
align-items: flex-end;
|
|
2443
|
+
gap: var(--qt-tab-group-gap, 0.25rem);
|
|
2444
|
+
padding: 0.375rem 0.5rem 0;
|
|
2445
|
+
overflow-x: auto;
|
|
2446
|
+
background: var(--qt-workspace-chrome-bg, var(--qt-panel-bg, var(--color-card)));
|
|
2447
|
+
border-bottom: 1px solid var(--qt-workspace-chrome-border, var(--color-border));
|
|
2448
|
+
|
|
2449
|
+
--qt-tab-bg: var(--qt-workspace-tab-bg,
|
|
2450
|
+
color-mix(in srgb, var(--color-muted) 86%, var(--color-foreground) 8%));
|
|
2451
|
+
--qt-tab-fg: var(--qt-workspace-tab-fg,
|
|
2452
|
+
color-mix(in srgb, var(--color-foreground) 75%, transparent));
|
|
2453
|
+
--qt-tab-border: var(--qt-workspace-tab-border,
|
|
2454
|
+
color-mix(in srgb, var(--color-foreground) 34%, transparent));
|
|
2455
|
+
--qt-tab-active-bg: var(--qt-workspace-tab-active-bg,
|
|
2456
|
+
color-mix(in srgb, var(--qt-workspace-accent, var(--color-primary)) 24%, var(--color-card)));
|
|
2457
|
+
--qt-tab-active-fg: var(--qt-workspace-tab-active-fg, var(--color-foreground));
|
|
2458
|
+
--qt-tab-active-border: var(--qt-workspace-tab-active-border,
|
|
2459
|
+
var(--qt-workspace-accent, var(--color-primary)));
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
.qt-tab-strip .qt-tab {
|
|
2463
|
+
display: inline-flex;
|
|
2464
|
+
align-items: center;
|
|
2465
|
+
user-select: none;
|
|
2466
|
+
border-width: var(--qt-workspace-tab-border-width, 2px);
|
|
2467
|
+
border-bottom-width: 0;
|
|
2468
|
+
border-style: solid;
|
|
2469
|
+
border-color: var(--qt-tab-border);
|
|
2470
|
+
font-weight: 500;
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
.qt-tab-strip .qt-tab-active {
|
|
2474
|
+
font-weight: 700;
|
|
2475
|
+
border-color: var(--qt-tab-active-border);
|
|
2476
|
+
box-shadow: 0 3px 0 0 var(--qt-tab-active-border) inset;
|
|
2477
|
+
}
|
|
2478
|
+
|
|
2479
|
+
.qt-tab-label {
|
|
2480
|
+
max-width: 14rem;
|
|
2481
|
+
overflow: hidden;
|
|
2482
|
+
text-overflow: ellipsis;
|
|
2483
|
+
white-space: nowrap;
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2486
|
+
.qt-tab-close {
|
|
2487
|
+
display: inline-flex;
|
|
2488
|
+
align-items: center;
|
|
2489
|
+
justify-content: center;
|
|
2490
|
+
width: 1.15rem;
|
|
2491
|
+
height: 1.15rem;
|
|
2492
|
+
margin-left: 0.125rem;
|
|
2493
|
+
border-radius: 0.25rem;
|
|
2494
|
+
opacity: 0.55;
|
|
2495
|
+
transition: opacity 0.15s ease, background 0.15s ease;
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
.qt-tab-close:hover {
|
|
2499
|
+
opacity: 1;
|
|
2500
|
+
background: var(--qt-tab-close-hover-bg,
|
|
2501
|
+
color-mix(in srgb, var(--color-muted-foreground) 22%, transparent));
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
.qt-tab-close-icon {
|
|
2505
|
+
width: 0.8rem;
|
|
2506
|
+
height: 0.8rem;
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
.qt-workspace-divider {
|
|
2510
|
+
display: flex;
|
|
2511
|
+
align-items: center;
|
|
2512
|
+
justify-content: center;
|
|
2513
|
+
cursor: col-resize;
|
|
2514
|
+
background: var(--qt-workspace-divider-bg, var(--color-border));
|
|
2515
|
+
transition: background 0.15s ease;
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2518
|
+
.qt-workspace-divider:hover,
|
|
2519
|
+
.qt-workspace-divider:focus-visible {
|
|
2520
|
+
background: var(--qt-workspace-divider-active-bg,
|
|
2521
|
+
color-mix(in srgb, var(--qt-workspace-accent, var(--color-primary)) 60%, transparent));
|
|
2522
|
+
outline: none;
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
.qt-workspace-divider-grip {
|
|
2526
|
+
width: 2px;
|
|
2527
|
+
height: 2rem;
|
|
2528
|
+
border-radius: 9999px;
|
|
2529
|
+
background: var(--qt-workspace-divider-grip,
|
|
2530
|
+
color-mix(in srgb, var(--color-muted-foreground) 60%, transparent));
|
|
2531
|
+
}
|
|
2532
|
+
|
|
2533
|
+
.qt-tab-drop-zone {
|
|
2534
|
+
position: absolute;
|
|
2535
|
+
top: 0;
|
|
2536
|
+
right: 0;
|
|
2537
|
+
bottom: 0;
|
|
2538
|
+
width: 42%;
|
|
2539
|
+
display: flex;
|
|
2540
|
+
align-items: center;
|
|
2541
|
+
justify-content: center;
|
|
2542
|
+
background: var(--qt-tab-drop-zone-bg,
|
|
2543
|
+
color-mix(in srgb, var(--qt-workspace-accent, var(--color-primary)) 14%, transparent));
|
|
2544
|
+
border-left: 2px dashed var(--qt-tab-drop-zone-border,
|
|
2545
|
+
color-mix(in srgb, var(--qt-workspace-accent, var(--color-primary)) 70%, transparent));
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2548
|
+
.qt-tab-drop-zone-hint {
|
|
2549
|
+
padding: 0.25rem 0.75rem;
|
|
2550
|
+
border-radius: 0.375rem;
|
|
2551
|
+
font-size: 0.875rem;
|
|
2552
|
+
font-weight: 500;
|
|
2553
|
+
color: var(--color-foreground);
|
|
2554
|
+
background: var(--color-background);
|
|
2555
|
+
box-shadow: 0 1px 3px color-mix(in srgb, var(--color-foreground) 15%, transparent);
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2430
2558
|
/* ==========================================================================
|
|
2431
2559
|
DIALOG OVERLAY
|
|
2432
2560
|
========================================================================== */
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace Story Component
|
|
3
|
+
*
|
|
4
|
+
* The tabbed workspace chrome: the per-pane tab strip (active / inactive /
|
|
5
|
+
* close), the resizable pane divider with its grip, and the split drop-zone.
|
|
6
|
+
*
|
|
7
|
+
* Every accented surface here derives from a single theme hook,
|
|
8
|
+
* `--qt-workspace-accent` (it falls back to `--color-primary`). A theme re-tints
|
|
9
|
+
* the whole workspace by setting that one token at its `[data-theme="…"]` root —
|
|
10
|
+
* e.g. Madman's Box points it at cyan rather than its amber primary. The
|
|
11
|
+
* individual `--qt-workspace-tab-*` / `--qt-workspace-divider-*` /
|
|
12
|
+
* `--qt-tab-drop-zone-*` hooks remain for finer control.
|
|
13
|
+
*
|
|
14
|
+
* @module @quilltap/theme-storybook/stories/components/Workspace
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import React, { useState } from 'react';
|
|
18
|
+
|
|
19
|
+
const SectionHeading: React.FC<{ children: React.ReactNode }> = ({ children }) => (
|
|
20
|
+
<h3
|
|
21
|
+
style={{
|
|
22
|
+
fontSize: '1.125rem',
|
|
23
|
+
fontWeight: 700,
|
|
24
|
+
marginBottom: '1rem',
|
|
25
|
+
borderBottom: '1px solid var(--color-border)',
|
|
26
|
+
paddingBottom: '0.5rem',
|
|
27
|
+
}}
|
|
28
|
+
>
|
|
29
|
+
{children}
|
|
30
|
+
</h3>
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const CloseGlyph: React.FC = () => (
|
|
34
|
+
<svg className="qt-tab-close-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
35
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
|
36
|
+
</svg>
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
/** A single workspace tab (extends the base `.qt-tab` with strip affordances). */
|
|
40
|
+
const WorkspaceTab: React.FC<{
|
|
41
|
+
label: string;
|
|
42
|
+
active?: boolean;
|
|
43
|
+
closeable?: boolean;
|
|
44
|
+
}> = ({ label, active, closeable = true }) => (
|
|
45
|
+
<div
|
|
46
|
+
className={`qt-tab ${active ? 'qt-tab-active' : ''}`}
|
|
47
|
+
style={{ display: 'inline-flex', alignItems: 'center', gap: '0.5rem', cursor: 'pointer' }}
|
|
48
|
+
>
|
|
49
|
+
<span className="qt-tab-label">{label}</span>
|
|
50
|
+
{closeable && (
|
|
51
|
+
<span className="qt-tab-close" role="button" aria-label={`Close ${label}`}>
|
|
52
|
+
<CloseGlyph />
|
|
53
|
+
</span>
|
|
54
|
+
)}
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
export const Workspace: React.FC = () => {
|
|
59
|
+
const [active, setActive] = useState('salon');
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div style={{ padding: '1.5rem' }}>
|
|
63
|
+
<h2 style={{ fontSize: '1.5rem', fontWeight: 700, marginBottom: '0.5rem' }}>Workspace</h2>
|
|
64
|
+
<p style={{ color: 'var(--color-muted-foreground)', marginBottom: '1.5rem', maxWidth: '46rem' }}>
|
|
65
|
+
The tabbed two-pane shell. Set <code>--qt-workspace-accent</code> in your theme to re-tint the
|
|
66
|
+
active tab, the pane divider, and the split drop-zone in one move.
|
|
67
|
+
</p>
|
|
68
|
+
|
|
69
|
+
{/* Tab strip */}
|
|
70
|
+
<section style={{ marginBottom: '2rem' }}>
|
|
71
|
+
<SectionHeading>Tab strip — active & inactive</SectionHeading>
|
|
72
|
+
<div className="qt-tab-strip" role="tablist" style={{ borderRadius: '0.5rem 0.5rem 0 0' }}>
|
|
73
|
+
{[
|
|
74
|
+
{ id: 'home', label: 'Home' },
|
|
75
|
+
{ id: 'salon', label: 'The Salon — Bertie' },
|
|
76
|
+
{ id: 'aurora', label: 'Aurora' },
|
|
77
|
+
{ id: 'scriptorium', label: 'The Scriptorium' },
|
|
78
|
+
].map((t) => (
|
|
79
|
+
<div key={t.id} onClick={() => setActive(t.id)}>
|
|
80
|
+
<WorkspaceTab label={t.label} active={active === t.id} closeable={t.id !== 'home'} />
|
|
81
|
+
</div>
|
|
82
|
+
))}
|
|
83
|
+
</div>
|
|
84
|
+
</section>
|
|
85
|
+
|
|
86
|
+
{/* Pane divider */}
|
|
87
|
+
<section style={{ marginBottom: '2rem' }}>
|
|
88
|
+
<SectionHeading>Pane divider</SectionHeading>
|
|
89
|
+
<p style={{ color: 'var(--color-muted-foreground)', marginBottom: '0.75rem' }}>
|
|
90
|
+
Resizable split between the two panes. Hover (or focus) to see the accent.
|
|
91
|
+
</p>
|
|
92
|
+
<div
|
|
93
|
+
style={{
|
|
94
|
+
display: 'grid',
|
|
95
|
+
gridTemplateColumns: '1fr 8px 1fr',
|
|
96
|
+
height: '120px',
|
|
97
|
+
border: '1px solid var(--color-border)',
|
|
98
|
+
borderRadius: '0.5rem',
|
|
99
|
+
overflow: 'hidden',
|
|
100
|
+
}}
|
|
101
|
+
>
|
|
102
|
+
<div className="qt-panel" style={{ display: 'grid', placeItems: 'center' }}>
|
|
103
|
+
Left pane
|
|
104
|
+
</div>
|
|
105
|
+
<div className="qt-workspace-divider" tabIndex={0} role="separator" aria-label="Resize panes">
|
|
106
|
+
<div className="qt-workspace-divider-grip" />
|
|
107
|
+
</div>
|
|
108
|
+
<div className="qt-panel" style={{ display: 'grid', placeItems: 'center' }}>
|
|
109
|
+
Right pane
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</section>
|
|
113
|
+
|
|
114
|
+
{/* Split drop-zone */}
|
|
115
|
+
<section>
|
|
116
|
+
<SectionHeading>Split drop-zone</SectionHeading>
|
|
117
|
+
<p style={{ color: 'var(--color-muted-foreground)', marginBottom: '0.75rem' }}>
|
|
118
|
+
Shown while a tab is dragged toward a pane edge to create the split.
|
|
119
|
+
</p>
|
|
120
|
+
<div
|
|
121
|
+
style={{
|
|
122
|
+
position: 'relative',
|
|
123
|
+
height: '120px',
|
|
124
|
+
border: '1px solid var(--color-border)',
|
|
125
|
+
borderRadius: '0.5rem',
|
|
126
|
+
overflow: 'hidden',
|
|
127
|
+
}}
|
|
128
|
+
>
|
|
129
|
+
<div className="qt-panel" style={{ height: '100%', display: 'grid', placeItems: 'center' }}>
|
|
130
|
+
Pane
|
|
131
|
+
</div>
|
|
132
|
+
<div className="qt-tab-drop-zone">
|
|
133
|
+
<span className="qt-tab-drop-zone-hint">Drop to split</span>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
</section>
|
|
137
|
+
</div>
|
|
138
|
+
);
|
|
139
|
+
};
|
package/src/stories/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ export * from './components/Surfaces';
|
|
|
18
18
|
export * from './components/Avatars';
|
|
19
19
|
export * from './components/Dialogs';
|
|
20
20
|
export * from './components/Tabs';
|
|
21
|
+
export * from './components/Workspace';
|
|
21
22
|
export * from './components/Chat';
|
|
22
23
|
export * from './components/Terminal';
|
|
23
24
|
export * from './components/FilePreview';
|