@heyramzi/ui 3.5.0 → 3.6.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.
Files changed (39) hide show
  1. package/COMPONENTS.md +1 -0
  2. package/dist/ai/chat-window/icons.js +43 -0
  3. package/dist/ai/chat-window/index.js +5 -0
  4. package/dist/ai/chat-window/labels.js +16 -0
  5. package/dist/ai/chat-window/reveal.svelte.js +106 -0
  6. package/dist/ai/chat-window/types.js +4 -0
  7. package/package.json +1 -1
  8. package/src/ai/chat-window/ChatGlyph.svelte +38 -0
  9. package/src/ai/chat-window/ChatGlyph.svelte.d.ts +9 -0
  10. package/src/ai/chat-window/ChatGptWindow.svelte +636 -0
  11. package/src/ai/chat-window/ChatGptWindow.svelte.d.ts +25 -0
  12. package/src/ai/chat-window/ClaudeWindow.svelte +668 -0
  13. package/src/ai/chat-window/ClaudeWindow.svelte.d.ts +25 -0
  14. package/src/ai/chat-window/chat-window.test.ts +80 -0
  15. package/src/ai/chat-window/icons/LICENSE +24 -0
  16. package/src/ai/chat-window/icons/chatgpt-chevron.svg +2 -0
  17. package/src/ai/chat-window/icons/chatgpt-copy.svg +2 -0
  18. package/src/ai/chat-window/icons/chatgpt-mic.svg +2 -0
  19. package/src/ai/chat-window/icons/chatgpt-more.svg +2 -0
  20. package/src/ai/chat-window/icons/chatgpt-plus.svg +2 -0
  21. package/src/ai/chat-window/icons/chatgpt-regenerate.svg +2 -0
  22. package/src/ai/chat-window/icons/chatgpt-share.svg +2 -0
  23. package/src/ai/chat-window/icons/chatgpt-sidebar.svg +1 -0
  24. package/src/ai/chat-window/icons/chatgpt-thumb.svg +2 -0
  25. package/src/ai/chat-window/icons/chatgpt-voice.svg +2 -0
  26. package/src/ai/chat-window/icons/claude-chevron.svg +1 -0
  27. package/src/ai/chat-window/icons/claude-copy.svg +1 -0
  28. package/src/ai/chat-window/icons/claude-plus.svg +1 -0
  29. package/src/ai/chat-window/icons/claude-retry.svg +1 -0
  30. package/src/ai/chat-window/icons/claude-send.svg +1 -0
  31. package/src/ai/chat-window/icons/claude-sidebar.svg +1 -0
  32. package/src/ai/chat-window/icons/claude-sliders.svg +1 -0
  33. package/src/ai/chat-window/icons/claude-spark.svg +1 -0
  34. package/src/ai/chat-window/icons/claude-thumb.svg +1 -0
  35. package/src/ai/chat-window/icons.ts +46 -0
  36. package/src/ai/chat-window/index.ts +26 -0
  37. package/src/ai/chat-window/labels.ts +39 -0
  38. package/src/ai/chat-window/reveal.svelte.ts +106 -0
  39. package/src/ai/chat-window/types.ts +42 -0
