@quilltap/theme-storybook 1.0.41 → 1.0.44
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/CHANGELOG.md +12 -0
- package/dist/{chunk-U2PTQQL5.mjs → chunk-77W5TNBS.mjs} +886 -755
- package/dist/index.css +136 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +887 -755
- package/dist/index.mjs +3 -1
- package/dist/stories/index.d.mts +13 -1
- package/dist/stories/index.d.ts +13 -1
- package/dist/stories/index.js +887 -755
- package/dist/stories/index.mjs +3 -1
- package/package.json +1 -1
- package/src/css/qt-components.css +72 -0
- package/src/stories/components/Chat.tsx +34 -0
- package/src/stories/components/Icons.tsx +2 -2
- package/src/stories/components/Surfaces.tsx +107 -0
- package/src/stories/index.ts +1 -0
package/dist/stories/index.mjs
CHANGED
|
@@ -15,11 +15,12 @@ import {
|
|
|
15
15
|
Loading,
|
|
16
16
|
Participant,
|
|
17
17
|
Spacing,
|
|
18
|
+
Surfaces,
|
|
18
19
|
Tabs,
|
|
19
20
|
Terminal,
|
|
20
21
|
ThemeComparison,
|
|
21
22
|
Typography
|
|
22
|
-
} from "../chunk-
|
|
23
|
+
} from "../chunk-77W5TNBS.mjs";
|
|
23
24
|
import "../chunk-WUKYLWAZ.mjs";
|
|
24
25
|
export {
|
|
25
26
|
Avatars,
|
|
@@ -38,6 +39,7 @@ export {
|
|
|
38
39
|
Loading,
|
|
39
40
|
Participant,
|
|
40
41
|
Spacing,
|
|
42
|
+
Surfaces,
|
|
41
43
|
Tabs,
|
|
42
44
|
Terminal,
|
|
43
45
|
ThemeComparison,
|
package/package.json
CHANGED
|
@@ -287,6 +287,17 @@
|
|
|
287
287
|
--qt-rp-button-ooc-bg: hsl(152 60% 28%);
|
|
288
288
|
--qt-rp-button-ooc-fg: hsl(152 60% 80%);
|
|
289
289
|
|
|
290
|
+
/* Roleplay-template palette (qt-roleplay-1..4): four distinct high-contrast
|
|
291
|
+
chips a delimiter can opt into. Themes override these four pairs to taste. */
|
|
292
|
+
--qt-roleplay-1-bg: hsl(217 91% 53%);
|
|
293
|
+
--qt-roleplay-1-fg: hsl(0 0% 100%);
|
|
294
|
+
--qt-roleplay-2-bg: hsl(270 65% 55%);
|
|
295
|
+
--qt-roleplay-2-fg: hsl(0 0% 100%);
|
|
296
|
+
--qt-roleplay-3-bg: hsl(38 92% 50%);
|
|
297
|
+
--qt-roleplay-3-fg: hsl(30 45% 12%);
|
|
298
|
+
--qt-roleplay-4-bg: hsl(168 78% 36%);
|
|
299
|
+
--qt-roleplay-4-fg: hsl(0 0% 100%);
|
|
300
|
+
|
|
290
301
|
/* Queue badge variables */
|
|
291
302
|
--qt-queue-badge-radius: var(--radius-sm);
|
|
292
303
|
--qt-queue-badge-padding-x: 0.375rem;
|
|
@@ -1546,6 +1557,26 @@
|
|
|
1546
1557
|
color: var(--color-accent-foreground);
|
|
1547
1558
|
}
|
|
1548
1559
|
|
|
1560
|
+
/* Hoverable accent surface — list rows, menu items, and option cards that
|
|
1561
|
+
should highlight on hover. On hover it paints the accent background AND
|
|
1562
|
+
forces the accent foreground onto the row and every descendant, so the whole
|
|
1563
|
+
row stays legible even on themes where --color-accent is a bold colour (e.g.
|
|
1564
|
+
Madman's Box amber). Without the descendant flip, children carrying their own
|
|
1565
|
+
colour (qt-text-secondary, qt-text-primary, …) would wash out — or, when their
|
|
1566
|
+
colour matches the accent, vanish entirely. The descendant selector is wrapped
|
|
1567
|
+
in :where() so it adds no specificity to the resting state (children own their
|
|
1568
|
+
colour as usual); the :hover rules still win via the hover pseudo-class. */
|
|
1569
|
+
.qt-hover-accent {
|
|
1570
|
+
transition: background-color 0.15s ease, color 0.15s ease;
|
|
1571
|
+
}
|
|
1572
|
+
.qt-hover-accent:hover {
|
|
1573
|
+
background-color: var(--color-accent);
|
|
1574
|
+
color: var(--color-accent-foreground);
|
|
1575
|
+
}
|
|
1576
|
+
.qt-hover-accent:hover :where(*) {
|
|
1577
|
+
color: var(--color-accent-foreground);
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1549
1580
|
/* ==========================================================================
|
|
1550
1581
|
STATUS COLOR UTILITIES (with opacity variants)
|
|
1551
1582
|
========================================================================== */
|
|
@@ -2526,3 +2557,44 @@
|
|
|
2526
2557
|
background-color: var(--qt-terminal-closed-badge-bg);
|
|
2527
2558
|
color: var(--qt-terminal-closed-badge-fg);
|
|
2528
2559
|
}
|
|
2560
|
+
|
|
2561
|
+
/* ==========================================================================
|
|
2562
|
+
ROLEPLAY-TEMPLATE STYLES
|
|
2563
|
+
The chips + add-on flourishes a roleplay-template delimiter can opt into. In
|
|
2564
|
+
the app these are scoped under .qt-chat-message-content to override prose; the
|
|
2565
|
+
stylebook has no prose layer, so they are declared plainly here for preview.
|
|
2566
|
+
========================================================================== */
|
|
2567
|
+
.qt-roleplay-1, .qt-roleplay-2, .qt-roleplay-3, .qt-roleplay-4,
|
|
2568
|
+
.qt-roleplay-danger, .qt-roleplay-warning, .qt-roleplay-success,
|
|
2569
|
+
.qt-roleplay-info, .qt-roleplay-muted, .qt-roleplay-code {
|
|
2570
|
+
padding: 0.125rem 0.375rem;
|
|
2571
|
+
border-radius: 0.1875rem;
|
|
2572
|
+
box-decoration-break: clone;
|
|
2573
|
+
-webkit-box-decoration-break: clone;
|
|
2574
|
+
}
|
|
2575
|
+
|
|
2576
|
+
.qt-roleplay-1 { --qt-rp-fg: var(--qt-roleplay-1-fg); --qt-rp-bg: var(--qt-roleplay-1-bg); color: var(--qt-rp-fg); background: var(--qt-rp-bg); }
|
|
2577
|
+
.qt-roleplay-2 { --qt-rp-fg: var(--qt-roleplay-2-fg); --qt-rp-bg: var(--qt-roleplay-2-bg); color: var(--qt-rp-fg); background: var(--qt-rp-bg); }
|
|
2578
|
+
.qt-roleplay-3 { --qt-rp-fg: var(--qt-roleplay-3-fg); --qt-rp-bg: var(--qt-roleplay-3-bg); color: var(--qt-rp-fg); background: var(--qt-rp-bg); }
|
|
2579
|
+
.qt-roleplay-4 { --qt-rp-fg: var(--qt-roleplay-4-fg); --qt-rp-bg: var(--qt-roleplay-4-bg); color: var(--qt-rp-fg); background: var(--qt-rp-bg); }
|
|
2580
|
+
|
|
2581
|
+
.qt-roleplay-danger { --qt-rp-fg: var(--color-destructive-foreground); --qt-rp-bg: var(--color-destructive); color: var(--qt-rp-fg); background: var(--qt-rp-bg); }
|
|
2582
|
+
.qt-roleplay-warning { --qt-rp-fg: var(--color-warning-foreground); --qt-rp-bg: var(--color-warning); color: var(--qt-rp-fg); background: var(--qt-rp-bg); }
|
|
2583
|
+
.qt-roleplay-success { --qt-rp-fg: var(--color-success-foreground); --qt-rp-bg: var(--color-success); color: var(--qt-rp-fg); background: var(--qt-rp-bg); }
|
|
2584
|
+
.qt-roleplay-info { --qt-rp-fg: var(--color-info-foreground); --qt-rp-bg: var(--color-info); color: var(--qt-rp-fg); background: var(--qt-rp-bg); }
|
|
2585
|
+
.qt-roleplay-muted { --qt-rp-fg: var(--color-muted-foreground); --qt-rp-bg: var(--color-muted); color: var(--qt-rp-fg); background: var(--qt-rp-bg); }
|
|
2586
|
+
.qt-roleplay-code { --qt-rp-fg: var(--color-foreground); --qt-rp-bg: var(--color-muted); color: var(--qt-rp-fg); background: var(--qt-rp-bg); font-family: var(--font-mono); }
|
|
2587
|
+
|
|
2588
|
+
/* Add-on flourishes (composed on top of any base style). */
|
|
2589
|
+
.qt-rp-bold { font-weight: 700; }
|
|
2590
|
+
.qt-rp-italic { font-style: italic; }
|
|
2591
|
+
.qt-rp-underline { text-decoration: underline; }
|
|
2592
|
+
.qt-rp-underline-double { text-decoration: underline; text-decoration-style: double; }
|
|
2593
|
+
.qt-rp-border { border: 1px solid currentColor; padding: 0.0625rem 0.25rem; border-radius: 0.1875rem; }
|
|
2594
|
+
.qt-rp-border-dashed { border: 1px dashed currentColor; padding: 0.0625rem 0.25rem; border-radius: 0.1875rem; }
|
|
2595
|
+
.qt-rp-reverse { color: var(--qt-rp-bg, var(--color-background)); background-color: var(--qt-rp-fg, var(--color-foreground)); }
|
|
2596
|
+
.qt-rp-font-sans { font-family: var(--theme-font-sans, ui-sans-serif, system-ui, sans-serif); }
|
|
2597
|
+
.qt-rp-font-serif { font-family: var(--theme-font-serif, ui-serif, Georgia, "Times New Roman", serif); }
|
|
2598
|
+
.qt-rp-font-mono { font-family: var(--theme-font-mono, ui-monospace, "SFMono-Regular", Menlo, monospace); }
|
|
2599
|
+
.qt-rp-font-display { font-family: var(--qt-rp-font-display, var(--theme-font-serif, Georgia, "Times New Roman", serif)); }
|
|
2600
|
+
.qt-rp-font-script { font-family: var(--qt-rp-font-script, "Segoe Script", "Brush Script MT", cursive); }
|
|
@@ -193,6 +193,40 @@ export const Chat: React.FC = () => {
|
|
|
193
193
|
</div>
|
|
194
194
|
</section>
|
|
195
195
|
|
|
196
|
+
{/* Roleplay-Template Styles */}
|
|
197
|
+
<section style={{ marginBottom: '2rem' }}>
|
|
198
|
+
<h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
|
|
199
|
+
Roleplay-Template Styles
|
|
200
|
+
</h3>
|
|
201
|
+
<p style={{ color: 'var(--color-muted-foreground)', marginBottom: '1rem' }}>
|
|
202
|
+
Style classes a roleplay-template delimiter can be assigned: four high-contrast chips (each theme picks its own four hues) plus a semantic set. Add-on flourishes (bold, italic, reverse, underline, border, font) compose on top.
|
|
203
|
+
</p>
|
|
204
|
+
<div className="qt-chat-message-content" style={{ display: 'flex', flexDirection: 'column', gap: '1rem', maxWidth: '36rem' }}>
|
|
205
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem', alignItems: 'center' }}>
|
|
206
|
+
<span className="qt-roleplay-1">Style 1</span>
|
|
207
|
+
<span className="qt-roleplay-2">Style 2</span>
|
|
208
|
+
<span className="qt-roleplay-3">Style 3</span>
|
|
209
|
+
<span className="qt-roleplay-4">Style 4</span>
|
|
210
|
+
</div>
|
|
211
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem', alignItems: 'center' }}>
|
|
212
|
+
<span className="qt-roleplay-danger">Danger</span>
|
|
213
|
+
<span className="qt-roleplay-warning">Warning</span>
|
|
214
|
+
<span className="qt-roleplay-success">Success</span>
|
|
215
|
+
<span className="qt-roleplay-info">Info</span>
|
|
216
|
+
<span className="qt-roleplay-muted">Muted</span>
|
|
217
|
+
<span className="qt-roleplay-code">code</span>
|
|
218
|
+
</div>
|
|
219
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem', alignItems: 'center' }}>
|
|
220
|
+
<span className="qt-roleplay-2 qt-rp-bold">Bold</span>
|
|
221
|
+
<span className="qt-roleplay-3 qt-rp-italic">Italic</span>
|
|
222
|
+
<span className="qt-roleplay-1 qt-rp-reverse">Reverse</span>
|
|
223
|
+
<span className="qt-roleplay-4 qt-rp-underline-double">Underline</span>
|
|
224
|
+
<span className="qt-roleplay-info qt-rp-border-dashed">Dashed border</span>
|
|
225
|
+
<span className="qt-roleplay-muted qt-rp-font-serif">Serif font</span>
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
</section>
|
|
229
|
+
|
|
196
230
|
{/* Whisper Messages */}
|
|
197
231
|
<section style={{ marginBottom: '2rem' }}>
|
|
198
232
|
<h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
|
|
@@ -23,7 +23,7 @@ const ICON_GROUPS: IconGroup[] = [
|
|
|
23
23
|
category: 'General UI',
|
|
24
24
|
names: [
|
|
25
25
|
'close', 'pencil', 'refresh', 'check', 'check-circle', 'chat', 'info', 'trash',
|
|
26
|
-
'copy', 'plus', 'search', 'download', 'upload', 'cloud-upload', 'external-link',
|
|
26
|
+
'copy', 'plus', 'minus', 'search', 'download', 'upload', 'cloud-upload', 'external-link',
|
|
27
27
|
'link', 'send', 'paperclip', 'eye', 'eye-off', 'star', 'bookmark', 'tag', 'expand', 'compress',
|
|
28
28
|
],
|
|
29
29
|
},
|
|
@@ -31,7 +31,7 @@ const ICON_GROUPS: IconGroup[] = [
|
|
|
31
31
|
category: 'Navigation arrows',
|
|
32
32
|
names: [
|
|
33
33
|
'chevron-down', 'chevron-right', 'chevron-left',
|
|
34
|
-
'arrow-left', 'arrow-right', 'arrow-up', 'arrow-down',
|
|
34
|
+
'arrow-left', 'arrow-right', 'arrow-up', 'arrow-down', 'sort',
|
|
35
35
|
],
|
|
36
36
|
},
|
|
37
37
|
{
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surfaces Story Component
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates the accent-surface contract for theme authors. The app uses
|
|
5
|
+
* `accent` as a quiet hover/selected/surface tint, but a theme is free to map
|
|
6
|
+
* `accent` to a bold colour (e.g. Madman's Box amber). These patterns stay
|
|
7
|
+
* legible either way, because they pair the accent background with the theme's
|
|
8
|
+
* own `accentForeground`, or use the quiet `muted` / faint-`primary` surfaces.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import React from 'react';
|
|
12
|
+
|
|
13
|
+
const sectionHeading: React.CSSProperties = {
|
|
14
|
+
fontSize: '1.125rem',
|
|
15
|
+
fontWeight: 700,
|
|
16
|
+
marginBottom: '1rem',
|
|
17
|
+
borderBottom: '1px solid var(--color-border)',
|
|
18
|
+
paddingBottom: '0.5rem',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const note: React.CSSProperties = {
|
|
22
|
+
color: 'var(--color-muted-foreground)',
|
|
23
|
+
marginBottom: '1rem',
|
|
24
|
+
fontSize: '0.875rem',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const Surfaces: React.FC = () => {
|
|
28
|
+
return (
|
|
29
|
+
<div style={{ padding: '1.5rem' }}>
|
|
30
|
+
<h2 style={{ fontSize: '1.5rem', fontWeight: 700, marginBottom: '0.5rem' }}>Surfaces</h2>
|
|
31
|
+
<p style={{ ...note, maxWidth: '44rem' }}>
|
|
32
|
+
How accent-coloured surfaces stay legible no matter how bold a theme makes
|
|
33
|
+
its <code>accent</code> token. Filled surfaces pair the background with{' '}
|
|
34
|
+
<code>qt-text-on-accent</code>; hover rows use <code>qt-hover-accent</code>;
|
|
35
|
+
quiet selected/panel surfaces lean on <code>muted</code> and faint{' '}
|
|
36
|
+
<code>primary</code> instead of the accent.
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
{/* Filled accent surfaces */}
|
|
40
|
+
<section style={{ marginBottom: '2rem' }}>
|
|
41
|
+
<h3 style={sectionHeading}>Filled accent surfaces</h3>
|
|
42
|
+
<p style={note}>
|
|
43
|
+
A solid <code>qt-bg-accent</code> fill <strong>must</strong> be paired with{' '}
|
|
44
|
+
<code>qt-text-on-accent</code> (the theme's <code>accentForeground</code>).
|
|
45
|
+
A fill without it falls back to the page foreground and washes out on bold accents.
|
|
46
|
+
</p>
|
|
47
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.75rem', alignItems: 'center' }}>
|
|
48
|
+
<span className="qt-bg-accent qt-text-on-accent" style={{ padding: '0.125rem 0.5rem', borderRadius: '0.25rem', fontSize: '0.75rem' }}>
|
|
49
|
+
keyword
|
|
50
|
+
</span>
|
|
51
|
+
<span className="qt-bg-accent qt-text-on-accent" style={{ padding: '0.125rem 0.5rem', borderRadius: '0.25rem', fontSize: '0.75rem' }}>
|
|
52
|
+
another keyword
|
|
53
|
+
</span>
|
|
54
|
+
<kbd className="qt-bg-accent qt-text-on-accent" style={{ padding: '0.125rem 0.375rem', borderRadius: '0.25rem', fontSize: '0.75rem' }}>
|
|
55
|
+
↵
|
|
56
|
+
</kbd>
|
|
57
|
+
</div>
|
|
58
|
+
</section>
|
|
59
|
+
|
|
60
|
+
{/* Hover-highlight rows */}
|
|
61
|
+
<section style={{ marginBottom: '2rem' }}>
|
|
62
|
+
<h3 style={sectionHeading}>Hover-highlight rows — <code>qt-hover-accent</code></h3>
|
|
63
|
+
<p style={note}>
|
|
64
|
+
For list rows, menu items, and option cards. On hover it paints the accent
|
|
65
|
+
background and forces the accent foreground onto the row <em>and every
|
|
66
|
+
descendant</em> — so children that carry their own colour (the title and the
|
|
67
|
+
muted subtitle below) flip too, instead of washing out (or, when their colour
|
|
68
|
+
matches the accent, vanishing). Hover the rows to see it.
|
|
69
|
+
</p>
|
|
70
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.25rem', maxWidth: '24rem', border: '1px solid var(--color-border)', borderRadius: '0.5rem', padding: '0.375rem' }}>
|
|
71
|
+
<div className="qt-hover-accent" style={{ display: 'flex', flexDirection: 'column', padding: '0.5rem 0.75rem', borderRadius: '0.375rem', cursor: 'pointer' }}>
|
|
72
|
+
<span className="qt-text-primary">Compose a reply</span>
|
|
73
|
+
<span className="qt-text-secondary" style={{ fontSize: '0.8125rem' }}>Draft a response in this thread</span>
|
|
74
|
+
</div>
|
|
75
|
+
<div className="qt-hover-accent" style={{ display: 'flex', flexDirection: 'column', padding: '0.5rem 0.75rem', borderRadius: '0.375rem', cursor: 'pointer' }}>
|
|
76
|
+
<span className="qt-text-primary">Mark as resolved</span>
|
|
77
|
+
<span className="qt-text-secondary" style={{ fontSize: '0.8125rem' }}>Close and archive this item</span>
|
|
78
|
+
</div>
|
|
79
|
+
<div className="qt-hover-accent" style={{ display: 'flex', flexDirection: 'column', padding: '0.5rem 0.75rem', borderRadius: '0.375rem', cursor: 'pointer' }}>
|
|
80
|
+
<span className="qt-text-primary">Delete</span>
|
|
81
|
+
<span className="qt-text-secondary" style={{ fontSize: '0.8125rem' }}>Remove permanently</span>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</section>
|
|
85
|
+
|
|
86
|
+
{/* Quiet selected / panel surfaces */}
|
|
87
|
+
<section>
|
|
88
|
+
<h3 style={sectionHeading}>Quiet selected & panel surfaces</h3>
|
|
89
|
+
<p style={note}>
|
|
90
|
+
Persistent surfaces (selected cards, informational panels) deliberately avoid
|
|
91
|
+
the bold accent. Selected states use a faint <code>qt-bg-primary/10</code> tint;
|
|
92
|
+
informational panels use the neutral <code>qt-bg-muted</code> surface.
|
|
93
|
+
</p>
|
|
94
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '1rem' }}>
|
|
95
|
+
<div className="qt-bg-primary/10" style={{ padding: '0.75rem 1rem', borderRadius: '0.5rem', border: '1px solid var(--color-primary)', maxWidth: '16rem' }}>
|
|
96
|
+
<div className="qt-text-primary" style={{ fontWeight: 600 }}>Selected option</div>
|
|
97
|
+
<div className="qt-text-secondary" style={{ fontSize: '0.8125rem' }}>Faint primary tint marks the choice.</div>
|
|
98
|
+
</div>
|
|
99
|
+
<div className="qt-bg-muted" style={{ padding: '0.75rem 1rem', borderRadius: '0.5rem', border: '1px solid var(--color-border)', maxWidth: '16rem' }}>
|
|
100
|
+
<div style={{ fontWeight: 600 }}>Informational panel</div>
|
|
101
|
+
<div className="qt-text-secondary" style={{ fontSize: '0.8125rem' }}>Neutral muted surface, never the accent.</div>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</section>
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
};
|
package/src/stories/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ export * from './components/Buttons';
|
|
|
14
14
|
export * from './components/Cards';
|
|
15
15
|
export * from './components/Inputs';
|
|
16
16
|
export * from './components/Badges';
|
|
17
|
+
export * from './components/Surfaces';
|
|
17
18
|
export * from './components/Avatars';
|
|
18
19
|
export * from './components/Dialogs';
|
|
19
20
|
export * from './components/Tabs';
|