@quilltap/theme-storybook 1.0.21 → 1.0.23

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.
@@ -8,13 +8,16 @@ import {
8
8
  ColorPalette,
9
9
  ColorSwatch,
10
10
  Dialogs,
11
+ EmptyState,
11
12
  FilePreview,
12
13
  Inputs,
14
+ Loading,
15
+ Participant,
13
16
  Spacing,
14
17
  Tabs,
15
18
  ThemeComparison,
16
19
  Typography
17
- } from "../chunk-W3J7BRAL.mjs";
20
+ } from "../chunk-45RKCZL3.mjs";
18
21
  import "../chunk-WUKYLWAZ.mjs";
19
22
  export {
20
23
  Avatars,
@@ -26,8 +29,11 @@ export {
26
29
  ColorPalette,
27
30
  ColorSwatch,
28
31
  Dialogs,
32
+ EmptyState,
29
33
  FilePreview,
30
34
  Inputs,
35
+ Loading,
36
+ Participant,
31
37
  Spacing,
32
38
  Tabs,
33
39
  ThemeComparison,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quilltap/theme-storybook",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
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.1.11",
46
+ "@storybook/react": "^10.2.17",
47
47
  "@types/react": "^18.2.0",
48
48
  "react": "^19.0.0",
49
- "storybook": "^10.1.11",
49
+ "storybook": "^10.2.17",
50
50
  "tsup": "^8.0.0",
51
51
  "typescript": "^5.3.0"
52
52
  },
@@ -173,6 +173,8 @@
173
173
  --qt-badge-tag-fg: hsl(25 95% 40%);
174
174
  --qt-badge-memory-bg: hsl(330 80% 60% / 0.15);
175
175
  --qt-badge-memory-fg: hsl(330 80% 40%);
176
+ --qt-badge-message-bg: hsl(45 70% 48% / 0.12);
177
+ --qt-badge-message-fg: hsl(45 70% 35%);
176
178
  --qt-badge-project-bg: hsl(185 80% 40% / 0.15);
177
179
  --qt-badge-project-fg: hsl(185 80% 30%);
178
180
 
@@ -869,6 +871,77 @@
869
871
  max-width: min(var(--qt-page-max-width, 75rem), calc(100vw - 2rem));
870
872
  }
871
873
 
874
+ /* ==========================================================================
875
+ SLIDE-OVER PANELS
876
+ ========================================================================== */
877
+
878
+ .qt-slide-over-overlay {
879
+ position: fixed;
880
+ inset: 0;
881
+ z-index: 55;
882
+ background-color: var(--qt-dialog-backdrop);
883
+ opacity: 0;
884
+ transition: opacity 200ms ease;
885
+ pointer-events: none;
886
+ }
887
+
888
+ .qt-slide-over-overlay[data-open="true"] {
889
+ opacity: 1;
890
+ pointer-events: auto;
891
+ }
892
+
893
+ .qt-slide-over-panel {
894
+ position: fixed;
895
+ right: 0;
896
+ top: 0;
897
+ z-index: 55;
898
+ height: 100%;
899
+ display: flex;
900
+ flex-direction: column;
901
+ background-color: var(--qt-dialog-bg);
902
+ border-left: 1px solid var(--qt-dialog-border);
903
+ box-shadow: var(--qt-dialog-shadow);
904
+ transform: translateX(100%);
905
+ transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1);
906
+ }
907
+
908
+ .qt-slide-over-panel[data-open="true"] {
909
+ transform: translateX(0);
910
+ }
911
+
912
+ .qt-slide-over-header {
913
+ display: flex;
914
+ align-items: center;
915
+ justify-content: space-between;
916
+ padding: 0.75rem 1rem;
917
+ flex-shrink: 0;
918
+ border-bottom: 1px solid var(--qt-dialog-border);
919
+ }
920
+
921
+ .qt-inspector-entry {
922
+ transition: all 150ms ease;
923
+ border-radius: var(--qt-card-radius);
924
+ background: var(--qt-card-bg);
925
+ border: 1px solid color-mix(in srgb, var(--qt-card-border) calc(var(--qt-card-border-opacity, 1) * 100%), transparent);
926
+ }
927
+
928
+ .qt-inspector-entry:hover {
929
+ border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
930
+ }
931
+
932
+ .qt-inspector-entry-highlight {
933
+ animation: qt-inspector-highlight 2s ease-out;
934
+ }
935
+
936
+ @keyframes qt-inspector-highlight {
937
+ 0% {
938
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary) 60%, transparent);
939
+ }
940
+ 100% {
941
+ box-shadow: 0 0 0 0px transparent;
942
+ }
943
+ }
944
+
872
945
  /* ==========================================================================
873
946
  TAB COMPONENTS
874
947
  ========================================================================== */
