shadow-claw 1.23.3 → 1.23.4

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 (89) hide show
  1. package/bin/assert-version-bump.mjs +60 -38
  2. package/bin/assert-version-bump.test.mjs +74 -11
  3. package/dist/public/agent.worker.js +6 -6
  4. package/dist/public/{app-routes-B0ePT49v.js → app-routes-Bs-riIvr.js} +1 -1
  5. package/dist/public/components/settings/shadow-claw-storage/shadow-claw-storage.html +1 -1
  6. package/dist/public/components/shadow-claw-files/shadow-claw-files.css +1 -1
  7. package/dist/public/components/shadow-claw-files/shadow-claw-files.html +1 -1
  8. package/dist/public/config-BYAuxx3j.js +1 -0
  9. package/dist/public/{configurePeerJs-B7kNU8AQ.js → configurePeerJs-B4Ym9VMj.js} +1 -1
  10. package/dist/public/{connections-xd_66YVU.js → connections-BEn6JYdu.js} +1 -1
  11. package/dist/public/{custom-element-security-CZ92anB8.js → custom-element-security-DdYlUozq.js} +1 -1
  12. package/dist/public/docs/architecture/storage.md +5 -2
  13. package/dist/public/docs/decisions/indexeddb-and-opfs-storage.md +5 -2
  14. package/dist/public/docs/example/article/index.html +2 -2
  15. package/dist/public/docs/publishing/index.html +19 -76
  16. package/dist/public/docs/skill-creator/index.html +2 -2
  17. package/dist/public/{downloadGroupFile-BABv_1mJ.js → downloadGroupFile-Drdvg1Ev.js} +1 -1
  18. package/dist/public/{e2e-bridge-DkS5xFGX.js → e2e-bridge-BQ4KzUt5.js} +1 -1
  19. package/dist/public/{file-viewer-CCSABMsE.js → file-viewer-CcZYw-PS.js} +1 -1
  20. package/dist/public/files/main/~/docs/publishing-to-github-pages.md +17 -82
  21. package/dist/public/{git-BkjrsRXX.js → git-DEUvQTUA.js} +2 -2
  22. package/dist/public/{iframe-sanitizer-L6Jyu__Z.js → iframe-sanitizer-0NS4XLOd.js} +1 -1
  23. package/dist/public/index.html +2 -2
  24. package/dist/public/index.js +1 -1
  25. package/dist/public/{initChatSplitResize-BslPXAXS.js → initChatSplitResize-llGkSJXg.js} +1 -1
  26. package/dist/public/main/index.html +2 -2
  27. package/dist/public/main/memory/index.html +2 -2
  28. package/dist/public/{markdown-6MBrIo-S.js → markdown-CyYR4App.js} +1 -1
  29. package/dist/public/mcp-reconnect-CSx4aMwy.js +1 -0
  30. package/dist/public/{memoryStorage-CjGseKI1.js → memoryStorage-Dwg8NhAZ.js} +1 -1
  31. package/dist/public/{orchestrator-B9KmIj8Q.js → orchestrator-DRfEudXk.js} +18 -18
  32. package/dist/public/orchestrator-o9Fj67BN.js +15 -0
  33. package/dist/public/pages/main/~/docs/publishing-to-github-pages.md +17 -82
  34. package/dist/public/{peerjs-Dv8JNm7v.js → peerjs-CurBuKvk.js} +1 -1
  35. package/dist/public/{push-client-Dqq06wbB.js → push-client-Dii-vPEh.js} +1 -1
  36. package/dist/public/service-worker/fetch-proxy.js +1 -1
  37. package/dist/public/service-worker.js +1 -1
  38. package/dist/public/{shadow-claw-Bd1rfuVC.js → shadow-claw-5IHaDDMJ.js} +2 -2
  39. package/dist/public/{shadow-claw-accounts-DL2l3oM0.js → shadow-claw-accounts-CZvz4iQz.js} +3 -3
  40. package/dist/public/{shadow-claw-channels-BGXDsQ38.js → shadow-claw-channels-BKXFyRS3.js} +1 -1
  41. package/dist/public/{shadow-claw-chat-NXg6zz_l.js → shadow-claw-chat-CCLuhWdI.js} +3 -3
  42. package/dist/public/{shadow-claw-conversations-C8eqGpP9.js → shadow-claw-conversations-DV-87UUh.js} +1 -1
  43. package/dist/public/shadow-claw-file-viewer-Dk2dbAUd.js +577 -0
  44. package/dist/public/shadow-claw-files-BpfpJIuP.js +840 -0
  45. package/dist/public/{shadow-claw-git-C0ntz7aX.js → shadow-claw-git-DRA7_qck.js} +3 -3
  46. package/dist/public/{shadow-claw-integrations-DCXV2r69.js → shadow-claw-integrations-1Xu5snuV.js} +1 -1
  47. package/dist/public/{shadow-claw-llm-CudgFQsS.js → shadow-claw-llm-6Aci1BDP.js} +2 -2
  48. package/dist/public/{shadow-claw-mcp-remote-B8RkpX28.js → shadow-claw-mcp-remote-BUjAeVXC.js} +1 -1
  49. package/dist/public/{shadow-claw-networking-BLiRsrsK.js → shadow-claw-networking-FQe4nCp3.js} +1 -1
  50. package/dist/public/{shadow-claw-notifications-CQhQcjtL.js → shadow-claw-notifications-DV2wibL3.js} +1 -1
  51. package/dist/public/{shadow-claw-page-header-NeRD0tKU.js → shadow-claw-page-header-B63S4HTU.js} +1 -1
  52. package/dist/public/{shadow-claw-pages-DCHnFh6r.js → shadow-claw-pages-DE3jWj5K.js} +3 -3
  53. package/dist/public/{shadow-claw-settings-VAfjKFQg.js → shadow-claw-settings-S6DAKfYx.js} +3 -3
  54. package/dist/public/shadow-claw-storage-DaacA3_K.js +219 -0
  55. package/dist/public/{shadow-claw-task-server-Dk33N_1G.js → shadow-claw-task-server-IjKX042p.js} +1 -1
  56. package/dist/public/{shadow-claw-tasks-xA1VfmWN.js → shadow-claw-tasks-Cy0JYmGU.js} +4 -4
  57. package/dist/public/{shadow-claw-terminal-Du2r0ciq.js → shadow-claw-terminal-znAt7HyP.js} +1 -1
  58. package/dist/public/{shadow-claw-tools-CZj4rq7l.js → shadow-claw-tools-Cutv9Si5.js} +2 -2
  59. package/dist/public/{shadow-claw-webvm-JYUkWICG.js → shadow-claw-webvm-BH8mPDEu.js} +1 -1
  60. package/dist/public/static-main/~/docs/publishing-to-github-pages.md +17 -82
  61. package/dist/public/static-main-manifest.json +1 -1
  62. package/dist/public/{syncWebMcpRegistration-DfpvASnh.js → syncWebMcpRegistration-BqJxaMGR.js} +1 -1
  63. package/package.json +1 -1
  64. package/src/components/settings/shadow-claw-storage/shadow-claw-storage.html +17 -0
  65. package/src/components/settings/shadow-claw-storage/shadow-claw-storage.test.ts +44 -0
  66. package/src/components/settings/shadow-claw-storage/shadow-claw-storage.ts +56 -0
  67. package/src/components/shadow-claw-file-viewer/shadow-claw-file-viewer.test.ts +105 -0
  68. package/src/components/shadow-claw-file-viewer/shadow-claw-file-viewer.ts +11 -9
  69. package/src/components/shadow-claw-files/shadow-claw-files.css +41 -17
  70. package/src/components/shadow-claw-files/shadow-claw-files.html +35 -0
  71. package/src/components/shadow-claw-files/shadow-claw-files.test.ts +219 -0
  72. package/src/components/shadow-claw-files/shadow-claw-files.ts +170 -6
  73. package/src/components/shadow-claw-pages/utils/resolveWorkspaceLinkPath.test.ts +31 -0
  74. package/src/components/shadow-claw-pages/utils/resolveWorkspaceLinkPath.ts +2 -1
  75. package/src/components/shadow-claw-pages/utils/rewriteWorkspacePreviewHtml.test.ts +15 -0
  76. package/src/config/config.test.ts +9 -0
  77. package/src/config/config.ts +5 -0
  78. package/src/core/app-routes.test.ts +56 -0
  79. package/src/core/app-routes.ts +8 -1
  80. package/src/db/openDatabase.test.ts +10 -1
  81. package/src/db/openDatabase.ts +3 -1
  82. package/src/storage/migrateLegacyOpfs.test.ts +327 -0
  83. package/src/storage/migrateLegacyOpfs.ts +117 -0
  84. package/dist/public/config-AL77QAx4.js +0 -1
  85. package/dist/public/mcp-reconnect-DoicazQd.js +0 -1
  86. package/dist/public/orchestrator-4su7iyWj.js +0 -15
  87. package/dist/public/shadow-claw-file-viewer-9Qkwc30T.js +0 -577
  88. package/dist/public/shadow-claw-files-aDyq6Hv7.js +0 -781
  89. package/dist/public/shadow-claw-storage-Cf31np81.js +0 -202
