@brftech/filex 0.1.56 → 0.1.60

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 (37) hide show
  1. package/LICENSE +21 -21
  2. package/dist/{ArchiveViewer-CMaBM4yZ.js → ArchiveViewer-BotnnnoW.js} +13 -13
  3. package/dist/ArchiveViewer-BotnnnoW.js.map +1 -0
  4. package/dist/{CsvViewer-D5_c7bkP.js → CsvViewer-CrwZZqmq.js} +3 -3
  5. package/dist/CsvViewer-CrwZZqmq.js.map +1 -0
  6. package/dist/{DrawioViewer-CBOqWzaj.js → DrawioViewer-uEJbt6hj.js} +3 -3
  7. package/dist/DrawioViewer-uEJbt6hj.js.map +1 -0
  8. package/dist/{EpubViewer-Cs6yZIP2.js → EpubViewer-mCV3ZEXb.js} +3 -3
  9. package/dist/EpubViewer-mCV3ZEXb.js.map +1 -0
  10. package/dist/{IpynbViewer-wJhbhUla.js → IpynbViewer-B3g-lJfV.js} +3 -3
  11. package/dist/IpynbViewer-B3g-lJfV.js.map +1 -0
  12. package/dist/{MermaidViewer-k_XVXoc5.js → MermaidViewer-B0Q0ghbV.js} +3 -3
  13. package/dist/MermaidViewer-B0Q0ghbV.js.map +1 -0
  14. package/dist/{PsdViewer-Bo4imBCF.js → PsdViewer-lk6xrjRB.js} +8 -8
  15. package/dist/PsdViewer-lk6xrjRB.js.map +1 -0
  16. package/dist/{TiffViewer-D73-Gyt-.js → TiffViewer-PXjYKqzo.js} +3 -3
  17. package/dist/TiffViewer-PXjYKqzo.js.map +1 -0
  18. package/dist/{Viewer3D-Ba-RPIRz.js → Viewer3D-DtT-hBa3.js} +4 -4
  19. package/dist/Viewer3D-DtT-hBa3.js.map +1 -0
  20. package/dist/filex.js +1 -1
  21. package/dist/filex.umd.cjs +13 -13
  22. package/dist/filex.umd.cjs.map +1 -1
  23. package/dist/{index-idz8Cz5t.js → index-BNs90VaG.js} +378 -378
  24. package/dist/index-BNs90VaG.js.map +1 -0
  25. package/dist/style.css +1 -1
  26. package/dist/useViewerFetch-czqbd2Lj.js.map +1 -1
  27. package/package.json +2 -2
  28. package/dist/ArchiveViewer-CMaBM4yZ.js.map +0 -1
  29. package/dist/CsvViewer-D5_c7bkP.js.map +0 -1
  30. package/dist/DrawioViewer-CBOqWzaj.js.map +0 -1
  31. package/dist/EpubViewer-Cs6yZIP2.js.map +0 -1
  32. package/dist/IpynbViewer-wJhbhUla.js.map +0 -1
  33. package/dist/MermaidViewer-k_XVXoc5.js.map +0 -1
  34. package/dist/PsdViewer-Bo4imBCF.js.map +0 -1
  35. package/dist/TiffViewer-D73-Gyt-.js.map +0 -1
  36. package/dist/Viewer3D-Ba-RPIRz.js.map +0 -1
  37. package/dist/index-idz8Cz5t.js.map +0 -1
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- .filex-tag-picker[data-v-0cce6f92]{display:flex;flex-wrap:wrap;gap:6px;align-items:center}.filex-tag-picker.is-loading[data-v-0cce6f92]{opacity:.6;pointer-events:none}.filex-tag[data-v-0cce6f92]{display:inline-flex;align-items:center;gap:4px;border-radius:999px;padding:2px 10px;font-size:12px;font-weight:500;color:#fff;background:var(--filex-tag-color)}.filex-tag-x[data-v-0cce6f92]{background:transparent;border:none;color:#ffffffd9;cursor:pointer;padding:0 2px;font-size:14px;line-height:1}.filex-tag-x[data-v-0cce6f92]:hover{color:#fff}.filex-tag-add input[data-v-0cce6f92]{border:1px solid var(--filex-border, #d1d5db);border-radius:12px;padding:2px 10px;font-size:12px;width:110px}.filex-tag-add-btn[data-v-0cce6f92]{border:1px dashed var(--filex-border, #d1d5db);background:transparent;border-radius:999px;padding:2px 10px;font-size:12px;color:var(--filex-text-muted, #6b7280);cursor:pointer}.filex-tag-add-btn[data-v-0cce6f92]:hover{border-color:var(--filex-accent, #6366f1);color:var(--filex-accent, #6366f1)}.filex-recent[data-v-b6b9b1f3]{background:var(--fe-bg-elev, var(--filex-bg-card, #ffffff));border:1px solid var(--fe-border, var(--filex-border, #e5e7eb));border-radius:8px;padding:12px;font-size:13px}.filex-recent header[data-v-b6b9b1f3]{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}.filex-recent h3[data-v-b6b9b1f3]{margin:0;font-size:13px;font-weight:600;color:var(--fe-text, var(--filex-text, #111827))}.filex-recent-refresh[data-v-b6b9b1f3]{background:transparent;border:none;color:var(--fe-text-muted, var(--filex-text-muted, #9ca3af));cursor:pointer;font-size:14px;padding:2px 6px}.filex-recent ul[data-v-b6b9b1f3]{list-style:none;margin:0;padding:0}.filex-recent-item[data-v-b6b9b1f3]{display:flex;justify-content:space-between;align-items:center;width:100%;background:transparent;border:none;padding:6px 8px;cursor:pointer;border-radius:4px;text-align:left}.filex-recent-item[data-v-b6b9b1f3]:hover{background:var(--fe-bg-hover, var(--filex-bg-soft, #f3f4f6))}.filex-recent-name[data-v-b6b9b1f3]{color:var(--fe-text, var(--filex-text, #111827));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.filex-recent-meta[data-v-b6b9b1f3]{color:var(--fe-text-muted, var(--filex-text-muted, #9ca3af));font-size:11px;margin-left:8px;flex-shrink:0}.filex-recent-empty[data-v-b6b9b1f3]{color:var(--fe-text-muted, var(--filex-text-muted, #9ca3af));margin:4px 0 0}.filex-star-btn[data-v-d5f804ca]{display:inline-flex;align-items:center;gap:6px;background:transparent;border:1px solid transparent;border-radius:6px;padding:4px 8px;color:var(--filex-text-muted, #9ca3af);cursor:pointer;transition:color .12s,background .12s}.filex-star-btn[data-v-d5f804ca]:hover{color:var(--filex-accent-amber, #f59e0b);background:var(--filex-bg-soft, rgba(0, 0, 0, .04))}.filex-star-btn.is-starred[data-v-d5f804ca]{color:var(--filex-accent-amber, #f59e0b)}.filex-star-btn.is-compact[data-v-d5f804ca]{padding:4px}.filex-star-label[data-v-d5f804ca]{font-size:13px}.fe-preview__code-editor.is-hidden{display:none}.fe-preview__viewer{width:100%;height:100%;min-height:70vh;display:flex;flex-direction:column}.fe-preview .fe-preview__viewer{align-self:stretch}.fe-preview__md-mermaid{display:flex;justify-content:center;margin:16px 0}.fe-preview__md-mermaid svg{max-width:100%;height:auto}.fe-preview__md-math{margin:16px 0;text-align:center;overflow-x:auto}.filex-cv__bg[data-v-dfaf8d90]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1000;background:#0000008c;display:flex;align-items:center;justify-content:center}.filex-cv[data-v-dfaf8d90]{width:min(560px,92vw);max-height:80vh;overflow:hidden;display:flex;flex-direction:column;background:var(--fe-bg, #fff);color:var(--fe-text, #1a1f29);border:1px solid var(--fe-border, #e2e6ed);border-radius:12px;box-shadow:0 20px 60px #00000059}.filex-cv__head[data-v-dfaf8d90]{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--fe-border, #e2e6ed)}.filex-cv__head h3[data-v-dfaf8d90]{margin:0;font-size:14px;font-weight:600}.filex-cv__x[data-v-dfaf8d90]{border:0;background:none;cursor:pointer;font-size:16px;color:var(--fe-text-muted, #5a6475)}.filex-cv__msg[data-v-dfaf8d90]{padding:28px;text-align:center;color:var(--fe-text-muted, #5a6475)}.filex-cv__ok[data-v-dfaf8d90]{color:#059669}.filex-cv__src[data-v-dfaf8d90]{padding:12px 16px 0;font-size:13px;color:var(--fe-text-muted, #5a6475)}.filex-cv__search[data-v-dfaf8d90]{margin:8px 16px;padding:8px 10px;border:1px solid var(--fe-border, #e2e6ed);border-radius:8px;background:var(--fe-bg-elev, #f7f8fa);color:inherit;font-size:13px}.filex-cv__list[data-v-dfaf8d90]{flex:1;overflow-y:auto;padding:4px 12px 12px;display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px}.filex-cv__fmt[data-v-dfaf8d90]{display:flex;flex-direction:column;gap:2px;align-items:flex-start;padding:8px 10px;cursor:pointer;text-align:left;border:1px solid var(--fe-border, #e2e6ed);border-radius:8px;background:var(--fe-bg-elev, #f7f8fa);color:inherit}.filex-cv__fmt small[data-v-dfaf8d90]{color:var(--fe-text-muted, #5a6475);font-size:11px}.filex-cv__fmt.is-sel[data-v-dfaf8d90]{border-color:#44c878;background:#44c8781f}.filex-cv__empty[data-v-dfaf8d90]{grid-column:1 / -1;text-align:center;color:var(--fe-text-muted, #5a6475);padding:16px}.filex-cv__err[data-v-dfaf8d90]{padding:0 16px;color:var(--fe-danger, #dc2626);font-size:13px}.filex-cv__foot[data-v-dfaf8d90]{padding:12px 16px;border-top:1px solid var(--fe-border, #e2e6ed);text-align:right}.filex-cv__convert[data-v-dfaf8d90]{padding:8px 18px;border:0;border-radius:8px;cursor:pointer;background:#44c878;color:#03200f;font-weight:600;font-size:13px}.filex-cv__convert[data-v-dfaf8d90]:disabled{opacity:.5;cursor:default}.filex-cv__frame[data-v-dfaf8d90]{position:absolute;width:0;height:0;border:0;left:-9999px}.fx-perm-overlay[data-v-4228dd5b]{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:10000;font-family:var(--fe-font)}.fx-perm-modal[data-v-4228dd5b]{display:flex;flex-direction:column;background:var(--fe-bg);color:var(--fe-text);width:min(520px,94vw);max-height:86vh;border:1px solid var(--fe-border);border-radius:var(--fe-radius-lg, 14px);box-shadow:var(--fe-shadow);font-size:14px;overflow:hidden}.fx-perm-head[data-v-4228dd5b]{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:16px 18px 12px;flex:none}.fx-perm-title[data-v-4228dd5b]{display:flex;align-items:center;gap:10px;min-width:0}.fx-perm-ico[data-v-4228dd5b]{font-size:22px;line-height:1}.fx-perm-titletext[data-v-4228dd5b]{display:flex;flex-direction:column;min-width:0}.fx-perm-title h3[data-v-4228dd5b]{margin:0;font-size:15px;font-weight:600;color:var(--fe-text)}.fx-perm-sub[data-v-4228dd5b]{font-size:12px;color:var(--fe-text);max-width:340px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fx-perm-subdim[data-v-4228dd5b]{color:var(--fe-text-muted)}.fx-perm-x[data-v-4228dd5b]{background:none;border:none;font-size:17px;cursor:pointer;color:var(--fe-text-muted);flex:none;line-height:1;padding:2px 4px;border-radius:6px}.fx-perm-x[data-v-4228dd5b]:hover{color:var(--fe-text);background:var(--fe-bg-hover)}.fx-perm-tabs[data-v-4228dd5b]{display:flex;gap:2px;padding:0 18px;border-bottom:1px solid var(--fe-border);flex:none}.fx-perm-tab[data-v-4228dd5b]{background:none;border:none;border-bottom:2px solid transparent;padding:8px 12px;cursor:pointer;color:var(--fe-text-muted);font-size:13px;font-family:inherit;font-weight:500}.fx-perm-tab[data-v-4228dd5b]:hover{color:var(--fe-text)}.fx-perm-tab.is-active[data-v-4228dd5b]{color:var(--fe-primary);border-bottom-color:var(--fe-primary)}.fx-perm-body[data-v-4228dd5b]{flex:1 1 auto;overflow-y:auto;padding:14px 18px 18px}.fx-perm-addcard[data-v-4228dd5b]{padding:12px;border-radius:var(--fe-radius-md, 10px);background:var(--fe-bg-elev);border:1px solid var(--fe-border)}.fx-perm-section[data-v-4228dd5b]{margin-top:16px}.fx-perm-section h4[data-v-4228dd5b]{margin:0 0 8px;font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--fe-text-muted)}.fx-perm-empty[data-v-4228dd5b]{color:var(--fe-text-muted);font-size:13px;padding:8px 2px}.fx-perm-person[data-v-4228dd5b]{display:flex;align-items:center;gap:10px;padding:7px 2px}.fx-perm-person+.fx-perm-person[data-v-4228dd5b]{border-top:1px solid var(--fe-border)}.fx-perm-inh[data-v-4228dd5b]{color:var(--fe-text-muted)}.fx-perm-av[data-v-4228dd5b]{width:28px;height:28px;flex:none;border-radius:50%;display:flex;align-items:center;justify-content:center;background:var(--fe-primary);color:var(--fe-text-on-primary, #fff);font-size:12px;font-weight:600}.fx-perm-av--dim[data-v-4228dd5b]{background:var(--fe-bg-hover);color:var(--fe-text-muted)}.fx-perm-user[data-v-4228dd5b]{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--fe-text);min-width:0}.fx-perm-from[data-v-4228dd5b]{font-size:11px;color:var(--fe-text-muted);white-space:nowrap}.fx-perm-badge[data-v-4228dd5b]{font-size:11px;padding:2px 9px;border-radius:999px;background:var(--fe-bg-hover);color:var(--fe-text)}.fx-perm-sel[data-v-4228dd5b],.fx-perm-input[data-v-4228dd5b]{padding:7px 9px;border-radius:var(--fe-radius-sm, 7px);border:1px solid var(--fe-border);background:var(--fe-bg);color:var(--fe-text);font-size:13px;font-family:inherit}.fx-perm-sel--sm[data-v-4228dd5b]{padding:5px 7px;font-size:12px}.fx-perm-sel[data-v-4228dd5b]:focus,.fx-perm-input[data-v-4228dd5b]:focus{outline:none;border-color:var(--fe-primary)}.fx-perm-add[data-v-4228dd5b]{display:flex;gap:8px;align-items:stretch}.fx-perm-emailwrap[data-v-4228dd5b]{position:relative;flex:1;min-width:120px}.fx-perm-input[data-v-4228dd5b]{width:100%;box-sizing:border-box}.fx-perm-suggest[data-v-4228dd5b]{position:absolute;top:calc(100% + 3px);left:0;right:0;z-index:5;margin:0;padding:4px;list-style:none;background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius-sm, 7px);box-shadow:var(--fe-shadow);max-height:210px;overflow:auto}.fx-perm-suggest li[data-v-4228dd5b]{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;cursor:pointer}.fx-perm-suggest li[data-v-4228dd5b]:hover{background:var(--fe-bg-hover)}.fx-perm-suggest-av[data-v-4228dd5b]{width:24px;height:24px;flex:none;border-radius:50%;display:flex;align-items:center;justify-content:center;background:var(--fe-bg-hover);color:var(--fe-text);font-size:11px;font-weight:600}.fx-perm-suggest-txt[data-v-4228dd5b]{display:flex;flex-direction:column;min-width:0}.fx-perm-suggest-name[data-v-4228dd5b]{color:var(--fe-text);font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fx-perm-suggest-meta[data-v-4228dd5b]{color:var(--fe-text-muted);font-size:11px}.fx-perm-check[data-v-4228dd5b]{display:inline-flex;gap:6px;align-items:center;font-size:13px;color:var(--fe-text);cursor:pointer}.fx-perm-btn[data-v-4228dd5b]{padding:7px 13px;border-radius:var(--fe-radius-sm, 7px);border:1px solid var(--fe-border);background:var(--fe-bg);color:var(--fe-text);font-size:13px;font-family:inherit;cursor:pointer;white-space:nowrap}.fx-perm-btn[data-v-4228dd5b]:hover:not(:disabled){background:var(--fe-bg-hover)}.fx-perm-btn[data-v-4228dd5b]:disabled{opacity:.55;cursor:default}.fx-perm-btn--sm[data-v-4228dd5b]{padding:5px 10px;font-size:12px}.fx-perm-btn--primary[data-v-4228dd5b]{background:var(--fe-primary);border-color:var(--fe-primary);color:var(--fe-text-on-primary, #fff)}.fx-perm-btn--primary[data-v-4228dd5b]:hover:not(:disabled){background:var(--fe-primary-hover, var(--fe-primary));filter:brightness(1.05)}.fx-perm-btn--ghost[data-v-4228dd5b]{background:none;border-color:transparent;color:var(--fe-primary);padding-left:2px}.fx-perm-btn--ghost[data-v-4228dd5b]:hover:not(:disabled){background:none;text-decoration:underline}.fx-perm-del[data-v-4228dd5b]{background:none;border:none;color:var(--fe-danger);cursor:pointer;font-size:14px;flex:none;padding:2px 4px}.fx-perm-del[data-v-4228dd5b]:hover:not(:disabled){filter:brightness(1.15)}.fx-perm-invite[data-v-4228dd5b]{margin-top:10px;padding-top:10px;border-top:1px dashed var(--fe-border)}.fx-perm-invite-actions[data-v-4228dd5b]{display:flex;flex-direction:column;gap:8px;margin-top:6px}.fx-perm-invite-row[data-v-4228dd5b]{display:flex;gap:8px;align-items:stretch}.fx-perm-invite-row .fx-perm-btn--primary[data-v-4228dd5b]{flex:1}.fx-perm-share-opts[data-v-4228dd5b]{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.fx-perm-expiry[data-v-4228dd5b]{display:inline-flex;gap:6px;align-items:center;font-size:13px}.fx-perm-share-opts .fx-perm-btn--primary[data-v-4228dd5b]{margin-left:auto}.fx-perm-result[data-v-4228dd5b]{margin-top:12px;padding-top:12px;border-top:1px solid var(--fe-border)}.fx-perm-linkrow[data-v-4228dd5b]{display:flex;gap:8px;align-items:center}.fx-perm-link[data-v-4228dd5b]{color:var(--fe-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;text-decoration:none}.fx-perm-link[data-v-4228dd5b]:hover{text-decoration:underline}.fx-perm-pin[data-v-4228dd5b]{margin:8px 0 0;font-size:13px;color:var(--fe-text);display:flex;align-items:center;gap:8px}.fx-perm-pin code[data-v-4228dd5b],.fx-perm-reveal code[data-v-4228dd5b]{font-family:var(--fe-font-mono, monospace);background:var(--fe-bg-hover);padding:1px 6px;border-radius:5px}.fx-perm-mailrow[data-v-4228dd5b]{display:flex;gap:8px;margin-top:10px}.fx-perm-mailrow .fx-perm-input[data-v-4228dd5b]{flex:1}.fx-perm-hint[data-v-4228dd5b]{font-size:13px;color:var(--fe-text-muted);margin:10px 0 0}.fx-perm-dropintro[data-v-4228dd5b]{margin:0 0 12px;line-height:1.4}.fx-perm-advtoggle[data-v-4228dd5b]{margin-top:10px;padding-left:2px}.fx-perm-adv[data-v-4228dd5b]{margin-top:8px;padding-top:10px;border-top:1px dashed var(--fe-border);display:flex;flex-direction:column;gap:8px}.fx-perm-adv-row[data-v-4228dd5b]{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:13px}.fx-perm-input--sm[data-v-4228dd5b]{width:130px;padding:5px 8px;font-size:12px}.fx-perm-warn[data-v-4228dd5b]{background:#f59e0b24;border:1px solid rgba(245,158,11,.4);border-radius:var(--fe-radius-sm, 7px);padding:8px 10px;font-size:13px;margin-bottom:10px;color:var(--fe-text)}.fx-perm-notice[data-v-4228dd5b]{margin-top:8px;font-size:13px;color:var(--fe-text-muted)}.fx-perm-reveal[data-v-4228dd5b]{margin-top:8px;font-size:13px;word-break:break-all;color:var(--fe-text)}.fx-perm-muted[data-v-4228dd5b]{color:var(--fe-text-muted);font-size:13px}:root{--fe-bg: #ffffff;--fe-bg-elev: #f7f8fa;--fe-bg-hover: #edf0f5;--fe-bg-selected: #dfe8ff;--fe-border: #e2e6ed;--fe-border-strong: #c7ced9;--fe-text: #1a1e27;--fe-text-muted: #5a6475;--fe-text-on-primary: #ffffff;--fe-primary: #3b82f6;--fe-primary-hover: #2563eb;--fe-danger: #dc2626;--fe-danger-hover: #b91c1c;--fe-shadow: 0 10px 32px rgba(15, 23, 42, .14);--fe-shadow-sm: 0 2px 6px rgba(15, 23, 42, .08);--fe-radius: 8px;--fe-radius-sm: 4px;--fe-radius-lg: 12px;--fe-font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--fe-font-mono: ui-monospace, "SF Mono", Consolas, Menlo, monospace;--fe-gap: 12px}.fe--theme-dark,:root[data-theme=dark] .fe,.fe.fe--theme-dark,:root.dark,.dark,:root.dark .fe,.dark .fe,.fe-ctx-backdrop--theme-dark,.fe-ctx-backdrop--theme-auto[data-prefers-dark="1"]{--fe-bg: #0f1419;--fe-bg-elev: #161c25;--fe-bg-hover: #1f2733;--fe-bg-selected: #23324a;--fe-border: #2a323e;--fe-border-strong: #3a4453;--fe-text: #e5e9f0;--fe-text-muted: #8b95a7;--fe-primary: #60a5fa;--fe-primary-hover: #3b82f6;--fe-danger: #f87171;--fe-danger-hover: #ef4444;--fe-shadow: 0 12px 32px rgba(0, 0, 0, .45);--fe-shadow-sm: 0 2px 6px rgba(0, 0, 0, .25)}@media (prefers-color-scheme: dark){.fe:not(.fe--theme-light),.fe-ctx-backdrop--theme-auto:not(.fe-ctx-backdrop--theme-light){--fe-bg: #0f1419;--fe-bg-elev: #161c25;--fe-bg-hover: #1f2733;--fe-bg-selected: #23324a;--fe-border: #2a323e;--fe-border-strong: #3a4453;--fe-text: #e5e9f0;--fe-text-muted: #8b95a7;--fe-primary: #60a5fa;--fe-primary-hover: #3b82f6;--fe-danger: #f87171;--fe-danger-hover: #ef4444;--fe-shadow: 0 12px 32px rgba(0, 0, 0, .45);--fe-shadow-sm: 0 2px 6px rgba(0, 0, 0, .25)}}.fe{position:relative;display:flex;flex-direction:column;min-height:420px;height:100%;background:var(--fe-bg);color:var(--fe-text);font-family:var(--fe-font);font-size:14px;border:1px solid var(--fe-border);border-radius:var(--fe-radius);overflow:hidden;outline:none}.fe *{box-sizing:border-box}.fe__body{flex:1 1 auto;overflow:auto;background:var(--fe-bg)}.fe__loading{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;min-height:240px;height:100%;color:var(--fe-text-muted)}.fe__spinner{width:34px;height:34px;border-radius:50%;border:3px solid color-mix(in srgb,var(--fe-text-muted) 30%,transparent);border-top-color:var(--fe-primary);animation:fe-spin .7s linear infinite}.fe__loading-text{margin:0;font-size:13px}@keyframes fe-spin{to{transform:rotate(360deg)}}.fe__file-input{position:absolute;left:-9999px;width:1px;height:1px;opacity:0}.fe-btn{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:var(--fe-bg-elev);border:1px solid var(--fe-border);border-radius:var(--fe-radius-sm);color:var(--fe-text);font:inherit;cursor:pointer;transition:background .12s,border-color .12s;white-space:nowrap}.fe-btn:hover:not(:disabled){background:var(--fe-bg-hover);border-color:var(--fe-border-strong)}.fe-btn:disabled{opacity:.5;cursor:not-allowed}.fe-btn--primary{background:var(--fe-primary);border-color:var(--fe-primary);color:var(--fe-text-on-primary)}.fe-btn--primary:hover:not(:disabled){background:var(--fe-primary-hover);border-color:var(--fe-primary-hover)}.fe-btn--danger{background:var(--fe-danger);border-color:var(--fe-danger);color:var(--fe-text-on-primary)}.fe-btn--danger:hover:not(:disabled){background:var(--fe-danger-hover);border-color:var(--fe-danger-hover)}.fe-btn--icon-only{padding:6px 8px}.fe-btn.is-active{background:var(--fe-bg-selected);border-color:var(--fe-primary)}.fe-btn__label{line-height:1}.fe-icon{font-size:1.05em;line-height:1}.fe-toolbar{display:flex;align-items:center;gap:8px;padding:10px 12px;background:var(--fe-bg-elev);border-bottom:1px solid var(--fe-border);flex-wrap:wrap}.fe-toolbar__primary{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}.fe-toolbar__spacer{flex:1 1 auto}.fe-toolbar__search-group{display:inline-flex;align-items:center;gap:4px;background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius-sm);padding:2px}.fe-toolbar__search-group .fe-search__input{border:0;background:transparent;padding:4px 8px}.fe-toolbar__search-group .fe-btn{border:0;background:transparent;padding:4px 6px}.fe-toolbar__search-group .fe-btn:hover:not(:disabled){background:var(--fe-bg-hover)}.fe-toolbar__view{display:inline-flex;gap:2px;padding:2px;background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius-sm)}.fe-toolbar__view .fe-btn{border:0;background:transparent}.fe-toolbar__view .fe-btn.is-active{background:var(--fe-bg-selected)}.fe-search{position:relative}.fe-search__input{background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius-sm);padding:6px 10px;font:inherit;color:var(--fe-text);min-width:200px}.fe-search__input:focus-visible{outline:2px solid var(--fe-primary);outline-offset:1px}.fe-breadcrumb{display:flex;align-items:center;gap:4px;flex-wrap:wrap;padding:6px 12px;background:var(--fe-bg);border-bottom:1px solid var(--fe-border);font-size:13px;color:var(--fe-text-muted)}.fe-breadcrumb__crumb{display:inline-flex;align-items:center;gap:4px;background:transparent;border:0;color:inherit;padding:2px 6px;border-radius:var(--fe-radius-sm);cursor:pointer;font:inherit}.fe-breadcrumb__crumb:hover{background:var(--fe-bg-hover);color:var(--fe-text)}.fe-breadcrumb__crumb.is-last{color:var(--fe-text);font-weight:600}.fe-breadcrumb__sep{color:var(--fe-text-muted)}.fe-breadcrumb__edit{margin-left:auto;background:none;border:1px solid transparent;color:var(--fe-text-muted);cursor:pointer;font-size:14px;line-height:1;padding:4px 8px;border-radius:4px}.fe-breadcrumb__edit:hover{background:var(--fe-bg-hover);color:var(--fe-text);border-color:var(--fe-border)}.fe-breadcrumb__input{flex:1;background:var(--fe-bg);color:var(--fe-text);border:1px solid var(--fe-accent, #2563eb);border-radius:4px;padding:4px 8px;font-family:var(--fe-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);font-size:13px;outline:none}.fe-list{display:flex;flex-direction:column}.fe-list__head{display:grid;grid-template-columns:32px minmax(0,1fr) 120px 180px;gap:8px;padding:8px 12px;font-weight:600;color:var(--fe-text-muted);font-size:12px;text-transform:uppercase;letter-spacing:.04em;background:var(--fe-bg-elev);border-bottom:1px solid var(--fe-border)}.fe-list__body{display:flex;flex-direction:column}.fe-list__row{display:grid;grid-template-columns:32px minmax(0,1fr) 120px 180px;gap:8px;padding:8px 12px;align-items:center;cursor:pointer;border-bottom:1px solid var(--fe-border);transition:background .08s;-webkit-user-select:none;user-select:none}.fe-list__row:hover{background:var(--fe-bg-hover)}.fe-list__row.is-selected{background:var(--fe-bg-selected)}.fe-list__row.is-trash{opacity:.7}.fe-list__row.is-clipped,.fe-grid__card.is-clipped{opacity:.45;font-style:italic}.fe-list__row:focus-visible{outline:2px solid var(--fe-primary);outline-offset:-2px}.fe-list__col--star{display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .12s}.fe-list__row:hover .fe-list__col--star,.fe-list__row:focus-within .fe-list__col--star,.fe-list__col--star:has(.is-starred){opacity:1}.fe-list__col--star .filex-star-btn.is-starred{color:var(--fe-warning, #f59e0b)}.fe-list__col--name{display:flex;align-items:center;gap:8px;min-width:0}.fe-list__icon{flex-shrink:0;font-size:16px}.fe-list__name-wrap{display:flex;flex-direction:column;min-width:0;flex:1 1 auto}.fe-list__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fe-list__parent{font-size:11px;color:var(--fe-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:2px}.fe-list__col--size,.fe-list__col--mod{color:var(--fe-text-muted);font-size:13px}.fe-list__empty{padding:40px 20px;text-align:center;color:var(--fe-text-muted)}.fe-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:var(--fe-gap);padding:var(--fe-gap)}.fe-grid__card{display:flex;flex-direction:column;align-items:stretch;padding:8px;border:1px solid var(--fe-border);border-radius:var(--fe-radius);background:var(--fe-bg-elev);cursor:pointer;transition:background .08s,border-color .08s;-webkit-user-select:none;user-select:none}.fe-grid__card:hover{background:var(--fe-bg-hover);border-color:var(--fe-border-strong)}.fe-grid__card.is-selected{background:var(--fe-bg-selected);border-color:var(--fe-primary)}.fe-grid__card.is-trash{opacity:.7}.fe-grid__thumb{display:flex;align-items:center;justify-content:center;aspect-ratio:1 / 1;background:var(--fe-bg);border-radius:var(--fe-radius-sm);margin-bottom:8px;overflow:hidden}.fe-grid__thumb img{width:100%;height:100%;object-fit:cover}.fe-grid__icon{font-size:32px}.fe-grid__label{font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fe-grid__meta{font-size:11px;color:var(--fe-text-muted);margin-top:2px}.fe-grid__parent{font-size:11px;color:var(--fe-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:2px;font-style:italic}.fe-grid__empty{grid-column:1 / -1;padding:40px 20px;text-align:center;color:var(--fe-text-muted)}.fe__dragover{position:absolute;top:0;right:0;bottom:0;left:0;z-index:30;display:flex;align-items:center;justify-content:center;background:#3b82f61f;border:3px dashed var(--fe-primary);pointer-events:none}.fe__dragover-card{background:var(--fe-bg);border-radius:var(--fe-radius-lg);padding:24px 40px;box-shadow:var(--fe-shadow);text-align:center}.fe__dragover-card .fe-icon{font-size:32px;display:block;margin-bottom:8px}.fe-upload{position:absolute;right:16px;bottom:16px;width:min(360px,calc(100% - 32px));background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius);box-shadow:var(--fe-shadow);z-index:40;max-height:40vh;display:flex;flex-direction:column;overflow:hidden}.fe-upload__header{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--fe-bg-elev);border-bottom:1px solid var(--fe-border);font-size:13px}.fe-upload__count{background:var(--fe-primary);color:var(--fe-text-on-primary);font-size:12px;padding:1px 7px;border-radius:999px}.fe-upload__list{list-style:none;padding:0;margin:0;overflow:auto}.fe-upload__item{padding:10px 14px;border-bottom:1px solid var(--fe-border)}.fe-upload__item:last-child{border-bottom:0}.fe-upload__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;margin-bottom:4px}.fe-upload__bar{background:var(--fe-bg-elev);border-radius:99px;height:6px;overflow:hidden;margin-bottom:4px}.fe-upload__bar-fill{background:var(--fe-primary);height:100%;transition:width .2s}.fe-upload__item.is-error .fe-upload__bar-fill,.fe-upload__item.is-aborted .fe-upload__bar-fill{background:var(--fe-danger)}.fe-upload__item.is-done .fe-upload__bar-fill{background:#16a34a}.fe-upload__meta{display:flex;align-items:center;justify-content:space-between;gap:6px;font-size:11px;color:var(--fe-text-muted)}.fe-upload__cancel{background:transparent;border:0;color:var(--fe-primary);cursor:pointer;font:inherit}.fe-upload-slide-enter-active,.fe-upload-slide-leave-active{transition:transform .2s,opacity .2s}.fe-upload-slide-enter-from,.fe-upload-slide-leave-to{opacity:0;transform:translateY(10px)}.fe-ops{position:absolute;left:16px;bottom:16px;width:min(320px,calc(100% - 32px));display:flex;flex-direction:column;gap:8px;z-index:40}.fe-ops__item{background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius);box-shadow:var(--fe-shadow);padding:10px 14px;font-size:13px}.fe-ops__item.is-done{border-color:#16a34a}.fe-ops__item.is-error{border-color:var(--fe-danger)}.fe-ops__row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px}.fe-ops__title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto}.fe-ops__dismiss{background:transparent;border:0;color:var(--fe-text-muted);cursor:pointer;font-size:18px;line-height:1;padding:0 4px}.fe-ops__bar{background:var(--fe-bg-elev);border-radius:99px;height:6px;overflow:hidden}.fe-ops__bar-fill{background:var(--fe-primary);height:100%;transition:width .25s}.fe-ops__item.is-done .fe-ops__bar-fill{background:#16a34a}.fe-ops__item.is-error .fe-ops__bar-fill{background:var(--fe-danger)}.fe-ops__error{margin-top:6px;font-size:11px;color:var(--fe-danger)}.fe-ops-slide-enter-active,.fe-ops-slide-leave-active{transition:transform .2s,opacity .2s}.fe-ops-slide-enter-from,.fe-ops-slide-leave-to{opacity:0;transform:translateY(10px)}.fe-ctx-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:80;color:var(--fe-text);font-family:var(--fe-font);font-size:14px}.fe-ctx{position:absolute;min-width:180px;background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius);box-shadow:var(--fe-shadow);padding:4px;z-index:90;color:var(--fe-text)}.fe-ctx__item{display:flex;align-items:center;gap:8px;padding:6px 10px;border-radius:var(--fe-radius-sm);border:0;background:transparent;color:var(--fe-text);font:inherit;width:100%;text-align:left;cursor:pointer}.fe-ctx__item:hover:not(.is-disabled){background:var(--fe-bg-hover)}.fe-ctx__item.is-danger{color:var(--fe-danger)}.fe-ctx__item.is-disabled{opacity:.45;cursor:not-allowed}.fe-ctx__icon{width:1.2em;text-align:center}.fe-ctx__sep{height:1px;background:var(--fe-border);margin:4px 0}.fe-ctx-enter-active,.fe-ctx-leave-active{transition:opacity .1s}.fe-ctx-enter-from,.fe-ctx-leave-to{opacity:0}.fe-modal__backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:70;display:flex;align-items:center;justify-content:center;background:#0d131b7a;padding:16px}.fe-modal__card{background:var(--fe-bg);border-radius:var(--fe-radius);box-shadow:var(--fe-shadow);width:100%;max-height:calc(100vh - 32px);display:flex;flex-direction:column;overflow:hidden}.fe-modal__card--sm{max-width:420px}.fe-modal__card--md{max-width:560px}.fe-modal__card--lg{max-width:800px}.fe-modal__card--xl{max-width:1080px;height:calc(100vh - 64px)}.fe-recents__backdrop{align-items:flex-start!important;padding-top:60px}.fe-recents__panel{background:var(--fe-bg, #fff);border-radius:var(--fe-radius, 8px);box-shadow:var(--fe-shadow, 0 6px 24px rgba(0, 0, 0, .18));width:min(480px,calc(100vw - 32px));max-height:calc(100vh - 96px);display:flex;flex-direction:column;overflow:hidden}.fe-recents__header{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-bottom:1px solid var(--fe-border, #e2e6ed)}.fe-recents__close{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;font-size:22px;line-height:1;cursor:pointer;color:var(--fe-text-muted, #6b7280);padding:0 4px}.fe-recents__close:hover{color:var(--fe-text, #111)}.fe-preview__md-split{display:flex;flex-direction:column;height:100%;width:100%;min-height:0}.fe-preview__md-split-bar{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 14px;background:var(--fe-bg-elev, #f6f7f9);border-bottom:1px solid var(--fe-border, #e2e6ed);flex:0 0 auto}.fe-preview__md-split-label{font-family:var(--fe-font-mono, ui-monospace, monospace);font-size:11px;letter-spacing:.06em;color:var(--fe-text-muted, #6b7280)}.fe-preview__md-split-error{flex:1 1 auto;font-size:12px;color:var(--fe-danger, #dc2626);text-align:center}.fe-preview__md-split-body{flex:1 1 auto;display:grid;grid-template-columns:1fr 1fr;min-height:0}.fe-preview__md-split-input{resize:none;border:0;outline:0;padding:16px 20px;font-family:var(--fe-font-mono, ui-monospace, monospace);font-size:13px;line-height:1.6;background:var(--fe-bg, #fff);color:var(--fe-text, #111);border-right:1px solid var(--fe-border, #e2e6ed);overflow:auto;-moz-tab-size:2;tab-size:2}.fe-preview__md-split-output{overflow:auto;padding:16px 24px;background:var(--fe-bg, #fff)}.fe-preview__md-split-output.fe-preview__md{max-height:none;min-height:0;height:100%}@media (max-width: 900px){.fe-preview__md-split-body{grid-template-columns:1fr;grid-template-rows:1fr 1fr}.fe-preview__md-split-input{border-right:0;border-bottom:1px solid var(--fe-border, #e2e6ed)}}.fe-modal__backdrop--chromeless{background:transparent;padding:0}.fe-modal__card--chromeless{max-width:none;width:100vw;height:100vh;max-height:100vh;border-radius:0;box-shadow:none}.fe-modal__card--chromeless .fe-modal__body{flex:1 1 auto;min-height:0;padding:0}.fe-modal__card--chromeless .fe-preview{align-items:stretch;justify-content:stretch;min-height:0;flex:1 1 auto}.fe-modal__card--chromeless .fe-preview>*{width:100%;height:100%}.fe-modal__head{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--fe-border)}.fe-modal__title{font-size:16px;font-weight:600;margin:0}.fe-modal__close{background:transparent;border:0;color:var(--fe-text-muted);font-size:22px;cursor:pointer;padding:0 4px;line-height:1}.fe-modal__body{padding:16px;overflow:auto;flex:1 1 auto}.fe-modal__actions{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--fe-border);background:var(--fe-bg-elev)}.fe-modal-enter-active,.fe-modal-leave-active{transition:opacity .15s}.fe-modal-enter-from,.fe-modal-leave-to{opacity:0}.fe-input{width:100%;padding:8px 10px;background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius-sm);font:inherit;color:var(--fe-text)}.fe-input:focus-visible{outline:2px solid var(--fe-primary);outline-offset:1px}.fe-input--mono{font-family:var(--fe-font-mono);letter-spacing:.1em}.fe-form{display:flex;flex-direction:column;gap:12px}.fe-form__row{display:flex;align-items:center;gap:8px}.fe-form__row--stack{flex-direction:column;align-items:stretch}.fe-form__error{color:var(--fe-danger);font-size:12px;margin:6px 0 0}.fe-share-result{display:flex;flex-direction:column;gap:12px}.fe-share-result__row label{display:block;font-size:12px;font-weight:600;color:var(--fe-text-muted);margin-bottom:4px}.fe-share-result__copy{display:flex;gap:6px}.fe-preview{display:flex;align-items:center;justify-content:center;width:100%;height:100%;min-height:50vh;background:var(--fe-bg-elev)}.fe-preview__image{max-width:100%;max-height:70vh;object-fit:contain}.fe-preview__video,.fe-preview__audio{max-width:100%;max-height:70vh}.fe-preview__iframe{width:100%;height:70vh;border:0;background:#fff}.fe-preview__office{width:100%;height:78vh;background:var(--fe-bg)}.fe-preview__code-wrap{display:flex;flex-direction:column;width:100%;height:78vh}.fe-preview__code-toolbar{display:flex;align-items:center;gap:12px;padding:8px 12px;background:var(--fe-bg-hover, #f3f4f6);border-bottom:1px solid var(--fe-border, #e5e7eb);font-size:12px}.fe-preview__code-lang{font-family:var(--fe-font-mono, ui-monospace, monospace);color:var(--fe-text-muted);text-transform:uppercase;letter-spacing:.04em}.fe-preview__code-toolbar>.fe-btn{margin-left:auto}.fe-preview__code-status{font-size:12px;font-weight:500}.fe-preview__code-status--ok{color:#059669}.fe-preview__code-status--err{color:#dc2626;cursor:help}.fe-preview__code-editor{flex:1;min-height:0;overflow:hidden}.fe-preview__code-editor .cm-editor{height:100%;font-size:13px}.fe-preview__code-editor .cm-scroller{font-family:var(--fe-font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace)}.fe-preview__fallback{text-align:center;color:var(--fe-text-muted);padding:40px 20px}.fe-preview__fallback-icon{font-size:48px;display:block;margin-bottom:12px}.fe-preview__pre{margin:0;padding:16px;width:100%;max-height:70vh;overflow:auto;background:var(--fe-bg);color:var(--fe-text);font-family:var(--fe-font-mono);font-size:13px;line-height:1.5;white-space:pre-wrap;word-wrap:break-word}.fe-preview__code{white-space:pre;word-wrap:normal}.hljs{background:var(--fe-bg);color:var(--fe-text)}.hljs-comment,.hljs-quote{color:var(--fe-text-muted);font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-built_in,.hljs-section,.hljs-meta{color:#c678dd}.hljs-string,.hljs-attr,.hljs-symbol,.hljs-bullet,.hljs-addition,.hljs-link{color:#98c379}.hljs-number,.hljs-literal,.hljs-deletion{color:#d19a66}.hljs-title,.hljs-name,.hljs-selector-id,.hljs-selector-class,.hljs-template-tag,.hljs-template-variable{color:#61aeee}.hljs-type,.hljs-tag{color:#e06c75}.hljs-variable,.hljs-attribute{color:#d19a66}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.fe-preview__md{width:100%;max-height:70vh;overflow:auto;padding:24px 32px;background:var(--fe-bg);color:var(--fe-text);line-height:1.6;font-size:15px}.fe-preview__md h1,.fe-preview__md h2,.fe-preview__md h3,.fe-preview__md h4{margin:1.2em 0 .6em;font-weight:600}.fe-preview__md h1{font-size:1.8em;border-bottom:1px solid var(--fe-border);padding-bottom:.3em}.fe-preview__md h2{font-size:1.4em;border-bottom:1px solid var(--fe-border);padding-bottom:.3em}.fe-preview__md h3{font-size:1.2em}.fe-preview__md p{margin:.8em 0}.fe-preview__md a{color:var(--fe-primary);text-decoration:underline}.fe-preview__md code{font-family:var(--fe-font-mono);background:var(--fe-bg-elev);padding:1px 5px;border-radius:3px;font-size:.92em}.fe-preview__md pre{background:var(--fe-bg-elev);border:1px solid var(--fe-border);border-radius:var(--fe-radius-sm);padding:12px 16px;overflow:auto;font-size:.9em}.fe-preview__md pre code{background:transparent;padding:0}.fe-preview__md ul,.fe-preview__md ol{padding-left:2em;margin:.8em 0}.fe-preview__md li{margin:.3em 0}.fe-preview__md blockquote{border-left:3px solid var(--fe-border-strong);padding:0 1em;color:var(--fe-text-muted);margin:.8em 0}.fe-preview__md table{border-collapse:collapse;margin:1em 0;width:100%}.fe-preview__md th,.fe-preview__md td{border:1px solid var(--fe-border);padding:6px 10px;text-align:left}.fe-preview__md th{background:var(--fe-bg-elev)}.fe-preview__md img{max-width:100%}.fe-toast{position:absolute;bottom:24px;left:50%;transform:translate(-50%);background:var(--fe-text);color:var(--fe-bg);padding:8px 14px;border-radius:var(--fe-radius);font-size:13px;box-shadow:var(--fe-shadow-sm);z-index:95}.fe-toast-enter-active,.fe-toast-leave-active{transition:opacity .2s,transform .2s}.fe-toast-enter-from,.fe-toast-leave-to{opacity:0;transform:translate(-50%,10px)}@media (max-width: 640px){.fe-list__head,.fe-list__row{grid-template-columns:28px minmax(0,1fr) 90px}.fe-list__col--mod{display:none}.fe-toolbar{padding:8px}.fe-search__input{min-width:120px}}.filex-viewer-3d[data-v-d5c3ab71]{width:100%;height:100%;min-height:480px;background:#1a1a1a;display:flex;align-items:center;justify-content:center}.filex-viewer-3d[data-v-d5c3ab71] model-viewer{width:100%;height:100%;min-height:480px;background:#1a1a1a;display:block}.filex-viewer-fallback[data-v-d5c3ab71]{text-align:center;color:#c8cdd6;padding:32px;max-width:480px}.filex-viewer-fallback__icon[data-v-d5c3ab71]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-epub__nav[data-v-cd1c1cee]{position:absolute;bottom:12px;left:50%;transform:translate(-50%);display:flex;gap:8px;padding:4px 8px;background:var(--fe-bg-elev, rgba(255, 255, 255, .9));border:1px solid var(--fe-border, #e2e6ed);border-radius:6px;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.filex-viewer-epub[data-v-cd1c1cee]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27);position:relative}.filex-viewer-epub__bar[data-v-cd1c1cee]{display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--fe-bg-elev, #f7f8fa);border-bottom:1px solid var(--fe-border, #e2e6ed);font-size:13px}.filex-viewer-spacer[data-v-cd1c1cee]{flex:1}.filex-viewer-epub__fs[data-v-cd1c1cee]{display:inline-block;min-width:40px;text-align:center;font-variant-numeric:tabular-nums;font-size:12px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-epub__main[data-v-cd1c1cee]{flex:1;min-height:0;display:flex}.filex-viewer-epub__rendition[data-v-cd1c1cee]{flex:1;min-height:0}.filex-viewer-epub__toc[data-v-cd1c1cee]{width:260px;border-right:1px solid var(--fe-border, #e2e6ed);overflow-y:auto;padding:12px 0;background:var(--fe-bg-elev, #f7f8fa)}.filex-viewer-epub__toc ul[data-v-cd1c1cee]{list-style:none;margin:0;padding:0}.filex-viewer-epub__toc-link[data-v-cd1c1cee]{display:block;width:100%;text-align:left;background:transparent;border:0;padding:6px 14px;font:inherit;color:inherit;cursor:pointer}.filex-viewer-epub__toc-link[data-v-cd1c1cee]:hover{background:var(--fe-bg-hover, #edf0f5)}.filex-viewer-epub__toc-link.is-child[data-v-cd1c1cee]{padding-left:28px;color:var(--fe-text-muted, #5a6475);font-size:12px}.filex-viewer-epub__loading[data-v-cd1c1cee]{position:absolute;inset:auto 0 0 0;text-align:center;padding:6px;background:#0000000d;font-size:12px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-fallback[data-v-cd1c1cee]{text-align:center;padding:32px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-fallback__icon[data-v-cd1c1cee]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-btn[data-v-cd1c1cee]{border:1px solid var(--fe-border, #e2e6ed);background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27);padding:4px 10px;border-radius:4px;cursor:pointer;font:inherit;font-size:12px}.filex-viewer-btn[data-v-cd1c1cee]:hover:not(:disabled){background:var(--fe-bg-hover, #edf0f5)}.filex-viewer-btn[data-v-cd1c1cee]:disabled{opacity:.5;cursor:not-allowed}.filex-viewer-mermaid[data-v-cd37a551]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27)}.filex-viewer-mermaid__bar[data-v-cd37a551]{display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--fe-bg-elev, #f7f8fa);border-bottom:1px solid var(--fe-border, #e2e6ed);font-size:13px}.filex-viewer-mermaid__zoom[data-v-cd37a551]{min-width:50px;text-align:center;font-variant-numeric:tabular-nums;font-size:12px}.filex-viewer-mermaid__pane[data-v-cd37a551]{flex:1;overflow:hidden;position:relative;cursor:grab;background:var(--fe-bg-elev, #f7f8fa);touch-action:none}.filex-viewer-mermaid__pane[data-v-cd37a551]:active{cursor:grabbing}.filex-viewer-mermaid__surface[data-v-cd37a551]{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;transform-origin:center center;transition:transform .05s linear;-webkit-user-select:none;user-select:none}.filex-viewer-mermaid__surface[data-v-cd37a551] svg{max-width:90%;max-height:90%}.filex-viewer-fallback[data-v-cd37a551]{text-align:center;padding:32px;color:var(--fe-text-muted, #5a6475);width:100%;display:flex;flex-direction:column;align-items:center;justify-content:center}.filex-viewer-fallback__icon[data-v-cd37a551]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-btn[data-v-cd37a551]{border:1px solid var(--fe-border, #e2e6ed);background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27);padding:4px 10px;border-radius:4px;cursor:pointer;font:inherit;font-size:12px}.filex-viewer-btn[data-v-cd37a551]:hover:not(:disabled){background:var(--fe-bg-hover, #edf0f5)}.filex-viewer-drawio[data-v-699c407a]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff)}.filex-viewer-drawio__bar[data-v-699c407a]{display:flex;align-items:center;gap:12px;padding:6px 12px;background:var(--fe-bg-elev, #f7f8fa);border-bottom:1px solid var(--fe-border, #e2e6ed);font-size:12px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-drawio__status[data-state=error][data-v-699c407a]{color:var(--fe-danger, #dc2626)}.filex-viewer-drawio__status[data-state=saved][data-v-699c407a]{color:#059669}.filex-viewer-drawio__readonly[data-v-699c407a]{font-style:italic;margin-left:auto}.filex-viewer-drawio__frame[data-v-699c407a]{flex:1;width:100%;border:0;background:#fafafa;min-height:0}.filex-viewer-fallback[data-v-699c407a]{text-align:center;padding:32px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-fallback__icon[data-v-699c407a]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-tiff__pager[data-v-9c711133]{position:absolute;bottom:12px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:8px;padding:4px 8px;background:var(--fe-bg-elev, rgba(255, 255, 255, .9));border:1px solid var(--fe-border, #e2e6ed);border-radius:6px;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.filex-viewer-tiff__pages[data-v-9c711133]{font-size:12px;font-variant-numeric:tabular-nums}.filex-viewer-tiff[data-v-9c711133]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff)}.filex-viewer-tiff__bar[data-v-9c711133]{display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--fe-bg-elev, #f7f8fa);border-bottom:1px solid var(--fe-border, #e2e6ed);font-size:13px}.filex-viewer-tiff__pages[data-v-9c711133]{min-width:110px;text-align:center;font-variant-numeric:tabular-nums;font-size:12px}.filex-viewer-tiff__zoom[data-v-9c711133]{min-width:50px;text-align:center;font-variant-numeric:tabular-nums;font-size:12px}.filex-viewer-spacer[data-v-9c711133]{flex:1}.filex-viewer-tiff__pane[data-v-9c711133]{flex:1;overflow:auto;padding:16px;background:#2a2d33;display:flex;align-items:flex-start;justify-content:flex-start}.filex-viewer-tiff__pane canvas[data-v-9c711133]{background:#fff;box-shadow:0 4px 16px #0000004d}.filex-viewer-fallback[data-v-9c711133]{text-align:center;padding:32px;color:#c8cdd6;margin:auto}.filex-viewer-fallback__icon[data-v-9c711133]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-btn[data-v-9c711133]{border:1px solid var(--fe-border, #e2e6ed);background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27);padding:4px 10px;border-radius:4px;cursor:pointer;font:inherit;font-size:12px}.filex-viewer-btn[data-v-9c711133]:hover:not(:disabled){background:var(--fe-bg-hover, #edf0f5)}.filex-viewer-btn[data-v-9c711133]:disabled{opacity:.4;cursor:not-allowed}.filex-viewer-psd[data-v-e073aaf6]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff)}.filex-viewer-psd__bar[data-v-e073aaf6]{display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--fe-bg-elev, #f7f8fa);border-bottom:1px solid var(--fe-border, #e2e6ed);font-size:13px}.filex-viewer-spacer[data-v-e073aaf6]{flex:1}.filex-viewer-psd__dim[data-v-e073aaf6]{font-size:12px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-psd__zoom[data-v-e073aaf6]{min-width:50px;text-align:center;font-variant-numeric:tabular-nums;font-size:12px}.filex-viewer-psd__main[data-v-e073aaf6]{flex:1;display:flex;min-height:0}.filex-viewer-psd__layers[data-v-e073aaf6]{width:240px;border-right:1px solid var(--fe-border, #e2e6ed);overflow-y:auto;padding:8px 0;background:var(--fe-bg-elev, #f7f8fa)}.filex-viewer-psd__layers ul[data-v-e073aaf6]{list-style:none;margin:0;padding:0}.filex-viewer-psd__layers li[data-v-e073aaf6]{display:flex;align-items:center;gap:6px;padding:4px 12px;font-size:12px}.filex-viewer-psd__layer-vis[data-v-e073aaf6]{width:14px;text-align:center;color:var(--fe-text-muted, #5a6475)}.filex-viewer-psd__layer-vis[data-hidden="1"][data-v-e073aaf6]{color:var(--fe-border-strong, #c7ced9)}.filex-viewer-psd__layer-name[data-v-e073aaf6]{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.filex-viewer-psd__pane[data-v-e073aaf6]{flex:1;overflow:auto;padding:16px;background:#2a2d33;display:flex;align-items:flex-start;justify-content:flex-start}.filex-viewer-psd__pane canvas[data-v-e073aaf6]{background:#fff repeating-conic-gradient(#e0e0e0 0% 25%,transparent 0% 50%) 50% / 16px 16px;box-shadow:0 4px 16px #0000004d}.filex-viewer-fallback[data-v-e073aaf6]{text-align:center;padding:32px;color:#c8cdd6;margin:auto}.filex-viewer-fallback__icon[data-v-e073aaf6]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-btn[data-v-e073aaf6]{border:1px solid var(--fe-border, #e2e6ed);background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27);padding:4px 10px;border-radius:4px;cursor:pointer;font:inherit;font-size:12px}.filex-viewer-btn[data-v-e073aaf6]:hover:not(:disabled){background:var(--fe-bg-hover, #edf0f5)}.filex-viewer-btn.is-active[data-v-e073aaf6]{background:var(--fe-bg-selected, #dfe8ff);border-color:var(--fe-primary, #3b82f6)}.filex-viewer-ipynb[data-v-cd9ee977]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27)}.filex-viewer-ipynb__bar[data-v-cd9ee977]{display:flex;align-items:center;gap:12px;padding:8px 12px;background:var(--fe-bg-elev, #f7f8fa);border-bottom:1px solid var(--fe-border, #e2e6ed);font-size:12px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-ipynb__lang[data-v-cd9ee977]{font-family:var(--fe-font-mono, monospace);text-transform:uppercase;letter-spacing:.04em}.filex-viewer-ipynb__pane[data-v-cd9ee977]{flex:1;overflow:auto;padding:16px 24px}.filex-viewer-ipynb__cell[data-v-cd9ee977]{border:1px solid var(--fe-border, #e2e6ed);border-radius:6px;margin-bottom:16px;overflow:hidden}.filex-viewer-ipynb__cell[data-type=code][data-v-cd9ee977]{background:var(--fe-bg-elev, #f7f8fa)}.filex-viewer-ipynb__exec[data-v-cd9ee977]{padding:4px 12px;font-family:var(--fe-font-mono, monospace);font-size:11px;color:var(--fe-text-muted, #5a6475);background:#0000000a}.filex-viewer-ipynb__src[data-v-cd9ee977]{margin:0;padding:12px;font-family:var(--fe-font-mono, monospace);font-size:12px;line-height:1.5;white-space:pre;overflow-x:auto}.filex-viewer-ipynb__outputs[data-v-cd9ee977]{border-top:1px dashed var(--fe-border, #e2e6ed);background:var(--fe-bg, #fff);padding:8px 12px}.filex-viewer-ipynb__out[data-v-cd9ee977]{margin:0;padding:4px 0;font-family:var(--fe-font-mono, monospace);font-size:12px;white-space:pre-wrap;word-wrap:break-word}.filex-viewer-ipynb__out[data-type=error][data-v-cd9ee977]{color:var(--fe-danger, #dc2626)}.filex-viewer-ipynb__img[data-v-cd9ee977]{display:block;max-width:100%;height:auto;margin:8px 0}.filex-viewer-ipynb__html[data-v-cd9ee977]{font-size:13px}.filex-viewer-ipynb__md[data-v-cd9ee977]{padding:12px 16px;font-size:14px;line-height:1.6}.filex-viewer-ipynb__md-raw[data-v-cd9ee977]{padding:12px;margin:0;font-family:var(--fe-font-mono, monospace);font-size:12px;white-space:pre-wrap}.filex-viewer-fallback[data-v-cd9ee977]{text-align:center;padding:32px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-fallback__icon[data-v-cd9ee977]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-csv[data-v-fc9f1e8b]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27)}.filex-viewer-csv__bar[data-v-fc9f1e8b]{display:flex;align-items:center;gap:12px;padding:8px 12px;background:var(--fe-bg-elev, #f7f8fa);border-bottom:1px solid var(--fe-border, #e2e6ed);font-size:12px}.filex-viewer-csv__check[data-v-fc9f1e8b]{display:flex;align-items:center;gap:4px;font-size:12px}.filex-viewer-csv__select[data-v-fc9f1e8b],.filex-viewer-csv__filter[data-v-fc9f1e8b]{border:1px solid var(--fe-border, #e2e6ed);background:var(--fe-bg, #fff);color:inherit;padding:4px 8px;border-radius:4px;font:inherit;font-size:12px}.filex-viewer-csv__filter[data-v-fc9f1e8b]{flex:0 1 240px}.filex-viewer-spacer[data-v-fc9f1e8b]{flex:1}.filex-viewer-csv__count[data-v-fc9f1e8b]{font-size:11px;color:var(--fe-text-muted, #5a6475);font-variant-numeric:tabular-nums}.filex-viewer-csv__pane[data-v-fc9f1e8b]{flex:1;overflow:auto}.filex-viewer-csv__table[data-v-fc9f1e8b]{border-collapse:collapse;width:max-content;min-width:100%;font-size:12px;font-family:var(--fe-font-mono, monospace)}.filex-viewer-csv__table th[data-v-fc9f1e8b],.filex-viewer-csv__table td[data-v-fc9f1e8b]{padding:4px 10px;border:1px solid var(--fe-border, #e2e6ed);white-space:nowrap;max-width:320px;overflow:hidden;text-overflow:ellipsis}.filex-viewer-csv__table th[data-v-fc9f1e8b]{background:var(--fe-bg-elev, #f7f8fa);position:sticky;top:0;font-weight:600;text-align:left}.filex-viewer-csv__table tbody tr[data-v-fc9f1e8b]:nth-child(2n){background:var(--fe-bg-hover, rgba(0, 0, 0, .02))}.filex-viewer-csv__rownum[data-v-fc9f1e8b]{color:var(--fe-text-muted, #5a6475);text-align:right;background:var(--fe-bg-elev, #f7f8fa);font-variant-numeric:tabular-nums;position:sticky;left:0}.filex-viewer-csv__pager[data-v-fc9f1e8b]{display:flex;justify-content:center;align-items:center;gap:8px;padding:6px;background:var(--fe-bg-elev, #f7f8fa);border-top:1px solid var(--fe-border, #e2e6ed);font-size:12px}.filex-viewer-csv__pageno[data-v-fc9f1e8b]{font-variant-numeric:tabular-nums;font-size:12px}.filex-viewer-fallback[data-v-fc9f1e8b]{text-align:center;padding:32px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-fallback__icon[data-v-fc9f1e8b]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-btn[data-v-fc9f1e8b]{border:1px solid var(--fe-border, #e2e6ed);background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27);padding:4px 10px;border-radius:4px;cursor:pointer;font:inherit;font-size:12px}.filex-viewer-btn[data-v-fc9f1e8b]:hover:not(:disabled){background:var(--fe-bg-hover, #edf0f5)}.filex-viewer-btn[data-v-fc9f1e8b]:disabled{opacity:.4;cursor:not-allowed}.filex-viewer-archive[data-v-95e6ab29]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27)}.filex-viewer-archive__pane[data-v-95e6ab29]{flex:1;overflow:auto;padding:16px 20px}.filex-viewer-archive__summary[data-v-95e6ab29]{font-size:12px;color:var(--fe-text-muted, #5a6475);margin-bottom:12px;font-variant-numeric:tabular-nums}.filex-viewer-archive__table[data-v-95e6ab29]{width:100%;border-collapse:collapse;font-size:13px;font-family:var(--fe-font-mono, monospace)}.filex-viewer-archive__table th[data-v-95e6ab29],.filex-viewer-archive__table td[data-v-95e6ab29]{padding:6px 12px;border-bottom:1px solid var(--fe-border, #e2e6ed);text-align:left}.filex-viewer-archive__table th[data-v-95e6ab29]{background:var(--fe-bg-elev, #f7f8fa);font-weight:600;position:sticky;top:0}.filex-viewer-archive__size[data-v-95e6ab29]{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap;color:var(--fe-text-muted, #5a6475)}.filex-viewer-archive__icon[data-v-95e6ab29]{margin-right:6px}.filex-viewer-archive__table tr[data-dir="1"][data-v-95e6ab29]{color:var(--fe-text-muted, #5a6475)}.filex-viewer-fallback[data-v-95e6ab29]{text-align:center;padding:32px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-fallback__icon[data-v-95e6ab29]{font-size:48px;display:block;margin-bottom:12px}
1
+ .filex-tag-picker[data-v-f2104118]{display:flex;flex-wrap:wrap;gap:6px;align-items:center}.filex-tag-picker.is-loading[data-v-f2104118]{opacity:.6;pointer-events:none}.filex-tag[data-v-f2104118]{display:inline-flex;align-items:center;gap:4px;border-radius:999px;padding:2px 10px;font-size:12px;font-weight:500;color:#fff;background:var(--filex-tag-color)}.filex-tag-x[data-v-f2104118]{background:transparent;border:none;color:#ffffffd9;cursor:pointer;padding:0 2px;font-size:14px;line-height:1}.filex-tag-x[data-v-f2104118]:hover{color:#fff}.filex-tag-add input[data-v-f2104118]{border:1px solid var(--filex-border, #d1d5db);border-radius:12px;padding:2px 10px;font-size:12px;width:110px}.filex-tag-add-btn[data-v-f2104118]{border:1px dashed var(--filex-border, #d1d5db);background:transparent;border-radius:999px;padding:2px 10px;font-size:12px;color:var(--filex-text-muted, #6b7280);cursor:pointer}.filex-tag-add-btn[data-v-f2104118]:hover{border-color:var(--filex-accent, #6366f1);color:var(--filex-accent, #6366f1)}.filex-recent[data-v-ff50baed]{background:var(--fe-bg-elev, var(--filex-bg-card, #ffffff));border:1px solid var(--fe-border, var(--filex-border, #e5e7eb));border-radius:8px;padding:12px;font-size:13px}.filex-recent header[data-v-ff50baed]{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}.filex-recent h3[data-v-ff50baed]{margin:0;font-size:13px;font-weight:600;color:var(--fe-text, var(--filex-text, #111827))}.filex-recent-refresh[data-v-ff50baed]{background:transparent;border:none;color:var(--fe-text-muted, var(--filex-text-muted, #9ca3af));cursor:pointer;font-size:14px;padding:2px 6px}.filex-recent ul[data-v-ff50baed]{list-style:none;margin:0;padding:0}.filex-recent-item[data-v-ff50baed]{display:flex;justify-content:space-between;align-items:center;width:100%;background:transparent;border:none;padding:6px 8px;cursor:pointer;border-radius:4px;text-align:left}.filex-recent-item[data-v-ff50baed]:hover{background:var(--fe-bg-hover, var(--filex-bg-soft, #f3f4f6))}.filex-recent-name[data-v-ff50baed]{color:var(--fe-text, var(--filex-text, #111827));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.filex-recent-meta[data-v-ff50baed]{color:var(--fe-text-muted, var(--filex-text-muted, #9ca3af));font-size:11px;margin-left:8px;flex-shrink:0}.filex-recent-empty[data-v-ff50baed]{color:var(--fe-text-muted, var(--filex-text-muted, #9ca3af));margin:4px 0 0}.filex-star-btn[data-v-1b788147]{display:inline-flex;align-items:center;gap:6px;background:transparent;border:1px solid transparent;border-radius:6px;padding:4px 8px;color:var(--filex-text-muted, #9ca3af);cursor:pointer;transition:color .12s,background .12s}.filex-star-btn[data-v-1b788147]:hover{color:var(--filex-accent-amber, #f59e0b);background:var(--filex-bg-soft, rgba(0, 0, 0, .04))}.filex-star-btn.is-starred[data-v-1b788147]{color:var(--filex-accent-amber, #f59e0b)}.filex-star-btn.is-compact[data-v-1b788147]{padding:4px}.filex-star-label[data-v-1b788147]{font-size:13px}.fe-preview__code-editor.is-hidden{display:none}.fe-preview__viewer{width:100%;height:100%;min-height:70vh;display:flex;flex-direction:column}.fe-preview .fe-preview__viewer{align-self:stretch}.fe-preview__md-mermaid{display:flex;justify-content:center;margin:16px 0}.fe-preview__md-mermaid svg{max-width:100%;height:auto}.fe-preview__md-math{margin:16px 0;text-align:center;overflow-x:auto}.filex-cv__bg[data-v-dfaf8d90]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1000;background:#0000008c;display:flex;align-items:center;justify-content:center}.filex-cv[data-v-dfaf8d90]{width:min(560px,92vw);max-height:80vh;overflow:hidden;display:flex;flex-direction:column;background:var(--fe-bg, #fff);color:var(--fe-text, #1a1f29);border:1px solid var(--fe-border, #e2e6ed);border-radius:12px;box-shadow:0 20px 60px #00000059}.filex-cv__head[data-v-dfaf8d90]{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--fe-border, #e2e6ed)}.filex-cv__head h3[data-v-dfaf8d90]{margin:0;font-size:14px;font-weight:600}.filex-cv__x[data-v-dfaf8d90]{border:0;background:none;cursor:pointer;font-size:16px;color:var(--fe-text-muted, #5a6475)}.filex-cv__msg[data-v-dfaf8d90]{padding:28px;text-align:center;color:var(--fe-text-muted, #5a6475)}.filex-cv__ok[data-v-dfaf8d90]{color:#059669}.filex-cv__src[data-v-dfaf8d90]{padding:12px 16px 0;font-size:13px;color:var(--fe-text-muted, #5a6475)}.filex-cv__search[data-v-dfaf8d90]{margin:8px 16px;padding:8px 10px;border:1px solid var(--fe-border, #e2e6ed);border-radius:8px;background:var(--fe-bg-elev, #f7f8fa);color:inherit;font-size:13px}.filex-cv__list[data-v-dfaf8d90]{flex:1;overflow-y:auto;padding:4px 12px 12px;display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:8px}.filex-cv__fmt[data-v-dfaf8d90]{display:flex;flex-direction:column;gap:2px;align-items:flex-start;padding:8px 10px;cursor:pointer;text-align:left;border:1px solid var(--fe-border, #e2e6ed);border-radius:8px;background:var(--fe-bg-elev, #f7f8fa);color:inherit}.filex-cv__fmt small[data-v-dfaf8d90]{color:var(--fe-text-muted, #5a6475);font-size:11px}.filex-cv__fmt.is-sel[data-v-dfaf8d90]{border-color:#44c878;background:#44c8781f}.filex-cv__empty[data-v-dfaf8d90]{grid-column:1 / -1;text-align:center;color:var(--fe-text-muted, #5a6475);padding:16px}.filex-cv__err[data-v-dfaf8d90]{padding:0 16px;color:var(--fe-danger, #dc2626);font-size:13px}.filex-cv__foot[data-v-dfaf8d90]{padding:12px 16px;border-top:1px solid var(--fe-border, #e2e6ed);text-align:right}.filex-cv__convert[data-v-dfaf8d90]{padding:8px 18px;border:0;border-radius:8px;cursor:pointer;background:#44c878;color:#03200f;font-weight:600;font-size:13px}.filex-cv__convert[data-v-dfaf8d90]:disabled{opacity:.5;cursor:default}.filex-cv__frame[data-v-dfaf8d90]{position:absolute;width:0;height:0;border:0;left:-9999px}.fx-perm-overlay[data-v-2f29f6ce]{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:10000;font-family:var(--fe-font)}.fx-perm-modal[data-v-2f29f6ce]{display:flex;flex-direction:column;background:var(--fe-bg);color:var(--fe-text);width:min(520px,94vw);max-height:86vh;border:1px solid var(--fe-border);border-radius:var(--fe-radius-lg, 14px);box-shadow:var(--fe-shadow);font-size:14px;overflow:hidden}.fx-perm-head[data-v-2f29f6ce]{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:16px 18px 12px;flex:none}.fx-perm-title[data-v-2f29f6ce]{display:flex;align-items:center;gap:10px;min-width:0}.fx-perm-ico[data-v-2f29f6ce]{font-size:22px;line-height:1}.fx-perm-titletext[data-v-2f29f6ce]{display:flex;flex-direction:column;min-width:0}.fx-perm-title h3[data-v-2f29f6ce]{margin:0;font-size:15px;font-weight:600;color:var(--fe-text)}.fx-perm-sub[data-v-2f29f6ce]{font-size:12px;color:var(--fe-text);max-width:340px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fx-perm-subdim[data-v-2f29f6ce]{color:var(--fe-text-muted)}.fx-perm-x[data-v-2f29f6ce]{background:none;border:none;font-size:17px;cursor:pointer;color:var(--fe-text-muted);flex:none;line-height:1;padding:2px 4px;border-radius:6px}.fx-perm-x[data-v-2f29f6ce]:hover{color:var(--fe-text);background:var(--fe-bg-hover)}.fx-perm-tabs[data-v-2f29f6ce]{display:flex;gap:2px;padding:0 18px;border-bottom:1px solid var(--fe-border);flex:none}.fx-perm-tab[data-v-2f29f6ce]{background:none;border:none;border-bottom:2px solid transparent;padding:8px 12px;cursor:pointer;color:var(--fe-text-muted);font-size:13px;font-family:inherit;font-weight:500}.fx-perm-tab[data-v-2f29f6ce]:hover{color:var(--fe-text)}.fx-perm-tab.is-active[data-v-2f29f6ce]{color:var(--fe-primary);border-bottom-color:var(--fe-primary)}.fx-perm-body[data-v-2f29f6ce]{flex:1 1 auto;overflow-y:auto;padding:14px 18px 18px}.fx-perm-addcard[data-v-2f29f6ce]{padding:12px;border-radius:var(--fe-radius-md, 10px);background:var(--fe-bg-elev);border:1px solid var(--fe-border)}.fx-perm-section[data-v-2f29f6ce]{margin-top:16px}.fx-perm-section h4[data-v-2f29f6ce]{margin:0 0 8px;font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--fe-text-muted)}.fx-perm-empty[data-v-2f29f6ce]{color:var(--fe-text-muted);font-size:13px;padding:8px 2px}.fx-perm-person[data-v-2f29f6ce]{display:flex;align-items:center;gap:10px;padding:7px 2px}.fx-perm-person+.fx-perm-person[data-v-2f29f6ce]{border-top:1px solid var(--fe-border)}.fx-perm-inh[data-v-2f29f6ce]{color:var(--fe-text-muted)}.fx-perm-av[data-v-2f29f6ce]{width:28px;height:28px;flex:none;border-radius:50%;display:flex;align-items:center;justify-content:center;background:var(--fe-primary);color:var(--fe-text-on-primary, #fff);font-size:12px;font-weight:600}.fx-perm-av--dim[data-v-2f29f6ce]{background:var(--fe-bg-hover);color:var(--fe-text-muted)}.fx-perm-user[data-v-2f29f6ce]{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--fe-text);min-width:0}.fx-perm-from[data-v-2f29f6ce]{font-size:11px;color:var(--fe-text-muted);white-space:nowrap}.fx-perm-badge[data-v-2f29f6ce]{font-size:11px;padding:2px 9px;border-radius:999px;background:var(--fe-bg-hover);color:var(--fe-text)}.fx-perm-sel[data-v-2f29f6ce],.fx-perm-input[data-v-2f29f6ce]{padding:7px 9px;border-radius:var(--fe-radius-sm, 7px);border:1px solid var(--fe-border);background:var(--fe-bg);color:var(--fe-text);font-size:13px;font-family:inherit}.fx-perm-sel--sm[data-v-2f29f6ce]{padding:5px 7px;font-size:12px}.fx-perm-sel[data-v-2f29f6ce]:focus,.fx-perm-input[data-v-2f29f6ce]:focus{outline:none;border-color:var(--fe-primary)}.fx-perm-add[data-v-2f29f6ce]{display:flex;gap:8px;align-items:stretch}.fx-perm-emailwrap[data-v-2f29f6ce]{position:relative;flex:1;min-width:120px}.fx-perm-input[data-v-2f29f6ce]{width:100%;box-sizing:border-box}.fx-perm-suggest[data-v-2f29f6ce]{position:absolute;top:calc(100% + 3px);left:0;right:0;z-index:5;margin:0;padding:4px;list-style:none;background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius-sm, 7px);box-shadow:var(--fe-shadow);max-height:210px;overflow:auto}.fx-perm-suggest li[data-v-2f29f6ce]{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;cursor:pointer}.fx-perm-suggest li[data-v-2f29f6ce]:hover{background:var(--fe-bg-hover)}.fx-perm-suggest-av[data-v-2f29f6ce]{width:24px;height:24px;flex:none;border-radius:50%;display:flex;align-items:center;justify-content:center;background:var(--fe-bg-hover);color:var(--fe-text);font-size:11px;font-weight:600}.fx-perm-suggest-txt[data-v-2f29f6ce]{display:flex;flex-direction:column;min-width:0}.fx-perm-suggest-name[data-v-2f29f6ce]{color:var(--fe-text);font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fx-perm-suggest-meta[data-v-2f29f6ce]{color:var(--fe-text-muted);font-size:11px}.fx-perm-check[data-v-2f29f6ce]{display:inline-flex;gap:6px;align-items:center;font-size:13px;color:var(--fe-text);cursor:pointer}.fx-perm-btn[data-v-2f29f6ce]{padding:7px 13px;border-radius:var(--fe-radius-sm, 7px);border:1px solid var(--fe-border);background:var(--fe-bg);color:var(--fe-text);font-size:13px;font-family:inherit;cursor:pointer;white-space:nowrap}.fx-perm-btn[data-v-2f29f6ce]:hover:not(:disabled){background:var(--fe-bg-hover)}.fx-perm-btn[data-v-2f29f6ce]:disabled{opacity:.55;cursor:default}.fx-perm-btn--sm[data-v-2f29f6ce]{padding:5px 10px;font-size:12px}.fx-perm-btn--primary[data-v-2f29f6ce]{background:var(--fe-primary);border-color:var(--fe-primary);color:var(--fe-text-on-primary, #fff)}.fx-perm-btn--primary[data-v-2f29f6ce]:hover:not(:disabled){background:var(--fe-primary-hover, var(--fe-primary));filter:brightness(1.05)}.fx-perm-btn--ghost[data-v-2f29f6ce]{background:none;border-color:transparent;color:var(--fe-primary);padding-left:2px}.fx-perm-btn--ghost[data-v-2f29f6ce]:hover:not(:disabled){background:none;text-decoration:underline}.fx-perm-del[data-v-2f29f6ce]{background:none;border:none;color:var(--fe-danger);cursor:pointer;font-size:14px;flex:none;padding:2px 4px}.fx-perm-del[data-v-2f29f6ce]:hover:not(:disabled){filter:brightness(1.15)}.fx-perm-invite[data-v-2f29f6ce]{margin-top:10px;padding-top:10px;border-top:1px dashed var(--fe-border)}.fx-perm-invite-actions[data-v-2f29f6ce]{display:flex;flex-direction:column;gap:8px;margin-top:6px}.fx-perm-invite-row[data-v-2f29f6ce]{display:flex;gap:8px;align-items:stretch}.fx-perm-invite-row .fx-perm-btn--primary[data-v-2f29f6ce]{flex:1}.fx-perm-share-opts[data-v-2f29f6ce]{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.fx-perm-expiry[data-v-2f29f6ce]{display:inline-flex;gap:6px;align-items:center;font-size:13px}.fx-perm-share-opts .fx-perm-btn--primary[data-v-2f29f6ce]{margin-left:auto}.fx-perm-result[data-v-2f29f6ce]{margin-top:12px;padding-top:12px;border-top:1px solid var(--fe-border)}.fx-perm-linkrow[data-v-2f29f6ce]{display:flex;gap:8px;align-items:center}.fx-perm-link[data-v-2f29f6ce]{color:var(--fe-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;text-decoration:none}.fx-perm-link[data-v-2f29f6ce]:hover{text-decoration:underline}.fx-perm-pin[data-v-2f29f6ce]{margin:8px 0 0;font-size:13px;color:var(--fe-text);display:flex;align-items:center;gap:8px}.fx-perm-pin code[data-v-2f29f6ce],.fx-perm-reveal code[data-v-2f29f6ce]{font-family:var(--fe-font-mono, monospace);background:var(--fe-bg-hover);padding:1px 6px;border-radius:5px}.fx-perm-mailrow[data-v-2f29f6ce]{display:flex;gap:8px;margin-top:10px}.fx-perm-mailrow .fx-perm-input[data-v-2f29f6ce]{flex:1}.fx-perm-hint[data-v-2f29f6ce]{font-size:13px;color:var(--fe-text-muted);margin:10px 0 0}.fx-perm-dropintro[data-v-2f29f6ce]{margin:0 0 12px;line-height:1.4}.fx-perm-advtoggle[data-v-2f29f6ce]{margin-top:10px;padding-left:2px}.fx-perm-adv[data-v-2f29f6ce]{margin-top:8px;padding-top:10px;border-top:1px dashed var(--fe-border);display:flex;flex-direction:column;gap:8px}.fx-perm-adv-row[data-v-2f29f6ce]{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:13px}.fx-perm-input--sm[data-v-2f29f6ce]{width:130px;padding:5px 8px;font-size:12px}.fx-perm-warn[data-v-2f29f6ce]{background:#f59e0b24;border:1px solid rgba(245,158,11,.4);border-radius:var(--fe-radius-sm, 7px);padding:8px 10px;font-size:13px;margin-bottom:10px;color:var(--fe-text)}.fx-perm-notice[data-v-2f29f6ce]{margin-top:8px;font-size:13px;color:var(--fe-text-muted)}.fx-perm-reveal[data-v-2f29f6ce]{margin-top:8px;font-size:13px;word-break:break-all;color:var(--fe-text)}.fx-perm-muted[data-v-2f29f6ce]{color:var(--fe-text-muted);font-size:13px}:root{--fe-bg: #ffffff;--fe-bg-elev: #f7f8fa;--fe-bg-hover: #edf0f5;--fe-bg-selected: #dfe8ff;--fe-border: #e2e6ed;--fe-border-strong: #c7ced9;--fe-text: #1a1e27;--fe-text-muted: #5a6475;--fe-text-on-primary: #ffffff;--fe-primary: #3b82f6;--fe-primary-hover: #2563eb;--fe-danger: #dc2626;--fe-danger-hover: #b91c1c;--fe-shadow: 0 10px 32px rgba(15, 23, 42, .14);--fe-shadow-sm: 0 2px 6px rgba(15, 23, 42, .08);--fe-radius: 8px;--fe-radius-sm: 4px;--fe-radius-lg: 12px;--fe-font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--fe-font-mono: ui-monospace, "SF Mono", Consolas, Menlo, monospace;--fe-gap: 12px}.fe--theme-dark,:root[data-theme=dark] .fe,.fe.fe--theme-dark,:root.dark,.dark,:root.dark .fe,.dark .fe,.fe-ctx-backdrop--theme-dark,.fe-ctx-backdrop--theme-auto[data-prefers-dark="1"]{--fe-bg: #0f1419;--fe-bg-elev: #161c25;--fe-bg-hover: #1f2733;--fe-bg-selected: #23324a;--fe-border: #2a323e;--fe-border-strong: #3a4453;--fe-text: #e5e9f0;--fe-text-muted: #8b95a7;--fe-primary: #60a5fa;--fe-primary-hover: #3b82f6;--fe-danger: #f87171;--fe-danger-hover: #ef4444;--fe-shadow: 0 12px 32px rgba(0, 0, 0, .45);--fe-shadow-sm: 0 2px 6px rgba(0, 0, 0, .25)}@media (prefers-color-scheme: dark){.fe:not(.fe--theme-light),.fe-ctx-backdrop--theme-auto:not(.fe-ctx-backdrop--theme-light){--fe-bg: #0f1419;--fe-bg-elev: #161c25;--fe-bg-hover: #1f2733;--fe-bg-selected: #23324a;--fe-border: #2a323e;--fe-border-strong: #3a4453;--fe-text: #e5e9f0;--fe-text-muted: #8b95a7;--fe-primary: #60a5fa;--fe-primary-hover: #3b82f6;--fe-danger: #f87171;--fe-danger-hover: #ef4444;--fe-shadow: 0 12px 32px rgba(0, 0, 0, .45);--fe-shadow-sm: 0 2px 6px rgba(0, 0, 0, .25)}}.fe{position:relative;display:flex;flex-direction:column;min-height:420px;height:100%;background:var(--fe-bg);color:var(--fe-text);font-family:var(--fe-font);font-size:14px;border:1px solid var(--fe-border);border-radius:var(--fe-radius);overflow:hidden;outline:none}.fe *{box-sizing:border-box}.fe__body{flex:1 1 auto;overflow:auto;background:var(--fe-bg)}.fe__loading{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;min-height:240px;height:100%;color:var(--fe-text-muted)}.fe__spinner{width:34px;height:34px;border-radius:50%;border:3px solid color-mix(in srgb,var(--fe-text-muted) 30%,transparent);border-top-color:var(--fe-primary);animation:fe-spin .7s linear infinite}.fe__loading-text{margin:0;font-size:13px}@keyframes fe-spin{to{transform:rotate(360deg)}}.fe__file-input{position:absolute;left:-9999px;width:1px;height:1px;opacity:0}.fe-btn{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:var(--fe-bg-elev);border:1px solid var(--fe-border);border-radius:var(--fe-radius-sm);color:var(--fe-text);font:inherit;cursor:pointer;transition:background .12s,border-color .12s;white-space:nowrap}.fe-btn:hover:not(:disabled){background:var(--fe-bg-hover);border-color:var(--fe-border-strong)}.fe-btn:disabled{opacity:.5;cursor:not-allowed}.fe-btn--primary{background:var(--fe-primary);border-color:var(--fe-primary);color:var(--fe-text-on-primary)}.fe-btn--primary:hover:not(:disabled){background:var(--fe-primary-hover);border-color:var(--fe-primary-hover)}.fe-btn--danger{background:var(--fe-danger);border-color:var(--fe-danger);color:var(--fe-text-on-primary)}.fe-btn--danger:hover:not(:disabled){background:var(--fe-danger-hover);border-color:var(--fe-danger-hover)}.fe-btn--icon-only{padding:6px 8px}.fe-btn.is-active{background:var(--fe-bg-selected);border-color:var(--fe-primary)}.fe-btn__label{line-height:1}.fe-icon{font-size:1.05em;line-height:1}.fe-toolbar{display:flex;align-items:center;gap:8px;padding:10px 12px;background:var(--fe-bg-elev);border-bottom:1px solid var(--fe-border);flex-wrap:wrap}.fe-toolbar__primary{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}.fe-toolbar__spacer{flex:1 1 auto}.fe-toolbar__search-group{display:inline-flex;align-items:center;gap:4px;background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius-sm);padding:2px}.fe-toolbar__search-group .fe-search__input{border:0;background:transparent;padding:4px 8px}.fe-toolbar__search-group .fe-btn{border:0;background:transparent;padding:4px 6px}.fe-toolbar__search-group .fe-btn:hover:not(:disabled){background:var(--fe-bg-hover)}.fe-toolbar__view{display:inline-flex;gap:2px;padding:2px;background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius-sm)}.fe-toolbar__view .fe-btn{border:0;background:transparent}.fe-toolbar__view .fe-btn.is-active{background:var(--fe-bg-selected)}.fe-search{position:relative}.fe-search__input{background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius-sm);padding:6px 10px;font:inherit;color:var(--fe-text);min-width:200px}.fe-search__input:focus-visible{outline:2px solid var(--fe-primary);outline-offset:1px}.fe-breadcrumb{display:flex;align-items:center;gap:4px;flex-wrap:wrap;padding:6px 12px;background:var(--fe-bg);border-bottom:1px solid var(--fe-border);font-size:13px;color:var(--fe-text-muted)}.fe-breadcrumb__crumb{display:inline-flex;align-items:center;gap:4px;background:transparent;border:0;color:inherit;padding:2px 6px;border-radius:var(--fe-radius-sm);cursor:pointer;font:inherit}.fe-breadcrumb__crumb:hover{background:var(--fe-bg-hover);color:var(--fe-text)}.fe-breadcrumb__crumb.is-last{color:var(--fe-text);font-weight:600}.fe-breadcrumb__sep{color:var(--fe-text-muted)}.fe-breadcrumb__edit{margin-left:auto;background:none;border:1px solid transparent;color:var(--fe-text-muted);cursor:pointer;font-size:14px;line-height:1;padding:4px 8px;border-radius:4px}.fe-breadcrumb__edit:hover{background:var(--fe-bg-hover);color:var(--fe-text);border-color:var(--fe-border)}.fe-breadcrumb__input{flex:1;background:var(--fe-bg);color:var(--fe-text);border:1px solid var(--fe-accent, #2563eb);border-radius:4px;padding:4px 8px;font-family:var(--fe-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);font-size:13px;outline:none}.fe-list{display:flex;flex-direction:column}.fe-list__head{display:grid;grid-template-columns:32px minmax(0,1fr) 120px 180px;gap:8px;padding:8px 12px;font-weight:600;color:var(--fe-text-muted);font-size:12px;text-transform:uppercase;letter-spacing:.04em;background:var(--fe-bg-elev);border-bottom:1px solid var(--fe-border)}.fe-list__body{display:flex;flex-direction:column}.fe-list__row{display:grid;grid-template-columns:32px minmax(0,1fr) 120px 180px;gap:8px;padding:8px 12px;align-items:center;cursor:pointer;border-bottom:1px solid var(--fe-border);transition:background .08s;-webkit-user-select:none;user-select:none}.fe-list__row:hover{background:var(--fe-bg-hover)}.fe-list__row.is-selected{background:var(--fe-bg-selected)}.fe-list__row.is-trash{opacity:.7}.fe-list__row.is-clipped,.fe-grid__card.is-clipped{opacity:.45;font-style:italic}.fe-list__row:focus-visible{outline:2px solid var(--fe-primary);outline-offset:-2px}.fe-list__col--star{display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .12s}.fe-list__row:hover .fe-list__col--star,.fe-list__row:focus-within .fe-list__col--star,.fe-list__col--star:has(.is-starred){opacity:1}.fe-list__col--star .filex-star-btn.is-starred{color:var(--fe-warning, #f59e0b)}.fe-list__col--name{display:flex;align-items:center;gap:8px;min-width:0}.fe-list__icon{flex-shrink:0;font-size:16px}.fe-list__name-wrap{display:flex;flex-direction:column;min-width:0;flex:1 1 auto}.fe-list__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fe-list__parent{font-size:11px;color:var(--fe-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:2px}.fe-list__col--size,.fe-list__col--mod{color:var(--fe-text-muted);font-size:13px}.fe-list__empty{padding:40px 20px;text-align:center;color:var(--fe-text-muted)}.fe-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:var(--fe-gap);padding:var(--fe-gap)}.fe-grid__card{display:flex;flex-direction:column;align-items:stretch;padding:8px;border:1px solid var(--fe-border);border-radius:var(--fe-radius);background:var(--fe-bg-elev);cursor:pointer;transition:background .08s,border-color .08s;-webkit-user-select:none;user-select:none}.fe-grid__card:hover{background:var(--fe-bg-hover);border-color:var(--fe-border-strong)}.fe-grid__card.is-selected{background:var(--fe-bg-selected);border-color:var(--fe-primary)}.fe-grid__card.is-trash{opacity:.7}.fe-grid__thumb{display:flex;align-items:center;justify-content:center;aspect-ratio:1 / 1;background:var(--fe-bg);border-radius:var(--fe-radius-sm);margin-bottom:8px;overflow:hidden}.fe-grid__thumb img{width:100%;height:100%;object-fit:cover}.fe-grid__icon{font-size:32px}.fe-grid__label{font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fe-grid__meta{font-size:11px;color:var(--fe-text-muted);margin-top:2px}.fe-grid__parent{font-size:11px;color:var(--fe-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:2px;font-style:italic}.fe-grid__empty{grid-column:1 / -1;padding:40px 20px;text-align:center;color:var(--fe-text-muted)}.fe__dragover{position:absolute;top:0;right:0;bottom:0;left:0;z-index:30;display:flex;align-items:center;justify-content:center;background:#3b82f61f;border:3px dashed var(--fe-primary);pointer-events:none}.fe__dragover-card{background:var(--fe-bg);border-radius:var(--fe-radius-lg);padding:24px 40px;box-shadow:var(--fe-shadow);text-align:center}.fe__dragover-card .fe-icon{font-size:32px;display:block;margin-bottom:8px}.fe-upload{position:absolute;right:16px;bottom:16px;width:min(360px,calc(100% - 32px));background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius);box-shadow:var(--fe-shadow);z-index:40;max-height:40vh;display:flex;flex-direction:column;overflow:hidden}.fe-upload__header{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:var(--fe-bg-elev);border-bottom:1px solid var(--fe-border);font-size:13px}.fe-upload__count{background:var(--fe-primary);color:var(--fe-text-on-primary);font-size:12px;padding:1px 7px;border-radius:999px}.fe-upload__list{list-style:none;padding:0;margin:0;overflow:auto}.fe-upload__item{padding:10px 14px;border-bottom:1px solid var(--fe-border)}.fe-upload__item:last-child{border-bottom:0}.fe-upload__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;margin-bottom:4px}.fe-upload__bar{background:var(--fe-bg-elev);border-radius:99px;height:6px;overflow:hidden;margin-bottom:4px}.fe-upload__bar-fill{background:var(--fe-primary);height:100%;transition:width .2s}.fe-upload__item.is-error .fe-upload__bar-fill,.fe-upload__item.is-aborted .fe-upload__bar-fill{background:var(--fe-danger)}.fe-upload__item.is-done .fe-upload__bar-fill{background:#16a34a}.fe-upload__meta{display:flex;align-items:center;justify-content:space-between;gap:6px;font-size:11px;color:var(--fe-text-muted)}.fe-upload__cancel{background:transparent;border:0;color:var(--fe-primary);cursor:pointer;font:inherit}.fe-upload-slide-enter-active,.fe-upload-slide-leave-active{transition:transform .2s,opacity .2s}.fe-upload-slide-enter-from,.fe-upload-slide-leave-to{opacity:0;transform:translateY(10px)}.fe-ops{position:absolute;left:16px;bottom:16px;width:min(320px,calc(100% - 32px));display:flex;flex-direction:column;gap:8px;z-index:40}.fe-ops__item{background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius);box-shadow:var(--fe-shadow);padding:10px 14px;font-size:13px}.fe-ops__item.is-done{border-color:#16a34a}.fe-ops__item.is-error{border-color:var(--fe-danger)}.fe-ops__row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px}.fe-ops__title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto}.fe-ops__dismiss{background:transparent;border:0;color:var(--fe-text-muted);cursor:pointer;font-size:18px;line-height:1;padding:0 4px}.fe-ops__bar{background:var(--fe-bg-elev);border-radius:99px;height:6px;overflow:hidden}.fe-ops__bar-fill{background:var(--fe-primary);height:100%;transition:width .25s}.fe-ops__item.is-done .fe-ops__bar-fill{background:#16a34a}.fe-ops__item.is-error .fe-ops__bar-fill{background:var(--fe-danger)}.fe-ops__error{margin-top:6px;font-size:11px;color:var(--fe-danger)}.fe-ops-slide-enter-active,.fe-ops-slide-leave-active{transition:transform .2s,opacity .2s}.fe-ops-slide-enter-from,.fe-ops-slide-leave-to{opacity:0;transform:translateY(10px)}.fe-ctx-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:80;color:var(--fe-text);font-family:var(--fe-font);font-size:14px}.fe-ctx{position:absolute;min-width:180px;background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius);box-shadow:var(--fe-shadow);padding:4px;z-index:90;color:var(--fe-text)}.fe-ctx__item{display:flex;align-items:center;gap:8px;padding:6px 10px;border-radius:var(--fe-radius-sm);border:0;background:transparent;color:var(--fe-text);font:inherit;width:100%;text-align:left;cursor:pointer}.fe-ctx__item:hover:not(.is-disabled){background:var(--fe-bg-hover)}.fe-ctx__item.is-danger{color:var(--fe-danger)}.fe-ctx__item.is-disabled{opacity:.45;cursor:not-allowed}.fe-ctx__icon{width:1.2em;text-align:center}.fe-ctx__sep{height:1px;background:var(--fe-border);margin:4px 0}.fe-ctx-enter-active,.fe-ctx-leave-active{transition:opacity .1s}.fe-ctx-enter-from,.fe-ctx-leave-to{opacity:0}.fe-modal__backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:70;display:flex;align-items:center;justify-content:center;background:#0d131b7a;padding:16px}.fe-modal__card{background:var(--fe-bg);border-radius:var(--fe-radius);box-shadow:var(--fe-shadow);width:100%;max-height:calc(100vh - 32px);display:flex;flex-direction:column;overflow:hidden}.fe-modal__card--sm{max-width:420px}.fe-modal__card--md{max-width:560px}.fe-modal__card--lg{max-width:800px}.fe-modal__card--xl{max-width:1080px;height:calc(100vh - 64px)}.fe-recents__backdrop{align-items:flex-start!important;padding-top:60px}.fe-recents__panel{background:var(--fe-bg, #fff);border-radius:var(--fe-radius, 8px);box-shadow:var(--fe-shadow, 0 6px 24px rgba(0, 0, 0, .18));width:min(480px,calc(100vw - 32px));max-height:calc(100vh - 96px);display:flex;flex-direction:column;overflow:hidden}.fe-recents__header{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-bottom:1px solid var(--fe-border, #e2e6ed)}.fe-recents__close{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;font-size:22px;line-height:1;cursor:pointer;color:var(--fe-text-muted, #6b7280);padding:0 4px}.fe-recents__close:hover{color:var(--fe-text, #111)}.fe-preview__md-split{display:flex;flex-direction:column;height:100%;width:100%;min-height:0}.fe-preview__md-split-bar{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 14px;background:var(--fe-bg-elev, #f6f7f9);border-bottom:1px solid var(--fe-border, #e2e6ed);flex:0 0 auto}.fe-preview__md-split-label{font-family:var(--fe-font-mono, ui-monospace, monospace);font-size:11px;letter-spacing:.06em;color:var(--fe-text-muted, #6b7280)}.fe-preview__md-split-error{flex:1 1 auto;font-size:12px;color:var(--fe-danger, #dc2626);text-align:center}.fe-preview__md-split-body{flex:1 1 auto;display:grid;grid-template-columns:1fr 1fr;min-height:0}.fe-preview__md-split-input{resize:none;border:0;outline:0;padding:16px 20px;font-family:var(--fe-font-mono, ui-monospace, monospace);font-size:13px;line-height:1.6;background:var(--fe-bg, #fff);color:var(--fe-text, #111);border-right:1px solid var(--fe-border, #e2e6ed);overflow:auto;-moz-tab-size:2;tab-size:2}.fe-preview__md-split-output{overflow:auto;padding:16px 24px;background:var(--fe-bg, #fff)}.fe-preview__md-split-output.fe-preview__md{max-height:none;min-height:0;height:100%}@media (max-width: 900px){.fe-preview__md-split-body{grid-template-columns:1fr;grid-template-rows:1fr 1fr}.fe-preview__md-split-input{border-right:0;border-bottom:1px solid var(--fe-border, #e2e6ed)}}.fe-modal__backdrop--chromeless{background:transparent;padding:0}.fe-modal__card--chromeless{max-width:none;width:100vw;height:100vh;max-height:100vh;border-radius:0;box-shadow:none}.fe-modal__card--chromeless .fe-modal__body{flex:1 1 auto;min-height:0;padding:0}.fe-modal__card--chromeless .fe-preview{align-items:stretch;justify-content:stretch;min-height:0;flex:1 1 auto}.fe-modal__card--chromeless .fe-preview>*{width:100%;height:100%}.fe-modal__head{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--fe-border)}.fe-modal__title{font-size:16px;font-weight:600;margin:0}.fe-modal__close{background:transparent;border:0;color:var(--fe-text-muted);font-size:22px;cursor:pointer;padding:0 4px;line-height:1}.fe-modal__body{padding:16px;overflow:auto;flex:1 1 auto}.fe-modal__actions{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--fe-border);background:var(--fe-bg-elev)}.fe-modal-enter-active,.fe-modal-leave-active{transition:opacity .15s}.fe-modal-enter-from,.fe-modal-leave-to{opacity:0}.fe-input{width:100%;padding:8px 10px;background:var(--fe-bg);border:1px solid var(--fe-border);border-radius:var(--fe-radius-sm);font:inherit;color:var(--fe-text)}.fe-input:focus-visible{outline:2px solid var(--fe-primary);outline-offset:1px}.fe-input--mono{font-family:var(--fe-font-mono);letter-spacing:.1em}.fe-form{display:flex;flex-direction:column;gap:12px}.fe-form__row{display:flex;align-items:center;gap:8px}.fe-form__row--stack{flex-direction:column;align-items:stretch}.fe-form__error{color:var(--fe-danger);font-size:12px;margin:6px 0 0}.fe-share-result{display:flex;flex-direction:column;gap:12px}.fe-share-result__row label{display:block;font-size:12px;font-weight:600;color:var(--fe-text-muted);margin-bottom:4px}.fe-share-result__copy{display:flex;gap:6px}.fe-preview{display:flex;align-items:center;justify-content:center;width:100%;height:100%;min-height:50vh;background:var(--fe-bg-elev)}.fe-preview__image{max-width:100%;max-height:70vh;object-fit:contain}.fe-preview__video,.fe-preview__audio{max-width:100%;max-height:70vh}.fe-preview__iframe{width:100%;height:70vh;border:0;background:#fff}.fe-preview__office{width:100%;height:78vh;background:var(--fe-bg)}.fe-preview__code-wrap{display:flex;flex-direction:column;width:100%;height:78vh}.fe-preview__code-toolbar{display:flex;align-items:center;gap:12px;padding:8px 12px;background:var(--fe-bg-hover, #f3f4f6);border-bottom:1px solid var(--fe-border, #e5e7eb);font-size:12px}.fe-preview__code-lang{font-family:var(--fe-font-mono, ui-monospace, monospace);color:var(--fe-text-muted);text-transform:uppercase;letter-spacing:.04em}.fe-preview__code-toolbar>.fe-btn{margin-left:auto}.fe-preview__code-status{font-size:12px;font-weight:500}.fe-preview__code-status--ok{color:#059669}.fe-preview__code-status--err{color:#dc2626;cursor:help}.fe-preview__code-editor{flex:1;min-height:0;overflow:hidden}.fe-preview__code-editor .cm-editor{height:100%;font-size:13px}.fe-preview__code-editor .cm-scroller{font-family:var(--fe-font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace)}.fe-preview__fallback{text-align:center;color:var(--fe-text-muted);padding:40px 20px}.fe-preview__fallback-icon{font-size:48px;display:block;margin-bottom:12px}.fe-preview__pre{margin:0;padding:16px;width:100%;max-height:70vh;overflow:auto;background:var(--fe-bg);color:var(--fe-text);font-family:var(--fe-font-mono);font-size:13px;line-height:1.5;white-space:pre-wrap;word-wrap:break-word}.fe-preview__code{white-space:pre;word-wrap:normal}.hljs{background:var(--fe-bg);color:var(--fe-text)}.hljs-comment,.hljs-quote{color:var(--fe-text-muted);font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-built_in,.hljs-section,.hljs-meta{color:#c678dd}.hljs-string,.hljs-attr,.hljs-symbol,.hljs-bullet,.hljs-addition,.hljs-link{color:#98c379}.hljs-number,.hljs-literal,.hljs-deletion{color:#d19a66}.hljs-title,.hljs-name,.hljs-selector-id,.hljs-selector-class,.hljs-template-tag,.hljs-template-variable{color:#61aeee}.hljs-type,.hljs-tag{color:#e06c75}.hljs-variable,.hljs-attribute{color:#d19a66}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.fe-preview__md{width:100%;max-height:70vh;overflow:auto;padding:24px 32px;background:var(--fe-bg);color:var(--fe-text);line-height:1.6;font-size:15px}.fe-preview__md h1,.fe-preview__md h2,.fe-preview__md h3,.fe-preview__md h4{margin:1.2em 0 .6em;font-weight:600}.fe-preview__md h1{font-size:1.8em;border-bottom:1px solid var(--fe-border);padding-bottom:.3em}.fe-preview__md h2{font-size:1.4em;border-bottom:1px solid var(--fe-border);padding-bottom:.3em}.fe-preview__md h3{font-size:1.2em}.fe-preview__md p{margin:.8em 0}.fe-preview__md a{color:var(--fe-primary);text-decoration:underline}.fe-preview__md code{font-family:var(--fe-font-mono);background:var(--fe-bg-elev);padding:1px 5px;border-radius:3px;font-size:.92em}.fe-preview__md pre{background:var(--fe-bg-elev);border:1px solid var(--fe-border);border-radius:var(--fe-radius-sm);padding:12px 16px;overflow:auto;font-size:.9em}.fe-preview__md pre code{background:transparent;padding:0}.fe-preview__md ul,.fe-preview__md ol{padding-left:2em;margin:.8em 0}.fe-preview__md li{margin:.3em 0}.fe-preview__md blockquote{border-left:3px solid var(--fe-border-strong);padding:0 1em;color:var(--fe-text-muted);margin:.8em 0}.fe-preview__md table{border-collapse:collapse;margin:1em 0;width:100%}.fe-preview__md th,.fe-preview__md td{border:1px solid var(--fe-border);padding:6px 10px;text-align:left}.fe-preview__md th{background:var(--fe-bg-elev)}.fe-preview__md img{max-width:100%}.fe-toast{position:absolute;bottom:24px;left:50%;transform:translate(-50%);background:var(--fe-text);color:var(--fe-bg);padding:8px 14px;border-radius:var(--fe-radius);font-size:13px;box-shadow:var(--fe-shadow-sm);z-index:95}.fe-toast-enter-active,.fe-toast-leave-active{transition:opacity .2s,transform .2s}.fe-toast-enter-from,.fe-toast-leave-to{opacity:0;transform:translate(-50%,10px)}@media (max-width: 640px){.fe-list__head,.fe-list__row{grid-template-columns:28px minmax(0,1fr) 90px}.fe-list__col--mod{display:none}.fe-toolbar{padding:8px}.fe-search__input{min-width:120px}}.filex-viewer-3d[data-v-299b3816]{width:100%;height:100%;min-height:480px;background:#1a1a1a;display:flex;align-items:center;justify-content:center}.filex-viewer-3d[data-v-299b3816] model-viewer{width:100%;height:100%;min-height:480px;background:#1a1a1a;display:block}.filex-viewer-fallback[data-v-299b3816]{text-align:center;color:#c8cdd6;padding:32px;max-width:480px}.filex-viewer-fallback__icon[data-v-299b3816]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-epub__nav[data-v-639afd99]{position:absolute;bottom:12px;left:50%;transform:translate(-50%);display:flex;gap:8px;padding:4px 8px;background:var(--fe-bg-elev, rgba(255, 255, 255, .9));border:1px solid var(--fe-border, #e2e6ed);border-radius:6px;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.filex-viewer-epub[data-v-639afd99]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27);position:relative}.filex-viewer-epub__bar[data-v-639afd99]{display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--fe-bg-elev, #f7f8fa);border-bottom:1px solid var(--fe-border, #e2e6ed);font-size:13px}.filex-viewer-spacer[data-v-639afd99]{flex:1}.filex-viewer-epub__fs[data-v-639afd99]{display:inline-block;min-width:40px;text-align:center;font-variant-numeric:tabular-nums;font-size:12px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-epub__main[data-v-639afd99]{flex:1;min-height:0;display:flex}.filex-viewer-epub__rendition[data-v-639afd99]{flex:1;min-height:0}.filex-viewer-epub__toc[data-v-639afd99]{width:260px;border-right:1px solid var(--fe-border, #e2e6ed);overflow-y:auto;padding:12px 0;background:var(--fe-bg-elev, #f7f8fa)}.filex-viewer-epub__toc ul[data-v-639afd99]{list-style:none;margin:0;padding:0}.filex-viewer-epub__toc-link[data-v-639afd99]{display:block;width:100%;text-align:left;background:transparent;border:0;padding:6px 14px;font:inherit;color:inherit;cursor:pointer}.filex-viewer-epub__toc-link[data-v-639afd99]:hover{background:var(--fe-bg-hover, #edf0f5)}.filex-viewer-epub__toc-link.is-child[data-v-639afd99]{padding-left:28px;color:var(--fe-text-muted, #5a6475);font-size:12px}.filex-viewer-epub__loading[data-v-639afd99]{position:absolute;inset:auto 0 0 0;text-align:center;padding:6px;background:#0000000d;font-size:12px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-fallback[data-v-639afd99]{text-align:center;padding:32px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-fallback__icon[data-v-639afd99]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-btn[data-v-639afd99]{border:1px solid var(--fe-border, #e2e6ed);background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27);padding:4px 10px;border-radius:4px;cursor:pointer;font:inherit;font-size:12px}.filex-viewer-btn[data-v-639afd99]:hover:not(:disabled){background:var(--fe-bg-hover, #edf0f5)}.filex-viewer-btn[data-v-639afd99]:disabled{opacity:.5;cursor:not-allowed}.filex-viewer-mermaid[data-v-e19076c3]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27)}.filex-viewer-mermaid__bar[data-v-e19076c3]{display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--fe-bg-elev, #f7f8fa);border-bottom:1px solid var(--fe-border, #e2e6ed);font-size:13px}.filex-viewer-mermaid__zoom[data-v-e19076c3]{min-width:50px;text-align:center;font-variant-numeric:tabular-nums;font-size:12px}.filex-viewer-mermaid__pane[data-v-e19076c3]{flex:1;overflow:hidden;position:relative;cursor:grab;background:var(--fe-bg-elev, #f7f8fa);touch-action:none}.filex-viewer-mermaid__pane[data-v-e19076c3]:active{cursor:grabbing}.filex-viewer-mermaid__surface[data-v-e19076c3]{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;transform-origin:center center;transition:transform .05s linear;-webkit-user-select:none;user-select:none}.filex-viewer-mermaid__surface[data-v-e19076c3] svg{max-width:90%;max-height:90%}.filex-viewer-fallback[data-v-e19076c3]{text-align:center;padding:32px;color:var(--fe-text-muted, #5a6475);width:100%;display:flex;flex-direction:column;align-items:center;justify-content:center}.filex-viewer-fallback__icon[data-v-e19076c3]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-btn[data-v-e19076c3]{border:1px solid var(--fe-border, #e2e6ed);background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27);padding:4px 10px;border-radius:4px;cursor:pointer;font:inherit;font-size:12px}.filex-viewer-btn[data-v-e19076c3]:hover:not(:disabled){background:var(--fe-bg-hover, #edf0f5)}.filex-viewer-drawio[data-v-680c72a8]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff)}.filex-viewer-drawio__bar[data-v-680c72a8]{display:flex;align-items:center;gap:12px;padding:6px 12px;background:var(--fe-bg-elev, #f7f8fa);border-bottom:1px solid var(--fe-border, #e2e6ed);font-size:12px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-drawio__status[data-state=error][data-v-680c72a8]{color:var(--fe-danger, #dc2626)}.filex-viewer-drawio__status[data-state=saved][data-v-680c72a8]{color:#059669}.filex-viewer-drawio__readonly[data-v-680c72a8]{font-style:italic;margin-left:auto}.filex-viewer-drawio__frame[data-v-680c72a8]{flex:1;width:100%;border:0;background:#fafafa;min-height:0}.filex-viewer-fallback[data-v-680c72a8]{text-align:center;padding:32px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-fallback__icon[data-v-680c72a8]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-tiff__pager[data-v-11c3469a]{position:absolute;bottom:12px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:8px;padding:4px 8px;background:var(--fe-bg-elev, rgba(255, 255, 255, .9));border:1px solid var(--fe-border, #e2e6ed);border-radius:6px;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.filex-viewer-tiff__pages[data-v-11c3469a]{font-size:12px;font-variant-numeric:tabular-nums}.filex-viewer-tiff[data-v-11c3469a]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff)}.filex-viewer-tiff__bar[data-v-11c3469a]{display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--fe-bg-elev, #f7f8fa);border-bottom:1px solid var(--fe-border, #e2e6ed);font-size:13px}.filex-viewer-tiff__pages[data-v-11c3469a]{min-width:110px;text-align:center;font-variant-numeric:tabular-nums;font-size:12px}.filex-viewer-tiff__zoom[data-v-11c3469a]{min-width:50px;text-align:center;font-variant-numeric:tabular-nums;font-size:12px}.filex-viewer-spacer[data-v-11c3469a]{flex:1}.filex-viewer-tiff__pane[data-v-11c3469a]{flex:1;overflow:auto;padding:16px;background:#2a2d33;display:flex;align-items:flex-start;justify-content:flex-start}.filex-viewer-tiff__pane canvas[data-v-11c3469a]{background:#fff;box-shadow:0 4px 16px #0000004d}.filex-viewer-fallback[data-v-11c3469a]{text-align:center;padding:32px;color:#c8cdd6;margin:auto}.filex-viewer-fallback__icon[data-v-11c3469a]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-btn[data-v-11c3469a]{border:1px solid var(--fe-border, #e2e6ed);background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27);padding:4px 10px;border-radius:4px;cursor:pointer;font:inherit;font-size:12px}.filex-viewer-btn[data-v-11c3469a]:hover:not(:disabled){background:var(--fe-bg-hover, #edf0f5)}.filex-viewer-btn[data-v-11c3469a]:disabled{opacity:.4;cursor:not-allowed}.filex-viewer-psd[data-v-46b5b3c2]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff)}.filex-viewer-psd__bar[data-v-46b5b3c2]{display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--fe-bg-elev, #f7f8fa);border-bottom:1px solid var(--fe-border, #e2e6ed);font-size:13px}.filex-viewer-spacer[data-v-46b5b3c2]{flex:1}.filex-viewer-psd__dim[data-v-46b5b3c2]{font-size:12px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-psd__zoom[data-v-46b5b3c2]{min-width:50px;text-align:center;font-variant-numeric:tabular-nums;font-size:12px}.filex-viewer-psd__main[data-v-46b5b3c2]{flex:1;display:flex;min-height:0}.filex-viewer-psd__layers[data-v-46b5b3c2]{width:240px;border-right:1px solid var(--fe-border, #e2e6ed);overflow-y:auto;padding:8px 0;background:var(--fe-bg-elev, #f7f8fa)}.filex-viewer-psd__layers ul[data-v-46b5b3c2]{list-style:none;margin:0;padding:0}.filex-viewer-psd__layers li[data-v-46b5b3c2]{display:flex;align-items:center;gap:6px;padding:4px 12px;font-size:12px}.filex-viewer-psd__layer-vis[data-v-46b5b3c2]{width:14px;text-align:center;color:var(--fe-text-muted, #5a6475)}.filex-viewer-psd__layer-vis[data-hidden="1"][data-v-46b5b3c2]{color:var(--fe-border-strong, #c7ced9)}.filex-viewer-psd__layer-name[data-v-46b5b3c2]{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.filex-viewer-psd__pane[data-v-46b5b3c2]{flex:1;overflow:auto;padding:16px;background:#2a2d33;display:flex;align-items:flex-start;justify-content:flex-start}.filex-viewer-psd__pane canvas[data-v-46b5b3c2]{background:#fff repeating-conic-gradient(#e0e0e0 0% 25%,transparent 0% 50%) 50% / 16px 16px;box-shadow:0 4px 16px #0000004d}.filex-viewer-fallback[data-v-46b5b3c2]{text-align:center;padding:32px;color:#c8cdd6;margin:auto}.filex-viewer-fallback__icon[data-v-46b5b3c2]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-btn[data-v-46b5b3c2]{border:1px solid var(--fe-border, #e2e6ed);background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27);padding:4px 10px;border-radius:4px;cursor:pointer;font:inherit;font-size:12px}.filex-viewer-btn[data-v-46b5b3c2]:hover:not(:disabled){background:var(--fe-bg-hover, #edf0f5)}.filex-viewer-btn.is-active[data-v-46b5b3c2]{background:var(--fe-bg-selected, #dfe8ff);border-color:var(--fe-primary, #3b82f6)}.filex-viewer-ipynb[data-v-10bd637a]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27)}.filex-viewer-ipynb__bar[data-v-10bd637a]{display:flex;align-items:center;gap:12px;padding:8px 12px;background:var(--fe-bg-elev, #f7f8fa);border-bottom:1px solid var(--fe-border, #e2e6ed);font-size:12px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-ipynb__lang[data-v-10bd637a]{font-family:var(--fe-font-mono, monospace);text-transform:uppercase;letter-spacing:.04em}.filex-viewer-ipynb__pane[data-v-10bd637a]{flex:1;overflow:auto;padding:16px 24px}.filex-viewer-ipynb__cell[data-v-10bd637a]{border:1px solid var(--fe-border, #e2e6ed);border-radius:6px;margin-bottom:16px;overflow:hidden}.filex-viewer-ipynb__cell[data-type=code][data-v-10bd637a]{background:var(--fe-bg-elev, #f7f8fa)}.filex-viewer-ipynb__exec[data-v-10bd637a]{padding:4px 12px;font-family:var(--fe-font-mono, monospace);font-size:11px;color:var(--fe-text-muted, #5a6475);background:#0000000a}.filex-viewer-ipynb__src[data-v-10bd637a]{margin:0;padding:12px;font-family:var(--fe-font-mono, monospace);font-size:12px;line-height:1.5;white-space:pre;overflow-x:auto}.filex-viewer-ipynb__outputs[data-v-10bd637a]{border-top:1px dashed var(--fe-border, #e2e6ed);background:var(--fe-bg, #fff);padding:8px 12px}.filex-viewer-ipynb__out[data-v-10bd637a]{margin:0;padding:4px 0;font-family:var(--fe-font-mono, monospace);font-size:12px;white-space:pre-wrap;word-wrap:break-word}.filex-viewer-ipynb__out[data-type=error][data-v-10bd637a]{color:var(--fe-danger, #dc2626)}.filex-viewer-ipynb__img[data-v-10bd637a]{display:block;max-width:100%;height:auto;margin:8px 0}.filex-viewer-ipynb__html[data-v-10bd637a]{font-size:13px}.filex-viewer-ipynb__md[data-v-10bd637a]{padding:12px 16px;font-size:14px;line-height:1.6}.filex-viewer-ipynb__md-raw[data-v-10bd637a]{padding:12px;margin:0;font-family:var(--fe-font-mono, monospace);font-size:12px;white-space:pre-wrap}.filex-viewer-fallback[data-v-10bd637a]{text-align:center;padding:32px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-fallback__icon[data-v-10bd637a]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-csv[data-v-1a0b9c8e]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27)}.filex-viewer-csv__bar[data-v-1a0b9c8e]{display:flex;align-items:center;gap:12px;padding:8px 12px;background:var(--fe-bg-elev, #f7f8fa);border-bottom:1px solid var(--fe-border, #e2e6ed);font-size:12px}.filex-viewer-csv__check[data-v-1a0b9c8e]{display:flex;align-items:center;gap:4px;font-size:12px}.filex-viewer-csv__select[data-v-1a0b9c8e],.filex-viewer-csv__filter[data-v-1a0b9c8e]{border:1px solid var(--fe-border, #e2e6ed);background:var(--fe-bg, #fff);color:inherit;padding:4px 8px;border-radius:4px;font:inherit;font-size:12px}.filex-viewer-csv__filter[data-v-1a0b9c8e]{flex:0 1 240px}.filex-viewer-spacer[data-v-1a0b9c8e]{flex:1}.filex-viewer-csv__count[data-v-1a0b9c8e]{font-size:11px;color:var(--fe-text-muted, #5a6475);font-variant-numeric:tabular-nums}.filex-viewer-csv__pane[data-v-1a0b9c8e]{flex:1;overflow:auto}.filex-viewer-csv__table[data-v-1a0b9c8e]{border-collapse:collapse;width:max-content;min-width:100%;font-size:12px;font-family:var(--fe-font-mono, monospace)}.filex-viewer-csv__table th[data-v-1a0b9c8e],.filex-viewer-csv__table td[data-v-1a0b9c8e]{padding:4px 10px;border:1px solid var(--fe-border, #e2e6ed);white-space:nowrap;max-width:320px;overflow:hidden;text-overflow:ellipsis}.filex-viewer-csv__table th[data-v-1a0b9c8e]{background:var(--fe-bg-elev, #f7f8fa);position:sticky;top:0;font-weight:600;text-align:left}.filex-viewer-csv__table tbody tr[data-v-1a0b9c8e]:nth-child(2n){background:var(--fe-bg-hover, rgba(0, 0, 0, .02))}.filex-viewer-csv__rownum[data-v-1a0b9c8e]{color:var(--fe-text-muted, #5a6475);text-align:right;background:var(--fe-bg-elev, #f7f8fa);font-variant-numeric:tabular-nums;position:sticky;left:0}.filex-viewer-csv__pager[data-v-1a0b9c8e]{display:flex;justify-content:center;align-items:center;gap:8px;padding:6px;background:var(--fe-bg-elev, #f7f8fa);border-top:1px solid var(--fe-border, #e2e6ed);font-size:12px}.filex-viewer-csv__pageno[data-v-1a0b9c8e]{font-variant-numeric:tabular-nums;font-size:12px}.filex-viewer-fallback[data-v-1a0b9c8e]{text-align:center;padding:32px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-fallback__icon[data-v-1a0b9c8e]{font-size:48px;display:block;margin-bottom:12px}.filex-viewer-btn[data-v-1a0b9c8e]{border:1px solid var(--fe-border, #e2e6ed);background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27);padding:4px 10px;border-radius:4px;cursor:pointer;font:inherit;font-size:12px}.filex-viewer-btn[data-v-1a0b9c8e]:hover:not(:disabled){background:var(--fe-bg-hover, #edf0f5)}.filex-viewer-btn[data-v-1a0b9c8e]:disabled{opacity:.4;cursor:not-allowed}.filex-viewer-archive[data-v-d3ad0fc4]{display:flex;flex-direction:column;width:100%;height:100%;min-height:70vh;background:var(--fe-bg, #fff);color:var(--fe-text, #1a1e27)}.filex-viewer-archive__pane[data-v-d3ad0fc4]{flex:1;overflow:auto;padding:16px 20px}.filex-viewer-archive__summary[data-v-d3ad0fc4]{font-size:12px;color:var(--fe-text-muted, #5a6475);margin-bottom:12px;font-variant-numeric:tabular-nums}.filex-viewer-archive__table[data-v-d3ad0fc4]{width:100%;border-collapse:collapse;font-size:13px;font-family:var(--fe-font-mono, monospace)}.filex-viewer-archive__table th[data-v-d3ad0fc4],.filex-viewer-archive__table td[data-v-d3ad0fc4]{padding:6px 12px;border-bottom:1px solid var(--fe-border, #e2e6ed);text-align:left}.filex-viewer-archive__table th[data-v-d3ad0fc4]{background:var(--fe-bg-elev, #f7f8fa);font-weight:600;position:sticky;top:0}.filex-viewer-archive__size[data-v-d3ad0fc4]{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap;color:var(--fe-text-muted, #5a6475)}.filex-viewer-archive__icon[data-v-d3ad0fc4]{margin-right:6px}.filex-viewer-archive__table tr[data-dir="1"][data-v-d3ad0fc4]{color:var(--fe-text-muted, #5a6475)}.filex-viewer-fallback[data-v-d3ad0fc4]{text-align:center;padding:32px;color:var(--fe-text-muted, #5a6475)}.filex-viewer-fallback__icon[data-v-d3ad0fc4]{font-size:48px;display:block;margin-bottom:12px}
@@ -1 +1 @@
1
- {"version":3,"file":"useViewerFetch-czqbd2Lj.js","sources":["../../core/src/composables/useViewerFetch.ts"],"sourcesContent":["/**\r\n * useViewerFetch — tiny wrapper around `fetch` for the rich viewers.\r\n *\r\n * The PreviewModal already builds and pushes `authHeaders` + the\r\n * configured `credentials` mode into every viewer. The viewers need\r\n * binary access (ArrayBuffer for utif/ag-psd/pdfjs, Blob for EPUB,\r\n * text for CSV/Mermaid/ipynb), and they all want to honour the same\r\n * auth strategy.\r\n *\r\n * Each helper uses the URL the modal hands down (`previewUrl(path)`)\r\n * and merges in the same headers + credentials so a CSRF/Bearer host\r\n * doesn't reject the request when the viewer fetches the file body\r\n * directly (instead of letting the browser do it via `<img src>` etc).\r\n */\r\nexport interface ViewerFetchOptions {\r\n url: string;\r\n headers?: Record<string, string>;\r\n credentials?: RequestCredentials;\r\n signal?: AbortSignal;\r\n}\r\n\r\nasync function fetchOk(opts: ViewerFetchOptions): Promise<Response> {\r\n const res = await fetch(opts.url, {\r\n headers: opts.headers ?? {},\r\n credentials: opts.credentials ?? 'same-origin',\r\n signal: opts.signal,\r\n });\r\n if (!res.ok) {\r\n const text = await res.text().catch(() => '');\r\n throw new Error(\r\n `${res.status} ${res.statusText}${text ? ' — ' + text.slice(0, 200) : ''}`,\r\n );\r\n }\r\n return res;\r\n}\r\n\r\nexport async function fetchViewerArrayBuffer(\r\n opts: ViewerFetchOptions,\r\n): Promise<ArrayBuffer> {\r\n const res = await fetchOk(opts);\r\n return res.arrayBuffer();\r\n}\r\n\r\nexport async function fetchViewerBlob(\r\n opts: ViewerFetchOptions,\r\n): Promise<{ blob: Blob; objectUrl: string; mime: string }> {\r\n const res = await fetchOk(opts);\r\n const blob = await res.blob();\r\n const mime = blob.type || res.headers.get('content-type') || '';\r\n return { blob, objectUrl: URL.createObjectURL(blob), mime };\r\n}\r\n\r\nexport async function fetchViewerText(\r\n opts: ViewerFetchOptions,\r\n): Promise<string> {\r\n const res = await fetchOk(opts);\r\n return res.text();\r\n}\r\n"],"names":["fetchOk","opts","res","text","fetchViewerArrayBuffer","fetchViewerText"],"mappings":"AAqBA,eAAeA,EAAQC,GAA6C;AAClE,QAAMC,IAAM,MAAM,MAAMD,EAAK,KAAK;AAAA,IAChC,SAASA,EAAK,WAAW,CAAA;AAAA,IACzB,aAAaA,EAAK,eAAe;AAAA,IACjC,QAAQA,EAAK;AAAA,EAAA,CACd;AACD,MAAI,CAACC,EAAI,IAAI;AACX,UAAMC,IAAO,MAAMD,EAAI,OAAO,MAAM,MAAM,EAAE;AAC5C,UAAM,IAAI;AAAA,MACR,GAAGA,EAAI,MAAM,IAAIA,EAAI,UAAU,GAAGC,IAAO,QAAQA,EAAK,MAAM,GAAG,GAAG,IAAI,EAAE;AAAA,IAAA;AAAA,EAE5E;AACA,SAAOD;AACT;AAEA,eAAsBE,EACpBH,GACsB;AAEtB,UADY,MAAMD,EAAQC,CAAI,GACnB,YAAA;AACb;AAWA,eAAsBI,EACpBJ,GACiB;AAEjB,UADY,MAAMD,EAAQC,CAAI,GACnB,KAAA;AACb;"}
1
+ {"version":3,"file":"useViewerFetch-czqbd2Lj.js","sources":["../../core/src/composables/useViewerFetch.ts"],"sourcesContent":["/**\n * useViewerFetch — tiny wrapper around `fetch` for the rich viewers.\n *\n * The PreviewModal already builds and pushes `authHeaders` + the\n * configured `credentials` mode into every viewer. The viewers need\n * binary access (ArrayBuffer for utif/ag-psd/pdfjs, Blob for EPUB,\n * text for CSV/Mermaid/ipynb), and they all want to honour the same\n * auth strategy.\n *\n * Each helper uses the URL the modal hands down (`previewUrl(path)`)\n * and merges in the same headers + credentials so a CSRF/Bearer host\n * doesn't reject the request when the viewer fetches the file body\n * directly (instead of letting the browser do it via `<img src>` etc).\n */\nexport interface ViewerFetchOptions {\n url: string;\n headers?: Record<string, string>;\n credentials?: RequestCredentials;\n signal?: AbortSignal;\n}\n\nasync function fetchOk(opts: ViewerFetchOptions): Promise<Response> {\n const res = await fetch(opts.url, {\n headers: opts.headers ?? {},\n credentials: opts.credentials ?? 'same-origin',\n signal: opts.signal,\n });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(\n `${res.status} ${res.statusText}${text ? ' — ' + text.slice(0, 200) : ''}`,\n );\n }\n return res;\n}\n\nexport async function fetchViewerArrayBuffer(\n opts: ViewerFetchOptions,\n): Promise<ArrayBuffer> {\n const res = await fetchOk(opts);\n return res.arrayBuffer();\n}\n\nexport async function fetchViewerBlob(\n opts: ViewerFetchOptions,\n): Promise<{ blob: Blob; objectUrl: string; mime: string }> {\n const res = await fetchOk(opts);\n const blob = await res.blob();\n const mime = blob.type || res.headers.get('content-type') || '';\n return { blob, objectUrl: URL.createObjectURL(blob), mime };\n}\n\nexport async function fetchViewerText(\n opts: ViewerFetchOptions,\n): Promise<string> {\n const res = await fetchOk(opts);\n return res.text();\n}\n"],"names":["fetchOk","opts","res","text","fetchViewerArrayBuffer","fetchViewerText"],"mappings":"AAqBA,eAAeA,EAAQC,GAA6C;AAClE,QAAMC,IAAM,MAAM,MAAMD,EAAK,KAAK;AAAA,IAChC,SAASA,EAAK,WAAW,CAAA;AAAA,IACzB,aAAaA,EAAK,eAAe;AAAA,IACjC,QAAQA,EAAK;AAAA,EAAA,CACd;AACD,MAAI,CAACC,EAAI,IAAI;AACX,UAAMC,IAAO,MAAMD,EAAI,OAAO,MAAM,MAAM,EAAE;AAC5C,UAAM,IAAI;AAAA,MACR,GAAGA,EAAI,MAAM,IAAIA,EAAI,UAAU,GAAGC,IAAO,QAAQA,EAAK,MAAM,GAAG,GAAG,IAAI,EAAE;AAAA,IAAA;AAAA,EAE5E;AACA,SAAOD;AACT;AAEA,eAAsBE,EACpBH,GACsB;AAEtB,UADY,MAAMD,EAAQC,CAAI,GACnB,YAAA;AACb;AAWA,eAAsBI,EACpBJ,GACiB;AAEjB,UADY,MAAMD,EAAQC,CAAI,GACnB,KAAA;AACb;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brftech/filex",
3
- "version": "0.1.56",
3
+ "version": "0.1.60",
4
4
  "description": "filex Web Component — drop-in <filex-explorer> custom element (Vue 3 runtime bundled)",
5
5
  "type": "module",
6
6
  "main": "./dist/filex.umd.cjs",
@@ -25,7 +25,7 @@
25
25
  ],
26
26
  "dependencies": {
27
27
  "vue": "^3.5.13",
28
- "@brftech/filex-core": "0.1.56"
28
+ "@brftech/filex-core": "0.1.60"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^22.7.0",
@@ -1 +0,0 @@
1
- {"version":3,"file":"ArchiveViewer-CMaBM4yZ.js","sources":["../../core/src/viewers/ArchiveViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\n/**\r\n * ArchiveViewer — minimal zip / archive contents preview.\r\n *\r\n * Hits `POST /api/files/archive/list` with the adapter-qualified path\r\n * and renders the member list as a flat table (name, size, mtime).\r\n * Read-only — extraction is exposed elsewhere (context menu / actions\r\n * panel). The viewer's job is just \"what's inside?\" so the user can\r\n * decide whether to extract or download.\r\n */\r\nimport { computed, onMounted, ref, watch } from 'vue';\r\n\r\ninterface ArchiveEntry {\r\n name: string;\r\n size: number;\r\n mtime?: string;\r\n is_dir?: boolean;\r\n}\r\n\r\nconst props = defineProps<{\r\n url: string;\r\n filePath?: string;\r\n ext: string;\r\n t?: (key: string) => string;\r\n authHeaders?: () => Record<string, string>;\r\n authCredentials?: RequestCredentials;\r\n}>();\r\n\r\nconst entries = ref<ArchiveEntry[]>([]);\r\nconst loading = ref(true);\r\nconst error = ref<string | null>(null);\r\n\r\nfunction tt(key: string, fallback: string): string {\r\n return props.t ? props.t(key) : fallback;\r\n}\r\n\r\nfunction fmtSize(n: number): string {\r\n if (n < 1024) return `${n} B`;\r\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;\r\n if (n < 1024 * 1024 * 1024) return `${(n / (1024 * 1024)).toFixed(1)} MB`;\r\n return `${(n / (1024 * 1024 * 1024)).toFixed(2)} GB`;\r\n}\r\n\r\nasync function load(): Promise<void> {\r\n loading.value = true;\r\n error.value = null;\r\n entries.value = [];\r\n // The viewer is mounted with the resolved file path. Hit the API\r\n // endpoint with the same adapter-qualified path the preview URL\r\n // points at — the backend resolves storage + relative path itself.\r\n if (!props.filePath) {\r\n error.value = tt('viewer.archive.error', 'Could not read archive contents.');\r\n loading.value = false;\r\n return;\r\n }\r\n try {\r\n const res = await fetch('/api/files/archive/list', {\r\n method: 'POST',\r\n credentials: props.authCredentials || 'include',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...(props.authHeaders ? props.authHeaders() : {}),\r\n },\r\n body: JSON.stringify({ path: props.filePath }),\r\n });\r\n if (!res.ok) {\r\n throw new Error(`${res.status} ${res.statusText}`);\r\n }\r\n const body = (await res.json()) as { entries?: ArchiveEntry[] };\r\n entries.value = body.entries ?? [];\r\n } catch (err) {\r\n error.value = err instanceof Error ? err.message : tt('viewer.archive.error', 'Could not read archive contents.');\r\n } finally {\r\n loading.value = false;\r\n }\r\n}\r\n\r\nonMounted(load);\r\nwatch(() => props.filePath, load);\r\n\r\nconst totalSize = computed(() => entries.value.reduce((sum, e) => sum + (e.size || 0), 0));\r\nconst fileCount = computed(() => entries.value.filter((e) => !e.is_dir).length);\r\n</script>\r\n\r\n<template>\r\n <div class=\"filex-viewer-archive\">\r\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">🗜️</span>\r\n <p>{{ error }}</p>\r\n </div>\r\n <div v-else-if=\"loading\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">⏳</span>\r\n <p>{{ tt('viewer.loading', 'Loading…') }}</p>\r\n </div>\r\n <div v-else-if=\"entries.length === 0\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">🗜️</span>\r\n <p>{{ tt('viewer.archive.empty', 'Archive is empty.') }}</p>\r\n </div>\r\n <div v-else class=\"filex-viewer-archive__pane\">\r\n <div class=\"filex-viewer-archive__summary\">\r\n {{ fileCount }} {{ tt('viewer.archive.entries', '{n} files').replace('{n}', String(fileCount)) }}\r\n · {{ fmtSize(totalSize) }}\r\n </div>\r\n <table class=\"filex-viewer-archive__table\">\r\n <thead>\r\n <tr>\r\n <th>{{ tt('viewer.name', 'Name') }}</th>\r\n <th class=\"filex-viewer-archive__size\">{{ tt('viewer.size', 'Size') }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr v-for=\"(e, i) in entries\" :key=\"i\" :data-dir=\"e.is_dir ? '1' : '0'\">\r\n <td>\r\n <span class=\"filex-viewer-archive__icon\">{{ e.is_dir ? '📁' : '📄' }}</span>\r\n {{ e.name }}\r\n </td>\r\n <td class=\"filex-viewer-archive__size\">{{ e.is_dir ? '' : fmtSize(e.size) }}</td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.filex-viewer-archive {\r\n display: flex;\r\n flex-direction: column;\r\n width: 100%;\r\n height: 100%;\r\n min-height: 70vh;\r\n background: var(--fe-bg, #fff);\r\n color: var(--fe-text, #1a1e27);\r\n}\r\n.filex-viewer-archive__pane {\r\n flex: 1;\r\n overflow: auto;\r\n padding: 16px 20px;\r\n}\r\n.filex-viewer-archive__summary {\r\n font-size: 12px;\r\n color: var(--fe-text-muted, #5a6475);\r\n margin-bottom: 12px;\r\n font-variant-numeric: tabular-nums;\r\n}\r\n.filex-viewer-archive__table {\r\n width: 100%;\r\n border-collapse: collapse;\r\n font-size: 13px;\r\n font-family: var(--fe-font-mono, monospace);\r\n}\r\n.filex-viewer-archive__table th,\r\n.filex-viewer-archive__table td {\r\n padding: 6px 12px;\r\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\r\n text-align: left;\r\n}\r\n.filex-viewer-archive__table th {\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n font-weight: 600;\r\n position: sticky;\r\n top: 0;\r\n}\r\n.filex-viewer-archive__size {\r\n text-align: right;\r\n font-variant-numeric: tabular-nums;\r\n white-space: nowrap;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-archive__icon {\r\n margin-right: 6px;\r\n}\r\n.filex-viewer-archive__table tr[data-dir=\"1\"] {\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-fallback {\r\n text-align: center;\r\n padding: 32px;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-fallback__icon {\r\n font-size: 48px;\r\n display: block;\r\n margin-bottom: 12px;\r\n}\r\n</style>\r\n"],"names":["props","__props","entries","ref","loading","error","tt","key","fallback","fmtSize","n","load","res","body","err","onMounted","watch","totalSize","computed","sum","e","fileCount","_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","_cache","_createElementVNode","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_toDisplayString","_hoisted_7","_hoisted_8","_Fragment","_renderList","i","_hoisted_10","_hoisted_11"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"CsvViewer-D5_c7bkP.js","sources":["../../core/src/viewers/CsvViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\n/**\r\n * CsvViewer — lightweight CSV / TSV table preview.\r\n *\r\n * Lazy-imports `papaparse` when available (best-quality parser — handles\r\n * embedded quotes, multi-line cells, etc). Falls back to a simple\r\n * `split` parser when the peer is missing — workable for the trivial\r\n * \"first 1000 rows\" preview case but loses fidelity on complex files.\r\n *\r\n * UX:\r\n * - first-row-as-header toggle\r\n * - filter input that case-insensitively matches any cell\r\n * - 100-rows-per-page pagination\r\n * - tab vs comma auto-detection (manual override via toolbar)\r\n */\r\nimport { computed, onMounted, ref, watch } from 'vue';\r\nimport { fetchViewerText } from '../composables/useViewerFetch';\r\n\r\nconst props = defineProps<{\r\n url: string;\r\n ext: string;\r\n t?: (key: string) => string;\r\n authHeaders?: () => Record<string, string>;\r\n authCredentials?: RequestCredentials;\r\n}>();\r\n\r\nconst PAGE_SIZE = 100;\r\nconst ROW_LIMIT = 1000;\r\n\r\nconst rows = ref<string[][]>([]);\r\nconst error = ref<string | null>(null);\r\nconst loading = ref(true);\r\nconst firstRowHeader = ref(true);\r\nconst filter = ref('');\r\nconst page = ref(1);\r\nconst detectedDelim = ref<',' | '\\t' | ';'>(',');\r\nconst userDelim = ref<'auto' | ',' | '\\t' | ';'>('auto');\r\n\r\nlet renderToken = 0;\r\n\r\nfunction detectDelimiter(sample: string): ',' | '\\t' | ';' {\r\n const sampleLines = sample.split(/\\r?\\n/).slice(0, 5).join('\\n');\r\n const tab = (sampleLines.match(/\\t/g) || []).length;\r\n const semi = (sampleLines.match(/;/g) || []).length;\r\n const comma = (sampleLines.match(/,/g) || []).length;\r\n if (tab > comma && tab > semi) return '\\t';\r\n if (semi > comma && semi > tab) return ';';\r\n return ',';\r\n}\r\n\r\nasync function parseWith(text: string, delim: string): Promise<string[][]> {\r\n try {\r\n const mod = await import(/* @vite-ignore */ 'papaparse');\r\n const Papa = (mod as any).default ?? mod;\r\n const result = Papa.parse(text, {\r\n delimiter: delim,\r\n skipEmptyLines: true,\r\n header: false,\r\n });\r\n return (result.data as string[][]).slice(0, ROW_LIMIT);\r\n } catch {\r\n // Fallback: naive line/column split. Loses quoted-comma support\r\n // but renders something reasonable.\r\n return text\r\n .split(/\\r?\\n/)\r\n .filter((l) => l.length > 0)\r\n .slice(0, ROW_LIMIT)\r\n .map((line) => line.split(delim));\r\n }\r\n}\r\n\r\nasync function load(): Promise<void> {\r\n loading.value = true;\r\n error.value = null;\r\n rows.value = [];\r\n page.value = 1;\r\n const myToken = ++renderToken;\r\n\r\n let text: string;\r\n try {\r\n text = await fetchViewerText({\r\n url: props.url,\r\n headers: props.authHeaders?.() ?? {},\r\n credentials: props.authCredentials,\r\n });\r\n } catch (err) {\r\n error.value = err instanceof Error ? err.message : 'fetch failed';\r\n loading.value = false;\r\n return;\r\n }\r\n\r\n if (myToken !== renderToken) return;\r\n\r\n if (props.ext === 'tsv') {\r\n detectedDelim.value = '\\t';\r\n } else {\r\n detectedDelim.value = detectDelimiter(text.slice(0, 4096));\r\n }\r\n\r\n const delim = userDelim.value === 'auto' ? detectedDelim.value : userDelim.value;\r\n rows.value = await parseWith(text, delim);\r\n loading.value = false;\r\n}\r\n\r\nonMounted(load);\r\nwatch(() => props.url, load);\r\nwatch(() => userDelim.value, () => {\r\n if (rows.value.length === 0) return;\r\n // Re-parse with the new delimiter using the cached source — but we\r\n // didn't keep it. Cheapest path is a refetch.\r\n load();\r\n});\r\n\r\nconst headers = computed<string[]>(() => {\r\n if (!firstRowHeader.value || rows.value.length === 0) {\r\n if (rows.value.length === 0) return [];\r\n return rows.value[0].map((_, i) => `Col ${i + 1}`);\r\n }\r\n return rows.value[0];\r\n});\r\n\r\nconst dataRows = computed<string[][]>(() => {\r\n return firstRowHeader.value ? rows.value.slice(1) : rows.value;\r\n});\r\n\r\nconst filtered = computed<string[][]>(() => {\r\n const q = filter.value.trim().toLowerCase();\r\n if (!q) return dataRows.value;\r\n return dataRows.value.filter((r) =>\r\n r.some((c) => (c || '').toLowerCase().includes(q)),\r\n );\r\n});\r\n\r\nconst totalPages = computed(() =>\r\n Math.max(1, Math.ceil(filtered.value.length / PAGE_SIZE)),\r\n);\r\n\r\nconst visibleRows = computed<string[][]>(() => {\r\n const start = (page.value - 1) * PAGE_SIZE;\r\n return filtered.value.slice(start, start + PAGE_SIZE);\r\n});\r\n\r\nwatch(filter, () => {\r\n page.value = 1;\r\n});\r\n\r\nfunction tt(key: string, fallback: string): string {\r\n return props.t ? props.t(key) : fallback;\r\n}\r\n</script>\r\n\r\n<template>\r\n <div class=\"filex-viewer-csv\">\r\n <div class=\"filex-viewer-csv__pane\">\r\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">📊</span>\r\n <p>{{ error }}</p>\r\n </div>\r\n <div v-else-if=\"loading\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">⏳</span>\r\n <p>{{ tt('viewer.loading', 'Loading…') }}</p>\r\n </div>\r\n <table v-else class=\"filex-viewer-csv__table\">\r\n <thead>\r\n <tr>\r\n <th class=\"filex-viewer-csv__rownum\">#</th>\r\n <th v-for=\"(h, i) in headers\" :key=\"i\">{{ h }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr v-for=\"(row, ri) in visibleRows\" :key=\"ri\">\r\n <td class=\"filex-viewer-csv__rownum\">{{ (page - 1) * 100 + ri + 1 }}</td>\r\n <td v-for=\"(c, ci) in row\" :key=\"ci\">{{ c }}</td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n <div v-if=\"!loading && !error && totalPages > 1\" class=\"filex-viewer-csv__pager\">\r\n <button\r\n type=\"button\"\r\n class=\"filex-viewer-btn\"\r\n :disabled=\"page <= 1\"\r\n @click=\"page--\"\r\n >‹</button>\r\n <span class=\"filex-viewer-csv__pageno\">{{ page }} / {{ totalPages }} ({{ filtered.length }} satır)</span>\r\n <button\r\n type=\"button\"\r\n class=\"filex-viewer-btn\"\r\n :disabled=\"page >= totalPages\"\r\n @click=\"page++\"\r\n >›</button>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.filex-viewer-csv {\r\n display: flex;\r\n flex-direction: column;\r\n width: 100%;\r\n height: 100%;\r\n min-height: 70vh;\r\n background: var(--fe-bg, #fff);\r\n color: var(--fe-text, #1a1e27);\r\n}\r\n.filex-viewer-csv__bar {\r\n display: flex;\r\n align-items: center;\r\n gap: 12px;\r\n padding: 8px 12px;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\r\n font-size: 12px;\r\n}\r\n.filex-viewer-csv__check {\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-csv__select,\r\n.filex-viewer-csv__filter {\r\n border: 1px solid var(--fe-border, #e2e6ed);\r\n background: var(--fe-bg, #fff);\r\n color: inherit;\r\n padding: 4px 8px;\r\n border-radius: 4px;\r\n font: inherit;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-csv__filter {\r\n flex: 0 1 240px;\r\n}\r\n.filex-viewer-spacer { flex: 1; }\r\n.filex-viewer-csv__count {\r\n font-size: 11px;\r\n color: var(--fe-text-muted, #5a6475);\r\n font-variant-numeric: tabular-nums;\r\n}\r\n.filex-viewer-csv__pane {\r\n flex: 1;\r\n overflow: auto;\r\n}\r\n.filex-viewer-csv__table {\r\n border-collapse: collapse;\r\n width: max-content;\r\n min-width: 100%;\r\n font-size: 12px;\r\n font-family: var(--fe-font-mono, monospace);\r\n}\r\n.filex-viewer-csv__table th,\r\n.filex-viewer-csv__table td {\r\n padding: 4px 10px;\r\n border: 1px solid var(--fe-border, #e2e6ed);\r\n white-space: nowrap;\r\n max-width: 320px;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n}\r\n.filex-viewer-csv__table th {\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n position: sticky;\r\n top: 0;\r\n font-weight: 600;\r\n text-align: left;\r\n}\r\n.filex-viewer-csv__table tbody tr:nth-child(even) {\r\n background: var(--fe-bg-hover, rgba(0, 0, 0, 0.02));\r\n}\r\n.filex-viewer-csv__rownum {\r\n color: var(--fe-text-muted, #5a6475);\r\n text-align: right;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n font-variant-numeric: tabular-nums;\r\n position: sticky;\r\n left: 0;\r\n}\r\n.filex-viewer-csv__pager {\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 6px;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n border-top: 1px solid var(--fe-border, #e2e6ed);\r\n font-size: 12px;\r\n}\r\n.filex-viewer-csv__pageno {\r\n font-variant-numeric: tabular-nums;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-fallback {\r\n text-align: center;\r\n padding: 32px;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-fallback__icon {\r\n font-size: 48px;\r\n display: block;\r\n margin-bottom: 12px;\r\n}\r\n.filex-viewer-btn {\r\n border: 1px solid var(--fe-border, #e2e6ed);\r\n background: var(--fe-bg, #fff);\r\n color: var(--fe-text, #1a1e27);\r\n padding: 4px 10px;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n font: inherit;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-btn:hover:not(:disabled) {\r\n background: var(--fe-bg-hover, #edf0f5);\r\n}\r\n.filex-viewer-btn:disabled {\r\n opacity: 0.4;\r\n cursor: not-allowed;\r\n}\r\n</style>\r\n"],"names":["PAGE_SIZE","ROW_LIMIT","props","__props","rows","ref","error","loading","firstRowHeader","filter","page","detectedDelim","userDelim","renderToken","detectDelimiter","sample","sampleLines","tab","semi","comma","parseWith","text","delim","mod","n","l","line","load","myToken","fetchViewerText","_a","err","onMounted","watch","headers","computed","_","i","dataRows","filtered","q","r","c","totalPages","visibleRows","start","tt","key","fallback","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_cache","_hoisted_4","_hoisted_5","_Fragment","_renderList","h","row","ri","_hoisted_6","_toDisplayString","ci","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"DrawioViewer-CBOqWzaj.js","sources":["../../core/src/viewers/DrawioViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\n/**\r\n * DrawioViewer — embed diagrams.net via iframe + postMessage handshake.\r\n *\r\n * The diagrams.net embed mode (`?embed=1&proto=json`) handshakes via\r\n * window.postMessage:\r\n *\r\n * 1. iframe sends {event:'init'} ← bootstrap\r\n * 2. parent sends {action:'load', xml} ← our payload\r\n * 3. iframe sends {event:'save', xml} on save ← we POST back\r\n *\r\n * No external library required — diagrams.net hosts the entire editor\r\n * inside the iframe. We just fetch the source XML on mount and route\r\n * `save` events back to the configured `pdfSaveUrl`-style endpoint\r\n * (drawio uses the same shape: POST `{path, content}` body).\r\n */\r\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';\r\nimport { fetchViewerText } from '../composables/useViewerFetch';\r\n\r\nconst props = defineProps<{\r\n url: string;\r\n filePath: string;\r\n ext: string;\r\n drawioUrl?: string;\r\n /** Optional save endpoint. When unset the iframe stays read-only. */\r\n saveUrl?: string;\r\n readOnly?: boolean;\r\n t?: (key: string) => string;\r\n authHeaders?: () => Record<string, string>;\r\n authCredentials?: RequestCredentials;\r\n}>();\r\n\r\nconst iframeRef = ref<HTMLIFrameElement | null>(null);\r\nconst error = ref<string | null>(null);\r\nconst status = ref<'loading' | 'ready' | 'saving' | 'saved' | 'error'>('loading');\r\nconst readOnly = ref(!!props.readOnly || !props.saveUrl);\r\n\r\n// drawioUrl=null is the operator's \"off\" signal — FileExplorer wipes it\r\n// when the capabilities probe reports drawio offline. Don't silently fall\r\n// back to the public embed.diagrams.net iframe, that defeats the point of\r\n// gating: render a \"not configured\" pane instead so the user understands\r\n// why the editor isn't loading.\r\n//\r\n// `drawioBase` MUST be a computed (not a const), otherwise a stale null\r\n// at mount time (capabilities probe still inflight) gets cached for the\r\n// component's lifetime — leading to the spurious\r\n// \"viewer.drawio.disabled\" fallback after the capability flips to \"ok\".\r\nconst drawioBase = computed<string | null>(() =>\r\n props.drawioUrl ? props.drawioUrl.replace(/\\/$/, '') : null,\r\n);\r\nconst iframeSrc = computed<string>(() => {\r\n if (!drawioBase.value) return '';\r\n const params = new URLSearchParams({\r\n embed: '1',\r\n proto: 'json',\r\n spin: '1',\r\n saveAndExit: '0',\r\n noSaveBtn: readOnly.value ? '1' : '0',\r\n noExitBtn: '1',\r\n ui: 'kennedy',\r\n modified: 'unsavedChanges',\r\n });\r\n return `${drawioBase.value}/?${params.toString()}`;\r\n});\r\n\r\nlet pendingXml: string = '';\r\n\r\nasync function loadXml(): Promise<void> {\r\n status.value = 'loading';\r\n error.value = null;\r\n try {\r\n pendingXml = await fetchViewerText({\r\n url: props.url,\r\n headers: props.authHeaders?.() ?? {},\r\n credentials: props.authCredentials,\r\n });\r\n } catch (err) {\r\n error.value = err instanceof Error ? err.message : 'fetch failed';\r\n status.value = 'error';\r\n }\r\n}\r\n\r\nfunction send(msg: unknown): void {\r\n iframeRef.value?.contentWindow?.postMessage(JSON.stringify(msg), '*');\r\n}\r\n\r\nasync function persist(xml: string): Promise<void> {\r\n if (!props.saveUrl) return;\r\n status.value = 'saving';\r\n try {\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n ...(props.authHeaders?.() ?? {}),\r\n };\r\n const res = await fetch(props.saveUrl, {\r\n method: 'POST',\r\n headers,\r\n credentials: props.authCredentials || 'same-origin',\r\n body: JSON.stringify({ path: props.filePath, content: xml }),\r\n });\r\n if (!res.ok) {\r\n throw new Error(`${res.status} ${res.statusText}`);\r\n }\r\n status.value = 'saved';\r\n setTimeout(() => {\r\n if (status.value === 'saved') status.value = 'ready';\r\n }, 2500);\r\n } catch (err) {\r\n error.value = err instanceof Error ? err.message : 'save failed';\r\n status.value = 'error';\r\n }\r\n}\r\n\r\nfunction onMessage(ev: MessageEvent): void {\r\n if (typeof ev.data !== 'string' || ev.data.length === 0) return;\r\n // Drawio messages always start with '{' or '<'. Ignore anything else\r\n // (devtools / unrelated postMessage senders inside the same window).\r\n const first = ev.data[0];\r\n if (first !== '{' && first !== '<') return;\r\n let payload: any;\r\n try {\r\n payload = JSON.parse(ev.data);\r\n } catch {\r\n return;\r\n }\r\n if (!payload || typeof payload !== 'object') return;\r\n switch (payload.event) {\r\n case 'init':\r\n send({\r\n action: 'load',\r\n xml: pendingXml,\r\n autosave: 0,\r\n });\r\n status.value = 'ready';\r\n break;\r\n case 'save':\r\n if (typeof payload.xml === 'string') {\r\n persist(payload.xml);\r\n }\r\n break;\r\n case 'export':\r\n // Could persist a PNG/SVG render; out of V1 scope.\r\n break;\r\n case 'autosave':\r\n if (typeof payload.xml === 'string' && !readOnly.value) {\r\n persist(payload.xml);\r\n }\r\n break;\r\n default:\r\n break;\r\n }\r\n}\r\n\r\nfunction bootIfReady(): void {\r\n if (!drawioBase.value) {\r\n error.value = tt('viewer.drawio.disabled', 'Drawio (diagrams.net) yapılandırılmamış.');\r\n status.value = 'error';\r\n return;\r\n }\r\n // Clear a previous \"disabled\" error in case the prop just became\r\n // available (capability probe finished after mount).\r\n if (error.value === tt('viewer.drawio.disabled', 'Drawio (diagrams.net) yapılandırılmamış.')) {\r\n error.value = null;\r\n status.value = 'loading';\r\n }\r\n loadXml();\r\n}\r\n\r\nonMounted(() => {\r\n window.addEventListener('message', onMessage);\r\n bootIfReady();\r\n});\r\n\r\nwatch(() => props.drawioUrl, bootIfReady);\r\n\r\nonBeforeUnmount(() => {\r\n window.removeEventListener('message', onMessage);\r\n});\r\n\r\nfunction tt(key: string, fallback: string): string {\r\n return props.t ? props.t(key) : fallback;\r\n}\r\n</script>\r\n\r\n<template>\r\n <div class=\"filex-viewer-drawio\">\r\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">📐</span>\r\n <p>{{ error }}</p>\r\n </div>\r\n <iframe\r\n v-else\r\n ref=\"iframeRef\"\r\n :src=\"iframeSrc\"\r\n class=\"filex-viewer-drawio__frame\"\r\n title=\"diagrams.net editor\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.filex-viewer-drawio {\r\n display: flex;\r\n flex-direction: column;\r\n width: 100%;\r\n height: 100%;\r\n min-height: 70vh;\r\n background: var(--fe-bg, #fff);\r\n}\r\n.filex-viewer-drawio__bar {\r\n display: flex;\r\n align-items: center;\r\n gap: 12px;\r\n padding: 6px 12px;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\r\n font-size: 12px;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-drawio__status[data-state=\"error\"] { color: var(--fe-danger, #dc2626); }\r\n.filex-viewer-drawio__status[data-state=\"saved\"] { color: #059669; }\r\n.filex-viewer-drawio__readonly {\r\n font-style: italic;\r\n margin-left: auto;\r\n}\r\n.filex-viewer-drawio__frame {\r\n flex: 1;\r\n width: 100%;\r\n border: 0;\r\n background: #fafafa;\r\n min-height: 0;\r\n}\r\n.filex-viewer-fallback {\r\n text-align: center;\r\n padding: 32px;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-fallback__icon {\r\n font-size: 48px;\r\n display: block;\r\n margin-bottom: 12px;\r\n}\r\n</style>\r\n"],"names":["props","__props","iframeRef","ref","error","status","readOnly","drawioBase","computed","iframeSrc","params","pendingXml","loadXml","fetchViewerText","_a","err","send","msg","_b","persist","xml","headers","res","onMessage","ev","first","payload","bootIfReady","tt","onMounted","watch","onBeforeUnmount","key","fallback","_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","_cache","_createElementVNode"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"EpubViewer-Cs6yZIP2.js","sources":["../../core/src/viewers/EpubViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\n/**\r\n * EpubViewer — flowable EPUB reader via `epubjs`.\r\n *\r\n * Lazy-imports `epubjs` (~80 KB gzipped). epub.js renders the publication\r\n * inside an iframe (default `flow: 'paginated'`), but we use it in\r\n * scrolled-doc mode only when the user toggles the \"fit-width\" flag — by\r\n * default we keep paginated since that matches reader-app expectations.\r\n *\r\n * UX:\r\n * - prev/next page buttons (also keyboard arrow keys via composable)\r\n * - collapsible TOC sidebar (built from `book.loaded.navigation`)\r\n * - font size +/- (Themes API)\r\n * - graceful fallback if peer not installed\r\n */\r\nimport { onBeforeUnmount, onMounted, ref, watch } from 'vue';\r\n\r\nconst props = defineProps<{\r\n url: string;\r\n mime?: string;\r\n ext: string;\r\n t?: (key: string) => string;\r\n authHeaders?: () => Record<string, string>;\r\n authCredentials?: RequestCredentials;\r\n}>();\r\n\r\ninterface TocNode {\r\n href: string;\r\n label: string;\r\n subitems?: TocNode[];\r\n}\r\n\r\nconst root = ref<HTMLDivElement | null>(null);\r\nconst containerRef = ref<HTMLDivElement | null>(null);\r\nconst error = ref<string | null>(null);\r\nconst toc = ref<TocNode[]>([]);\r\nconst tocOpen = ref(false);\r\nconst fontSize = ref(100);\r\nconst ready = ref(false);\r\nconst loading = ref(true);\r\n\r\nlet book: any = null;\r\nlet rendition: any = null;\r\n\r\nasync function load(): Promise<void> {\r\n loading.value = true;\r\n ready.value = false;\r\n error.value = null;\r\n let mod: any = null;\r\n try {\r\n mod = await import(/* @vite-ignore */ 'epubjs');\r\n } catch {\r\n error.value = props.t\r\n ? props.t('viewer.peer_not_installed')\r\n : 'EPUB viewer requires `epubjs` — install or use download.';\r\n loading.value = false;\r\n return;\r\n }\r\n try {\r\n const Epub = mod.default ?? mod;\r\n // epub.js wants a URL (it then fetches with XHR). When the host\r\n // site requires auth headers we have to load the file ourselves\r\n // and pass an ArrayBuffer instead.\r\n let source: string | ArrayBuffer = props.url;\r\n if (props.authHeaders) {\r\n const headers = props.authHeaders();\r\n const res = await fetch(props.url, {\r\n headers,\r\n credentials: props.authCredentials || 'same-origin',\r\n });\r\n if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);\r\n source = await res.arrayBuffer();\r\n }\r\n book = Epub(source);\r\n if (!containerRef.value) {\r\n throw new Error('EPUB mount target missing');\r\n }\r\n rendition = book.renderTo(containerRef.value, {\r\n width: '100%',\r\n height: '100%',\r\n flow: 'paginated',\r\n manager: 'default',\r\n });\r\n await rendition.display();\r\n rendition.themes.fontSize(fontSize.value + '%');\r\n const nav = await book.loaded.navigation;\r\n toc.value = (nav?.toc ?? []) as TocNode[];\r\n ready.value = true;\r\n } catch (err) {\r\n error.value =\r\n err instanceof Error ? err.message : 'EPUB load failed';\r\n } finally {\r\n loading.value = false;\r\n }\r\n}\r\n\r\nfunction next(): void {\r\n rendition?.next?.();\r\n}\r\nfunction prev(): void {\r\n rendition?.prev?.();\r\n}\r\nfunction gotoHref(href: string): void {\r\n rendition?.display?.(href);\r\n tocOpen.value = false;\r\n}\r\nfunction bigger(): void {\r\n fontSize.value = Math.min(200, fontSize.value + 10);\r\n rendition?.themes?.fontSize(fontSize.value + '%');\r\n}\r\nfunction smaller(): void {\r\n fontSize.value = Math.max(60, fontSize.value - 10);\r\n rendition?.themes?.fontSize(fontSize.value + '%');\r\n}\r\n\r\nfunction onKey(ev: KeyboardEvent): void {\r\n if (ev.key === 'ArrowRight' || ev.key === 'PageDown') next();\r\n else if (ev.key === 'ArrowLeft' || ev.key === 'PageUp') prev();\r\n}\r\n\r\nonMounted(() => {\r\n load();\r\n window.addEventListener('keydown', onKey);\r\n});\r\n\r\nonBeforeUnmount(() => {\r\n window.removeEventListener('keydown', onKey);\r\n try {\r\n rendition?.destroy?.();\r\n } catch {\r\n /* ignore */\r\n }\r\n try {\r\n book?.destroy?.();\r\n } catch {\r\n /* ignore */\r\n }\r\n rendition = null;\r\n book = null;\r\n});\r\n\r\nwatch(\r\n () => props.url,\r\n () => {\r\n if (rendition) {\r\n try {\r\n rendition.destroy();\r\n } catch {\r\n /* ignore */\r\n }\r\n }\r\n if (book) {\r\n try {\r\n book.destroy();\r\n } catch {\r\n /* ignore */\r\n }\r\n }\r\n book = null;\r\n rendition = null;\r\n load();\r\n },\r\n);\r\n\r\nfunction tt(key: string, fallback: string): string {\r\n return props.t ? props.t(key) : fallback;\r\n}\r\n</script>\r\n\r\n<template>\r\n <div ref=\"root\" class=\"filex-viewer-epub\">\r\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">📖</span>\r\n <p>{{ error }}</p>\r\n </div>\r\n <template v-else>\r\n <div ref=\"containerRef\" class=\"filex-viewer-epub__rendition\" />\r\n <div v-if=\"ready\" class=\"filex-viewer-epub__nav\">\r\n <button type=\"button\" class=\"filex-viewer-btn\" @click=\"prev\" :disabled=\"!ready\">‹</button>\r\n <button type=\"button\" class=\"filex-viewer-btn\" @click=\"next\" :disabled=\"!ready\">›</button>\r\n </div>\r\n <div v-if=\"loading\" class=\"filex-viewer-epub__loading\">\r\n {{ tt('viewer.loading', 'Loading…') }}\r\n </div>\r\n </template>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.filex-viewer-epub__nav {\r\n position: absolute;\r\n bottom: 12px;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n display: flex;\r\n gap: 8px;\r\n padding: 4px 8px;\r\n background: var(--fe-bg-elev, rgba(255, 255, 255, 0.9));\r\n border: 1px solid var(--fe-border, #e2e6ed);\r\n border-radius: 6px;\r\n backdrop-filter: blur(4px);\r\n}\r\n.filex-viewer-epub {\r\n display: flex;\r\n flex-direction: column;\r\n width: 100%;\r\n height: 100%;\r\n min-height: 70vh;\r\n background: var(--fe-bg, #fff);\r\n color: var(--fe-text, #1a1e27);\r\n position: relative;\r\n}\r\n.filex-viewer-epub__bar {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 8px 12px;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\r\n font-size: 13px;\r\n}\r\n.filex-viewer-spacer { flex: 1; }\r\n.filex-viewer-epub__fs {\r\n display: inline-block;\r\n min-width: 40px;\r\n text-align: center;\r\n font-variant-numeric: tabular-nums;\r\n font-size: 12px;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-epub__main {\r\n flex: 1;\r\n min-height: 0;\r\n display: flex;\r\n}\r\n.filex-viewer-epub__rendition {\r\n flex: 1;\r\n min-height: 0;\r\n}\r\n.filex-viewer-epub__toc {\r\n width: 260px;\r\n border-right: 1px solid var(--fe-border, #e2e6ed);\r\n overflow-y: auto;\r\n padding: 12px 0;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n}\r\n.filex-viewer-epub__toc ul {\r\n list-style: none;\r\n margin: 0;\r\n padding: 0;\r\n}\r\n.filex-viewer-epub__toc-link {\r\n display: block;\r\n width: 100%;\r\n text-align: left;\r\n background: transparent;\r\n border: 0;\r\n padding: 6px 14px;\r\n font: inherit;\r\n color: inherit;\r\n cursor: pointer;\r\n}\r\n.filex-viewer-epub__toc-link:hover {\r\n background: var(--fe-bg-hover, #edf0f5);\r\n}\r\n.filex-viewer-epub__toc-link.is-child {\r\n padding-left: 28px;\r\n color: var(--fe-text-muted, #5a6475);\r\n font-size: 12px;\r\n}\r\n.filex-viewer-epub__loading {\r\n position: absolute;\r\n inset: auto 0 0 0;\r\n text-align: center;\r\n padding: 6px;\r\n background: rgba(0, 0, 0, 0.05);\r\n font-size: 12px;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-fallback {\r\n text-align: center;\r\n padding: 32px;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-fallback__icon {\r\n font-size: 48px;\r\n display: block;\r\n margin-bottom: 12px;\r\n}\r\n.filex-viewer-btn {\r\n border: 1px solid var(--fe-border, #e2e6ed);\r\n background: var(--fe-bg, #fff);\r\n color: var(--fe-text, #1a1e27);\r\n padding: 4px 10px;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n font: inherit;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-btn:hover:not(:disabled) {\r\n background: var(--fe-bg-hover, #edf0f5);\r\n}\r\n.filex-viewer-btn:disabled {\r\n opacity: 0.5;\r\n cursor: not-allowed;\r\n}\r\n</style>\r\n"],"names":["props","__props","root","ref","containerRef","error","toc","fontSize","ready","loading","book","rendition","load","mod","Epub","source","headers","res","nav","err","next","_a","prev","onKey","ev","onMounted","onBeforeUnmount","_b","watch","tt","key","fallback","_createElementBlock","_openBlock","_hoisted_1","_cache","_createElementVNode","_Fragment","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_toDisplayString"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"IpynbViewer-wJhbhUla.js","sources":["../../core/src/viewers/IpynbViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\n/**\r\n * IpynbViewer — Jupyter notebook (.ipynb JSON) renderer.\r\n *\r\n * Pure-JS render — no peer dependency required:\r\n * - code cells → `<pre><code>` (highlight.js when available)\r\n * - markdown cells → markdown-it when available, plain `<pre>` otherwise\r\n * - output cells → text (stream / display_data 'text/plain'),\r\n * images (display_data 'image/png' base64),\r\n * HTML (display_data 'text/html', sanitized via\r\n * element-only insertion — no script tags)\r\n *\r\n * Source list / output count counters at the top so a 200-cell\r\n * notebook doesn't surprise the user.\r\n */\r\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';\r\nimport { fetchViewerText } from '../composables/useViewerFetch';\r\nimport { ensureHighlight } from '../composables/useMonacoLoader';\r\n\r\nconst props = defineProps<{\r\n url: string;\r\n ext: string;\r\n t?: (key: string) => string;\r\n authHeaders?: () => Record<string, string>;\r\n authCredentials?: RequestCredentials;\r\n}>();\r\n\r\ninterface Cell {\r\n cell_type: 'code' | 'markdown' | 'raw' | string;\r\n source: string | string[];\r\n outputs?: any[];\r\n execution_count?: number | null;\r\n metadata?: Record<string, unknown>;\r\n}\r\n\r\ninterface Notebook {\r\n cells: Cell[];\r\n metadata?: { kernelspec?: { language?: string; name?: string } };\r\n}\r\n\r\nconst cells = ref<Cell[]>([]);\r\nconst language = ref<string>('python');\r\nconst error = ref<string | null>(null);\r\nconst loading = ref(true);\r\nconst renderedSources = ref<Map<number, string>>(new Map());\r\nconst renderedMarkdown = ref<Map<number, string>>(new Map());\r\n\r\nlet renderToken = 0;\r\nlet highlight: any = null;\r\nlet mdRenderer: any = null;\r\n\r\nasync function ensureMd(): Promise<any | null> {\r\n if (mdRenderer !== null) return mdRenderer || null;\r\n try {\r\n const mod = await import(/* @vite-ignore */ 'markdown-it');\r\n const Md = (mod as any).default ?? mod;\r\n mdRenderer = new Md({ html: false, linkify: true, breaks: true });\r\n return mdRenderer;\r\n } catch {\r\n mdRenderer = false;\r\n return null;\r\n }\r\n}\r\n\r\nfunction joinSource(source: string | string[]): string {\r\n return Array.isArray(source) ? source.join('') : (source ?? '');\r\n}\r\n\r\nasync function load(): Promise<void> {\r\n loading.value = true;\r\n error.value = null;\r\n cells.value = [];\r\n renderedSources.value = new Map();\r\n renderedMarkdown.value = new Map();\r\n const myToken = ++renderToken;\r\n\r\n let raw: string;\r\n try {\r\n raw = await fetchViewerText({\r\n url: props.url,\r\n headers: props.authHeaders?.() ?? {},\r\n credentials: props.authCredentials,\r\n });\r\n } catch (err) {\r\n error.value = err instanceof Error ? err.message : 'fetch failed';\r\n loading.value = false;\r\n return;\r\n }\r\n\r\n if (myToken !== renderToken) return;\r\n\r\n let nb: Notebook;\r\n try {\r\n nb = JSON.parse(raw);\r\n } catch (err) {\r\n error.value = 'Invalid notebook JSON';\r\n loading.value = false;\r\n return;\r\n }\r\n cells.value = Array.isArray(nb.cells) ? nb.cells : [];\r\n language.value = nb.metadata?.kernelspec?.language || 'python';\r\n\r\n // Best-effort hljs highlight per code cell.\r\n highlight = (await ensureHighlight()) as any;\r\n if (myToken !== renderToken) return;\r\n if (highlight) {\r\n const hljs = highlight.default ?? highlight;\r\n const langOk = hljs.getLanguage?.(language.value) ? language.value : null;\r\n cells.value.forEach((cell, idx) => {\r\n if (cell.cell_type === 'code') {\r\n const text = joinSource(cell.source);\r\n try {\r\n const result = langOk\r\n ? hljs.highlight(text, { language: langOk, ignoreIllegals: true })\r\n : hljs.highlightAuto(text);\r\n renderedSources.value.set(idx, result.value);\r\n } catch {\r\n /* leave unrendered */\r\n }\r\n }\r\n });\r\n }\r\n\r\n const md = await ensureMd();\r\n if (myToken !== renderToken) return;\r\n if (md) {\r\n cells.value.forEach((cell, idx) => {\r\n if (cell.cell_type === 'markdown') {\r\n try {\r\n renderedMarkdown.value.set(idx, md.render(joinSource(cell.source)));\r\n } catch {\r\n /* leave plain */\r\n }\r\n }\r\n });\r\n }\r\n\r\n loading.value = false;\r\n}\r\n\r\nfunction outputText(out: any): string | null {\r\n if (!out) return null;\r\n if (out.output_type === 'stream') {\r\n return joinSource(out.text);\r\n }\r\n if (out.output_type === 'error') {\r\n return [out.ename, out.evalue, ...(out.traceback || [])]\r\n .filter(Boolean)\r\n .join('\\n');\r\n }\r\n if (out.output_type === 'execute_result' || out.output_type === 'display_data') {\r\n if (out.data?.['text/plain']) {\r\n return joinSource(out.data['text/plain']);\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction outputImage(out: any): string | null {\r\n if (!out?.data) return null;\r\n if (out.data['image/png']) return `data:image/png;base64,${out.data['image/png']}`;\r\n if (out.data['image/jpeg']) return `data:image/jpeg;base64,${out.data['image/jpeg']}`;\r\n if (out.data['image/svg+xml']) {\r\n const svg = joinSource(out.data['image/svg+xml']);\r\n return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;\r\n }\r\n return null;\r\n}\r\n\r\nfunction outputHtml(out: any): string | null {\r\n if (!out?.data) return null;\r\n if (out.data['text/html']) {\r\n const html = joinSource(out.data['text/html']);\r\n // Strip <script> for safety — outputs from arbitrary notebooks.\r\n return html.replace(/<script[\\s\\S]*?<\\/script>/gi, '');\r\n }\r\n return null;\r\n}\r\n\r\nonMounted(load);\r\nonBeforeUnmount(() => {\r\n renderToken++;\r\n});\r\nwatch(() => props.url, load);\r\n\r\nconst stats = computed(() => {\r\n const codeCount = cells.value.filter((c) => c.cell_type === 'code').length;\r\n const mdCount = cells.value.filter((c) => c.cell_type === 'markdown').length;\r\n return { code: codeCount, md: mdCount, total: cells.value.length };\r\n});\r\n\r\nfunction tt(key: string, fallback: string): string {\r\n return props.t ? props.t(key) : fallback;\r\n}\r\n</script>\r\n\r\n<template>\r\n <div class=\"filex-viewer-ipynb\">\r\n <div class=\"filex-viewer-ipynb__pane\">\r\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">📓</span>\r\n <p>{{ error }}</p>\r\n </div>\r\n <div v-else-if=\"loading\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">⏳</span>\r\n <p>{{ tt('viewer.loading', 'Loading…') }}</p>\r\n </div>\r\n <div v-else>\r\n <div\r\n v-for=\"(cell, idx) in cells\"\r\n :key=\"idx\"\r\n class=\"filex-viewer-ipynb__cell\"\r\n :data-type=\"cell.cell_type\"\r\n >\r\n <template v-if=\"cell.cell_type === 'code'\">\r\n <div class=\"filex-viewer-ipynb__exec\">\r\n In [{{ cell.execution_count ?? ' ' }}]:\r\n </div>\r\n <pre class=\"filex-viewer-ipynb__src hljs\"><code\r\n v-if=\"renderedSources.get(idx)\"\r\n v-html=\"renderedSources.get(idx)\"\r\n /><code v-else>{{ joinSource(cell.source) }}</code></pre>\r\n <div v-if=\"cell.outputs && cell.outputs.length\" class=\"filex-viewer-ipynb__outputs\">\r\n <template v-for=\"(out, j) in cell.outputs\" :key=\"j\">\r\n <img\r\n v-if=\"outputImage(out)\"\r\n :src=\"outputImage(out) || ''\"\r\n class=\"filex-viewer-ipynb__img\"\r\n :alt=\"`output ${j}`\"\r\n />\r\n <div\r\n v-else-if=\"outputHtml(out)\"\r\n class=\"filex-viewer-ipynb__html\"\r\n v-html=\"outputHtml(out)\"\r\n />\r\n <pre\r\n v-else-if=\"outputText(out)\"\r\n class=\"filex-viewer-ipynb__out\"\r\n :data-type=\"out.output_type\"\r\n >{{ outputText(out) }}</pre>\r\n </template>\r\n </div>\r\n </template>\r\n\r\n <template v-else-if=\"cell.cell_type === 'markdown'\">\r\n <div\r\n v-if=\"renderedMarkdown.get(idx)\"\r\n class=\"filex-viewer-ipynb__md\"\r\n v-html=\"renderedMarkdown.get(idx)\"\r\n />\r\n <pre v-else class=\"filex-viewer-ipynb__md-raw\">{{ joinSource(cell.source) }}</pre>\r\n </template>\r\n\r\n <template v-else>\r\n <pre class=\"filex-viewer-ipynb__src\">{{ joinSource(cell.source) }}</pre>\r\n </template>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.filex-viewer-ipynb {\r\n display: flex;\r\n flex-direction: column;\r\n width: 100%;\r\n height: 100%;\r\n min-height: 70vh;\r\n background: var(--fe-bg, #fff);\r\n color: var(--fe-text, #1a1e27);\r\n}\r\n.filex-viewer-ipynb__bar {\r\n display: flex;\r\n align-items: center;\r\n gap: 12px;\r\n padding: 8px 12px;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\r\n font-size: 12px;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-ipynb__lang {\r\n font-family: var(--fe-font-mono, monospace);\r\n text-transform: uppercase;\r\n letter-spacing: 0.04em;\r\n}\r\n.filex-viewer-ipynb__pane {\r\n flex: 1;\r\n overflow: auto;\r\n padding: 16px 24px;\r\n}\r\n.filex-viewer-ipynb__cell {\r\n border: 1px solid var(--fe-border, #e2e6ed);\r\n border-radius: 6px;\r\n margin-bottom: 16px;\r\n overflow: hidden;\r\n}\r\n.filex-viewer-ipynb__cell[data-type=\"code\"] {\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n}\r\n.filex-viewer-ipynb__exec {\r\n padding: 4px 12px;\r\n font-family: var(--fe-font-mono, monospace);\r\n font-size: 11px;\r\n color: var(--fe-text-muted, #5a6475);\r\n background: rgba(0, 0, 0, 0.04);\r\n}\r\n.filex-viewer-ipynb__src {\r\n margin: 0;\r\n padding: 12px;\r\n font-family: var(--fe-font-mono, monospace);\r\n font-size: 12px;\r\n line-height: 1.5;\r\n white-space: pre;\r\n overflow-x: auto;\r\n}\r\n.filex-viewer-ipynb__outputs {\r\n border-top: 1px dashed var(--fe-border, #e2e6ed);\r\n background: var(--fe-bg, #fff);\r\n padding: 8px 12px;\r\n}\r\n.filex-viewer-ipynb__out {\r\n margin: 0;\r\n padding: 4px 0;\r\n font-family: var(--fe-font-mono, monospace);\r\n font-size: 12px;\r\n white-space: pre-wrap;\r\n word-wrap: break-word;\r\n}\r\n.filex-viewer-ipynb__out[data-type=\"error\"] {\r\n color: var(--fe-danger, #dc2626);\r\n}\r\n.filex-viewer-ipynb__img {\r\n display: block;\r\n max-width: 100%;\r\n height: auto;\r\n margin: 8px 0;\r\n}\r\n.filex-viewer-ipynb__html {\r\n font-size: 13px;\r\n}\r\n.filex-viewer-ipynb__md {\r\n padding: 12px 16px;\r\n font-size: 14px;\r\n line-height: 1.6;\r\n}\r\n.filex-viewer-ipynb__md-raw {\r\n padding: 12px;\r\n margin: 0;\r\n font-family: var(--fe-font-mono, monospace);\r\n font-size: 12px;\r\n white-space: pre-wrap;\r\n}\r\n.filex-viewer-fallback {\r\n text-align: center;\r\n padding: 32px;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-fallback__icon {\r\n font-size: 48px;\r\n display: block;\r\n margin-bottom: 12px;\r\n}\r\n</style>\r\n"],"names":["props","__props","cells","ref","language","error","loading","renderedSources","renderedMarkdown","renderToken","highlight","mdRenderer","ensureMd","mod","Md","joinSource","source","load","myToken","raw","fetchViewerText","_a","err","nb","_c","_b","ensureHighlight","hljs","langOk","_d","cell","idx","text","result","md","outputText","out","outputImage","svg","outputHtml","onMounted","onBeforeUnmount","watch","tt","key","fallback","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_cache","_hoisted_4","_hoisted_5","_Fragment","_renderList","_hoisted_7","_hoisted_8","_hoisted_10","_toDisplayString","_hoisted_11","j","_hoisted_14","_hoisted_16","_hoisted_17"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"MermaidViewer-k_XVXoc5.js","sources":["../../core/src/viewers/MermaidViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\n/**\r\n * MermaidViewer — render a `.mmd` / `.mermaid` source file.\r\n *\r\n * Lazy-imports the `mermaid` library (~150 KB gzipped). Source text is\r\n * fetched from `props.url` (with the auth headers from PreviewModal),\r\n * then rendered to SVG via `mermaid.render('id', src)`. The resulting\r\n * SVG node is inserted into a wrapper that supports pan + scale via\r\n * pure CSS transforms (no extra panzoom dep).\r\n */\r\nimport { onBeforeUnmount, onMounted, ref } from 'vue';\r\nimport { fetchViewerText } from '../composables/useViewerFetch';\r\n\r\nconst props = defineProps<{\r\n url: string;\r\n mime?: string;\r\n ext: string;\r\n t?: (key: string) => string;\r\n authHeaders?: () => Record<string, string>;\r\n authCredentials?: RequestCredentials;\r\n}>();\r\n\r\nconst surface = ref<HTMLDivElement | null>(null);\r\nconst error = ref<string | null>(null);\r\nconst loading = ref(true);\r\nconst scale = ref(1);\r\nconst tx = ref(0);\r\nconst ty = ref(0);\r\n\r\nlet dragging = false;\r\nlet dragStart: { x: number; y: number; tx: number; ty: number } | null = null;\r\nlet renderToken = 0;\r\n\r\nlet cachedMermaid: any = null;\r\nasync function ensureMermaid(): Promise<any | null> {\r\n if (cachedMermaid) return cachedMermaid;\r\n try {\r\n const mod = await import(/* @vite-ignore */ 'mermaid');\r\n cachedMermaid = mod.default ?? mod;\r\n cachedMermaid.initialize?.({\r\n startOnLoad: false,\r\n securityLevel: 'strict',\r\n theme: window.matchMedia?.('(prefers-color-scheme: dark)').matches\r\n ? 'dark'\r\n : 'default',\r\n });\r\n return cachedMermaid;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nasync function load(): Promise<void> {\r\n loading.value = true;\r\n error.value = null;\r\n const myToken = ++renderToken;\r\n\r\n const mermaid = await ensureMermaid();\r\n if (myToken !== renderToken) return;\r\n if (!mermaid) {\r\n error.value = props.t\r\n ? props.t('viewer.peer_not_installed')\r\n : 'Mermaid viewer requires `mermaid` — install or use download.';\r\n loading.value = false;\r\n return;\r\n }\r\n\r\n let src: string;\r\n try {\r\n src = await fetchViewerText({\r\n url: props.url,\r\n headers: props.authHeaders?.() ?? {},\r\n credentials: props.authCredentials,\r\n });\r\n } catch (err) {\r\n error.value = err instanceof Error ? err.message : 'fetch failed';\r\n loading.value = false;\r\n return;\r\n }\r\n\r\n if (myToken !== renderToken) return;\r\n\r\n try {\r\n const id = `filex-mermaid-${Date.now()}`;\r\n const { svg } = await mermaid.render(id, src);\r\n if (myToken !== renderToken) return;\r\n if (surface.value) {\r\n surface.value.innerHTML = svg;\r\n const svgEl = surface.value.querySelector('svg');\r\n if (svgEl) {\r\n svgEl.style.maxWidth = '100%';\r\n svgEl.style.height = 'auto';\r\n }\r\n }\r\n } catch (err) {\r\n error.value = err instanceof Error ? err.message : 'render failed';\r\n } finally {\r\n loading.value = false;\r\n }\r\n}\r\n\r\nfunction zoomIn(): void {\r\n scale.value = Math.min(8, scale.value * 1.25);\r\n}\r\nfunction zoomOut(): void {\r\n scale.value = Math.max(0.2, scale.value / 1.25);\r\n}\r\nfunction reset(): void {\r\n scale.value = 1;\r\n tx.value = 0;\r\n ty.value = 0;\r\n}\r\n\r\nfunction onWheel(ev: WheelEvent): void {\r\n if (!ev.ctrlKey && !ev.metaKey) return;\r\n ev.preventDefault();\r\n const delta = -ev.deltaY;\r\n const factor = delta > 0 ? 1.1 : 1 / 1.1;\r\n scale.value = Math.max(0.2, Math.min(8, scale.value * factor));\r\n}\r\n\r\nfunction onPointerDown(ev: PointerEvent): void {\r\n dragging = true;\r\n dragStart = { x: ev.clientX, y: ev.clientY, tx: tx.value, ty: ty.value };\r\n (ev.target as HTMLElement).setPointerCapture?.(ev.pointerId);\r\n}\r\nfunction onPointerMove(ev: PointerEvent): void {\r\n if (!dragging || !dragStart) return;\r\n tx.value = dragStart.tx + (ev.clientX - dragStart.x);\r\n ty.value = dragStart.ty + (ev.clientY - dragStart.y);\r\n}\r\nfunction onPointerUp(): void {\r\n dragging = false;\r\n dragStart = null;\r\n}\r\n\r\nonMounted(load);\r\nonBeforeUnmount(() => {\r\n renderToken++;\r\n});\r\n\r\nfunction tt(key: string, fallback: string): string {\r\n return props.t ? props.t(key) : fallback;\r\n}\r\n</script>\r\n\r\n<template>\r\n <div class=\"filex-viewer-mermaid\">\r\n <div\r\n class=\"filex-viewer-mermaid__pane\"\r\n @wheel=\"onWheel\"\r\n @pointerdown=\"onPointerDown\"\r\n @pointermove=\"onPointerMove\"\r\n @pointerup=\"onPointerUp\"\r\n @pointercancel=\"onPointerUp\"\r\n >\r\n <div\r\n v-if=\"error\"\r\n class=\"filex-viewer-fallback\"\r\n >\r\n <span class=\"filex-viewer-fallback__icon\">📊</span>\r\n <p>{{ error }}</p>\r\n </div>\r\n <div\r\n v-else-if=\"loading\"\r\n class=\"filex-viewer-fallback\"\r\n >\r\n <span class=\"filex-viewer-fallback__icon\">⏳</span>\r\n <p>{{ tt('viewer.loading', 'Loading…') }}</p>\r\n </div>\r\n <div\r\n v-show=\"!loading && !error\"\r\n ref=\"surface\"\r\n class=\"filex-viewer-mermaid__surface\"\r\n :style=\"{ transform: `translate(${tx}px, ${ty}px) scale(${scale})` }\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.filex-viewer-mermaid {\r\n display: flex;\r\n flex-direction: column;\r\n width: 100%;\r\n height: 100%;\r\n min-height: 70vh;\r\n background: var(--fe-bg, #fff);\r\n color: var(--fe-text, #1a1e27);\r\n}\r\n.filex-viewer-mermaid__bar {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 8px 12px;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\r\n font-size: 13px;\r\n}\r\n.filex-viewer-mermaid__zoom {\r\n min-width: 50px;\r\n text-align: center;\r\n font-variant-numeric: tabular-nums;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-mermaid__pane {\r\n flex: 1;\r\n overflow: hidden;\r\n position: relative;\r\n cursor: grab;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n touch-action: none;\r\n}\r\n.filex-viewer-mermaid__pane:active {\r\n cursor: grabbing;\r\n}\r\n.filex-viewer-mermaid__surface {\r\n position: absolute;\r\n inset: 0;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n transform-origin: center center;\r\n transition: transform 0.05s linear;\r\n user-select: none;\r\n}\r\n.filex-viewer-mermaid__surface :deep(svg) {\r\n max-width: 90%;\r\n max-height: 90%;\r\n}\r\n.filex-viewer-fallback {\r\n text-align: center;\r\n padding: 32px;\r\n color: var(--fe-text-muted, #5a6475);\r\n width: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n.filex-viewer-fallback__icon {\r\n font-size: 48px;\r\n display: block;\r\n margin-bottom: 12px;\r\n}\r\n.filex-viewer-btn {\r\n border: 1px solid var(--fe-border, #e2e6ed);\r\n background: var(--fe-bg, #fff);\r\n color: var(--fe-text, #1a1e27);\r\n padding: 4px 10px;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n font: inherit;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-btn:hover:not(:disabled) {\r\n background: var(--fe-bg-hover, #edf0f5);\r\n}\r\n</style>\r\n"],"names":["props","__props","surface","ref","error","loading","scale","tx","ty","dragging","dragStart","renderToken","cachedMermaid","ensureMermaid","mod","_b","_a","load","myToken","mermaid","src","fetchViewerText","err","id","svg","svgEl","onWheel","ev","factor","onPointerDown","onPointerMove","onPointerUp","onMounted","onBeforeUnmount","tt","key","fallback","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_cache","_hoisted_3","_normalizeStyle","_vShow"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"PsdViewer-Bo4imBCF.js","sources":["../../core/src/viewers/PsdViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\n/**\r\n * PsdViewer — Photoshop document preview via `ag-psd`.\r\n *\r\n * Lazy-imports `ag-psd` (~150 KB). Renders the flattened composite to\r\n * a canvas via `psd.canvas`. A simple layer panel toggles the rendered\r\n * preview (V1: just lists names + visibility; full composite swap on\r\n * toggle requires re-rendering with `applyOpacity`/`composite` logic\r\n * — left as TODO for V2 since `ag-psd` doesn't ship a composite\r\n * pipeline of its own).\r\n */\r\nimport { onBeforeUnmount, onMounted, ref, watch } from 'vue';\r\nimport { fetchViewerArrayBuffer } from '../composables/useViewerFetch';\r\n\r\nconst props = defineProps<{\r\n url: string;\r\n mime?: string;\r\n ext: string;\r\n t?: (key: string) => string;\r\n authHeaders?: () => Record<string, string>;\r\n authCredentials?: RequestCredentials;\r\n}>();\r\n\r\ninterface FlatLayer {\r\n index: number;\r\n name: string;\r\n hidden: boolean;\r\n}\r\n\r\nconst canvasEl = ref<HTMLCanvasElement | null>(null);\r\nconst layers = ref<FlatLayer[]>([]);\r\nconst error = ref<string | null>(null);\r\nconst loading = ref(true);\r\nconst showLayerPanel = ref(false);\r\nconst dims = ref<{ width: number; height: number }>({ width: 0, height: 0 });\r\nconst scale = ref(1);\r\n\r\nlet renderToken = 0;\r\n\r\nlet agPsd: any = null;\r\nasync function ensureAgPsd(): Promise<any | null> {\r\n if (agPsd) return agPsd;\r\n try {\r\n const mod = await import(/* @vite-ignore */ 'ag-psd');\r\n agPsd = mod;\r\n return agPsd;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction flattenLayers(node: any, list: FlatLayer[]): void {\r\n if (!node) return;\r\n if (Array.isArray(node.children)) {\r\n for (const child of node.children) {\r\n list.push({\r\n index: list.length,\r\n name: child.name ?? '(unnamed)',\r\n hidden: !!child.hidden,\r\n });\r\n if (child.children) flattenLayers(child, list);\r\n }\r\n }\r\n}\r\n\r\nasync function load(): Promise<void> {\r\n loading.value = true;\r\n error.value = null;\r\n layers.value = [];\r\n const myToken = ++renderToken;\r\n\r\n const lib = await ensureAgPsd();\r\n if (myToken !== renderToken) return;\r\n if (!lib) {\r\n error.value = props.t\r\n ? props.t('viewer.peer_not_installed')\r\n : 'PSD viewer requires `ag-psd` — install or use download.';\r\n loading.value = false;\r\n return;\r\n }\r\n\r\n try {\r\n const buf = await fetchViewerArrayBuffer({\r\n url: props.url,\r\n headers: props.authHeaders?.() ?? {},\r\n credentials: props.authCredentials,\r\n });\r\n if (myToken !== renderToken) return;\r\n const psd = lib.readPsd(buf, {\r\n skipLayerImageData: false,\r\n skipCompositeImageData: false,\r\n skipThumbnail: true,\r\n });\r\n dims.value = { width: psd.width, height: psd.height };\r\n\r\n const composite = psd.canvas;\r\n if (composite && canvasEl.value) {\r\n const target = canvasEl.value;\r\n target.width = psd.width;\r\n target.height = psd.height;\r\n const ctx = target.getContext('2d');\r\n ctx?.drawImage(composite, 0, 0);\r\n } else {\r\n throw new Error('PSD has no composite image (skipCompositeImageData?)');\r\n }\r\n\r\n const flat: FlatLayer[] = [];\r\n flattenLayers(psd, flat);\r\n layers.value = flat;\r\n } catch (err) {\r\n error.value = err instanceof Error ? err.message : 'PSD decode failed';\r\n } finally {\r\n loading.value = false;\r\n }\r\n}\r\n\r\nfunction zoomIn(): void {\r\n scale.value = Math.min(8, scale.value * 1.25);\r\n}\r\nfunction zoomOut(): void {\r\n scale.value = Math.max(0.1, scale.value / 1.25);\r\n}\r\nfunction reset(): void {\r\n scale.value = 1;\r\n}\r\n\r\nonMounted(load);\r\nonBeforeUnmount(() => {\r\n renderToken++;\r\n});\r\nwatch(() => props.url, load);\r\n\r\nfunction tt(key: string, fallback: string): string {\r\n return props.t ? props.t(key) : fallback;\r\n}\r\n</script>\r\n\r\n<template>\r\n <div class=\"filex-viewer-psd\">\r\n <div class=\"filex-viewer-psd__pane\">\r\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">🎨</span>\r\n <p>{{ error }}</p>\r\n </div>\r\n <div v-else-if=\"loading\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">⏳</span>\r\n <p>{{ tt('viewer.loading', 'Loading…') }}</p>\r\n </div>\r\n <canvas\r\n v-show=\"!loading && !error\"\r\n ref=\"canvasEl\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.filex-viewer-psd {\r\n display: flex;\r\n flex-direction: column;\r\n width: 100%;\r\n height: 100%;\r\n min-height: 70vh;\r\n background: var(--fe-bg, #fff);\r\n}\r\n.filex-viewer-psd__bar {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 8px 12px;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\r\n font-size: 13px;\r\n}\r\n.filex-viewer-spacer { flex: 1; }\r\n.filex-viewer-psd__dim {\r\n font-size: 12px;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-psd__zoom {\r\n min-width: 50px;\r\n text-align: center;\r\n font-variant-numeric: tabular-nums;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-psd__main {\r\n flex: 1;\r\n display: flex;\r\n min-height: 0;\r\n}\r\n.filex-viewer-psd__layers {\r\n width: 240px;\r\n border-right: 1px solid var(--fe-border, #e2e6ed);\r\n overflow-y: auto;\r\n padding: 8px 0;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n}\r\n.filex-viewer-psd__layers ul {\r\n list-style: none;\r\n margin: 0;\r\n padding: 0;\r\n}\r\n.filex-viewer-psd__layers li {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 4px 12px;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-psd__layer-vis {\r\n width: 14px;\r\n text-align: center;\r\n color: var(--fe-text-muted, #5a6475);\r\n}\r\n.filex-viewer-psd__layer-vis[data-hidden=\"1\"] { color: var(--fe-border-strong, #c7ced9); }\r\n.filex-viewer-psd__layer-name {\r\n flex: 1;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n}\r\n.filex-viewer-psd__pane {\r\n flex: 1;\r\n overflow: auto;\r\n padding: 16px;\r\n background: #2a2d33;\r\n display: flex;\r\n align-items: flex-start;\r\n justify-content: flex-start;\r\n}\r\n.filex-viewer-psd__pane canvas {\r\n background: #fff\r\n repeating-conic-gradient(#e0e0e0 0% 25%, transparent 0% 50%) 50% / 16px 16px;\r\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);\r\n}\r\n.filex-viewer-fallback {\r\n text-align: center;\r\n padding: 32px;\r\n color: #c8cdd6;\r\n margin: auto;\r\n}\r\n.filex-viewer-fallback__icon {\r\n font-size: 48px;\r\n display: block;\r\n margin-bottom: 12px;\r\n}\r\n.filex-viewer-btn {\r\n border: 1px solid var(--fe-border, #e2e6ed);\r\n background: var(--fe-bg, #fff);\r\n color: var(--fe-text, #1a1e27);\r\n padding: 4px 10px;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n font: inherit;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-btn:hover:not(:disabled) {\r\n background: var(--fe-bg-hover, #edf0f5);\r\n}\r\n.filex-viewer-btn.is-active {\r\n background: var(--fe-bg-selected, #dfe8ff);\r\n border-color: var(--fe-primary, #3b82f6);\r\n}\r\n</style>\r\n"],"names":["props","__props","canvasEl","ref","layers","error","loading","dims","renderToken","agPsd","ensureAgPsd","flattenLayers","node","list","child","load","myToken","lib","buf","fetchViewerArrayBuffer","_a","psd","composite","target","ctx","flat","err","onMounted","onBeforeUnmount","watch","tt","key","fallback","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_cache","_hoisted_4","_vShow"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"TiffViewer-D73-Gyt-.js","sources":["../../core/src/viewers/TiffViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\n/**\r\n * TiffViewer — multi-page TIFF preview via `utif`.\r\n *\r\n * Lazy-imports `utif` (~50 KB). Decodes IFDs once, paints the active\r\n * page to a `<canvas>` via `UTIF.toRGBA8`. Page navigation (1/N) +\r\n * zoom in/out controls. Browser <img> can't render TIFF natively, so\r\n * the canvas pipeline is the only option short of server-side\r\n * conversion.\r\n */\r\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';\r\nimport { fetchViewerArrayBuffer } from '../composables/useViewerFetch';\r\n\r\nconst props = defineProps<{\r\n url: string;\r\n mime?: string;\r\n ext: string;\r\n t?: (key: string) => string;\r\n authHeaders?: () => Record<string, string>;\r\n authCredentials?: RequestCredentials;\r\n}>();\r\n\r\nconst canvasEl = ref<HTMLCanvasElement | null>(null);\r\nconst error = ref<string | null>(null);\r\nconst loading = ref(true);\r\nconst scale = ref(1);\r\nconst pageIndex = ref(0);\r\nconst pageCount = ref(0);\r\nconst pageDims = ref<{ width: number; height: number }>({ width: 0, height: 0 });\r\n\r\nlet UTIF: any = null;\r\nlet ifds: any[] | null = null;\r\nlet renderToken = 0;\r\n\r\nasync function ensureUtif(): Promise<any | null> {\r\n if (UTIF) return UTIF;\r\n try {\r\n const mod = await import(/* @vite-ignore */ 'utif');\r\n UTIF = mod.default ?? mod;\r\n return UTIF;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nasync function load(): Promise<void> {\r\n loading.value = true;\r\n error.value = null;\r\n ifds = null;\r\n pageIndex.value = 0;\r\n pageCount.value = 0;\r\n const myToken = ++renderToken;\r\n\r\n const lib = await ensureUtif();\r\n if (myToken !== renderToken) return;\r\n if (!lib) {\r\n error.value = props.t\r\n ? props.t('viewer.peer_not_installed')\r\n : 'TIFF viewer requires `utif` — install or use download.';\r\n loading.value = false;\r\n return;\r\n }\r\n\r\n try {\r\n const buf = await fetchViewerArrayBuffer({\r\n url: props.url,\r\n headers: props.authHeaders?.() ?? {},\r\n credentials: props.authCredentials,\r\n });\r\n if (myToken !== renderToken) return;\r\n ifds = lib.decode(buf);\r\n pageCount.value = ifds?.length ?? 0;\r\n if (pageCount.value === 0) {\r\n throw new Error('No pages decoded');\r\n }\r\n paint();\r\n } catch (err) {\r\n error.value = err instanceof Error ? err.message : 'TIFF decode failed';\r\n } finally {\r\n loading.value = false;\r\n }\r\n}\r\n\r\nfunction paint(): void {\r\n if (!UTIF || !ifds || !canvasEl.value) return;\r\n const idx = Math.max(0, Math.min(pageIndex.value, ifds.length - 1));\r\n const ifd = ifds[idx];\r\n try {\r\n UTIF.decodeImage(undefined, ifd);\r\n } catch {\r\n // some images already decoded — UTIF.decodeImage is idempotent on\r\n // older versions.\r\n }\r\n const rgba = UTIF.toRGBA8(ifd);\r\n const w = ifd.width;\r\n const h = ifd.height;\r\n pageDims.value = { width: w, height: h };\r\n const canvas = canvasEl.value;\r\n canvas.width = w;\r\n canvas.height = h;\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return;\r\n const imageData = ctx.createImageData(w, h);\r\n imageData.data.set(rgba);\r\n ctx.putImageData(imageData, 0, 0);\r\n}\r\n\r\nfunction next(): void {\r\n if (pageIndex.value < pageCount.value - 1) {\r\n pageIndex.value++;\r\n paint();\r\n }\r\n}\r\nfunction prev(): void {\r\n if (pageIndex.value > 0) {\r\n pageIndex.value--;\r\n paint();\r\n }\r\n}\r\nfunction zoomIn(): void {\r\n scale.value = Math.min(8, scale.value * 1.25);\r\n}\r\nfunction zoomOut(): void {\r\n scale.value = Math.max(0.1, scale.value / 1.25);\r\n}\r\nfunction reset(): void {\r\n scale.value = 1;\r\n}\r\n\r\nonMounted(load);\r\nonBeforeUnmount(() => {\r\n renderToken++;\r\n ifds = null;\r\n});\r\n\r\nwatch(() => props.url, load);\r\n\r\nconst pageLabel = computed(() => {\r\n const m = (props.t && props.t('viewer.page_n_of_m')) || 'Page {n} of {m}';\r\n return m.replace('{n}', String(pageIndex.value + 1)).replace('{m}', String(pageCount.value));\r\n});\r\n\r\nfunction tt(key: string, fallback: string): string {\r\n return props.t ? props.t(key) : fallback;\r\n}\r\n</script>\r\n\r\n<template>\r\n <div class=\"filex-viewer-tiff\">\r\n <div class=\"filex-viewer-tiff__pane\">\r\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">🖼️</span>\r\n <p>{{ error }}</p>\r\n </div>\r\n <div v-else-if=\"loading\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">⏳</span>\r\n <p>{{ tt('viewer.loading', 'Loading…') }}</p>\r\n </div>\r\n <canvas\r\n v-show=\"!loading && !error\"\r\n ref=\"canvasEl\"\r\n :style=\"{ imageRendering: 'pixelated' }\"\r\n />\r\n <div v-if=\"!loading && !error && pageCount > 1\" class=\"filex-viewer-tiff__pager\">\r\n <button\r\n type=\"button\"\r\n class=\"filex-viewer-btn\"\r\n :disabled=\"pageIndex === 0\"\r\n @click=\"prev\"\r\n >‹</button>\r\n <span class=\"filex-viewer-tiff__pages\">{{ pageLabel }}</span>\r\n <button\r\n type=\"button\"\r\n class=\"filex-viewer-btn\"\r\n :disabled=\"pageIndex >= pageCount - 1\"\r\n @click=\"next\"\r\n >›</button>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.filex-viewer-tiff__pager {\r\n position: absolute;\r\n bottom: 12px;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 4px 8px;\r\n background: var(--fe-bg-elev, rgba(255, 255, 255, 0.9));\r\n border: 1px solid var(--fe-border, #e2e6ed);\r\n border-radius: 6px;\r\n backdrop-filter: blur(4px);\r\n}\r\n.filex-viewer-tiff__pages {\r\n font-size: 12px;\r\n font-variant-numeric: tabular-nums;\r\n}\r\n.filex-viewer-tiff {\r\n display: flex;\r\n flex-direction: column;\r\n width: 100%;\r\n height: 100%;\r\n min-height: 70vh;\r\n background: var(--fe-bg, #fff);\r\n}\r\n.filex-viewer-tiff__bar {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 8px 12px;\r\n background: var(--fe-bg-elev, #f7f8fa);\r\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\r\n font-size: 13px;\r\n}\r\n.filex-viewer-tiff__pages {\r\n min-width: 110px;\r\n text-align: center;\r\n font-variant-numeric: tabular-nums;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-tiff__zoom {\r\n min-width: 50px;\r\n text-align: center;\r\n font-variant-numeric: tabular-nums;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-spacer { flex: 1; }\r\n.filex-viewer-tiff__pane {\r\n flex: 1;\r\n overflow: auto;\r\n padding: 16px;\r\n background: #2a2d33;\r\n display: flex;\r\n align-items: flex-start;\r\n justify-content: flex-start;\r\n}\r\n.filex-viewer-tiff__pane canvas {\r\n background: #fff;\r\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);\r\n}\r\n.filex-viewer-fallback {\r\n text-align: center;\r\n padding: 32px;\r\n color: #c8cdd6;\r\n margin: auto;\r\n}\r\n.filex-viewer-fallback__icon {\r\n font-size: 48px;\r\n display: block;\r\n margin-bottom: 12px;\r\n}\r\n.filex-viewer-btn {\r\n border: 1px solid var(--fe-border, #e2e6ed);\r\n background: var(--fe-bg, #fff);\r\n color: var(--fe-text, #1a1e27);\r\n padding: 4px 10px;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n font: inherit;\r\n font-size: 12px;\r\n}\r\n.filex-viewer-btn:hover:not(:disabled) {\r\n background: var(--fe-bg-hover, #edf0f5);\r\n}\r\n.filex-viewer-btn:disabled {\r\n opacity: 0.4;\r\n cursor: not-allowed;\r\n}\r\n</style>\r\n"],"names":["props","__props","canvasEl","ref","error","loading","pageIndex","pageCount","pageDims","UTIF","ifds","renderToken","ensureUtif","mod","n","load","myToken","lib","buf","fetchViewerArrayBuffer","_a","paint","err","idx","ifd","rgba","w","h","canvas","ctx","imageData","next","prev","onMounted","onBeforeUnmount","watch","pageLabel","computed","tt","key","fallback","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_cache","_hoisted_4","_vShow","_hoisted_5","_hoisted_6","_hoisted_7","_toDisplayString","_hoisted_8"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"Viewer3D-Ba-RPIRz.js","sources":["../../core/src/viewers/Viewer3D.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\n/**\r\n * Viewer3D — 3D model preview via `@google/model-viewer`.\r\n *\r\n * Lazy-imports the `@google/model-viewer` web component (~80 KB).\r\n *\r\n * Format support: model-viewer **only** understands glTF (`.gltf`,\r\n * `.glb`) and USDZ (iOS). For unsupported formats (`.stl`, `.obj`,\r\n * `.fbx`, `.3ds`) we deliberately render a download fallback instead\r\n * of feeding them to model-viewer — earlier code did the latter,\r\n * which surfaced as `JSON.parse(<ascii STL>)` SyntaxError because\r\n * model-viewer parses the response body as glTF JSON. (sweep-2026-05-09\r\n * bugs 19-20.)\r\n *\r\n * GLB rendering size: model-viewer mounts its canvas inside a\r\n * shadow root that doesn't always inherit `height: 100%` from\r\n * flexbox parents — we pin explicit sizing on the host element\r\n * to avoid the \"Framebuffer is incomplete: zero size\" warning.\r\n * (sweep-2026-05-09 bug 21.)\r\n */\r\nimport { computed, onMounted, ref, watch } from 'vue';\r\n\r\nconst props = defineProps<{\r\n url: string;\r\n mime?: string;\r\n ext: string;\r\n /** Locale-aware error/loading messages. */\r\n t?: (key: string) => string;\r\n}>();\r\n\r\nconst SUPPORTED_EXTS = new Set(['glb', 'gltf', 'usdz']);\r\n\r\nconst isSupported = computed(() => SUPPORTED_EXTS.has((props.ext || '').toLowerCase()));\r\n\r\nconst error = ref<string | null>(null);\r\nconst ready = ref(false);\r\n\r\nasync function load(): Promise<void> {\r\n ready.value = false;\r\n error.value = null;\r\n // Bail out early for formats model-viewer can't parse — feeding\r\n // them to <model-viewer> triggers JSON.parse SyntaxError because\r\n // it expects glTF JSON.\r\n if (!isSupported.value) {\r\n error.value = props.t\r\n ? props.t('viewer.format_unsupported_3d')\r\n : `3D format \".${props.ext}\" not supported in browser preview — please download.`;\r\n return;\r\n }\r\n try {\r\n await import(/* @vite-ignore */ '@google/model-viewer');\r\n ready.value = true;\r\n } catch {\r\n error.value = props.t\r\n ? props.t('viewer.peer_not_installed')\r\n : '3D viewer requires `@google/model-viewer` — install or use download.';\r\n }\r\n}\r\n\r\nonMounted(load);\r\n\r\nwatch(() => props.url, () => {\r\n // Re-evaluate on URL change (different file may need different\r\n // fallback message).\r\n load();\r\n});\r\n</script>\r\n\r\n<template>\r\n <div class=\"filex-viewer-3d\">\r\n <model-viewer\r\n v-if=\"ready && !error\"\r\n :src=\"url\"\r\n auto-rotate\r\n camera-controls\r\n touch-action=\"pan-y\"\r\n shadow-intensity=\"1\"\r\n :alt=\"ext + ' model'\"\r\n style=\"width: 100%; height: 100%; min-height: 480px; display: block\"\r\n />\r\n <div v-else-if=\"error\" class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">📦</span>\r\n <p>{{ error }}</p>\r\n </div>\r\n <div v-else class=\"filex-viewer-fallback\">\r\n <span class=\"filex-viewer-fallback__icon\">⏳</span>\r\n <p>{{ t ? t('viewer.loading') : 'Loading…' }}</p>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.filex-viewer-3d {\r\n width: 100%;\r\n height: 100%;\r\n min-height: 480px;\r\n background: #1a1a1a;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n.filex-viewer-3d :deep(model-viewer) {\r\n width: 100%;\r\n height: 100%;\r\n min-height: 480px;\r\n background: #1a1a1a;\r\n display: block;\r\n}\r\n.filex-viewer-fallback {\r\n text-align: center;\r\n color: #c8cdd6;\r\n padding: 32px;\r\n max-width: 480px;\r\n}\r\n.filex-viewer-fallback__icon {\r\n font-size: 48px;\r\n display: block;\r\n margin-bottom: 12px;\r\n}\r\n</style>\r\n"],"names":["props","__props","SUPPORTED_EXTS","isSupported","computed","error","ref","ready","load","onMounted","watch","_openBlock","_createElementBlock","_hoisted_1","_createBlock","_component_model_viewer","_hoisted_2","_cache","_createElementVNode","_hoisted_3","_toDisplayString"],"mappings":";;;;;;;;;;;;;;;;AAsBA,UAAMA,IAAQC,GAQRC,IAAiB,oBAAI,IAAI,CAAC,OAAO,QAAQ,MAAM,CAAC,GAEhDC,IAAcC,EAAS,MAAMF,EAAe,KAAKF,EAAM,OAAO,IAAI,YAAA,CAAa,CAAC,GAEhFK,IAAQC,EAAmB,IAAI,GAC/BC,IAAQD,EAAI,EAAK;AAEvB,mBAAeE,IAAsB;AAMnC,UALAD,EAAM,QAAQ,IACdF,EAAM,QAAQ,MAIV,CAACF,EAAY,OAAO;AACtB,QAAAE,EAAM,QAAQL,EAAM,IAChBA,EAAM,EAAE,8BAA8B,IACtC,eAAeA,EAAM,GAAG;AAC5B;AAAA,MACF;AACA,UAAI;AACF,cAAM;AAAA;AAAA,UAA0B;AAAA,QAAA,GAChCO,EAAM,QAAQ;AAAA,MAChB,QAAQ;AACN,QAAAF,EAAM,QAAQL,EAAM,IAChBA,EAAM,EAAE,2BAA2B,IACnC;AAAA,MACN;AAAA,IACF;AAEA,WAAAS,EAAUD,CAAI,GAEdE,EAAM,MAAMV,EAAM,KAAK,MAAM;AAG3B,MAAAQ,EAAA;AAAA,IACF,CAAC;;AAIC,aAAAG,EAAA,GAAAC,EAmBM,OAnBNC,GAmBM;AAAA,QAjBIN,EAAA,UAAUF,EAAA,cADlBS,EASEC,GAAA;AAAA;UAPC,KAAKd,EAAA;AAAA,UACN,eAAA;AAAA,UACA,mBAAA;AAAA,UACA,gBAAa;AAAA,UACb,oBAAiB;AAAA,UAChB,KAAKA,EAAA,MAAG;AAAA,UACT,OAAA,EAAA,OAAA,QAAA,QAAA,QAAA,cAAA,SAAA,SAAA,QAAA;AAAA,QAAA,+BAEcI,EAAA,SAAhBM,EAAA,GAAAC,EAGM,OAHNI,GAGM;AAAA,UAFJC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAC,EAAmD,QAAA,EAA7C,OAAM,8BAAA,GAA8B,MAAE,EAAA;AAAA,UAC5CA,EAAkB,aAAZb,EAAA,KAAK,GAAA,CAAA;AAAA,QAAA,OAEbM,EAAA,GAAAC,EAGM,OAHNO,GAGM;AAAA,UAFJF,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAC,EAAkD,QAAA,EAA5C,OAAM,8BAAA,GAA8B,KAAC,EAAA;AAAA,UAC3CA,EAAiD,KAAA,MAAAE,EAA3CnB,EAAA,IAAIA,EAAA,EAAC,gBAAA,IAAA,UAAA,GAAA,CAAA;AAAA,QAAA;;;;;"}