@heyramzi/ui 3.4.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 (305) hide show
  1. package/COMPONENTS.md +2 -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/dist/components/copy/clipboard.js +3 -3
  8. package/dist/components/flag/codes.js +13 -0
  9. package/dist/components/flag/index.js +2 -0
  10. package/dist/slides/export/pdf.js +7 -0
  11. package/dist/vite/flags.js +46 -0
  12. package/package.json +7 -2
  13. package/src/ai/chat-window/ChatGlyph.svelte +38 -0
  14. package/src/ai/chat-window/ChatGlyph.svelte.d.ts +9 -0
  15. package/src/ai/chat-window/ChatGptWindow.svelte +636 -0
  16. package/src/ai/chat-window/ChatGptWindow.svelte.d.ts +25 -0
  17. package/src/ai/chat-window/ClaudeWindow.svelte +668 -0
  18. package/src/ai/chat-window/ClaudeWindow.svelte.d.ts +25 -0
  19. package/src/ai/chat-window/chat-window.test.ts +80 -0
  20. package/src/ai/chat-window/icons/LICENSE +24 -0
  21. package/src/ai/chat-window/icons/chatgpt-chevron.svg +2 -0
  22. package/src/ai/chat-window/icons/chatgpt-copy.svg +2 -0
  23. package/src/ai/chat-window/icons/chatgpt-mic.svg +2 -0
  24. package/src/ai/chat-window/icons/chatgpt-more.svg +2 -0
  25. package/src/ai/chat-window/icons/chatgpt-plus.svg +2 -0
  26. package/src/ai/chat-window/icons/chatgpt-regenerate.svg +2 -0
  27. package/src/ai/chat-window/icons/chatgpt-share.svg +2 -0
  28. package/src/ai/chat-window/icons/chatgpt-sidebar.svg +1 -0
  29. package/src/ai/chat-window/icons/chatgpt-thumb.svg +2 -0
  30. package/src/ai/chat-window/icons/chatgpt-voice.svg +2 -0
  31. package/src/ai/chat-window/icons/claude-chevron.svg +1 -0
  32. package/src/ai/chat-window/icons/claude-copy.svg +1 -0
  33. package/src/ai/chat-window/icons/claude-plus.svg +1 -0
  34. package/src/ai/chat-window/icons/claude-retry.svg +1 -0
  35. package/src/ai/chat-window/icons/claude-send.svg +1 -0
  36. package/src/ai/chat-window/icons/claude-sidebar.svg +1 -0
  37. package/src/ai/chat-window/icons/claude-sliders.svg +1 -0
  38. package/src/ai/chat-window/icons/claude-spark.svg +1 -0
  39. package/src/ai/chat-window/icons/claude-thumb.svg +1 -0
  40. package/src/ai/chat-window/icons.ts +46 -0
  41. package/src/ai/chat-window/index.ts +26 -0
  42. package/src/ai/chat-window/labels.ts +39 -0
  43. package/src/ai/chat-window/reveal.svelte.ts +106 -0
  44. package/src/ai/chat-window/types.ts +42 -0
  45. package/src/components/copy/clipboard.test.ts +17 -1
  46. package/src/components/copy/clipboard.ts +3 -3
  47. package/src/components/flag/codes.test.ts +30 -0
  48. package/src/components/flag/codes.ts +25 -0
  49. package/src/components/flag/flag.svelte +51 -0
  50. package/src/components/flag/flag.svelte.d.ts +12 -0
  51. package/src/components/flag/flags/AD.svg +1 -0
  52. package/src/components/flag/flags/AE.svg +1 -0
  53. package/src/components/flag/flags/AF.svg +1 -0
  54. package/src/components/flag/flags/AG.svg +1 -0
  55. package/src/components/flag/flags/AI.svg +1 -0
  56. package/src/components/flag/flags/AL.svg +1 -0
  57. package/src/components/flag/flags/AM.svg +1 -0
  58. package/src/components/flag/flags/AO.svg +1 -0
  59. package/src/components/flag/flags/AQ.svg +1 -0
  60. package/src/components/flag/flags/AR.svg +1 -0
  61. package/src/components/flag/flags/AS.svg +1 -0
  62. package/src/components/flag/flags/AT.svg +1 -0
  63. package/src/components/flag/flags/AU.svg +1 -0
  64. package/src/components/flag/flags/AW.svg +1 -0
  65. package/src/components/flag/flags/AX.svg +1 -0
  66. package/src/components/flag/flags/AZ.svg +1 -0
  67. package/src/components/flag/flags/BA.svg +1 -0
  68. package/src/components/flag/flags/BB.svg +1 -0
  69. package/src/components/flag/flags/BD.svg +1 -0
  70. package/src/components/flag/flags/BE.svg +1 -0
  71. package/src/components/flag/flags/BF.svg +1 -0
  72. package/src/components/flag/flags/BG.svg +1 -0
  73. package/src/components/flag/flags/BH.svg +1 -0
  74. package/src/components/flag/flags/BI.svg +1 -0
  75. package/src/components/flag/flags/BJ.svg +1 -0
  76. package/src/components/flag/flags/BL.svg +1 -0
  77. package/src/components/flag/flags/BM.svg +1 -0
  78. package/src/components/flag/flags/BN.svg +1 -0
  79. package/src/components/flag/flags/BO.svg +1 -0
  80. package/src/components/flag/flags/BQ.svg +1 -0
  81. package/src/components/flag/flags/BR.svg +1 -0
  82. package/src/components/flag/flags/BS.svg +1 -0
  83. package/src/components/flag/flags/BT.svg +1 -0
  84. package/src/components/flag/flags/BV.svg +1 -0
  85. package/src/components/flag/flags/BW.svg +1 -0
  86. package/src/components/flag/flags/BY.svg +1 -0
  87. package/src/components/flag/flags/BZ.svg +1 -0
  88. package/src/components/flag/flags/CA.svg +1 -0
  89. package/src/components/flag/flags/CC.svg +1 -0
  90. package/src/components/flag/flags/CD.svg +1 -0
  91. package/src/components/flag/flags/CF.svg +1 -0
  92. package/src/components/flag/flags/CG.svg +1 -0
  93. package/src/components/flag/flags/CH.svg +1 -0
  94. package/src/components/flag/flags/CI.svg +1 -0
  95. package/src/components/flag/flags/CK.svg +1 -0
  96. package/src/components/flag/flags/CL.svg +1 -0
  97. package/src/components/flag/flags/CM.svg +1 -0
  98. package/src/components/flag/flags/CN.svg +1 -0
  99. package/src/components/flag/flags/CO.svg +1 -0
  100. package/src/components/flag/flags/CR.svg +1 -0
  101. package/src/components/flag/flags/CU.svg +1 -0
  102. package/src/components/flag/flags/CV.svg +1 -0
  103. package/src/components/flag/flags/CW.svg +1 -0
  104. package/src/components/flag/flags/CX.svg +1 -0
  105. package/src/components/flag/flags/CY.svg +1 -0
  106. package/src/components/flag/flags/CZ.svg +1 -0
  107. package/src/components/flag/flags/DE.svg +1 -0
  108. package/src/components/flag/flags/DJ.svg +1 -0
  109. package/src/components/flag/flags/DK.svg +1 -0
  110. package/src/components/flag/flags/DM.svg +1 -0
  111. package/src/components/flag/flags/DO.svg +1 -0
  112. package/src/components/flag/flags/DZ.svg +1 -0
  113. package/src/components/flag/flags/EC.svg +1 -0
  114. package/src/components/flag/flags/EE.svg +1 -0
  115. package/src/components/flag/flags/EG.svg +1 -0
  116. package/src/components/flag/flags/EH.svg +1 -0
  117. package/src/components/flag/flags/ER.svg +1 -0
  118. package/src/components/flag/flags/ES.svg +1 -0
  119. package/src/components/flag/flags/ET.svg +1 -0
  120. package/src/components/flag/flags/FI.svg +1 -0
  121. package/src/components/flag/flags/FJ.svg +1 -0
  122. package/src/components/flag/flags/FK.svg +1 -0
  123. package/src/components/flag/flags/FM.svg +1 -0
  124. package/src/components/flag/flags/FO.svg +1 -0
  125. package/src/components/flag/flags/FR.svg +1 -0
  126. package/src/components/flag/flags/GA.svg +1 -0
  127. package/src/components/flag/flags/GB.svg +1 -0
  128. package/src/components/flag/flags/GD.svg +1 -0
  129. package/src/components/flag/flags/GE.svg +1 -0
  130. package/src/components/flag/flags/GF.svg +1 -0
  131. package/src/components/flag/flags/GG.svg +1 -0
  132. package/src/components/flag/flags/GH.svg +1 -0
  133. package/src/components/flag/flags/GI.svg +1 -0
  134. package/src/components/flag/flags/GL.svg +1 -0
  135. package/src/components/flag/flags/GM.svg +1 -0
  136. package/src/components/flag/flags/GN.svg +1 -0
  137. package/src/components/flag/flags/GP.svg +1 -0
  138. package/src/components/flag/flags/GQ.svg +1 -0
  139. package/src/components/flag/flags/GR.svg +1 -0
  140. package/src/components/flag/flags/GS.svg +1 -0
  141. package/src/components/flag/flags/GT.svg +1 -0
  142. package/src/components/flag/flags/GU.svg +1 -0
  143. package/src/components/flag/flags/GW.svg +1 -0
  144. package/src/components/flag/flags/GY.svg +1 -0
  145. package/src/components/flag/flags/HK.svg +1 -0
  146. package/src/components/flag/flags/HM.svg +1 -0
  147. package/src/components/flag/flags/HN.svg +1 -0
  148. package/src/components/flag/flags/HR.svg +1 -0
  149. package/src/components/flag/flags/HT.svg +1 -0
  150. package/src/components/flag/flags/HU.svg +1 -0
  151. package/src/components/flag/flags/ID.svg +1 -0
  152. package/src/components/flag/flags/IE.svg +1 -0
  153. package/src/components/flag/flags/IL.svg +1 -0
  154. package/src/components/flag/flags/IM.svg +1 -0
  155. package/src/components/flag/flags/IN.svg +1 -0
  156. package/src/components/flag/flags/IO.svg +1 -0
  157. package/src/components/flag/flags/IQ.svg +1 -0
  158. package/src/components/flag/flags/IR.svg +1 -0
  159. package/src/components/flag/flags/IS.svg +1 -0
  160. package/src/components/flag/flags/IT.svg +1 -0
  161. package/src/components/flag/flags/JE.svg +1 -0
  162. package/src/components/flag/flags/JM.svg +1 -0
  163. package/src/components/flag/flags/JO.svg +1 -0
  164. package/src/components/flag/flags/JP.svg +1 -0
  165. package/src/components/flag/flags/KE.svg +1 -0
  166. package/src/components/flag/flags/KG.svg +1 -0
  167. package/src/components/flag/flags/KH.svg +1 -0
  168. package/src/components/flag/flags/KI.svg +1 -0
  169. package/src/components/flag/flags/KM.svg +1 -0
  170. package/src/components/flag/flags/KN.svg +1 -0
  171. package/src/components/flag/flags/KP.svg +1 -0
  172. package/src/components/flag/flags/KR.svg +1 -0
  173. package/src/components/flag/flags/KW.svg +1 -0
  174. package/src/components/flag/flags/KY.svg +1 -0
  175. package/src/components/flag/flags/KZ.svg +1 -0
  176. package/src/components/flag/flags/LA.svg +1 -0
  177. package/src/components/flag/flags/LB.svg +1 -0
  178. package/src/components/flag/flags/LC.svg +1 -0
  179. package/src/components/flag/flags/LI.svg +1 -0
  180. package/src/components/flag/flags/LICENSE +22 -0
  181. package/src/components/flag/flags/LK.svg +1 -0
  182. package/src/components/flag/flags/LR.svg +1 -0
  183. package/src/components/flag/flags/LS.svg +1 -0
  184. package/src/components/flag/flags/LT.svg +1 -0
  185. package/src/components/flag/flags/LU.svg +1 -0
  186. package/src/components/flag/flags/LV.svg +1 -0
  187. package/src/components/flag/flags/LY.svg +1 -0
  188. package/src/components/flag/flags/MA.svg +1 -0
  189. package/src/components/flag/flags/MC.svg +1 -0
  190. package/src/components/flag/flags/MD.svg +1 -0
  191. package/src/components/flag/flags/ME.svg +1 -0
  192. package/src/components/flag/flags/MF.svg +1 -0
  193. package/src/components/flag/flags/MG.svg +1 -0
  194. package/src/components/flag/flags/MH.svg +1 -0
  195. package/src/components/flag/flags/MK.svg +1 -0
  196. package/src/components/flag/flags/ML.svg +1 -0
  197. package/src/components/flag/flags/MM.svg +1 -0
  198. package/src/components/flag/flags/MN.svg +1 -0
  199. package/src/components/flag/flags/MO.svg +1 -0
  200. package/src/components/flag/flags/MP.svg +1 -0
  201. package/src/components/flag/flags/MQ.svg +1 -0
  202. package/src/components/flag/flags/MR.svg +1 -0
  203. package/src/components/flag/flags/MS.svg +1 -0
  204. package/src/components/flag/flags/MT.svg +1 -0
  205. package/src/components/flag/flags/MU.svg +1 -0
  206. package/src/components/flag/flags/MV.svg +1 -0
  207. package/src/components/flag/flags/MW.svg +1 -0
  208. package/src/components/flag/flags/MX.svg +1 -0
  209. package/src/components/flag/flags/MY.svg +1 -0
  210. package/src/components/flag/flags/MZ.svg +1 -0
  211. package/src/components/flag/flags/NA.svg +1 -0
  212. package/src/components/flag/flags/NC.svg +1 -0
  213. package/src/components/flag/flags/NE.svg +1 -0
  214. package/src/components/flag/flags/NF.svg +1 -0
  215. package/src/components/flag/flags/NG.svg +1 -0
  216. package/src/components/flag/flags/NI.svg +1 -0
  217. package/src/components/flag/flags/NL.svg +1 -0
  218. package/src/components/flag/flags/NO.svg +1 -0
  219. package/src/components/flag/flags/NP.svg +1 -0
  220. package/src/components/flag/flags/NR.svg +1 -0
  221. package/src/components/flag/flags/NU.svg +1 -0
  222. package/src/components/flag/flags/NZ.svg +1 -0
  223. package/src/components/flag/flags/OM.svg +1 -0
  224. package/src/components/flag/flags/PA.svg +1 -0
  225. package/src/components/flag/flags/PE.svg +1 -0
  226. package/src/components/flag/flags/PF.svg +1 -0
  227. package/src/components/flag/flags/PG.svg +1 -0
  228. package/src/components/flag/flags/PH.svg +1 -0
  229. package/src/components/flag/flags/PK.svg +1 -0
  230. package/src/components/flag/flags/PL.svg +1 -0
  231. package/src/components/flag/flags/PM.svg +1 -0
  232. package/src/components/flag/flags/PN.svg +1 -0
  233. package/src/components/flag/flags/PR.svg +1 -0
  234. package/src/components/flag/flags/PS.svg +1 -0
  235. package/src/components/flag/flags/PT.svg +1 -0
  236. package/src/components/flag/flags/PW.svg +1 -0
  237. package/src/components/flag/flags/PY.svg +1 -0
  238. package/src/components/flag/flags/QA.svg +1 -0
  239. package/src/components/flag/flags/RE.svg +1 -0
  240. package/src/components/flag/flags/RO.svg +1 -0
  241. package/src/components/flag/flags/RS.svg +1 -0
  242. package/src/components/flag/flags/RU.svg +1 -0
  243. package/src/components/flag/flags/RW.svg +1 -0
  244. package/src/components/flag/flags/SA.svg +1 -0
  245. package/src/components/flag/flags/SB.svg +1 -0
  246. package/src/components/flag/flags/SC.svg +1 -0
  247. package/src/components/flag/flags/SD.svg +1 -0
  248. package/src/components/flag/flags/SE.svg +1 -0
  249. package/src/components/flag/flags/SG.svg +1 -0
  250. package/src/components/flag/flags/SH.svg +1 -0
  251. package/src/components/flag/flags/SI.svg +1 -0
  252. package/src/components/flag/flags/SJ.svg +1 -0
  253. package/src/components/flag/flags/SK.svg +1 -0
  254. package/src/components/flag/flags/SL.svg +1 -0
  255. package/src/components/flag/flags/SM.svg +1 -0
  256. package/src/components/flag/flags/SN.svg +1 -0
  257. package/src/components/flag/flags/SO.svg +1 -0
  258. package/src/components/flag/flags/SR.svg +1 -0
  259. package/src/components/flag/flags/SS.svg +1 -0
  260. package/src/components/flag/flags/ST.svg +1 -0
  261. package/src/components/flag/flags/SV.svg +1 -0
  262. package/src/components/flag/flags/SX.svg +1 -0
  263. package/src/components/flag/flags/SY.svg +1 -0
  264. package/src/components/flag/flags/SZ.svg +1 -0
  265. package/src/components/flag/flags/TC.svg +1 -0
  266. package/src/components/flag/flags/TD.svg +1 -0
  267. package/src/components/flag/flags/TF.svg +1 -0
  268. package/src/components/flag/flags/TG.svg +1 -0
  269. package/src/components/flag/flags/TH.svg +1 -0
  270. package/src/components/flag/flags/TJ.svg +1 -0
  271. package/src/components/flag/flags/TK.svg +1 -0
  272. package/src/components/flag/flags/TL.svg +1 -0
  273. package/src/components/flag/flags/TM.svg +1 -0
  274. package/src/components/flag/flags/TN.svg +1 -0
  275. package/src/components/flag/flags/TO.svg +1 -0
  276. package/src/components/flag/flags/TR.svg +1 -0
  277. package/src/components/flag/flags/TT.svg +1 -0
  278. package/src/components/flag/flags/TV.svg +1 -0
  279. package/src/components/flag/flags/TW.svg +1 -0
  280. package/src/components/flag/flags/TZ.svg +1 -0
  281. package/src/components/flag/flags/UA.svg +1 -0
  282. package/src/components/flag/flags/UG.svg +1 -0
  283. package/src/components/flag/flags/UM.svg +1 -0
  284. package/src/components/flag/flags/US.svg +1 -0
  285. package/src/components/flag/flags/UY.svg +1 -0
  286. package/src/components/flag/flags/UZ.svg +1 -0
  287. package/src/components/flag/flags/VA.svg +1 -0
  288. package/src/components/flag/flags/VC.svg +1 -0
  289. package/src/components/flag/flags/VE.svg +1 -0
  290. package/src/components/flag/flags/VG.svg +1 -0
  291. package/src/components/flag/flags/VI.svg +1 -0
  292. package/src/components/flag/flags/VN.svg +1 -0
  293. package/src/components/flag/flags/VU.svg +1 -0
  294. package/src/components/flag/flags/WF.svg +1 -0
  295. package/src/components/flag/flags/WS.svg +1 -0
  296. package/src/components/flag/flags/XK.svg +1 -0
  297. package/src/components/flag/flags/YE.svg +1 -0
  298. package/src/components/flag/flags/YT.svg +1 -0
  299. package/src/components/flag/flags/ZA.svg +1 -0
  300. package/src/components/flag/flags/ZM.svg +1 -0
  301. package/src/components/flag/flags/ZW.svg +1 -0
  302. package/src/components/flag/index.ts +2 -0
  303. package/src/slides/export/pdf.ts +11 -0
  304. package/src/vite/flags.test.ts +38 -0
  305. package/src/vite/flags.ts +63 -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;