@@ -0,0 +1,577 @@
1
+ import{r as e}from"./config-BYAuxx3j.js";import{a as t,n,o as r,s as i,u as a}from"./app-routes-Bs-riIvr.js";import{n as o}from"./txPromise-EBECky1b.js";import{t as s}from"./getConfig-D89uJgo5.js";import{d as c,f as l,i as u,l as d,n as f,r as p,s as m,u as h}from"./custom-element-security-DdYlUozq.js";import{bn as g,mn as _,sn as v,t as y}from"./orchestrator-DRfEudXk.js";import{r as b,t as x}from"./toast-D3gxhZpN.js";import{t as S}from"./shadow-claw-element-DIrv3P6A.js";import{t as C}from"./effect-BEsuusE8.js";import{t as w}from"./config-value-oBfKgLT4.js";import{n as T,r as E,t as D}from"./markdown-CyYR4App.js";import{t as O}from"./file-viewer-CcZYw-PS.js";import"./shadow-claw-dialog-ByyHgxM9.js";import{a as k,c as A,i as j,n as M,o as N,r as P,s as F,t as I}from"./iframe-storage-proxy-B9Zt-vJ2.js";const L=new CSSStyleSheet;L.replaceSync(`*,
2
+ *::before,
3
+ *::after {
4
+ box-sizing: border-box;
5
+ scrollbar-color: var(--shadow-claw-border-color) transparent;
6
+ scrollbar-width: thin;
7
+ }
8
+
9
+ :root {
10
+ --shadow-claw-font-mono: "Fira Code", "Courier New", monospace;
11
+ }
12
+
13
+ pre {
14
+ font-family: var(--shadow-claw-font-mono) !important;
15
+ }
16
+
17
+ /* Scrollbar — cross-browser thin style (Shadow DOM) */
18
+ * {
19
+ scrollbar-color: var(--shadow-claw-border-color) transparent;
20
+ scrollbar-width: thin;
21
+ }
22
+
23
+ ::-webkit-scrollbar {
24
+ height: 0.5rem;
25
+ width: 0.5rem;
26
+ }
27
+
28
+ ::-webkit-scrollbar-track {
29
+ background: transparent;
30
+ }
31
+
32
+ ::-webkit-scrollbar-thumb {
33
+ background: var(--shadow-claw-border-color);
34
+ border-radius: 0.25rem;
35
+ }
36
+
37
+ ::-webkit-scrollbar-thumb:hover {
38
+ background: var(--shadow-claw-text-tertiary);
39
+ }
40
+
41
+ .hidden,
42
+ [hidden] {
43
+ display: none !important;
44
+ }
45
+
46
+ :host {
47
+ display: contents;
48
+ }
49
+
50
+ .file-modal {
51
+ background: transparent;
52
+ border: none;
53
+ margin: 0;
54
+ max-height: unset;
55
+ max-width: unset;
56
+ padding: 0;
57
+ }
58
+
59
+ .file-modal[open] {
60
+ align-items: flex-start;
61
+ box-sizing: border-box;
62
+ display: flex;
63
+ inset: 0;
64
+ justify-content: center;
65
+ padding: 0.5rem;
66
+ position: fixed;
67
+ width: auto;
68
+ z-index: 1000;
69
+ }
70
+
71
+ .file-modal::backdrop {
72
+ background-color: rgba(0, 0, 0, 0.5);
73
+ }
74
+
75
+ .modal-content {
76
+ background-color: var(--shadow-claw-bg-primary);
77
+ border: 0.0625rem solid var(--shadow-claw-border-color);
78
+ border-radius: var(--shadow-claw-radius-l);
79
+ box-shadow: var(--shadow-claw-shadow-lg);
80
+ display: flex;
81
+ flex-direction: column;
82
+ height: min(88dvh, 45rem);
83
+ max-height: calc(100dvh - 1rem);
84
+ max-width: 56rem;
85
+ width: calc(100vw - 1rem);
86
+ }
87
+
88
+ .modal-content.modal-content--fullscreen {
89
+ height: calc(100dvh - 1rem);
90
+ max-height: calc(100dvh - 1rem);
91
+ max-width: calc(100vw - 1rem);
92
+ width: calc(100vw - 1rem);
93
+ }
94
+
95
+ .modal-header {
96
+ align-items: center;
97
+ border-bottom: 0.0625rem solid var(--shadow-claw-border-color);
98
+ display: flex;
99
+ gap: 0.5rem;
100
+ justify-content: space-between;
101
+ min-width: 0;
102
+ padding: 0.625rem 0.75rem;
103
+ }
104
+
105
+ .modal-header-actions {
106
+ align-items: center;
107
+ display: flex;
108
+ flex: none;
109
+ gap: 0.5rem;
110
+ }
111
+
112
+ .modal-cancel-btn,
113
+ .modal-save-btn,
114
+ .modal-share-btn {
115
+ background-color: transparent;
116
+ border: 0.0625rem solid var(--shadow-claw-border-color);
117
+ border-radius: var(--shadow-claw-radius-m);
118
+ color: var(--shadow-claw-text-secondary);
119
+ cursor: pointer;
120
+ font-size: 0.75rem;
121
+ font-weight: 600;
122
+ min-height: 2rem;
123
+ padding: 0.375rem 0.625rem;
124
+ transition: all 0.15s;
125
+ }
126
+
127
+ .modal-share-btn:hover {
128
+ border-color: var(--shadow-claw-text-primary);
129
+ box-shadow: var(--shadow-claw-shadow-md);
130
+ color: var(--shadow-claw-text-primary);
131
+ }
132
+
133
+ .modal-save-btn {
134
+ background-color: var(--shadow-claw-text-primary);
135
+ border-color: var(--shadow-claw-text-primary);
136
+ color: var(--shadow-claw-bg-primary);
137
+ }
138
+
139
+ .modal-save-btn:hover {
140
+ background-color: var(--shadow-claw-accent-primary);
141
+ border-color: var(--shadow-claw-accent-primary);
142
+ color: var(--shadow-claw-on-primary);
143
+ }
144
+
145
+ .modal-cancel-btn {
146
+ border-color: var(--shadow-claw-border-color);
147
+ color: var(--shadow-claw-text-secondary);
148
+ }
149
+
150
+ .modal-cancel-btn:hover {
151
+ border-color: var(--shadow-claw-error, #ef4444);
152
+ color: var(--shadow-claw-error, #ef4444);
153
+ }
154
+
155
+ .modal-title {
156
+ color: var(--shadow-claw-text-primary);
157
+ flex: 1;
158
+ font-size: 1rem;
159
+ font-weight: 600;
160
+ margin: 0;
161
+ overflow: hidden;
162
+ text-overflow: ellipsis;
163
+ white-space: nowrap;
164
+ }
165
+
166
+ /* Segmented view-mode group (Edit + Preview) */
167
+ .modal-view-modes {
168
+ border: 0.0625rem solid var(--shadow-claw-border-color);
169
+ border-radius: var(--shadow-claw-radius-m);
170
+ display: flex;
171
+ flex: none;
172
+ margin-right: 0.5rem;
173
+ overflow: hidden;
174
+ }
175
+
176
+ .modal-view-modes .modal-edit-btn,
177
+ .modal-view-modes .modal-preview-btn,
178
+ .modal-view-modes .modal-fullscreen-btn {
179
+ background-color: transparent;
180
+ border: none;
181
+ border-radius: 0;
182
+ color: var(--shadow-claw-text-secondary);
183
+ cursor: pointer;
184
+ font-size: 0.75rem;
185
+ font-weight: 600;
186
+ min-height: 2rem;
187
+ padding: 0.375rem 0.625rem;
188
+ transition: all 0.15s;
189
+ }
190
+
191
+ .modal-view-modes .modal-edit-btn {
192
+ border-right: 0.0625rem solid var(--shadow-claw-border-color);
193
+ }
194
+
195
+ .modal-view-modes .modal-preview-btn {
196
+ border-right: 0.0625rem solid var(--shadow-claw-border-color);
197
+ }
198
+
199
+ /* When edit button is hidden (binary files), preview gets full rounding */
200
+ .modal-view-modes .modal-edit-btn.hidden + .modal-preview-btn {
201
+ border-radius: var(--shadow-claw-radius-m);
202
+ }
203
+
204
+ .modal-view-modes .modal-edit-btn:hover,
205
+ .modal-view-modes .modal-preview-btn:hover,
206
+ .modal-view-modes .modal-fullscreen-btn:hover {
207
+ background-color: var(--shadow-claw-bg-secondary);
208
+ color: var(--shadow-claw-text-primary);
209
+ }
210
+
211
+ .modal-view-modes .modal-edit-btn[aria-pressed="true"],
212
+ .modal-view-modes .modal-preview-btn[aria-pressed="true"],
213
+ .modal-view-modes .modal-fullscreen-btn[aria-pressed="true"] {
214
+ background-color: var(--shadow-claw-bg-secondary);
215
+ color: var(--shadow-claw-text-primary);
216
+ }
217
+
218
+ .modal-close-btn {
219
+ background-color: var(--shadow-claw-bg-tertiary);
220
+ border: 0.0625rem solid var(--shadow-claw-border-color);
221
+ border-radius: var(--shadow-claw-radius-m);
222
+ color: var(--shadow-claw-text-secondary);
223
+ cursor: pointer;
224
+ font-size: 1.25rem;
225
+ line-height: 1;
226
+ min-height: 2rem;
227
+ padding: 0.375rem 0.625rem;
228
+ }
229
+
230
+ .modal-close-btn:hover {
231
+ background-color: var(--shadow-claw-bg-secondary);
232
+ border-color: var(--shadow-claw-accent-primary);
233
+ color: var(--shadow-claw-text-primary);
234
+ }
235
+
236
+ @media (max-width: 640px) {
237
+ .modal-cancel-btn .btn-label,
238
+ .modal-save-btn .btn-label {
239
+ display: none;
240
+ }
241
+ }
242
+
243
+ @media (max-width: 480px) {
244
+ .btn-label {
245
+ display: none;
246
+ }
247
+
248
+ .modal-header-actions {
249
+ gap: 0.25rem;
250
+ }
251
+ }
252
+
253
+ .modal-body {
254
+ display: flex;
255
+ flex: 1;
256
+ flex-direction: column;
257
+ min-height: 0;
258
+ overflow: hidden;
259
+ padding: 0;
260
+ position: relative;
261
+ }
262
+
263
+ .modal-body.modal-body--editing {
264
+ overflow: hidden;
265
+ }
266
+
267
+ .file-content {
268
+ color: var(--shadow-claw-text-primary);
269
+ flex: 1;
270
+ font-family: var(--shadow-claw-font-mono);
271
+ font-size: 0.8125rem;
272
+ min-height: 0;
273
+ overflow-x: hidden;
274
+ overflow-y: auto;
275
+ padding: 0.75rem;
276
+ white-space: pre-wrap;
277
+ word-break: break-all;
278
+ }
279
+
280
+ .file-content--preview {
281
+ font-family: var(--shadow-claw-font-sans);
282
+ font-size: var(--shadow-claw-font-size-sm);
283
+ line-height: 1.5;
284
+ overflow-wrap: anywhere;
285
+ padding: 0.75rem 1rem;
286
+ user-select: text !important;
287
+ white-space: normal;
288
+ word-break: break-word;
289
+ }
290
+
291
+ .file-content--preview *,
292
+ .file-content--preview pre,
293
+ .file-content--preview code {
294
+ user-select: text !important;
295
+ }
296
+
297
+ .file-content--preview > :first-child {
298
+ margin-top: 0;
299
+ }
300
+
301
+ .file-content--preview > :last-child {
302
+ margin-bottom: 0;
303
+ }
304
+
305
+ .file-content--preview pre {
306
+ background: var(--shadow-claw-bg-secondary);
307
+ border: 0.0625rem solid var(--shadow-claw-border-color);
308
+ border-radius: var(--shadow-claw-radius-m);
309
+ margin: 0.75rem 0;
310
+ overflow-x: auto;
311
+ padding: 0;
312
+ }
313
+
314
+ .file-content--preview pre code.hljs {
315
+ background-color: transparent;
316
+ display: block;
317
+ font-size: 0.8125rem;
318
+ line-height: 1.6;
319
+ padding: 0.75rem;
320
+ }
321
+
322
+ .file-content--preview code:not(pre code) {
323
+ background: var(--shadow-claw-bg-tertiary);
324
+ border-radius: var(--shadow-claw-radius-s);
325
+ font-size: 0.85em;
326
+ padding: 0.125rem 0.3rem;
327
+ }
328
+
329
+ .file-content--preview img {
330
+ height: auto;
331
+ max-width: 100%;
332
+ }
333
+
334
+ .file-content--preview table {
335
+ border-collapse: collapse;
336
+ display: block;
337
+ max-width: 100%;
338
+ overflow-x: auto;
339
+ }
340
+
341
+ .file-content--preview th,
342
+ .file-content--preview td {
343
+ border: 0.0625rem solid var(--shadow-claw-border-color);
344
+ padding: 0.375rem 0.75rem;
345
+ text-align: left;
346
+ }
347
+
348
+ .file-content--preview th {
349
+ background: var(--shadow-claw-bg-secondary);
350
+ font-weight: 600;
351
+ }
352
+
353
+ .file-content--preview blockquote {
354
+ border-left: 0.25rem solid var(--shadow-claw-border-color);
355
+ color: var(--shadow-claw-text-secondary);
356
+ margin: 0.75rem 0;
357
+ padding: 0.25rem 1rem;
358
+ }
359
+
360
+ .file-content--preview a {
361
+ color: var(--shadow-claw-accent-primary);
362
+ }
363
+
364
+ .file-content--preview h1,
365
+ .file-content--preview h2 {
366
+ border-bottom: 0.0625rem solid var(--shadow-claw-border-color);
367
+ padding-bottom: 0.375rem;
368
+ }
369
+
370
+ .file-content--preview ul,
371
+ .file-content--preview ol {
372
+ padding-left: 1.5rem;
373
+ }
374
+
375
+ .file-content--iframe {
376
+ height: 100%;
377
+ margin: 0;
378
+ overflow: auto;
379
+ padding: 0;
380
+ width: 100%;
381
+ }
382
+
383
+ .file-content-iframe {
384
+ background-color: var(--shadow-claw-bg-primary);
385
+ border: none;
386
+ border-radius: var(--shadow-claw-radius-s);
387
+ display: block;
388
+ min-height: 100%;
389
+ width: 100%;
390
+ }
391
+
392
+ .file-editor-container {
393
+ background-color: var(--shadow-claw-hljs-background-color, rgb(40, 44, 52));
394
+ display: none;
395
+ flex: 1;
396
+ margin: 0.75rem;
397
+ min-height: 0;
398
+ min-width: 0;
399
+ position: relative;
400
+ }
401
+
402
+ .file-editor-container.active {
403
+ display: block;
404
+ }
405
+
406
+ .file-editor {
407
+ background-color: transparent;
408
+ border: 0.0625rem solid var(--shadow-claw-border-color);
409
+ border-radius: var(--shadow-claw-radius-s);
410
+ caret-color: #abb2bf !important;
411
+ color: transparent;
412
+ font-family: var(--shadow-claw-font-mono), monospace !important;
413
+ font-size: 1rem !important;
414
+ font-variant-ligatures: none !important;
415
+ height: 100%;
416
+ left: 0;
417
+ line-height: 1.5 !important;
418
+ overflow: auto;
419
+ padding: 0.625rem;
420
+ position: absolute;
421
+ resize: none;
422
+ tab-size: 2;
423
+ top: 0;
424
+ white-space: pre;
425
+ width: 100%;
426
+ z-index: 1;
427
+ }
428
+
429
+ .file-editor-container pre.file-editor-overlay {
430
+ border: 0.0625rem solid transparent !important;
431
+ border-radius: var(--shadow-claw-radius-s);
432
+ box-sizing: border-box !important;
433
+ font-family: var(--shadow-claw-font-mono), monospace !important;
434
+ font-size: 1rem !important;
435
+ font-variant-ligatures: none !important;
436
+ height: 100% !important;
437
+ left: 0 !important;
438
+ line-height: 1.5 !important;
439
+ margin: 0 !important;
440
+ overflow: hidden !important;
441
+ padding: 0.625rem !important;
442
+ pointer-events: none;
443
+ position: absolute !important;
444
+ tab-size: 2 !important;
445
+ top: 0 !important;
446
+ white-space: pre !important;
447
+ width: 100% !important;
448
+ z-index: 0;
449
+ }
450
+
451
+ .file-editor-container pre.file-editor-overlay code,
452
+ .file-editor-container pre.file-editor-overlay code.hljs {
453
+ display: block !important;
454
+ font-family: inherit !important;
455
+ font-size: inherit !important;
456
+ font-variant-ligatures: none !important;
457
+ /* hljs CSS injects overflow-x:auto on pre code.hljs via a constructed stylesheet.
458
+ Inside the overlay (pointer-events:none) this would create an unclickable ghost scrollbar.
459
+ Use overflow:visible so the code content extends into the pre's scroll area.
460
+ The pre (overflow:hidden) handles visual clipping; JS sync scrolls the pre.
461
+ visible never generates a scrollbar, so no ghost scrollbar appears. */
462
+ overflow: visible !important;
463
+ line-height: inherit !important;
464
+ margin: 0 !important;
465
+ padding: 0 !important;
466
+ white-space: inherit !important;
467
+ word-break: normal !important;
468
+ word-wrap: normal !important;
469
+ }
470
+
471
+ .file-editor:focus {
472
+ border-color: var(--shadow-claw-accent-primary);
473
+ box-shadow: 0 0 0 0.125rem var(--shadow-claw-bg-tertiary);
474
+ outline: none;
475
+ }
476
+
477
+ .code-line {
478
+ border-left: 0.1875rem solid transparent;
479
+ display: inline-block;
480
+ padding-left: 0.5rem;
481
+ transition:
482
+ background-color 0.2s ease,
483
+ border-color 0.2s ease;
484
+ width: 100%;
485
+ }
486
+
487
+ .code-line.highlighted {
488
+ background-color: var(--shadow-claw-bg-tertiary);
489
+ border-left: 0.1875rem solid var(--shadow-claw-accent-primary);
490
+ }
491
+ `);const R=new DOMParser().parseFromString(`<template>
492
+ <shadow-claw-dialog dialog-class="file-modal" dialog-aria-label="File viewer">
493
+ <div class="modal-content">
494
+ <div class="modal-header">
495
+ <h3 class="modal-title">File:</h3>
496
+ <div class="modal-header-actions">
497
+ <button
498
+ aria-label="Share file"
499
+ class="modal-share-btn hidden"
500
+ type="button"
501
+ >
502
+ ↗<span class="btn-label"> Share</span>
503
+ </button>
504
+ <div class="modal-view-modes">
505
+ <button
506
+ aria-pressed="false"
507
+ aria-label="Edit file"
508
+ class="modal-edit-btn"
509
+ title="Edit"
510
+ type="button"
511
+ >
512
+ ✏️<span class="btn-label"> Edit</span>
513
+ </button>
514
+ <button
515
+ aria-pressed="false"
516
+ aria-label="Toggle preview mode"
517
+ class="modal-preview-btn"
518
+ title="Preview"
519
+ type="button"
520
+ >
521
+ 👁️<span class="btn-label"> Preview</span>
522
+ </button>
523
+ <button
524
+ aria-pressed="false"
525
+ aria-label="Enter fullscreen"
526
+ class="modal-fullscreen-btn"
527
+ title="Fullscreen"
528
+ type="button"
529
+ >
530
+ ⛶<span class="btn-label"> Fullscreen</span>
531
+ </button>
532
+ </div>
533
+ <button
534
+ aria-label="Discard changes"
535
+ class="modal-cancel-btn hidden"
536
+ title="Discard unsaved changes"
537
+ type="button"
538
+ >
539
+ ✕<span class="btn-label"> Cancel</span>
540
+ </button>
541
+ <button
542
+ aria-label="Save file"
543
+ class="modal-save-btn hidden"
544
+ type="button"
545
+ >
546
+ 💾<span class="btn-label"> Save</span>
547
+ </button>
548
+ <button
549
+ aria-label="Close file viewer"
550
+ class="modal-close-btn"
551
+ type="button"
552
+ >
553
+ &times;
554
+ </button>
555
+ </div>
556
+ </div>
557
+ <div class="modal-body">
558
+ <div class="file-content file-content--raw"></div>
559
+ <div class="file-editor-container">
560
+ <pre
561
+ class="file-editor-overlay"
562
+ aria-hidden="true"
563
+ ><code class="hljs"></code></pre>
564
+ <textarea
565
+ aria-label="File editor"
566
+ class="file-editor"
567
+ spellcheck="false"
568
+ ></textarea>
569
+ </div>
570
+ </div>
571
+ </div>
572
+ </shadow-claw-dialog>
573
+ </template>
574
+ `,`text/html`),z=R.querySelector(`template`);let B=[];B=z?Array.from(z.content.children):Array.from(R.head.children).concat(Array.from(R.body.children));var V=B;const H=`shadow-claw-file-viewer`,U=`components/${H}/highlightjs-atom-one-dark.min.css`,W=`pre code.hljs, code.hljs, .hljs { font-family: var(--shadow-claw-font-mono) !important; }`,G={ALLOWED_URI_REGEXP:/^(?:(?:https?|mailto|ftp|tel|file|blob|data):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i,ADD_TAGS:[`iframe`,`figure`,`figcaption`],CUSTOM_ELEMENT_HANDLING:{tagNameCheck:e=>m(e),attributeNameCheck:()=>!0,allowCustomizedBuiltInElements:!1},ADD_ATTR:[`allow`,`allowfullscreen`,`frameborder`,`scrolling`,`referrerpolicy`,`loading`]};function K(e,t){return!e||typeof e.transaction!=`function`||s(e,t).then(e=>w(e,!0)).catch(()=>!0)}var q=class extends S{static styles=L;static template=V;broadcastProxy=null;currentImageObjectUrls=[];currentObjectUrl=null;db=null;editorDraftContent=null;isEditorDirty=!1;isFileEditMode=!1;isFilePreviewMode=!1;isFullscreenMode=!1;lastOpenedFileName=``;previewFrameWindow=null;themeObserver=null;viewRenderToken=0;constructor(){super()}async connectedCallback(){if(!this.shadowRoot)throw Error(`shadowRoot not found`);this.setupEffects(),this.bindEventListeners(),this.broadcastProxy=new N(()=>this.previewFrameWindow||this.shadowRoot?.querySelector(`.file-content-iframe`)?.contentWindow||null),window.addEventListener(`message`,this.handleIframeMessage),document.addEventListener(`fullscreenchange`,this.handleFullscreenChange),this.themeObserver=new MutationObserver(e=>{for(let t of e)t.type===`attributes`&&t.attributeName===`class`&&this.syncIframeTheme()}),this.themeObserver.observe(document.documentElement,{attributes:!0,attributeFilter:[`class`]}),this.db=await o();try{let e=await fetch(U).then(e=>e.text());this.applyHighlightStyles(e)}catch(e){console.warn(`Failed to load highlight.js styles:`,e)}}disconnectedCallback(){this.broadcastProxy?.dispose(),this.broadcastProxy=null,window.removeEventListener(`message`,this.handleIframeMessage),document.removeEventListener(`fullscreenchange`,this.handleFullscreenChange),this.themeObserver&&=(this.themeObserver.disconnect(),null),this.revokeObjectUrl()}applyFullscreenMode(e){let t=e.querySelector(`.modal-content`);t instanceof HTMLElement&&t.classList.toggle(`modal-content--fullscreen`,this.isFullscreenMode);let n=e.querySelector(`.modal-fullscreen-btn`);n instanceof HTMLButtonElement&&(n.setAttribute(`aria-pressed`,String(this.isFullscreenMode)),n.setAttribute(`aria-label`,this.isFullscreenMode?`Exit fullscreen`:`Enter fullscreen`),n.title=this.isFullscreenMode?`Exit fullscreen`:`Fullscreen`)}applyHighlightStyles(e){let t=this.shadowRoot;if(!t)return;if(typeof CSSStyleSheet<`u`&&typeof CSSStyleSheet.prototype.replaceSync==`function`&&`adoptedStyleSheets`in t)try{let n=new CSSStyleSheet;n.replaceSync(e);let r=new CSSStyleSheet;r.replaceSync(W),t.adoptedStyleSheets=[...t.adoptedStyleSheets?Array.from(t.adoptedStyleSheets):[],n,r];return}catch{}let n=document.createElement(`style`);n.setAttribute(`data-shadow-claw-highlight-theme`,`true`),n.textContent=`${e}\n${W}`,t.appendChild(n)}bindEventListeners(){let e=this.shadowRoot;if(!e)return;e.querySelector(`.file-content`)?.addEventListener(`click`,e=>{this.handlePreviewLinkClick(e)});let t=e.querySelector(`.file-modal`);t?.addEventListener(`cancel`,e=>{e.preventDefault(),this.requestCloseViewer()}),t?.addEventListener(`close`,()=>{O.file&&O.closeFile()}),e.querySelector(`.modal-close-btn`)?.addEventListener(`click`,()=>void this.requestCloseViewer()),e.querySelector(`.modal-preview-btn`)?.addEventListener(`click`,async()=>{this.isFilePreviewMode=!this.isFilePreviewMode,this.isFileEditMode=!1,await this.updateView()}),e.querySelector(`.modal-fullscreen-btn`)?.addEventListener(`click`,()=>{t&&this.toggleFullscreenMode(t)}),e.querySelector(`.modal-share-btn`)?.addEventListener(`click`,async()=>{await this.handleShareFile()}),e.querySelector(`.modal-edit-btn`)?.addEventListener(`click`,async()=>{this.isFileEditMode=!this.isFileEditMode,this.isFileEditMode&&(this.isFilePreviewMode=!1),await this.updateView()}),e.querySelector(`.modal-save-btn`)?.addEventListener(`click`,()=>this.handleSave()),e.querySelector(`.modal-cancel-btn`)?.addEventListener(`click`,async()=>{this.isEditorDirty=!1,this.editorDraftContent=null,this.isFileEditMode=!1,await this.updateView()});let n=e.querySelector(`.file-editor`);if(n?.addEventListener(`input`,()=>{n instanceof HTMLTextAreaElement&&(this.editorDraftContent=n.value,this.updateEditorHighlight(n.value)),this.isEditorDirty=!0,this.updateView()}),n instanceof HTMLTextAreaElement){let t=()=>{let t=e.querySelector(`.file-editor-overlay`);t&&(t.scrollTop=n.scrollTop,t.scrollLeft=n.scrollLeft)};n.addEventListener(`scroll`,t),n.addEventListener(`focus`,t),n.addEventListener(`click`,t),n.addEventListener(`keyup`,t),n.addEventListener(`mouseup`,t),e.querySelector(`.modal-body`)?.addEventListener(`scroll`,t)}}buildWebShareFile(e){if(e?.nativeFile instanceof File)return e.nativeFile;let t=e?.binaryContent;if(!(t instanceof Uint8Array)||t.length===0)return null;let n=new Uint8Array(t.byteLength);return n.set(t),new File([n],e.name||`shared-file`,{type:e?.mimeType||`application/octet-stream`})}canShareCurrentFile(e){if(!e||!this.isWebShareAvailable())return!1;if(e.kind===`text`)return!0;let t=this.buildWebShareFile(e);if(!t||typeof navigator.canShare!=`function`)return!1;try{return navigator.canShare({files:[t]})}catch{return!1}}canUseNativeFullscreen(e){return document.fullscreenEnabled===!0&&(typeof e.requestFullscreen==`function`||typeof e.webkitRequestFullscreen==`function`)&&(typeof document.exitFullscreen==`function`||typeof document.webkitExitFullscreen==`function`)}getCurrentFullscreenElement(){return document.fullscreenElement||document.webkitFullscreenElement||null}getFullscreenTarget(e){let t=e.querySelector(`.modal-content`);return t instanceof HTMLElement?t:null}getIframeBridgeScriptUrl(){return n(`/assets/file-viewer-preview-bridge.js`)}getIframeSandboxPermissions(e){return/\.svg$/i.test(e)?`allow-modals allow-popups allow-popups-to-escape-sandbox`:u()}getLanguageFromFilename(e){return{bash:`bash`,cjs:`javascript`,css:`css`,html:`xml`,java:`java`,javascript:`javascript`,js:`javascript`,json:`json`,jsx:`jsx`,markdown:`markdown`,md:`markdown`,mjs:`javascript`,php:`php`,python:`python`,py:`python`,ruby:`ruby`,rb:`ruby`,rust:`rust`,rs:`rust`,sh:`bash`,sql:`sql`,svg:`xml`,ts:`typescript`,tsx:`tsx`,xml:`xml`,yaml:`yaml`,yml:`yaml`}[e.toLowerCase().split(`.`).pop()||``]||``}getPreviewSourceFile(e,t){return this.getWorkingSourceFile(e,t)}getWorkingSourceFile(e,t){if(!this.isEditorDirty||e?.kind!==`text`)return e;if(typeof this.editorDraftContent==`string`)return{...e,content:this.editorDraftContent};let n=t.querySelector(`.file-editor`);return n instanceof HTMLTextAreaElement?{...e,content:n.value}:e}getWorkspaceRouteTarget(e,t={}){let{allowCrossGroup:n=!1}=t,i=e.split(/[?#]/,1)[0].trim();if(!i)return null;if(/^[a-zA-Z][a-zA-Z\d+.-]*:/u.test(i)||i.startsWith(`//`)){let e;try{e=new URL(i,window.location.href)}catch{return null}if(e.origin!==window.location.origin)return null;i=e.pathname}let a=i.replace(/^(?:\.\/)+/u,``),o=[];if(a.startsWith(`files/`)&&o.push(`/${a}`),i.startsWith(`/`)){let e=i.lastIndexOf(`/files/`);e>0&&o.push(i.slice(e)),o.push(i)}for(let e of o){let t=r(e);if(!t)continue;let i=this.resolveRouteGroupId(t.groupId);if(i&&!(!n&&i!==y.activeGroupId))return{groupId:i,path:t.path}}return null}handleAnchorNavigation(e){let t=this.shadowRoot;if(!t)return!1;let n=t.querySelector(`.file-content`);if(!n)return!1;n.querySelectorAll(`.code-line.highlighted`).forEach(e=>{e.classList.remove(`highlighted`)});let r=e.match(/^#?L(\d+)(?:-L?(\d+))?$/i);if(r){let e=parseInt(r[1],10),t=r[2]?parseInt(r[2],10):e,i=null;return n.querySelectorAll(`.code-line`).forEach(n=>{let r=parseInt(n.getAttribute(`data-line`)||`0`,10);r>=e&&r<=t&&(n.classList.add(`highlighted`),i||=n)}),i?(i.scrollIntoView({behavior:`smooth`,block:`center`}),!0):!1}else{let t=e.replace(/^#/,``),r=n.querySelector(`[id="${t}"]`)||n.querySelector(`a[name="${t}"]`);return r?(r.scrollIntoView({behavior:`smooth`,block:`start`}),!0):!1}}handleFullscreenChange=()=>{let e=this.shadowRoot;if(!e)return;let t=e.querySelector(`.file-modal`);if(!(t instanceof HTMLElement))return;let n=this.getFullscreenTarget(t);this.isFullscreenMode=this.isTargetInFullscreen(n),this.applyFullscreenMode(t)};handleIframeMessage=e=>{if(!e.data||typeof e.data!=`object`)return;let r=e.data;if(r.type===`shadow-claw-broadcast-result`&&typeof r.channel==`string`){this.broadcastProxy?.handleResultFromIframe(e.source,r.channel,r.payload);return}if(r.type===`shadow-claw-iframe-resize`&&typeof r.height==`number`){let t=this.shadowRoot?.querySelector(`.file-content-iframe`);t instanceof HTMLIFrameElement&&(!this.previewFrameWindow||e.source===this.previewFrameWindow||t.contentWindow&&e.source===t.contentWindow)&&(this.previewFrameWindow=t.contentWindow,t.style.setProperty(`height`,`${r.height}px`,`important`));return}if(r.type===`shadow-claw-storage-proxy`){if(this.previewFrameWindow&&e.source!==this.previewFrameWindow)return;let t=r;this.handleStorageProxyRequest(e.source,String(t.requestId||``),String(t.method||``),t.args&&typeof t.args==`object`?t.args:{});return}if(!this.db||r.type!==`shadow-claw-file-viewer-link`||typeof r.href!=`string`||this.previewFrameWindow&&e.source!==this.previewFrameWindow)return;let o=O.file,s=o?.path||o?.name||``,c=n(t(y.activeGroupId,s)),l=a(r.href,c,window.location.origin);if(!l)return;if(l.searchParams.has(`gameSave`)){this.reloadPreviewWithSearchParams(l.search);return}if(!(l.origin===window.location.origin&&(i(l.pathname)||this.resolveWorkspaceLinkPath(r.href,s)))){window.open(l.href,`_blank`,`noopener,noreferrer`);return}let u=`${l.pathname}${l.search}${l.hash}`,d=window.navigation;if(d&&typeof d.navigate==`function`){d.navigate(u);return}window.history.pushState({},``,u),window.dispatchEvent(new PopStateEvent(`popstate`))};hasUnsavedChanges(){return this.isEditorDirty}isIframePreviewFile(e){return/\.(?:html?|svg)$/i.test(e)}isMarkdownLikeFile(e){return/(?:^readme$|\.mdx?$|\.markdown$|\.mdown$)/i.test(e)}isNodeInComposedTree(e,t){let n=e;for(;n;){if(n===t)return!0;if(n.parentNode){n=n.parentNode;continue}let e=n.getRootNode?.();if(e instanceof ShadowRoot&&e.host){n=e.host;continue}n=null}return!1}isRenderTokenCurrent(e){return this.viewRenderToken===e}isTargetInFullscreen(e){if(!e)return!1;let t=this.getCurrentFullscreenElement();return t?t===e||this.isNodeInComposedTree(e,t)||this.isNodeInComposedTree(t,e):!1}isWebShareAvailable(){return typeof navigator<`u`&&typeof navigator.share==`function`}mimeTypeForImageExt(e){return{apng:`image/apng`,avif:`image/avif`,gif:`image/gif`,jpg:`image/jpeg`,jpeg:`image/jpeg`,png:`image/png`,svg:`image/svg+xml`,webp:`image/webp`}[e]??`image/jpeg`}renderBinaryPreview(e,t){let n=t.mimeType||`application/octet-stream`;if(t.nativeFile instanceof File)this.currentObjectUrl=URL.createObjectURL(t.nativeFile);else{let r=t.binaryContent;if(!(r instanceof Uint8Array)||r.length===0){e.classList.remove(`file-content--raw`,`file-content--iframe`),e.classList.add(`file-content--preview`),e.textContent=`Binary content unavailable.`;return}let i=new Uint8Array(r.byteLength);i.set(r);let a=new Blob([i],{type:n});this.currentObjectUrl=URL.createObjectURL(a)}if(e.classList.remove(`file-content--raw`,`file-content--preview`),e.classList.add(`file-content--iframe`),n.startsWith(`image/`)){let n=document.createElement(`img`);n.className=`file-content-iframe`,n.alt=`Preview: ${t.name}`,n.src=this.currentObjectUrl,n.style.objectFit=`contain`,e.replaceChildren(n);return}if(n.startsWith(`video/`)){let t=document.createElement(`video`);t.className=`file-content-iframe`,t.controls=!0,t.src=this.currentObjectUrl,t.style.backgroundColor=`black`,e.replaceChildren(t);return}if(n.startsWith(`audio/`)){let n=document.createElement(`div`);n.className=`file-content file-content--preview`,n.style.padding=`1rem`;let r=document.createElement(`p`);r.textContent=t.name;let i=document.createElement(`audio`);i.controls=!0,i.src=this.currentObjectUrl,i.style.width=`100%`,n.replaceChildren(r,i),e.replaceChildren(n),e.classList.remove(`file-content--iframe`);return}let r=document.createElement(`iframe`);r.className=`file-content-iframe`,r.setAttribute(`title`,`Preview: ${t.name}`),r.setAttribute(`referrerpolicy`,`no-referrer`),r.src=this.currentObjectUrl,e.replaceChildren(r)}resetContent(){let e=this.shadowRoot;if(!e)return;let t=e.querySelector(`.file-modal`);if(!(t instanceof HTMLElement))return;let n=this.getFullscreenTarget(t);n&&this.isTargetInFullscreen(n)&&this.exitNativeFullscreen().catch(()=>{}),this.isFullscreenMode=!1,this.applyFullscreenMode(t);let r=t.querySelector(`.file-content`),i=t.querySelector(`.modal-preview-btn`);i instanceof HTMLButtonElement&&(i.setAttribute(`aria-pressed`,`false`),i.setAttribute(`aria-label`,`Switch to preview mode`));let a=t.querySelector(`.modal-edit-btn`);a instanceof HTMLButtonElement&&(a.setAttribute(`aria-pressed`,`false`),a.setAttribute(`aria-label`,`Edit file`),a.classList.remove(`hidden`));let o=t.querySelector(`.modal-close-btn`);o instanceof HTMLButtonElement&&(o.disabled=!1,o.setAttribute(`aria-label`,`Close file viewer`),o.title=`Close`),t.querySelector(`.modal-save-btn`)?.classList.add(`hidden`),t.querySelector(`.file-editor-container`)?.classList.remove(`active`),t.querySelector(`.modal-body`)?.classList.remove(`modal-body--editing`);let s=t.querySelector(`.file-editor`);s instanceof HTMLTextAreaElement&&(s.value=``,s.removeAttribute(`language`));let c=t.querySelector(`.file-editor-overlay code`);c&&(c.innerHTML=``,c.className=`hljs`),this.isFileEditMode=!1,this.editorDraftContent=null,r instanceof HTMLElement&&(this.revokeObjectUrl(),r.classList.remove(`hidden`),r.classList.add(`file-content--raw`),r.classList.remove(`file-content--preview`,`file-content--iframe`),r.textContent=``)}resolveRouteGroupId(e){let t=y.activeGroupId;if(e===t||this.routeGroupMatches(e,t))return t;let n=Array.isArray(y.groups)?y.groups:[],r=n.find(t=>t.groupId===e);if(r)return r.groupId;let i=n.find(t=>this.routeGroupMatches(e,t.groupId));return i?i.groupId:e||null}resolveWorkspaceLinkPath(e,t=``){let n=e.trim();if(!n||n.startsWith(`#`))return null;let r=n,i=/^[a-zA-Z][a-zA-Z\d+.-]*:/.test(n);if(i||n.startsWith(`//`)){let e;try{e=new URL(n,window.location.href)}catch{return null}if(!(e.protocol===`http:`||e.protocol===`https:`)||e.host!==window.location.host)return null;r=`${e.pathname}${e.search}${e.hash}`}let a=this.getWorkspaceRouteTarget(r);if(a)return a.path;let o=r.split(/[?#]/,1)[0].replace(/\\/g,`/`),s=o.startsWith(`/`);if(i||s||(o=o.replace(/^\/+/,``),!o))return null;let c=[];if(!s){let e=t.replace(/\\/g,`/`).replace(/^\/+/,``).split(`/`).filter(Boolean);e.pop(),c.push(...e)}for(let e of o.split(`/`))if(!(!e||e===`.`)){if(e===`..`){if(c.length===0)return null;c.pop();continue}c.push(e)}return c.length>0?c.join(`/`):null}revokeObjectUrl(){this.previewFrameWindow=null,this.currentObjectUrl&&=(URL.revokeObjectURL(this.currentObjectUrl),null);for(let e of this.currentImageObjectUrls)URL.revokeObjectURL(e);this.currentImageObjectUrls=[]}rewriteWorkspacePreviewHtml(e,r){if(!e)return e;let o=n(t(y.activeGroupId,r)),s=new DOMParser().parseFromString(e,`text/html`),c=(e,t)=>{let n=Array.from(s.querySelectorAll(e));for(let e of n){let n=(e.getAttribute(t)||``).trim();if(!n||n.startsWith(`#`)||n.startsWith(`javascript:`))continue;let s=a(n,o,window.location.origin);!s||s.origin!==window.location.origin||t===`href`&&!(i(s.pathname)||this.resolveWorkspaceLinkPath(n,r))||e.setAttribute(t,`${s.pathname}${s.search}${s.hash}`)}};return c(`a[href]`,`href`),c(`img[src]`,`src`),c(`audio[src]`,`src`),c(`video[src]`,`src`),c(`source[src]`,`src`),s.body.innerHTML}routeGroupMatches(e,t){if(e===t||e===`main`&&t===`br:main`||e===`br:main`&&t===`main`)return!0;if(!e.includes(`:`)&&!t.includes(`:`))return!1;let n=e=>e.trim().replace(/:/g,`-`);return n(e)===n(t)}setupEffects(){C(()=>{let e=_.declarativeTools;this.broadcastProxy&&e.length>0&&this.broadcastProxy.registerChannelsFromTools(e)}),C(()=>{let e=O.file,t=++this.viewRenderToken,n=this.shadowRoot;if(!n)return;let r=n.querySelector(`shadow-claw-dialog`);r&&typeof r.ensureDialog==`function`&&r.ensureDialog();let i=n.querySelector(`.file-modal`);if(e){r&&typeof r.showModal==`function`&&!r.open?r.showModal():i instanceof HTMLDialogElement&&!i.open&&i.showModal();let a=n.querySelector(`.modal-title`);a instanceof HTMLElement&&(a.textContent=`File: ${e.name}`),this.lastOpenedFileName!==e.name&&(this.lastOpenedFileName=e.name,this.isFilePreviewMode=this.shouldAutoPreview(e),this.isFileEditMode=!1,this.isEditorDirty=!1,this.editorDraftContent=null),this.updateView(t)}else r&&typeof r.close==`function`&&r.open?r.close():i instanceof HTMLDialogElement&&i.open&&i.close(),this.lastOpenedFileName=``,this.isFilePreviewMode=!1,this.isEditorDirty=!1,this.editorDraftContent=null,this.resetContent()})}shouldAutoPreview(e){return!e||typeof e!=`object`?!1:e.kind===`pdf`||e.kind===`binary`?!0:e.kind===`text`?this.isIframePreviewFile(e.name)||this.isMarkdownLikeFile(e.name):!1}stripHtmlFrontmatter(e){if(typeof e!=`string`||!e.trimStart().startsWith(`---`))return e;let t=T(e);return Object.keys(t.data||{}).length===0?e:t.content||``}toPreviewMarkdown(e){return this.isMarkdownLikeFile(e.name)?e.content:"```"+this.getLanguageFromFilename(e.name)+`
575
+ `+e.content+"\n```"}updateEditorHighlight(e){let t=this.shadowRoot;if(!t)return;let n=t.querySelector(`.file-editor-overlay code`);if(!n)return;let r=O.file,i=this.getLanguageFromFilename(r?.name||``),a=``;try{a=i&&E.getLanguage(i)?E.highlight(e,{language:i}).value:E.highlightAuto(e).value}catch{a=e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}n.className=i?`hljs language-${i}`:`hljs`,n.innerHTML=l(a+`<br>`)}wrapCodeLines(e){e.querySelectorAll(`pre code`).forEach(e=>{let t=e.innerHTML.split(/\r?\n/u);t.length>1&&t[t.length-1]===``&&t.pop(),h(e,t.map((e,t)=>`<span class="code-line" data-line="${t+1}">${e||`&nbsp;`}</span>`).join(`
576
+ `))})}async buildIframePreviewSrcdoc(e,r=``){if(/\.svg$/i.test(e.name))return e.content;let i=e.path||e.name||``,a=this.stripHtmlFrontmatter(e.content||``),o=this.rewriteWorkspacePreviewHtml(a,i),s=d(await this.resolveRelativeImagesInHtml(o,i),G),c=crypto.randomUUID().replace(/-/g,``),l=this.getIframeBridgeScriptUrl(),u=n(`/assets/iframe-storage-bridge.js`),m=f(),h=p(c),g=typeof document<`u`?document.getElementById(`shadow-claw-site-config`):null,_=g&&g.textContent?`<script id="shadow-claw-site-config" type="application/json">${g.textContent}<\/script>`:``,v=r?`<script nonce="${c}">(function(){try{Object.defineProperty(window.location,"search",{get:function(){return ${JSON.stringify(r)};},configurable:true});}catch(e){}})();<\/script>`:``,b=m.map(e=>`<script type="module" src="${e.startsWith(`http://`)||e.startsWith(`https://`)||e.startsWith(`//`)?e:n(e.startsWith(`/`)?e:`/${e.replace(/^pages\/main\//,``)}`)}" nonce="${c}"><\/script>`).join(`
577
+ `),x=`<link rel="stylesheet" href="${n(`/theme.css`)}">`;return[`<!doctype html>`,`<html class="${F()}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">`,`<meta http-equiv="Content-Security-Policy" content="${h}">`,`<base href="${n(t(y.activeGroupId,i))}" target="_blank">`,v,_,`<script src="${u}" nonce="${c}"><\/script>`,`<script src="${l}" nonce="${c}"><\/script>`,A(),x,b,`</head><body>`,s,`</body></html>`].join(``)}async canDismissViewer(){if(!this.hasUnsavedChanges())return!0;let e=await this.requestConfirmation({title:`Discard Unsaved Changes`,message:`You have unsaved changes. Discard them and close?`,confirmLabel:`Discard`,cancelLabel:`Keep Editing`});return e&&(this.isEditorDirty=!1,this.editorDraftContent=null),e}async exitFullscreenIfActive(e){let t=this.shadowRoot,n=e||t?.querySelector(`.file-modal`);if(!n)return;let r=this.getFullscreenTarget(n);if(!(!r||!this.isTargetInFullscreen(r)))try{await this.exitNativeFullscreen()}catch{}}async exitNativeFullscreen(){let e=document.exitFullscreen||document.webkitExitFullscreen;if(typeof e!=`function`)throw Error(`Native fullscreen exit unavailable`);await Promise.resolve(e.call(document))}async handlePreviewLinkClick(e){if(e.defaultPrevented||e.button!==0||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)return;let r=e.target;if(!(r instanceof Element))return;let o=r.closest(`a`);if(!(o instanceof HTMLAnchorElement)||!this.db)return;let s=O.file,c=s?.path||s?.name||``,l=o.getAttribute(`href`)||``,u=a(l,n(t(y.activeGroupId,c)),window.location.origin);if(u&&u.origin===window.location.origin&&(i(u.pathname)||this.resolveWorkspaceLinkPath(l,c))&&u){e.preventDefault();let t=`${u.pathname}${u.search}${u.hash}`,n=window.navigation;n&&typeof n.navigate==`function`?n.navigate(t):(window.history.pushState({},``,t),window.dispatchEvent(new PopStateEvent(`popstate`)));return}let d=l.trim();if(d&&!d.startsWith(`#`)&&!d.startsWith(`javascript:`)){let t=o.getAttribute(`target`)||`_blank`,n=t===`_self`||t===`_top`||t===`_parent`?`_blank`:t;try{new URL(d,window.location.href).host!==window.location.host&&(e.preventDefault(),window.open(d,n,`noopener,noreferrer`))}catch{/^[a-zA-Z][a-zA-Z\d+.-]*:/u.test(d)&&(e.preventDefault(),window.open(d,n,`noopener,noreferrer`))}}}async handleSave(){let e=O.file;if(!e||!this.db)return;let t=this.shadowRoot,n=t?.querySelector(`.modal-save-btn`),r=t?.querySelector(`.file-editor`);if(r instanceof HTMLTextAreaElement)try{n instanceof HTMLButtonElement&&(n.disabled=!0,n.textContent=`⏳ saving...`);let t=r.value,i=e.path||(y.currentPath===`.`?e.name:`${y.currentPath}/${e.name}`),a=e.groupId||y.activeGroupId;await v(this.db,a,i,t),b(`Saved ${e.name}`),document.dispatchEvent(new CustomEvent(`shadow-claw-file-saved`,{detail:{groupId:a,path:i},bubbles:!0,composed:!0})),await y.loadFiles(this.db),e.content=t,this.isFileEditMode=!1,this.isEditorDirty=!1,this.editorDraftContent=null,await this.updateView()}catch(e){x(`Failed to save file: ${e instanceof Error?e.message:String(e)}`)}finally{n instanceof HTMLButtonElement&&(n.disabled=!1,n.textContent=`💾 Save`)}}async handleShareFile(){let e=O.file;if(!e||!this.canShareCurrentFile(e)){x(`Sharing is not supported for this file on this device.`,4500);return}try{if(e.kind===`text`)await navigator.share({title:e.name,text:e.content||``});else{let t=this.buildWebShareFile(e);if(!t||!navigator.canShare?.({files:[t]})){x(`File sharing is not supported on this device.`,4500);return}await navigator.share({title:e.name,files:[t]})}b(`Shared ${e.name}`)}catch(e){if(e instanceof DOMException&&e.name===`AbortError`)return;x(`Failed to share file: ${e instanceof Error?e.message:String(e)}`,5e3)}}async openFolderInFilesView(e){if(!this.db)return;let t=e.replace(/^\/+|\/+$/g,``);if(t)try{await y.setCurrentPath(this.db,t),O.closeFile();let e=window?.shadowclaw?.ui;e&&typeof e.showPage==`function`&&e.showPage(`files`)}catch(e){x(`Failed to open linked folder: ${e instanceof Error?e.message:String(e)}`,5e3)}}async openWorkspaceLink(e,t){if(!this.db)return;let n=this.resolveWorkspaceLinkPath(e,t);if(!n)return;let r=n.split(`/`).filter(Boolean).pop()||``;if(!/\.[^./]+$/u.test(r)){try{await O.openFile(this.db,n,y.activeGroupId);return}catch(e){let t=e instanceof DOMException&&e.name===`NotFoundError`,n=e instanceof DOMException&&e.name===`TypeMismatchError`;if(!t&&!n){x(`Failed to open linked file: ${e instanceof Error?e.message:String(e)}`,5e3);return}}await this.openFolderInFilesView(n);return}try{await O.openFile(this.db,n,y.activeGroupId)}catch(e){x(`Failed to open linked file: ${e instanceof Error?e.message:String(e)}`,5e3)}}async renderPreview(t,n,r=this.viewRenderToken){if(!this.isRenderTokenCurrent(r))return;if(this.revokeObjectUrl(),this.previewFrameWindow=null,n.kind===`pdf`){t.classList.remove(`file-content--raw`,`file-content--preview`,`file-content--iframe`),import(`./shadow-claw-pdf-viewer-gOiW-_Bh.js`).then(()=>{let e=document.createElement(`shadow-claw-pdf-viewer`);e.file=n,t.replaceChildren(e)}).catch(console.error);return}if(n.kind===`binary`){this.renderBinaryPreview(t,n);return}if(this.isIframePreviewFile(n.name)){t.classList.remove(`file-content--raw`,`file-content--preview`),t.classList.add(`file-content--iframe`);let e=document.createElement(`iframe`);e.className=`file-content-iframe`,e.setAttribute(`title`,`Preview: ${n.name}`),e.setAttribute(`sandbox`,this.getIframeSandboxPermissions(n.name)),e.setAttribute(`allow`,`fullscreen`),e.setAttribute(`referrerpolicy`,`no-referrer`),c(e,await this.buildIframePreviewSrcdoc(n)),e.addEventListener(`load`,()=>{this.previewFrameWindow=e.contentWindow,this.syncIframeTheme()}),t.replaceChildren(e);return}t.classList.remove(`file-content--raw`),t.classList.add(`file-content--preview`);let i=O.file,a=i?.path||i?.name||``,o=this.toPreviewMarkdown(n),s=K(this.db,e.MARKDOWN_FRONTMATTER_FILE_VIEWER),l=await D(o,{renderFrontmatter:typeof s==`boolean`?s:await s});if(!this.isRenderTokenCurrent(r))return;let u=this.rewriteWorkspacePreviewHtml(l,a);this.isRenderTokenCurrent(r)&&(h(t,u,G),this.wrapCodeLines(t),await this.resolveMarkdownImages(t,a))}async requestCloseViewer(){return await this.canDismissViewer()?(await this.exitFullscreenIfActive(),O.closeFile(),!0):!1}async requestConfirmation(e){let t=document.querySelector(`shadow-claw`);return t&&typeof t.requestDialog==`function`?await t.requestDialog({mode:`confirm`,...e}):!1}async requestNativeFullscreen(e){let t=e.requestFullscreen||e.webkitRequestFullscreen;if(typeof t!=`function`)throw Error(`Native fullscreen unavailable`);await Promise.resolve(t.call(e))}async resolveMarkdownImages(e,t){if(!this.db)return;let n=Array.from(e.querySelectorAll(`img`));n.length!==0&&await Promise.all(n.map(async e=>{let n=e.getAttribute(`src`)||``;if(!n||/^(?:blob:|data:|#)/u.test(n))return;let r=this.getWorkspaceRouteTarget(n,{allowCrossGroup:!0})||(()=>{let e=this.resolveWorkspaceLinkPath(n,t);return e?{groupId:y.activeGroupId,path:e}:null})();if(r)try{let t=await g(this.db,r.groupId,r.path),n=r.path.split(`.`).pop()?.toLowerCase()||``,i=this.mimeTypeForImageExt(n),a=new Uint8Array(t.byteLength);a.set(t),e.src=await new Promise((e,t)=>{let n=new FileReader;n.onload=()=>e(n.result),n.onerror=t,n.readAsDataURL(new Blob([a],{type:i}))})}catch{}}))}async resolveRelativeImagesInHtml(e,t){if(!this.db||!e)return e;let n=new DOMParser().parseFromString(e,`text/html`),r=Array.from(n.querySelectorAll(`img`));return r.length===0?e:(await Promise.all(r.map(async e=>{let n=e.getAttribute(`src`)||``;if(!n||/^(?:blob:|data:|#)/u.test(n))return;let r=this.getWorkspaceRouteTarget(n,{allowCrossGroup:!0})||(()=>{let e=this.resolveWorkspaceLinkPath(n,t);return e?{groupId:y.activeGroupId,path:e}:null})();if(r)try{let t=await g(this.db,r.groupId,r.path),n=r.path.split(`.`).pop()?.toLowerCase()||``,i=this.mimeTypeForImageExt(n),a=new Uint8Array(t.byteLength);a.set(t);let o=await new Promise((e,t)=>{let n=new FileReader;n.onload=()=>e(n.result),n.onerror=t,n.readAsDataURL(new Blob([a],{type:i}))});e.setAttribute(`src`,o)}catch{}})),n.body.innerHTML)}async toggleFullscreenMode(e){let t=this.getFullscreenTarget(e);if(t){if(this.canUseNativeFullscreen(t)){let n=this.isTargetInFullscreen(t);try{n?(await this.exitNativeFullscreen(),this.isFullscreenMode=!1):(await this.requestNativeFullscreen(t),this.isFullscreenMode=!0)}catch{this.isFullscreenMode=!this.isFullscreenMode}this.applyFullscreenMode(e);return}this.isFullscreenMode=!this.isFullscreenMode,this.applyFullscreenMode(e)}}async updateView(e=this.viewRenderToken){let t=O.file,n=this.shadowRoot;if(!n||!t)return;let r=n.querySelector(`.file-modal`);if(!(r instanceof HTMLElement))return;this.applyFullscreenMode(r);let i=r.querySelector(`.file-content`),a=r.querySelector(`.modal-preview-btn`),o=r.querySelector(`.modal-body`);if(!(i instanceof HTMLElement))return;i.classList.remove(`file-content--iframe`);let s=this.getWorkingSourceFile(t,r),c=t.kind===`text`;a instanceof HTMLButtonElement&&(a.setAttribute(`aria-pressed`,String(this.isFilePreviewMode)),a.setAttribute(`aria-label`,this.isFilePreviewMode?`Switch to raw text view`:`Switch to preview mode`));let l=r.querySelector(`.file-editor-container`),u=r.querySelector(`.modal-edit-btn`),d=r.querySelector(`.modal-save-btn`),f=r.querySelector(`.modal-share-btn`),p=r.querySelector(`.modal-close-btn`),m=r.querySelector(`.modal-cancel-btn`);if(f instanceof HTMLButtonElement){let e=this.canShareCurrentFile(t);f.classList.toggle(`hidden`,!e),f.disabled=!e}if(p instanceof HTMLButtonElement){let e=this.hasUnsavedChanges();p.disabled=!1,p.setAttribute(`aria-label`,e?`Close file viewer (unsaved changes)`:`Close file viewer`),p.title=e?`Close (you have unsaved changes)`:`Close`}let h=this.hasUnsavedChanges();if(d instanceof HTMLButtonElement&&d.classList.toggle(`hidden`,!h),m instanceof HTMLButtonElement&&m.classList.toggle(`hidden`,!h),this.isFilePreviewMode){o?.classList.remove(`modal-body--editing`),i.classList.remove(`hidden`),l?.classList.remove(`active`),u instanceof HTMLButtonElement&&(u.setAttribute(`aria-pressed`,`false`),u.setAttribute(`aria-label`,`Edit file`),u.classList.toggle(`hidden`,!c)),await this.renderPreview(i,s,e);return}if(this.isRenderTokenCurrent(e))if(this.isFileEditMode&&c){o?.classList.add(`modal-body--editing`),i.classList.add(`hidden`),l?.classList.add(`active`),u instanceof HTMLButtonElement&&(u.setAttribute(`aria-pressed`,`true`),u.setAttribute(`aria-label`,`Switch to raw text view`),u.classList.remove(`hidden`));let e=l?.querySelector(`.file-editor`);if(e instanceof HTMLTextAreaElement){e.setAttribute(`tab-size`,`2`);let n=this.getLanguageFromFilename(t.name);if(n?e.setAttribute(`language`,n):e.removeAttribute(`language`),this.isEditorDirty)typeof s?.content==`string`&&(e.value!==s.content&&(e.value=s.content),this.updateEditorHighlight(e.value));else{let n=t.content||``;e.value!==n&&(e.value=n),this.updateEditorHighlight(e.value)}e.dispatchEvent(new Event(`scroll`))}}else o?.classList.remove(`modal-body--editing`),i.classList.remove(`hidden`),l?.classList.remove(`active`),u instanceof HTMLButtonElement&&(u.setAttribute(`aria-pressed`,`false`),u.setAttribute(`aria-label`,`Edit file`),u.classList.toggle(`hidden`,!c)),i.classList.add(`file-content--raw`),i.classList.remove(`file-content--preview`,`file-content--iframe`),t.kind===`binary`?i.textContent=`Binary file (${t.mimeType||`application/octet-stream`}). Switch to Preview to view.`:i.textContent=s.content||``}syncIframeTheme(){if(!this.previewFrameWindow)return;let e=document.documentElement.classList.contains(`dark-mode`),t=getComputedStyle(document.documentElement),n={};for(let e=0;e<t.length;e++){let r=t[e];r.startsWith(`--`)&&(n[r]=t.getPropertyValue(r))}this.previewFrameWindow.postMessage({type:`shadow-claw-theme-update`,theme:e?`dark`:`light`,customProperties:n},`*`)}async handleStorageProxyRequest(e,t,n,r){if(!t)return;let i=O.file,a=i?.path||i?.name||`__default__`;try{let i;switch(n){case`setItem`:await k(a,String(r.key||``),r.value);break;case`removeItem`:await M(a,String(r.key||``));break;case`clear`:await I(a);break;case`getAllItems`:i=await j(a);break;case`idb-get`:i=await P(`${a}::idb::${r.dbName}::${r.storeName}`,String(r.key||``));break;case`idb-getAll`:i=await j(`${a}::idb::${r.dbName}::${r.storeName}`);break;case`idb-put`:{let e=r.key==null?`__auto_${Date.now()}`:String(r.key);await k(`${a}::idb::${r.dbName}::${r.storeName}`,e,r.value),i=e;break}case`idb-delete`:await M(`${a}::idb::${r.dbName}::${r.storeName}`,String(r.key||``));break;case`idb-clear`:await I(`${a}::idb::${r.dbName}::${r.storeName}`);break;case`idb-deleteDatabase`:await I(`${a}::idb::${r.dbName}::__default__`);break;default:throw Error(`Unknown storage proxy method: ${n}`)}e.postMessage({type:`shadow-claw-storage-proxy-result`,requestId:t,result:i??null},`*`)}catch(n){e.postMessage({type:`shadow-claw-storage-proxy-result`,requestId:t,error:n instanceof Error?n.message:String(n)},`*`)}}async reloadPreviewWithSearchParams(e){let t=O.file;if(!t)return;let n=this.shadowRoot?.querySelector(`.file-viewer__iframe`);n&&(this.previewFrameWindow=null,c(n,await this.buildIframePreviewSrcdoc(t,e)))}};customElements.get(H)||customElements.define(H,q);export{q as ShadowClawFileViewer};