@hienlh/ppm 0.18.10 → 0.18.12
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 +18 -0
- package/README.md +81 -23
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/dist/web/assets/adaptive-context-menu-DGCKKeTy.js +1 -0
- package/dist/web/assets/ai-resource-editor-BOHHTTe7.js +1 -0
- package/dist/web/assets/ai-settings-section-BigC_nZR.js +1 -0
- package/dist/web/assets/{angular-html-Ctz0zN01.js → angular-html-BYPaydvh.js} +1 -1
- package/dist/web/assets/{angular-ts-QXHpgB1C.js → angular-ts-Bb4AMKlk.js} +1 -1
- package/dist/web/assets/api-client-DTZEgjBQ.js +1 -0
- package/dist/web/assets/{api-settings-kQHV6pYZ.js → api-settings-Bd3M4YpI.js} +1 -1
- package/dist/web/assets/api-settings-kd1j4iR8.js +1 -0
- package/dist/web/assets/{api-themes-CrK0tkW_.js → api-themes-Cpx419SL.js} +1 -1
- package/dist/web/assets/{apl-b9KVk-O4.js → apl-DB2VjFCS.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-8dCMT9r7.js +1 -0
- package/dist/web/assets/{astro-BlFEeGYr.js → astro-BeoJdVpk.js} +1 -1
- package/dist/web/assets/{audio-preview-CZLmhf__.js → audio-preview-BgFuTn-0.js} +1 -1
- package/dist/web/assets/{blade-CGkj2MUI.js → blade-Cf2q1sPf.js} +1 -1
- package/dist/web/assets/{bsl-CVsbb6ap.js → bsl-W1kOaNpu.js} +1 -1
- package/dist/web/assets/{button-BA_fJOtX.js → button-5zTrkEoN.js} +1 -1
- package/dist/web/assets/{cairo-BbIHl2iE.js → cairo-BoAZFcje.js} +1 -1
- package/dist/web/assets/chat-tab-E3bf_V8X.js +15 -0
- package/dist/web/assets/chevron-down-Dp0rpHb8.js +1 -0
- package/dist/web/assets/clipboard-7fw0Shic.js +1 -0
- package/dist/web/assets/{cobol-BWSGjmWb.js → cobol-B0Nm7RXj.js} +1 -1
- package/dist/web/assets/code-editor-BUlM2gXk.js +10 -0
- package/dist/web/assets/{coffee-CWGNOxds.js → coffee-BakMn3on.js} +1 -1
- package/dist/web/assets/{conflict-editor-fRTU3f1o.js → conflict-editor-BUs5k9q_.js} +4 -4
- package/dist/web/assets/context-menu-Bq92km4s.js +1 -0
- package/dist/web/assets/{cpp-DHGV24J2.js → cpp-BRAJQHK2.js} +1 -1
- package/dist/web/assets/{crystal-Vlwf2UMP.js → crystal-kqqO3zkK.js} +1 -1
- package/dist/web/assets/{csv-preview-D1d0cxOJ.js → csv-preview-ByoDgLAZ.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-D9il5DZS.js → data-grid-overlay-editor-Brkf9z41.js} +1 -1
- package/dist/web/assets/database-viewer-Btc3h8Yu.js +1 -0
- package/dist/web/assets/dialog-DwtGlowE.js +1 -0
- package/dist/web/assets/diff-viewer-CZaDnR4w.js +4 -0
- package/dist/web/assets/docx-preview-DAD_vg59.js +12 -0
- package/dist/web/assets/{edge-Bhqk64zS.js → edge-Cq1ZKZuE.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-gq6ALf2B.js → edit-diff-preview-B_VE7ppQ.js} +1 -1
- package/dist/web/assets/{elixir-D466WCFm.js → elixir-BM_JoJRk.js} +1 -1
- package/dist/web/assets/{elm-Bfs2qNPR.js → elm-Dw7oO08Y.js} +1 -1
- package/dist/web/assets/{erb-WI7jUaB6.js → erb-CfKOGAfk.js} +1 -1
- package/dist/web/assets/{erlang-BCBe8nCc.js → erlang-DlDmGVeE.js} +1 -1
- package/dist/web/assets/{esm-CZs9WVDO.js → esm-DGAP0GFh.js} +1 -1
- package/dist/web/assets/explorer-body-9aBmyVpZ.js +2 -0
- package/dist/web/assets/explorer-window-content-DRtqoSPA.js +1 -0
- package/dist/web/assets/extension-store-Cpfh2vMm.js +1 -0
- package/dist/web/assets/{extension-webview-BH_mWYMe.js → extension-webview-B2OnjuCu.js} +2 -2
- package/dist/web/assets/external-link-B8BynhvY.js +1 -0
- package/dist/web/assets/file-store-aOERIEo-.js +1 -0
- package/dist/web/assets/folder-symlink-B8XrtvQK.js +1 -0
- package/dist/web/assets/{fortran-fixed-form-CXLIv8Ox.js → fortran-fixed-form-XnAhQWxS.js} +1 -1
- package/dist/web/assets/{fsharp-CZsYmiw9.js → fsharp-CdNvy0PG.js} +1 -1
- package/dist/web/assets/{gdresource-BGRvoWfC.js → gdresource-DxuG5i8i.js} +1 -1
- package/dist/web/assets/{git-commit-DH6mY3Km.js → git-commit-3lMonsur.js} +1 -1
- package/dist/web/assets/git-log-panel-Co0PBPHC.js +1 -0
- package/dist/web/assets/{git-rebase-C5Gql6Ma.js → git-rebase-N8Z9kIMf.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-2e_8dfbs.js +1 -0
- package/dist/web/assets/{glide-data-grid-n4ox_uev.js → glide-data-grid-C4_zIneN.js} +8 -8
- package/dist/web/assets/{glimmer-js-1-6JMJlj.js → glimmer-js-Dp9OXiib.js} +1 -1
- package/dist/web/assets/{glimmer-ts-C_Njj0nK.js → glimmer-ts-CDVKBcDj.js} +1 -1
- package/dist/web/assets/{glsl-DbkxE1TN.js → glsl-DPJxI4us.js} +1 -1
- package/dist/web/assets/{graphql-BK75fiXl.js → graphql-BrFhaQQl.js} +1 -1
- package/dist/web/assets/group-chat-tab-rOd8J8GC.js +1 -0
- package/dist/web/assets/{hack-DG151vit.js → hack-BzXbDMlA.js} +1 -1
- package/dist/web/assets/{haml-DKeIPQWM.js → haml-CPpkX0s5.js} +1 -1
- package/dist/web/assets/{handlebars-398uCI13.js → handlebars-BqrApy52.js} +1 -1
- package/dist/web/assets/{html-NLWdst5q.js → html-DmjUl-OA.js} +1 -1
- package/dist/web/assets/{html-derivative-CJf_Le2z.js → html-derivative-Cnd6XFR5.js} +1 -1
- package/dist/web/assets/{http-G1K2FozA.js → http-DMLWYun2.js} +1 -1
- package/dist/web/assets/{hurl-WDC6sSBz.js → hurl-CKkCVxbj.js} +1 -1
- package/dist/web/assets/{hxml-Dc3jBXuf.js → hxml-CAx19TtQ.js} +1 -1
- package/dist/web/assets/image-preview-DHUoylQ1.js +1 -0
- package/dist/web/assets/index-BImUaigO.js +52 -0
- package/dist/web/assets/index-CSfi6DSU.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-BZi1Gha1.js +1 -0
- package/dist/web/assets/input-DcEk7mA3.js +1 -0
- package/dist/web/assets/{jinja-CWsQj2y0.js → jinja-BmB9YN9l.js} +1 -1
- package/dist/web/assets/{jison-CciJg2NW.js → jison-BaVsKKpw.js} +1 -1
- package/dist/web/assets/{julia-IOQNJAB7.js → julia-BgVBLveX.js} +1 -1
- package/dist/web/assets/{just-BGdHchwS.js → just-C2ENIbl9.js} +1 -1
- package/dist/web/assets/keybindings-store-BGIyqXHI.js +1 -0
- package/dist/web/assets/keybindings-store-CzV2sPls.js +1 -0
- package/dist/web/assets/{latex-D6TOl-L2.js → latex-BiDIWxKL.js} +1 -1
- package/dist/web/assets/{liquid-CVSvu_Wn.js → liquid-NxpapreE.js} +1 -1
- package/dist/web/assets/loader-circle-gSPVxfvH.js +1 -0
- package/dist/web/assets/lock-Did-87UV.js +1 -0
- package/dist/web/assets/{lua-CcKiU6HW.js → lua-DVepQvwH.js} +1 -1
- package/dist/web/assets/markdown-renderer-CcbR33VG.js +1 -0
- package/dist/web/assets/{markdown-renderer-B317vEys.js → markdown-renderer-DlcDhgrF.js} +3 -3
- package/dist/web/assets/{marko--UOicMGo.js → marko-CJ2606Xl.js} +1 -1
- package/dist/web/assets/{mdc-D690aU2C.js → mdc-D2bjqclE.js} +1 -1
- package/dist/web/assets/{media-url-CylYQld1.js → media-url-H17XJF-I.js} +1 -1
- package/dist/web/assets/mobile-bottom-sheet-g-r2hCFa.js +1 -0
- package/dist/web/assets/mobile-explorer-sheet-SIwQXlwA.js +1 -0
- package/dist/web/assets/monitor-Dv8vn_6O.js +1 -0
- package/dist/web/assets/{nextflow-DR8PhpF8.js → nextflow-BtJwUbfF.js} +1 -1
- package/dist/web/assets/{nginx-Qb9pUk1g.js → nginx-j4gyIhHE.js} +1 -1
- package/dist/web/assets/{nim-DLa8R3NS.js → nim-ClH_gjP5.js} +1 -1
- package/dist/web/assets/notification-store-DV5QtUTg.js +1 -0
- package/dist/web/assets/{number-overlay-editor-D9SkFg1Y.js → number-overlay-editor-C1EqJnWq.js} +1 -1
- package/dist/web/assets/{overview-panel-BxDohIEa.js → overview-panel-vTeeJYVZ.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-o5htEcin.js +1 -0
- package/dist/web/assets/panel-store-BSnkjgHt.js +1 -0
- package/dist/web/assets/pdf-preview-CqFGRY0Z.js +1 -0
- package/dist/web/assets/pencil-BlIIg6RH.js +1 -0
- package/dist/web/assets/{perl-AMNGIneF.js → perl-C9H7X7CT.js} +1 -1
- package/dist/web/assets/{php-CDsOOxXn.js → php-Bx2U-cQ_.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-BXAIFSAD.js +1 -0
- package/dist/web/assets/play-4MZi1Axp.js +1 -0
- package/dist/web/assets/portal-container-context-Cm5HipFr.js +1 -0
- package/dist/web/assets/{postgres-viewer-BWZLW7kI.js → postgres-viewer-DHwcQucn.js} +3 -3
- package/dist/web/assets/process-table-BGRJNlpn.js +1 -0
- package/dist/web/assets/{project-store-B8BkHXy5.js → project-store--nvQiy75.js} +1 -1
- package/dist/web/assets/{pug-C2kdkhQ6.js → pug-Cw74sKsE.js} +1 -1
- package/dist/web/assets/{qml-DRDkUp75.js → qml-BXD94Eqz.js} +1 -1
- package/dist/web/assets/radar-KQ55EAFF-Dbt2Aebl.js +1 -0
- package/dist/web/assets/{razor-wY_6wUeC.js → razor-DZ0-Ge0S.js} +1 -1
- package/dist/web/assets/refresh-cw-B06yaBrW.js +1 -0
- package/dist/web/assets/rotate-ccw-COXu_9oj.js +1 -0
- package/dist/web/assets/{rst-BRpofyNs.js → rst-Dtdh0QUj.js} +1 -1
- package/dist/web/assets/{ruby-ieATBhWm.js → ruby-BC51BW2Q.js} +1 -1
- package/dist/web/assets/{run-in-terminal-CyS5Itj-.js → run-in-terminal-Sd3KyjN4.js} +1 -1
- package/dist/web/assets/{sas-CoOOEbOO.js → sas-BN8i4qOU.js} +1 -1
- package/dist/web/assets/scroll-area-0gljZ6lF.js +1 -0
- package/dist/web/assets/{scss-_nWV0bsb.js → scss-H-QtA7Rz.js} +1 -1
- package/dist/web/assets/send-BlyNJAzy.js +1 -0
- package/dist/web/assets/{send-to-chat-BcO39BDR.js → send-to-chat-u6m8l-rH.js} +1 -1
- package/dist/web/assets/{settings-store-C20lqh0G.js → settings-store-CHY6Kzin.js} +2 -2
- package/dist/web/assets/settings-tab-Dic6TKkU.js +1 -0
- package/dist/web/assets/settings-tab-IY6K1MiZ.js +3 -0
- package/dist/web/assets/{shaderlab-XkqfIfO8.js → shaderlab-CalNsj_x.js} +1 -1
- package/dist/web/assets/shallow-DYo6goJ4.js +1 -0
- package/dist/web/assets/{shellsession-BKBIqTlM.js → shellsession-BFrcoR8x.js} +1 -1
- package/dist/web/assets/{soy-oVDnPzzh.js → soy-CNbku7vP.js} +1 -1
- package/dist/web/assets/{sparql-N2VclEsF.js → sparql-BN_orcVp.js} +1 -1
- package/dist/web/assets/{sql-query-editor-BwPjEaP9.js → sql-query-editor-C6pC3I8l.js} +1 -1
- package/dist/web/assets/sqlite-viewer-DTr5PzUb.js +1 -0
- package/dist/web/assets/{stata-BuuClVDg.js → stata-C6a5Ijzq.js} +1 -1
- package/dist/web/assets/{surrealql-DE5_63MS.js → surrealql-ClplI_HY.js} +1 -1
- package/dist/web/assets/{svelte--YWjlOrK.js → svelte-DNm-UNXB.js} +1 -1
- package/dist/web/assets/switch-DKvKya9y.js +1 -0
- package/dist/web/assets/system-monitor-body-iwGiCns9.js +2 -0
- package/dist/web/assets/system-monitor-tab-DdXQhEel.js +1 -0
- package/dist/web/assets/system-monitor-window-content-BUqRsPK2.js +1 -0
- package/dist/web/assets/tab-host-window-content-BnqGPu8a.js +1 -0
- package/dist/web/assets/{tab-store-DAsvpx4t.js → tab-store-CJuJRapl.js} +1 -1
- package/dist/web/assets/team-member-sheet-LkAFSCvb.js +2 -0
- package/dist/web/assets/team-member-window-content-T4Q5JI-G.js +1 -0
- package/dist/web/assets/{templ-MlpvJx4a.js → templ-CSdqVobu.js} +1 -1
- package/dist/web/assets/terminal-tab-Bb2rZegQ.js +3 -0
- package/dist/web/assets/{tex-0loAoXJG.js → tex-DzSJ4kcZ.js} +1 -1
- package/dist/web/assets/text-wrap-CBT4Gxtg.js +1 -0
- package/dist/web/assets/tool-cards-lhqhrDTT.js +8 -0
- package/dist/web/assets/trash-2-Bk4yYlck.js +1 -0
- package/dist/web/assets/treemap-KZPCXAKY-DUbnl9dz.js +1 -0
- package/dist/web/assets/triangle-alert-B8EYecpe.js +1 -0
- package/dist/web/assets/{ts-tags-pt-Ug0hK.js → ts-tags-C28w3bTg.js} +1 -1
- package/dist/web/assets/{twig-DOePpLOL.js → twig-i5jY3QXB.js} +1 -1
- package/dist/web/assets/upload-BNlX8D07.js +1 -0
- package/dist/web/assets/{use-blob-url-BKyVxOZw.js → use-blob-url-Dsq9OjTh.js} +1 -1
- package/dist/web/assets/{use-monaco-theme-DSCdlrjO.js → use-monaco-theme-BZvlsoBv.js} +1 -1
- package/dist/web/assets/use-open-team-member-DkiEjFYE.js +1 -0
- package/dist/web/assets/{use-websocket-iJfc7EbK.js → use-websocket-B8R50f7f.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-DrwG0NYt.js → vendor-mermaid-By4AVvJY.js} +1 -1
- package/dist/web/assets/video-preview-m0-3p7QZ.js +1 -0
- package/dist/web/assets/{vue-D6f-rprj.js → vue-Ceyet_lv.js} +1 -1
- package/dist/web/assets/{vue-html-DEYRkS1V.js → vue-html-GuU7g_hg.js} +1 -1
- package/dist/web/assets/{vue-vine-CxSG2ojf.js → vue-vine-CxXoaJr2.js} +1 -1
- package/dist/web/assets/window-store-CsEW6jiE.js +1 -0
- package/dist/web/assets/{xml-DhrxbATj.js → xml-CbqOVhkP.js} +1 -1
- package/dist/web/assets/{xsl-CU0ZndUO.js → xsl-KfAmCauy.js} +1 -1
- package/dist/web/index.html +56 -27
- package/dist/web/sw.js +1 -1
- package/docs/code-standards.md +8 -0
- package/docs/codebase-summary.md +19 -5
- package/docs/design-guidelines.md +13 -2
- package/docs/project-roadmap.md +9 -0
- package/docs/system-architecture.md +83 -6
- package/package.json +1 -1
- package/src/web/components/chat/file-picker.tsx +5 -2
- package/src/web/components/chat/mode-selector.tsx +5 -2
- package/src/web/components/chat/model-selector.tsx +5 -2
- package/src/web/components/chat/model-thinking-selector.tsx +5 -2
- package/src/web/components/chat/provider-selector.tsx +5 -2
- package/src/web/components/chat/slash-command-picker.tsx +5 -2
- package/src/web/components/editor/code-editor.tsx +13 -3
- package/src/web/components/editor/conflict-editor.tsx +9 -0
- package/src/web/components/editor/diff-viewer.tsx +9 -0
- package/src/web/components/floating-window/floating-window.tsx +23 -15
- package/src/web/components/floating-window/pip/pip-caption-button.tsx +108 -0
- package/src/web/components/floating-window/pip/pip-focus-target.ts +58 -0
- package/src/web/components/floating-window/pip/pip-geometry.ts +46 -0
- package/src/web/components/floating-window/pip/pip-host.ts +156 -0
- package/src/web/components/floating-window/pip/pip-key-forward.ts +59 -0
- package/src/web/components/floating-window/pip/pip-resize-signal.ts +33 -0
- package/src/web/components/floating-window/pip/pip-style-copy.ts +108 -0
- package/src/web/components/floating-window/pip/pip-support.ts +33 -0
- package/src/web/components/floating-window/tab-host-window-content.tsx +80 -0
- package/src/web/components/floating-window/use-window-body-element.ts +67 -0
- package/src/web/components/floating-window/use-window-drag.ts +5 -0
- package/src/web/components/floating-window/use-window-gesture-context.ts +14 -0
- package/src/web/components/floating-window/use-window-resize.ts +5 -0
- package/src/web/components/floating-window/window-content-registry.ts +4 -16
- package/src/web/components/floating-window/window-layer.tsx +1 -2
- package/src/web/components/floating-window/window-persistence.ts +9 -2
- package/src/web/components/floating-window/window-pip-placeholder.tsx +31 -0
- package/src/web/components/floating-window/window-pip-registry.ts +69 -0
- package/src/web/components/floating-window/window-skin-chrome.tsx +21 -0
- package/src/web/components/floating-window/window-store-types.ts +8 -2
- package/src/web/components/layout/reparenting-tab.tsx +136 -0
- package/src/web/components/layout/tab-bar.tsx +2 -0
- package/src/web/components/layout/tab-pool-collect.ts +38 -2
- package/src/web/components/layout/tab-pool-registry.ts +48 -0
- package/src/web/components/layout/tab-pool.tsx +54 -168
- package/src/web/components/layout/tab-pop-out-menu-item.tsx +42 -0
- package/src/web/components/layout/use-window-panel-reconcile.ts +48 -0
- package/src/web/components/os-explorer/skins/macos-window-chrome.tsx +16 -7
- package/src/web/components/os-explorer/skins/windows-window-chrome.tsx +14 -8
- package/src/web/components/ui/context-menu.tsx +10 -3
- package/src/web/components/ui/dialog.tsx +10 -1
- package/src/web/components/ui/dropdown-menu.tsx +10 -3
- package/src/web/components/ui/mobile-bottom-sheet.tsx +7 -4
- package/src/web/components/ui/portal-container-context.tsx +40 -0
- package/src/web/components/ui/select.tsx +3 -1
- package/src/web/components/ui/tooltip.tsx +3 -1
- package/src/web/hooks/use-terminal.ts +24 -3
- package/src/web/stores/panel-store.ts +72 -7
- package/src/web/stores/panel-utils.ts +36 -0
- package/src/web/stores/window-panel-actions.ts +211 -0
- package/src/web/stores/window-panel-persistence.ts +115 -0
- package/src/web/stores/window-panel-reconcile.ts +97 -0
- package/.spike/group-protected-probe.ts +0 -21
- package/.spike/s.err +0 -63
- package/.spike/tunnel.err +0 -22
- package/.spike/w.err +0 -28
- package/dist/web/assets/ai-resource-editor-mdDKG-rw.js +0 -1
- package/dist/web/assets/api-client-CzABTreM.js +0 -1
- package/dist/web/assets/api-settings-nblja3Rk.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-C7ra20CE.js +0 -1
- package/dist/web/assets/chat-tab-C060A94y.js +0 -15
- package/dist/web/assets/code-editor-WELegzdp.js +0 -10
- package/dist/web/assets/context-menu-Cq0u3SK9.js +0 -1
- package/dist/web/assets/database-viewer-DevnWTV4.js +0 -1
- package/dist/web/assets/diff-viewer-DGxVg1pD.js +0 -4
- package/dist/web/assets/docx-preview-Cx-zLwAw.js +0 -12
- package/dist/web/assets/explorer-body-j_4hVc34.js +0 -2
- package/dist/web/assets/explorer-window-content-DdrGwk3w.js +0 -1
- package/dist/web/assets/git-log-panel-CfpXRJcP.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-D4hYLNJU.js +0 -1
- package/dist/web/assets/group-chat-tab-dYuuknLN.js +0 -1
- package/dist/web/assets/image-preview-Ss38ex8g.js +0 -1
- package/dist/web/assets/index-BiTiXgBZ.css +0 -2
- package/dist/web/assets/index-Ch8l9de-.js +0 -52
- package/dist/web/assets/info-3K5VOQVL-lRlrTlkb.js +0 -1
- package/dist/web/assets/keybindings-store-CDfTjwZX.js +0 -1
- package/dist/web/assets/markdown-renderer-CpRlpLHw.js +0 -1
- package/dist/web/assets/mobile-bottom-sheet-BUOJgiaZ.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-D1Bv9UCT.js +0 -1
- package/dist/web/assets/notification-store-KwTAZT8b.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-BIhk1mvp.js +0 -1
- package/dist/web/assets/panel-store-DCD82zc1.js +0 -1
- package/dist/web/assets/pdf-preview-dwRe54ht.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-SLS6i76l.js +0 -1
- package/dist/web/assets/process-table-CI-fnVsy.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-JJ6O1Er_.js +0 -1
- package/dist/web/assets/settings-tab-mPxrKkfm.js +0 -1
- package/dist/web/assets/sqlite-viewer-Cs-_D942.js +0 -1
- package/dist/web/assets/system-monitor-body-CV7-0hZG.js +0 -2
- package/dist/web/assets/system-monitor-tab-Ce-8Axhh.js +0 -1
- package/dist/web/assets/system-monitor-window-content-CetwYOQy.js +0 -1
- package/dist/web/assets/team-member-sheet-CjgaQjsZ.js +0 -2
- package/dist/web/assets/team-member-window-content-DNJiYWS7.js +0 -1
- package/dist/web/assets/terminal-tab-DF7521sT.js +0 -3
- package/dist/web/assets/tool-cards-DCAXGDJI.js +0 -8
- package/dist/web/assets/treemap-KZPCXAKY-Be3KNmns.js +0 -1
- package/dist/web/assets/use-open-team-member-H4k74HnV.js +0 -1
- package/dist/web/assets/video-preview-B0ZWpX0F.js +0 -1
- package/src/web/components/floating-window/default-window-chrome.tsx +0 -71
- package/src/web/components/os-explorer/skins/explorer-skin-chrome.tsx +0 -17
- /package/dist/web/assets/{abap-MRbmsXOs.js → abap-C6nB04tn.js} +0 -0
- /package/dist/web/assets/{actionscript-3-BDDHKqa4.js → actionscript-3-Vx4rw2sC.js} +0 -0
- /package/dist/web/assets/{ada-DpuV9KwV.js → ada-Ccd8vM20.js} +0 -0
- /package/dist/web/assets/{andromeeda-D6qUCKJo.js → andromeeda-DnBX5xMg.js} +0 -0
- /package/dist/web/assets/{apache-CX1NU_Tl.js → apache-B-9_sx0g.js} +0 -0
- /package/dist/web/assets/{apex-B4-aoQ3K.js → apex-_wPVBYoL.js} +0 -0
- /package/dist/web/assets/{api-client-BSB14J4w.js → api-client-aQb5hHE5.js} +0 -0
- /package/dist/web/assets/{applescript-Dm9NI6KR.js → applescript-CcvD-qr0.js} +0 -0
- /package/dist/web/assets/{apply-theme-BH_d4amk.js → apply-theme-BeLRfsSu.js} +0 -0
- /package/dist/web/assets/{ara-BGN8GAYn.js → ara-C40Ztoms.js} +0 -0
- /package/dist/web/assets/{asciidoc-s_yVuR3t.js → asciidoc-CybYkJV4.js} +0 -0
- /package/dist/web/assets/{asm-BzQdSvTe.js → asm-9eOKwzR0.js} +0 -0
- /package/dist/web/assets/{aurora-x-BJTLETG_.js → aurora-x-B5ZH4t7t.js} +0 -0
- /package/dist/web/assets/{awk-BQEGWxvX.js → awk-Dqilob-2.js} +0 -0
- /package/dist/web/assets/{ayu-dark-CpTORmLc.js → ayu-dark-CPgRhf5r.js} +0 -0
- /package/dist/web/assets/{ayu-light-D8PVj-e6.js → ayu-light-Do06Q52f.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-DyElQHtm.js → ayu-mirage-_BhxcrxY.js} +0 -0
- /package/dist/web/assets/{ballerina-C82NkRtj.js → ballerina-DDwK54QW.js} +0 -0
- /package/dist/web/assets/{bat-0X7DtGI-.js → bat-BGyGlzGk.js} +0 -0
- /package/dist/web/assets/{beancount-Xgvy6YRl.js → beancount-CRWBdapI.js} +0 -0
- /package/dist/web/assets/{berry-CCT2pZcQ.js → berry-DbSFn2gO.js} +0 -0
- /package/dist/web/assets/{bibtex-CpXgZ9M_.js → bibtex-QpsV9gm9.js} +0 -0
- /package/dist/web/assets/{bicep-fkeSA62l.js → bicep-CxS8CUve.js} +0 -0
- /package/dist/web/assets/{bird2-Co7SeAI8.js → bird2-CuZhQzYR.js} +0 -0
- /package/dist/web/assets/{bot-CunPuEdW.js → bot-D6sx11y0.js} +0 -0
- /package/dist/web/assets/{c-BpmrTvJh.js → c-9bnDqE3g.js} +0 -0
- /package/dist/web/assets/{c3-BZ_Z0RrR.js → c3-JMZTrOhA.js} +0 -0
- /package/dist/web/assets/{cadence-B0GBC8OF.js → cadence-DsDNayJS.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-omBzUBBq.js → can-open-in-ppm-BJfpynya.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-DIt_xR7m.js → catppuccin-frappe-DYIKXXBe.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-Dw40AcqA.js → catppuccin-latte-IYYOnUJ8.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-BJ7DfVEF.js → catppuccin-macchiato-BrJ_7mfS.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-NI2lfXzU.js → catppuccin-mocha-gzSu7v7-.js} +0 -0
- /package/dist/web/assets/{chevron-right-BLOtX8Vy.js → chevron-right-De-Wz5Lz.js} +0 -0
- /package/dist/web/assets/{circle-hjUGru6R.js → circle-BCy0AUCo.js} +0 -0
- /package/dist/web/assets/{clarity-F39L0xMJ.js → clarity-DLzsC0Hb.js} +0 -0
- /package/dist/web/assets/{clock-CvhF4DJP.js → clock-C1CQUQPZ.js} +0 -0
- /package/dist/web/assets/{clojure-DloMkd8K.js → clojure-DS1BvoTt.js} +0 -0
- /package/dist/web/assets/{cmake-CwerJun_.js → cmake-CDvsJwYp.js} +0 -0
- /package/dist/web/assets/{code-DDPoqVri.js → code-DJgYrFzm.js} +0 -0
- /package/dist/web/assets/{codeowners-CQyVz4Qf.js → codeowners-BjsYiflJ.js} +0 -0
- /package/dist/web/assets/{codeql-Bb229zuY.js → codeql-CG-7ARat.js} +0 -0
- /package/dist/web/assets/{common-lisp-KMlIwq5I.js → common-lisp-DSO1Lbh9.js} +0 -0
- /package/dist/web/assets/{copy-DKn11Pye.js → copy-BewHj66E.js} +0 -0
- /package/dist/web/assets/{coq-DHX_3IIo.js → coq-DYdh3oP_.js} +0 -0
- /package/dist/web/assets/{csharp-CEmCZv9Q.js → csharp-DxEBz5s0.js} +0 -0
- /package/dist/web/assets/{css-CqZqBD05.js → css-dal3Q-8C.js} +0 -0
- /package/dist/web/assets/{csv-l1g_V5MV.js → csv-CpqjMGiA.js} +0 -0
- /package/dist/web/assets/{csv-parser-CnS0wqr6.js → csv-parser-3umBA4NY.js} +0 -0
- /package/dist/web/assets/{cue-BrxRmilg.js → cue-DinoJ_5k.js} +0 -0
- /package/dist/web/assets/{cypher-rZkKwqZc.js → cypher-DzxqmkUW.js} +0 -0
- /package/dist/web/assets/{d-BALR-QuP.js → d-BxNwJuEC.js} +0 -0
- /package/dist/web/assets/{dark-plus-Cj7rVwh-.js → dark-plus-Clmv3V-0.js} +0 -0
- /package/dist/web/assets/{dart-CWQcdkXk.js → dart-BWVtXD35.js} +0 -0
- /package/dist/web/assets/{data-grid-types-CYvF-xK5.js → data-grid-types-B4n51Fck.js} +0 -0
- /package/dist/web/assets/{database-BH0urvbs.js → database-Y3ESDK4-.js} +0 -0
- /package/dist/web/assets/{dax-BNHD-QBA.js → dax-DsImuWgJ.js} +0 -0
- /package/dist/web/assets/{desktop-CN0IXPrP.js → desktop-B0jJuG2r.js} +0 -0
- /package/dist/web/assets/{diff-BtOXapES.js → diff-CWqAAxoE.js} +0 -0
- /package/dist/web/assets/{dist-DB1Oaqcc.js → dist-B-EXdSYE.js} +0 -0
- /package/dist/web/assets/{dist-Di6G_5jU.js → dist-C0eNNfbt.js} +0 -0
- /package/dist/web/assets/{docker-DNsAo_qO.js → docker-CYFCJdIL.js} +0 -0
- /package/dist/web/assets/{dotenv-D6Pl6aOU.js → dotenv-CKDUjURg.js} +0 -0
- /package/dist/web/assets/{download-zCATy4x4.js → download-DG3_9xXy.js} +0 -0
- /package/dist/web/assets/{dracula-C3m-w12D.js → dracula-CSoPspHE.js} +0 -0
- /package/dist/web/assets/{dracula-soft-BYqvXm6Z.js → dracula-soft-BuFjw5L1.js} +0 -0
- /package/dist/web/assets/{dream-maker-DZAPbPTi.js → dream-maker-B6PdDRZu.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-Ao5SW8ay.js → emacs-lisp-CMcXvD0G.js} +0 -0
- /package/dist/web/assets/{everforest-dark-uC8QYotQ.js → everforest-dark-cU8-wYzi.js} +0 -0
- /package/dist/web/assets/{everforest-light-CTgsVNMr.js → everforest-light-KhorllqK.js} +0 -0
- /package/dist/web/assets/{fennel-WuBw6IR1.js → fennel-BCELZK87.js} +0 -0
- /package/dist/web/assets/{file-exclamation-point-COAwgNGw.js → file-exclamation-point-CZ4DiR75.js} +0 -0
- /package/dist/web/assets/{fish-Byy9dusu.js → fish-BQc0y_jy.js} +0 -0
- /package/dist/web/assets/{fluent-CDxb_sgw.js → fluent-BTINnwF6.js} +0 -0
- /package/dist/web/assets/{format-bytes-BE_W3UBg.js → format-bytes-WVcFxJuT.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-DKWSTamT.js → fortran-free-form-BQim9wDz.js} +0 -0
- /package/dist/web/assets/{gdscript-prYHMgtD.js → gdscript-03w5u8un.js} +0 -0
- /package/dist/web/assets/{gdshader-D-RM-SQk.js → gdshader-Dp2daNzU.js} +0 -0
- /package/dist/web/assets/{genie-CowkJhej.js → genie-CoNcjPiD.js} +0 -0
- /package/dist/web/assets/{gherkin-CLFpoVYJ.js → gherkin-NrPOSPQL.js} +0 -0
- /package/dist/web/assets/{github-dark-default-BK_1Qgb8.js → github-dark-default-DOKw-1cI.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-Cv9lj6f-.js → github-dark-dimmed-DJRNMkEA.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-CW5ZgIDh.js → github-dark-high-contrast-Bj7jJ_Gs.js} +0 -0
- /package/dist/web/assets/{github-dark-nW2F-RLd.js → github-dark-z4RE9ZqA.js} +0 -0
- /package/dist/web/assets/{github-light-D4PqBHGZ.js → github-light-B4k_yMFu.js} +0 -0
- /package/dist/web/assets/{github-light-default-B-cHtJJV.js → github-light-default-BHc-Uzhs.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-Dt0HJq50.js → github-light-high-contrast-CHisIywL.js} +0 -0
- /package/dist/web/assets/{gleam-DwSyXJWP.js → gleam-CfbypZ4q.js} +0 -0
- /package/dist/web/assets/{gn-Cv5WEzHc.js → gn-YoAjyhJa.js} +0 -0
- /package/dist/web/assets/{gnuplot-D7bRdY_M.js → gnuplot-xVkc1f1c.js} +0 -0
- /package/dist/web/assets/{go-DiRVJ22U.js → go-GPCwP3Gu.js} +0 -0
- /package/dist/web/assets/{groovy-BHAgLTeO.js → groovy-Crh4Yww9.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-C8QZ3gzY.js → gruvbox-dark-hard-BluUFuDS.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-Dp1eeid2.js → gruvbox-dark-medium-Cxk1FWQp.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-Cwq0dWVj.js → gruvbox-dark-soft-CHXMiFmj.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-CLQCq2-w.js → gruvbox-light-hard-B6eKPjAD.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-APHsh6Mo.js → gruvbox-light-medium-pDwMm1ut.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-CX-fYc64.js → gruvbox-light-soft-Cxu6kHqK.js} +0 -0
- /package/dist/web/assets/{haskell-C4Tw-TDa.js → haskell-C6JKHjbK.js} +0 -0
- /package/dist/web/assets/{haxe-B7fSduTQ.js → haxe-BuBNdF0a.js} +0 -0
- /package/dist/web/assets/{hcl-Bi3ho6yC.js → hcl-DZpDdGj2.js} +0 -0
- /package/dist/web/assets/{hjson-BXwae2M1.js → hjson-CBkhYRuo.js} +0 -0
- /package/dist/web/assets/{hlsl-CRuQLBSa.js → hlsl-C5nMxnp9.js} +0 -0
- /package/dist/web/assets/{horizon-DtdQ6qjv.js → horizon-VAFvA6R6.js} +0 -0
- /package/dist/web/assets/{horizon-bright-BXSF_uKq.js → horizon-bright-BC0xn7T3.js} +0 -0
- /package/dist/web/assets/{houston-C6ASpUjT.js → houston-BxrUivmz.js} +0 -0
- /package/dist/web/assets/{hy-BrWBHtHY.js → hy-DLtOXoaH.js} +0 -0
- /package/dist/web/assets/{image-gallery-CGvlv8zR.js → image-gallery-Gnf7TdCR.js} +0 -0
- /package/dist/web/assets/{imba-C_JJXckG.js → imba-BdpFXM2W.js} +0 -0
- /package/dist/web/assets/{ini-DEE_vSHQ.js → ini-BInJO_T0.js} +0 -0
- /package/dist/web/assets/{java-CnmpcjcT.js → java-Dxuddnkb.js} +0 -0
- /package/dist/web/assets/{javascript-C-M7sa2e.js → javascript-CVamJfLY.js} +0 -0
- /package/dist/web/assets/{json-BjZ3dAk6.js → json-BLZ0ozYk.js} +0 -0
- /package/dist/web/assets/{json5-BQ2vpqjp.js → json5-BnXzmMKs.js} +0 -0
- /package/dist/web/assets/{jsonc-C5MjoWGx.js → jsonc-CSgkSga7.js} +0 -0
- /package/dist/web/assets/{jsonl-JvhrmQJI.js → jsonl-CY5W2nF2.js} +0 -0
- /package/dist/web/assets/{jsonnet-C5pdZVuo.js → jsonnet-CEJYH3sF.js} +0 -0
- /package/dist/web/assets/{jssm-Db17uybX.js → jssm-CsJc7Uhk.js} +0 -0
- /package/dist/web/assets/{jsx-tJp2Cyqu.js → jsx-jCiRaHU7.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-BculT_Y1.js → kanagawa-dragon-DfoA_GxX.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-yQgHUGwU.js → kanagawa-lotus-BOLYJpWd.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-CyGoWN4d.js → kanagawa-wave-DfKlbT1G.js} +0 -0
- /package/dist/web/assets/{kdl-Bn8R1REF.js → kdl-CmssIFTi.js} +0 -0
- /package/dist/web/assets/{kotlin-DWughK73.js → kotlin-BRsNgp6x.js} +0 -0
- /package/dist/web/assets/{kusto--serPb0x.js → kusto-T8X9jUab.js} +0 -0
- /package/dist/web/assets/{laserwave-DfAPJ1tt.js → laserwave-DkJMVJ8Z.js} +0 -0
- /package/dist/web/assets/{lean-UAm1HOKl.js → lean-C65KGVPq.js} +0 -0
- /package/dist/web/assets/{less-Xj6Ka0fF.js → less-exIPdDlf.js} +0 -0
- /package/dist/web/assets/{lib-DgNcCtj3.js → lib-mC1NZfuw.js} +0 -0
- /package/dist/web/assets/{libesm-CPh1Av0r.js → libesm-DSutUtl1.js} +0 -0
- /package/dist/web/assets/{light-plus-BfS7gPcj.js → light-plus-DiHUXAZt.js} +0 -0
- /package/dist/web/assets/{llvm-DvWiVwvU.js → llvm-CJBnEzFM.js} +0 -0
- /package/dist/web/assets/{log-Bo5z9bNz.js → log-DxMyUMuP.js} +0 -0
- /package/dist/web/assets/{logo-CrIjcMZT.js → logo-CC9NKzca.js} +0 -0
- /package/dist/web/assets/{luau-C9TsYwNt.js → luau-Bw10I6zf.js} +0 -0
- /package/dist/web/assets/{make-GYq4qVbx.js → make-C_6M90m6.js} +0 -0
- /package/dist/web/assets/{markdown-p5mNledS.js → markdown-bR9_R-LF.js} +0 -0
- /package/dist/web/assets/{material-theme-CWYOVxsP.js → material-theme-BUx2Qujn.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-BDGty7YH.js → material-theme-darker-CRJrPgKm.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-JbgOgV3n.js → material-theme-lighter-CUAYppPa.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-EMOpLpa2.js → material-theme-ocean-DuINF1fg.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-CY5hgm7h.js → material-theme-palenight-W6_icGCj.js} +0 -0
- /package/dist/web/assets/{matlab-C-He_NTH.js → matlab-rfqn_b3z.js} +0 -0
- /package/dist/web/assets/{mdx-Cr2TR5fj.js → mdx-Bh1B_YOJ.js} +0 -0
- /package/dist/web/assets/{mermaid-BYc0-B0U.js → mermaid-Dxf6Ya2k.js} +0 -0
- /package/dist/web/assets/{min-dark-CMJwqJqB.js → min-dark-CivZ2L0h.js} +0 -0
- /package/dist/web/assets/{min-light-Cx6vFiEX.js → min-light-B1Ykqtma.js} +0 -0
- /package/dist/web/assets/{mipsasm-Bjer5HwK.js → mipsasm-DynHaM0d.js} +0 -0
- /package/dist/web/assets/{mojo-t90PR-Y2.js → mojo-Clw5PbGH.js} +0 -0
- /package/dist/web/assets/{monokai-dci_PdCm.js → monokai-DFIooFZT.js} +0 -0
- /package/dist/web/assets/{moonbit-AAzI-Hd-.js → moonbit-DnBSZWGM.js} +0 -0
- /package/dist/web/assets/{move-kwBhnhrG.js → move-CCcL2PfL.js} +0 -0
- /package/dist/web/assets/{narrat-CXww2YQL.js → narrat-BDarg5Lk.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-CJXsuXGB.js → nextflow-groovy-DrZOeCNW.js} +0 -0
- /package/dist/web/assets/{night-owl-_GD204Wr.js → night-owl-BnZZCK7v.js} +0 -0
- /package/dist/web/assets/{night-owl-light-DNgkw3kl.js → night-owl-light-CEwBsVHS.js} +0 -0
- /package/dist/web/assets/{nix-BgiorKFd.js → nix-amCzOPMR.js} +0 -0
- /package/dist/web/assets/{nord-CaBmcxFC.js → nord-BIs2BC6q.js} +0 -0
- /package/dist/web/assets/{nushell-DUh4UGx1.js → nushell-Y02fo4yw.js} +0 -0
- /package/dist/web/assets/{objective-c-Cl9KU86S.js → objective-c-7xOZtWW1.js} +0 -0
- /package/dist/web/assets/{objective-cpp-DVkIA8A0.js → objective-cpp-eVtjUvVB.js} +0 -0
- /package/dist/web/assets/{ocaml-vvoHTak0.js → ocaml-Bi6ZwqG4.js} +0 -0
- /package/dist/web/assets/{odin-Cyjw8woZ.js → odin-8xf1Y0S9.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-B1cviILi.js → one-dark-pro-hVv-_y_b.js} +0 -0
- /package/dist/web/assets/{one-light-BPGUJeYI.js → one-light-CJJ3MtHt.js} +0 -0
- /package/dist/web/assets/{openscad-BLMdTUU8.js → openscad-B2HcywLk.js} +0 -0
- /package/dist/web/assets/{pascal-i5niy3e7.js → pascal-C7fllV_7.js} +0 -0
- /package/dist/web/assets/{pkl-CuOV7SsU.js → pkl-qvLC1IWP.js} +0 -0
- /package/dist/web/assets/{plastic-Bf_zE5KL.js → plastic-BT1wHZv2.js} +0 -0
- /package/dist/web/assets/{plsql-cfqEtMD3.js → plsql-1MsmdmJD.js} +0 -0
- /package/dist/web/assets/{plus-BM-Ty0fp.js → plus-BhMZqFsN.js} +0 -0
- /package/dist/web/assets/{po-CFJcWgjr.js → po-BigskytD.js} +0 -0
- /package/dist/web/assets/{poimandres-G5YoaIFf.js → poimandres-DuklniF7.js} +0 -0
- /package/dist/web/assets/{polar-rcjs3i9R.js → polar-e2pjN_sp.js} +0 -0
- /package/dist/web/assets/{postcss-CBKY1FTZ.js → postcss-DtAeYjWw.js} +0 -0
- /package/dist/web/assets/{powerquery-Db7SXLbO.js → powerquery-Cr2PtehI.js} +0 -0
- /package/dist/web/assets/{powershell-LFy3MUTP.js → powershell-BxFTGLJ4.js} +0 -0
- /package/dist/web/assets/{prisma-BE8GR1lH.js → prisma-COWJiwdZ.js} +0 -0
- /package/dist/web/assets/{prolog-DOn5lR1e.js → prolog-DFvGKRx6.js} +0 -0
- /package/dist/web/assets/{proto-wr-TpAK_.js → proto-CcK80lFt.js} +0 -0
- /package/dist/web/assets/{puppet-D2Dkv62u.js → puppet-BF60bZ4F.js} +0 -0
- /package/dist/web/assets/{purescript-DvgJgPdy.js → purescript-zL_69MzU.js} +0 -0
- /package/dist/web/assets/{python-C7TlkHhK.js → python-CIwKhfb_.js} +0 -0
- /package/dist/web/assets/{qmldir-CtZMwhcW.js → qmldir-CXNe04Lo.js} +0 -0
- /package/dist/web/assets/{qss-dNZ2btnl.js → qss-C8lAWe6G.js} +0 -0
- /package/dist/web/assets/{r-BlqnNkHS.js → r-CL5ZVL3_.js} +0 -0
- /package/dist/web/assets/{racket-CzRQrGc4.js → racket-BBfh0uh0.js} +0 -0
- /package/dist/web/assets/{raku-BwutWhBF.js → raku-o6E8R5Q3.js} +0 -0
- /package/dist/web/assets/{react-I_EwPIZi.js → react-CBTnT4sY.js} +0 -0
- /package/dist/web/assets/{red-BMXMywmL.js → red-GomRF2Xp.js} +0 -0
- /package/dist/web/assets/{reg-BqOKrIOw.js → reg-_ffDIvx9.js} +0 -0
- /package/dist/web/assets/{regexp-Bero1BN2.js → regexp-Bl5sF65W.js} +0 -0
- /package/dist/web/assets/{rel-BXKWIElA.js → rel-DgMdqDuj.js} +0 -0
- /package/dist/web/assets/{resolve-theme-B9ABAH_3.js → resolve-theme-CRt_7wpd.js} +0 -0
- /package/dist/web/assets/{riscv-BbbBYJBo.js → riscv-8b3-Ye4X.js} +0 -0
- /package/dist/web/assets/{ron-BtVTWW4b.js → ron-DrmU1KHP.js} +0 -0
- /package/dist/web/assets/{rose-pine-hvkvQzvU.js → rose-pine-C_-E2tF1.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-D7lwhUei.js → rose-pine-dawn-DEfhNlFH.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-CoHDmsIw.js → rose-pine-moon-BdvX3gdn.js} +0 -0
- /package/dist/web/assets/{rosmsg-CdaZFgI8.js → rosmsg-B6GhGpd5.js} +0 -0
- /package/dist/web/assets/{rust-Dy2qsphD.js → rust-DmC97M1-.js} +0 -0
- /package/dist/web/assets/{sass-Bz7NVxDb.js → sass-B0tJOHLM.js} +0 -0
- /package/dist/web/assets/{save-C4z1p51e.js → save-CtIGOjmx.js} +0 -0
- /package/dist/web/assets/{scala-sXSwsNyq.js → scala-n8zaFOXv.js} +0 -0
- /package/dist/web/assets/{scheme-DS7TUbN7.js → scheme-BKD9ztBU.js} +0 -0
- /package/dist/web/assets/{sdbl-iISFvIep.js → sdbl-D8gB5-rS.js} +0 -0
- /package/dist/web/assets/{shellscript-BkIl4ApC.js → shellscript-BfXlf_Ao.js} +0 -0
- /package/dist/web/assets/{shield-check-C5laObJv.js → shield-check-B0iGUiOK.js} +0 -0
- /package/dist/web/assets/{shield-off-DULFtyLS.js → shield-off-BNLWBhcq.js} +0 -0
- /package/dist/web/assets/{slack-dark-B1eg0_m2.js → slack-dark-CylEddse.js} +0 -0
- /package/dist/web/assets/{slack-ochin-mdkc1ldu.js → slack-ochin-w8wg8vuC.js} +0 -0
- /package/dist/web/assets/{smalltalk-CORtd03t.js → smalltalk-hiAXA64u.js} +0 -0
- /package/dist/web/assets/{snazzy-light-Bc6Q2G89.js → snazzy-light-BwlV3Xty.js} +0 -0
- /package/dist/web/assets/{solarized-dark-CF83zRXM.js → solarized-dark-vmNGdykz.js} +0 -0
- /package/dist/web/assets/{solarized-light-BoKQZaYU.js → solarized-light-DGv_0JXq.js} +0 -0
- /package/dist/web/assets/{solidity-DOgi1N4w.js → solidity-Y7QSH0B1.js} +0 -0
- /package/dist/web/assets/{sparkles-Dqsf3hq6.js → sparkles-Dh-_J2Rd.js} +0 -0
- /package/dist/web/assets/{splunk-BXfw5ZLy.js → splunk-BtgpLjHi.js} +0 -0
- /package/dist/web/assets/{sql-BcVs-eX4.js → sql-CRHYhOia.js} +0 -0
- /package/dist/web/assets/{ssh-config-CLCtNkkd.js → ssh-config-DOqSs3au.js} +0 -0
- /package/dist/web/assets/{stylus-DdP992aO.js → stylus-crCAEaBT.js} +0 -0
- /package/dist/web/assets/{swift-BnGb6Lgc.js → swift-eE3rT7TC.js} +0 -0
- /package/dist/web/assets/{synthwave-84-cg9264l9.js → synthwave-84-BWy14LBX.js} +0 -0
- /package/dist/web/assets/{system-verilog-GbHpszs3.js → system-verilog-DC0-DZM4.js} +0 -0
- /package/dist/web/assets/{systemd-Dz-bNsDQ.js → systemd-to5p6N8I.js} +0 -0
- /package/dist/web/assets/{table-CHmxuh6M.js → table-Bbc783ko.js} +0 -0
- /package/dist/web/assets/{talonscript-CFIidoBA.js → talonscript-DoTcU8wm.js} +0 -0
- /package/dist/web/assets/{tasl-Cu-TRTKx.js → tasl-cNZvUs95.js} +0 -0
- /package/dist/web/assets/{tcl-DwCHCB1K.js → tcl-mZE8sZH8.js} +0 -0
- /package/dist/web/assets/{terraform-BzZw4T1z.js → terraform-CqHPpIfu.js} +0 -0
- /package/dist/web/assets/{tokyo-night-RKsj2-tv.js → tokyo-night-Tp2rTIZd.js} +0 -0
- /package/dist/web/assets/{toml-CirbOgDP.js → toml-CU_vscgn.js} +0 -0
- /package/dist/web/assets/{tsv-CraRcWdU.js → tsv-ik7iFB9D.js} +0 -0
- /package/dist/web/assets/{tsx-CjFg0lgw.js → tsx-BMvvMKiv.js} +0 -0
- /package/dist/web/assets/{turtle-B-WBIOa6.js → turtle-DBqKCq9o.js} +0 -0
- /package/dist/web/assets/{typescript-MpLarYn1.js → typescript-DXJDmMZZ.js} +0 -0
- /package/dist/web/assets/{typespec-B7QlHMZ_.js → typespec-CBseCMtZ.js} +0 -0
- /package/dist/web/assets/{typst-CcHSKFZj.js → typst-4oY25U9y.js} +0 -0
- /package/dist/web/assets/{use-is-mobile-BXGVvczu.js → use-is-mobile-D1weanbj.js} +0 -0
- /package/dist/web/assets/{utils-DoY4yTP-.js → utils-BNRH507E.js} +0 -0
- /package/dist/web/assets/{v-xTGhWZuD.js → v-BXaZ_1oy.js} +0 -0
- /package/dist/web/assets/{vala-DwebjH3H.js → vala-BImWJE7z.js} +0 -0
- /package/dist/web/assets/{vb-BxJT2RAy.js → vb-CLfj2_sy.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-CU6zIYMB.js → vendor-xterm-_yyu5n32.js} +0 -0
- /package/dist/web/assets/{verilog-CvV6RHPD.js → verilog-BWa8Ed2b.js} +0 -0
- /package/dist/web/assets/{vesper-CY3qd7E_.js → vesper-BGj1cg6m.js} +0 -0
- /package/dist/web/assets/{vhdl-B9ZX-sUL.js → vhdl-mByK7mlx.js} +0 -0
- /package/dist/web/assets/{viml-Y42h_ExQ.js → viml-CugmlW5g.js} +0 -0
- /package/dist/web/assets/{vitesse-black-DkXP6Sv-.js → vitesse-black-vPdpy9TL.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-B9CkIB6r.js → vitesse-dark-BuQK3dUh.js} +0 -0
- /package/dist/web/assets/{vitesse-light-C7DHrJCK.js → vitesse-light-B3nz1XL9.js} +0 -0
- /package/dist/web/assets/{vyper-Cnd9s5j-.js → vyper-DH_GTIHG.js} +0 -0
- /package/dist/web/assets/{wasm-DQE71XTB.js → wasm-C-LF9GjX.js} +0 -0
- /package/dist/web/assets/{wasm-iWe7Fzjc.js → wasm-DfVbVJlW.js} +0 -0
- /package/dist/web/assets/{wenyan-Bc5Pnm9l.js → wenyan-CzQkHyHx.js} +0 -0
- /package/dist/web/assets/{wgsl-D-YUAWkP.js → wgsl-Du_M1DW9.js} +0 -0
- /package/dist/web/assets/{wikitext-DYQDUYf2.js → wikitext-BWN_w5S7.js} +0 -0
- /package/dist/web/assets/{wit-P6u7mfwy.js → wit-BR13v5HD.js} +0 -0
- /package/dist/web/assets/{wolfram-6SXLUqao.js → wolfram-BoXxp_Xl.js} +0 -0
- /package/dist/web/assets/{x-BcqfTY_7.js → x-nhriOX9o.js} +0 -0
- /package/dist/web/assets/{yaml-CQiMLVcZ.js → yaml-DpR_EF-d.js} +0 -0
- /package/dist/web/assets/{zenscript-DFMywo_P.js → zenscript-C-EdUtUd.js} +0 -0
- /package/dist/web/assets/{zig-CtAjaIiF.js → zig-BD4eA5nU.js} +0 -0
|
@@ -2264,10 +2264,87 @@ below the app's existing `z-40` click-away backdrops and `z-50` Radix layers, so
|
|
|
2264
2264
|
dropdowns and dialogs always stay reachable above any number of open explorer windows. Below the
|
|
2265
2265
|
`md` breakpoint the layer never mounts at all; `src/web/components/os-explorer/mobile/` renders the
|
|
2266
2266
|
same `ExplorerBody` component inside a full-screen bottom sheet instead (`variant="sheet"`).
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2267
|
+
Drag and resize share a `gestureAbandoned()` guard (`use-window-gesture-context.ts`) for the
|
|
2268
|
+
pointer-up that still arrives after a mid-gesture window close (e.g. dragging by a titlebar button
|
|
2269
|
+
that closes the frame).
|
|
2270
|
+
|
|
2271
|
+
**One chrome, every kind.** `WindowSkinChrome` (`window-skin-chrome.tsx`) is the titlebar every
|
|
2272
|
+
window kind — explorer, team-member session, system monitor, detached tab — renders: it resolves
|
|
2273
|
+
the active OS skin via `useExplorerSkin()` (Settings override, else host platform; Linux → macOS)
|
|
2274
|
+
and delegates to that skin's `WindowsWindowChrome` / `MacosWindowChrome`
|
|
2275
|
+
(`src/web/components/os-explorer/skins/`), scoped entirely through `[data-skin="windows"|"macos"]`
|
|
2276
|
+
CSS variables layered over PPM's existing semantic theme tokens — no second color table. The
|
|
2277
|
+
Windows skin's folder glyph draws only for `kind === "explorer"`; every other kind gets the bare
|
|
2278
|
+
titlebar. The macOS skin boxes the title between the traffic lights and the PiP button as a flex
|
|
2279
|
+
child (so a long title truncates instead of overlapping either), and puts the PiP button at the
|
|
2280
|
+
titlebar's right end; the Windows skin puts it left of minimize.
|
|
2281
|
+
|
|
2282
|
+
**PiP is a capability of the frame, not of one kind.** `useWindowBodyElement`
|
|
2283
|
+
(`use-window-body-element.ts`) creates the single DOM element `FloatingWindow` portals a window's
|
|
2284
|
+
content into and publishes it as that window's PiP slot (`window-pip-registry.ts`, keyed by window
|
|
2285
|
+
id). `PipCaptionButton` (`pip/pip-caption-button.tsx`), rendered by both skins, moves that slot into
|
|
2286
|
+
a `documentPictureInPicture` window and back; it is absent (not disabled) where the API is
|
|
2287
|
+
unsupported. `WindowPipPlaceholder` (`window-pip-placeholder.tsx`) takes the body's place in the
|
|
2288
|
+
frame while it plays in PiP, with a ≥44px "Bring back" control. The mechanics below (attach/detach,
|
|
2289
|
+
style mirroring, key forwarding, resize signalling) apply to whichever window kind currently owns
|
|
2290
|
+
the slot — a tab-host window is only the one kind whose body is itself a portal target for another
|
|
2291
|
+
component (`TabPool`).
|
|
2292
|
+
|
|
2293
|
+
#### Tab-host windows (detaching a tab into its own window)
|
|
2294
|
+
|
|
2295
|
+
- **Off-grid panel.** Detaching creates `` `__win__:${windowId}` `` (`windowPanelId()`,
|
|
2296
|
+
`stores/panel-utils.ts`) — same treatment as `__dock__`: lives in `panels`, never in `grid`, so no
|
|
2297
|
+
grid math (rows/columns/split) sees it. `stores/window-panel-actions.ts` is the only writer of
|
|
2298
|
+
these panels and enforces the paired invariant: `focusedPanelId` never points at one (it would
|
|
2299
|
+
send the next `openTab()` with no explicit panel into a window). `popOutTab`/`redockFromWindow`
|
|
2300
|
+
create and destroy the panel and its window together; every close path (titlebar ×, keyboard,
|
|
2301
|
+
reconcile) routes through `redockFromWindow`, which re-docks to the origin panel if it is still in
|
|
2302
|
+
the grid, else the focused grid panel, else the first grid panel. All tab types pop out except
|
|
2303
|
+
`system-monitor`, which already has its own window kind.
|
|
2304
|
+
- **No-remount move.** `TabPool` (`components/layout/tab-pool.tsx`) mounts every tab once into a
|
|
2305
|
+
wrapper `div[data-tab-pool-id]` created imperatively in `ReparentingTab`
|
|
2306
|
+
(`components/layout/reparenting-tab.tsx`) and rendered into it via `createPortal` — React attaches
|
|
2307
|
+
its listeners to the wrapper itself, so they keep firing after the node moves, including into
|
|
2308
|
+
another document. A `useLayoutEffect` with no deps calls `appendChild` to move the wrapper into
|
|
2309
|
+
whichever element last registered for the tab's panel id (`slotRegistry`,
|
|
2310
|
+
`components/layout/tab-pool-registry.ts`); `TabHostWindowContent`'s slot `div` is always mounted
|
|
2311
|
+
(never swapped for a placeholder), because it may currently be living inside the PiP document.
|
|
2312
|
+
- **Persistence.** Window panels persist to their own global `localStorage["ppm-window-panels"]`
|
|
2313
|
+
key (`stores/window-panel-persistence.ts`), separate from the per-project `ppm-panels-*` blob and
|
|
2314
|
+
not synced to the server — the same limitation window geometry (`ppm-windows`) already has.
|
|
2315
|
+
`WINDOW_KINDS` (`window-store-types.ts`) is the single list both the window store and
|
|
2316
|
+
`window-persistence.ts` filter against; `team-member` is excluded from restore because its body
|
|
2317
|
+
streams a live subagent session that cannot survive a reload.
|
|
2318
|
+
- **Reconcile.** The two halves persist separately, so a reload can restore one without the other.
|
|
2319
|
+
`reconcileTabHostWindows` (`stores/window-panel-reconcile.ts`), run once per project via
|
|
2320
|
+
`useWindowPanelReconcile()` after the window layer restores, and unconditionally below `md` (the
|
|
2321
|
+
window layer never mounts there): a panel whose window is gone comes back to the grid; a window
|
|
2322
|
+
with no panel behind it closes.
|
|
2323
|
+
- **PiP host.** `attachPipHost`/`isDocumentPipSupported` (`floating-window/pip/pip-host.ts`,
|
|
2324
|
+
`pip-support.ts`) move a window's *slot* element — never a tab's own wrapper — into a
|
|
2325
|
+
`documentPictureInPicture` window, one at a time per page. `pagehide` triggers a synchronous
|
|
2326
|
+
restore (no `await` between it and the DOM move) so a closing PiP document never strips listeners
|
|
2327
|
+
off a still-live terminal. `pip-style-copy.ts` mirrors stylesheets + `adoptedStyleSheets` once and
|
|
2328
|
+
`<html>` class/inline theme CSS vars + `<body>` class **and inline style** on every theme change
|
|
2329
|
+
(the page background is an inline `background: var(--bg)` on `<body>` in `index.html`, not a
|
|
2330
|
+
class), plus a MutationObserver for Vite HMR-injected `<style>` tags. `pip-key-forward.ts`
|
|
2331
|
+
re-dispatches keydown/keyup from the PiP window onto the main window for app-level shortcuts,
|
|
2332
|
+
skipping targets that own their own input (`input`, `.monaco-editor`, `.xterm-helper-textarea`,
|
|
2333
|
+
etc.). `pip-resize-signal.ts` dispatches a non-bubbling `ppm:host-resize` CustomEvent on each
|
|
2334
|
+
`[data-tab-pool-id]` wrapper inside the slot (on attach, every PiP `resize`, and on detach); the
|
|
2335
|
+
terminal and editors subscribe via `onHostResize` and re-fit, because main-window
|
|
2336
|
+
`ResizeObserver`s are late or silent for a PiP-driven size.
|
|
2337
|
+
- **Radix portals in PiP.** `PortalContainerProvider` (`components/ui/portal-container-context.tsx`)
|
|
2338
|
+
is mounted inside `ReparentingTab` around each tab's content, fed the PiP document's `body` while
|
|
2339
|
+
that tab's window is in PiP (`usePipPortalContainer`, `window-pip-registry.ts`) — so a tab's own
|
|
2340
|
+
dropdowns/tooltips/dialogs render inside the PiP document instead of opening unreachably in the
|
|
2341
|
+
main window. `undefined` (document default) while docked.
|
|
2342
|
+
- **Known limitations** (see the comment block atop `pip/pip-caption-button.tsx`): sonner toasts
|
|
2343
|
+
always render in the main window (one app-root toaster); `useIsMobile()`/Tailwind `md:` read the
|
|
2344
|
+
main window's viewport, not the PiP window's; `onSelect`/`selectionchange` degrades for PiP
|
|
2345
|
+
content; the terminal's reconnect check reads the main document's visibility; Monaco keybindings
|
|
2346
|
+
(Ctrl+Z, Ctrl+F, …) don't fire while the editor sits in PiP (typing still reaches the buffer); a
|
|
2347
|
+
tab-host window's titlebar keeps the tab title captured at pop-out time.
|
|
2348
|
+
- **Mobile.** Pop-out and PiP are hidden entirely below `md` (`useIsMobile()`) — never a scaled-down
|
|
2349
|
+
window.
|
|
2273
2350
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hienlh/ppm",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.12",
|
|
4
4
|
"description": "Personal Project Manager  mobile-first web IDE with AI assistance",
|
|
5
5
|
"author": "hienlh",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -77,8 +77,11 @@ export function FilePicker({
|
|
|
77
77
|
const handler = (e: globalThis.KeyboardEvent) => {
|
|
78
78
|
if (handleKeyDown(e)) e.stopPropagation();
|
|
79
79
|
};
|
|
80
|
-
document
|
|
81
|
-
|
|
80
|
+
// The list's own document — in a picture-in-picture window the keys are
|
|
81
|
+
// delivered there, not to the main document.
|
|
82
|
+
const doc = listRef.current?.ownerDocument ?? document;
|
|
83
|
+
doc.addEventListener("keydown", handler, true);
|
|
84
|
+
return () => doc.removeEventListener("keydown", handler, true);
|
|
82
85
|
}, [visible, handleKeyDown]);
|
|
83
86
|
|
|
84
87
|
if (!visible || filtered.length === 0) return null;
|
|
@@ -39,8 +39,11 @@ export function ModeSelector({ value, onChange, open, onOpenChange }: ModeSelect
|
|
|
39
39
|
onOpenChange(false);
|
|
40
40
|
}
|
|
41
41
|
};
|
|
42
|
-
document
|
|
43
|
-
|
|
42
|
+
// The panel's own document — in a picture-in-picture window the main
|
|
43
|
+
// document never sees these clicks, so the panel would never close.
|
|
44
|
+
const doc = panelRef.current?.ownerDocument ?? document;
|
|
45
|
+
doc.addEventListener("mousedown", handler);
|
|
46
|
+
return () => doc.removeEventListener("mousedown", handler);
|
|
44
47
|
}, [open, onOpenChange]);
|
|
45
48
|
|
|
46
49
|
// Focus current mode on open
|
|
@@ -50,8 +50,11 @@ export function ModelSelector({ value, onChange, projectName, providerId, disabl
|
|
|
50
50
|
setOpen(false);
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
|
-
document
|
|
54
|
-
|
|
53
|
+
// The panel's own document — in a picture-in-picture window the main
|
|
54
|
+
// document never sees these clicks, so the panel would never close.
|
|
55
|
+
const doc = panelRef.current?.ownerDocument ?? document;
|
|
56
|
+
doc.addEventListener("mousedown", handler);
|
|
57
|
+
return () => doc.removeEventListener("mousedown", handler);
|
|
55
58
|
}, [open]);
|
|
56
59
|
|
|
57
60
|
// Focus current on open
|
|
@@ -69,8 +69,11 @@ export function ModelThinkingSelector({
|
|
|
69
69
|
const handler = (e: MouseEvent) => {
|
|
70
70
|
if (panelRef.current && !panelRef.current.contains(e.target as Node)) setOpen(false);
|
|
71
71
|
};
|
|
72
|
-
document
|
|
73
|
-
|
|
72
|
+
// The panel's own document — in a picture-in-picture window the main
|
|
73
|
+
// document never sees these clicks, so the panel would never close.
|
|
74
|
+
const doc = panelRef.current?.ownerDocument ?? document;
|
|
75
|
+
doc.addEventListener("mousedown", handler);
|
|
76
|
+
return () => doc.removeEventListener("mousedown", handler);
|
|
74
77
|
}, [open, isMobile]);
|
|
75
78
|
|
|
76
79
|
const current = models.find((m) => m.value === model);
|
|
@@ -45,8 +45,11 @@ export function ProviderSelector({ value, onChange, projectName }: ProviderSelec
|
|
|
45
45
|
setOpen(false);
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
|
-
document
|
|
49
|
-
|
|
48
|
+
// The panel's own document — in a picture-in-picture window the main
|
|
49
|
+
// document never sees these clicks, so the panel would never close.
|
|
50
|
+
const doc = panelRef.current?.ownerDocument ?? document;
|
|
51
|
+
doc.addEventListener("mousedown", handler);
|
|
52
|
+
return () => doc.removeEventListener("mousedown", handler);
|
|
50
53
|
}, [open]);
|
|
51
54
|
|
|
52
55
|
// Focus current on open
|
|
@@ -117,8 +117,11 @@ export function SlashCommandPicker({
|
|
|
117
117
|
const handler = (e: globalThis.KeyboardEvent) => {
|
|
118
118
|
if (handleKeyDown(e)) e.stopPropagation();
|
|
119
119
|
};
|
|
120
|
-
document
|
|
121
|
-
|
|
120
|
+
// The list's own document — in a picture-in-picture window the keys are
|
|
121
|
+
// delivered there, not to the main document.
|
|
122
|
+
const doc = listRef.current?.ownerDocument ?? document;
|
|
123
|
+
doc.addEventListener("keydown", handler, true);
|
|
124
|
+
return () => doc.removeEventListener("keydown", handler, true);
|
|
122
125
|
}, [visible, handleKeyDown]);
|
|
123
126
|
|
|
124
127
|
const handleRefresh = useCallback(() => {
|
|
@@ -22,6 +22,7 @@ import type { DbQueryResult } from "../database/use-database";
|
|
|
22
22
|
// Single source of truth: the explorer decides whether a double-click can open a file at
|
|
23
23
|
// all from these very sets, so they must not be redeclared here.
|
|
24
24
|
import { AUDIO_EXTS, IMAGE_EXTS, SQLITE_EXTS, VIDEO_EXTS } from "@/components/os-explorer/can-open-in-ppm";
|
|
25
|
+
import { onHostResize } from "@/components/floating-window/pip/pip-resize-signal";
|
|
25
26
|
|
|
26
27
|
const MarkdownRenderer = lazy(() =>
|
|
27
28
|
import("@/components/shared/markdown-renderer").then((m) => ({ default: m.MarkdownRenderer }))
|
|
@@ -247,6 +248,12 @@ export const CodeEditor = memo(function CodeEditor({ metadata, tabId }: CodeEdit
|
|
|
247
248
|
};
|
|
248
249
|
}, [isMobile]);
|
|
249
250
|
|
|
251
|
+
// Host-driven resize (picture-in-picture): `automaticLayout` never fires for
|
|
252
|
+
// a size driven by another document, and after the return the editor keeps
|
|
253
|
+
// the PiP size until it is told to lay out again.
|
|
254
|
+
// Re-runs on loading/error because the container only exists once the file rendered.
|
|
255
|
+
useEffect(() => onHostResize(containerRef.current, () => editorRef.current?.layout()), [loading, error]);
|
|
256
|
+
|
|
250
257
|
// CodeLens: inline Run buttons between SQL statements
|
|
251
258
|
const codeLensDisposable = useRef<MonacoType.IDisposable[]>([]);
|
|
252
259
|
const runSqlRef = useRef(runSqlInViewer);
|
|
@@ -820,10 +827,13 @@ function SqlResultPanel({ result, error, loading, connName, onClose, onOpenInTab
|
|
|
820
827
|
e.preventDefault();
|
|
821
828
|
const startY = e.clientY;
|
|
822
829
|
const startH = panelHeight;
|
|
830
|
+
// The handle's own document — the editor may be living in a PiP window,
|
|
831
|
+
// where the main document never sees these pointer events.
|
|
832
|
+
const doc = e.currentTarget.ownerDocument;
|
|
823
833
|
const onMove = (ev: MouseEvent) => setPanelHeight(Math.max(80, startH + (startY - ev.clientY)));
|
|
824
|
-
const onUp = () => {
|
|
825
|
-
|
|
826
|
-
|
|
834
|
+
const onUp = () => { doc.removeEventListener("mousemove", onMove); doc.removeEventListener("mouseup", onUp); };
|
|
835
|
+
doc.addEventListener("mousemove", onMove);
|
|
836
|
+
doc.addEventListener("mouseup", onUp);
|
|
827
837
|
}, [panelHeight]);
|
|
828
838
|
|
|
829
839
|
return (
|
|
@@ -5,6 +5,7 @@ import { api, projectUrl } from "@/lib/api-client";
|
|
|
5
5
|
import { useShallow } from "zustand/react/shallow";
|
|
6
6
|
import { useSettingsStore } from "@/stores/settings-store";
|
|
7
7
|
import { useMonacoTheme } from "@/lib/use-monaco-theme";
|
|
8
|
+
import { onHostResize } from "@/components/floating-window/pip/pip-resize-signal";
|
|
8
9
|
import { Loader2 } from "lucide-react";
|
|
9
10
|
|
|
10
11
|
function getMonacoLanguage(filename: string): string {
|
|
@@ -117,6 +118,14 @@ export function ConflictEditor({ metadata }: ConflictEditorProps) {
|
|
|
117
118
|
return () => ro.disconnect();
|
|
118
119
|
}, []);
|
|
119
120
|
|
|
121
|
+
// Host-driven resize (picture-in-picture): `automaticLayout` never fires for a
|
|
122
|
+
// size driven by another document, and the editor keeps the PiP size after the
|
|
123
|
+
// return. Re-runs on loading/error because the container renders only then.
|
|
124
|
+
useEffect(
|
|
125
|
+
() => onHostResize(containerRef.current, () => editorRef.current?.layout()),
|
|
126
|
+
[loading, error],
|
|
127
|
+
);
|
|
128
|
+
|
|
120
129
|
// Load file content
|
|
121
130
|
useEffect(() => {
|
|
122
131
|
if (!filePath || !projectName) return;
|
|
@@ -4,6 +4,7 @@ import { api, projectUrl } from "@/lib/api-client";
|
|
|
4
4
|
import { useShallow } from "zustand/react/shallow";
|
|
5
5
|
import { useSettingsStore } from "@/stores/settings-store";
|
|
6
6
|
import { useMonacoTheme } from "@/lib/use-monaco-theme";
|
|
7
|
+
import { onHostResize } from "@/components/floating-window/pip/pip-resize-signal";
|
|
7
8
|
import { Loader2, FileCode, WrapText } from "lucide-react";
|
|
8
9
|
|
|
9
10
|
function getMonacoLanguage(filename: string): string {
|
|
@@ -60,6 +61,14 @@ export function DiffViewer({ metadata }: DiffViewerProps) {
|
|
|
60
61
|
return () => ro.disconnect();
|
|
61
62
|
}, [loading, error]);
|
|
62
63
|
|
|
64
|
+
// Host-driven resize (picture-in-picture): `automaticLayout` never fires for a
|
|
65
|
+
// size driven by another document, and the editor keeps the PiP size after the
|
|
66
|
+
// return. Re-runs on loading/error because the container renders only then.
|
|
67
|
+
useEffect(
|
|
68
|
+
() => onHostResize(containerRef.current, () => diffEditorRef.current?.layout()),
|
|
69
|
+
[loading, error],
|
|
70
|
+
);
|
|
71
|
+
|
|
63
72
|
useEffect(() => {
|
|
64
73
|
if (isInline) return;
|
|
65
74
|
if (!projectName) return;
|
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* One floating window: geometry, gestures, keyboard,
|
|
2
|
+
* One floating window: geometry, gestures, keyboard, the skinned chrome, and the body
|
|
3
|
+
* element every kind renders into.
|
|
3
4
|
*
|
|
4
5
|
* Geometry is written straight to the element instead of through React state — a drag emits
|
|
5
6
|
* a pointermove per frame and re-rendering the window (and its content) on each one is what
|
|
6
7
|
* makes a window manager feel heavy. The store is written only when a gesture ends, which is
|
|
7
8
|
* also the moment the rect is rounded to whole pixels.
|
|
9
|
+
*
|
|
10
|
+
* Picture-in-picture is a capability of the FRAME, not of any one kind: the body element is
|
|
11
|
+
* published as this window's PiP slot, so an explorer, a system monitor, a team-member
|
|
12
|
+
* session and a detached tab all pop out through the same titlebar button.
|
|
8
13
|
*/
|
|
9
14
|
|
|
10
15
|
import { useCallback, useLayoutEffect, useRef, useState, type ReactNode } from "react";
|
|
16
|
+
import { createPortal } from "react-dom";
|
|
11
17
|
import { cn } from "@/lib/utils";
|
|
12
|
-
import {
|
|
13
|
-
import { TITLEBAR_HEIGHT
|
|
18
|
+
import { PortalContainerProvider } from "@/components/ui/portal-container-context";
|
|
19
|
+
import { TITLEBAR_HEIGHT } from "./window-chrome-contract";
|
|
20
|
+
import { useWindowBodyElement } from "./use-window-body-element";
|
|
21
|
+
import { WindowPipPlaceholder } from "./window-pip-placeholder";
|
|
22
|
+
import { WindowSkinChrome } from "./window-skin-chrome";
|
|
14
23
|
import { windowZIndex, type Bounds, type Rect } from "./window-geometry";
|
|
15
24
|
import { useWindowStore, type WindowRuntimeState } from "./window-store";
|
|
16
25
|
import { useWindowDrag } from "./use-window-drag";
|
|
@@ -28,8 +37,6 @@ export interface FloatingWindowProps {
|
|
|
28
37
|
getScale: () => number;
|
|
29
38
|
/** Told when a gesture starts/ends so the layer can raise its capture overlay. */
|
|
30
39
|
onGestureActive: (active: boolean) => void;
|
|
31
|
-
/** Skin component for the titlebar; owns its own hooks and state. */
|
|
32
|
-
chrome?: WindowChrome;
|
|
33
40
|
children: ReactNode;
|
|
34
41
|
}
|
|
35
42
|
|
|
@@ -47,7 +54,6 @@ export function FloatingWindow({
|
|
|
47
54
|
focused,
|
|
48
55
|
getScale,
|
|
49
56
|
onGestureActive,
|
|
50
|
-
chrome,
|
|
51
57
|
children,
|
|
52
58
|
}: FloatingWindowProps) {
|
|
53
59
|
const rootRef = useRef<HTMLDivElement>(null);
|
|
@@ -57,6 +63,8 @@ export function FloatingWindow({
|
|
|
57
63
|
const minimized = win.state === "minimized";
|
|
58
64
|
const rect: Rect = maximized ? { x: 0, y: 0, w: bounds.w, h: bounds.h } : win.rect;
|
|
59
65
|
|
|
66
|
+
const { body, pip } = useWindowBodyElement(win.id, rootRef, minimized);
|
|
67
|
+
|
|
60
68
|
// Latest committed geometry, read at the first frame of a gesture (never mid-gesture,
|
|
61
69
|
// where it would compound the cumulative movement).
|
|
62
70
|
const rectRef = useRef(rect);
|
|
@@ -112,8 +120,6 @@ export function FloatingWindow({
|
|
|
112
120
|
movable: !maximized,
|
|
113
121
|
});
|
|
114
122
|
|
|
115
|
-
const Chrome = chrome ?? DefaultWindowChrome;
|
|
116
|
-
|
|
117
123
|
return (
|
|
118
124
|
<div
|
|
119
125
|
ref={rootRef}
|
|
@@ -131,7 +137,7 @@ export function FloatingWindow({
|
|
|
131
137
|
gesturing ? "transition-none" : "transition-[transform,width,height] duration-150 motion-reduce:transition-none",
|
|
132
138
|
)}
|
|
133
139
|
>
|
|
134
|
-
<
|
|
140
|
+
<WindowSkinChrome
|
|
135
141
|
id={win.id}
|
|
136
142
|
kind={win.kind}
|
|
137
143
|
title={title}
|
|
@@ -152,16 +158,18 @@ export function FloatingWindow({
|
|
|
152
158
|
onClose={close}
|
|
153
159
|
/>
|
|
154
160
|
|
|
155
|
-
|
|
156
|
-
{/* Always mounted, even minimized — content owns per-window state (explorer history,
|
|
157
|
-
selection, filter) that a remount would wipe. Hidden via CSS, not unmounted. */}
|
|
158
|
-
<div className={cn("relative flex-1 min-h-0 overflow-hidden rounded-b-[8px] bg-panel", minimized && "hidden")}>
|
|
159
|
-
{children}
|
|
160
|
-
</div>
|
|
161
|
+
{pip && <WindowPipPlaceholder pip={pip} minimized={minimized} />}
|
|
161
162
|
|
|
162
163
|
{!maximized && !minimized && (
|
|
163
164
|
<WindowResizeHandles bind={(handle) => bindResize(handle) as Record<string, unknown>} />
|
|
164
165
|
)}
|
|
166
|
+
|
|
167
|
+
{/* Radix primitives inside the content must portal into whichever document the body
|
|
168
|
+
currently lives in; `undefined` (never `null`) restores the document default. */}
|
|
169
|
+
{createPortal(
|
|
170
|
+
<PortalContainerProvider container={pip?.pipWindow.document.body}>{children}</PortalContainerProvider>,
|
|
171
|
+
body,
|
|
172
|
+
)}
|
|
165
173
|
</div>
|
|
166
174
|
);
|
|
167
175
|
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Titlebar button that moves a floating window's body into a Document Picture-in-Picture
|
|
3
|
+
* window and back. Every skin renders it, so every window kind gets the capability — the
|
|
4
|
+
* skin only supplies the box (`className`) that matches its own caption metric.
|
|
5
|
+
*
|
|
6
|
+
* The button is absent, never disabled, where the API is missing (Firefox, Safari, any
|
|
7
|
+
* non-secure context) — a caption button that only ever explains itself is worse than no
|
|
8
|
+
* button at all.
|
|
9
|
+
*
|
|
10
|
+
* Known limitations while a window's body runs in PiP; expected behaviour, not regressions:
|
|
11
|
+
* - Toasts render in the main window. Sonner mounts one toaster at the app root and it
|
|
12
|
+
* stays there, so a message raised from the PiP body appears behind it.
|
|
13
|
+
* - `useIsMobile()` and Tailwind `md:` variants read the MAIN window's viewport, so the
|
|
14
|
+
* content keeps its desktop layout in a narrow PiP window instead of switching to mobile.
|
|
15
|
+
* - React's `onSelect`/`selectionchange` is delegated from the document the app root is
|
|
16
|
+
* mounted in; selection-driven UI degrades for content living in the PiP document.
|
|
17
|
+
* - `use-terminal`'s reconnect check reads the main document's visibility, so a hidden
|
|
18
|
+
* main tab is treated as hidden even while its terminal is visible in PiP.
|
|
19
|
+
* - Monaco chords (Ctrl+Z, Ctrl+F, …) do not fire while the editor sits in PiP: typing
|
|
20
|
+
* reaches the buffer, but the keybinding dispatcher listens on the window the editor was
|
|
21
|
+
* created in. Undo works again as soon as the body is brought back.
|
|
22
|
+
* - A tab-host titlebar shows the tab title captured at pop-out time; a tab renamed
|
|
23
|
+
* afterwards (a chat acquiring a name) keeps the old caption until it is popped out again.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { PictureInPicture2 } from "lucide-react";
|
|
27
|
+
import { toast } from "sonner";
|
|
28
|
+
import { cn } from "@/lib/utils";
|
|
29
|
+
import { TITLEBAR_HEIGHT } from "../window-chrome-contract";
|
|
30
|
+
import { useWindowStore } from "../window-store";
|
|
31
|
+
import { setWindowPip, windowPip, windowSlot, useWindowPip } from "../window-pip-registry";
|
|
32
|
+
import { activePipHost, attachPipHost } from "./pip-host";
|
|
33
|
+
import { focusPipDocument } from "./pip-focus-target";
|
|
34
|
+
import { isDocumentPipSupported } from "./pip-support";
|
|
35
|
+
|
|
36
|
+
export interface PipCaptionButtonProps {
|
|
37
|
+
/** Window id — the registry key for both the body element and the resulting handle. */
|
|
38
|
+
id: string;
|
|
39
|
+
/** The skin's caption-button box. Defaults to a compact icon button. */
|
|
40
|
+
className?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const DEFAULT_BOX =
|
|
44
|
+
"grid place-items-center size-6 rounded text-text-2 can-hover:hover:bg-surface-elevated can-hover:hover:text-text transition-colors";
|
|
45
|
+
|
|
46
|
+
export function PipCaptionButton({ id, className }: PipCaptionButtonProps) {
|
|
47
|
+
const pip = useWindowPip(id);
|
|
48
|
+
|
|
49
|
+
if (!isDocumentPipSupported()) return null;
|
|
50
|
+
|
|
51
|
+
const togglePip = () => {
|
|
52
|
+
const active = windowPip(id);
|
|
53
|
+
if (active) {
|
|
54
|
+
active.detach();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const slot = windowSlot(id);
|
|
59
|
+
if (!slot) {
|
|
60
|
+
toast.error("This window has nothing to pop out yet");
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const rect = useWindowStore.getState().windows[id]?.rect;
|
|
64
|
+
|
|
65
|
+
// attachPipHost() is the first call that can consume the click's transient
|
|
66
|
+
// activation; anything awaited before it costs the gesture and the request is
|
|
67
|
+
// rejected. Only synchronous store/registry reads may precede it. The PiP window
|
|
68
|
+
// shows the body alone, so the titlebar comes off the requested height.
|
|
69
|
+
attachPipHost(slot, {
|
|
70
|
+
// A zero falls through to the host's minimum size rather than a magic default.
|
|
71
|
+
width: rect?.w ?? 0,
|
|
72
|
+
height: rect ? rect.h - TITLEBAR_HEIGHT : 0,
|
|
73
|
+
onDetach: () => setWindowPip(id, null),
|
|
74
|
+
})
|
|
75
|
+
.then((handle) => {
|
|
76
|
+
// The window can be closed before this resolves, in which case onDetach has
|
|
77
|
+
// already cleared the state and storing the handle would strand a dead one.
|
|
78
|
+
// A null handle is that same case, detected inside the host. The slot check
|
|
79
|
+
// covers a body that unmounted and came back: the new one is not this one.
|
|
80
|
+
if (!handle || activePipHost() !== handle) return;
|
|
81
|
+
if (windowSlot(id) !== slot) {
|
|
82
|
+
handle.detach();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
setWindowPip(id, handle);
|
|
86
|
+
// A DOM move carries no focus with it: without this the popped-out terminal or
|
|
87
|
+
// editor is visible but swallows nothing until the user clicks it.
|
|
88
|
+
focusPipDocument(handle.pipWindow.document);
|
|
89
|
+
})
|
|
90
|
+
.catch(() => {
|
|
91
|
+
toast.error("Could not open the picture-in-picture window");
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const label = pip ? "Bring back from picture-in-picture" : "Open in picture-in-picture";
|
|
96
|
+
return (
|
|
97
|
+
<button
|
|
98
|
+
type="button"
|
|
99
|
+
title={label}
|
|
100
|
+
aria-label={label}
|
|
101
|
+
aria-pressed={Boolean(pip)}
|
|
102
|
+
className={cn(className ?? DEFAULT_BOX, pip && "text-primary")}
|
|
103
|
+
onClick={togglePip}
|
|
104
|
+
>
|
|
105
|
+
<PictureInPicture2 className="size-3.5" />
|
|
106
|
+
</button>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Picks what to focus inside a freshly opened PiP window.
|
|
3
|
+
*
|
|
4
|
+
* Moving a subtree into another document does not move focus with it, so a popped-out
|
|
5
|
+
* terminal or editor would sit there swallowing nothing until the user clicked it. The
|
|
6
|
+
* order below is "the thing you type into first": xterm's hidden helper textarea, Monaco's
|
|
7
|
+
* edit context or textarea, then any other text surface, and only then the first focusable
|
|
8
|
+
* control.
|
|
9
|
+
*
|
|
10
|
+
* A panel slot can hold several tabs (the inactive ones are `display: none`), so hidden
|
|
11
|
+
* candidates are skipped — focusing one of those steals input from the visible tab.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** The subset of an element this module touches; keeps the helper testable without a DOM. */
|
|
15
|
+
export interface FocusCandidate {
|
|
16
|
+
focus(): void;
|
|
17
|
+
checkVisibility?(): boolean;
|
|
18
|
+
readonly offsetParent?: unknown;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Text surfaces first, in the order a user would expect to type into them. */
|
|
22
|
+
export const PIP_FOCUS_SELECTORS = [
|
|
23
|
+
".xterm-helper-textarea",
|
|
24
|
+
".native-edit-context",
|
|
25
|
+
"textarea",
|
|
26
|
+
"[contenteditable]",
|
|
27
|
+
'button, [href], input, select, [tabindex]:not([tabindex="-1"])',
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
function isVisible(el: FocusCandidate): boolean {
|
|
31
|
+
// checkVisibility() is the accurate answer (display, content-visibility, hidden
|
|
32
|
+
// attribute) and exists wherever Document PiP does; offsetParent is the fallback
|
|
33
|
+
// for a test double or an older engine.
|
|
34
|
+
if (typeof el.checkVisibility === "function") return el.checkVisibility();
|
|
35
|
+
return el.offsetParent !== null && el.offsetParent !== undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* First visible match for the selector list, or null.
|
|
40
|
+
*
|
|
41
|
+
* Takes a query function rather than a root node so the caller keeps its own element type
|
|
42
|
+
* (`doc.querySelectorAll<HTMLElement>`) and a test can pass a plain fake.
|
|
43
|
+
*/
|
|
44
|
+
export function pipFocusTarget<T extends FocusCandidate>(
|
|
45
|
+
query: (selector: string) => Iterable<T>,
|
|
46
|
+
): T | null {
|
|
47
|
+
for (const selector of PIP_FOCUS_SELECTORS) {
|
|
48
|
+
for (const el of query(selector)) {
|
|
49
|
+
if (isVisible(el)) return el;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Focus the popped-out tab's primary input so the user can type straight away. */
|
|
56
|
+
export function focusPipDocument(doc: Document): void {
|
|
57
|
+
pipFocusTarget<HTMLElement>((selector) => doc.querySelectorAll<HTMLElement>(selector))?.focus();
|
|
58
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Size math for the PiP window request.
|
|
3
|
+
*
|
|
4
|
+
* Kept free of DOM reads (the screen bounds are an argument) so it is unit
|
|
5
|
+
* testable and so a caller can pass a floating window rect straight through.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface PipSize {
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Below this a terminal/editor is unusable, and Chromium rejects tiny sizes. */
|
|
14
|
+
export const MIN_PIP_WIDTH = 320;
|
|
15
|
+
export const MIN_PIP_HEIGHT = 240;
|
|
16
|
+
|
|
17
|
+
/** Fallback bounds when no screen is available (SSR, tests). */
|
|
18
|
+
const FALLBACK_BOUNDS: PipSize = { width: 1920, height: 1080 };
|
|
19
|
+
|
|
20
|
+
function clampAxis(value: number, min: number, max: number): number {
|
|
21
|
+
// Non-finite input (NaN from an unmeasured rect) collapses to the minimum
|
|
22
|
+
// rather than propagating into the request.
|
|
23
|
+
if (!Number.isFinite(value)) return min;
|
|
24
|
+
return Math.round(Math.min(Math.max(value, min), Math.max(min, max)));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Read the usable screen area; safe to call without a window. */
|
|
28
|
+
export function screenBounds(): PipSize {
|
|
29
|
+
if (typeof window === "undefined" || !window.screen) return FALLBACK_BOUNDS;
|
|
30
|
+
const { availWidth, availHeight } = window.screen;
|
|
31
|
+
return {
|
|
32
|
+
width: Number.isFinite(availWidth) && availWidth > 0 ? availWidth : FALLBACK_BOUNDS.width,
|
|
33
|
+
height: Number.isFinite(availHeight) && availHeight > 0 ? availHeight : FALLBACK_BOUNDS.height,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Clamp a requested inner size to [min, screen] and round to whole CSS px.
|
|
39
|
+
* Chromium may still ignore the hint entirely — never assume the result.
|
|
40
|
+
*/
|
|
41
|
+
export function clampPipSize(size: PipSize, bounds: PipSize = screenBounds()): PipSize {
|
|
42
|
+
return {
|
|
43
|
+
width: clampAxis(size.width, MIN_PIP_WIDTH, bounds.width),
|
|
44
|
+
height: clampAxis(size.height, MIN_PIP_HEIGHT, bounds.height),
|
|
45
|
+
};
|
|
46
|
+
}
|