@leanspec/ui 0.2.7 → 0.2.9
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/packages/ui/.next/BUILD_ID +1 -1
- package/.next/standalone/packages/ui/.next/app-path-routes-manifest.json +4 -0
- package/.next/standalone/packages/ui/.next/build-manifest.json +4 -4
- package/.next/standalone/packages/ui/.next/prerender-manifest.json +3 -3
- package/.next/standalone/packages/ui/.next/routes-manifest.json +24 -0
- package/.next/standalone/packages/ui/.next/server/app/_global-error/page/build-manifest.json +2 -2
- package/.next/standalone/packages/ui/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_global-error.html +2 -2
- package/.next/standalone/packages/ui/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_not-found/page/build-manifest.json +2 -2
- package/.next/standalone/packages/ui/.next/server/app/_not-found/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/_not-found.html +2 -2
- package/.next/standalone/packages/ui/.next/server/app/_not-found.rsc +19 -19
- package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_full.segment.rsc +19 -19
- package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_index.segment.rsc +11 -11
- package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +3 -3
- package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_tree.segment.rsc +6 -6
- package/.next/standalone/packages/ui/.next/server/app/api/context/route/app-paths-manifest.json +3 -0
- package/.next/standalone/packages/ui/.next/server/app/api/context/route/build-manifest.json +11 -0
- package/.next/standalone/packages/ui/.next/server/app/api/context/route/server-reference-manifest.json +4 -0
- package/.next/standalone/packages/ui/.next/server/app/api/context/route.js +8 -0
- package/.next/standalone/packages/ui/.next/server/app/api/context/route.js.map +5 -0
- package/.next/standalone/packages/ui/.next/server/app/api/context/route.js.nft.json +1 -0
- package/.next/standalone/packages/ui/.next/server/app/api/context/route_client-reference-manifest.js +2 -0
- package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route/app-paths-manifest.json +3 -0
- package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route/build-manifest.json +11 -0
- package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route/server-reference-manifest.json +4 -0
- package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route.js +8 -0
- package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route.js.map +5 -0
- package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route.js.nft.json +1 -0
- package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route_client-reference-manifest.js +2 -0
- package/.next/standalone/packages/ui/.next/server/app/api/local-projects/[id]/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/local-projects/discover/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/local-projects/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/revalidate/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/dependency-graph/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/status/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/subspecs/[file]/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/api/stats/route.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/context/page/app-paths-manifest.json +3 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page/build-manifest.json +18 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page/next-font-manifest.json +6 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page/react-loadable-manifest.json +1 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page/server-reference-manifest.json +4 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page.js +19 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page.js.map +5 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page.js.nft.json +1 -0
- package/.next/standalone/packages/ui/.next/server/app/context/page_client-reference-manifest.js +2 -0
- package/.next/standalone/packages/ui/.next/server/app/dependencies/page/app-paths-manifest.json +3 -0
- package/.next/standalone/packages/ui/.next/server/app/dependencies/page/build-manifest.json +18 -0
- package/.next/standalone/packages/ui/.next/server/app/dependencies/page/next-font-manifest.json +6 -0
- package/.next/standalone/packages/ui/.next/server/app/dependencies/page/react-loadable-manifest.json +1 -0
- package/.next/standalone/packages/ui/.next/server/app/dependencies/page/server-reference-manifest.json +4 -0
- package/.next/standalone/packages/ui/.next/server/app/dependencies/page.js +19 -0
- package/.next/standalone/packages/ui/.next/server/app/dependencies/page.js.map +5 -0
- package/.next/standalone/packages/ui/.next/server/app/dependencies/page.js.nft.json +1 -0
- package/.next/standalone/packages/ui/.next/server/app/dependencies/page_client-reference-manifest.js +2 -0
- package/.next/standalone/packages/ui/.next/server/app/page/build-manifest.json +2 -2
- package/.next/standalone/packages/ui/.next/server/app/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page/build-manifest.json +2 -2
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page/build-manifest.json +2 -2
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page/build-manifest.json +2 -2
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/page/build-manifest.json +2 -2
- package/.next/standalone/packages/ui/.next/server/app/projects/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/projects.html +2 -2
- package/.next/standalone/packages/ui/.next/server/app/projects.rsc +24 -23
- package/.next/standalone/packages/ui/.next/server/app/projects.segments/_full.segment.rsc +24 -23
- package/.next/standalone/packages/ui/.next/server/app/projects.segments/_index.segment.rsc +9 -9
- package/.next/standalone/packages/ui/.next/server/app/projects.segments/_tree.segment.rsc +3 -3
- package/.next/standalone/packages/ui/.next/server/app/projects.segments/projects/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/packages/ui/.next/server/app/projects.segments/projects.segment.rsc +1 -1
- package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page/build-manifest.json +2 -2
- package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/specs/page/build-manifest.json +2 -2
- package/.next/standalone/packages/ui/.next/server/app/specs/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/specs/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/specs/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/stats/page/build-manifest.json +2 -2
- package/.next/standalone/packages/ui/.next/server/app/stats/page.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app/stats/page.js.nft.json +1 -1
- package/.next/standalone/packages/ui/.next/server/app/stats/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/app-paths-manifest.json +4 -0
- package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__3559376c._.js +2 -2
- package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__65667b70._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__803d07f0._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__84cdc14a._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__8a9ab1a3._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__b0969111._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__bdc3963a._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__f5c6d6b8._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/packages_ui__next-internal_server_app_api_context_route_actions_dead6daa.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/packages_ui__next-internal_server_app_api_dependencies_route_actions_cf6b14c3.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__12b4eb41._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__3c77d95b._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__44b603f9._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__69a0d63a._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/{[root-of-the-server]__daee3355._.js → [root-of-the-server]__8608a6fa._.js} +2 -2
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/{[root-of-the-server]__fd80e4dd._.js → [root-of-the-server]__a965a67b._.js} +2 -2
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__daedd80e._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__dc176c61._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/{[root-of-the-server]__5382b397._.js → [root-of-the-server]__ead1539c._.js} +2 -2
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_000dd317._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_03aa8d19._.js +7 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_28fe1532._.js +5 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_8cec504f._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_959ad3d8._.js +4 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/{_22274047._.js → _adb9d7cb._.js} +2 -2
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_da18b655._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_ea899b87._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_f38e75b7._.js +4 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_fe120f8a._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_015f83ca._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_1120b57c._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_151891de._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_1c916fe3._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_80605a06._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_bb80de48._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_e8075f9b._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_f919ef4a._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui__next-internal_server_app_context_page_actions_1a062d48.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui__next-internal_server_app_dependencies_page_actions_57387d47.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_context_context-client_tsx_4ba99a62._.js +12 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_dependencies_dependencies-client_tsx_0e82443a._.js +4 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_specs_specs-client_tsx_0bb8f8f8._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_components_spec-detail-wrapper_tsx_fd35401c._.js +3 -0
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_components_specs-nav-sidebar_tsx_8237ed13._.js +1 -1
- package/.next/standalone/packages/ui/.next/server/middleware-build-manifest.js +2 -2
- package/.next/standalone/packages/ui/.next/server/pages/404.html +2 -2
- package/.next/standalone/packages/ui/.next/server/pages/500.html +2 -2
- package/.next/standalone/packages/ui/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/packages/ui/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/packages/ui/.next/static/chunks/094cf9f4e3553261.js +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/1c015eb9eaaf9f9c.js +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/1d36660b2877d213.js +3 -0
- package/.next/standalone/packages/ui/.next/static/chunks/46275d9d67603bf5.js +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/4d29ca0fa6843070.js +2 -0
- package/.next/standalone/packages/ui/.next/static/chunks/59854b15bf046467.js +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/{cca4441cde342ae3.js → 5fd8101e32b076b1.js} +1 -1
- package/.next/standalone/packages/ui/.next/static/chunks/6d938a49daa10208.js +2 -0
- package/.next/standalone/packages/ui/.next/static/chunks/979625373d5474b6.js +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/a33f10af6abef4df.js +10 -0
- package/.next/{static/chunks/794f3931f1ca12d2.js → standalone/packages/ui/.next/static/chunks/a3d7e1be47de010b.js} +1 -1
- package/.next/standalone/packages/ui/.next/static/chunks/a5e25b9fa6b88eee.js +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/b53250480fde6816.js +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/b7f19087afe1d2c9.css +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/c658e22a605e0ed1.js +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/c92660d8d0c4763d.js +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/ddd87cd0d26bc2f5.js +1 -0
- package/.next/standalone/packages/ui/.next/static/chunks/eeec245955b3b600.js +5 -0
- package/.next/standalone/packages/ui/.next/static/chunks/ff11efb770d5a0bc.js +1 -0
- package/.next/{static/chunks/turbopack-5fa55215af0efb15.js → standalone/packages/ui/.next/static/chunks/turbopack-261c5dcdd873f310.js} +1 -1
- package/.next/standalone/packages/ui/package.json +5 -1
- package/.next/standalone/packages/ui/src/app/api/context/route.ts +22 -0
- package/.next/standalone/packages/ui/src/app/api/dependencies/route.ts +81 -0
- package/.next/standalone/packages/ui/src/app/context/context-client.tsx +393 -0
- package/.next/standalone/packages/ui/src/app/context/page.tsx +17 -0
- package/.next/standalone/packages/ui/src/app/dependencies/constants.ts +24 -0
- package/.next/standalone/packages/ui/src/app/dependencies/dependencies-client.tsx +625 -0
- package/.next/standalone/packages/ui/src/app/dependencies/index.ts +19 -0
- package/.next/standalone/packages/ui/src/app/dependencies/page.tsx +38 -0
- package/.next/standalone/packages/ui/src/app/dependencies/spec-node.tsx +80 -0
- package/.next/standalone/packages/ui/src/app/dependencies/spec-sidebar.tsx +198 -0
- package/.next/standalone/packages/ui/src/app/dependencies/types.ts +37 -0
- package/.next/standalone/packages/ui/src/app/dependencies/utils.ts +194 -0
- package/.next/standalone/packages/ui/src/app/globals.css +16 -16
- package/.next/standalone/packages/ui/src/app/layout.tsx +4 -7
- package/.next/standalone/packages/ui/src/components/context-file-detail.tsx +308 -0
- package/.next/standalone/packages/ui/src/components/context-file-viewer.tsx +385 -0
- package/.next/standalone/packages/ui/src/components/main-sidebar.tsx +19 -1
- package/.next/standalone/packages/ui/src/components/spec-detail-client.tsx +181 -134
- package/.next/standalone/packages/ui/src/components/spec-detail-wrapper.tsx +20 -0
- package/.next/standalone/packages/ui/src/components/specs-nav-sidebar.tsx +3 -2
- package/.next/standalone/packages/ui/src/components/ui/accordion.tsx +58 -0
- package/.next/standalone/packages/ui/src/lib/db/service-queries.ts +172 -3
- package/.next/standalone/packages/ui/src/lib/specs/types.ts +44 -0
- package/.next/standalone/packages/ui/tsconfig.tsbuildinfo +1 -1
- package/.next/static/chunks/094cf9f4e3553261.js +1 -0
- package/.next/static/chunks/1c015eb9eaaf9f9c.js +1 -0
- package/.next/static/chunks/1d36660b2877d213.js +3 -0
- package/.next/static/chunks/46275d9d67603bf5.js +1 -0
- package/.next/static/chunks/4d29ca0fa6843070.js +2 -0
- package/.next/static/chunks/59854b15bf046467.js +1 -0
- package/.next/static/chunks/{cca4441cde342ae3.js → 5fd8101e32b076b1.js} +1 -1
- package/.next/static/chunks/6d938a49daa10208.js +2 -0
- package/.next/static/chunks/979625373d5474b6.js +1 -0
- package/.next/static/chunks/a33f10af6abef4df.js +10 -0
- package/.next/{standalone/packages/ui/.next/static/chunks/794f3931f1ca12d2.js → static/chunks/a3d7e1be47de010b.js} +1 -1
- package/.next/static/chunks/a5e25b9fa6b88eee.js +1 -0
- package/.next/static/chunks/b53250480fde6816.js +1 -0
- package/.next/static/chunks/b7f19087afe1d2c9.css +1 -0
- package/.next/static/chunks/c658e22a605e0ed1.js +1 -0
- package/.next/static/chunks/c92660d8d0c4763d.js +1 -0
- package/.next/static/chunks/ddd87cd0d26bc2f5.js +1 -0
- package/.next/static/chunks/eeec245955b3b600.js +5 -0
- package/.next/static/chunks/ff11efb770d5a0bc.js +1 -0
- package/.next/{standalone/packages/ui/.next/static/chunks/turbopack-5fa55215af0efb15.js → static/chunks/turbopack-261c5dcdd873f310.js} +1 -1
- package/package.json +6 -2
- package/.next/standalone/node_modules/.pnpm/source-map@0.8.0-beta.0/node_modules/source-map/package.json +0 -95
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__1d0c2012._.js +0 -3
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__73f60f12._.js +0 -7
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__a7ae8552._.js +0 -7
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_0f9ffe32._.js +0 -3
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_14118969._.js +0 -3
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_4129cc0f._.js +0 -3
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_497c8b73._.js +0 -3
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_ac867463._.js +0 -3
- package/.next/standalone/packages/ui/.next/server/chunks/ssr/_c2f54661._.js +0 -5
- package/.next/standalone/packages/ui/.next/static/chunks/16ff9833ae1bb3ae.js +0 -1
- package/.next/standalone/packages/ui/.next/static/chunks/2204c0f16b23ec4c.js +0 -3
- package/.next/standalone/packages/ui/.next/static/chunks/294dea6dbec43ca6.js +0 -1
- package/.next/standalone/packages/ui/.next/static/chunks/7590e65bcaa41e8b.js +0 -1
- package/.next/standalone/packages/ui/.next/static/chunks/b6976cf6c48996e5.js +0 -1
- package/.next/standalone/packages/ui/.next/static/chunks/b8353eb8c6fb895e.js +0 -1
- package/.next/standalone/packages/ui/.next/static/chunks/b845813463167db0.js +0 -5
- package/.next/standalone/packages/ui/.next/static/chunks/bd9893e28f8f6a9a.css +0 -1
- package/.next/standalone/packages/ui/.next/static/chunks/d784d84d5b880e48.js +0 -1
- package/.next/static/chunks/16ff9833ae1bb3ae.js +0 -1
- package/.next/static/chunks/2204c0f16b23ec4c.js +0 -3
- package/.next/static/chunks/294dea6dbec43ca6.js +0 -1
- package/.next/static/chunks/7590e65bcaa41e8b.js +0 -1
- package/.next/static/chunks/b6976cf6c48996e5.js +0 -1
- package/.next/static/chunks/b8353eb8c6fb895e.js +0 -1
- package/.next/static/chunks/b845813463167db0.js +0 -5
- package/.next/static/chunks/bd9893e28f8f6a9a.css +0 -1
- package/.next/static/chunks/d784d84d5b880e48.js +0 -1
- /package/.next/standalone/packages/ui/.next/static/{6nq7WNafPv5Bf_7mWgRQ- → 8PwFWS-09QjFSbDbfp15t}/_buildManifest.js +0 -0
- /package/.next/standalone/packages/ui/.next/static/{6nq7WNafPv5Bf_7mWgRQ- → 8PwFWS-09QjFSbDbfp15t}/_clientMiddlewareManifest.json +0 -0
- /package/.next/standalone/packages/ui/.next/static/{6nq7WNafPv5Bf_7mWgRQ- → 8PwFWS-09QjFSbDbfp15t}/_ssgManifest.js +0 -0
- /package/.next/static/{6nq7WNafPv5Bf_7mWgRQ- → 8PwFWS-09QjFSbDbfp15t}/_buildManifest.js +0 -0
- /package/.next/static/{6nq7WNafPv5Bf_7mWgRQ- → 8PwFWS-09QjFSbDbfp15t}/_clientMiddlewareManifest.json +0 -0
- /package/.next/static/{6nq7WNafPv5Bf_7mWgRQ- → 8PwFWS-09QjFSbDbfp15t}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Handle, Position, NodeProps } from 'reactflow';
|
|
5
|
+
import { cn } from '@/lib/utils';
|
|
6
|
+
import type { SpecNodeData } from './types';
|
|
7
|
+
import {
|
|
8
|
+
NODE_WIDTH,
|
|
9
|
+
COMPACT_NODE_WIDTH,
|
|
10
|
+
toneClasses,
|
|
11
|
+
} from './constants';
|
|
12
|
+
|
|
13
|
+
export const SpecNode = React.memo(function SpecNode({ data }: NodeProps<SpecNodeData>) {
|
|
14
|
+
const isCompact = data.isCompact;
|
|
15
|
+
const isSecondary = data.isSecondary;
|
|
16
|
+
const depthOpacity =
|
|
17
|
+
data.connectionDepth === 0
|
|
18
|
+
? 1
|
|
19
|
+
: data.connectionDepth === 1
|
|
20
|
+
? 0.95
|
|
21
|
+
: data.connectionDepth === 2
|
|
22
|
+
? 0.7
|
|
23
|
+
: data.isDimmed
|
|
24
|
+
? 0.15
|
|
25
|
+
: 1;
|
|
26
|
+
|
|
27
|
+
// Secondary nodes (shown due to critical path) are slightly transparent
|
|
28
|
+
const baseOpacity = isSecondary ? 0.65 : 1;
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div
|
|
32
|
+
className={cn(
|
|
33
|
+
'flex flex-col rounded-lg shadow-lg transition-all duration-200',
|
|
34
|
+
toneClasses[data.tone],
|
|
35
|
+
data.interactive && 'cursor-pointer hover:scale-105 hover:shadow-xl hover:border-white/50',
|
|
36
|
+
data.isFocused && 'ring-2 ring-white ring-offset-2 ring-offset-background scale-110 z-50',
|
|
37
|
+
data.connectionDepth === 1 && 'ring-1 ring-white/40',
|
|
38
|
+
isCompact ? 'px-2 py-1 gap-0.5' : 'px-2.5 py-1.5 gap-0.5',
|
|
39
|
+
isSecondary ? 'border border-dashed' : 'border-2'
|
|
40
|
+
)}
|
|
41
|
+
style={{
|
|
42
|
+
width: isCompact ? COMPACT_NODE_WIDTH : NODE_WIDTH,
|
|
43
|
+
opacity: depthOpacity * baseOpacity,
|
|
44
|
+
transform: data.isDimmed ? 'scale(0.9)' : undefined,
|
|
45
|
+
}}
|
|
46
|
+
>
|
|
47
|
+
<Handle type="target" position={Position.Left} className="opacity-0" />
|
|
48
|
+
<div className="flex items-center justify-between gap-1">
|
|
49
|
+
<span className={cn('font-bold text-white/90', isCompact ? 'text-[9px]' : 'text-[10px]')}>
|
|
50
|
+
#{data.number.toString().padStart(3, '0')}
|
|
51
|
+
</span>
|
|
52
|
+
<span
|
|
53
|
+
className={cn(
|
|
54
|
+
'font-medium uppercase tracking-wide rounded',
|
|
55
|
+
isCompact ? 'text-[7px] px-0.5 py-0.5' : 'text-[8px] px-1 py-0.5',
|
|
56
|
+
data.tone === 'planned' && 'bg-blue-500/30 text-blue-300',
|
|
57
|
+
data.tone === 'in-progress' && 'bg-orange-500/30 text-orange-300',
|
|
58
|
+
data.tone === 'complete' && 'bg-green-500/30 text-green-300',
|
|
59
|
+
data.tone === 'archived' && 'bg-gray-500/30 text-gray-400'
|
|
60
|
+
)}
|
|
61
|
+
>
|
|
62
|
+
{data.badge}
|
|
63
|
+
</span>
|
|
64
|
+
</div>
|
|
65
|
+
<span
|
|
66
|
+
className={cn('font-medium leading-tight truncate', isCompact ? 'text-[8px]' : 'text-[10px]')}
|
|
67
|
+
title={data.label}
|
|
68
|
+
>
|
|
69
|
+
{isCompact ? data.shortLabel : data.label}
|
|
70
|
+
</span>
|
|
71
|
+
<Handle type="source" position={Position.Right} className="opacity-0" />
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
SpecNode.displayName = 'SpecNode';
|
|
77
|
+
|
|
78
|
+
export const nodeTypes = {
|
|
79
|
+
specNode: SpecNode,
|
|
80
|
+
};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cn } from '@/lib/utils';
|
|
5
|
+
import type { SpecNode, FocusedNodeDetails, SpecsByDepth } from './types';
|
|
6
|
+
|
|
7
|
+
interface SpecListItemProps {
|
|
8
|
+
spec: SpecNode;
|
|
9
|
+
type: 'upstream' | 'downstream';
|
|
10
|
+
onClick: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function SpecListItem({ spec, type, onClick }: SpecListItemProps) {
|
|
14
|
+
const typeColors = {
|
|
15
|
+
upstream: 'border-l-amber-500',
|
|
16
|
+
downstream: 'border-l-emerald-500',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<button
|
|
21
|
+
onClick={onClick}
|
|
22
|
+
className={cn(
|
|
23
|
+
'w-full text-left px-2 py-1.5 rounded border-l-2 bg-muted/30 hover:bg-muted/50 transition-colors',
|
|
24
|
+
typeColors[type]
|
|
25
|
+
)}
|
|
26
|
+
>
|
|
27
|
+
<div className="flex items-center gap-1.5">
|
|
28
|
+
<span className="text-[10px] font-bold text-muted-foreground">
|
|
29
|
+
#{spec.number.toString().padStart(3, '0')}
|
|
30
|
+
</span>
|
|
31
|
+
<span
|
|
32
|
+
className={cn(
|
|
33
|
+
'text-[8px] px-1 py-0.5 rounded font-medium uppercase',
|
|
34
|
+
spec.status === 'planned' && 'bg-amber-500/20 text-amber-400',
|
|
35
|
+
spec.status === 'in-progress' && 'bg-sky-500/20 text-sky-400',
|
|
36
|
+
spec.status === 'complete' && 'bg-emerald-500/20 text-emerald-400'
|
|
37
|
+
)}
|
|
38
|
+
>
|
|
39
|
+
{spec.status === 'in-progress' ? 'WIP' : spec.status.slice(0, 3)}
|
|
40
|
+
</span>
|
|
41
|
+
</div>
|
|
42
|
+
<p className="text-[11px] text-foreground truncate leading-tight mt-0.5">{spec.name}</p>
|
|
43
|
+
</button>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface DepthGroupProps {
|
|
48
|
+
group: SpecsByDepth;
|
|
49
|
+
type: 'upstream' | 'downstream';
|
|
50
|
+
onSelectSpec: (specId: string) => void;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function DepthGroup({ group, type, onSelectSpec }: DepthGroupProps) {
|
|
54
|
+
const [isExpanded, setIsExpanded] = React.useState(group.depth === 1);
|
|
55
|
+
const depthLabel = group.depth === 1 ? 'Direct' : `Level ${group.depth}`;
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div className="space-y-1">
|
|
59
|
+
<button
|
|
60
|
+
onClick={() => setIsExpanded(!isExpanded)}
|
|
61
|
+
className="flex items-center gap-1.5 w-full text-left text-[10px] text-muted-foreground hover:text-foreground transition-colors"
|
|
62
|
+
>
|
|
63
|
+
<span className={cn(
|
|
64
|
+
'transition-transform text-[8px]',
|
|
65
|
+
isExpanded ? 'rotate-90' : 'rotate-0'
|
|
66
|
+
)}>
|
|
67
|
+
▶
|
|
68
|
+
</span>
|
|
69
|
+
<span className="font-medium">{depthLabel}</span>
|
|
70
|
+
<span className="opacity-60">({group.specs.length})</span>
|
|
71
|
+
</button>
|
|
72
|
+
{isExpanded && (
|
|
73
|
+
<div className="space-y-1 ml-2">
|
|
74
|
+
{group.specs.map((spec) => (
|
|
75
|
+
<SpecListItem
|
|
76
|
+
key={spec.id}
|
|
77
|
+
spec={spec}
|
|
78
|
+
type={type}
|
|
79
|
+
onClick={() => onSelectSpec(spec.id)}
|
|
80
|
+
/>
|
|
81
|
+
))}
|
|
82
|
+
</div>
|
|
83
|
+
)}
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface SpecSidebarProps {
|
|
89
|
+
focusedDetails: FocusedNodeDetails | null;
|
|
90
|
+
onSelectSpec: (specId: string) => void;
|
|
91
|
+
onOpenSpec: (specNumber: number) => void;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function SpecSidebar({ focusedDetails, onSelectSpec, onOpenSpec }: SpecSidebarProps) {
|
|
95
|
+
if (!focusedDetails) {
|
|
96
|
+
return (
|
|
97
|
+
<div className="w-64 shrink-0 rounded-lg border border-border bg-background/95 overflow-hidden flex flex-col">
|
|
98
|
+
<div className="flex-1 flex items-center justify-center p-4">
|
|
99
|
+
<div className="text-center text-muted-foreground">
|
|
100
|
+
<div className="w-12 h-12 mx-auto mb-3 rounded-full bg-muted/50 flex items-center justify-center">
|
|
101
|
+
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
102
|
+
<path
|
|
103
|
+
strokeLinecap="round"
|
|
104
|
+
strokeLinejoin="round"
|
|
105
|
+
strokeWidth={1.5}
|
|
106
|
+
d="M15 15l-2 5L9 9l11 4-5 2zm0 0l5 5M7.188 2.239l.777 2.897M5.136 7.965l-2.898-.777M13.95 4.05l-2.122 2.122m-5.657 5.656l-2.12 2.122"
|
|
107
|
+
/>
|
|
108
|
+
</svg>
|
|
109
|
+
</div>
|
|
110
|
+
<p className="text-sm font-medium">Select a spec</p>
|
|
111
|
+
<p className="text-xs mt-1">Click on a spec to see its dependencies</p>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const { node, upstream, downstream } = focusedDetails;
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<div className="w-64 shrink-0 rounded-lg border border-border bg-background/95 overflow-hidden flex flex-col">
|
|
122
|
+
{/* Selected spec header */}
|
|
123
|
+
<div className="p-3 border-b border-border bg-muted/30">
|
|
124
|
+
<div className="flex items-center gap-2 mb-1">
|
|
125
|
+
<span className="font-bold text-sm">#{node.number.toString().padStart(3, '0')}</span>
|
|
126
|
+
<span
|
|
127
|
+
className={cn(
|
|
128
|
+
'px-1.5 py-0.5 rounded text-[10px] font-medium uppercase',
|
|
129
|
+
node.status === 'planned' && 'bg-amber-500/20 text-amber-300',
|
|
130
|
+
node.status === 'in-progress' && 'bg-sky-500/20 text-sky-300',
|
|
131
|
+
node.status === 'complete' && 'bg-emerald-500/20 text-emerald-300'
|
|
132
|
+
)}
|
|
133
|
+
>
|
|
134
|
+
{node.status}
|
|
135
|
+
</span>
|
|
136
|
+
</div>
|
|
137
|
+
<p className="text-sm font-medium text-foreground leading-snug">{node.name}</p>
|
|
138
|
+
<button
|
|
139
|
+
onClick={() => onOpenSpec(node.number)}
|
|
140
|
+
className="mt-2 w-full rounded bg-primary/20 border border-primary/40 px-2 py-1.5 text-xs text-primary hover:bg-primary/30 font-medium"
|
|
141
|
+
>
|
|
142
|
+
Open Spec →
|
|
143
|
+
</button>
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
{/* Scrollable spec lists */}
|
|
147
|
+
<div className="flex-1 overflow-auto p-3 space-y-4">
|
|
148
|
+
{/* Upstream Dependencies */}
|
|
149
|
+
<div>
|
|
150
|
+
<div className="flex items-center gap-2 mb-2">
|
|
151
|
+
<span className="inline-block w-2 h-2 rounded-full bg-amber-500" />
|
|
152
|
+
<span className="text-xs font-semibold text-muted-foreground uppercase tracking-wide">
|
|
153
|
+
Depends On ({upstream.reduce((sum, g) => sum + g.specs.length, 0)})
|
|
154
|
+
</span>
|
|
155
|
+
</div>
|
|
156
|
+
{upstream.length > 0 ? (
|
|
157
|
+
<div className="space-y-2">
|
|
158
|
+
{upstream.map((group) => (
|
|
159
|
+
<DepthGroup
|
|
160
|
+
key={group.depth}
|
|
161
|
+
group={group}
|
|
162
|
+
type="upstream"
|
|
163
|
+
onSelectSpec={onSelectSpec}
|
|
164
|
+
/>
|
|
165
|
+
))}
|
|
166
|
+
</div>
|
|
167
|
+
) : (
|
|
168
|
+
<p className="text-xs text-muted-foreground/60 italic">No upstream dependencies</p>
|
|
169
|
+
)}
|
|
170
|
+
</div>
|
|
171
|
+
|
|
172
|
+
{/* Downstream Dependents */}
|
|
173
|
+
<div>
|
|
174
|
+
<div className="flex items-center gap-2 mb-2">
|
|
175
|
+
<span className="inline-block w-2 h-2 rounded-full bg-emerald-500" />
|
|
176
|
+
<span className="text-xs font-semibold text-muted-foreground uppercase tracking-wide">
|
|
177
|
+
Required By ({downstream.reduce((sum, g) => sum + g.specs.length, 0)})
|
|
178
|
+
</span>
|
|
179
|
+
</div>
|
|
180
|
+
{downstream.length > 0 ? (
|
|
181
|
+
<div className="space-y-2">
|
|
182
|
+
{downstream.map((group) => (
|
|
183
|
+
<DepthGroup
|
|
184
|
+
key={group.depth}
|
|
185
|
+
group={group}
|
|
186
|
+
type="downstream"
|
|
187
|
+
onSelectSpec={onSelectSpec}
|
|
188
|
+
/>
|
|
189
|
+
))}
|
|
190
|
+
</div>
|
|
191
|
+
) : (
|
|
192
|
+
<p className="text-xs text-muted-foreground/60 italic">No specs depend on this</p>
|
|
193
|
+
)}
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ProjectDependencyGraph } from '@/app/api/dependencies/route';
|
|
2
|
+
|
|
3
|
+
export type GraphTone = 'planned' | 'in-progress' | 'complete' | 'archived';
|
|
4
|
+
|
|
5
|
+
export interface SpecNodeData {
|
|
6
|
+
label: string;
|
|
7
|
+
shortLabel: string;
|
|
8
|
+
badge: string;
|
|
9
|
+
number: number;
|
|
10
|
+
tone: GraphTone;
|
|
11
|
+
href?: string;
|
|
12
|
+
interactive?: boolean;
|
|
13
|
+
isFocused?: boolean;
|
|
14
|
+
connectionDepth?: number;
|
|
15
|
+
isDimmed?: boolean;
|
|
16
|
+
isCompact?: boolean;
|
|
17
|
+
isSecondary?: boolean; // Shown due to critical path, not primary filter
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type SpecNode = ProjectDependencyGraph['nodes'][0];
|
|
21
|
+
|
|
22
|
+
// Specs grouped by their depth level from the focused node
|
|
23
|
+
export interface SpecsByDepth {
|
|
24
|
+
depth: number;
|
|
25
|
+
specs: SpecNode[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface FocusedNodeDetails {
|
|
29
|
+
node: SpecNode;
|
|
30
|
+
upstream: SpecsByDepth[]; // All transitive deps grouped by depth
|
|
31
|
+
downstream: SpecsByDepth[]; // All transitive dependents grouped by depth
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ConnectionStats {
|
|
35
|
+
connected: number;
|
|
36
|
+
standalone: number;
|
|
37
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import dagre from '@dagrejs/dagre';
|
|
2
|
+
import type { Node, Edge } from 'reactflow';
|
|
3
|
+
import type { SpecNodeData } from './types';
|
|
4
|
+
import {
|
|
5
|
+
NODE_WIDTH,
|
|
6
|
+
NODE_HEIGHT,
|
|
7
|
+
COMPACT_NODE_WIDTH,
|
|
8
|
+
COMPACT_NODE_HEIGHT,
|
|
9
|
+
} from './constants';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get nodes at various depths from a starting node (directional BFS)
|
|
13
|
+
* Only includes upstream (specs this depends on) and downstream (specs that depend on this)
|
|
14
|
+
* Edge direction: source depends_on target (A→B means A depends on B)
|
|
15
|
+
*/
|
|
16
|
+
export function getConnectionDepths(
|
|
17
|
+
startId: string,
|
|
18
|
+
edges: Array<{ source: string; target: string }>,
|
|
19
|
+
maxDepth: number = 2
|
|
20
|
+
): Map<string, number> {
|
|
21
|
+
const depths = new Map<string, number>();
|
|
22
|
+
depths.set(startId, 0);
|
|
23
|
+
|
|
24
|
+
// Build directional adjacency maps
|
|
25
|
+
// upstreamMap: source → targets (specs that source depends on)
|
|
26
|
+
// downstreamMap: target → sources (specs that depend on target)
|
|
27
|
+
const upstreamMap = new Map<string, Set<string>>();
|
|
28
|
+
const downstreamMap = new Map<string, Set<string>>();
|
|
29
|
+
|
|
30
|
+
edges.forEach((e) => {
|
|
31
|
+
// source depends on target, so target is upstream of source
|
|
32
|
+
if (!upstreamMap.has(e.source)) upstreamMap.set(e.source, new Set());
|
|
33
|
+
upstreamMap.get(e.source)!.add(e.target);
|
|
34
|
+
|
|
35
|
+
// source depends on target, so source is downstream of target
|
|
36
|
+
if (!downstreamMap.has(e.target)) downstreamMap.set(e.target, new Set());
|
|
37
|
+
downstreamMap.get(e.target)!.add(e.source);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// BFS upstream (specs this depends on, directly or transitively)
|
|
41
|
+
let currentLevel = new Set([startId]);
|
|
42
|
+
let depth = 1;
|
|
43
|
+
while (currentLevel.size > 0 && depth <= maxDepth) {
|
|
44
|
+
const nextLevel = new Set<string>();
|
|
45
|
+
currentLevel.forEach((nodeId) => {
|
|
46
|
+
const upstreamNodes = upstreamMap.get(nodeId);
|
|
47
|
+
if (upstreamNodes) {
|
|
48
|
+
upstreamNodes.forEach((upstream) => {
|
|
49
|
+
if (!depths.has(upstream)) {
|
|
50
|
+
depths.set(upstream, depth);
|
|
51
|
+
nextLevel.add(upstream);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
currentLevel = nextLevel;
|
|
57
|
+
depth++;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// BFS downstream (specs that depend on this, directly or transitively)
|
|
61
|
+
currentLevel = new Set([startId]);
|
|
62
|
+
depth = 1;
|
|
63
|
+
while (currentLevel.size > 0 && depth <= maxDepth) {
|
|
64
|
+
const nextLevel = new Set<string>();
|
|
65
|
+
currentLevel.forEach((nodeId) => {
|
|
66
|
+
const downstreamNodes = downstreamMap.get(nodeId);
|
|
67
|
+
if (downstreamNodes) {
|
|
68
|
+
downstreamNodes.forEach((downstream) => {
|
|
69
|
+
if (!depths.has(downstream)) {
|
|
70
|
+
depths.set(downstream, depth);
|
|
71
|
+
nextLevel.add(downstream);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
currentLevel = nextLevel;
|
|
77
|
+
depth++;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return depths;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Layout the graph using dagre (hierarchical DAG layout)
|
|
85
|
+
*/
|
|
86
|
+
export function layoutGraph(
|
|
87
|
+
nodes: Node<SpecNodeData>[],
|
|
88
|
+
edges: Edge[],
|
|
89
|
+
isCompact: boolean,
|
|
90
|
+
showStandalone: boolean
|
|
91
|
+
): { nodes: Node<SpecNodeData>[]; edges: Edge[] } {
|
|
92
|
+
if (nodes.length === 0) return { nodes: [], edges: [] };
|
|
93
|
+
|
|
94
|
+
const width = isCompact ? COMPACT_NODE_WIDTH : NODE_WIDTH;
|
|
95
|
+
const height = isCompact ? COMPACT_NODE_HEIGHT : NODE_HEIGHT;
|
|
96
|
+
const gap = isCompact ? 30 : 50;
|
|
97
|
+
|
|
98
|
+
// Separate nodes with dependencies from standalone nodes
|
|
99
|
+
const nodesWithDeps = new Set<string>();
|
|
100
|
+
edges.forEach((e) => {
|
|
101
|
+
nodesWithDeps.add(e.source);
|
|
102
|
+
nodesWithDeps.add(e.target);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const connectedNodes = nodes.filter((n) => nodesWithDeps.has(n.id));
|
|
106
|
+
const standaloneNodes = showStandalone ? nodes.filter((n) => !nodesWithDeps.has(n.id)) : [];
|
|
107
|
+
|
|
108
|
+
const allLayoutedNodes: Node<SpecNodeData>[] = [];
|
|
109
|
+
|
|
110
|
+
// DAG view: Layout connected nodes with dagre (left-to-right for dependency flow)
|
|
111
|
+
if (connectedNodes.length > 0) {
|
|
112
|
+
const graph = new dagre.graphlib.Graph();
|
|
113
|
+
graph.setGraph({
|
|
114
|
+
rankdir: 'LR',
|
|
115
|
+
align: 'UL',
|
|
116
|
+
nodesep: isCompact ? 30 : 50,
|
|
117
|
+
ranksep: isCompact ? 80 : 120,
|
|
118
|
+
marginx: 40,
|
|
119
|
+
marginy: 40,
|
|
120
|
+
});
|
|
121
|
+
graph.setDefaultEdgeLabel(() => ({}));
|
|
122
|
+
|
|
123
|
+
connectedNodes.forEach((node) => {
|
|
124
|
+
graph.setNode(node.id, { width, height });
|
|
125
|
+
});
|
|
126
|
+
edges.forEach((edge) => {
|
|
127
|
+
if (nodesWithDeps.has(edge.source) && nodesWithDeps.has(edge.target)) {
|
|
128
|
+
graph.setEdge(edge.source, edge.target);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
dagre.layout(graph);
|
|
133
|
+
|
|
134
|
+
// Find bounds for centering
|
|
135
|
+
let minX = Infinity, minY = Infinity, maxX = 0, maxY = 0;
|
|
136
|
+
connectedNodes.forEach((node) => {
|
|
137
|
+
const pos = graph.node(node.id);
|
|
138
|
+
minX = Math.min(minX, pos.x - width / 2);
|
|
139
|
+
minY = Math.min(minY, pos.y - height / 2);
|
|
140
|
+
maxX = Math.max(maxX, pos.x + width / 2);
|
|
141
|
+
maxY = Math.max(maxY, pos.y + height / 2);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
connectedNodes.forEach((node) => {
|
|
145
|
+
const pos = graph.node(node.id);
|
|
146
|
+
allLayoutedNodes.push({
|
|
147
|
+
...node,
|
|
148
|
+
position: {
|
|
149
|
+
x: pos.x - minX,
|
|
150
|
+
y: pos.y - minY,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Layout standalone nodes in a grid below the graph
|
|
156
|
+
if (standaloneNodes.length > 0) {
|
|
157
|
+
const graphHeight = maxY - minY;
|
|
158
|
+
const graphWidth = maxX - minX;
|
|
159
|
+
const gridStartY = graphHeight + gap * 2;
|
|
160
|
+
const cols = Math.ceil(Math.sqrt(standaloneNodes.length * 1.5));
|
|
161
|
+
const gridWidth = cols * (width + gap);
|
|
162
|
+
const gridStartX = graphWidth > gridWidth ? Math.floor((graphWidth - gridWidth) / 2) : 0;
|
|
163
|
+
|
|
164
|
+
standaloneNodes.forEach((node, i) => {
|
|
165
|
+
const col = i % cols;
|
|
166
|
+
const row = Math.floor(i / cols);
|
|
167
|
+
allLayoutedNodes.push({
|
|
168
|
+
...node,
|
|
169
|
+
position: {
|
|
170
|
+
x: gridStartX + col * (width + gap),
|
|
171
|
+
y: gridStartY + row * (height + gap),
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
// Only standalone nodes - arrange in a grid
|
|
178
|
+
const cols = Math.ceil(Math.sqrt(standaloneNodes.length * 1.5));
|
|
179
|
+
|
|
180
|
+
standaloneNodes.forEach((node, i) => {
|
|
181
|
+
const col = i % cols;
|
|
182
|
+
const row = Math.floor(i / cols);
|
|
183
|
+
allLayoutedNodes.push({
|
|
184
|
+
...node,
|
|
185
|
+
position: {
|
|
186
|
+
x: col * (width + gap),
|
|
187
|
+
y: row * (height + gap),
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return { nodes: allLayoutedNodes, edges };
|
|
194
|
+
}
|
|
@@ -283,34 +283,34 @@ html.changing-theme * {
|
|
|
283
283
|
.prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6 {
|
|
284
284
|
font-weight: 600;
|
|
285
285
|
line-height: 1.25;
|
|
286
|
-
margin-top:
|
|
287
|
-
margin-bottom: 0.
|
|
286
|
+
margin-top: 1.5em;
|
|
287
|
+
margin-bottom: 0.5em;
|
|
288
288
|
color: hsl(222.2 84% 4.9%);
|
|
289
289
|
scroll-margin-top: 5rem;
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
.prose h1 {
|
|
293
|
-
font-size:
|
|
293
|
+
font-size: 2em;
|
|
294
294
|
margin-top: 0;
|
|
295
295
|
border-bottom: 1px solid hsl(214.3 31.8% 91.4%);
|
|
296
|
-
padding-bottom: 0.
|
|
296
|
+
padding-bottom: 0.25em;
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
.prose h2 {
|
|
300
|
-
font-size: 1.
|
|
300
|
+
font-size: 1.65em;
|
|
301
301
|
border-bottom: 1px solid hsl(214.3 31.8% 91.4%);
|
|
302
|
-
padding-bottom: 0.
|
|
302
|
+
padding-bottom: 0.25em;
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
-
.prose h3 { font-size: 1.
|
|
306
|
-
.prose h4 { font-size: 1.
|
|
307
|
-
.prose h5 { font-size: 1.
|
|
305
|
+
.prose h3 { font-size: 1.35em; }
|
|
306
|
+
.prose h4 { font-size: 1.15em; }
|
|
307
|
+
.prose h5 { font-size: 1.05em; }
|
|
308
308
|
.prose h6 { font-size: 1em; }
|
|
309
309
|
|
|
310
310
|
.prose p {
|
|
311
|
-
margin-top:
|
|
312
|
-
margin-bottom:
|
|
313
|
-
line-height: 1.
|
|
311
|
+
margin-top: 1em;
|
|
312
|
+
margin-bottom: 1em;
|
|
313
|
+
line-height: 1.7;
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
.prose a {
|
|
@@ -337,7 +337,7 @@ html.changing-theme * {
|
|
|
337
337
|
}
|
|
338
338
|
|
|
339
339
|
.prose pre {
|
|
340
|
-
margin: 1.
|
|
340
|
+
margin: 1.25em 0;
|
|
341
341
|
overflow-x: auto;
|
|
342
342
|
border-radius: 0.5rem;
|
|
343
343
|
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
@@ -369,9 +369,9 @@ html.changing-theme * {
|
|
|
369
369
|
.prose blockquote {
|
|
370
370
|
border-left: 4px solid hsl(221 83% 53%);
|
|
371
371
|
padding-left: 1em;
|
|
372
|
-
padding-top: 0.
|
|
373
|
-
padding-bottom: 0.
|
|
374
|
-
margin:
|
|
372
|
+
padding-top: 0.25em;
|
|
373
|
+
padding-bottom: 0.25em;
|
|
374
|
+
margin: 1em 0;
|
|
375
375
|
background: hsl(210 40% 98%);
|
|
376
376
|
border-radius: 0 0.25rem 0.25rem 0;
|
|
377
377
|
color: hsl(215.4 16.3% 36.9%);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Metadata
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
2
|
import "./globals.css";
|
|
3
3
|
import { Navigation } from "@/components/navigation";
|
|
4
4
|
import { MainSidebar } from "@/components/main-sidebar";
|
|
@@ -6,6 +6,7 @@ import { ThemeProvider } from "@/components/theme-provider";
|
|
|
6
6
|
import { Toast } from "@/components/ui/toast";
|
|
7
7
|
import { ProjectProvider } from "@/contexts/project-context";
|
|
8
8
|
import { getSpecs } from "@/lib/db/service-queries";
|
|
9
|
+
import { Analytics } from "@vercel/analytics/react";
|
|
9
10
|
|
|
10
11
|
export const metadata: Metadata = {
|
|
11
12
|
title: "LeanSpec Web - Interactive Spec Showcase",
|
|
@@ -24,12 +25,6 @@ export const metadata: Metadata = {
|
|
|
24
25
|
},
|
|
25
26
|
};
|
|
26
27
|
|
|
27
|
-
export const viewport: Viewport = {
|
|
28
|
-
width: 'device-width',
|
|
29
|
-
initialScale: 1,
|
|
30
|
-
maximumScale: 5,
|
|
31
|
-
};
|
|
32
|
-
|
|
33
28
|
export default async function RootLayout({
|
|
34
29
|
children,
|
|
35
30
|
}: Readonly<{
|
|
@@ -68,6 +63,8 @@ export default async function RootLayout({
|
|
|
68
63
|
<Toast />
|
|
69
64
|
</ProjectProvider>
|
|
70
65
|
</ThemeProvider>
|
|
66
|
+
{/* Analytics enabled via ENABLE_ANALYTICS env var in Vercel */}
|
|
67
|
+
{process.env.ENABLE_ANALYTICS === 'true' && <Analytics />}
|
|
71
68
|
</body>
|
|
72
69
|
</html>
|
|
73
70
|
);
|