wiki-viewer 1.9.1 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +3 -0
- package/.next/standalone/.next/build-manifest.json +5 -5
- package/.next/standalone/.next/routes-manifest.json +22 -0
- package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/_global-error/page.js +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/_not-found/page/next-font-manifest.json +7 -1
- package/.next/standalone/.next/server/app/_not-found/page.js +2 -2
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/agent/activity/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/admin/agents/[agentId]/revoke/route.js +1 -1
- package/.next/standalone/.next/server/app/api/agent/admin/agents/[agentId]/revoke/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/admin/agents/route.js +1 -1
- package/.next/standalone/.next/server/app/api/agent/admin/agents/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js +3 -4
- package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js +10 -11
- package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js +4 -5
- package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/move/route.js +3 -4
- package/.next/standalone/.next/server/app/api/agent/fs/move/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/search/route.js +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/internal/span/route.js +3 -4
- package/.next/standalone/.next/server/app/api/agent/internal/span/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/settings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js +3 -4
- package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/app-proxy/[...path]/route.js +1 -1
- package/.next/standalone/.next/server/app/api/app-proxy/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/assets/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/[...all]/route.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/[...all]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/share/[token]/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/share/[token]/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/share/[token]/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/share/[token]/route.js +14 -0
- package/.next/standalone/.next/server/app/api/share/[token]/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/share/[token]/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/share/[token]/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/share/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/share/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/share/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/share/route.js +14 -0
- package/.next/standalone/.next/server/app/api/share/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/share/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/share/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/system/browse/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/clear-root/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/reveal/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/root-status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/set-root/route.js +2 -2
- package/.next/standalone/.next/server/app/api/system/set-root/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/upload/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/app/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/content/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/download/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/file/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/folder/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/move/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/new-file/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/page/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/presence/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/slugs/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/upload/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/watch/route.js +1 -1
- package/.next/standalone/.next/server/app/api/wiki/watch/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +9 -3
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +9 -3
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +8 -2
- package/.next/standalone/.next/server/app/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/page/next-font-manifest.json +7 -1
- package/.next/standalone/.next/server/app/page.js +2 -2
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/s/[token]/page/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/s/[token]/page/build-manifest.json +16 -0
- package/.next/standalone/.next/server/app/s/[token]/page/next-font-manifest.json +16 -0
- package/.next/standalone/.next/server/app/s/[token]/page/react-loadable-manifest.json +1 -0
- package/.next/standalone/.next/server/app/s/[token]/page/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/s/[token]/page.js +14 -0
- package/.next/standalone/.next/server/app/s/[token]/page.js.map +5 -0
- package/.next/standalone/.next/server/app/s/[token]/page.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/s/[token]/page_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/signin/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/signin/page/next-font-manifest.json +7 -1
- package/.next/standalone/.next/server/app/signin/page.js +3 -3
- package/.next/standalone/.next/server/app/signin/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/signin/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/chunks/0dti_kysely_dist_esm_0u.fq2l._.js +1 -1
- package/.next/standalone/.next/server/chunks/0p91_next_dist_esm_build_templates_app-route_0d2jbo5.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__01hp8ax._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__02scxiu._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__07nnfjx._.js +16 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__12q8ch8._.js → [root-of-the-server]__08n~vj1._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__09s9qkd._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__12ee_s6._.js → [root-of-the-server]__0bfl4v7._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l-8clq._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0n3i3vu._.js +16 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ncjv3e._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0s8ovh5._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0~.-3yk._.js → [root-of-the-server]__0x3m4up._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0yzle76._.js +20 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0z.pwwj._.js +20 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zgb.q2._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__00qu86p._.js → [root-of-the-server]__0zq0rlw._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-inabx._.js → [root-of-the-server]__12y5z5j._.js} +2 -2
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_share_[token]_route_actions_0~m-o26.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_share_route_actions_0gz4h.j.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules__pnpm_0aj5g-w._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_lib_auth_admin_ts_0g4i6v_._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/08s9_dagre-d3-es_src_dagre_index_0iwjukf.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/0p91_next_dist_esm_build_templates_app-page_0p1dt3f.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{0~w0_katex_dist_katex_mjs_0hyln.b._.js → 0~w0_katex_dist_katex_mjs_03n1kec._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_chunk-5ZQYHXKU_mjs_0z1.978._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_chunk-KSCS5N6A_mjs_0v4oeem._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_diagram-OG6HWLK6_mjs_0t5sus6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_erDiagram-TEJ5UH35_mjs_0v6rnqy._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_sankeyDiagram-5OEKKPKP_mjs_11ifrnu._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_mermaid_core_mjs_0hj_n-~._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__02twzph._.js → [root-of-the-server]__00_67m6._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__00lk0r~._.js → [root-of-the-server]__06mzg2t._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0du58sw._.js → [root-of-the-server]__0lh.8ub._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oh...2._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0osa2xb._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0txwwn-._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0wmhtx3._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0yevh-d._.js +115 -0
- package/.next/standalone/.next/server/chunks/ssr/_0~a9dyk._.js +115 -0
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_s_[token]_page_actions_0bubzp7.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0iikbcy._.js → node_modules__pnpm_0-ljbo6._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_03z3na-._.js → node_modules__pnpm_0.b51bz._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0qd2ovj._.js → node_modules__pnpm_02z1q6x._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0elpfsb._.js → node_modules__pnpm_06rujwe._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0b5fla7._.js → node_modules__pnpm_07~ezvd._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_03.1jli._.js → node_modules__pnpm_0annbkv._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_0aq-myi._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_00y7foi._.js → node_modules__pnpm_0db-578._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0s4yn43._.js → node_modules__pnpm_0e-h_5v._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0arbjru._.js → node_modules__pnpm_0efhg__._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_09eo8jh._.js → node_modules__pnpm_0fdgk8l._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0d~ida~._.js → node_modules__pnpm_0fy2khf._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0s8fvbn._.js → node_modules__pnpm_0ge9-p_._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0dbr7c2._.js → node_modules__pnpm_0h0n.h9._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0fh.6ir._.js → node_modules__pnpm_0k48w96._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0.~goq~._.js → node_modules__pnpm_0k8t~gn._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0mvih7b._.js → node_modules__pnpm_0kx2gj~._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_0lzb-n~._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0fm6wcx._.js → node_modules__pnpm_0m2aya9._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_05~w-ok._.js → node_modules__pnpm_0rhh2ug._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0beormu._.js → node_modules__pnpm_0s7.cqo._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0adm8h6._.js → node_modules__pnpm_0u2s0ie._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_09d5yyu._.js → node_modules__pnpm_0uhtpu4._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0tq8zs6._.js → node_modules__pnpm_0vn52ck._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0c7u76a._.js → node_modules__pnpm_0z_-o7y._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0xa.ko1._.js → node_modules__pnpm_11li7t8._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0.kyqfq._.js → node_modules__pnpm_12ggywb._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0vyv.lz._.js → node_modules__pnpm_12ohbxv._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_12.ymhl._.js → node_modules__pnpm_12yj7m8._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_app_page_tsx_0ss2.w7._.js +19 -0
- package/.next/standalone/.next/server/edge/chunks/0p91_next_dist_0nh.6nc._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +5 -5
- package/.next/standalone/.next/server/middleware-manifest.json +1 -1
- package/.next/standalone/.next/server/next-font-manifest.js +1 -1
- package/.next/standalone/.next/server/next-font-manifest.json +30 -3
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/static/chunks/02c9264uigqjd.js +1 -0
- package/.next/standalone/.next/static/chunks/03zepg.10g9nk.js +21 -0
- package/.next/standalone/.next/static/chunks/08~wl1f9eyv70.css +5 -0
- package/.next/standalone/.next/static/chunks/0cre2g95gqnc_.js +1 -0
- package/.next/standalone/.next/static/chunks/0dhnx18v._gaq.js +113 -0
- package/.next/standalone/.next/static/chunks/{144e01xuvhx~x.js → 0g5dv59skfo1z.js} +1 -1
- package/.next/standalone/.next/static/chunks/{14n5cp8rr-k_b.js → 0qiz7kkyaxa93.js} +1 -1
- package/.next/standalone/.next/static/chunks/0vhw1us0pjfdy.js +1 -0
- package/.next/standalone/.next/static/chunks/{06iw_iy5e90d4.js → 0vp-ahhagxptc.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0b84.439zffwm.js → 0yhis._5rr6tc.js} +1 -1
- package/.next/standalone/.next/static/chunks/0z1s6bzchqtx3.js +17 -0
- package/.next/standalone/.next/static/chunks/139g2hzko-flp.js +1 -0
- package/.next/standalone/.next/static/chunks/141sj6_6_3ryx.js +113 -0
- package/.next/standalone/.next/static/chunks/{turbopack-0lf4~b-ofzbm6.js → turbopack-12~z-mr7b9b50.js} +1 -1
- package/.next/standalone/.next/static/media/02263ebadd758ea4-s.0qg7j5o.yrclm.woff2 +0 -0
- package/.next/standalone/.next/static/media/0ada71b763703d9d-s.03kpp5fbi.88j.woff2 +0 -0
- package/.next/standalone/.next/static/media/167cd0713aa75522-s.0j1f760ks3~7e.woff2 +0 -0
- package/.next/standalone/.next/static/media/1a69062cfe6f77f8-s.07r2ragk8ph~z.woff2 +0 -0
- package/.next/standalone/.next/static/media/23b7a97ae3b5c134-s.p.0o14nraug8u5s.woff2 +0 -0
- package/.next/standalone/.next/static/media/2b7d3311b69a4dca-s.p.0g6adshk-wxa_.woff2 +0 -0
- package/.next/standalone/.next/static/media/2e95a7d252b9825a-s.0dgq8lqrj3gc_.woff2 +0 -0
- package/.next/standalone/.next/static/media/2fe89d53234c61d4-s.0k_.i63k_i_qa.woff2 +0 -0
- package/.next/standalone/.next/static/media/59b15b4bcd7b1eb5-s.0x08jh8vondwt.woff2 +0 -0
- package/.next/standalone/.next/static/media/5e05ae5b48faa55e-s.0m9hhkgdlzukj.woff2 +0 -0
- package/.next/standalone/.next/static/media/6632a144c419935f-s.02msn089-soa4.woff2 +0 -0
- package/.next/standalone/.next/static/media/68757d6cddeff913-s.0hkrq11n-dhos.woff2 +0 -0
- package/.next/standalone/.next/static/media/6ff74e33ebd7bca3-s.0_n_qwbzcushi.woff2 +0 -0
- package/.next/standalone/.next/static/media/791bf8c4bb753ed6-s.p.0524igg32t-c1.woff2 +0 -0
- package/.next/standalone/.next/static/media/7b27d9904b50e540-s.13-bl75dp544c.woff2 +0 -0
- package/.next/standalone/.next/static/media/99e609270109b47d-s.p.16-z~2sp29ex6.woff2 +0 -0
- package/.next/standalone/.next/static/media/9a4838fcda0d1bca-s.0787d67~10694.woff2 +0 -0
- package/.next/standalone/.next/static/media/a7afbb44bec2bb18-s.0juuwbcf7uz~t.woff2 +0 -0
- package/.next/standalone/.next/static/media/ca8956476e4b15e1-s.08wnys.spqmz-.woff2 +0 -0
- package/.next/standalone/.next/static/media/d38f3bca7db33566-s.p.07n94j49quulv.woff2 +0 -0
- package/.next/standalone/.next/static/media/e390973e931a41c5-s.08hd0g.321csk.woff2 +0 -0
- package/.next/standalone/.next/static/media/e455bcff747f0d5e-s.0lukgm0wyhr0a.woff2 +0 -0
- package/.next/standalone/.next/static/media/e532fa1b9921e1cd-s.0~wrfy7sm-h4g.woff2 +0 -0
- package/.next/standalone/.next/static/media/effe91970fc4db64-s.p.07ig5l8azj~hy.woff2 +0 -0
- package/.next/standalone/docs/editorial-skin-spec.md +242 -0
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/src/app/api/share/[token]/route.ts +269 -0
- package/.next/standalone/src/app/api/share/route.ts +127 -0
- package/.next/standalone/src/app/api/system/workspaces/route.ts +9 -0
- package/.next/standalone/src/app/globals.css +470 -56
- package/.next/standalone/src/app/layout.tsx +29 -2
- package/.next/standalone/src/app/page.tsx +162 -19
- package/.next/standalone/src/app/s/[token]/page.tsx +357 -0
- package/.next/standalone/src/components/ai-panel/ai-panel.tsx +1 -1
- package/.next/standalone/src/components/auth-settings-sheet.tsx +38 -1
- package/.next/standalone/src/components/editor/csv-viewer.tsx +46 -3
- package/.next/standalone/src/components/editor/editor.tsx +14 -6
- package/.next/standalone/src/components/editor/large-file-gate.tsx +108 -0
- package/.next/standalone/src/components/editor/office/xlsx-viewer.tsx +83 -8
- package/.next/standalone/src/components/editor/slash-commands.tsx +2 -2
- package/.next/standalone/src/components/editor/source-viewer.tsx +67 -18
- package/.next/standalone/src/components/share-dialog.tsx +307 -0
- package/.next/standalone/src/components/ui/dialog.tsx +1 -1
- package/.next/standalone/src/components/ui/sheet.tsx +1 -1
- package/.next/standalone/src/components/ui/switch.tsx +1 -1
- package/.next/standalone/src/components/view-width-toggle.tsx +23 -0
- package/.next/standalone/src/lib/shared-docs/db.ts +177 -0
- package/.next/standalone/src/middleware.ts +1 -0
- package/.next/standalone/src/stores/sidebar-width-store.ts +39 -0
- package/.next/standalone/src/stores/skin-store.ts +42 -0
- package/.next/standalone/src/stores/view-width-store.ts +43 -4
- package/.next/standalone/tailwind.config.ts +11 -21
- package/.next/standalone/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-244bv._.js +0 -16
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__012753j._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__03p0ob1._.js +0 -16
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0gda_iu._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jk1uf4._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0nd.b_c._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__13aid91._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hvvps3._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0pqaawz._.js +0 -131
- package/.next/standalone/.next/static/chunks/09-jtayuhrq~b.js +0 -1
- package/.next/standalone/.next/static/chunks/0vp2gi~fq70je.js +0 -21
- package/.next/standalone/.next/static/chunks/125_k3o0s4cid.js +0 -129
- package/.next/standalone/.next/static/chunks/135c~rq_ux73w.js +0 -1
- package/.next/standalone/.next/static/chunks/167ph4xws_-61.css +0 -2
- /package/.next/standalone/.next/static/{NN8w2BNeE9aJeGzUsWJ8G → GCGec_I7i0LnI4YpnaeMc}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{NN8w2BNeE9aJeGzUsWJ8G → GCGec_I7i0LnI4YpnaeMc}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{NN8w2BNeE9aJeGzUsWJ8G → GCGec_I7i0LnI4YpnaeMc}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Download, ExternalLink, FileWarning, FolderOpen } from "lucide-react";
|
|
4
|
+
import { ViewerToolbar } from "@/components/layout/viewer-toolbar";
|
|
5
|
+
import { Button } from "@/components/ui/button";
|
|
6
|
+
import { withWs, wsFetch } from "@/lib/workspace-client";
|
|
7
|
+
|
|
8
|
+
interface LargeFileGateProps {
|
|
9
|
+
path: string;
|
|
10
|
+
size: number;
|
|
11
|
+
/** Mount the real viewer. */
|
|
12
|
+
onOpen: () => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function formatSize(bytes: number): string {
|
|
16
|
+
if (bytes >= 1024 * 1024 * 1024)
|
|
17
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
|
|
18
|
+
if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
19
|
+
if (bytes >= 1024) return `${Math.round(bytes / 1024)} KB`;
|
|
20
|
+
return `${bytes} B`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Confirmation shown before mounting a viewer that loads and renders a whole
|
|
25
|
+
* large file. Sits above the viewer dispatch, so it guards every unsafe viewer
|
|
26
|
+
* in one place. The user can open it anyway, download it, or open the raw bytes.
|
|
27
|
+
*/
|
|
28
|
+
export function LargeFileGate({ path, size, onOpen }: LargeFileGateProps) {
|
|
29
|
+
const assetUrl = withWs(`/api/assets/${path}`);
|
|
30
|
+
const filename = path.split("/").pop() || path;
|
|
31
|
+
const ext = filename.includes(".")
|
|
32
|
+
? filename.split(".").pop()?.toUpperCase()
|
|
33
|
+
: "";
|
|
34
|
+
|
|
35
|
+
const revealInFinder = async () => {
|
|
36
|
+
try {
|
|
37
|
+
await wsFetch("/api/system/reveal", {
|
|
38
|
+
method: "POST",
|
|
39
|
+
headers: { "Content-Type": "application/json" },
|
|
40
|
+
body: JSON.stringify({ path }),
|
|
41
|
+
});
|
|
42
|
+
} catch {
|
|
43
|
+
/* ignore */
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div className="flex-1 flex flex-col overflow-hidden">
|
|
49
|
+
<ViewerToolbar path={path} badge={ext || undefined} />
|
|
50
|
+
<div className="flex-1 flex items-center justify-center">
|
|
51
|
+
<div className="flex flex-col items-center gap-4 text-center max-w-sm">
|
|
52
|
+
<div className="flex size-16 items-center justify-center rounded-2xl bg-amber-500/10">
|
|
53
|
+
<FileWarning className="size-8 text-amber-500" />
|
|
54
|
+
</div>
|
|
55
|
+
<div className="space-y-1">
|
|
56
|
+
<p className="text-sm font-medium">{filename}</p>
|
|
57
|
+
<p className="text-xs text-muted-foreground">
|
|
58
|
+
This file is {formatSize(size)}. Opening it in the viewer may
|
|
59
|
+
freeze the tab while it loads and renders.
|
|
60
|
+
</p>
|
|
61
|
+
</div>
|
|
62
|
+
<div className="flex flex-wrap items-center justify-center gap-2">
|
|
63
|
+
<Button
|
|
64
|
+
variant="default"
|
|
65
|
+
size="sm"
|
|
66
|
+
className="gap-2"
|
|
67
|
+
onClick={onOpen}
|
|
68
|
+
>
|
|
69
|
+
Open anyway
|
|
70
|
+
</Button>
|
|
71
|
+
<Button
|
|
72
|
+
variant="outline"
|
|
73
|
+
size="sm"
|
|
74
|
+
className="gap-2"
|
|
75
|
+
onClick={() => window.open(assetUrl, "_blank")}
|
|
76
|
+
>
|
|
77
|
+
<ExternalLink className="h-4 w-4" />
|
|
78
|
+
Raw
|
|
79
|
+
</Button>
|
|
80
|
+
<Button
|
|
81
|
+
variant="outline"
|
|
82
|
+
size="sm"
|
|
83
|
+
className="gap-2"
|
|
84
|
+
onClick={() => {
|
|
85
|
+
const a = document.createElement("a");
|
|
86
|
+
a.href = assetUrl;
|
|
87
|
+
a.download = filename;
|
|
88
|
+
a.click();
|
|
89
|
+
}}
|
|
90
|
+
>
|
|
91
|
+
<Download className="h-4 w-4" />
|
|
92
|
+
Download
|
|
93
|
+
</Button>
|
|
94
|
+
<Button
|
|
95
|
+
variant="outline"
|
|
96
|
+
size="sm"
|
|
97
|
+
className="gap-2"
|
|
98
|
+
onClick={revealInFinder}
|
|
99
|
+
>
|
|
100
|
+
<FolderOpen className="h-4 w-4" />
|
|
101
|
+
Open in Finder
|
|
102
|
+
</Button>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { Loader2 } from "lucide-react";
|
|
4
4
|
import { wsFetch } from "@/lib/workspace-client";
|
|
5
|
-
import { useEffect, useMemo, useState } from "react";
|
|
5
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
6
6
|
import { cn } from "@/lib/utils";
|
|
7
7
|
import { OfficeChrome } from "./office-chrome";
|
|
8
8
|
|
|
@@ -13,14 +13,48 @@ interface Props {
|
|
|
13
13
|
|
|
14
14
|
interface Sheet {
|
|
15
15
|
name: string;
|
|
16
|
-
|
|
16
|
+
// Built lazily on first view; sheet_to_html over a huge sheet freezes the tab.
|
|
17
|
+
html: string | null;
|
|
18
|
+
rows: number; // total rows, for the truncation banner
|
|
19
|
+
truncated: boolean;
|
|
17
20
|
}
|
|
18
21
|
|
|
22
|
+
// Sheets longer than this are clamped before conversion to cap DOM size.
|
|
23
|
+
const MAX_ROWS = 2000;
|
|
24
|
+
|
|
19
25
|
export function XlsxViewer({ path, title }: Props) {
|
|
20
26
|
const [sheets, setSheets] = useState<Sheet[] | null>(null);
|
|
21
27
|
const [active, setActive] = useState(0);
|
|
22
28
|
const [loading, setLoading] = useState(true);
|
|
23
29
|
const [error, setError] = useState<string | null>(null);
|
|
30
|
+
const wbRef = useRef<{
|
|
31
|
+
wb: import("xlsx").WorkBook;
|
|
32
|
+
toHtml: (ws: import("xlsx").WorkSheet) => {
|
|
33
|
+
html: string;
|
|
34
|
+
rows: number;
|
|
35
|
+
truncated: boolean;
|
|
36
|
+
};
|
|
37
|
+
} | null>(null);
|
|
38
|
+
|
|
39
|
+
// Build the active sheet's HTML the first time it is viewed.
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (!sheets || !wbRef.current) return;
|
|
42
|
+
const s = sheets[active];
|
|
43
|
+
if (!s || s.html !== null) return;
|
|
44
|
+
const { wb, toHtml } = wbRef.current;
|
|
45
|
+
const r = toHtml(wb.Sheets[s.name]);
|
|
46
|
+
setSheets((prev) => {
|
|
47
|
+
if (!prev) return prev;
|
|
48
|
+
const next = [...prev];
|
|
49
|
+
next[active] = {
|
|
50
|
+
...next[active],
|
|
51
|
+
html: r.html,
|
|
52
|
+
rows: r.rows,
|
|
53
|
+
truncated: r.truncated,
|
|
54
|
+
};
|
|
55
|
+
return next;
|
|
56
|
+
});
|
|
57
|
+
}, [sheets, active]);
|
|
24
58
|
|
|
25
59
|
useEffect(() => {
|
|
26
60
|
let cancelled = false;
|
|
@@ -42,12 +76,46 @@ export function XlsxViewer({ path, title }: Props) {
|
|
|
42
76
|
cellDates: true,
|
|
43
77
|
cellStyles: true,
|
|
44
78
|
});
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
79
|
+
// Convert one worksheet to HTML, clamping its row range to MAX_ROWS.
|
|
80
|
+
// Returns the HTML plus whether it was truncated and the true row
|
|
81
|
+
// count. Kept here so it closes over the dynamically-imported XLSX.
|
|
82
|
+
// sheet_to_html has no range option; it honors the sheet's own !ref.
|
|
83
|
+
// For oversized sheets we shrink a copied !ref so only MAX_ROWS emit.
|
|
84
|
+
const toHtml = (ws: import("xlsx").WorkSheet) => {
|
|
85
|
+
const ref = ws["!ref"];
|
|
86
|
+
const range = ref ? XLSX.utils.decode_range(ref) : null;
|
|
87
|
+
const totalRows = range ? range.e.r - range.s.r + 1 : 0;
|
|
88
|
+
if (!range || totalRows <= MAX_ROWS) {
|
|
89
|
+
return {
|
|
90
|
+
html: XLSX.utils.sheet_to_html(ws, { editable: false }),
|
|
91
|
+
rows: totalRows,
|
|
92
|
+
truncated: false,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const clampedWs = {
|
|
96
|
+
...ws,
|
|
97
|
+
"!ref": XLSX.utils.encode_range({
|
|
98
|
+
s: range.s,
|
|
99
|
+
e: { r: range.s.r + MAX_ROWS - 1, c: range.e.c },
|
|
100
|
+
}),
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
html: XLSX.utils.sheet_to_html(clampedWs, { editable: false }),
|
|
104
|
+
rows: totalRows,
|
|
105
|
+
truncated: true,
|
|
106
|
+
};
|
|
107
|
+
};
|
|
49
108
|
if (cancelled) return;
|
|
50
|
-
|
|
109
|
+
// Sheets render lazily via the active-sheet effect, so start them empty.
|
|
110
|
+
wbRef.current = { wb, toHtml };
|
|
111
|
+
setSheets(
|
|
112
|
+
wb.SheetNames.map((name) => ({
|
|
113
|
+
name,
|
|
114
|
+
html: null,
|
|
115
|
+
rows: 0,
|
|
116
|
+
truncated: false,
|
|
117
|
+
})),
|
|
118
|
+
);
|
|
51
119
|
setActive(0);
|
|
52
120
|
setLoading(false);
|
|
53
121
|
} catch (err) {
|
|
@@ -105,7 +173,14 @@ export function XlsxViewer({ path, title }: Props) {
|
|
|
105
173
|
</div>
|
|
106
174
|
</div>
|
|
107
175
|
)}
|
|
108
|
-
{current && (
|
|
176
|
+
{current?.truncated && (
|
|
177
|
+
<div className="px-3 py-2 text-[11px] text-amber-600 dark:text-amber-400 border-b border-border">
|
|
178
|
+
Large sheet ({current.rows.toLocaleString()} rows). Showing first{" "}
|
|
179
|
+
{MAX_ROWS.toLocaleString()} for performance. Download the file to
|
|
180
|
+
see everything.
|
|
181
|
+
</div>
|
|
182
|
+
)}
|
|
183
|
+
{current?.html != null && (
|
|
109
184
|
<div
|
|
110
185
|
className="xlsx-sheet p-3 text-[12px]"
|
|
111
186
|
dangerouslySetInnerHTML={{ __html: current.html }}
|
|
@@ -344,8 +344,8 @@ function CommandPreview({ cmd }: { cmd: SlashCommand }) {
|
|
|
344
344
|
);
|
|
345
345
|
case "Warning":
|
|
346
346
|
return (
|
|
347
|
-
<div className="flex items-start gap-1.5 bg-
|
|
348
|
-
<AlertTriangle className="h-3 w-3 text-
|
|
347
|
+
<div className="flex items-start gap-1.5 bg-warning/10 border border-warning/20 rounded px-2 py-1">
|
|
348
|
+
<AlertTriangle className="h-3 w-3 text-warning shrink-0 mt-0.5" />
|
|
349
349
|
<span className="text-[10px] text-foreground/60">Warning callout</span>
|
|
350
350
|
</div>
|
|
351
351
|
);
|
|
@@ -32,6 +32,19 @@ interface SourceViewerProps {
|
|
|
32
32
|
|
|
33
33
|
const lowlight = createLowlight(common);
|
|
34
34
|
|
|
35
|
+
// Large files skip syntax highlighting (lowlight is synchronous and blocks the
|
|
36
|
+
// main thread) and render in chunks (one <tr> per line freezes the tab).
|
|
37
|
+
const LARGE_BYTES = 2 * 1024 * 1024; // 2 MB
|
|
38
|
+
const LARGE_LINES = 5000;
|
|
39
|
+
const RENDER_CHUNK = 2000; // lines added per "Show more"
|
|
40
|
+
|
|
41
|
+
function escapeHtml(s: string): string {
|
|
42
|
+
return s
|
|
43
|
+
.replace(/&/g, "&")
|
|
44
|
+
.replace(/</g, "<")
|
|
45
|
+
.replace(/>/g, ">");
|
|
46
|
+
}
|
|
47
|
+
|
|
35
48
|
const EXT_TO_LANG: Record<string, string> = {
|
|
36
49
|
".js": "javascript",
|
|
37
50
|
".cjs": "javascript",
|
|
@@ -90,10 +103,12 @@ function formatBadge(filename: string): string {
|
|
|
90
103
|
|
|
91
104
|
export function SourceViewer({ path }: SourceViewerProps) {
|
|
92
105
|
const [content, setContent] = useState<string | null>(null);
|
|
106
|
+
const [byteSize, setByteSize] = useState(0);
|
|
93
107
|
const [binary, setBinary] = useState(false);
|
|
94
108
|
const [loading, setLoading] = useState(true);
|
|
95
109
|
const [wrap, setWrap] = useState(false);
|
|
96
110
|
const [copied, setCopied] = useState(false);
|
|
111
|
+
const [visibleCount, setVisibleCount] = useState(RENDER_CHUNK);
|
|
97
112
|
|
|
98
113
|
const assetUrl = withWs(`/api/assets/${path}`);
|
|
99
114
|
const filename = path.split("/").pop() || path;
|
|
@@ -108,6 +123,7 @@ export function SourceViewer({ path }: SourceViewerProps) {
|
|
|
108
123
|
if (looksBinary(bytes)) {
|
|
109
124
|
setBinary(true);
|
|
110
125
|
} else {
|
|
126
|
+
setByteSize(bytes.length);
|
|
111
127
|
setContent(new TextDecoder("utf-8").decode(bytes));
|
|
112
128
|
}
|
|
113
129
|
}
|
|
@@ -122,27 +138,31 @@ export function SourceViewer({ path }: SourceViewerProps) {
|
|
|
122
138
|
void fetchContent();
|
|
123
139
|
}, [fetchContent]);
|
|
124
140
|
|
|
141
|
+
const lineCount = useMemo(
|
|
142
|
+
() => (content ? content.split("\n").length : 0),
|
|
143
|
+
[content],
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
const isLarge = byteSize > LARGE_BYTES || lineCount > LARGE_LINES;
|
|
147
|
+
|
|
125
148
|
const highlightedLines = useMemo(() => {
|
|
126
149
|
if (!content) return [];
|
|
150
|
+
if (isLarge) return content.split("\n").map(escapeHtml);
|
|
127
151
|
try {
|
|
128
152
|
const tree = language
|
|
129
153
|
? lowlight.highlight(language, content)
|
|
130
154
|
: lowlight.highlightAuto(content);
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return html.split("\n");
|
|
155
|
+
// Split on newlines, preserving tags that span lines.
|
|
156
|
+
return toHtml(tree).split("\n");
|
|
134
157
|
} catch {
|
|
135
|
-
|
|
136
|
-
return content
|
|
137
|
-
.split("\n")
|
|
138
|
-
.map((line) =>
|
|
139
|
-
line
|
|
140
|
-
.replace(/&/g, "&")
|
|
141
|
-
.replace(/</g, "<")
|
|
142
|
-
.replace(/>/g, ">"),
|
|
143
|
-
);
|
|
158
|
+
return content.split("\n").map(escapeHtml);
|
|
144
159
|
}
|
|
145
|
-
}, [content, language]);
|
|
160
|
+
}, [content, language, isLarge]);
|
|
161
|
+
|
|
162
|
+
const shownLines = isLarge
|
|
163
|
+
? highlightedLines.slice(0, visibleCount)
|
|
164
|
+
: highlightedLines;
|
|
165
|
+
const hasMore = isLarge && visibleCount < highlightedLines.length;
|
|
146
166
|
|
|
147
167
|
const copyToClipboard = () => {
|
|
148
168
|
if (!content) return;
|
|
@@ -212,27 +232,56 @@ export function SourceViewer({ path }: SourceViewerProps) {
|
|
|
212
232
|
Raw
|
|
213
233
|
</Button>
|
|
214
234
|
</ViewerToolbar>
|
|
215
|
-
<div className="flex-1 overflow-auto source-viewer-code bg-
|
|
235
|
+
<div className="flex-1 overflow-auto source-viewer-code bg-muted">
|
|
216
236
|
{loading ? (
|
|
217
237
|
<div className="flex items-center justify-center h-full text-muted-foreground text-sm">
|
|
218
238
|
Loading...
|
|
219
239
|
</div>
|
|
220
240
|
) : (
|
|
241
|
+
<>
|
|
242
|
+
{isLarge && (
|
|
243
|
+
<div className="px-4 py-2 text-[11px] text-amber-700 dark:text-amber-300 bg-amber-500/15 border-b border-amber-500/30 font-sans">
|
|
244
|
+
Large file ({(byteSize / (1024 * 1024)).toFixed(1)} MB,{" "}
|
|
245
|
+
{highlightedLines.length.toLocaleString()} lines). Syntax
|
|
246
|
+
highlighting disabled for performance. Use Raw or Download for
|
|
247
|
+
the full file.
|
|
248
|
+
</div>
|
|
249
|
+
)}
|
|
221
250
|
<table className="w-full border-collapse text-[13px] leading-relaxed font-mono">
|
|
222
251
|
<tbody>
|
|
223
|
-
{
|
|
224
|
-
<tr key={i} className="hover:bg-
|
|
225
|
-
<td className="w-12 pr-4 text-right text-
|
|
252
|
+
{shownLines.map((lineHtml, i) => (
|
|
253
|
+
<tr key={i} className="hover:bg-foreground/5">
|
|
254
|
+
<td className="w-12 pr-4 text-right text-muted-foreground select-none align-top sticky left-0 bg-muted">
|
|
226
255
|
{i + 1}
|
|
227
256
|
</td>
|
|
228
257
|
<td
|
|
229
|
-
className={`text-
|
|
258
|
+
className={`text-foreground pl-2 ${wrap ? "whitespace-pre-wrap break-all" : "whitespace-pre"}`}
|
|
230
259
|
dangerouslySetInnerHTML={{ __html: lineHtml || " " }}
|
|
231
260
|
/>
|
|
232
261
|
</tr>
|
|
233
262
|
))}
|
|
234
263
|
</tbody>
|
|
235
264
|
</table>
|
|
265
|
+
{hasMore && (
|
|
266
|
+
<div className="flex items-center gap-3 px-4 py-3 border-t border-border font-sans">
|
|
267
|
+
<button
|
|
268
|
+
onClick={() => setVisibleCount((v) => v + RENDER_CHUNK)}
|
|
269
|
+
className="text-[11px] text-foreground hover:text-foreground px-2.5 py-1 rounded bg-foreground/10 hover:bg-foreground/20 transition-colors"
|
|
270
|
+
>
|
|
271
|
+
Show{" "}
|
|
272
|
+
{Math.min(
|
|
273
|
+
RENDER_CHUNK,
|
|
274
|
+
highlightedLines.length - visibleCount,
|
|
275
|
+
).toLocaleString()}{" "}
|
|
276
|
+
more
|
|
277
|
+
</button>
|
|
278
|
+
<span className="text-[11px] text-muted-foreground">
|
|
279
|
+
{visibleCount.toLocaleString()} /{" "}
|
|
280
|
+
{highlightedLines.length.toLocaleString()} lines
|
|
281
|
+
</span>
|
|
282
|
+
</div>
|
|
283
|
+
)}
|
|
284
|
+
</>
|
|
236
285
|
)}
|
|
237
286
|
</div>
|
|
238
287
|
</div>
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Copy,
|
|
5
|
+
Check,
|
|
6
|
+
Globe,
|
|
7
|
+
Loader2,
|
|
8
|
+
Lock,
|
|
9
|
+
Trash2,
|
|
10
|
+
Clock,
|
|
11
|
+
} from "lucide-react";
|
|
12
|
+
import { useCallback, useEffect, useState } from "react";
|
|
13
|
+
import { Button } from "@/components/ui/button";
|
|
14
|
+
import { Input } from "@/components/ui/input";
|
|
15
|
+
import { Switch } from "@/components/ui/switch";
|
|
16
|
+
import { Label } from "@/components/ui/label";
|
|
17
|
+
import {
|
|
18
|
+
Dialog,
|
|
19
|
+
DialogContent,
|
|
20
|
+
DialogHeader,
|
|
21
|
+
DialogTitle,
|
|
22
|
+
DialogDescription,
|
|
23
|
+
} from "@/components/ui/dialog";
|
|
24
|
+
import { showSuccess, showError } from "@/lib/toast";
|
|
25
|
+
import { wsFetch } from "@/lib/workspace-client";
|
|
26
|
+
|
|
27
|
+
interface Share {
|
|
28
|
+
id: string;
|
|
29
|
+
token: string;
|
|
30
|
+
url: string;
|
|
31
|
+
hasPassword: boolean;
|
|
32
|
+
expiresAt: string | null;
|
|
33
|
+
createdAt: string;
|
|
34
|
+
viewCount: number;
|
|
35
|
+
isExpired: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface ShareDialogProps {
|
|
39
|
+
open: boolean;
|
|
40
|
+
onOpenChange: (open: boolean) => void;
|
|
41
|
+
filePath: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function ShareDialog({
|
|
45
|
+
open,
|
|
46
|
+
onOpenChange,
|
|
47
|
+
filePath,
|
|
48
|
+
}: ShareDialogProps) {
|
|
49
|
+
const [shares, setShares] = useState<Share[]>([]);
|
|
50
|
+
const [loading, setLoading] = useState(true);
|
|
51
|
+
const [creating, setCreating] = useState(false);
|
|
52
|
+
|
|
53
|
+
// Form fields
|
|
54
|
+
const [password, setPassword] = useState("");
|
|
55
|
+
const [enablePassword, setEnablePassword] = useState(false);
|
|
56
|
+
const [enableExpiry, setEnableExpiry] = useState(false);
|
|
57
|
+
const [expiryDays, setExpiryDays] = useState("7");
|
|
58
|
+
|
|
59
|
+
// Copied state per share token
|
|
60
|
+
const [copiedToken, setCopiedToken] = useState<string | null>(null);
|
|
61
|
+
|
|
62
|
+
const loadShares = useCallback(async () => {
|
|
63
|
+
setLoading(true);
|
|
64
|
+
try {
|
|
65
|
+
const res = await wsFetch(
|
|
66
|
+
`/api/share?path=${encodeURIComponent(filePath)}`,
|
|
67
|
+
);
|
|
68
|
+
if (res.ok) {
|
|
69
|
+
const data = await res.json();
|
|
70
|
+
setShares(data.shares ?? []);
|
|
71
|
+
}
|
|
72
|
+
} catch {
|
|
73
|
+
// silently fail
|
|
74
|
+
}
|
|
75
|
+
setLoading(false);
|
|
76
|
+
}, [filePath]);
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
if (open) void loadShares();
|
|
80
|
+
}, [open, loadShares]);
|
|
81
|
+
|
|
82
|
+
const handleCreate = async () => {
|
|
83
|
+
setCreating(true);
|
|
84
|
+
try {
|
|
85
|
+
const body: Record<string, unknown> = { path: filePath };
|
|
86
|
+
if (enablePassword && password.trim()) {
|
|
87
|
+
body.password = password.trim();
|
|
88
|
+
}
|
|
89
|
+
if (enableExpiry && expiryDays) {
|
|
90
|
+
const d = new Date();
|
|
91
|
+
d.setDate(d.getDate() + Number(expiryDays));
|
|
92
|
+
body.expiresAt = d.toISOString();
|
|
93
|
+
}
|
|
94
|
+
const res = await wsFetch("/api/share", {
|
|
95
|
+
method: "POST",
|
|
96
|
+
headers: { "Content-Type": "application/json" },
|
|
97
|
+
body: JSON.stringify(body),
|
|
98
|
+
});
|
|
99
|
+
if (!res.ok) {
|
|
100
|
+
const e = await res.json();
|
|
101
|
+
showError(e.error ?? "Failed to create share link");
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
showSuccess("Share link created");
|
|
105
|
+
setPassword("");
|
|
106
|
+
setEnablePassword(false);
|
|
107
|
+
setEnableExpiry(false);
|
|
108
|
+
setExpiryDays("7");
|
|
109
|
+
await loadShares();
|
|
110
|
+
} catch {
|
|
111
|
+
showError("Failed to create share link");
|
|
112
|
+
} finally {
|
|
113
|
+
setCreating(false);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const handleRevoke = async (token: string) => {
|
|
118
|
+
try {
|
|
119
|
+
const res = await fetch(`/api/share/${token}`, { method: "DELETE" });
|
|
120
|
+
if (!res.ok) {
|
|
121
|
+
showError("Failed to revoke share link");
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
showSuccess("Share link revoked");
|
|
125
|
+
await loadShares();
|
|
126
|
+
} catch {
|
|
127
|
+
showError("Failed to revoke share link");
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const copyLink = (url: string, token: string) => {
|
|
132
|
+
const fullUrl = `${window.location.origin}${url}`;
|
|
133
|
+
void navigator.clipboard.writeText(fullUrl);
|
|
134
|
+
setCopiedToken(token);
|
|
135
|
+
setTimeout(() => setCopiedToken(null), 2000);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
140
|
+
<DialogContent className="sm:max-w-md">
|
|
141
|
+
<DialogHeader>
|
|
142
|
+
<DialogTitle>Share document</DialogTitle>
|
|
143
|
+
<DialogDescription>
|
|
144
|
+
Create a public link to share this document as read-only.
|
|
145
|
+
</DialogDescription>
|
|
146
|
+
</DialogHeader>
|
|
147
|
+
|
|
148
|
+
<div className="space-y-4">
|
|
149
|
+
{/* Create new share */}
|
|
150
|
+
<div className="rounded-sm border border-border p-3 space-y-3">
|
|
151
|
+
<h3 className="text-sm font-medium">New share link</h3>
|
|
152
|
+
|
|
153
|
+
{/* Password toggle */}
|
|
154
|
+
<div className="flex items-center justify-between">
|
|
155
|
+
<Label htmlFor="share-pwd" className="text-xs gap-1.5 flex items-center">
|
|
156
|
+
<Lock className="h-3 w-3 text-muted-foreground" />
|
|
157
|
+
Password protect
|
|
158
|
+
</Label>
|
|
159
|
+
<Switch
|
|
160
|
+
id="share-pwd"
|
|
161
|
+
checked={enablePassword}
|
|
162
|
+
onCheckedChange={setEnablePassword}
|
|
163
|
+
/>
|
|
164
|
+
</div>
|
|
165
|
+
{enablePassword && (
|
|
166
|
+
<Input
|
|
167
|
+
type="password"
|
|
168
|
+
placeholder="Set a password"
|
|
169
|
+
value={password}
|
|
170
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
171
|
+
/>
|
|
172
|
+
)}
|
|
173
|
+
|
|
174
|
+
{/* Expiry toggle */}
|
|
175
|
+
<div className="flex items-center justify-between">
|
|
176
|
+
<Label htmlFor="share-expiry" className="text-xs gap-1.5 flex items-center">
|
|
177
|
+
<Clock className="h-3 w-3 text-muted-foreground" />
|
|
178
|
+
Set expiration
|
|
179
|
+
</Label>
|
|
180
|
+
<Switch
|
|
181
|
+
id="share-expiry"
|
|
182
|
+
checked={enableExpiry}
|
|
183
|
+
onCheckedChange={setEnableExpiry}
|
|
184
|
+
/>
|
|
185
|
+
</div>
|
|
186
|
+
{enableExpiry && (
|
|
187
|
+
<div className="flex items-center gap-2">
|
|
188
|
+
<Input
|
|
189
|
+
type="number"
|
|
190
|
+
min={1}
|
|
191
|
+
max={365}
|
|
192
|
+
value={expiryDays}
|
|
193
|
+
onChange={(e) => setExpiryDays(e.target.value)}
|
|
194
|
+
className="w-20"
|
|
195
|
+
/>
|
|
196
|
+
<span className="text-xs text-muted-foreground">days</span>
|
|
197
|
+
</div>
|
|
198
|
+
)}
|
|
199
|
+
|
|
200
|
+
<Button
|
|
201
|
+
size="sm"
|
|
202
|
+
className="w-full gap-1.5"
|
|
203
|
+
onClick={handleCreate}
|
|
204
|
+
disabled={creating}
|
|
205
|
+
>
|
|
206
|
+
{creating ? (
|
|
207
|
+
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
|
208
|
+
) : (
|
|
209
|
+
<Globe className="h-3.5 w-3.5" />
|
|
210
|
+
)}
|
|
211
|
+
Create link
|
|
212
|
+
</Button>
|
|
213
|
+
</div>
|
|
214
|
+
|
|
215
|
+
{/* Existing shares */}
|
|
216
|
+
<div className="space-y-2">
|
|
217
|
+
<h3 className="text-xs font-medium text-muted-foreground">
|
|
218
|
+
{shares.length > 0
|
|
219
|
+
? `Active links (${shares.length})`
|
|
220
|
+
: loading
|
|
221
|
+
? "Loading..."
|
|
222
|
+
: "No active links"}
|
|
223
|
+
</h3>
|
|
224
|
+
{loading && (
|
|
225
|
+
<div className="flex justify-center py-2">
|
|
226
|
+
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
|
|
227
|
+
</div>
|
|
228
|
+
)}
|
|
229
|
+
{shares.map((share) => (
|
|
230
|
+
<div
|
|
231
|
+
key={share.id}
|
|
232
|
+
className="flex items-center gap-2 rounded-sm border border-border p-2"
|
|
233
|
+
>
|
|
234
|
+
<div className="flex-1 min-w-0">
|
|
235
|
+
<div className="flex items-center gap-1.5">
|
|
236
|
+
<span className="text-xs font-mono truncate">
|
|
237
|
+
{window.location.origin}/s/{share.token}
|
|
238
|
+
</span>
|
|
239
|
+
</div>
|
|
240
|
+
<div className="flex items-center gap-2 mt-0.5">
|
|
241
|
+
{share.hasPassword && (
|
|
242
|
+
<span className="flex items-center gap-0.5 text-[10px] text-muted-foreground">
|
|
243
|
+
<Lock className="h-2.5 w-2.5" />
|
|
244
|
+
pwd
|
|
245
|
+
</span>
|
|
246
|
+
)}
|
|
247
|
+
{share.expiresAt && (
|
|
248
|
+
<span className="flex items-center gap-0.5 text-[10px] text-muted-foreground">
|
|
249
|
+
<Clock className="h-2.5 w-2.5" />
|
|
250
|
+
{formatExpiry(share.expiresAt)}
|
|
251
|
+
</span>
|
|
252
|
+
)}
|
|
253
|
+
<span className="text-[10px] text-muted-foreground">
|
|
254
|
+
{share.viewCount} view
|
|
255
|
+
{share.viewCount !== 1 ? "s" : ""}
|
|
256
|
+
</span>
|
|
257
|
+
{share.isExpired && (
|
|
258
|
+
<span className="text-[10px] text-destructive">
|
|
259
|
+
expired
|
|
260
|
+
</span>
|
|
261
|
+
)}
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
<div className="flex items-center gap-1 shrink-0">
|
|
265
|
+
<Button
|
|
266
|
+
size="sm"
|
|
267
|
+
variant="ghost"
|
|
268
|
+
className="h-7 w-7 p-0"
|
|
269
|
+
title="Copy link"
|
|
270
|
+
onClick={() => copyLink(share.url, share.token)}
|
|
271
|
+
>
|
|
272
|
+
{copiedToken === share.token ? (
|
|
273
|
+
<Check className="h-3.5 w-3.5 text-success" />
|
|
274
|
+
) : (
|
|
275
|
+
<Copy className="h-3.5 w-3.5" />
|
|
276
|
+
)}
|
|
277
|
+
</Button>
|
|
278
|
+
<Button
|
|
279
|
+
size="sm"
|
|
280
|
+
variant="ghost"
|
|
281
|
+
className="h-7 w-7 p-0 text-destructive hover:text-destructive"
|
|
282
|
+
title="Revoke link"
|
|
283
|
+
onClick={() => handleRevoke(share.token)}
|
|
284
|
+
>
|
|
285
|
+
<Trash2 className="h-3.5 w-3.5" />
|
|
286
|
+
</Button>
|
|
287
|
+
</div>
|
|
288
|
+
</div>
|
|
289
|
+
))}
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
</DialogContent>
|
|
293
|
+
</Dialog>
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function formatExpiry(iso: string): string {
|
|
298
|
+
const d = new Date(iso);
|
|
299
|
+
const now = new Date();
|
|
300
|
+
const ms = d.getTime() - now.getTime();
|
|
301
|
+
if (ms <= 0) return "expired";
|
|
302
|
+
const days = Math.floor(ms / 86400000);
|
|
303
|
+
const hours = Math.floor((ms % 86400000) / 3600000);
|
|
304
|
+
if (days > 0) return `${days}d`;
|
|
305
|
+
if (hours > 0) return `${hours}h`;
|
|
306
|
+
return "<1h";
|
|
307
|
+
}
|