@@ -1712,6 +1785,8 @@
1712
1785
  --qt-badge-tag-fg: hsl(25 95% 65%);
1713
1786
  --qt-badge-memory-bg: hsl(330 80% 60% / 0.3);
1714
1787
  --qt-badge-memory-fg: hsl(330 80% 70%);
1788
+ --qt-badge-message-bg: hsl(45 70% 50% / 0.25);
1789
+ --qt-badge-message-fg: hsl(45 70% 68%);
1715
1790
  --qt-badge-project-bg: hsl(185 80% 40% / 0.3);
1716
1791
  --qt-badge-project-fg: hsl(185 80% 70%);
1717
1792
 
@@ -83,6 +83,96 @@ export const Badges: React.FC = () => {
83
83
  </div>
84
84
  </section>
85
85
 
86
+ {/* Entity Type Badges */}
87
+ <section style={{ marginBottom: '2rem' }}>
88
+ <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
89
+ Entity Type Badges
90
+ </h3>
91
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.75rem', alignItems: 'center' }}>
92
+ <span className="qt-badge qt-badge-character">Character</span>
93
+ <span className="qt-badge qt-badge-persona">Persona</span>
94
+ <span className="qt-badge qt-badge-chat">Chat</span>
95
+ <span className="qt-badge qt-badge-tag">Tag</span>
96
+ <span className="qt-badge qt-badge-memory">Memory</span>
97
+ </div>
98
+ </section>
99
+
100
+ {/* State Badges */}
101
+ <section style={{ marginBottom: '2rem' }}>
102
+ <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
103
+ State Badges
104
+ </h3>
105
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.75rem', alignItems: 'center' }}>
106
+ <span className="qt-badge qt-badge-enabled">Enabled</span>
107
+ <span className="qt-badge qt-badge-disabled">Disabled</span>
108
+ <span className="qt-badge qt-badge-related">Related</span>
109
+ <span className="qt-badge qt-badge-manual">Manual</span>
110
+ <span className="qt-badge qt-badge-auto">Auto</span>
111
+ </div>
112
+ </section>
113
+
114
+ {/* Plugin Source Badges */}
115
+ <section style={{ marginBottom: '2rem' }}>
116
+ <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
117
+ Plugin Source Badges
118
+ </h3>
119
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.75rem', alignItems: 'center' }}>
120
+ <span className="qt-badge qt-badge-source-included">Included</span>
121
+ <span className="qt-badge qt-badge-source-npm">NPM</span>
122
+ <span className="qt-badge qt-badge-source-git">Git</span>
123
+ <span className="qt-badge qt-badge-source-manual">Manual</span>
124
+ </div>
125
+ </section>
126
+
127
+ {/* Tag Badges */}
128
+ <section style={{ marginBottom: '2rem' }}>
129
+ <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
130
+ Tag Badges
131
+ </h3>
132
+ <div style={{ marginBottom: '1.5rem' }}>
133
+ <p style={{ color: 'var(--color-muted-foreground)', marginBottom: '0.75rem', fontSize: '0.875rem' }}>
134
+ Basic tags
135
+ </p>
136
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.75rem', alignItems: 'center' }}>
137
+ <span className="qt-tag-badge">Fantasy</span>
138
+ <span className="qt-tag-badge">Sci-Fi</span>
139
+ <span className="qt-tag-badge">Romance</span>
140
+ </div>
141
+ </div>
142
+ <div style={{ marginBottom: '1.5rem' }}>
143
+ <p style={{ color: 'var(--color-muted-foreground)', marginBottom: '0.75rem', fontSize: '0.875rem' }}>
144
+ Emoji tag
145
+ </p>
146
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.75rem', alignItems: 'center' }}>
147
+ <span className="qt-tag-badge qt-tag-badge-emoji">Adventure</span>
148
+ </div>
149
+ </div>
150
+ <div style={{ marginBottom: '1.5rem' }}>
151
+ <p style={{ color: 'var(--color-muted-foreground)', marginBottom: '0.75rem', fontSize: '0.875rem' }}>
152
+ Removable tag
153
+ </p>
154
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.75rem', alignItems: 'center' }}>
155
+ <span className="qt-tag-badge">
156
+ Fantasy
157
+ <button className="qt-tag-badge-remove">×</button>
158
+ </span>
159
+ </div>
160
+ </div>
161
+ <div>
162
+ <p style={{ color: 'var(--color-muted-foreground)', marginBottom: '0.75rem', fontSize: '0.875rem' }}>
163
+ Small tags in card context
164
+ </p>
165
+ <div className="qt-card" style={{ maxWidth: '24rem' }}>
166
+ <div className="qt-card-body">
167
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}>
168
+ <span className="qt-tag-badge qt-tag-badge-sm">Fantasy</span>
169
+ <span className="qt-tag-badge qt-tag-badge-sm">Sci-Fi</span>
170
+ </div>
171
+ </div>
172
+ </div>
173
+ </div>
174
+ </section>
175
+
86
176
  {/* Badge Usage Examples */}
