@hienlh/ppm 0.18.1 → 0.18.3
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.
- package/CHANGELOG.md +22 -0
- package/CLAUDE.md +1 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +6 -1
- package/dist/web/assets/{ai-resource-editor-Bmk4P0YS.js → ai-resource-editor-3Zk3gYSZ.js} +1 -1
- package/dist/web/assets/{angular-html-C-Kjr43S.js → angular-html-jfMqUuRd.js} +1 -1
- package/dist/web/assets/{angular-ts-CaDDbZqm.js → angular-ts-wytn9PMm.js} +1 -1
- package/dist/web/assets/api-client-CzABTreM.js +1 -0
- package/dist/web/assets/{api-settings-CAhcNpj5.js → api-settings-DfNRPr1q.js} +1 -1
- package/dist/web/assets/api-settings-DlcoR5QT.js +1 -0
- package/dist/web/assets/{api-themes-CAjg_Bt9.js → api-themes-CEyYK7AK.js} +1 -1
- package/dist/web/assets/{apl-B1WsQFAb.js → apl-i-ahKx6O.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-Bs7wzj-W.js +1 -0
- package/dist/web/assets/arrow-right-DubGFkN8.js +1 -0
- package/dist/web/assets/{astro-Bdnz7nVp.js → astro-DVBCJfG6.js} +1 -1
- package/dist/web/assets/audio-preview-DG2Tw0cO.js +1 -0
- package/dist/web/assets/{blade-B2euh8sS.js → blade-BHlL8SqU.js} +1 -1
- package/dist/web/assets/{bsl-GNeMaxd0.js → bsl-D-UOfR1F.js} +1 -1
- package/dist/web/assets/button-B4MWPjWj.js +1 -0
- package/dist/web/assets/{cairo-D7G0W7-s.js → cairo-Bn6rucli.js} +1 -1
- package/dist/web/assets/chat-tab-DvbbVMBi.js +15 -0
- package/dist/web/assets/{cobol-Q6YgysnI.js → cobol-Byn9FYKu.js} +1 -1
- package/dist/web/assets/code-editor-BKg7Li-L.js +10 -0
- package/dist/web/assets/{coffee-BjufWxVc.js → coffee-DjBl4gm-.js} +1 -1
- package/dist/web/assets/{conflict-editor-DC3liBm_.js → conflict-editor-CJNtovCh.js} +3 -3
- package/dist/web/assets/{context-menu-q-RHHAWz.js → context-menu-DkQdt6YA.js} +1 -1
- package/dist/web/assets/{cpp-CqWU0gCR.js → cpp-CKzic-3E.js} +1 -1
- package/dist/web/assets/{crystal-ylayVajF.js → crystal-Bkg-Ly_g.js} +1 -1
- package/dist/web/assets/{csv-preview-BhCOjgq1.js → csv-preview-BR6gCSZJ.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-BzPfsCfd.js → data-grid-overlay-editor-B1mTl3KS.js} +1 -1
- package/dist/web/assets/{database-viewer-Z6uLyZVO.js → database-viewer-DzuwuFSr.js} +1 -1
- package/dist/web/assets/diff-viewer-DL3_tISz.js +4 -0
- package/dist/web/assets/{docx-preview-C_fSjfy_.js → docx-preview-BzgyssBV.js} +1 -1
- package/dist/web/assets/download-D9UYwY0-.js +1 -0
- package/dist/web/assets/{edge-DX4NxQfh.js → edge-DVbZnd3Y.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-DfX-9om9.js → edit-diff-preview-HTZPC9VP.js} +1 -1
- package/dist/web/assets/{elixir-CSh3NjbV.js → elixir-Dwi8Wu7W.js} +1 -1
- package/dist/web/assets/{elm-DBzwFYq9.js → elm-DtIv-HXJ.js} +1 -1
- package/dist/web/assets/{erb-yxVOb8aB.js → erb-D3HEDz1x.js} +1 -1
- package/dist/web/assets/{erlang-5XIDkYrM.js → erlang-2MjTCzGz.js} +1 -1
- package/dist/web/assets/{esm-DO4el2OJ.js → esm-CZ8B8Ba2.js} +1 -1
- package/dist/web/assets/explorer-body-CrrY1HbH.js +2 -0
- package/dist/web/assets/explorer-window-content-CvQPeiwU.js +1 -0
- package/dist/web/assets/{extension-webview-ePIM2fwM.js → extension-webview-DH1PfQF2.js} +1 -1
- package/dist/web/assets/{fortran-fixed-form-D4tE5VWY.js → fortran-fixed-form-BLyAtyPM.js} +1 -1
- package/dist/web/assets/{fsharp-By8soj6-.js → fsharp-Bxbn_gbr.js} +1 -1
- package/dist/web/assets/{gdresource-DoSwM7Hv.js → gdresource-sFMY4D2Q.js} +1 -1
- package/dist/web/assets/{git-commit-_ZiciHIx.js → git-commit-BzB9Lio5.js} +1 -1
- package/dist/web/assets/{git-log-panel-BRWmTzX1.js → git-log-panel-gUm4E3wo.js} +1 -1
- package/dist/web/assets/{git-rebase-C3Y5N9-s.js → git-rebase-CKSVd848.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-D7i54kbM.js +1 -0
- package/dist/web/assets/glide-data-grid-D8J5lwUP.js +138 -0
- package/dist/web/assets/{glimmer-js-BPBTXVlC.js → glimmer-js-BY8aExAJ.js} +1 -1
- package/dist/web/assets/{glimmer-ts-BQSZdy_D.js → glimmer-ts-Bak54dBX.js} +1 -1
- package/dist/web/assets/{glsl-CbQdxpU-.js → glsl-nR2eaJQe.js} +1 -1
- package/dist/web/assets/{graphql-GMlKikpY.js → graphql-CGPPFAU6.js} +1 -1
- package/dist/web/assets/group-chat-tab-DihiQPSi.js +1 -0
- package/dist/web/assets/{hack-DyshcLec.js → hack-CXIMX-Ol.js} +1 -1
- package/dist/web/assets/{haml-rqCqWzsq.js → haml-tPY-9Pfm.js} +1 -1
- package/dist/web/assets/{handlebars-BCKwSWjR.js → handlebars-BuW1LT7T.js} +1 -1
- package/dist/web/assets/{html-Cg29xPR1.js → html-bgVcwZ-t.js} +1 -1
- package/dist/web/assets/{html-derivative-geltIVg8.js → html-derivative-D6-IxTgn.js} +1 -1
- package/dist/web/assets/{http-pG7Vp237.js → http-CJ1zyB-h.js} +1 -1
- package/dist/web/assets/{hurl-Di3Uu_Mc.js → hurl-CmoT7l3T.js} +1 -1
- package/dist/web/assets/{hxml-CRy4lbv8.js → hxml-CztOsL8o.js} +1 -1
- package/dist/web/assets/{image-preview-CP82lor8.js → image-preview-DOQBNgwl.js} +1 -1
- package/dist/web/assets/index-BtncTUyM.js +52 -0
- package/dist/web/assets/index-Bucbpby-.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-BV41AzR9.js +1 -0
- package/dist/web/assets/{jinja-C8GyVnvd.js → jinja-B1pq3jJq.js} +1 -1
- package/dist/web/assets/{jison-BywnqPn6.js → jison-D8B5pCwA.js} +1 -1
- package/dist/web/assets/{julia-DTrO3T3B.js → julia-D0K3bwpU.js} +1 -1
- package/dist/web/assets/{just-CA3KSHPi.js → just-B9Jlddu-.js} +1 -1
- package/dist/web/assets/keybindings-store-AynYQVnV.js +1 -0
- package/dist/web/assets/{latex-BC5xUMpc.js → latex-BPJSSE6j.js} +1 -1
- package/dist/web/assets/{liquid-Chd8tSyQ.js → liquid-lv10fo4U.js} +1 -1
- package/dist/web/assets/{lua-DHaEtwLv.js → lua-PNuaIBEF.js} +1 -1
- package/dist/web/assets/markdown-renderer-BBlGpszb.js +1 -0
- package/dist/web/assets/{markdown-renderer-DDgl5zDc.js → markdown-renderer-CVGub2iS.js} +3 -3
- package/dist/web/assets/{marko-Desx_bC-.js → marko-Du3frD6X.js} +1 -1
- package/dist/web/assets/{mdc-DahWHc1t.js → mdc-BeDVcFRl.js} +1 -1
- package/dist/web/assets/media-url-C5vA0ha9.js +1 -0
- package/dist/web/assets/{mobile-bottom-sheet-BQt45q9T.js → mobile-bottom-sheet-CS3XMwFw.js} +1 -1
- package/dist/web/assets/mobile-explorer-sheet-CSgc5JOk.js +1 -0
- package/dist/web/assets/{nextflow-3A7lutCA.js → nextflow-DkcXP71s.js} +1 -1
- package/dist/web/assets/{nginx-XQda6Hdy.js → nginx-C5n8N_bt.js} +1 -1
- package/dist/web/assets/{nim-DHqlpwP1.js → nim-CIhyfs-A.js} +1 -1
- package/dist/web/assets/notification-store-1ksB0YwR.js +1 -0
- package/dist/web/assets/{number-overlay-editor-DgZtViPO.js → number-overlay-editor-NgOsWJ7x.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-CaJoP44m.js +1 -0
- package/dist/web/assets/{panel-store-s6Qx49RK.js → panel-store-DCD82zc1.js} +1 -1
- package/dist/web/assets/{pdf-preview-BXDOe7bG.js → pdf-preview-DSAkWbxY.js} +1 -1
- package/dist/web/assets/{perl-M-ncjACb.js → perl-Cf31sZYE.js} +1 -1
- package/dist/web/assets/{php-CKIajrZi.js → php-Dzl_MDIW.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-DSGZmNw2.js +1 -0
- package/dist/web/assets/plus-DmjC2iRB.js +1 -0
- package/dist/web/assets/{postgres-viewer-DkHYV33h.js → postgres-viewer-DOiM_5Nv.js} +3 -3
- package/dist/web/assets/{project-store-DyaEpHVG.js → project-store-B8BkHXy5.js} +1 -1
- package/dist/web/assets/{pug-DO0u_gO4.js → pug-CxSYHrB3.js} +1 -1
- package/dist/web/assets/{qml-UEje1PAA.js → qml-DlEjGhwN.js} +1 -1
- package/dist/web/assets/radar-KQ55EAFF-Be4VUTs0.js +1 -0
- package/dist/web/assets/{razor-lCs5T1Ib.js → razor-KVt5uW14.js} +1 -1
- package/dist/web/assets/resolve-theme-CJvkL8hU.js +1 -0
- package/dist/web/assets/{rst-CZX_O0z4.js → rst-D5BwNTnw.js} +1 -1
- package/dist/web/assets/{ruby-idycVAyE.js → ruby-D5fejQwd.js} +1 -1
- package/dist/web/assets/run-in-terminal-B8TDtaM_.js +1 -0
- package/dist/web/assets/{sas-o5gTfUwp.js → sas-Bj7B1CB2.js} +1 -1
- package/dist/web/assets/{scss-CRTk3iBQ.js → scss-BB0CUoCL.js} +1 -1
- package/dist/web/assets/send-to-chat-CuBAVC8l.js +1 -0
- package/dist/web/assets/{settings-store-ChqHdT2V.js → settings-store-CY-4_U3H.js} +2 -2
- package/dist/web/assets/settings-tab-D_oruJB9.js +1 -0
- package/dist/web/assets/{shaderlab-3e5ln8ci.js → shaderlab-BdjEZUMc.js} +1 -1
- package/dist/web/assets/{shellsession-CGQjQ75I.js → shellsession-Bp1OA1rR.js} +1 -1
- package/dist/web/assets/{soy-CxY0VwX2.js → soy-DlYz3wsC.js} +1 -1
- package/dist/web/assets/{sparql-CBAGAFuq.js → sparql-CdfII5Jd.js} +1 -1
- package/dist/web/assets/sql-query-editor-PWpuw-O5.js +1 -0
- package/dist/web/assets/{sqlite-viewer-Cpq06-nz.js → sqlite-viewer-1S6cwVWa.js} +1 -1
- package/dist/web/assets/{stata-BoezhOvk.js → stata-BvUA6GUW.js} +1 -1
- package/dist/web/assets/{surrealql-CHEzAhu7.js → surrealql--DLNbTyI.js} +1 -1
- package/dist/web/assets/{svelte-y6xtu2zX.js → svelte-CBfSsG4n.js} +1 -1
- package/dist/web/assets/system-monitor-tab-U0Jh9-2v.js +1 -0
- package/dist/web/assets/{tab-store-C42sktPo.js → tab-store-DAsvpx4t.js} +1 -1
- package/dist/web/assets/team-member-window-content-DSZL4GIj.js +1 -0
- package/dist/web/assets/{templ-DbG2y5yD.js → templ-Dv8zpKZW.js} +1 -1
- package/dist/web/assets/terminal-tab-uVhX8AGG.js +3 -0
- package/dist/web/assets/{tex-CeKQhrQG.js → tex-CsrOiqh1.js} +1 -1
- package/dist/web/assets/tool-cards-QuTCNfYR.js +8 -0
- package/dist/web/assets/treemap-KZPCXAKY-Cu2zgbxU.js +1 -0
- package/dist/web/assets/{ts-tags-iKKOXJjG.js → ts-tags-3T98k4EJ.js} +1 -1
- package/dist/web/assets/{twig-DK8Vrp-G.js → twig-u6QZ45FH.js} +1 -1
- package/dist/web/assets/{use-blob-url-DYtOHK7u.js → use-blob-url-BmlYYZ8L.js} +1 -1
- package/dist/web/assets/use-is-mobile-B8FA4kQf.js +1 -0
- package/dist/web/assets/use-monaco-theme-DvmINdhI.js +1 -0
- package/dist/web/assets/use-websocket-DoZdQS0G.js +1 -0
- package/dist/web/assets/{vendor-mermaid-C977xNeE.js → vendor-mermaid-Bg4vE8QA.js} +1 -1
- package/dist/web/assets/video-preview-CzU09X0C.js +1 -0
- package/dist/web/assets/{vue-JkIEObMV.js → vue-CxIsxtwn.js} +1 -1
- package/dist/web/assets/{vue-html-D8SqnU86.js → vue-html-BGL5qnuH.js} +1 -1
- package/dist/web/assets/{vue-vine-DJj7N4WD.js → vue-vine-DHPh_gMr.js} +1 -1
- package/dist/web/assets/{xml-C-00w9Rv.js → xml-C-vM2m7J.js} +1 -1
- package/dist/web/assets/{xsl-CVdCwPHV.js → xsl-DvTXNwuO.js} +1 -1
- package/dist/web/index.html +21 -20
- package/dist/web/sw.js +1 -1
- package/docs/codebase-summary.md +1 -0
- package/package.json +1 -1
- package/scripts/dev-quick-tunnel-retry.mjs +51 -0
- package/src/providers/claude-agent-sdk.ts +6 -0
- package/src/server/helpers/media-route-handlers.ts +66 -0
- package/src/server/helpers/range-file-response.ts +86 -0
- package/src/server/index.ts +24 -17
- package/src/server/middleware/auth.ts +3 -2
- package/src/server/routes/files.ts +40 -7
- package/src/server/routes/fs-browse.ts +43 -5
- package/src/server/routes/fs-upload.ts +32 -0
- package/src/server/routes/teams.ts +34 -0
- package/src/server/ws/chat.ts +64 -16
- package/src/server/ws/team-inbox-watcher.ts +61 -22
- package/src/server/ws/terminal.ts +24 -6
- package/src/services/fs-ops/fs-ops-upload.service.ts +120 -0
- package/src/services/media-transcode/ffmpeg-capabilities.ts +89 -0
- package/src/services/media-transcode/media-probe.ts +63 -0
- package/src/services/media-transcode/transcode-stream.ts +129 -0
- package/src/services/subagent-transcript-merger.ts +1 -1
- package/src/services/team-member-activity/member-activity.service.ts +117 -0
- package/src/services/team-member-activity/outbound-message-scanner.ts +121 -0
- package/src/services/team-member-activity/subagent-transcript-index.ts +95 -0
- package/src/services/team-member-activity/transcript-tail-summary.ts +125 -0
- package/src/shared/background-agent-status.ts +79 -0
- package/src/types/api.ts +1 -0
- package/src/types/chat.ts +6 -1
- package/src/web/components/chat/chat-history-bar.tsx +4 -2
- package/src/web/components/chat/chat-tab.tsx +1 -0
- package/src/web/components/chat/message-input.tsx +13 -6
- package/src/web/components/chat/mini-markdown.tsx +17 -0
- package/src/web/components/chat/send-message-card.tsx +134 -0
- package/src/web/components/chat/send-message-parse.ts +159 -0
- package/src/web/components/chat/team-activity-panel.tsx +107 -121
- package/src/web/components/chat/team-member-activity-row.tsx +92 -0
- package/src/web/components/chat/team-member-list.tsx +43 -0
- package/src/web/components/chat/team-member-window-content.tsx +97 -0
- package/src/web/components/chat/team-message-badges.ts +18 -0
- package/src/web/components/chat/team-message-list.tsx +88 -0
- package/src/web/components/chat/team-message-preview.ts +87 -0
- package/src/web/components/chat/tool-cards.tsx +44 -18
- package/src/web/components/editor/audio-preview.tsx +6 -7
- package/src/web/components/editor/video-player/use-video-keyboard-shortcuts.ts +62 -0
- package/src/web/components/editor/video-player/video-player-controls.tsx +103 -0
- package/src/web/components/editor/video-player/video-player.tsx +190 -0
- package/src/web/components/editor/video-player/video-settings-menu.tsx +92 -0
- package/src/web/components/editor/video-player/video-transform.ts +49 -0
- package/src/web/components/editor/video-preview.tsx +75 -14
- package/src/web/components/explorer/file-tree.tsx +6 -0
- package/src/web/components/explorer/tree-node-context-menu.tsx +5 -1
- package/src/web/components/floating-window/window-content-registry.ts +5 -0
- package/src/web/components/floating-window/window-store-types.ts +1 -1
- package/src/web/components/os-explorer/actions/explorer-actions-upload.ts +96 -0
- package/src/web/components/os-explorer/actions/use-explorer-actions.ts +23 -2
- package/src/web/components/os-explorer/actions/use-explorer-upload-actions.tsx +41 -0
- package/src/web/components/os-explorer/dnd/use-drop-transfer.tsx +10 -1
- package/src/web/components/os-explorer/dnd/use-entry-row-dnd.ts +8 -1
- package/src/web/components/os-explorer/dnd/use-external-file-drop.ts +84 -0
- package/src/web/components/os-explorer/dnd/use-path-drop-target.ts +46 -3
- package/src/web/components/os-explorer/explorer-body.tsx +1 -1
- package/src/web/components/os-explorer/explorer-context-menu.tsx +10 -0
- package/src/web/components/os-explorer/explorer-dialogs.tsx +2 -0
- package/src/web/components/os-explorer/explorer-sidebar.tsx +10 -5
- package/src/web/components/os-explorer/explorer-toolbar.tsx +32 -2
- package/src/web/components/os-explorer/mobile/mobile-bottom-toolbar.tsx +5 -1
- package/src/web/components/os-explorer/upload/collect-dropped-entries.ts +81 -0
- package/src/web/components/os-explorer/upload/upload-queue.ts +79 -0
- package/src/web/components/os-explorer/upload/use-upload-picker.tsx +74 -0
- package/src/web/components/os-explorer/views/column-row.tsx +3 -1
- package/src/web/components/os-explorer/views/column-view-column.tsx +6 -1
- package/src/web/components/os-explorer/views/icons-view-tile.tsx +1 -1
- package/src/web/components/os-explorer/views/icons-view.tsx +5 -1
- package/src/web/components/os-explorer/views/list-row.tsx +1 -1
- package/src/web/components/os-explorer/views/list-view.tsx +5 -1
- package/src/web/components/shared/markdown-code-block.tsx +3 -7
- package/src/web/components/terminal/terminal-tab.tsx +19 -25
- package/src/web/hooks/use-chat.ts +77 -15
- package/src/web/hooks/use-team-activity-feed.ts +92 -0
- package/src/web/hooks/use-terminal-command-queue.ts +108 -0
- package/src/web/hooks/use-terminal.ts +45 -3
- package/src/web/lib/fs-api.ts +9 -0
- package/src/web/lib/fs-upload-xhr.ts +62 -0
- package/src/web/lib/media-url.ts +51 -0
- package/src/web/lib/open-terminal-at.ts +22 -0
- package/src/web/lib/run-in-terminal.ts +55 -0
- package/src/web/lib/send-to-chat.ts +118 -0
- package/src/web/lib/ws-auth.ts +13 -0
- package/src/web/lib/ws-client.ts +10 -5
- package/src/web/theme/builtin/aurora.ts +8 -5
- package/.release-run.sh +0 -5
- package/dist/web/assets/api-client-CaRE4HYh.js +0 -1
- package/dist/web/assets/api-settings-DBcXfeJ8.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-B4J2-O8Q.js +0 -1
- package/dist/web/assets/audio-preview-CikvnAOI.js +0 -1
- package/dist/web/assets/chat-tab-B3-KcCn2.js +0 -13
- package/dist/web/assets/code-editor-BpbZw13T.js +0 -10
- package/dist/web/assets/dialog-CkI7rwrh.js +0 -1
- package/dist/web/assets/diff-viewer-CT1ALWt2.js +0 -4
- package/dist/web/assets/explorer-body-CQCyGEet.js +0 -2
- package/dist/web/assets/explorer-window-content-EtyTAZSh.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-CtQ3yXN-.js +0 -1
- package/dist/web/assets/glide-data-grid-DCJCz4XB.js +0 -138
- package/dist/web/assets/group-chat-tab-C3UD2bcm.js +0 -1
- package/dist/web/assets/index-BYetJoXQ.js +0 -52
- package/dist/web/assets/index-D-xwjNyX.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-Cg0mIJn9.js +0 -1
- package/dist/web/assets/keybindings-store-yBWU8ZYT.js +0 -1
- package/dist/web/assets/markdown-renderer-B2D4gdok.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-BtxyynR3.js +0 -1
- package/dist/web/assets/notification-store-DKw_mGED.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-D79vAFR_.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-DYUOH68U.js +0 -1
- package/dist/web/assets/plus-9LatwJMx.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-B1eznNtd.js +0 -1
- package/dist/web/assets/resolve-theme-B0eotaPq.js +0 -1
- package/dist/web/assets/settings-tab-ESL-6MAA.js +0 -1
- package/dist/web/assets/sql-query-editor-CZdZuawP.js +0 -1
- package/dist/web/assets/system-monitor-tab-XR8NXHpv.js +0 -1
- package/dist/web/assets/terminal-tab-CCCB-_50.js +0 -3
- package/dist/web/assets/tool-cards-CsTs5go2.js +0 -7
- package/dist/web/assets/treemap-KZPCXAKY-SeI2TxLs.js +0 -1
- package/dist/web/assets/use-is-mobile-DnFSkUG2.js +0 -1
- package/dist/web/assets/use-monaco-theme-CZh7xTJZ.js +0 -1
- package/dist/web/assets/video-preview-KbRcyuAA.js +0 -1
- package/src/web/components/chat/team-activity-popover.tsx +0 -202
- /package/dist/web/assets/{abap-DrMyiWmK.js → abap-C1K0-wzc.js} +0 -0
- /package/dist/web/assets/{actionscript-3-BlSOyi0y.js → actionscript-3-CJhQVjLA.js} +0 -0
- /package/dist/web/assets/{ada-B_m96icB.js → ada-Bt8r9fME.js} +0 -0
- /package/dist/web/assets/{andromeeda-Ch3vOiZB.js → andromeeda-DF1I8qi3.js} +0 -0
- /package/dist/web/assets/{apache-CdsaXc1n.js → apache-CnlleE6P.js} +0 -0
- /package/dist/web/assets/{apex-0AnsBevk.js → apex-j0C6Xmk6.js} +0 -0
- /package/dist/web/assets/{api-client-rTAGdEKo.js → api-client-BSB14J4w.js} +0 -0
- /package/dist/web/assets/{applescript-CSxLolzy.js → applescript-DO7AnO8U.js} +0 -0
- /package/dist/web/assets/{apply-theme-CMQXnUAa.js → apply-theme-CNj1iA-v.js} +0 -0
- /package/dist/web/assets/{ara-DXZS0jA5.js → ara-i83AydZj.js} +0 -0
- /package/dist/web/assets/{asciidoc-DDy3pH2A.js → asciidoc-DbBA6-sF.js} +0 -0
- /package/dist/web/assets/{asm-Bd17hhqg.js → asm-B5S47Rgr.js} +0 -0
- /package/dist/web/assets/{aurora-x-C62HJRs-.js → aurora-x-De_IaSKw.js} +0 -0
- /package/dist/web/assets/{awk-Cc-nazni.js → awk-CfyLHXqS.js} +0 -0
- /package/dist/web/assets/{ayu-dark-BsfmNWCU.js → ayu-dark-DTLdZ1Si.js} +0 -0
- /package/dist/web/assets/{ayu-light-BZ4HLa4X.js → ayu-light-DTOfkzhu.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-Bhyjyiqr.js → ayu-mirage-DsAECCMv.js} +0 -0
- /package/dist/web/assets/{ballerina-QiWgir3v.js → ballerina-CumGp9A7.js} +0 -0
- /package/dist/web/assets/{bat-DxtlkwN3.js → bat-Ca2SBbYN.js} +0 -0
- /package/dist/web/assets/{beancount-Bt21X7M_.js → beancount-CqyXBwwF.js} +0 -0
- /package/dist/web/assets/{berry-Cksre7lO.js → berry-yl-kJr_H.js} +0 -0
- /package/dist/web/assets/{bibtex-DkakgDlR.js → bibtex-DoFFszjV.js} +0 -0
- /package/dist/web/assets/{bicep-8crmcyXU.js → bicep-CWPi4nfK.js} +0 -0
- /package/dist/web/assets/{bird2-CewQ2I_Z.js → bird2-DXew-ut0.js} +0 -0
- /package/dist/web/assets/{bot-nk1k3ELu.js → bot-CunPuEdW.js} +0 -0
- /package/dist/web/assets/{c-C_6zE8Ha.js → c-clbySDvd.js} +0 -0
- /package/dist/web/assets/{c3-DLWB9-dp.js → c3-B65jvSM1.js} +0 -0
- /package/dist/web/assets/{cadence-D8qYS6pR.js → cadence-Cm8tQTHN.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-BzVXoV-d.js → can-open-in-ppm-Cu-XYIgu.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-Bh95lNRy.js → catppuccin-frappe-DLeGslh_.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-C1PlN3G0.js → catppuccin-latte-CR5GeHws.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-CldtgdK4.js → catppuccin-macchiato-p-XgjxhP.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-BiwqxX9A.js → catppuccin-mocha-B8QOAZLl.js} +0 -0
- /package/dist/web/assets/{clarity-CGiU22jY.js → clarity-DPulbvKH.js} +0 -0
- /package/dist/web/assets/{clojure-COIC3doh.js → clojure-DFuWS20u.js} +0 -0
- /package/dist/web/assets/{cmake-DWUEQfHv.js → cmake-DejCqcu4.js} +0 -0
- /package/dist/web/assets/{codeowners-BNHiAQea.js → codeowners-BwAyqWIH.js} +0 -0
- /package/dist/web/assets/{codeql-BuKaoS0j.js → codeql-DgSwFjqI.js} +0 -0
- /package/dist/web/assets/{common-lisp-D5IKbxsd.js → common-lisp-CxIVJCtf.js} +0 -0
- /package/dist/web/assets/{coq-BMVS-p94.js → coq-DLSjSnmf.js} +0 -0
- /package/dist/web/assets/{csharp-DMlbXbM4.js → csharp-C1HHzXBp.js} +0 -0
- /package/dist/web/assets/{css-CjkJC89X.js → css-VXsMY--y.js} +0 -0
- /package/dist/web/assets/{csv-DoNVBBf0.js → csv-BEbcJdHz.js} +0 -0
- /package/dist/web/assets/{csv-parser-DHvoTjMF.js → csv-parser-r-Nk1oHT.js} +0 -0
- /package/dist/web/assets/{cue-DoTRbBg-.js → cue-BkDnFqUD.js} +0 -0
- /package/dist/web/assets/{cypher-DVsNdTT3.js → cypher-1cMqojSQ.js} +0 -0
- /package/dist/web/assets/{d-EX7BBSrv.js → d-BnYjRXtH.js} +0 -0
- /package/dist/web/assets/{dark-plus-P_YTHwlh.js → dark-plus-XfbaH7kZ.js} +0 -0
- /package/dist/web/assets/{dart-Do-rgU4S.js → dart-Ca7s-8hK.js} +0 -0
- /package/dist/web/assets/{data-grid-types-CUx8cusN.js → data-grid-types-BXwlFMzs.js} +0 -0
- /package/dist/web/assets/{dax-DxOieacu.js → dax-CmuOw-mY.js} +0 -0
- /package/dist/web/assets/{desktop-CvdV7SBf.js → desktop-C2gJ6Ovb.js} +0 -0
- /package/dist/web/assets/{diff-CNOetGen.js → diff-BCEo1Ej7.js} +0 -0
- /package/dist/web/assets/{dist-CMfLpPW_.js → dist-CUPbqNnL.js} +0 -0
- /package/dist/web/assets/{dist-DduBIVkD.js → dist-DOlBnxFX.js} +0 -0
- /package/dist/web/assets/{docker-DAlG4_q-.js → docker-DN2jlyAh.js} +0 -0
- /package/dist/web/assets/{dotenv-Dh3qf6yx.js → dotenv-NExMY2kS.js} +0 -0
- /package/dist/web/assets/{dracula-baAGmJYG.js → dracula-B9lbE01y.js} +0 -0
- /package/dist/web/assets/{dracula-soft-l7ZIyums.js → dracula-soft-CMBBfKF_.js} +0 -0
- /package/dist/web/assets/{dream-maker-DeRjdBn8.js → dream-maker-DEyDwFsd.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-CB05-jQA.js → emacs-lisp-D_qP2zS6.js} +0 -0
- /package/dist/web/assets/{everforest-dark-CT-llQBT.js → everforest-dark-DbHa2U-p.js} +0 -0
- /package/dist/web/assets/{everforest-light-ByPJkTT7.js → everforest-light-BISkJchP.js} +0 -0
- /package/dist/web/assets/{fennel-CeMarbvn.js → fennel-6B22SfJR.js} +0 -0
- /package/dist/web/assets/{file-exclamation-point-COAwgNGw.js → file-exclamation-point-a8f3_w7a.js} +0 -0
- /package/dist/web/assets/{fish-BYrt6Xtb.js → fish-CubIIvJD.js} +0 -0
- /package/dist/web/assets/{fluent-Cr5VcAwh.js → fluent-DF55zQ09.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-DQmKtrLa.js → fortran-free-form-DvOu8jAt.js} +0 -0
- /package/dist/web/assets/{gdscript-QTDKjzhY.js → gdscript-DCPxdLpq.js} +0 -0
- /package/dist/web/assets/{gdshader-Chr-5UYt.js → gdshader-CTZ381FO.js} +0 -0
- /package/dist/web/assets/{genie-kWHMWnt0.js → genie-C_QDtvgU.js} +0 -0
- /package/dist/web/assets/{gherkin-DtEBQFUo.js → gherkin-BcvK42tF.js} +0 -0
- /package/dist/web/assets/{github-dark-B5aiUta2.js → github-dark-C9afs_4w.js} +0 -0
- /package/dist/web/assets/{github-dark-default-BkxtsTqR.js → github-dark-default-CKGVrl3Z.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-B9QjR_0K.js → github-dark-dimmed-C3dQZ_LC.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-D6bO-5c0.js → github-dark-high-contrast-DW78QukY.js} +0 -0
- /package/dist/web/assets/{github-light-Cg2ZW_CJ.js → github-light-BnP2dznS.js} +0 -0
- /package/dist/web/assets/{github-light-default-eD7qUVlQ.js → github-light-default-C2fPZzPG.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-CFnlSVjd.js → github-light-high-contrast-BzIuUFR2.js} +0 -0
- /package/dist/web/assets/{gleam-BpYoOqIT.js → gleam-BpeKwEIO.js} +0 -0
- /package/dist/web/assets/{gn-BxwtZPau.js → gn-nUb_Mit0.js} +0 -0
- /package/dist/web/assets/{gnuplot-CRyiZDfl.js → gnuplot-D7I0v20p.js} +0 -0
- /package/dist/web/assets/{go-Dw1Qx94W.js → go-D7Qqska7.js} +0 -0
- /package/dist/web/assets/{groovy-zq_SbWk-.js → groovy-DS-pne5-.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-DbbNy8-Q.js → gruvbox-dark-hard-C0W01fsq.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-BQZ7Kj6C.js → gruvbox-dark-medium-Bqo6fQbg.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-vNavErXi.js → gruvbox-dark-soft-D-XSM_fu.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-AOFbCd7i.js → gruvbox-light-hard-IVAwMJRl.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-DqtxND6H.js → gruvbox-light-medium-38ATiG7i.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-Cg0basu6.js → gruvbox-light-soft-DnZr3c_0.js} +0 -0
- /package/dist/web/assets/{haskell-CcsmcOez.js → haskell-uQcywkDH.js} +0 -0
- /package/dist/web/assets/{haxe-BimYY9X4.js → haxe-c6bI4_GT.js} +0 -0
- /package/dist/web/assets/{hcl-CTrXCK40.js → hcl-CQXTiEXq.js} +0 -0
- /package/dist/web/assets/{hjson-CmqqU6Qg.js → hjson-ChETf2bz.js} +0 -0
- /package/dist/web/assets/{hlsl-CuJtX_uf.js → hlsl-BMC4JGoE.js} +0 -0
- /package/dist/web/assets/{horizon-BGeSjDYJ.js → horizon-BusFlhLW.js} +0 -0
- /package/dist/web/assets/{horizon-bright-GYMgd3R0.js → horizon-bright-2oD0Mz7W.js} +0 -0
- /package/dist/web/assets/{houston--JD_5r2q.js → houston-DdbbjqFg.js} +0 -0
- /package/dist/web/assets/{hy-C9ILOiqk.js → hy-D_SOuqw9.js} +0 -0
- /package/dist/web/assets/{image-gallery-BWFpZAAP.js → image-gallery-CrM5fHKy.js} +0 -0
- /package/dist/web/assets/{imba-B6F3yus5.js → imba-BxLOHO5I.js} +0 -0
- /package/dist/web/assets/{ini-BfkQswMZ.js → ini-ox-CFcg0.js} +0 -0
- /package/dist/web/assets/{java-DEH5avQ1.js → java-Bzo8yIal.js} +0 -0
- /package/dist/web/assets/{javascript-Dr4yHuV2.js → javascript-DHuz9VXn.js} +0 -0
- /package/dist/web/assets/{json-BuR35ewf.js → json-0_y80FD5.js} +0 -0
- /package/dist/web/assets/{json5-Ny9ZiJAC.js → json5-CEQ50pGM.js} +0 -0
- /package/dist/web/assets/{jsonc-zYVuoZkR.js → jsonc-CfrLEAKA.js} +0 -0
- /package/dist/web/assets/{jsonl-B9xthb_H.js → jsonl-fKbrANC2.js} +0 -0
- /package/dist/web/assets/{jsonnet-CCoLJbMP.js → jsonnet-DKbkPaQ2.js} +0 -0
- /package/dist/web/assets/{jssm-W0GDlQXi.js → jssm-Dxxx1Hqu.js} +0 -0
- /package/dist/web/assets/{jsx-BrLJpWC-.js → jsx-DlJL-Oj3.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-CuVwt_MO.js → kanagawa-dragon-CwN4SV1c.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-B3W_617P.js → kanagawa-lotus-BHltayiE.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-CEx4MP5W.js → kanagawa-wave-D-KXPjw6.js} +0 -0
- /package/dist/web/assets/{kdl-DilRejnB.js → kdl-DvtoJdFo.js} +0 -0
- /package/dist/web/assets/{kotlin-Bq5JtKaa.js → kotlin-CTS4MLcx.js} +0 -0
- /package/dist/web/assets/{kusto-Bhp2KYog.js → kusto-HtSE_sKm.js} +0 -0
- /package/dist/web/assets/{laserwave-WA_7c5hu.js → laserwave-DaXZG9ge.js} +0 -0
- /package/dist/web/assets/{lean-AEGcXwS-.js → lean-BYtGUfWx.js} +0 -0
- /package/dist/web/assets/{less-NPqH-26u.js → less-BoxmU_Mk.js} +0 -0
- /package/dist/web/assets/{lib-BFetOULu.js → lib-BzxL1ARZ.js} +0 -0
- /package/dist/web/assets/{libesm-tR4XlhMj.js → libesm-ah-mr-sh.js} +0 -0
- /package/dist/web/assets/{light-plus-B4xW7cgY.js → light-plus-Bt5CyUuo.js} +0 -0
- /package/dist/web/assets/{llvm-CPyWNcDE.js → llvm-CSdk9q9V.js} +0 -0
- /package/dist/web/assets/{log-CeQmiQSz.js → log-B-kp_3CL.js} +0 -0
- /package/dist/web/assets/{logo-BO0VrjBm.js → logo-DdIsXFDO.js} +0 -0
- /package/dist/web/assets/{luau-B6GT9kA1.js → luau-DUBpLlzQ.js} +0 -0
- /package/dist/web/assets/{make-CwfmN7e_.js → make-B3JVjoW_.js} +0 -0
- /package/dist/web/assets/{markdown-Bbe4FlLp.js → markdown-Seon0vHs.js} +0 -0
- /package/dist/web/assets/{material-theme-iD9XbfsB.js → material-theme-Nq-ChX1P.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-u7M3XGe7.js → material-theme-darker-CPV4ayXJ.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-BGdI48zn.js → material-theme-lighter-0kyjYqEd.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-_mk62F5q.js → material-theme-ocean-DGpAp5co.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-CxFbDyAu.js → material-theme-palenight-B0AUn0NG.js} +0 -0
- /package/dist/web/assets/{matlab-Z0RUE3V_.js → matlab-C2waytxs.js} +0 -0
- /package/dist/web/assets/{mdx-BZ5wPYzV.js → mdx-DAis6R6I.js} +0 -0
- /package/dist/web/assets/{mermaid-CY1_aP-h.js → mermaid-_rnT2YGD.js} +0 -0
- /package/dist/web/assets/{min-dark-DKWtxOre.js → min-dark-BSSjchUB.js} +0 -0
- /package/dist/web/assets/{min-light-e1iwHDfP.js → min-light-DomAFQsa.js} +0 -0
- /package/dist/web/assets/{mipsasm-BiDfQ4ir.js → mipsasm-bBgtvPyG.js} +0 -0
- /package/dist/web/assets/{mojo-DteFEHsj.js → mojo-Cp9BayW0.js} +0 -0
- /package/dist/web/assets/{monokai-BgPbE9xZ.js → monokai-CL_9gbmn.js} +0 -0
- /package/dist/web/assets/{moonbit-mEbRp-mA.js → moonbit-BS_fcr-P.js} +0 -0
- /package/dist/web/assets/{move-CogqZw7A.js → move-C79AH45U.js} +0 -0
- /package/dist/web/assets/{narrat-BD2qjmy1.js → narrat-CJ5s3BDf.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-BNX8GOD_.js → nextflow-groovy-ZHa4JrPJ.js} +0 -0
- /package/dist/web/assets/{night-owl-ed3GbziD.js → night-owl-Jkf9zFQK.js} +0 -0
- /package/dist/web/assets/{night-owl-light-B0j7O0Wn.js → night-owl-light-DRPeaG5J.js} +0 -0
- /package/dist/web/assets/{nix-DFDbcQQm.js → nix-D2Jet9DN.js} +0 -0
- /package/dist/web/assets/{nord-D93TxEQi.js → nord-CREVs22j.js} +0 -0
- /package/dist/web/assets/{nushell-3_H_XKja.js → nushell-CAiDi_mR.js} +0 -0
- /package/dist/web/assets/{objective-c-BM3u6nlm.js → objective-c-CVkmJkC1.js} +0 -0
- /package/dist/web/assets/{objective-cpp-DZ73h42g.js → objective-cpp-DIKDO1Ly.js} +0 -0
- /package/dist/web/assets/{ocaml-B1PU5gmh.js → ocaml-R9qtGQhs.js} +0 -0
- /package/dist/web/assets/{odin-D14L6aRL.js → odin-DTYNQqVr.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-Bj-94Z8v.js → one-dark-pro-BSLWUJn5.js} +0 -0
- /package/dist/web/assets/{one-light-DTdGWyOZ.js → one-light-DbkRXG3t.js} +0 -0
- /package/dist/web/assets/{openscad-Ciq554Sj.js → openscad-BlPcSnmT.js} +0 -0
- /package/dist/web/assets/{pascal-Bfd4qdGi.js → pascal-B1Y46ZZB.js} +0 -0
- /package/dist/web/assets/{pkl-CTurDUfj.js → pkl-BhJSJbFv.js} +0 -0
- /package/dist/web/assets/{plastic-BLQfZXQp.js → plastic-BzxsCTpi.js} +0 -0
- /package/dist/web/assets/{plsql-DyYfP9kQ.js → plsql-DBba7dyP.js} +0 -0
- /package/dist/web/assets/{po-CgXdT8vQ.js → po-BvgLlnNo.js} +0 -0
- /package/dist/web/assets/{poimandres-DOg5fK6s.js → poimandres-DUaI_1JP.js} +0 -0
- /package/dist/web/assets/{polar-Dv4aoL6X.js → polar-C7uILwJn.js} +0 -0
- /package/dist/web/assets/{postcss-DxugHnJD.js → postcss-BgJlpFdw.js} +0 -0
- /package/dist/web/assets/{powerquery-CR3kzRyX.js → powerquery-Dn1MIpZu.js} +0 -0
- /package/dist/web/assets/{powershell-BE91xJQB.js → powershell-Bo-DYzOS.js} +0 -0
- /package/dist/web/assets/{prisma-B_3yUlRQ.js → prisma-CTLs5IdT.js} +0 -0
- /package/dist/web/assets/{prolog-DcT781Ht.js → prolog-QRGun3eG.js} +0 -0
- /package/dist/web/assets/{proto-CSf-w5k2.js → proto-B7PI7apn.js} +0 -0
- /package/dist/web/assets/{puppet-CLGO6QWl.js → puppet-CBq0tLrP.js} +0 -0
- /package/dist/web/assets/{purescript-Bah2McKd.js → purescript-DFewOQb2.js} +0 -0
- /package/dist/web/assets/{python-DUH8qy7N.js → python-iWuxKXvT.js} +0 -0
- /package/dist/web/assets/{qmldir-YIsHnjKq.js → qmldir-cXiW3AsF.js} +0 -0
- /package/dist/web/assets/{qss-CLmoVNA4.js → qss-DASwAbBL.js} +0 -0
- /package/dist/web/assets/{r-Pon-b-vz.js → r-TU2eaIPw.js} +0 -0
- /package/dist/web/assets/{racket-BA09P5Kg.js → racket-SkRKqrLY.js} +0 -0
- /package/dist/web/assets/{raku-DlpzU7Fe.js → raku-D31lthkZ.js} +0 -0
- /package/dist/web/assets/{react-w6wINGnd.js → react-I_EwPIZi.js} +0 -0
- /package/dist/web/assets/{red-l7VuCR6d.js → red-CTcQZevb.js} +0 -0
- /package/dist/web/assets/{reg-g_k7gQEr.js → reg-D8YAsTGf.js} +0 -0
- /package/dist/web/assets/{regexp-CT17B7I7.js → regexp-CD2uvAWx.js} +0 -0
- /package/dist/web/assets/{rel-DkPCS7Bp.js → rel-CAaI-1fg.js} +0 -0
- /package/dist/web/assets/{riscv-CYuFTw30.js → riscv-DR-hJVIj.js} +0 -0
- /package/dist/web/assets/{ron-cY7u_yEu.js → ron-CuUCJ0n4.js} +0 -0
- /package/dist/web/assets/{rose-pine-Cr_h_Ubo.js → rose-pine-aFHxW48i.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-rRewaSZg.js → rose-pine-dawn-Bqz2sBRY.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-3VX5Xwca.js → rose-pine-moon-wqyh0an4.js} +0 -0
- /package/dist/web/assets/{rosmsg-Du4ie5PU.js → rosmsg-CI1ywimO.js} +0 -0
- /package/dist/web/assets/{rust-B7xWL-Eh.js → rust-p7Imk4G_.js} +0 -0
- /package/dist/web/assets/{sass-oXbOG8de.js → sass-C8JfaqCV.js} +0 -0
- /package/dist/web/assets/{save-C4z1p51e.js → save-DRPrDfTt.js} +0 -0
- /package/dist/web/assets/{scala-nlZJhKHf.js → scala-DNxCW1By.js} +0 -0
- /package/dist/web/assets/{scheme-FZ9_Zy8D.js → scheme-BYuUPJoL.js} +0 -0
- /package/dist/web/assets/{sdbl-D_lyvXiu.js → sdbl-DbPeJPUr.js} +0 -0
- /package/dist/web/assets/{shellscript-DRWRboAd.js → shellscript-DMiHlR3q.js} +0 -0
- /package/dist/web/assets/{shield-check-C5laObJv.js → shield-check-8GObuUAn.js} +0 -0
- /package/dist/web/assets/{shield-off-DULFtyLS.js → shield-off-egKAZEwR.js} +0 -0
- /package/dist/web/assets/{slack-dark-BGk2uVHu.js → slack-dark-C4xGcQXI.js} +0 -0
- /package/dist/web/assets/{slack-ochin-PAoSX041.js → slack-ochin-BzgRt_wm.js} +0 -0
- /package/dist/web/assets/{smalltalk-qP0zvICo.js → smalltalk-LDeL9PYH.js} +0 -0
- /package/dist/web/assets/{snazzy-light-B7uccpH6.js → snazzy-light-CXE7a5j_.js} +0 -0
- /package/dist/web/assets/{solarized-dark-CbICLZs3.js → solarized-dark-DgUhY74x.js} +0 -0
- /package/dist/web/assets/{solarized-light-CprWhyjj.js → solarized-light-DD9C-H-9.js} +0 -0
- /package/dist/web/assets/{solidity-B7pcm2K6.js → solidity-CAbDB4D4.js} +0 -0
- /package/dist/web/assets/{splunk-Co2LL4J_.js → splunk-kQREPfIc.js} +0 -0
- /package/dist/web/assets/{sql-cETIdGnT.js → sql-CBzeNAD8.js} +0 -0
- /package/dist/web/assets/{ssh-config-DETG6JCD.js → ssh-config-L1euxrsM.js} +0 -0
- /package/dist/web/assets/{stylus-tmTre2-O.js → stylus-DvBnYniP.js} +0 -0
- /package/dist/web/assets/{swift-BeKQbULV.js → swift-DF5NDQp6.js} +0 -0
- /package/dist/web/assets/{synthwave-84-eCL4-Xdn.js → synthwave-84-DbBhB_Hq.js} +0 -0
- /package/dist/web/assets/{system-verilog-CviwWvEx.js → system-verilog-D8s2ZW_k.js} +0 -0
- /package/dist/web/assets/{systemd-WuoFIbBS.js → systemd-a5-XZJsG.js} +0 -0
- /package/dist/web/assets/{table-CHmxuh6M.js → table-BX2ZrJfM.js} +0 -0
- /package/dist/web/assets/{talonscript-B9VBu7VI.js → talonscript-BLa0URTW.js} +0 -0
- /package/dist/web/assets/{tasl-CN7r11ky.js → tasl-DIoV4XcC.js} +0 -0
- /package/dist/web/assets/{tcl-e1cdhe3h.js → tcl-ztYAdXfQ.js} +0 -0
- /package/dist/web/assets/{terraform-BEP0mfa_.js → terraform-DvpCCiOZ.js} +0 -0
- /package/dist/web/assets/{tokyo-night-BfA_dA37.js → tokyo-night-BkHlYUv0.js} +0 -0
- /package/dist/web/assets/{toml-BrDIfNnt.js → toml-acIrxos6.js} +0 -0
- /package/dist/web/assets/{tsv-CyfGyE4i.js → tsv-BJB5EVCT.js} +0 -0
- /package/dist/web/assets/{tsx-BrFA8Iwf.js → tsx-B1MmXGT3.js} +0 -0
- /package/dist/web/assets/{turtle-9GBtR0mP.js → turtle-DFceTiqd.js} +0 -0
- /package/dist/web/assets/{typescript-BuTRZ65V.js → typescript-Dz9wU5Y1.js} +0 -0
- /package/dist/web/assets/{typespec-CRiNNRXF.js → typespec-CPuYZijj.js} +0 -0
- /package/dist/web/assets/{typst-CmpTnnkl.js → typst-CfsCIYv8.js} +0 -0
- /package/dist/web/assets/{utils-B9H0d3Fh.js → utils-DoY4yTP-.js} +0 -0
- /package/dist/web/assets/{v-DnIi2aab.js → v-CGo0jcXA.js} +0 -0
- /package/dist/web/assets/{vala-B7VxCNZP.js → vala-AsSR0hrb.js} +0 -0
- /package/dist/web/assets/{vb-DGoQ3pBT.js → vb-C7tvbXv1.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-ClRVIJ-k.js → vendor-xterm-BeaIjRrv.js} +0 -0
- /package/dist/web/assets/{verilog-zGOC4qwV.js → verilog--a33ND-p.js} +0 -0
- /package/dist/web/assets/{vesper-DXR9-06q.js → vesper-B_Z0h4pn.js} +0 -0
- /package/dist/web/assets/{vhdl-CCO0oz0l.js → vhdl-CWL5dZPN.js} +0 -0
- /package/dist/web/assets/{viml-Dxwr-QNN.js → viml-BglmT14Y.js} +0 -0
- /package/dist/web/assets/{vitesse-black-Bhah7RxE.js → vitesse-black-RKFsSqQI.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-CGK6XVwc.js → vitesse-dark-D7zDWNmc.js} +0 -0
- /package/dist/web/assets/{vitesse-light-ne5kfw8h.js → vitesse-light-MAp87W5b.js} +0 -0
- /package/dist/web/assets/{vyper-ErDFqVoP.js → vyper-CgCBYg1G.js} +0 -0
- /package/dist/web/assets/{wasm-DtWvUWGr.js → wasm-BOG7ZeTT.js} +0 -0
- /package/dist/web/assets/{wasm-Bd258nS1.js → wasm-Bwl4txwp.js} +0 -0
- /package/dist/web/assets/{wenyan-EZe1IEYT.js → wenyan-DpShPKXZ.js} +0 -0
- /package/dist/web/assets/{wgsl-B1o5_I_9.js → wgsl-BakcCblK.js} +0 -0
- /package/dist/web/assets/{wikitext-C_rwp8An.js → wikitext-NroRWVAO.js} +0 -0
- /package/dist/web/assets/{wit-gbYtF3rY.js → wit-B5CM2pg6.js} +0 -0
- /package/dist/web/assets/{wolfram-DrcQFe2n.js → wolfram-7MTFBJpR.js} +0 -0
- /package/dist/web/assets/{x-B1qHmLdR.js → x-BcqfTY_7.js} +0 -0
- /package/dist/web/assets/{yaml-CzDAObLX.js → yaml-Bwr01G2K.js} +0 -0
- /package/dist/web/assets/{zenscript-B-J1phtg.js → zenscript-Dj8GATvi.js} +0 -0
- /package/dist/web/assets/{zig-BlzNia0O.js → zig-LAE-fbS-.js} +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turns a dropped/picked file batch into `PUT /api/fs/upload` calls, streamed through
|
|
3
|
+
* `uploadFileXhr` with bounded concurrency. Mirrors `transfer()` in
|
|
4
|
+
* `explorer-actions-clipboard.ts`: the same collision prompt (`ctx.resolve`), the same
|
|
5
|
+
* trash-first "Replace" via the 409 `EEXIST` contract, and a `fsChanged` refresh once the
|
|
6
|
+
* batch settles — drag-to-upload and the picker both funnel through this one function.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { toast } from "sonner";
|
|
10
|
+
import { FsError } from "@/lib/fs-api";
|
|
11
|
+
import { uploadFileXhr } from "@/lib/fs-upload-xhr";
|
|
12
|
+
import { dirnameOf, joinPath } from "../format-file-meta";
|
|
13
|
+
import { fsChanged } from "../explorer-store";
|
|
14
|
+
import type { DroppedEntry } from "../upload/collect-dropped-entries";
|
|
15
|
+
import { runUploadQueue, type UploadJob } from "../upload/upload-queue";
|
|
16
|
+
import type { TransferContext } from "./explorer-actions-clipboard";
|
|
17
|
+
import { freeName } from "./explorer-actions-transfer-helpers";
|
|
18
|
+
|
|
19
|
+
/** Uploads sitting behind a collision prompt or a slow connection should not all queue up
|
|
20
|
+
* behind one giant file — three in flight matches the plan's chosen concurrency. */
|
|
21
|
+
const CONCURRENCY = 3;
|
|
22
|
+
|
|
23
|
+
function nameOf(relativePath: string): string {
|
|
24
|
+
return relativePath.split("/").pop() ?? relativePath;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Turns a "/"-joined relative path (as `collectDroppedEntries` produces) into a host path
|
|
28
|
+
* under `dstDir`, using the destination's own separator. */
|
|
29
|
+
function destinationFor(dstDir: string, relativePath: string, sep: string): string {
|
|
30
|
+
return joinPath(dstDir, relativePath.split("/").join(sep), sep);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function uploadResolvingCollisions(
|
|
34
|
+
entry: DroppedEntry,
|
|
35
|
+
dstDir: string,
|
|
36
|
+
sep: string,
|
|
37
|
+
ctx: TransferContext,
|
|
38
|
+
onProgress: (bytesLoaded: number) => void,
|
|
39
|
+
): Promise<void> {
|
|
40
|
+
const destination = destinationFor(dstDir, entry.relativePath, sep);
|
|
41
|
+
try {
|
|
42
|
+
await uploadFileXhr(destination, entry.file, false, (p) => onProgress(p.loaded));
|
|
43
|
+
return;
|
|
44
|
+
} catch (e) {
|
|
45
|
+
if (!(e instanceof FsError) || e.code !== "EEXIST") throw e;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const name = nameOf(entry.relativePath);
|
|
49
|
+
const choice = await ctx.resolve({ name, destination });
|
|
50
|
+
if (choice === "skip") return;
|
|
51
|
+
if (choice === "keep-both") {
|
|
52
|
+
const containingDir = dirnameOf(destination, sep);
|
|
53
|
+
const alternative = await freeName(containingDir, name, sep);
|
|
54
|
+
if (!alternative) throw new Error("No free name available");
|
|
55
|
+
await uploadFileXhr(joinPath(containingDir, alternative, sep), entry.file, false, (p) => onProgress(p.loaded));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
// Replace: the server upload route itself makes the overwrite atomic (tmp file + rename),
|
|
59
|
+
// so unlike the copy/move `transfer()` there is no separate trash-then-write step here.
|
|
60
|
+
await uploadFileXhr(destination, entry.file, true, (p) => onProgress(p.loaded));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function uploadLabel(entries: DroppedEntry[], fraction: number): string {
|
|
64
|
+
const label = entries.length === 1 ? entries[0]!.file.name : `${entries.length} files`;
|
|
65
|
+
return `Uploading ${label}… ${Math.round(fraction * 100)}%`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function uploadEntries(
|
|
69
|
+
entries: DroppedEntry[],
|
|
70
|
+
dstDir: string,
|
|
71
|
+
sep: string,
|
|
72
|
+
ctx: TransferContext,
|
|
73
|
+
): Promise<void> {
|
|
74
|
+
if (entries.length === 0) return;
|
|
75
|
+
|
|
76
|
+
const toastId = toast.loading(uploadLabel(entries, 0));
|
|
77
|
+
const jobs: UploadJob<void>[] = entries.map((entry, index) => ({
|
|
78
|
+
id: String(index),
|
|
79
|
+
size: entry.file.size,
|
|
80
|
+
run: (onProgress) => uploadResolvingCollisions(entry, dstDir, sep, ctx, onProgress),
|
|
81
|
+
}));
|
|
82
|
+
|
|
83
|
+
const results = await runUploadQueue(jobs, CONCURRENCY, (progress) => {
|
|
84
|
+
const fraction = progress.bytesTotal > 0 ? progress.bytesLoaded / progress.bytesTotal : 0;
|
|
85
|
+
toast.loading(uploadLabel(entries, fraction), { id: toastId });
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
fsChanged(dstDir);
|
|
89
|
+
const succeeded = results.filter((r) => r.ok).length;
|
|
90
|
+
const failed = results.length - succeeded;
|
|
91
|
+
if (failed === 0) {
|
|
92
|
+
toast.success(`Uploaded ${succeeded} item${succeeded === 1 ? "" : "s"}`, { id: toastId });
|
|
93
|
+
} else {
|
|
94
|
+
toast.error(`Uploaded ${succeeded}, ${failed} failed`, { id: toastId });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
* plain async functions with no React inside them.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { useCallback, useMemo, useRef, useState } from "react";
|
|
10
|
+
import { useCallback, useMemo, useRef, useState, type ReactNode } from "react";
|
|
11
11
|
import { toast } from "sonner";
|
|
12
12
|
import type { FsEntry } from "@/lib/fs-api";
|
|
13
|
+
import { openTerminalAt } from "@/lib/open-terminal-at";
|
|
13
14
|
import { useExplorerPinsStore } from "../explorer-pins-store";
|
|
14
15
|
import { useExplorerStore, type ExplorerSlice } from "../explorer-store";
|
|
15
16
|
import type { ExplorerNavigation } from "../use-explorer-navigation";
|
|
@@ -19,10 +20,14 @@ import {
|
|
|
19
20
|
type CollisionChoice, type CollisionRequest,
|
|
20
21
|
} from "./explorer-actions-clipboard";
|
|
21
22
|
import { createEntry, deleteEntries, renameEntry, validateEntryName } from "./explorer-actions-mutate";
|
|
23
|
+
import { useExplorerUploadActions } from "./use-explorer-upload-actions";
|
|
24
|
+
import type { DroppedEntry } from "../upload/collect-dropped-entries";
|
|
22
25
|
|
|
23
26
|
export interface ExplorerActions {
|
|
24
27
|
openEntry(entry: FsEntry): void;
|
|
25
28
|
openInNewWindow(entry: FsEntry): void;
|
|
29
|
+
/** Shell in the dock starting in the given directory (or the file's parent). */
|
|
30
|
+
openInTerminal(entry?: FsEntry): void;
|
|
26
31
|
cut(entries: FsEntry[]): void;
|
|
27
32
|
copy(entries: FsEntry[]): void;
|
|
28
33
|
paste(targetDir?: string): void;
|
|
@@ -39,6 +44,11 @@ export interface ExplorerActions {
|
|
|
39
44
|
showProperties(entry: FsEntry): void;
|
|
40
45
|
/** Move or copy arbitrary paths into a directory — also the drag-and-drop entry point. */
|
|
41
46
|
transferInto(paths: string[], dstDir: string, op: "copy" | "move"): Promise<void>;
|
|
47
|
+
/** Upload dropped/picked OS files into a directory — the upload counterpart of `transferInto`. */
|
|
48
|
+
uploadInto(entries: DroppedEntry[], dstDir: string): Promise<void>;
|
|
49
|
+
openUploadPicker(): void;
|
|
50
|
+
openUploadFolderPicker(): void;
|
|
51
|
+
supportsFolderUpload: boolean;
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
export interface ExplorerDialogState {
|
|
@@ -51,6 +61,8 @@ export interface ExplorerDialogState {
|
|
|
51
61
|
closeDelete(): void;
|
|
52
62
|
runPermanentDelete(): void;
|
|
53
63
|
closeProperties(): void;
|
|
64
|
+
/** Hidden upload `<input>`s — render once per window. */
|
|
65
|
+
uploadInputs: ReactNode;
|
|
54
66
|
}
|
|
55
67
|
|
|
56
68
|
export function useExplorerActions(
|
|
@@ -99,6 +111,7 @@ export function useExplorerActions(
|
|
|
99
111
|
);
|
|
100
112
|
|
|
101
113
|
const currentDir = () => sliceRef.current?.path ?? "";
|
|
114
|
+
const upload = useExplorerUploadActions(context, currentDir);
|
|
102
115
|
|
|
103
116
|
const actions = useMemo<ExplorerActions>(() => ({
|
|
104
117
|
openEntry: (entry) => {
|
|
@@ -108,6 +121,9 @@ export function useExplorerActions(
|
|
|
108
121
|
openInNewWindow: (entry) => {
|
|
109
122
|
openPathInNewWindow(entry.type === "directory" ? entry.path : (sliceRef.current?.path ?? entry.path));
|
|
110
123
|
},
|
|
124
|
+
openInTerminal: (entry) => {
|
|
125
|
+
openTerminalAt(entry?.type === "directory" ? entry.path : currentDir());
|
|
126
|
+
},
|
|
111
127
|
cut: (entries) => setClipboardPaths(entries.map((e) => e.path), "cut"),
|
|
112
128
|
copy: (entries) => setClipboardPaths(entries.map((e) => e.path), "copy"),
|
|
113
129
|
paste: (targetDir) => void pasteInto(targetDir ?? currentDir(), context),
|
|
@@ -120,6 +136,10 @@ export function useExplorerActions(
|
|
|
120
136
|
toast.success(`${verb} ${result.succeeded} item${result.succeeded === 1 ? "" : "s"}`);
|
|
121
137
|
}
|
|
122
138
|
},
|
|
139
|
+
uploadInto: upload.uploadInto,
|
|
140
|
+
openUploadPicker: upload.openUploadPicker,
|
|
141
|
+
openUploadFolderPicker: upload.openUploadFolderPicker,
|
|
142
|
+
supportsFolderUpload: upload.supportsFolderUpload,
|
|
123
143
|
|
|
124
144
|
startRename: (entry) => {
|
|
125
145
|
setInlineError(null);
|
|
@@ -180,7 +200,7 @@ export function useExplorerActions(
|
|
|
180
200
|
else pins.pin({ path, name });
|
|
181
201
|
},
|
|
182
202
|
showProperties: (entry) => setProperties(entry),
|
|
183
|
-
}), [windowId, patch, nav, context, platform]);
|
|
203
|
+
}), [windowId, patch, nav, context, platform, upload]);
|
|
184
204
|
|
|
185
205
|
const runPermanentDelete = useCallback(() => {
|
|
186
206
|
const target = pendingDelete;
|
|
@@ -200,6 +220,7 @@ export function useExplorerActions(
|
|
|
200
220
|
closeDelete: () => setPendingDelete(null),
|
|
201
221
|
runPermanentDelete,
|
|
202
222
|
closeProperties: () => setProperties(null),
|
|
223
|
+
uploadInputs: upload.uploadInputs,
|
|
203
224
|
},
|
|
204
225
|
};
|
|
205
226
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upload wiring for one explorer window: the hidden file/folder pickers and the action that
|
|
3
|
+
* turns a drop or a pick into `uploadEntries` calls. Split out of `use-explorer-actions.ts` to
|
|
4
|
+
* keep that file under the line cap — uploads are one more interruption-owning concern
|
|
5
|
+
* alongside collision/delete/properties, not a different architecture.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { useCallback, type ReactNode } from "react";
|
|
9
|
+
import type { DroppedEntry } from "../upload/collect-dropped-entries";
|
|
10
|
+
import { useUploadPicker } from "../upload/use-upload-picker";
|
|
11
|
+
import type { TransferContext } from "./explorer-actions-clipboard";
|
|
12
|
+
import { uploadEntries } from "./explorer-actions-upload";
|
|
13
|
+
|
|
14
|
+
export interface ExplorerUploadActions {
|
|
15
|
+
uploadInto(entries: DroppedEntry[], dstDir: string): Promise<void>;
|
|
16
|
+
openUploadPicker(): void;
|
|
17
|
+
openUploadFolderPicker(): void;
|
|
18
|
+
supportsFolderUpload: boolean;
|
|
19
|
+
/** Render once per window — the hidden `<input>` elements the pickers click. */
|
|
20
|
+
uploadInputs: ReactNode;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function useExplorerUploadActions(
|
|
24
|
+
context: TransferContext,
|
|
25
|
+
currentDir: () => string,
|
|
26
|
+
): ExplorerUploadActions {
|
|
27
|
+
const uploadInto = useCallback(
|
|
28
|
+
(entries: DroppedEntry[], dstDir: string) => uploadEntries(entries, dstDir, context.sep, context),
|
|
29
|
+
[context],
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const picker = useUploadPicker((entries) => void uploadInto(entries, currentDir()));
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
uploadInto,
|
|
36
|
+
openUploadPicker: picker.openFilePicker,
|
|
37
|
+
openUploadFolderPicker: picker.openFolderPicker,
|
|
38
|
+
supportsFolderUpload: picker.supportsFolderPicker,
|
|
39
|
+
uploadInputs: picker.inputs,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -10,12 +10,16 @@
|
|
|
10
10
|
|
|
11
11
|
import { useEffect, useMemo, useRef, useState, type ReactNode } from "react";
|
|
12
12
|
import type { CollisionChoice, CollisionRequest, TransferContext } from "../actions/explorer-actions-clipboard";
|
|
13
|
+
import { uploadEntries } from "../actions/explorer-actions-upload";
|
|
13
14
|
import type { ExplorerDialogState } from "../actions/use-explorer-actions";
|
|
14
15
|
import { ExplorerDialogs } from "../explorer-dialogs";
|
|
16
|
+
import type { DroppedEntry } from "../upload/collect-dropped-entries";
|
|
15
17
|
import { transferRunner, type DropRunner } from "./entry-drop-executor";
|
|
16
18
|
|
|
17
19
|
export interface DropTransfer {
|
|
18
20
|
run: DropRunner;
|
|
21
|
+
/** Upload dropped OS files into a directory, through the same collision prompt as `run`. */
|
|
22
|
+
uploadRun: (entries: DroppedEntry[], dstDir: string) => Promise<void>;
|
|
19
23
|
/** Render this somewhere inside the surface — it is empty until a prompt is raised. */
|
|
20
24
|
prompts: ReactNode;
|
|
21
25
|
}
|
|
@@ -60,6 +64,10 @@ export function useDropTransfer(sep: string, platform?: string): DropTransfer {
|
|
|
60
64
|
);
|
|
61
65
|
|
|
62
66
|
const run = useMemo<DropRunner>(() => transferRunner(context), [context]);
|
|
67
|
+
const uploadRun = useMemo(
|
|
68
|
+
() => (entries: DroppedEntry[], dstDir: string) => uploadEntries(entries, dstDir, sepRef.current, context),
|
|
69
|
+
[context],
|
|
70
|
+
);
|
|
63
71
|
|
|
64
72
|
const prompts = (
|
|
65
73
|
<ExplorerDialogs
|
|
@@ -72,11 +80,12 @@ export function useDropTransfer(sep: string, platform?: string): DropTransfer {
|
|
|
72
80
|
closeDelete: () => {},
|
|
73
81
|
runPermanentDelete: () => {},
|
|
74
82
|
closeProperties: () => {},
|
|
83
|
+
uploadInputs: null,
|
|
75
84
|
}}
|
|
76
85
|
platform={platform}
|
|
77
86
|
sep={sep}
|
|
78
87
|
/>
|
|
79
88
|
);
|
|
80
89
|
|
|
81
|
-
return { run, prompts };
|
|
90
|
+
return { run, uploadRun, prompts };
|
|
82
91
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import { useMemo, type DragEvent } from "react";
|
|
12
12
|
import type { FsEntry } from "@/lib/fs-api";
|
|
13
|
+
import type { DroppedEntry } from "../upload/collect-dropped-entries";
|
|
13
14
|
import type { DropRunner } from "./entry-drop-executor";
|
|
14
15
|
import type { EntryDragOrigin } from "./entry-drag-payload";
|
|
15
16
|
import { useEntryDragSource } from "./use-entry-drag-source";
|
|
@@ -36,6 +37,9 @@ export interface EntryRowDndOptions {
|
|
|
36
37
|
projectName?: string;
|
|
37
38
|
extraData?: Record<string, string>;
|
|
38
39
|
onDragStarted?(): void;
|
|
40
|
+
/** Also accept a native OS file drag onto this row when it is a directory. Omitted where
|
|
41
|
+
* the caller has no upload destination (e.g. a surface with no window action set). */
|
|
42
|
+
onFiles?: (entries: DroppedEntry[], targetDir: string) => void;
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
export interface EntryRowDnd {
|
|
@@ -45,7 +49,9 @@ export interface EntryRowDnd {
|
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
export function useEntryRowDnd(options: EntryRowDndOptions): EntryRowDnd {
|
|
48
|
-
const {
|
|
52
|
+
const {
|
|
53
|
+
entry, dragPaths, run, springLoad, origin = "explorer", projectName, extraData, onDragStarted, onFiles,
|
|
54
|
+
} = options;
|
|
49
55
|
|
|
50
56
|
const source = useEntryDragSource({ paths: dragPaths, origin, projectName, extraData, onDragStarted });
|
|
51
57
|
|
|
@@ -55,6 +61,7 @@ export function useEntryRowDnd(options: EntryRowDndOptions): EntryRowDnd {
|
|
|
55
61
|
targetDir: entry.type === "directory" ? entry.path : null,
|
|
56
62
|
run,
|
|
57
63
|
springLoad: entry.type === "directory" ? springLoad : undefined,
|
|
64
|
+
onFiles,
|
|
58
65
|
});
|
|
59
66
|
|
|
60
67
|
const props = useMemo<EntryRowDndProps>(
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drop target for a native OS `Files` drag — the upload counterpart to `useEntryDropTarget`
|
|
3
|
+
* (PPM's own entry drags). The two never overlap: an entry drag carries `ENTRY_DRAG_MIME` but
|
|
4
|
+
* never `Files` (see `use-entry-drag-source.ts`), so a caller wires both hooks' handlers onto
|
|
5
|
+
* the same element — see `usePathDropTarget` — and whichever drag kind is actually happening
|
|
6
|
+
* is the only one that ever calls `preventDefault`.
|
|
7
|
+
*
|
|
8
|
+
* `isExternalFileDrag` is the project tree's own check (`use-tree-row-dnd.ts`), reused rather
|
|
9
|
+
* than redeclared: it excludes the tree's legacy single-path MIME, which an entry drag never
|
|
10
|
+
* carries either, so the same test is exactly as correct here.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { useCallback, useRef, useState, type DragEvent } from "react";
|
|
14
|
+
import { isExternalFileDrag } from "@/components/explorer/use-tree-row-dnd";
|
|
15
|
+
import { collectDroppedEntries, type DroppedEntry } from "../upload/collect-dropped-entries";
|
|
16
|
+
import type { EntryDropTargetResult } from "./use-entry-drop-target";
|
|
17
|
+
|
|
18
|
+
export interface ExternalFileDropOptions {
|
|
19
|
+
/** Directory a drop uploads into; null disables the target. */
|
|
20
|
+
targetDir: string | null;
|
|
21
|
+
onFiles(entries: DroppedEntry[], targetDir: string): void;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function useExternalFileDrop(options: ExternalFileDropOptions): EntryDropTargetResult {
|
|
26
|
+
const { targetDir, onFiles, disabled } = options;
|
|
27
|
+
const [isOver, setIsOver] = useState(false);
|
|
28
|
+
// Nested children fire their own enter/leave pairs; only a balanced count means "left".
|
|
29
|
+
const depth = useRef(0);
|
|
30
|
+
|
|
31
|
+
const reset = useCallback(() => {
|
|
32
|
+
depth.current = 0;
|
|
33
|
+
setIsOver(false);
|
|
34
|
+
}, []);
|
|
35
|
+
|
|
36
|
+
const applies = useCallback(
|
|
37
|
+
(event: DragEvent) => !disabled && targetDir != null && isExternalFileDrag(event),
|
|
38
|
+
[disabled, targetDir],
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const onDragEnter = useCallback(
|
|
42
|
+
(event: DragEvent) => {
|
|
43
|
+
if (!applies(event)) return;
|
|
44
|
+
event.preventDefault();
|
|
45
|
+
event.stopPropagation();
|
|
46
|
+
depth.current++;
|
|
47
|
+
setIsOver(true);
|
|
48
|
+
},
|
|
49
|
+
[applies],
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const onDragOver = useCallback(
|
|
53
|
+
(event: DragEvent) => {
|
|
54
|
+
if (!applies(event)) return;
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
event.stopPropagation();
|
|
57
|
+
event.dataTransfer.dropEffect = "copy";
|
|
58
|
+
},
|
|
59
|
+
[applies],
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const onDragLeave = useCallback((event: DragEvent) => {
|
|
63
|
+
if (depth.current === 0) return;
|
|
64
|
+
event.stopPropagation();
|
|
65
|
+
depth.current--;
|
|
66
|
+
if (depth.current === 0) setIsOver(false);
|
|
67
|
+
}, []);
|
|
68
|
+
|
|
69
|
+
const onDrop = useCallback(
|
|
70
|
+
(event: DragEvent) => {
|
|
71
|
+
if (!applies(event) || targetDir == null) return;
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
event.stopPropagation();
|
|
74
|
+
const dataTransfer = event.dataTransfer;
|
|
75
|
+
reset();
|
|
76
|
+
void collectDroppedEntries(dataTransfer).then((entries) => {
|
|
77
|
+
if (entries.length > 0) onFiles(entries, targetDir);
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
[applies, targetDir, onFiles, reset],
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
return { isOver, handlers: { onDragEnter, onDragOver, onDragLeave, onDrop } };
|
|
84
|
+
}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Drop target for a surface that already knows its destination directory and has no drag
|
|
3
3
|
* source of its own: a view background, a sidebar place, a breadcrumb crumb, the tree root.
|
|
4
|
+
*
|
|
5
|
+
* When `onFiles` is supplied this also accepts a native OS `Files` drag on the same element —
|
|
6
|
+
* the drag-to-upload entry point. The two hooks underneath are mutually exclusive by MIME
|
|
7
|
+
* type (see `use-external-file-drop.ts`), so merging their handlers is safe: whichever drag
|
|
8
|
+
* kind is actually happening is the only one that ever calls `preventDefault`.
|
|
4
9
|
*/
|
|
5
10
|
|
|
6
|
-
import { useCallback } from "react";
|
|
11
|
+
import { useCallback, type DragEvent } from "react";
|
|
7
12
|
import { executeEntryDrop, type DropRunner } from "./entry-drop-executor";
|
|
8
13
|
import type { DropOperation, EntryDragPayload } from "./entry-drag-payload";
|
|
9
14
|
import { useEntryDropTarget, type EntryDropTargetResult } from "./use-entry-drop-target";
|
|
15
|
+
import { useExternalFileDrop } from "./use-external-file-drop";
|
|
16
|
+
import type { DroppedEntry } from "../upload/collect-dropped-entries";
|
|
10
17
|
|
|
11
18
|
export interface PathDropTargetOptions {
|
|
12
19
|
targetDir: string | null;
|
|
@@ -14,10 +21,15 @@ export interface PathDropTargetOptions {
|
|
|
14
21
|
/** Opens this destination after a rest — the project tree and Column view use it. */
|
|
15
22
|
springLoad?: () => void;
|
|
16
23
|
disabled?: boolean;
|
|
24
|
+
/** Also accept a native OS file drag on this same target. Omitted where the caller has no
|
|
25
|
+
* upload destination context to hand the dropped files to. */
|
|
26
|
+
onFiles?: (entries: DroppedEntry[], targetDir: string) => void;
|
|
17
27
|
}
|
|
18
28
|
|
|
29
|
+
function noopFiles(): void {}
|
|
30
|
+
|
|
19
31
|
export function usePathDropTarget(options: PathDropTargetOptions): EntryDropTargetResult {
|
|
20
|
-
const { targetDir, run, springLoad, disabled } = options;
|
|
32
|
+
const { targetDir, run, springLoad, disabled, onFiles } = options;
|
|
21
33
|
|
|
22
34
|
const onDropEntries = useCallback(
|
|
23
35
|
(payload: EntryDragPayload, op: DropOperation, dstDir: string) => {
|
|
@@ -26,5 +38,36 @@ export function usePathDropTarget(options: PathDropTargetOptions): EntryDropTarg
|
|
|
26
38
|
[run],
|
|
27
39
|
);
|
|
28
40
|
|
|
29
|
-
|
|
41
|
+
const entryDrop = useEntryDropTarget({ targetDir, onDropEntries, springLoad, disabled });
|
|
42
|
+
// Always called (Rules of Hooks) — `disabled` is what actually turns it off when the
|
|
43
|
+
// caller has no upload destination for this target.
|
|
44
|
+
const fileDrop = useExternalFileDrop({
|
|
45
|
+
targetDir,
|
|
46
|
+
onFiles: onFiles ?? noopFiles,
|
|
47
|
+
disabled: disabled || !onFiles,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (!onFiles) return entryDrop;
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
isOver: entryDrop.isOver || fileDrop.isOver,
|
|
54
|
+
handlers: {
|
|
55
|
+
onDragEnter: (event: DragEvent) => {
|
|
56
|
+
entryDrop.handlers.onDragEnter(event);
|
|
57
|
+
fileDrop.handlers.onDragEnter(event);
|
|
58
|
+
},
|
|
59
|
+
onDragOver: (event: DragEvent) => {
|
|
60
|
+
entryDrop.handlers.onDragOver(event);
|
|
61
|
+
fileDrop.handlers.onDragOver(event);
|
|
62
|
+
},
|
|
63
|
+
onDragLeave: (event: DragEvent) => {
|
|
64
|
+
entryDrop.handlers.onDragLeave(event);
|
|
65
|
+
fileDrop.handlers.onDragLeave(event);
|
|
66
|
+
},
|
|
67
|
+
onDrop: (event: DragEvent) => {
|
|
68
|
+
entryDrop.handlers.onDrop(event);
|
|
69
|
+
fileDrop.handlers.onDrop(event);
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
};
|
|
30
73
|
}
|
|
@@ -99,7 +99,7 @@ export function ExplorerBody({ windowId, initialPath, variant = "window" }: Expl
|
|
|
99
99
|
<MobilePlacesStrip host={host} currentPath={slice.path} onNavigate={nav.go} vocab={skin.vocab} />
|
|
100
100
|
</>
|
|
101
101
|
) : (
|
|
102
|
-
<ExplorerToolbar windowId={windowId} slice={slice} nav={nav} />
|
|
102
|
+
<ExplorerToolbar windowId={windowId} slice={slice} nav={nav} actions={actions} />
|
|
103
103
|
)}
|
|
104
104
|
|
|
105
105
|
{slice.error && (
|
|
@@ -54,6 +54,13 @@ export function ExplorerContextMenu({
|
|
|
54
54
|
<ContextMenuSeparator />
|
|
55
55
|
<ContextMenuItem disabled={!hasClipboard} onClick={() => actions.paste()}>Paste</ContextMenuItem>
|
|
56
56
|
<ContextMenuSeparator />
|
|
57
|
+
<ContextMenuItem onClick={() => actions.openUploadPicker()}>Upload Files…</ContextMenuItem>
|
|
58
|
+
{actions.supportsFolderUpload && (
|
|
59
|
+
<ContextMenuItem onClick={() => actions.openUploadFolderPicker()}>Upload Folder…</ContextMenuItem>
|
|
60
|
+
)}
|
|
61
|
+
<ContextMenuSeparator />
|
|
62
|
+
<ContextMenuItem onClick={() => actions.openInTerminal()}>Open in Terminal</ContextMenuItem>
|
|
63
|
+
<ContextMenuSeparator />
|
|
57
64
|
<ContextMenuSub>
|
|
58
65
|
<ContextMenuSubTrigger>Sort by</ContextMenuSubTrigger>
|
|
59
66
|
<ContextMenuSubContent>
|
|
@@ -92,6 +99,9 @@ export function ExplorerContextMenu({
|
|
|
92
99
|
Open in New Window
|
|
93
100
|
</ContextMenuItem>
|
|
94
101
|
)}
|
|
102
|
+
{onlyDirs && single && (
|
|
103
|
+
<ContextMenuItem onClick={() => actions.openInTerminal(single)}>Open in Terminal</ContextMenuItem>
|
|
104
|
+
)}
|
|
95
105
|
<ContextMenuSeparator />
|
|
96
106
|
|
|
97
107
|
<ContextMenuItem onClick={() => actions.cut(targets)}>Cut{suffix}</ContextMenuItem>
|
|
@@ -14,7 +14,7 @@ import { cn } from "@/lib/utils";
|
|
|
14
14
|
import { DROP_TARGET_CLASS } from "./dnd/drop-target-style";
|
|
15
15
|
import type { DropRunner } from "./dnd/entry-drop-executor";
|
|
16
16
|
import { usePathDropTarget } from "./dnd/use-path-drop-target";
|
|
17
|
-
import { useDropTransfer } from "./dnd/use-drop-transfer";
|
|
17
|
+
import { useDropTransfer, type DropTransfer } from "./dnd/use-drop-transfer";
|
|
18
18
|
import { useExplorerPinsStore } from "./explorer-pins-store";
|
|
19
19
|
import { FileTypeIcon } from "./icons/file-type-icon";
|
|
20
20
|
import type { SkinVocab } from "./skins/skin-types";
|
|
@@ -43,13 +43,14 @@ interface PlaceProps {
|
|
|
43
43
|
onUnpin?(): void;
|
|
44
44
|
/** Every place is a directory, so a drop always has somewhere valid to land. */
|
|
45
45
|
run: DropRunner;
|
|
46
|
+
uploadRun: DropTransfer["uploadRun"];
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
function Place({ label, path, active, icon: Icon, onNavigate, onUnpin, run }: PlaceProps) {
|
|
49
|
+
function Place({ label, path, active, icon: Icon, onNavigate, onUnpin, run, uploadRun }: PlaceProps) {
|
|
49
50
|
// Gated on real pointer coarseness, not a `md:` breakpoint — an iPad is ≥768px but has no
|
|
50
51
|
// mouse, so a breakpoint-only rule was silently dropping the 44px minimum for it.
|
|
51
52
|
const coarse = usePrefersCoarsePointer();
|
|
52
|
-
const drop = usePathDropTarget({ targetDir: path, run });
|
|
53
|
+
const drop = usePathDropTarget({ targetDir: path, run, onFiles: uploadRun });
|
|
53
54
|
return (
|
|
54
55
|
<div className="group/place relative flex items-center">
|
|
55
56
|
<button
|
|
@@ -112,7 +113,7 @@ export function ExplorerSidebar({ host, currentPath, onNavigate, vocab = DEFAULT
|
|
|
112
113
|
const isActive = (path: string) => path === currentPath;
|
|
113
114
|
// One drop-transfer context for the whole sidebar — every place lands through the same
|
|
114
115
|
// collision prompt rather than each row owning its own dialog state.
|
|
115
|
-
const { run, prompts } = useDropTransfer(host?.sep ?? "/", host?.platform);
|
|
116
|
+
const { run, uploadRun, prompts } = useDropTransfer(host?.sep ?? "/", host?.platform);
|
|
116
117
|
|
|
117
118
|
return (
|
|
118
119
|
<aside
|
|
@@ -132,6 +133,7 @@ export function ExplorerSidebar({ host, currentPath, onNavigate, vocab = DEFAULT
|
|
|
132
133
|
onNavigate={onNavigate}
|
|
133
134
|
onUnpin={() => unpin(pin.path)}
|
|
134
135
|
run={run}
|
|
136
|
+
uploadRun={uploadRun}
|
|
135
137
|
/>
|
|
136
138
|
))}
|
|
137
139
|
</Section>
|
|
@@ -148,6 +150,7 @@ export function ExplorerSidebar({ host, currentPath, onNavigate, vocab = DEFAULT
|
|
|
148
150
|
active={isActive(entry.path)}
|
|
149
151
|
onNavigate={onNavigate}
|
|
150
152
|
run={run}
|
|
153
|
+
uploadRun={uploadRun}
|
|
151
154
|
/>
|
|
152
155
|
))}
|
|
153
156
|
</Section>
|
|
@@ -155,7 +158,7 @@ export function ExplorerSidebar({ host, currentPath, onNavigate, vocab = DEFAULT
|
|
|
155
158
|
|
|
156
159
|
{host && (
|
|
157
160
|
<Section title={vocab.known}>
|
|
158
|
-
<Place label={vocab.home} path={host.homedir} icon={FolderPlaceIcon} active={isActive(host.homedir)} onNavigate={onNavigate} run={run} />
|
|
161
|
+
<Place label={vocab.home} path={host.homedir} icon={FolderPlaceIcon} active={isActive(host.homedir)} onNavigate={onNavigate} run={run} uploadRun={uploadRun} />
|
|
159
162
|
{host.knownFolders.map((folder) => (
|
|
160
163
|
<Place
|
|
161
164
|
key={folder.path}
|
|
@@ -165,6 +168,7 @@ export function ExplorerSidebar({ host, currentPath, onNavigate, vocab = DEFAULT
|
|
|
165
168
|
active={isActive(folder.path)}
|
|
166
169
|
onNavigate={onNavigate}
|
|
167
170
|
run={run}
|
|
171
|
+
uploadRun={uploadRun}
|
|
168
172
|
/>
|
|
169
173
|
))}
|
|
170
174
|
</Section>
|
|
@@ -181,6 +185,7 @@ export function ExplorerSidebar({ host, currentPath, onNavigate, vocab = DEFAULT
|
|
|
181
185
|
active={isActive(drive.path)}
|
|
182
186
|
onNavigate={onNavigate}
|
|
183
187
|
run={run}
|
|
188
|
+
uploadRun={uploadRun}
|
|
184
189
|
/>
|
|
185
190
|
))}
|
|
186
191
|
</Section>
|
|
@@ -9,9 +9,14 @@
|
|
|
9
9
|
|
|
10
10
|
import { useEffect, useState } from "react";
|
|
11
11
|
import {
|
|
12
|
-
ArrowLeft, ArrowRight, ArrowUp, Columns3, Eye, EyeOff, LayoutGrid, List, PencilLine, RefreshCw, Search,
|
|
12
|
+
ArrowLeft, ArrowRight, ArrowUp, Columns3, Eye, EyeOff, LayoutGrid, List, PencilLine, RefreshCw, Search,
|
|
13
|
+
Upload, X,
|
|
13
14
|
} from "lucide-react";
|
|
15
|
+
import {
|
|
16
|
+
DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger,
|
|
17
|
+
} from "@/components/ui/dropdown-menu";
|
|
14
18
|
import { cn } from "@/lib/utils";
|
|
19
|
+
import type { ExplorerActions } from "./actions/use-explorer-actions";
|
|
15
20
|
import { ExplorerBreadcrumb } from "./explorer-breadcrumb";
|
|
16
21
|
import { ExplorerSortMenu } from "./explorer-sort-menu";
|
|
17
22
|
import { useExplorerStore, type ExplorerSlice, type ViewMode } from "./explorer-store";
|
|
@@ -27,9 +32,10 @@ export interface ExplorerToolbarProps {
|
|
|
27
32
|
windowId: string;
|
|
28
33
|
slice: ExplorerSlice;
|
|
29
34
|
nav: ExplorerNavigation;
|
|
35
|
+
actions: ExplorerActions;
|
|
30
36
|
}
|
|
31
37
|
|
|
32
|
-
export function ExplorerToolbar({ windowId, slice, nav }: ExplorerToolbarProps) {
|
|
38
|
+
export function ExplorerToolbar({ windowId, slice, nav, actions }: ExplorerToolbarProps) {
|
|
33
39
|
const patch = useExplorerStore((s) => s.patch);
|
|
34
40
|
const showHidden = useExplorerStore((s) => s.showHidden);
|
|
35
41
|
const viewMode = useExplorerStore((s) => s.viewMode);
|
|
@@ -124,6 +130,30 @@ export function ExplorerToolbar({ windowId, slice, nav }: ExplorerToolbarProps)
|
|
|
124
130
|
|
|
125
131
|
<ExplorerSortMenu coarse={coarse} />
|
|
126
132
|
|
|
133
|
+
{actions.supportsFolderUpload ? (
|
|
134
|
+
<DropdownMenu>
|
|
135
|
+
<DropdownMenuTrigger asChild>
|
|
136
|
+
<button type="button" aria-label="Upload" title="Upload" className={buttonClass(coarse)}>
|
|
137
|
+
<Upload className="size-4" />
|
|
138
|
+
</button>
|
|
139
|
+
</DropdownMenuTrigger>
|
|
140
|
+
<DropdownMenuContent align="end">
|
|
141
|
+
<DropdownMenuItem onClick={() => actions.openUploadPicker()}>Upload Files…</DropdownMenuItem>
|
|
142
|
+
<DropdownMenuItem onClick={() => actions.openUploadFolderPicker()}>Upload Folder…</DropdownMenuItem>
|
|
143
|
+
</DropdownMenuContent>
|
|
144
|
+
</DropdownMenu>
|
|
145
|
+
) : (
|
|
146
|
+
<button
|
|
147
|
+
type="button"
|
|
148
|
+
aria-label="Upload"
|
|
149
|
+
title="Upload"
|
|
150
|
+
onClick={() => actions.openUploadPicker()}
|
|
151
|
+
className={buttonClass(coarse)}
|
|
152
|
+
>
|
|
153
|
+
<Upload className="size-4" />
|
|
154
|
+
</button>
|
|
155
|
+
)}
|
|
156
|
+
|
|
127
157
|
<button
|
|
128
158
|
type="button"
|
|
129
159
|
aria-label={showHidden ? "Hide hidden files" : "Show hidden files"}
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
import { useState } from "react";
|
|
10
10
|
import {
|
|
11
|
-
ArrowLeft, Check, ClipboardPaste, Copy, Download, FilePlus, FolderPlus, Info, MoreHorizontal, Plus, Scissors,
|
|
11
|
+
ArrowLeft, Check, ClipboardPaste, Copy, Download, FilePlus, FolderPlus, Info, MoreHorizontal, Plus, Scissors,
|
|
12
|
+
Trash2, Upload, X,
|
|
12
13
|
} from "lucide-react";
|
|
13
14
|
import type { FsEntry } from "@/lib/fs-api";
|
|
14
15
|
import { BottomSheet, BottomSheetItem } from "@/components/ui/mobile-bottom-sheet";
|
|
@@ -94,6 +95,9 @@ export function MobileBottomToolbar({ slice, nav, actions, entries, hasClipboard
|
|
|
94
95
|
<BottomSheetItem onClick={() => actions.startCreate("new-folder")}>
|
|
95
96
|
<FolderPlus className="size-4" /> New Folder
|
|
96
97
|
</BottomSheetItem>
|
|
98
|
+
<BottomSheetItem onClick={() => { setNewOpen(false); actions.openUploadPicker(); }}>
|
|
99
|
+
<Upload className="size-4" /> Upload Files…
|
|
100
|
+
</BottomSheetItem>
|
|
97
101
|
</BottomSheet>
|
|
98
102
|
|
|
99
103
|
<MobileMoreSheet open={moreOpen} onClose={() => setMoreOpen(false)} slice={slice} actions={actions} entries={entries} />
|