@taskmark/ui 0.2.6 → 0.3.1
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/README.md +16 -1
- package/app/board/page.tsx +3 -272
- package/app/globals.css +25 -0
- package/app/layout.tsx +15 -5
- package/app/page.tsx +14 -14
- package/app/setup/actions.ts +4 -4
- package/app/setup/page.tsx +9 -4
- package/bin/lib/resolve-board.mjs +1 -4
- package/bin/taskmark.js +15 -2
- package/components/board/app-bar.tsx +3 -0
- package/components/board/board-screen.tsx +229 -0
- package/components/board/changelog-panel.tsx +26 -0
- package/components/board/epic-list.tsx +4 -2
- package/components/board/list-view-switcher.tsx +7 -3
- package/components/board/markdown-content.tsx +21 -1
- package/components/board/mermaid-diagram.tsx +88 -0
- package/components/board/metric-stat-card.tsx +4 -4
- package/components/board/overall-tree-list.tsx +467 -0
- package/components/board/overall-work-items-list.tsx +6 -2
- package/components/board/points-heatmap.tsx +183 -0
- package/components/board/project-status-metrics-strip.tsx +5 -22
- package/components/board/static-board-app.tsx +29 -94
- package/components/board/status-badge.tsx +8 -0
- package/components/board/story-list.tsx +3 -1
- package/components/board/task-list.tsx +5 -1
- package/components/board/work-item-detail-body.tsx +123 -8
- package/components/board/work-items-list.tsx +2 -0
- package/components/theme-provider.tsx +39 -0
- package/components/theme-toggle.tsx +27 -0
- package/components/ui/sonner.tsx +2 -2
- package/dist/prod-next/BUILD_ID +1 -1
- package/dist/prod-next/app-path-routes-manifest.json +2 -2
- package/dist/prod-next/build-manifest.json +6 -6
- package/dist/prod-next/prerender-manifest.json +3 -27
- package/dist/prod-next/react-loadable-manifest.json +392 -2
- package/dist/prod-next/server/app/_global-error/page.js +2 -2
- package/dist/prod-next/server/app/_global-error/page.js.nft.json +1 -1
- package/dist/prod-next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/prod-next/server/app/_global-error.html +1 -1
- package/dist/prod-next/server/app/_global-error.rsc +1 -1
- package/dist/prod-next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/prod-next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/prod-next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/prod-next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/prod-next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/prod-next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/prod-next/server/app/_not-found/page.js +2 -2
- package/dist/prod-next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/prod-next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/prod-next/server/app/_not-found.html +1 -1
- package/dist/prod-next/server/app/_not-found.rsc +19 -17
- package/dist/prod-next/server/app/_not-found.segments/_full.segment.rsc +19 -17
- package/dist/prod-next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/prod-next/server/app/_not-found.segments/_index.segment.rsc +8 -6
- package/dist/prod-next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/prod-next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/prod-next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/dist/prod-next/server/app/api/taskmark-reload/route.js +1 -1
- package/dist/prod-next/server/app/api/taskmark-reload/route.js.nft.json +1 -1
- package/dist/prod-next/server/app/board/page.js +2 -50
- package/dist/prod-next/server/app/board/page.js.nft.json +1 -1
- package/dist/prod-next/server/app/board/page_client-reference-manifest.js +1 -1
- package/dist/prod-next/server/app/favicon.ico/route.js +1 -1
- package/dist/prod-next/server/app/favicon.ico/route.js.nft.json +1 -1
- package/dist/prod-next/server/app/page.js +2 -2
- package/dist/prod-next/server/app/page.js.nft.json +1 -1
- package/dist/prod-next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/prod-next/server/app/setup/page.js +2 -2
- package/dist/prod-next/server/app/setup/page.js.nft.json +1 -1
- package/dist/prod-next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/dist/prod-next/server/app-paths-manifest.json +2 -2
- package/dist/prod-next/server/chunks/102.js +90 -0
- package/dist/prod-next/server/chunks/11.js +1 -0
- package/dist/prod-next/server/chunks/1286.js +1 -0
- package/dist/prod-next/server/chunks/1412.js +38 -0
- package/dist/prod-next/server/chunks/1605.js +1 -0
- package/dist/prod-next/server/chunks/169.js +1 -0
- package/dist/prod-next/server/chunks/18.js +86 -0
- package/dist/prod-next/server/chunks/2.js +1 -0
- package/dist/prod-next/server/chunks/2022.js +1 -0
- package/dist/prod-next/server/chunks/2156.js +1 -0
- package/dist/prod-next/server/chunks/2157.js +1 -0
- package/dist/prod-next/server/chunks/2325.js +82 -0
- package/dist/prod-next/server/chunks/2838.js +1 -0
- package/dist/prod-next/server/chunks/2897.js +79 -0
- package/dist/prod-next/server/chunks/3227.js +1 -0
- package/dist/prod-next/server/chunks/3266.js +1 -0
- package/dist/prod-next/server/chunks/3307.js +49 -0
- package/dist/prod-next/server/chunks/3387.js +19 -0
- package/dist/prod-next/server/chunks/3428.js +32 -0
- package/dist/prod-next/server/chunks/3479.js +1 -0
- package/dist/prod-next/server/chunks/367.js +115 -0
- package/dist/prod-next/server/chunks/3698.js +93 -0
- package/dist/prod-next/server/chunks/3709.js +148 -0
- package/dist/prod-next/server/chunks/41.js +1 -0
- package/dist/prod-next/server/chunks/4107.js +62 -0
- package/dist/prod-next/server/chunks/4569.js +34 -0
- package/dist/prod-next/server/chunks/{741.js → 4741.js} +1 -1
- package/dist/prod-next/server/chunks/4755.js +153 -0
- package/dist/prod-next/server/chunks/487.js +1 -0
- package/dist/prod-next/server/chunks/5002.js +1 -0
- package/dist/prod-next/server/chunks/5112.js +1 -0
- package/dist/prod-next/server/chunks/5289.js +8 -0
- package/dist/prod-next/server/chunks/5318.js +1 -0
- package/dist/prod-next/server/chunks/5452.js +23 -0
- package/dist/prod-next/server/chunks/5453.js +1 -0
- package/dist/prod-next/server/chunks/5749.js +27 -0
- package/dist/prod-next/server/chunks/5782.js +36 -0
- package/dist/prod-next/server/chunks/6163.js +104 -0
- package/dist/prod-next/server/chunks/6169.js +64 -0
- package/dist/prod-next/server/chunks/6208.js +172 -0
- package/dist/prod-next/server/chunks/6399.js +24 -0
- package/dist/prod-next/server/chunks/6496.js +1 -0
- package/dist/prod-next/server/chunks/6823.js +215 -0
- package/dist/prod-next/server/chunks/6888.js +1 -0
- package/dist/prod-next/server/chunks/6980.js +1 -0
- package/dist/prod-next/server/chunks/7245.js +77 -0
- package/dist/prod-next/server/chunks/7307.js +1 -0
- package/dist/prod-next/server/chunks/7372.js +287 -0
- package/dist/prod-next/server/chunks/7384.js +226 -0
- package/dist/prod-next/server/chunks/7516.js +1 -0
- package/dist/prod-next/server/chunks/7531.js +24 -0
- package/dist/prod-next/server/chunks/7591.js +1 -0
- package/dist/prod-next/server/chunks/7755.js +138 -0
- package/dist/prod-next/server/chunks/7916.js +1 -0
- package/dist/prod-next/server/chunks/8078.js +94 -0
- package/dist/prod-next/server/chunks/8253.js +41 -0
- package/dist/prod-next/server/chunks/8635.js +1 -0
- package/dist/prod-next/server/chunks/8688.js +1 -0
- package/dist/prod-next/server/chunks/8872.js +1 -0
- package/dist/prod-next/server/chunks/9006.js +1 -0
- package/dist/prod-next/server/chunks/9018.js +1 -0
- package/dist/prod-next/server/chunks/9047.js +1 -0
- package/dist/prod-next/server/chunks/9108.js +1 -0
- package/dist/prod-next/server/chunks/9280.js +256 -0
- package/dist/prod-next/server/chunks/9419.js +1 -0
- package/dist/prod-next/server/chunks/9430.js +1 -0
- package/dist/prod-next/server/chunks/9586.js +1 -0
- package/dist/prod-next/server/chunks/9775.js +1 -0
- package/dist/prod-next/server/chunks/992.js +1 -0
- package/dist/prod-next/server/chunks/9926.js +1 -0
- package/dist/prod-next/server/chunks/9984.js +8 -0
- package/dist/prod-next/server/middleware-build-manifest.js +1 -1
- package/dist/prod-next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/prod-next/server/pages/404.html +1 -1
- package/dist/prod-next/server/pages/500.html +1 -1
- package/dist/prod-next/server/server-reference-manifest.js +1 -1
- package/dist/prod-next/server/server-reference-manifest.json +1 -1
- package/dist/prod-next/server/webpack-runtime.js +1 -1
- package/dist/prod-next/static/chunks/1213.e5c6e70a79b5f7e6.js +24 -0
- package/dist/prod-next/static/chunks/1519.2f596e5f5af9ef57.js +62 -0
- package/dist/prod-next/static/chunks/1759-f5b8fb456f8fb420.js +1 -0
- package/dist/prod-next/static/chunks/1974.885c9a133b86d8a4.js +32 -0
- package/dist/prod-next/static/chunks/2280.6a7f540787704698.js +1 -0
- package/dist/prod-next/static/chunks/2521.7f745f50d30076e7.js +77 -0
- package/dist/prod-next/static/chunks/2585.4d6aa847c780c666.js +1 -0
- package/dist/prod-next/static/chunks/2589.1aad68c09021b1ac.js +1 -0
- package/dist/prod-next/static/chunks/2600.45ba17a0f756fc31.js +1 -0
- package/dist/prod-next/static/chunks/2619.9aac8983f30c7c8a.js +1 -0
- package/dist/prod-next/static/chunks/26d302b2.9f6383e42abdfe16.js +122 -0
- package/dist/prod-next/static/chunks/2768.305914f7900745b6.js +1 -0
- package/dist/prod-next/static/chunks/2931.c2acdbf72808b646.js +41 -0
- package/dist/prod-next/static/chunks/3012-838f69b72a0dc1b3.js +1 -0
- package/dist/prod-next/static/chunks/3016.406e568aa95ff867.js +1 -0
- package/dist/prod-next/static/chunks/3022.972047558a20553a.js +172 -0
- package/dist/prod-next/static/chunks/3064.3a2a1e7cd4fdca5f.js +1 -0
- package/dist/prod-next/static/chunks/3174.03fbed7b7d7a8256.js +1 -0
- package/dist/prod-next/static/chunks/3189.b048866768087750.js +1 -0
- package/dist/prod-next/static/chunks/3217.1a053843c58b70b5.js +24 -0
- package/dist/prod-next/static/chunks/3308.30b95d524f9c1daf.js +74 -0
- package/dist/prod-next/static/chunks/331.fc5d78e1e91daf43.js +1 -0
- package/dist/prod-next/static/chunks/3510.5d4d1c79533e080c.js +1 -0
- package/dist/prod-next/static/chunks/364.ce5400a9dd70b9dc.js +1 -0
- package/dist/prod-next/static/chunks/3661-1f08d73aaffb011d.js +1 -0
- package/dist/prod-next/static/chunks/370.57cfa27da8567918.js +1 -0
- package/dist/prod-next/static/chunks/3789.c418b69121761983.js +1 -0
- package/dist/prod-next/static/chunks/3794-c66b3d8325973459.js +32 -0
- package/dist/prod-next/static/chunks/3831.25ae62d10dccc27a.js +1 -0
- package/dist/prod-next/static/chunks/395.b41e9d76613d37b5.js +90 -0
- package/dist/prod-next/static/chunks/3a7aa434.93dbd20997cfd24f.js +82 -0
- package/dist/prod-next/static/chunks/4020.3cc19c463c49f969.js +23 -0
- package/dist/prod-next/static/chunks/4035.0acc428926d5c8dd.js +1 -0
- package/dist/prod-next/static/chunks/405.0902e4f6eb7bd9a2.js +215 -0
- package/dist/prod-next/static/chunks/4159.49ae537ff687bdc6.js +138 -0
- package/dist/prod-next/static/chunks/4208.384b381ca2757643.js +287 -0
- package/dist/prod-next/static/chunks/4263.ffa8d9bd8a0faaae.js +1 -0
- package/dist/prod-next/static/chunks/4561.d1a3aaca8bae3224.js +34 -0
- package/dist/prod-next/static/chunks/4592.d0f37bc216b9d988.js +93 -0
- package/dist/prod-next/static/chunks/4799.0dc7aa21bff2fd2a.js +1 -0
- package/dist/prod-next/static/chunks/4bd1b696-e356ca5ba0218e27.js +1 -0
- package/dist/prod-next/static/chunks/514.b804c51b26f5e126.js +1 -0
- package/dist/prod-next/static/chunks/5270.28592864d38e881c.js +1 -0
- package/dist/prod-next/static/chunks/52733464.3870f99cc446f9ff.js +1 -0
- package/dist/prod-next/static/chunks/5354.b559c717a607dc5c.js +1 -0
- package/dist/prod-next/static/chunks/5448.d3972d9fb464b54f.js +38 -0
- package/dist/prod-next/static/chunks/587.d52737d7288c11b4.js +1 -0
- package/dist/prod-next/static/chunks/5909.9e37f7b495b11995.js +115 -0
- package/dist/prod-next/static/chunks/5949.5504b3545fcc3d34.js +104 -0
- package/dist/prod-next/static/chunks/6322-4e97920c006f7933.js +1 -0
- package/dist/prod-next/static/chunks/6361.893d04ac34fa1b49.js +148 -0
- package/dist/prod-next/static/chunks/6774.8cd53427dbf32cac.js +86 -0
- package/dist/prod-next/static/chunks/6968.b80277c724dbc96e.js +1 -0
- package/dist/prod-next/static/chunks/7113.4b9e7ea870aa300a.js +8 -0
- package/dist/prod-next/static/chunks/7236.55a9728d35f5b8a6.js +1 -0
- package/dist/prod-next/static/chunks/7390.dde9b5bc2f6e24b8.js +1 -0
- package/dist/prod-next/static/chunks/7806.a903780fcfa3a30e.js +1 -0
- package/dist/prod-next/static/chunks/7997.be57e92e583fe635.js +1 -0
- package/dist/prod-next/static/chunks/8216.64a72d4d35ea7be0.js +1 -0
- package/dist/prod-next/static/chunks/830.5d5274d7ad1cb58e.js +1 -0
- package/dist/prod-next/static/chunks/8378.fa91de3406f554c9.js +226 -0
- package/dist/prod-next/static/chunks/8501.cd06aa1b0c7e1c6a.js +79 -0
- package/dist/prod-next/static/chunks/8663.6ec5792fb4952e45.js +27 -0
- package/dist/prod-next/static/chunks/872.96937e758ddce860.js +1 -0
- package/dist/prod-next/static/chunks/8803.75bde095fe3613f5.js +1 -0
- package/dist/prod-next/static/chunks/8863.72f5dbb820a0e4c3.js +1 -0
- package/dist/prod-next/static/chunks/90542734.f7a7b2972ef5a749.js +1 -0
- package/dist/prod-next/static/chunks/9379.5bc9c9343ec5a16c.js +64 -0
- package/dist/prod-next/static/chunks/9389.906fe7aa9cd6a170.js +1 -0
- package/dist/prod-next/static/chunks/9472.8818ee52cfa931a4.js +94 -0
- package/dist/prod-next/static/chunks/966.d6babbf8119162cc.js +1 -0
- package/dist/prod-next/static/chunks/9884.d4ac1a961b3366f1.js +36 -0
- package/dist/prod-next/static/chunks/9909.67cf9940b125243b.js +1 -0
- package/dist/prod-next/static/chunks/app/_global-error/page-8be5492b3b872a4c.js +1 -0
- package/dist/prod-next/static/chunks/app/_not-found/page-799e445a538b0024.js +1 -0
- package/dist/prod-next/static/chunks/app/api/taskmark-reload/route-8be5492b3b872a4c.js +1 -0
- package/dist/prod-next/static/chunks/app/board/page-5c181f45738daf1c.js +1 -0
- package/dist/prod-next/static/chunks/app/layout-21782e6d13a6f275.js +1 -0
- package/dist/prod-next/static/chunks/app/page-51bfe4356fe233e3.js +1 -0
- package/dist/prod-next/static/chunks/app/setup/page-3ccfba00c10f9b17.js +1 -0
- package/dist/prod-next/static/chunks/d3ac728e.7964f816a1ca64e5.js +1 -0
- package/dist/prod-next/static/chunks/e413bedd.3a12a8cb02e28fdf.js +153 -0
- package/dist/prod-next/static/chunks/ea233666.f00b64a7d99b4950.js +62 -0
- package/dist/prod-next/static/chunks/framework-711ef29bc66f648c.js +1 -0
- package/dist/prod-next/static/chunks/main-app-dd26d4f9d120646e.js +1 -0
- package/dist/prod-next/static/chunks/{main-bb33c46a9c25dee8.js → main-df4bcaed74f274eb.js} +2 -2
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/app-error-8be5492b3b872a4c.js +1 -0
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/forbidden-8be5492b3b872a4c.js +1 -0
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/global-error-45a0cf77e03361ed.js +1 -0
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/not-found-8be5492b3b872a4c.js +1 -0
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/unauthorized-8be5492b3b872a4c.js +1 -0
- package/dist/prod-next/static/chunks/webpack-713747aaa9716c4c.js +1 -0
- package/dist/prod-next/static/css/cb78d4b0062d9a3f.css +1 -0
- package/dist/public/taskmark-snapshot.json +1 -1
- package/lib/taskmark/board-index.ts +101 -0
- package/lib/taskmark/build-snapshot.ts +28 -7
- package/lib/taskmark/derive-parents.test.ts +23 -0
- package/lib/taskmark/derive-parents.ts +323 -0
- package/lib/taskmark/detail-load.ts +55 -7
- package/lib/taskmark/detail-types.ts +10 -2
- package/lib/taskmark/dev-reload-token.ts +1 -1
- package/lib/taskmark/discover.ts +4 -7
- package/lib/taskmark/epic-types.ts +2 -1
- package/lib/taskmark/flat-work-item-types.ts +1 -4
- package/lib/taskmark/identity.ts +3 -3
- package/lib/taskmark/item-types.ts +2 -1
- package/lib/taskmark/list-filters.test.ts +23 -0
- package/lib/taskmark/list-filters.ts +7 -2
- package/lib/taskmark/list-view-mode.test.ts +45 -0
- package/lib/taskmark/list-view-mode.ts +20 -9
- package/lib/taskmark/load-changelog.test.ts +32 -0
- package/lib/taskmark/load-changelog.ts +18 -0
- package/lib/taskmark/overall-tree.test.ts +196 -0
- package/lib/taskmark/overall-tree.ts +194 -0
- package/lib/taskmark/parse-detail.ts +5 -5
- package/lib/taskmark/parse-epics.ts +19 -16
- package/lib/taskmark/parse-flat-lists.ts +32 -28
- package/lib/taskmark/parse-items.ts +47 -9
- package/lib/taskmark/parse-stories.ts +18 -15
- package/lib/taskmark/points-calendar.test.ts +72 -0
- package/lib/taskmark/points-calendar.ts +86 -0
- package/lib/taskmark/project-metrics.ts +11 -7
- package/lib/taskmark/snapshot-types.ts +2 -0
- package/lib/taskmark/story-types.ts +2 -1
- package/lib/taskmark/table-sort.ts +4 -3
- package/lib/taskmark/timing.ts +29 -18
- package/lib/taskmark/validate.ts +1 -1
- package/lib/theme-cookie.test.ts +27 -0
- package/lib/theme-cookie.ts +43 -0
- package/package.json +3 -1
- package/public/taskmark-snapshot.json +1 -1
- package/scripts/build-static.mjs +61 -3
- package/dist/prod-next/server/app/setup.html +0 -1
- package/dist/prod-next/server/app/setup.meta +0 -17
- package/dist/prod-next/server/app/setup.rsc +0 -22
- package/dist/prod-next/server/app/setup.segments/_full.segment.rsc +0 -22
- package/dist/prod-next/server/app/setup.segments/_head.segment.rsc +0 -6
- package/dist/prod-next/server/app/setup.segments/_index.segment.rsc +0 -8
- package/dist/prod-next/server/app/setup.segments/_tree.segment.rsc +0 -5
- package/dist/prod-next/server/app/setup.segments/setup/__PAGE__.segment.rsc +0 -6
- package/dist/prod-next/server/app/setup.segments/setup.segment.rsc +0 -5
- package/dist/prod-next/server/chunks/318.js +0 -1
- package/dist/prod-next/server/chunks/490.js +0 -8
- package/dist/prod-next/server/chunks/57.js +0 -19
- package/dist/prod-next/server/chunks/616.js +0 -1
- package/dist/prod-next/server/chunks/708.js +0 -1
- package/dist/prod-next/server/chunks/724.js +0 -1
- package/dist/prod-next/static/chunks/4bd1b696-deb4a0a1da1923b0.js +0 -1
- package/dist/prod-next/static/chunks/51.e9139a9ea6eb36b9.js +0 -1
- package/dist/prod-next/static/chunks/613-6f794154d28bb75a.js +0 -1
- package/dist/prod-next/static/chunks/669-8103441c67b185da.js +0 -1
- package/dist/prod-next/static/chunks/701-df3ee5f1cf837b1a.js +0 -1
- package/dist/prod-next/static/chunks/794-25668765560cb197.js +0 -32
- package/dist/prod-next/static/chunks/app/_global-error/page-d34451c04262dd7d.js +0 -1
- package/dist/prod-next/static/chunks/app/_not-found/page-0b3785af737e7968.js +0 -1
- package/dist/prod-next/static/chunks/app/api/taskmark-reload/route-d34451c04262dd7d.js +0 -1
- package/dist/prod-next/static/chunks/app/board/page-cd1d9be0c0127225.js +0 -1
- package/dist/prod-next/static/chunks/app/layout-856e8a282e69e7d0.js +0 -1
- package/dist/prod-next/static/chunks/app/page-d34451c04262dd7d.js +0 -1
- package/dist/prod-next/static/chunks/app/setup/page-c3003359e8becc84.js +0 -1
- package/dist/prod-next/static/chunks/framework-b29f9083d3cda3b2.js +0 -1
- package/dist/prod-next/static/chunks/main-app-bfb36455d24b3e5a.js +0 -1
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/app-error-d34451c04262dd7d.js +0 -1
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/forbidden-d34451c04262dd7d.js +0 -1
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/global-error-dc53ab29e0491fe4.js +0 -1
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/not-found-d34451c04262dd7d.js +0 -1
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/unauthorized-d34451c04262dd7d.js +0 -1
- package/dist/prod-next/static/chunks/webpack-bfe8992962004e2b.js +0 -1
- package/dist/prod-next/static/css/2e6ec4c80894e3c0.css +0 -1
- /package/dist/prod-next/static/{sAWr5ATVuqk6Wqs18kAWs → EI1zQaa_kQ7DqUSE4o3Qo}/_buildManifest.js +0 -0
- /package/dist/prod-next/static/{sAWr5ATVuqk6Wqs18kAWs → EI1zQaa_kQ7DqUSE4o3Qo}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -19,6 +19,21 @@ cd my-app-taskmark && npx taskmark
|
|
|
19
19
|
# or: npm i @taskmark/ui --save && npx taskmark serve
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
> **`npx taskmark` only works where `@taskmark/ui` is installed.** `taskmark` is the
|
|
23
|
+
> *bin* name, not a package name — an unrelated `taskmark` package exists on npm, and
|
|
24
|
+
> npx will fetch that one instead. Use `npx @taskmark/ui` when running from a folder
|
|
25
|
+
> with no local install, or install the CLI once (see below).
|
|
26
|
+
|
|
27
|
+
### Install the CLI globally
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install -g @taskmark/ui # published release
|
|
31
|
+
# from a clone of taskmark-frontend:
|
|
32
|
+
npm run build && npm link # local build on PATH as `taskmark`
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Then `taskmark` works anywhere: setup / project picker outside a board, bound board inside one.
|
|
36
|
+
|
|
22
37
|
`taskmark open` always forces the setup / picker, even when a board is nearby. Chosen master folders and the active project persist in cookies.
|
|
23
38
|
|
|
24
39
|
## Install and serve
|
|
@@ -67,7 +82,7 @@ Board resolution (bound mode only):
|
|
|
67
82
|
| Layout | Where to install / run |
|
|
68
83
|
|--------|------------------------|
|
|
69
84
|
| Single-git | Product root (discovers `./taskmark/`) or the `taskmark/` folder |
|
|
70
|
-
| Multi-git | Dedicated sibling `*-taskmark` repo root (`
|
|
85
|
+
| Multi-git | Dedicated sibling `*-taskmark` repo root (`epics/` at root) |
|
|
71
86
|
|
|
72
87
|
You do **not** need to clone `taskmark-frontend`.
|
|
73
88
|
|
package/app/board/page.tsx
CHANGED
|
@@ -1,49 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import Link from "next/link"
|
|
3
|
-
import { redirect } from "next/navigation"
|
|
4
|
-
|
|
5
|
-
import { AppBar } from "@/components/board/app-bar"
|
|
6
|
-
import { EpicList } from "@/components/board/epic-list"
|
|
7
|
-
import { ListViewSwitcher } from "@/components/board/list-view-switcher"
|
|
8
|
-
import { OverallWorkItemsList } from "@/components/board/overall-work-items-list"
|
|
9
|
-
import { ProjectStatusMetricsStrip } from "@/components/board/project-status-metrics-strip"
|
|
10
|
-
import { StaticBoardApp } from "@/components/board/static-board-app"
|
|
11
|
-
import { TaskList } from "@/components/board/task-list"
|
|
12
|
-
import { WorkItemsList } from "@/components/board/work-items-list"
|
|
13
|
-
import { WorkItemSheetProvider } from "@/components/board/work-item-sheet"
|
|
14
|
-
import { resolveActiveProject } from "@/lib/taskmark/active-project"
|
|
15
|
-
import {
|
|
16
|
-
getActiveProjectCookie,
|
|
17
|
-
getHideCompletedCookies,
|
|
18
|
-
getMasterFoldersCookie,
|
|
19
|
-
} from "@/lib/taskmark/cookies"
|
|
20
|
-
import {
|
|
21
|
-
LIST_VIEW_LABELS,
|
|
22
|
-
boardHref,
|
|
23
|
-
parseListViewMode,
|
|
24
|
-
type ListViewMode,
|
|
25
|
-
} from "@/lib/taskmark/list-view-mode"
|
|
26
|
-
import { DEV_RELOAD_TOKEN } from "@/lib/taskmark/dev-reload-token"
|
|
27
|
-
import { loadSnapshotFromPublic } from "@/lib/taskmark/load-snapshot-server"
|
|
28
|
-
import { parseEpicsForProject } from "@/lib/taskmark/parse-epics"
|
|
29
|
-
import {
|
|
30
|
-
parseWorkItemsForEpic,
|
|
31
|
-
parseWorkItemsViewForProject,
|
|
32
|
-
} from "@/lib/taskmark/parse-flat-lists"
|
|
33
|
-
import { parseItemsForStory } from "@/lib/taskmark/parse-items"
|
|
34
|
-
import {
|
|
35
|
-
collectCompletedLeafPointSamples,
|
|
36
|
-
collectMetricLeaves,
|
|
37
|
-
computeProjectStatusMetrics,
|
|
38
|
-
} from "@/lib/taskmark/project-metrics"
|
|
39
|
-
import { isStaticRuntime } from "@/lib/taskmark/static-mode"
|
|
40
|
-
import { loadWorkspace } from "@/lib/taskmark/workspace"
|
|
1
|
+
import { BoardScreen } from "@/components/board/board-screen"
|
|
41
2
|
|
|
42
3
|
export const dynamic = "force-dynamic"
|
|
43
4
|
|
|
44
|
-
// Keep this import so `taskmark dev` can touch the token module and refresh RSC.
|
|
45
|
-
void DEV_RELOAD_TOKEN
|
|
46
|
-
|
|
47
5
|
type BoardPageProps = {
|
|
48
6
|
searchParams: Promise<{
|
|
49
7
|
view?: string | string[]
|
|
@@ -53,234 +11,7 @@ type BoardPageProps = {
|
|
|
53
11
|
}>
|
|
54
12
|
}
|
|
55
13
|
|
|
56
|
-
|
|
57
|
-
if (typeof value === "string" && value.trim()) return value.trim()
|
|
58
|
-
return null
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function headingForView(view: ListViewMode): string {
|
|
62
|
-
if (view === "overall") return "Epics"
|
|
63
|
-
return LIST_VIEW_LABELS[view]
|
|
64
|
-
}
|
|
65
|
-
|
|
14
|
+
/** Alias of `/` — kept so older links and bookmarks keep working. */
|
|
66
15
|
export default async function BoardPage({ searchParams }: BoardPageProps) {
|
|
67
|
-
|
|
68
|
-
const snapshot = loadSnapshotFromPublic()
|
|
69
|
-
return (
|
|
70
|
-
<Suspense fallback={<div className="p-8 text-sm text-muted-foreground">Loading board…</div>}>
|
|
71
|
-
<StaticBoardApp snapshot={snapshot} />
|
|
72
|
-
</Suspense>
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const masters = await getMasterFoldersCookie()
|
|
77
|
-
const workspace = loadWorkspace(masters)
|
|
78
|
-
if (workspace.projects.length === 0) {
|
|
79
|
-
redirect("/setup")
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const savedActiveId = await getActiveProjectCookie()
|
|
83
|
-
const hideCompletedPrefs = await getHideCompletedCookies()
|
|
84
|
-
const activeProject = resolveActiveProject(
|
|
85
|
-
workspace.projects,
|
|
86
|
-
// Autoconfig: prefer the bound board; ignore stale active-project cookies.
|
|
87
|
-
workspace.autoconfig ? null : savedActiveId
|
|
88
|
-
)
|
|
89
|
-
if (!activeProject) {
|
|
90
|
-
redirect("/setup")
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const params = await searchParams
|
|
94
|
-
const activeView = parseListViewMode(params.view)
|
|
95
|
-
const selectedEpicId =
|
|
96
|
-
activeView === "overall" ? paramValue(params.epic) : null
|
|
97
|
-
const selectedStoryId =
|
|
98
|
-
activeView === "overall" && selectedEpicId
|
|
99
|
-
? paramValue(params.story)
|
|
100
|
-
: null
|
|
101
|
-
const selectedItemId = paramValue(params.item)
|
|
102
|
-
|
|
103
|
-
const list = parseEpicsForProject(activeProject)
|
|
104
|
-
const epicCount = list.epics.length
|
|
105
|
-
const errorCount = list.errors.length
|
|
106
|
-
|
|
107
|
-
const selectedEpic = selectedEpicId
|
|
108
|
-
? list.epics.find((e) => e.id === selectedEpicId) ?? null
|
|
109
|
-
: null
|
|
110
|
-
|
|
111
|
-
const epicWorkItems =
|
|
112
|
-
activeView === "overall" && selectedEpicId != null
|
|
113
|
-
? parseWorkItemsForEpic(
|
|
114
|
-
activeProject,
|
|
115
|
-
selectedEpicId,
|
|
116
|
-
selectedEpic?.title ?? null
|
|
117
|
-
)
|
|
118
|
-
: null
|
|
119
|
-
|
|
120
|
-
const selectedStory =
|
|
121
|
-
epicWorkItems && selectedStoryId
|
|
122
|
-
? (epicWorkItems.rows.find(
|
|
123
|
-
(row) => row.kind === "story" && row.id === selectedStoryId
|
|
124
|
-
) ?? null)
|
|
125
|
-
: null
|
|
126
|
-
|
|
127
|
-
const itemList =
|
|
128
|
-
activeView === "overall" &&
|
|
129
|
-
selectedEpicId != null &&
|
|
130
|
-
selectedStory != null
|
|
131
|
-
? parseItemsForStory(activeProject, selectedEpicId, selectedStory.id)
|
|
132
|
-
: null
|
|
133
|
-
|
|
134
|
-
const workItemsList =
|
|
135
|
-
activeView === "overall" || activeView === "workitems"
|
|
136
|
-
? parseWorkItemsViewForProject(activeProject)
|
|
137
|
-
: null
|
|
138
|
-
|
|
139
|
-
/** Match Current Speed exactly: completed task/bug leaf points only. */
|
|
140
|
-
const countableCompletions = collectCompletedLeafPointSamples(
|
|
141
|
-
collectMetricLeaves(activeProject)
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
const statusMetrics = computeProjectStatusMetrics(activeProject)
|
|
145
|
-
|
|
146
|
-
return (
|
|
147
|
-
<WorkItemSheetProvider>
|
|
148
|
-
<div className="min-h-svh bg-[linear-gradient(180deg,_#fff_0%,_#f7f4ff_100%)]">
|
|
149
|
-
<AppBar
|
|
150
|
-
projects={workspace.projects}
|
|
151
|
-
activeProjectId={activeProject.id}
|
|
152
|
-
autoconfig={workspace.autoconfig}
|
|
153
|
-
/>
|
|
154
|
-
|
|
155
|
-
<div className="mx-auto flex w-full max-w-5xl flex-col gap-6 px-4 py-8">
|
|
156
|
-
<div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
|
|
157
|
-
<div>
|
|
158
|
-
<h1 className="font-head text-3xl tracking-tight">
|
|
159
|
-
{headingForView(activeView)}
|
|
160
|
-
</h1>
|
|
161
|
-
<p className="mt-1 text-sm text-muted-foreground">
|
|
162
|
-
{activeProject.name}
|
|
163
|
-
{activeView === "overall"
|
|
164
|
-
? ` · ${epicCount} epic${epicCount === 1 ? "" : "s"}`
|
|
165
|
-
: ""}
|
|
166
|
-
{activeView === "overall" && errorCount > 0
|
|
167
|
-
? ` · ${errorCount} parse issue${errorCount === 1 ? "" : "s"}`
|
|
168
|
-
: ""}
|
|
169
|
-
{activeView === "workitems" && workItemsList
|
|
170
|
-
? ` · ${workItemsList.rows.length} item${workItemsList.rows.length === 1 ? "" : "s"}`
|
|
171
|
-
: ""}
|
|
172
|
-
{activeView === "overall" && selectedEpic
|
|
173
|
-
? ` · selected ${selectedEpic.id}`
|
|
174
|
-
: activeView === "overall" && selectedEpicId
|
|
175
|
-
? ` · epic ${selectedEpicId} not in list`
|
|
176
|
-
: activeView === "overall"
|
|
177
|
-
? " · select an epic to view work items"
|
|
178
|
-
: ""}
|
|
179
|
-
{activeView === "overall" && selectedStory
|
|
180
|
-
? ` · story ${selectedStory.id}`
|
|
181
|
-
: activeView === "overall" && selectedStoryId
|
|
182
|
-
? ` · story ${selectedStoryId} not in list`
|
|
183
|
-
: ""}
|
|
184
|
-
</p>
|
|
185
|
-
</div>
|
|
186
|
-
<ListViewSwitcher
|
|
187
|
-
activeView={activeView}
|
|
188
|
-
selectedEpicId={selectedEpicId}
|
|
189
|
-
selectedStoryId={selectedStory?.id ?? null}
|
|
190
|
-
/>
|
|
191
|
-
</div>
|
|
192
|
-
|
|
193
|
-
<ProjectStatusMetricsStrip metrics={statusMetrics} />
|
|
194
|
-
|
|
195
|
-
{activeView === "overall" ? (
|
|
196
|
-
<>
|
|
197
|
-
<EpicList
|
|
198
|
-
lists={[list]}
|
|
199
|
-
selectedEpicId={selectedEpicId}
|
|
200
|
-
countableCompletions={countableCompletions}
|
|
201
|
-
initialHideCompleted={hideCompletedPrefs.epics}
|
|
202
|
-
/>
|
|
203
|
-
|
|
204
|
-
{epicWorkItems ? (
|
|
205
|
-
<div className="flex flex-col gap-3">
|
|
206
|
-
<div className="flex items-baseline justify-between gap-3">
|
|
207
|
-
<h2 className="font-head text-2xl tracking-tight">
|
|
208
|
-
Work items for{" "}
|
|
209
|
-
{epicWorkItems.epicTitle ?? epicWorkItems.epicId}
|
|
210
|
-
</h2>
|
|
211
|
-
<Link
|
|
212
|
-
href={boardHref({
|
|
213
|
-
view: "overall",
|
|
214
|
-
item: selectedItemId,
|
|
215
|
-
})}
|
|
216
|
-
className="text-sm text-muted-foreground underline-offset-2 hover:underline"
|
|
217
|
-
>
|
|
218
|
-
Clear selection
|
|
219
|
-
</Link>
|
|
220
|
-
</div>
|
|
221
|
-
<p className="text-sm text-muted-foreground">
|
|
222
|
-
{epicWorkItems.rows.length} work item
|
|
223
|
-
{epicWorkItems.rows.length === 1 ? "" : "s"}
|
|
224
|
-
{epicWorkItems.errors.length > 0
|
|
225
|
-
? ` · ${epicWorkItems.errors.length} issue${epicWorkItems.errors.length === 1 ? "" : "s"}`
|
|
226
|
-
: ""}
|
|
227
|
-
{!selectedStory
|
|
228
|
-
? " · select a story to view its sub tasks"
|
|
229
|
-
: ""}
|
|
230
|
-
</p>
|
|
231
|
-
<OverallWorkItemsList
|
|
232
|
-
list={epicWorkItems}
|
|
233
|
-
selectedStoryId={selectedStory?.id ?? null}
|
|
234
|
-
countableCompletions={countableCompletions}
|
|
235
|
-
initialHideCompleted={hideCompletedPrefs.overallWorkItems}
|
|
236
|
-
/>
|
|
237
|
-
</div>
|
|
238
|
-
) : null}
|
|
239
|
-
|
|
240
|
-
{itemList && selectedStory ? (
|
|
241
|
-
<div className="flex flex-col gap-3">
|
|
242
|
-
<div className="flex items-baseline justify-between gap-3">
|
|
243
|
-
<h2 className="font-head text-2xl tracking-tight">
|
|
244
|
-
Sub Tasks for{" "}
|
|
245
|
-
{itemList.storyTitle ?? itemList.storyId}
|
|
246
|
-
</h2>
|
|
247
|
-
<Link
|
|
248
|
-
href={boardHref({
|
|
249
|
-
view: "overall",
|
|
250
|
-
epic: itemList.epicId,
|
|
251
|
-
item: selectedItemId,
|
|
252
|
-
})}
|
|
253
|
-
className="text-sm text-muted-foreground underline-offset-2 hover:underline"
|
|
254
|
-
>
|
|
255
|
-
Clear story
|
|
256
|
-
</Link>
|
|
257
|
-
</div>
|
|
258
|
-
<p className="text-sm text-muted-foreground">
|
|
259
|
-
{itemList.items.length} sub task
|
|
260
|
-
{itemList.items.length === 1 ? "" : "s"}
|
|
261
|
-
{itemList.errors.length > 0
|
|
262
|
-
? ` · ${itemList.errors.length} issue${itemList.errors.length === 1 ? "" : "s"}`
|
|
263
|
-
: ""}
|
|
264
|
-
</p>
|
|
265
|
-
<TaskList
|
|
266
|
-
list={itemList}
|
|
267
|
-
countableCompletions={countableCompletions}
|
|
268
|
-
initialHideCompleted={hideCompletedPrefs.tasks}
|
|
269
|
-
/>
|
|
270
|
-
</div>
|
|
271
|
-
) : null}
|
|
272
|
-
</>
|
|
273
|
-
) : null}
|
|
274
|
-
|
|
275
|
-
{activeView === "workitems" && workItemsList ? (
|
|
276
|
-
<WorkItemsList
|
|
277
|
-
list={workItemsList}
|
|
278
|
-
countableCompletions={countableCompletions}
|
|
279
|
-
initialHideCompleted={hideCompletedPrefs.workItems}
|
|
280
|
-
/>
|
|
281
|
-
) : null}
|
|
282
|
-
</div>
|
|
283
|
-
</div>
|
|
284
|
-
</WorkItemSheetProvider>
|
|
285
|
-
)
|
|
16
|
+
return <BoardScreen searchParams={searchParams} />
|
|
286
17
|
}
|
package/app/globals.css
CHANGED
|
@@ -94,6 +94,14 @@
|
|
|
94
94
|
--shadow-lg: 9px 9px 0 0 var(--shadow-color);
|
|
95
95
|
--shadow-xl: 14px 14px 0 1px var(--shadow-color);
|
|
96
96
|
--shadow-2xl: 20px 20px 0 2px var(--shadow-color);
|
|
97
|
+
--surface-gradient: linear-gradient(180deg, #ffffff 0%, #f7f4ff 100%);
|
|
98
|
+
--surface-glow: radial-gradient(ellipse at top, #eadffe 0%, transparent 55%);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@layer base {
|
|
102
|
+
body {
|
|
103
|
+
@apply bg-background text-foreground;
|
|
104
|
+
}
|
|
97
105
|
}
|
|
98
106
|
|
|
99
107
|
/* Markdown body: reset outer margins without Tailwind arbitrary :first-child variants
|
|
@@ -105,6 +113,21 @@
|
|
|
105
113
|
margin-bottom: 0;
|
|
106
114
|
}
|
|
107
115
|
|
|
116
|
+
.tm-mermaid svg {
|
|
117
|
+
max-width: 100%;
|
|
118
|
+
height: auto;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* Page surfaces follow the theme tokens instead of a light-only gradient. */
|
|
122
|
+
.tm-surface {
|
|
123
|
+
background-color: var(--background);
|
|
124
|
+
background-image: var(--surface-gradient);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.tm-surface-glow {
|
|
128
|
+
background-image: var(--surface-glow), var(--surface-gradient);
|
|
129
|
+
}
|
|
130
|
+
|
|
108
131
|
.dark {
|
|
109
132
|
--background: #0f0f0f;
|
|
110
133
|
--foreground: #fafafa;
|
|
@@ -134,6 +157,8 @@
|
|
|
134
157
|
--chart-5: #7b6df5;
|
|
135
158
|
--radius: 0.25rem;
|
|
136
159
|
--border-w: 2px;
|
|
160
|
+
--surface-gradient: linear-gradient(180deg, #0f0f0f 0%, #171325 100%);
|
|
161
|
+
--surface-glow: radial-gradient(ellipse at top, #2f2542 0%, transparent 55%);
|
|
137
162
|
--shadow-xs: 2px 2px 0 0 var(--shadow-color);
|
|
138
163
|
--shadow-sm: 3px 3px 0 0 var(--shadow-color);
|
|
139
164
|
--shadow: 5px 5px 0 0 var(--shadow-color);
|
package/app/layout.tsx
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { Metadata, Viewport } from "next"
|
|
2
2
|
import { Archivo_Black, Space_Grotesk } from "next/font/google"
|
|
3
|
+
import Script from "next/script"
|
|
3
4
|
import { BoardDevReloader } from "@/components/board/board-dev-reloader"
|
|
5
|
+
import { ThemeProvider } from "@/components/theme-provider"
|
|
4
6
|
import { Toaster } from "@/components/ui/sonner"
|
|
5
7
|
import { SITE } from "@/lib/site"
|
|
8
|
+
import { THEME_INIT_SCRIPT } from "@/lib/theme-cookie"
|
|
6
9
|
import "./globals.css"
|
|
7
10
|
|
|
8
11
|
const archivoBlack = Archivo_Black({
|
|
@@ -19,7 +22,7 @@ const spaceGrotesk = Space_Grotesk({
|
|
|
19
22
|
})
|
|
20
23
|
|
|
21
24
|
const siteDescription =
|
|
22
|
-
"Taskmark — product memory for agent work. Local markdown boards for Cursor with sizing
|
|
25
|
+
"Taskmark — product memory for agent work. Local markdown boards for Cursor with static sizing and work logs."
|
|
23
26
|
|
|
24
27
|
export const viewport: Viewport = {
|
|
25
28
|
themeColor: "#111111",
|
|
@@ -76,13 +79,20 @@ export default function RootLayout({
|
|
|
76
79
|
children: React.ReactNode
|
|
77
80
|
}) {
|
|
78
81
|
return (
|
|
79
|
-
<html lang="en">
|
|
82
|
+
<html lang="en" suppressHydrationWarning>
|
|
80
83
|
<body
|
|
81
84
|
className={`${archivoBlack.variable} ${spaceGrotesk.variable} font-sans antialiased`}
|
|
82
85
|
>
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
<Script
|
|
87
|
+
id="taskmark-theme-init"
|
|
88
|
+
strategy="beforeInteractive"
|
|
89
|
+
dangerouslySetInnerHTML={{ __html: THEME_INIT_SCRIPT }}
|
|
90
|
+
/>
|
|
91
|
+
<ThemeProvider>
|
|
92
|
+
<Toaster />
|
|
93
|
+
<BoardDevReloader />
|
|
94
|
+
{children}
|
|
95
|
+
</ThemeProvider>
|
|
86
96
|
</body>
|
|
87
97
|
</html>
|
|
88
98
|
)
|
package/app/page.tsx
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BoardScreen } from "@/components/board/board-screen"
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
import { isStaticRuntime } from "@/lib/taskmark/static-mode"
|
|
5
|
-
import { loadWorkspace } from "@/lib/taskmark/workspace"
|
|
3
|
+
export const dynamic = "force-dynamic"
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
5
|
+
type HomePageProps = {
|
|
6
|
+
searchParams: Promise<{
|
|
7
|
+
view?: string | string[]
|
|
8
|
+
epic?: string | string[]
|
|
9
|
+
story?: string | string[]
|
|
10
|
+
item?: string | string[]
|
|
11
|
+
}>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** The board is the default view; BoardScreen sends unbound setups to /setup. */
|
|
15
|
+
export default async function HomePage({ searchParams }: HomePageProps) {
|
|
16
|
+
return <BoardScreen searchParams={searchParams} />
|
|
17
17
|
}
|
package/app/setup/actions.ts
CHANGED
|
@@ -64,7 +64,7 @@ export async function saveMasterFolder(
|
|
|
64
64
|
await setActiveProjectCookie(preferred.id)
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
redirect("/
|
|
67
|
+
redirect("/")
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
export type PickMasterFolderState = {
|
|
@@ -89,7 +89,7 @@ export async function openAddProject(): Promise<void> {
|
|
|
89
89
|
"@/lib/taskmark/autoconfig"
|
|
90
90
|
)
|
|
91
91
|
if (resolveAutoconfigWorkspace()?.projects.length) {
|
|
92
|
-
redirect("/
|
|
92
|
+
redirect("/")
|
|
93
93
|
}
|
|
94
94
|
redirect("/setup?mode=add")
|
|
95
95
|
}
|
|
@@ -100,8 +100,8 @@ export async function selectActiveProject(formData: FormData): Promise<void> {
|
|
|
100
100
|
return
|
|
101
101
|
}
|
|
102
102
|
await setActiveProjectCookie(projectId)
|
|
103
|
-
revalidatePath("/
|
|
104
|
-
redirect("/
|
|
103
|
+
revalidatePath("/")
|
|
104
|
+
redirect("/")
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
/** Optional: clear everything and start over (not shown in app bar by default). */
|
package/app/setup/page.tsx
CHANGED
|
@@ -12,15 +12,20 @@ type SetupPageProps = {
|
|
|
12
12
|
searchParams?: Promise<{ mode?: string }>
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
// Depends on runtime env (workspace vs bound) and cookies — never prerender in
|
|
16
|
+
// server mode, or a build-time redirect gets baked in and loops against `/`.
|
|
17
|
+
// The static build rewrites this to force-static (see scripts/build-static.mjs).
|
|
18
|
+
export const dynamic = "force-dynamic"
|
|
19
|
+
|
|
15
20
|
export default async function SetupPage({ searchParams }: SetupPageProps) {
|
|
16
21
|
if (isStaticRuntime()) {
|
|
17
|
-
redirect("/
|
|
22
|
+
redirect("/")
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
const auto = resolveAutoconfigWorkspace()
|
|
21
26
|
if (auto && auto.projects.length > 0) {
|
|
22
27
|
// Zero-config bind — setup wizard is not needed.
|
|
23
|
-
redirect("/
|
|
28
|
+
redirect("/")
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
const params = searchParams ? await searchParams : {}
|
|
@@ -34,7 +39,7 @@ export default async function SetupPage({ searchParams }: SetupPageProps) {
|
|
|
34
39
|
<div className="relative flex min-h-svh flex-col items-center justify-center px-4 py-16">
|
|
35
40
|
<div
|
|
36
41
|
aria-hidden
|
|
37
|
-
className="pointer-events-none absolute inset-0
|
|
42
|
+
className="tm-surface-glow pointer-events-none absolute inset-0"
|
|
38
43
|
/>
|
|
39
44
|
<div className="relative z-10 flex w-full max-w-xl flex-col items-center gap-8">
|
|
40
45
|
<div className="flex flex-col items-center text-center">
|
|
@@ -59,7 +64,7 @@ export default async function SetupPage({ searchParams }: SetupPageProps) {
|
|
|
59
64
|
/>
|
|
60
65
|
{adding ? (
|
|
61
66
|
<p className="text-sm text-muted-foreground">
|
|
62
|
-
<Link href="/
|
|
67
|
+
<Link href="/" className="underline underline-offset-2">
|
|
63
68
|
Cancel and return to board
|
|
64
69
|
</Link>
|
|
65
70
|
</p>
|
|
@@ -2,10 +2,7 @@ import fs from "node:fs"
|
|
|
2
2
|
import path from "node:path"
|
|
3
3
|
|
|
4
4
|
function hasBoardMarkers(boardPath) {
|
|
5
|
-
return (
|
|
6
|
-
fs.existsSync(path.join(boardPath, "INDEX.md")) ||
|
|
7
|
-
fs.existsSync(path.join(boardPath, "epics"))
|
|
8
|
-
)
|
|
5
|
+
return fs.existsSync(path.join(boardPath, "epics"))
|
|
9
6
|
}
|
|
10
7
|
|
|
11
8
|
function isDedicatedBoardRepoName(name) {
|
package/bin/taskmark.js
CHANGED
|
@@ -139,6 +139,19 @@ function resolveNextBin() {
|
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
/**
|
|
143
|
+
* A `taskmark build` writes an `output: export` build. It has a server/ dir but
|
|
144
|
+
* serves prerendered HTML with the static runtime baked in, so `serve` must not
|
|
145
|
+
* reuse it.
|
|
146
|
+
*/
|
|
147
|
+
function isStaticExportBuild(dir) {
|
|
148
|
+
return fs.existsSync(path.join(dir, "export-detail.json"))
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function hasServerBuild(dir) {
|
|
152
|
+
return fs.existsSync(path.join(dir, "server")) && !isStaticExportBuild(dir)
|
|
153
|
+
}
|
|
154
|
+
|
|
142
155
|
/**
|
|
143
156
|
* Ensure packageRoot/.next points at a usable production build.
|
|
144
157
|
* Published packages ship dist/prod-next (npm cannot pack nested node_modules
|
|
@@ -147,8 +160,8 @@ function resolveNextBin() {
|
|
|
147
160
|
function ensureProdNext() {
|
|
148
161
|
const nextDir = path.join(packageRoot, ".next")
|
|
149
162
|
const shipped = path.join(packageRoot, "dist", "prod-next")
|
|
150
|
-
const hasLocalServer =
|
|
151
|
-
const hasShippedServer =
|
|
163
|
+
const hasLocalServer = hasServerBuild(nextDir)
|
|
164
|
+
const hasShippedServer = hasServerBuild(shipped)
|
|
152
165
|
|
|
153
166
|
if (hasLocalServer) return nextDir
|
|
154
167
|
if (!hasShippedServer) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { selectActiveProject, openAddProject } from "@/app/setup/actions"
|
|
4
4
|
import { BrandLogo } from "@/components/brand-logo"
|
|
5
|
+
import { ThemeToggle } from "@/components/theme-toggle"
|
|
5
6
|
import { Button } from "@/components/ui/button"
|
|
6
7
|
import { projectOptionLabel } from "@/lib/taskmark/project-label"
|
|
7
8
|
import type { DiscoveredProject } from "@/lib/taskmark/types"
|
|
@@ -90,6 +91,8 @@ export function AppBar({
|
|
|
90
91
|
</Button>
|
|
91
92
|
</form>
|
|
92
93
|
) : null}
|
|
94
|
+
|
|
95
|
+
<ThemeToggle />
|
|
93
96
|
</div>
|
|
94
97
|
</header>
|
|
95
98
|
)
|