@@ -0,0 +1,668 @@
1
+ <script lang="ts" module>
2
+ import type { ClaudeLabels } from "./labels.js";
3
+ import type { ChatMessage, ChatTheme } from "./types.js";
4
+
5
+ export interface ClaudeWindowProps {
6
+ /** The conversation's name, shown in the bar and read out as the picture's label. */
7
+ title: string;
8
+ messages: ChatMessage[];
9
+ /** The model picker in the composer. */
10
+ model?: string;
11
+ placeholder?: string;
12
+ theme?: ChatTheme;
13
+ /** Plays the messages in once the window is on screen. Off, it is a still. */
14
+ reveal?: boolean;
15
+ /** With `reveal`, plays each time this turns on, for a rotator. */
16
+ active?: boolean;
17
+ /** Called after the reveal ends and `hold` ms have passed. */
18
+ ondone?: () => void;
19
+ hold?: number;
20
+ /** Draws macOS's traffic lights, as the desktop app. */
21
+ frame?: boolean;
22
+ labels?: Partial<ClaudeLabels>;
23
+ class?: string;
24
+ }
25
+ </script>
26
+
27
+ <script lang="ts">
28
+ // =========================
29
+ // IMPORTS
30
+ // =========================
31
+ import ChatGlyph from "./ChatGlyph.svelte";
32
+ import { CLAUDE_ICONS as I } from "./icons.js";
33
+ import { CLAUDE_LABELS } from "./labels.js";
34
+ import { createReveal } from "./reveal.svelte.js";
35
+ import { fillName } from "./types.js";
36
+
37
+ // =========================
38
+ // PROPS
39
+ // =========================
40
+ let {
41
+ title,
42
+ messages,
43
+ model = "Opus 5.5",
44
+ placeholder = "Reply to Claude…",
45
+ theme = "auto",
46
+ reveal = false,
47
+ active = true,
48
+ ondone,
49
+ hold = 4000,
50
+ frame = true,
51
+ labels = {},
52
+ class: className = "",
53
+ }: ClaudeWindowProps = $props();
54
+
55
+ // =========================
56
+ // STATE
57
+ // =========================
58
+ const text = $derived({ ...CLAUDE_LABELS, ...labels });
59
+ const lastAssistant = $derived(messages.findLastIndex((m) => m.role === "assistant"));
60
+ const player = createReveal(() => ({
61
+ roles: messages.map((m) => m.role),
62
+ enabled: reveal,
63
+ active,
64
+ hold,
65
+ ondone,
66
+ }));
67
+ </script>
68
+
69
+ <!-- =========================== -->
70
+ <!-- MARKUP -->
71
+ <!-- =========================== -->
72
+ <figure
73
+ class="claude {className}"
74
+ data-mode={theme}
75
+ aria-label="Claude: {title}"
76
+ style:--claude-stream="{player.streamMs}ms"
77
+ {@attach player.attach}
78
+ >
79
+ <div class="bar" aria-hidden="true">
80
+ {#if frame}
81
+ <span class="lights"><i></i><i></i><i></i></span>
82
+ {/if}
83
+ <span class="ib"><ChatGlyph src={I.sidebar} size={18} /></span>
84
+ <span class="title">{title}<ChatGlyph src={I.chevron} size={14} /></span>
85
+ <span class="share">{text.share}</span>
86
+ </div>
87
+
88
+ <ol class="thread">
89
+ {#each messages as message, i (i)}
90
+ {@const phase = player.phase(i)}
91
+ <li class="turn {message.role}" data-phase={phase}>
92
+ {#if message.role === "user"}
93
+ <span class="vh">{text.userSaid}</span>
94
+ <p class="bubble">{message.text}</p>
95
+ {:else if message.role === "assistant"}
96
+ <span class="think" aria-hidden="true"><ChatGlyph src={I.spark} size={22} /></span>
97
+ <div class="reply">
98
+ <span class="vh">{text.assistantSaid}</span>
99
+ {#if message.content}
100
+ {@render message.content()}
101
+ {:else if message.text}
102
+ <p>{message.text}</p>
103
+ {/if}
104
+ </div>
105
+ {#if i === lastAssistant}
106
+ <div class="foot" aria-hidden="true">
107
+ <span class="spark"><ChatGlyph src={I.spark} size={24} /></span>
108
+ <span class="note">{text.disclaimer}</span>
109
+ <span class="actions">
110
+ <span class="ab"><ChatGlyph src={I.copy} size={18} /></span>
111
+ <span class="ab"><ChatGlyph src={I.thumb} size={18} /></span>
112
+ <span class="ab flip"><ChatGlyph src={I.thumb} size={18} /></span>
113
+ <span class="ab"><ChatGlyph src={I.retry} size={18} /></span>
114
+ </span>
115
+ </div>
116
+ {/if}
117
+ {:else}
118
+ <!-- A connector call, collapsed, as claude.ai draws it inside a reply: its text shimmers while it runs. -->
119
+ <p class="call">
120
+ <span class="call-icon" aria-hidden="true">
121
+ {#if message.icon}
122
+ {@render message.icon()}
123
+ {:else if message.iconSrc}
124
+ <img src={message.iconSrc} alt="" width="16" height="16" />
125
+ {:else}
126
+ <span class="call-letter">{message.name.slice(0, 1)}</span>
127
+ {/if}
128
+ </span>
129
+ <span class="call-text">
130
+ {fillName(phase === "running" ? text.running : text.done, message.name)}
131
+ </span>
132
+ {#if message.label}
133
+ <span class="call-name">{message.label}</span>
134
+ {/if}
135
+ <span class="call-chev" aria-hidden="true"><ChatGlyph src={I.chevron} size={14} /></span
136
+ >
137
+ </p>
138
+ {/if}
139
+ </li>
140
+ {/each}
141
+ </ol>
142
+
143
+ <div class="composer" aria-hidden="true">
144
+ <span class="prompt">{placeholder}</span>
145
+ <div class="tools">
146
+ <span class="cb"><ChatGlyph src={I.plus} size={18} /></span>
147
+ <span class="cb wide"><ChatGlyph src={I.sliders} size={18} /></span>
148
+ <span class="model">{model}<ChatGlyph src={I.chevron} size={14} /></span>
149
+ <span class="send"><ChatGlyph src={I.send} size={18} /></span>
150
+ </div>
151
+ </div>
152
+ </figure>
153
+
154
+ <style>
155
+ @layer theme, base, components, utilities;
156
+
157
+ @layer components {
158
+ /* claude.ai's tokens: warm paper light, warm charcoal dark, the clay accent on send and the spark. */
159
+ .claude {
160
+ --c-bg: light-dark(#faf9f5, #262624);
161
+ --c-bubble: light-dark(#f0eee6, #141413);
162
+ --c-composer: light-dark(#ffffff, #30302e);
163
+ --c-ink: light-dark(#141413, #faf9f5);
164
+ --c-reply: light-dark(#141413, #f0eee6);
165
+ --c-soft: light-dark(#3d3d3a, #c2c0b6);
166
+ --c-muted: light-dark(#73726c, #9c9a92);
167
+ --c-line: light-dark(rgb(31 30 29 / 0.15), rgb(222 220 209 / 0.15));
168
+ --c-rim: light-dark(rgb(0 0 0 / 0.1), rgb(255 255 255 / 0.1));
169
+ --c-letter: light-dark(#e8e6dc, #3d3d3a);
170
+ --c-clay: #d97757;
171
+ --c-send: #c6613f;
172
+
173
+ all: initial;
174
+ box-sizing: border-box;
175
+ display: grid;
176
+ grid-template-rows: auto minmax(0, 1fr) auto;
177
+ grid-template-columns: minmax(0, 1fr);
178
+ width: 100%;
179
+ height: 100%;
180
+ margin: 0;
181
+ container-type: inline-size;
182
+ overflow: hidden;
183
+ color-scheme: inherit;
184
+ /* The Mac window's 12px corner, not a kit role: it is the product's own. */
185
+ border-radius: 12px;
186
+ background: var(--c-bg);
187
+ color: var(--c-ink);
188
+ box-shadow:
189
+ 0 0 0 1px var(--c-rim),
190
+ var(--elev-overlay);
191
+ font-family:
192
+ system-ui,
193
+ -apple-system,
194
+ "Segoe UI",
195
+ Roboto,
196
+ Helvetica,
197
+ Arial,
198
+ sans-serif;
199
+ font-size: 15px;
200
+ line-height: 1.5;
201
+ text-align: left;
202
+ -webkit-font-smoothing: antialiased;
203
+ -moz-osx-font-smoothing: grayscale;
204
+ user-select: none;
205
+ }
206
+
207
+ .claude[data-mode="light"] {
208
+ color-scheme: light;
209
+ }
210
+
211
+ .claude[data-mode="dark"],
212
+ :global(.dark) .claude[data-mode="auto"],
213
+ :global([data-theme="dark"]) .claude[data-mode="auto"] {
214
+ color-scheme: dark;
215
+ }
216
+
217
+ :global([data-theme="light"]) .claude[data-mode="auto"] {
218
+ color-scheme: light;
219
+ }
220
+
221
+ .claude *,
222
+ .claude *::before,
223
+ .claude *::after {
224
+ box-sizing: border-box;
225
+ }
226
+
227
+ .vh {
228
+ position: absolute;
229
+ width: 1px;
230
+ height: 1px;
231
+ overflow: hidden;
232
+ clip-path: inset(50%);
233
+ white-space: nowrap;
234
+ }
235
+
236
+ .ib {
237
+ display: grid;
238
+ place-items: center;
239
+ flex: none;
240
+ width: 32px;
241
+ height: 32px;
242
+ border-radius: 8px;
243
+ color: var(--c-muted);
244
+ }
245
+
246
+ /* ---------- the bar ---------- */
247
+ .bar {
248
+ display: flex;
249
+ align-items: center;
250
+ gap: 4px;
251
+ height: 48px;
252
+ padding: 0 12px 0 14px;
253
+ }
254
+
255
+ .lights {
256
+ display: flex;
257
+ gap: 8px;
258
+ margin-right: 10px;
259
+ }
260
+
261
+ .lights i {
262
+ width: 12px;
263
+ height: 12px;
264
+ border-radius: 50%;
265
+ background: #ff5f57;
266
+ box-shadow: inset 0 0 0 0.5px rgb(0 0 0 / 0.18);
267
+ }
268
+
269
+ .lights i:nth-child(2) {
270
+ background: #febc2e;
271
+ }
272
+
273
+ .lights i:nth-child(3) {
274
+ background: #28c840;
275
+ }
276
+
277
+ .title {
278
+ display: inline-flex;
279
+ align-items: center;
280
+ gap: 4px;
281
+ min-width: 0;
282
+ padding: 0 6px;
283
+ overflow: hidden;
284
+ font-size: 14px;
285
+ color: var(--c-soft);
286
+ white-space: nowrap;
287
+ text-overflow: ellipsis;
288
+ }
289
+
290
+ .title :global(.chat-glyph) {
291
+ color: var(--c-muted);
292
+ }
293
+
294
+ .share {
295
+ flex: none;
296
+ margin-left: auto;
297
+ padding: 5px 12px;
298
+ border: 0.5px solid var(--c-line);
299
+ border-radius: 8px;
300
+ font-size: 13px;
301
+ font-weight: 500;
302
+ }
303
+
304
+ /* ---------- the conversation ---------- */
305
+ /* Pinned to the bottom like a chat scrolled to its end; a short window clips the top under a soft edge. */
306
+ .thread {
307
+ display: flex;
308
+ flex-direction: column;
309
+ justify-content: flex-end;
310
+ gap: 20px;
311
+ min-height: 0;
312
+ margin: 0;
313
+ padding: 14px clamp(16px, 5cqi, 40px) 14px;
314
+ overflow: hidden;
315
+ list-style: none;
316
+ mask-image: linear-gradient(to bottom, transparent, #000 16px);
317
+ }
318
+
319
+ .turn {
320
+ display: grid;
321
+ min-width: 0;
322
+ }
323
+
324
+ /* claude.ai sets the person's turn right, in a warm grey bubble, no avatar. */
325
+ .user {
326
+ justify-items: end;
327
+ }
328
+
329
+ .bubble {
330
+ max-width: 80%;
331
+ margin: 0;
332
+ padding: 10px 16px;
333
+ border-radius: 16px;
334
+ background: var(--c-bubble);
335
+ font-size: 15px;
336
+ line-height: 1.5;
337
+ overflow-wrap: anywhere;
338
+ white-space: pre-wrap;
339
+ }
340
+
341
+ .assistant > .think,
342
+ .assistant > .reply {
343
+ grid-area: 1 / 1;
344
+ }
345
+
346
+ .think {
347
+ align-self: start;
348
+ color: var(--c-clay);
349
+ opacity: 0;
350
+ }
351
+
352
+ /* Claude answers in a serif. ui-serif is New York on Apple systems, then Georgia: the closest free faces to Anthropic's. */
353
+ .reply {
354
+ display: grid;
355
+ gap: 12px;
356
+ min-width: 0;
357
+ font-family: ui-serif, Georgia, Cambria, "Times New Roman", serif;
358
+ font-size: 16.5px;
359
+ line-height: 1.6;
360
+ color: var(--c-reply);
361
+ overflow-wrap: anywhere;
362
+ }
363
+
364
+ .reply :global(:is(p, ul, ol, h3, table)) {
365
+ margin: 0;
366
+ }
367
+
368
+ .reply :global(:is(ul, ol)) {
369
+ display: grid;
370
+ gap: 4px;
371
+ padding-left: 1.4em;
372
+ }
373
+
374
+ .reply :global(:is(strong, b, h3, th)) {
375
+ font-weight: 600;
376
+ }
377
+
378
+ .reply :global(table) {
379
+ width: 100%;
380
+ border-collapse: collapse;
381
+ font-family:
382
+ system-ui,
383
+ -apple-system,
384
+ "Segoe UI",
385
+ sans-serif;
386
+ font-size: 14px;
387
+ line-height: 1.45;
388
+ font-variant-numeric: tabular-nums;
389
+ }
390
+
391
+ .reply :global(:is(th, td)) {
392
+ padding: 7px 10px 7px 0;
393
+ border-bottom: 0.5px solid var(--c-line);
394
+ text-align: left;
395
+ }
396
+
397
+ .reply :global(th) {
398
+ color: var(--c-soft);
399
+ font-weight: 500;
400
+ }
401
+
402
+ .reply :global(tr:last-child td) {
403
+ border-bottom: 0;
404
+ }
405
+
406
+ .call {
407
+ display: inline-flex;
408
+ align-items: center;
409
+ justify-self: start;
410
+ gap: 8px;
411
+ max-width: 100%;
412
+ min-width: 0;
413
+ margin: 0;
414
+ padding: 7px 10px 7px 9px;
415
+ border: 0.5px solid var(--c-line);
416
+ border-radius: 10px;
417
+ font-size: 14px;
418
+ line-height: 1.4286;
419
+ color: var(--c-soft);
420
+ }
421
+
422
+ .call-icon {
423
+ display: grid;
424
+ place-items: center;
425
+ flex: none;
426
+ width: 16px;
427
+ height: 16px;
428
+ overflow: hidden;
429
+ border-radius: 4px;
430
+ }
431
+
432
+ .call-icon img {
433
+ display: block;
434
+ width: 100%;
435
+ height: 100%;
436
+ object-fit: cover;
437
+ }
438
+
439
+ .call-letter {
440
+ display: grid;
441
+ place-items: center;
442
+ width: 100%;
443
+ height: 100%;
444
+ background: var(--c-letter);
445
+ color: var(--c-ink);
446
+ font-size: 10px;
447
+ font-weight: 600;
448
+ }
449
+
450
+ .call-text {
451
+ flex: none;
452
+ color: var(--c-ink);
453
+ }
454
+
455
+ /* The label gives way first: it truncates, the connector's name never does. */
456
+ .call-name {
457
+ min-width: 0;
458
+ overflow: hidden;
459
+ color: var(--c-muted);
460
+ white-space: nowrap;
461
+ text-overflow: ellipsis;
462
+ }
463
+
464
+ .call-chev {
465
+ flex: none;
466
+ color: var(--c-muted);
467
+ rotate: -90deg;
468
+ }
469
+
470
+ .foot {
471
+ display: flex;
472
+ align-items: center;
473
+ gap: 8px;
474
+ margin-top: 14px;
475
+ }
476
+
477
+ .spark {
478
+ flex: none;
479
+ color: var(--c-clay);
480
+ }
481
+
482
+ .note {
483
+ margin-left: auto;
484
+ font-size: 12px;
485
+ color: var(--c-muted);
486
+ text-align: right;
487
+ }
488
+
489
+ .actions {
490
+ display: flex;
491
+ margin-right: -6px;
492
+ }
493
+
494
+ .ab {
495
+ display: grid;
496
+ place-items: center;
497
+ width: 30px;
498
+ height: 30px;
499
+ border-radius: 6px;
500
+ color: var(--c-muted);
501
+ }
502
+
503
+ .flip {
504
+ scale: 1 -1;
505
+ }
506
+
507
+ /* ---------- the composer ---------- */
508
+ .composer {
509
+ display: grid;
510
+ gap: 12px;
511
+ margin: 0 clamp(10px, 3cqi, 24px) clamp(10px, 3cqi, 18px);
512
+ padding: 14px 10px 10px 16px;
513
+ border: 0.5px solid var(--c-line);
514
+ border-radius: 20px;
515
+ background: var(--c-composer);
516
+ box-shadow: 0 4px 20px light-dark(rgb(0 0 0 / 0.035), rgb(0 0 0 / 0.18));
517
+ }
518
+
519
+ .prompt {
520
+ overflow: hidden;
521
+ color: var(--c-muted);
522
+ white-space: nowrap;
523
+ text-overflow: ellipsis;
524
+ }
525
+
526
+ .tools {
527
+ display: flex;
528
+ align-items: center;
529
+ gap: 6px;
530
+ margin-left: -6px;
531
+ }
532
+
533
+ .cb {
534
+ display: grid;
535
+ place-items: center;
536
+ width: 32px;
537
+ height: 32px;
538
+ border: 0.5px solid var(--c-line);
539
+ border-radius: 8px;
540
+ color: var(--c-soft);
541
+ }
542
+
543
+ .model {
544
+ display: inline-flex;
545
+ align-items: center;
546
+ gap: 2px;
547
+ margin-left: auto;
548
+ padding: 0 6px;
549
+ font-size: 14px;
550
+ color: var(--c-soft);
551
+ white-space: nowrap;
552
+ }
553
+
554
+ .model :global(.chat-glyph) {
555
+ color: var(--c-muted);
556
+ }
557
+
558
+ /* An empty composer's send button sits at half strength, as claude.ai shows it. */
559
+ .send {
560
+ display: grid;
561
+ place-items: center;
562
+ width: 32px;
563
+ height: 32px;
564
+ border-radius: 8px;
565
+ background: var(--c-send);
566
+ color: #ffffff;
567
+ opacity: 0.5;
568
+ }
569
+
570
+ @container (width < 460px) {
571
+ .wide,
572
+ .note,
573
+ .lights {
574
+ display: none;
575
+ }
576
+
577
+ .actions {
578
+ margin-left: auto;
579
+ }
580
+
581
+ .bubble {
582
+ max-width: 88%;
583
+ }
584
+
585
+ .reply {
586
+ font-size: 16px;
587
+ }
588
+ }
589
+
590
+ /* ---------- the reveal: only opacity, a short rise and a mask move, so nothing reflows ---------- */
591
+ .turn > *,
592
+ .call-text,
593
+ .call-name {
594
+ transition:
595
+ opacity var(--duration-fast) var(--ease-smooth-out),
596
+ translate var(--duration-fast) var(--ease-smooth-out);
597
+ }
598
+
599
+ .turn[data-phase="hidden"] > *,
600
+ .turn[data-phase="thinking"] > :not(.think) {
601
+ opacity: 0;
602
+ translate: 0 6px;
603
+ }
604
+
605
+ .turn[data-phase="thinking"] > .think {
606
+ opacity: 1;
607
+ translate: none;
608
+ animation: claude-think calc(var(--duration-overlay) * 3) var(--ease-in-out) infinite;
609
+ }
610
+
611
+ .turn[data-phase="streaming"] > .reply {
612
+ animation: claude-stream var(--claude-stream) var(--ease-linear) both;
613
+ }
614
+
615
+ .turn[data-phase="streaming"] > .foot {
616
+ opacity: 0;
617
+ }
618
+
619
+ .reply {
620
+ mask-image: linear-gradient(to bottom, #000 40%, transparent 60%);
621
+ mask-size: 100% 250%;
622
+ mask-position: 0 0;
623
+ }
624
+
625
+ /* The label keeps its colour; a dimmer band sweeps through it by mask. */
626
+ .turn[data-phase="running"] .call-text {
627
+ mask-image: linear-gradient(100deg, #000 40%, rgb(0 0 0 / 0.4) 50%, #000 60%);
628
+ mask-size: 300% 100%;
629
+ animation: claude-shimmer calc(var(--duration-overlay) * 3) var(--ease-linear) infinite;
630
+ }
631
+
632
+ @keyframes claude-think {
633
+ 50% {
634
+ rotate: 60deg;
635
+ scale: 0.85;
636
+ }
637
+ }
638
+
639
+ @keyframes claude-stream {
640
+ from {
641
+ mask-position: 0 100%;
642
+ }
643
+ to {
644
+ mask-position: 0 0;
645
+ }
646
+ }
647
+
648
+ @keyframes claude-shimmer {
649
+ from {
650
+ mask-position: 100% 0;
651
+ }
652
+ to {
653
+ mask-position: 0 0;
654
+ }
655
+ }
656
+
657
+ @media (prefers-reduced-motion: reduce) {
658
+ .turn > *,
659
+ .call-text,
660
+ .call-name,
661
+ .turn[data-phase] > *,
662
+ .turn[data-phase] .call-text {
663
+ transition: none;
664
+ animation: none;
665
+ }
666
+ }
667
+ }
668
+ </style>
@@ -0,0 +1,25 @@
1
+ import type { ClaudeLabels } from "./labels.js";
2
+ import type { ChatMessage, ChatTheme } from "./types.js";
3
+ export interface ClaudeWindowProps {
4
+ /** The conversation's name, shown in the bar and read out as the picture's label. */
5
+ title: string;
6
+ messages: ChatMessage[];
7
+ /** The model picker in the composer. */
8
+ model?: string;
9
+ placeholder?: string;
10
+ theme?: ChatTheme;
11
+ /** Plays the messages in once the window is on screen. Off, it is a still. */
12
+ reveal?: boolean;
13
+ /** With `reveal`, plays each time this turns on, for a rotator. */
14
+ active?: boolean;
15
+ /** Called after the reveal ends and `hold` ms have passed. */
16
+ ondone?: () => void;
17
+ hold?: number;
18
+ /** Draws macOS's traffic lights, as the desktop app. */
19
+ frame?: boolean;
20
+ labels?: Partial<ClaudeLabels>;
21
+ class?: string;
22
+ }
23
+ declare const $$Component: import("svelte").Component<ClaudeWindowProps, {}, "">;
24
+ type $$Component = ReturnType<typeof $$Component>;
25
+ export default $$Component;