87
177
  <section>
88
178
  <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
@@ -72,6 +72,27 @@ export const Cards: React.FC = () => {
72
72
  </div>
73
73
  </section>
74
74
 
75
+ {/* Card Grid */}
76
+ <section style={{ marginBottom: '2rem' }}>
77
+ <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
78
+ Card Grid
79
+ </h3>
80
+ <div className="qt-card-grid-3">
81
+ <div className="qt-card" style={{ padding: '1rem' }}>
82
+ <h4 style={{ fontWeight: 600, marginBottom: '0.5rem' }}>Card 1</h4>
83
+ <p style={{ fontSize: '0.875rem', color: 'var(--color-muted-foreground)' }}>Grid card content</p>
84
+ </div>
85
+ <div className="qt-card" style={{ padding: '1rem' }}>
86
+ <h4 style={{ fontWeight: 600, marginBottom: '0.5rem' }}>Card 2</h4>
87
+ <p style={{ fontSize: '0.875rem', color: 'var(--color-muted-foreground)' }}>Grid card content</p>
88
+ </div>
89
+ <div className="qt-card" style={{ padding: '1rem' }}>
90
+ <h4 style={{ fontWeight: 600, marginBottom: '0.5rem' }}>Card 3</h4>
91
+ <p style={{ fontSize: '0.875rem', color: 'var(--color-muted-foreground)' }}>Grid card content</p>
92
+ </div>
93
+ </div>
94
+ </section>
95
+
75
96
  {/* Panels */}
76
97
  <section style={{ marginBottom: '2rem' }}>
77
98
  <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
@@ -21,7 +21,13 @@ export const Chat: React.FC = () => {
21
21
  {/* User Message */}
22
22
  <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
23
23
  <div className="qt-chat-message qt-chat-message-user">
24
- <p>Hello! How are you today?</p>
24
+ <div className="qt-chat-message-header">
25
+ <span className="qt-chat-message-author">You</span>
26
+ <span className="qt-chat-message-time">2:30 PM</span>
27
+ </div>
28
+ <div className="qt-chat-message-content">
29
+ <p>Hello! How are you today?</p>
30
+ </div>
25
31
  </div>
26
32
  </div>
27
33
 
@@ -31,7 +37,13 @@ export const Chat: React.FC = () => {
31
37
  <div className="qt-avatar-fallback">AI</div>
32
38
  </div>
33
39
  <div className="qt-chat-message qt-chat-message-assistant">
34
- <p>Hello! I&apos;m doing well, thank you for asking. How can I help you today?</p>
40
+ <div className="qt-chat-message-header">
41
+ <span className="qt-chat-message-author">Assistant</span>
42
+ <span className="qt-chat-message-time">2:30 PM</span>
43
+ </div>
44
+ <div className="qt-chat-message-content">
45
+ <p>Hello! I&apos;m doing well, thank you for asking. How can I help you today?</p>
46
+ </div>
35
47
  </div>
36
48
  </div>
37
49
 
@@ -41,20 +53,50 @@ export const Chat: React.FC = () => {
41
53
  <div className="qt-avatar-fallback">AI</div>
42
54
  </div>
43
55
  <div className="qt-chat-message qt-chat-message-assistant">
44
- <p>Here&apos;s some information you might find helpful:</p>
45
- <ul style={{ marginTop: '0.5rem', paddingLeft: '1.25rem' }}>
46
- <li>First point of interest</li>
47
- <li>Second important detail</li>
48
- <li>Third relevant fact</li>
49
- </ul>
50
- <p style={{ marginTop: '0.5rem' }}>Let me know if you&apos;d like more details about any of these!</p>
56
+ <div className="qt-chat-message-header">
57
+ <span className="qt-chat-message-author">Assistant</span>
58
+ <span className="qt-chat-message-time">2:31 PM</span>
59
+ </div>
60
+ <div className="qt-chat-message-content">
61
+ <p>Here&apos;s some information you might find helpful:</p>
62
+ <ul style={{ marginTop: '0.5rem', paddingLeft: '1.25rem' }}>
63
+ <li>First point of interest</li>
64
+ <li>Second important detail</li>
65
+ <li>Third relevant fact</li>
66
+ </ul>
67
+ <p style={{ marginTop: '0.5rem' }}>Let me know if you&apos;d like more details about any of these!</p>
68
+ </div>
69
+ <div className="qt-chat-message-actions">
70
+ <button className="qt-button-icon" title="Edit">
71
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
72
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
73
+ </svg>
74
+ </button>
75
+ <button className="qt-button-icon" title="Copy">
76
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
77
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
78
+ </svg>
79
+ </button>
80
+ </div>
81
+ </div>
82
+ </div>
83
+
84
+ {/* System Message */}
85
+ <div className="qt-chat-message qt-chat-message-system">
86
+ <div className="qt-chat-message-content">
87
+ <p>Alice has joined the conversation.</p>
51
88
  </div>
52
89
  </div>
53
90
 
54
91
  {/* User Message */}
55
92
  <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
56
93
  <div className="qt-chat-message qt-chat-message-user">
57
- <p>That&apos;s exactly what I needed, thanks!</p>
94
+ <div className="qt-chat-message-header">
95
+ <span className="qt-chat-message-author">You</span>
96
+ </div>
97
+ <div className="qt-chat-message-content">
98
+ <p>That&apos;s exactly what I needed, thanks!</p>
99
+ </div>
58
100
  </div>
59
101
  </div>
60
102
  </div>
@@ -95,6 +137,189 @@ export const Chat: React.FC = () => {
95
137
  </div>
96
138
  </section>
97
139
 
140
+ {/* Roleplay Annotations */}
141
+ <section style={{ marginBottom: '2rem' }}>
142
+ <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
143
+ Roleplay Annotations
144
+ </h3>
145
+ <p style={{ color: 'var(--color-muted-foreground)', marginBottom: '1rem' }}>
146
+ Special text formatting for roleplay-style messages with narration, inner thoughts, and out-of-character text.
147
+ </p>
148
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem', maxWidth: '32rem' }}>
149
+ {/* Narration */}
150
+ <div style={{ display: 'flex', gap: '0.5rem' }}>
151
+ <div className="qt-avatar qt-avatar-sm">
152
+ <div className="qt-avatar-fallback">A</div>
153
+ </div>
154
+ <div className="qt-chat-message qt-chat-message-assistant">
155
+ <div className="qt-chat-message-header">
156
+ <span className="qt-chat-message-author">Alice</span>
157
+ </div>
158
+ <div className="qt-chat-message-content">
159
+ <p>&quot;Hello there!&quot; <span className="qt-chat-narration">she said with a warm smile, stepping forward to greet you.</span></p>
160
+ </div>
161
+ </div>
162
+ </div>
163
+
164
+ {/* Inner Monologue */}
165
+ <div style={{ display: 'flex', gap: '0.5rem' }}>
166
+ <div className="qt-avatar qt-avatar-sm">
167
+ <div className="qt-avatar-fallback">A</div>
168
+ </div>
169
+ <div className="qt-chat-message qt-chat-message-assistant">
170
+ <div className="qt-chat-message-header">
171
+ <span className="qt-chat-message-author">Alice</span>
172
+ </div>
173
+ <div className="qt-chat-message-content">
174
+ <p><span className="qt-chat-narration">She paused for a moment, considering her words carefully.</span> <span className="qt-chat-inner-monologue">I wonder if they noticed...</span></p>
175
+ </div>
176
+ </div>
177
+ </div>
178
+
179
+ {/* Out of Character */}
180
+ <div style={{ display: 'flex', gap: '0.5rem' }}>
181
+ <div className="qt-avatar qt-avatar-sm">
182
+ <div className="qt-avatar-fallback">A</div>
183
+ </div>
184
+ <div className="qt-chat-message qt-chat-message-assistant">
185
+ <div className="qt-chat-message-header">
186
+ <span className="qt-chat-message-author">Alice</span>
187
+ </div>
188
+ <div className="qt-chat-message-content">
189
+ <p><span className="qt-chat-ooc">((OOC: Should we continue the scene or take a break?))</span></p>
190
+ </div>
191
+ </div>
192
+ </div>
193
+ </div>
194
+ </section>
195
+
196
+ {/* Whisper Messages */}
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
+ Whisper Messages
200
+ </h3>
201
+ <p style={{ color: 'var(--color-muted-foreground)', marginBottom: '1rem' }}>
202
+ Private messages visible only to sender and recipient. Overheard whispers have a faded style.
203
+ </p>
204
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem', maxWidth: '32rem' }}>
205
+ {/* Regular whisper */}
206
+ <div className="qt-chat-message-row qt-chat-message-row-assistant" style={{ marginBottom: '0.5rem' }}>
207
+ <div className="qt-chat-message-body qt-chat-message-assistant qt-chat-message-whisper">
208
+ <div className="qt-chat-whisper-label">whispered to Elena</div>
209
+ <p>I don&apos;t trust the merchant. Meet me at the tavern tonight—alone.</p>
210
+ </div>
211
+ </div>
212
+
213
+ {/* Overheard whisper */}
214
+ <div className="qt-chat-message-row qt-chat-message-row-assistant" style={{ marginBottom: '0.5rem' }}>
215
+ <div className="qt-chat-message-body qt-chat-message-assistant qt-chat-message-whisper qt-chat-message-whisper-overheard">
216
+ <div className="qt-chat-whisper-label">whispered to Marcus</div>
217
+ <p>Keep an eye on the door. We may need a quick exit.</p>
218
+ </div>
219
+ </div>
220
+ </div>
221
+ </section>
222
+
223
+ {/* Chat Toolbar */}
224
+ <section style={{ marginBottom: '2rem' }}>
225
+ <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
226
+ Chat Toolbar
227
+ </h3>
228
+ <p style={{ color: 'var(--color-muted-foreground)', marginBottom: '1rem' }}>
229
+ Formatting and action buttons for chat composition.
230
+ </p>
231
+ <div className="qt-chat-toolbar" style={{ maxWidth: '32rem', display: 'flex', gap: '0.5rem', flexWrap: 'wrap' }}>
232
+ <button className="qt-chat-toolbar-button" title="Bold">
233
+ <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
234
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 4h8a4 4 0 014 4v2M6 4v16M6 4h8a2 2 0 012 2v2M6 12h12" />
235
+ </svg>
236
+ </button>
237
+ <button className="qt-chat-toolbar-button" title="Italic">
238
+ <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
239
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 5h4m-4 14h4M9 5h6M9 19H3" />
240
+ </svg>
241
+ </button>
242
+ <button className="qt-chat-toolbar-button" title="Underline">
243
+ <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
244
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 5v10a4 4 0 008 0V5m0 14H7" />
245
+ </svg>
246
+ </button>
247
+ <div style={{ flex: 1 }} />
248
+ <button className="qt-chat-toolbar-button" title="Settings">
249
+ <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
250
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
251
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
252
+ </svg>
253
+ </button>
254
+ </div>
255
+ </section>
256
+
257
+ {/* RP Annotation Buttons */}
258
+ <section style={{ marginBottom: '2rem' }}>
259
+ <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
260
+ RP Annotation Buttons
261
+ </h3>
262
+ <p style={{ color: 'var(--color-muted-foreground)', marginBottom: '1rem' }}>
263
+ Quick-insert buttons for roleplay annotation types.
264
+ </p>
265
+ <div className="qt-rp-annotation-toolbar" style={{ maxWidth: '32rem', display: 'flex', gap: '0.5rem', flexWrap: 'wrap' }}>
266
+ <button className="qt-rp-annotation-button-narration" title="Narration">
267
+ <svg className="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
268
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h7" />
269
+ </svg>
270
+ Narration
271
+ </button>
272
+ <button className="qt-rp-annotation-button-internal" title="Inner Monologue">
273
+ <svg className="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
274
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
275
+ </svg>
276
+ Internal
277
+ </button>
278
+ <button className="qt-rp-annotation-button-ooc" title="Out of Character">
279
+ <svg className="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
280
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
281
+ </svg>
282
+ OOC
283
+ </button>
284
+ </div>
285
+ </section>
286
+
287
+ {/* Attachments */}
288
+ <section style={{ marginBottom: '2rem' }}>
289
+ <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
290
+ Attachments
291
+ </h3>
292
+ <p style={{ color: 'var(--color-muted-foreground)', marginBottom: '1rem' }}>
293
+ File attachment chips and attachment button.
294
+ </p>
295
+ <div className="qt-chat-composer" style={{ maxWidth: '32rem' }}>
296
+ <div className="qt-chat-attachment-list" style={{ display: 'flex', gap: '0.5rem', marginBottom: '0.75rem', flexWrap: 'wrap' }}>
297
+ <div className="qt-chat-attachment-chip">
298
+ <span>document.pdf</span>
299
+ <button className="ml-2 text-gray-400 hover:text-gray-600" style={{ marginLeft: '0.5rem' }}>×</button>
300
+ </div>
301
+ <div className="qt-chat-attachment-chip">
302
+ <span>image.png</span>
303
+ <button className="ml-2 text-gray-400 hover:text-gray-600" style={{ marginLeft: '0.5rem' }}>×</button>
304
+ </div>
305
+ </div>
306
+ <textarea
307
+ className="qt-chat-composer-input"
308
+ placeholder="Add a message about your files..."
309
+ rows={1}
310
+ style={{ width: '100%', padding: '0.5rem', marginBottom: '0.5rem' }}
311
+ />
312
+ <div className="qt-chat-composer-actions" style={{ display: 'flex', gap: '0.5rem' }}>
313
+ <button className="qt-chat-attachment-button">
314
+ <svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
315
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
316
+ </svg>
317
+ </button>
318
+ <button className="qt-button qt-button-primary">Send</button>
319
+ </div>
320
+ </div>
321
+ </section>
322
+
98
323
  {/* Chat Input */}
99
324
  <section style={{ marginBottom: '2rem' }}>
100
325
  <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
@@ -112,7 +337,7 @@ export const Chat: React.FC = () => {
112
337
  placeholder="Type a message..."
113
338
  rows={1}
114
339
  />
115
- <button className="qt-button qt-button-primary qt-button-sm">
340
+ <button className="qt-button qt-button-primary qt-chat-composer-send" style={{ height: 'auto', padding: '0.5rem 1rem' }}>
116
341
  <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
117
342
  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
118
343
  </svg>
@@ -140,6 +365,32 @@ export const Chat: React.FC = () => {
140
365
  </div>
141
366
  </section>
142
367
 
368
+ {/* Chat Control Buttons */}
369
+ <section style={{ marginBottom: '2rem' }}>
370
+ <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
371
+ Chat Control Buttons
372
+ </h3>
373
+ <p style={{ color: 'var(--color-muted-foreground)', marginBottom: '1rem' }}>
374
+ Continue and stop buttons for controlling AI response generation.
375
+ </p>
376
+ <div style={{ display: 'flex', gap: '1rem', maxWidth: '32rem' }}>
377
+ <button className="qt-chat-continue-button">
378
+ <svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
379
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" />
380
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
381
+ </svg>
382
+ Continue
383
+ </button>
384
+ <button className="qt-chat-stop-button">
385
+ <svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
386
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
387
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 10a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 01-1-1v-4z" />
388
+ </svg>
389
+ Stop
390
+ </button>
391
+ </div>
392
+ </section>
393
+
143
394
  {/* Full Chat Layout Preview */}
144
395
  <section>
145
396
  <h3 style={{ fontSize: '1.125rem', fontWeight: 700, marginBottom: '1rem', borderBottom: '1px solid var(--color-border)', paddingBottom: '0.5rem' }}>
@@ -87,6 +87,15 @@ export const ColorPalette: React.FC = () => {
87
87
  { name: 'Chat User Foreground', variable: '--color-chat-user-foreground', description: 'User message text' },
88
88
  ];
89
89
 
90
+ const componentTokens: ColorSwatchProps[] = [
91
+ { name: 'Button Primary BG', variable: '--qt-button-primary-bg', description: 'Primary button background' },
92
+ { name: 'Button Primary Hover', variable: '--qt-button-primary-hover-bg', description: 'Primary button hover' },
93
+ { name: 'Card BG', variable: '--qt-card-bg', description: 'Card background' },
94
+ { name: 'Card Border', variable: '--qt-card-border', description: 'Card border' },
95
+ { name: 'Input BG', variable: '--qt-input-bg', description: 'Input background' },
96
+ { name: 'Input Border', variable: '--qt-input-border', description: 'Input border' },
97
+ ];
98
+
90
99
  return (
91
100
  <div style={{ padding: '1.5rem' }}>
92
101
  <h2 style={{ fontSize: '1.5rem', fontWeight: 700, marginBottom: '1.5rem' }}>Color Palette</h2>
@@ -98,6 +107,7 @@ export const ColorPalette: React.FC = () => {
98
107
  <ColorGroup title="Semantic Colors" colors={semanticColors} />
99
108
  <ColorGroup title="Status Colors" colors={statusColors} />
100
109
  <ColorGroup title="Chat Colors" colors={chatColors} />
110
+ <ColorGroup title="Component Tokens" colors={componentTokens} />
101
111
  </div>
102
112
  );
103
113
  };