@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.
Files changed (262) hide show
  1. package/.next/standalone/packages/ui/.next/BUILD_ID +1 -1
  2. package/.next/standalone/packages/ui/.next/app-path-routes-manifest.json +4 -0
  3. package/.next/standalone/packages/ui/.next/build-manifest.json +4 -4
  4. package/.next/standalone/packages/ui/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/packages/ui/.next/routes-manifest.json +24 -0
  6. package/.next/standalone/packages/ui/.next/server/app/_global-error/page/build-manifest.json +2 -2
  7. package/.next/standalone/packages/ui/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/packages/ui/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/packages/ui/.next/server/app/_global-error.html +2 -2
  10. package/.next/standalone/packages/ui/.next/server/app/_global-error.rsc +1 -1
  11. package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  12. package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  13. package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  14. package/.next/standalone/packages/ui/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  15. package/.next/standalone/packages/ui/.next/server/app/_not-found/page/build-manifest.json +2 -2
  16. package/.next/standalone/packages/ui/.next/server/app/_not-found/page.js +1 -1
  17. package/.next/standalone/packages/ui/.next/server/app/_not-found/page.js.nft.json +1 -1
  18. package/.next/standalone/packages/ui/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  19. package/.next/standalone/packages/ui/.next/server/app/_not-found.html +2 -2
  20. package/.next/standalone/packages/ui/.next/server/app/_not-found.rsc +19 -19
  21. package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_full.segment.rsc +19 -19
  22. package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_index.segment.rsc +11 -11
  23. package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +3 -3
  24. package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  25. package/.next/standalone/packages/ui/.next/server/app/_not-found.segments/_tree.segment.rsc +6 -6
  26. package/.next/standalone/packages/ui/.next/server/app/api/context/route/app-paths-manifest.json +3 -0
  27. package/.next/standalone/packages/ui/.next/server/app/api/context/route/build-manifest.json +11 -0
  28. package/.next/standalone/packages/ui/.next/server/app/api/context/route/server-reference-manifest.json +4 -0
  29. package/.next/standalone/packages/ui/.next/server/app/api/context/route.js +8 -0
  30. package/.next/standalone/packages/ui/.next/server/app/api/context/route.js.map +5 -0
  31. package/.next/standalone/packages/ui/.next/server/app/api/context/route.js.nft.json +1 -0
  32. package/.next/standalone/packages/ui/.next/server/app/api/context/route_client-reference-manifest.js +2 -0
  33. package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route/app-paths-manifest.json +3 -0
  34. package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route/build-manifest.json +11 -0
  35. package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route/server-reference-manifest.json +4 -0
  36. package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route.js +8 -0
  37. package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route.js.map +5 -0
  38. package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route.js.nft.json +1 -0
  39. package/.next/standalone/packages/ui/.next/server/app/api/dependencies/route_client-reference-manifest.js +2 -0
  40. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/[id]/route.js.nft.json +1 -1
  41. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/discover/route.js.nft.json +1 -1
  42. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/list-directory/route.js.nft.json +1 -1
  43. package/.next/standalone/packages/ui/.next/server/app/api/local-projects/route.js.nft.json +1 -1
  44. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/route.js.nft.json +1 -1
  45. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/route.js.nft.json +1 -1
  46. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/[spec]/status/route.js.nft.json +1 -1
  47. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/specs/route.js.nft.json +1 -1
  48. package/.next/standalone/packages/ui/.next/server/app/api/projects/[id]/stats/route.js.nft.json +1 -1
  49. package/.next/standalone/packages/ui/.next/server/app/api/projects/route.js.nft.json +1 -1
  50. package/.next/standalone/packages/ui/.next/server/app/api/revalidate/route.js.nft.json +1 -1
  51. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/dependency-graph/route.js.nft.json +1 -1
  52. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/route.js.nft.json +1 -1
  53. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/status/route.js.nft.json +1 -1
  54. package/.next/standalone/packages/ui/.next/server/app/api/specs/[id]/subspecs/[file]/route.js.nft.json +1 -1
  55. package/.next/standalone/packages/ui/.next/server/app/api/stats/route.js.nft.json +1 -1
  56. package/.next/standalone/packages/ui/.next/server/app/context/page/app-paths-manifest.json +3 -0
  57. package/.next/standalone/packages/ui/.next/server/app/context/page/build-manifest.json +18 -0
  58. package/.next/standalone/packages/ui/.next/server/app/context/page/next-font-manifest.json +6 -0
  59. package/.next/standalone/packages/ui/.next/server/app/context/page/react-loadable-manifest.json +1 -0
  60. package/.next/standalone/packages/ui/.next/server/app/context/page/server-reference-manifest.json +4 -0
  61. package/.next/standalone/packages/ui/.next/server/app/context/page.js +19 -0
  62. package/.next/standalone/packages/ui/.next/server/app/context/page.js.map +5 -0
  63. package/.next/standalone/packages/ui/.next/server/app/context/page.js.nft.json +1 -0
  64. package/.next/standalone/packages/ui/.next/server/app/context/page_client-reference-manifest.js +2 -0
  65. package/.next/standalone/packages/ui/.next/server/app/dependencies/page/app-paths-manifest.json +3 -0
  66. package/.next/standalone/packages/ui/.next/server/app/dependencies/page/build-manifest.json +18 -0
  67. package/.next/standalone/packages/ui/.next/server/app/dependencies/page/next-font-manifest.json +6 -0
  68. package/.next/standalone/packages/ui/.next/server/app/dependencies/page/react-loadable-manifest.json +1 -0
  69. package/.next/standalone/packages/ui/.next/server/app/dependencies/page/server-reference-manifest.json +4 -0
  70. package/.next/standalone/packages/ui/.next/server/app/dependencies/page.js +19 -0
  71. package/.next/standalone/packages/ui/.next/server/app/dependencies/page.js.map +5 -0
  72. package/.next/standalone/packages/ui/.next/server/app/dependencies/page.js.nft.json +1 -0
  73. package/.next/standalone/packages/ui/.next/server/app/dependencies/page_client-reference-manifest.js +2 -0
  74. package/.next/standalone/packages/ui/.next/server/app/page/build-manifest.json +2 -2
  75. package/.next/standalone/packages/ui/.next/server/app/page.js +1 -1
  76. package/.next/standalone/packages/ui/.next/server/app/page.js.nft.json +1 -1
  77. package/.next/standalone/packages/ui/.next/server/app/page_client-reference-manifest.js +1 -1
  78. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page/build-manifest.json +2 -2
  79. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page.js +1 -1
  80. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page.js.nft.json +1 -1
  81. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/page_client-reference-manifest.js +1 -1
  82. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page/build-manifest.json +2 -2
  83. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page.js +1 -1
  84. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page.js.nft.json +1 -1
  85. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/[specId]/page_client-reference-manifest.js +1 -1
  86. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page/build-manifest.json +2 -2
  87. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page.js +1 -1
  88. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page.js.nft.json +1 -1
  89. package/.next/standalone/packages/ui/.next/server/app/projects/[projectId]/specs/page_client-reference-manifest.js +1 -1
  90. package/.next/standalone/packages/ui/.next/server/app/projects/page/build-manifest.json +2 -2
  91. package/.next/standalone/packages/ui/.next/server/app/projects/page.js +1 -1
  92. package/.next/standalone/packages/ui/.next/server/app/projects/page.js.nft.json +1 -1
  93. package/.next/standalone/packages/ui/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  94. package/.next/standalone/packages/ui/.next/server/app/projects.html +2 -2
  95. package/.next/standalone/packages/ui/.next/server/app/projects.rsc +24 -23
  96. package/.next/standalone/packages/ui/.next/server/app/projects.segments/_full.segment.rsc +24 -23
  97. package/.next/standalone/packages/ui/.next/server/app/projects.segments/_index.segment.rsc +9 -9
  98. package/.next/standalone/packages/ui/.next/server/app/projects.segments/_tree.segment.rsc +3 -3
  99. package/.next/standalone/packages/ui/.next/server/app/projects.segments/projects/__PAGE__.segment.rsc +2 -2
  100. package/.next/standalone/packages/ui/.next/server/app/projects.segments/projects.segment.rsc +1 -1
  101. package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page/build-manifest.json +2 -2
  102. package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page.js +1 -1
  103. package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page.js.nft.json +1 -1
  104. package/.next/standalone/packages/ui/.next/server/app/specs/[id]/page_client-reference-manifest.js +1 -1
  105. package/.next/standalone/packages/ui/.next/server/app/specs/page/build-manifest.json +2 -2
  106. package/.next/standalone/packages/ui/.next/server/app/specs/page.js +1 -1
  107. package/.next/standalone/packages/ui/.next/server/app/specs/page.js.nft.json +1 -1
  108. package/.next/standalone/packages/ui/.next/server/app/specs/page_client-reference-manifest.js +1 -1
  109. package/.next/standalone/packages/ui/.next/server/app/stats/page/build-manifest.json +2 -2
  110. package/.next/standalone/packages/ui/.next/server/app/stats/page.js +1 -1
  111. package/.next/standalone/packages/ui/.next/server/app/stats/page.js.nft.json +1 -1
  112. package/.next/standalone/packages/ui/.next/server/app/stats/page_client-reference-manifest.js +1 -1
  113. package/.next/standalone/packages/ui/.next/server/app-paths-manifest.json +4 -0
  114. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__3559376c._.js +2 -2
  115. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__65667b70._.js +1 -1
  116. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__803d07f0._.js +1 -1
  117. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__84cdc14a._.js +1 -1
  118. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__8a9ab1a3._.js +3 -0
  119. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__b0969111._.js +3 -0
  120. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__bdc3963a._.js +1 -1
  121. package/.next/standalone/packages/ui/.next/server/chunks/[root-of-the-server]__f5c6d6b8._.js +1 -1
  122. package/.next/standalone/packages/ui/.next/server/chunks/packages_ui__next-internal_server_app_api_context_route_actions_dead6daa.js +3 -0
  123. package/.next/standalone/packages/ui/.next/server/chunks/packages_ui__next-internal_server_app_api_dependencies_route_actions_cf6b14c3.js +3 -0
  124. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__12b4eb41._.js +3 -0
  125. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__3c77d95b._.js +3 -0
  126. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__44b603f9._.js +3 -0
  127. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__69a0d63a._.js +3 -0
  128. package/.next/standalone/packages/ui/.next/server/chunks/ssr/{[root-of-the-server]__daee3355._.js → [root-of-the-server]__8608a6fa._.js} +2 -2
  129. package/.next/standalone/packages/ui/.next/server/chunks/ssr/{[root-of-the-server]__fd80e4dd._.js → [root-of-the-server]__a965a67b._.js} +2 -2
  130. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__daedd80e._.js +3 -0
  131. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__dc176c61._.js +3 -0
  132. package/.next/standalone/packages/ui/.next/server/chunks/ssr/{[root-of-the-server]__5382b397._.js → [root-of-the-server]__ead1539c._.js} +2 -2
  133. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_000dd317._.js +1 -1
  134. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_03aa8d19._.js +7 -0
  135. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_28fe1532._.js +5 -0
  136. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_8cec504f._.js +3 -0
  137. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_959ad3d8._.js +4 -0
  138. package/.next/standalone/packages/ui/.next/server/chunks/ssr/{_22274047._.js → _adb9d7cb._.js} +2 -2
  139. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_da18b655._.js +3 -0
  140. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_ea899b87._.js +3 -0
  141. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_f38e75b7._.js +4 -0
  142. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_fe120f8a._.js +3 -0
  143. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_015f83ca._.js +3 -0
  144. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_1120b57c._.js +3 -0
  145. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_151891de._.js +3 -0
  146. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_1c916fe3._.js +3 -0
  147. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_80605a06._.js +3 -0
  148. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_bb80de48._.js +3 -0
  149. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_e8075f9b._.js +3 -0
  150. package/.next/standalone/packages/ui/.next/server/chunks/ssr/node_modules__pnpm_f919ef4a._.js +3 -0
  151. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui__next-internal_server_app_context_page_actions_1a062d48.js +3 -0
  152. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui__next-internal_server_app_dependencies_page_actions_57387d47.js +3 -0
  153. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_context_context-client_tsx_4ba99a62._.js +12 -0
  154. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_dependencies_dependencies-client_tsx_0e82443a._.js +4 -0
  155. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_app_specs_specs-client_tsx_0bb8f8f8._.js +1 -1
  156. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_components_spec-detail-wrapper_tsx_fd35401c._.js +3 -0
  157. package/.next/standalone/packages/ui/.next/server/chunks/ssr/packages_ui_src_components_specs-nav-sidebar_tsx_8237ed13._.js +1 -1
  158. package/.next/standalone/packages/ui/.next/server/middleware-build-manifest.js +2 -2
  159. package/.next/standalone/packages/ui/.next/server/pages/404.html +2 -2
  160. package/.next/standalone/packages/ui/.next/server/pages/500.html +2 -2
  161. package/.next/standalone/packages/ui/.next/server/server-reference-manifest.js +1 -1
  162. package/.next/standalone/packages/ui/.next/server/server-reference-manifest.json +1 -1
  163. package/.next/standalone/packages/ui/.next/static/chunks/094cf9f4e3553261.js +1 -0
  164. package/.next/standalone/packages/ui/.next/static/chunks/1c015eb9eaaf9f9c.js +1 -0
  165. package/.next/standalone/packages/ui/.next/static/chunks/1d36660b2877d213.js +3 -0
  166. package/.next/standalone/packages/ui/.next/static/chunks/46275d9d67603bf5.js +1 -0
  167. package/.next/standalone/packages/ui/.next/static/chunks/4d29ca0fa6843070.js +2 -0
  168. package/.next/standalone/packages/ui/.next/static/chunks/59854b15bf046467.js +1 -0
  169. package/.next/standalone/packages/ui/.next/static/chunks/{cca4441cde342ae3.js → 5fd8101e32b076b1.js} +1 -1
  170. package/.next/standalone/packages/ui/.next/static/chunks/6d938a49daa10208.js +2 -0
  171. package/.next/standalone/packages/ui/.next/static/chunks/979625373d5474b6.js +1 -0
  172. package/.next/standalone/packages/ui/.next/static/chunks/a33f10af6abef4df.js +10 -0
  173. package/.next/{static/chunks/794f3931f1ca12d2.js → standalone/packages/ui/.next/static/chunks/a3d7e1be47de010b.js} +1 -1
  174. package/.next/standalone/packages/ui/.next/static/chunks/a5e25b9fa6b88eee.js +1 -0
  175. package/.next/standalone/packages/ui/.next/static/chunks/b53250480fde6816.js +1 -0
  176. package/.next/standalone/packages/ui/.next/static/chunks/b7f19087afe1d2c9.css +1 -0
  177. package/.next/standalone/packages/ui/.next/static/chunks/c658e22a605e0ed1.js +1 -0
  178. package/.next/standalone/packages/ui/.next/static/chunks/c92660d8d0c4763d.js +1 -0
  179. package/.next/standalone/packages/ui/.next/static/chunks/ddd87cd0d26bc2f5.js +1 -0
  180. package/.next/standalone/packages/ui/.next/static/chunks/eeec245955b3b600.js +5 -0
  181. package/.next/standalone/packages/ui/.next/static/chunks/ff11efb770d5a0bc.js +1 -0
  182. package/.next/{static/chunks/turbopack-5fa55215af0efb15.js → standalone/packages/ui/.next/static/chunks/turbopack-261c5dcdd873f310.js} +1 -1
  183. package/.next/standalone/packages/ui/package.json +5 -1
  184. package/.next/standalone/packages/ui/src/app/api/context/route.ts +22 -0
  185. package/.next/standalone/packages/ui/src/app/api/dependencies/route.ts +81 -0
  186. package/.next/standalone/packages/ui/src/app/context/context-client.tsx +393 -0
  187. package/.next/standalone/packages/ui/src/app/context/page.tsx +17 -0
  188. package/.next/standalone/packages/ui/src/app/dependencies/constants.ts +24 -0
  189. package/.next/standalone/packages/ui/src/app/dependencies/dependencies-client.tsx +625 -0
  190. package/.next/standalone/packages/ui/src/app/dependencies/index.ts +19 -0
  191. package/.next/standalone/packages/ui/src/app/dependencies/page.tsx +38 -0
  192. package/.next/standalone/packages/ui/src/app/dependencies/spec-node.tsx +80 -0
  193. package/.next/standalone/packages/ui/src/app/dependencies/spec-sidebar.tsx +198 -0
  194. package/.next/standalone/packages/ui/src/app/dependencies/types.ts +37 -0
  195. package/.next/standalone/packages/ui/src/app/dependencies/utils.ts +194 -0
  196. package/.next/standalone/packages/ui/src/app/globals.css +16 -16
  197. package/.next/standalone/packages/ui/src/app/layout.tsx +4 -7
  198. package/.next/standalone/packages/ui/src/components/context-file-detail.tsx +308 -0
  199. package/.next/standalone/packages/ui/src/components/context-file-viewer.tsx +385 -0
  200. package/.next/standalone/packages/ui/src/components/main-sidebar.tsx +19 -1
  201. package/.next/standalone/packages/ui/src/components/spec-detail-client.tsx +181 -134
  202. package/.next/standalone/packages/ui/src/components/spec-detail-wrapper.tsx +20 -0
  203. package/.next/standalone/packages/ui/src/components/specs-nav-sidebar.tsx +3 -2
  204. package/.next/standalone/packages/ui/src/components/ui/accordion.tsx +58 -0
  205. package/.next/standalone/packages/ui/src/lib/db/service-queries.ts +172 -3
  206. package/.next/standalone/packages/ui/src/lib/specs/types.ts +44 -0
  207. package/.next/standalone/packages/ui/tsconfig.tsbuildinfo +1 -1
  208. package/.next/static/chunks/094cf9f4e3553261.js +1 -0
  209. package/.next/static/chunks/1c015eb9eaaf9f9c.js +1 -0
  210. package/.next/static/chunks/1d36660b2877d213.js +3 -0
  211. package/.next/static/chunks/46275d9d67603bf5.js +1 -0
  212. package/.next/static/chunks/4d29ca0fa6843070.js +2 -0
  213. package/.next/static/chunks/59854b15bf046467.js +1 -0
  214. package/.next/static/chunks/{cca4441cde342ae3.js → 5fd8101e32b076b1.js} +1 -1
  215. package/.next/static/chunks/6d938a49daa10208.js +2 -0
  216. package/.next/static/chunks/979625373d5474b6.js +1 -0
  217. package/.next/static/chunks/a33f10af6abef4df.js +10 -0
  218. package/.next/{standalone/packages/ui/.next/static/chunks/794f3931f1ca12d2.js → static/chunks/a3d7e1be47de010b.js} +1 -1
  219. package/.next/static/chunks/a5e25b9fa6b88eee.js +1 -0
  220. package/.next/static/chunks/b53250480fde6816.js +1 -0
  221. package/.next/static/chunks/b7f19087afe1d2c9.css +1 -0
  222. package/.next/static/chunks/c658e22a605e0ed1.js +1 -0
  223. package/.next/static/chunks/c92660d8d0c4763d.js +1 -0
  224. package/.next/static/chunks/ddd87cd0d26bc2f5.js +1 -0
  225. package/.next/static/chunks/eeec245955b3b600.js +5 -0
  226. package/.next/static/chunks/ff11efb770d5a0bc.js +1 -0
  227. package/.next/{standalone/packages/ui/.next/static/chunks/turbopack-5fa55215af0efb15.js → static/chunks/turbopack-261c5dcdd873f310.js} +1 -1
  228. package/package.json +6 -2
  229. package/.next/standalone/node_modules/.pnpm/source-map@0.8.0-beta.0/node_modules/source-map/package.json +0 -95
  230. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__1d0c2012._.js +0 -3
  231. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__73f60f12._.js +0 -7
  232. package/.next/standalone/packages/ui/.next/server/chunks/ssr/[root-of-the-server]__a7ae8552._.js +0 -7
  233. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_0f9ffe32._.js +0 -3
  234. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_14118969._.js +0 -3
  235. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_4129cc0f._.js +0 -3
  236. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_497c8b73._.js +0 -3
  237. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_ac867463._.js +0 -3
  238. package/.next/standalone/packages/ui/.next/server/chunks/ssr/_c2f54661._.js +0 -5
  239. package/.next/standalone/packages/ui/.next/static/chunks/16ff9833ae1bb3ae.js +0 -1
  240. package/.next/standalone/packages/ui/.next/static/chunks/2204c0f16b23ec4c.js +0 -3
  241. package/.next/standalone/packages/ui/.next/static/chunks/294dea6dbec43ca6.js +0 -1
  242. package/.next/standalone/packages/ui/.next/static/chunks/7590e65bcaa41e8b.js +0 -1
  243. package/.next/standalone/packages/ui/.next/static/chunks/b6976cf6c48996e5.js +0 -1
  244. package/.next/standalone/packages/ui/.next/static/chunks/b8353eb8c6fb895e.js +0 -1
  245. package/.next/standalone/packages/ui/.next/static/chunks/b845813463167db0.js +0 -5
  246. package/.next/standalone/packages/ui/.next/static/chunks/bd9893e28f8f6a9a.css +0 -1
  247. package/.next/standalone/packages/ui/.next/static/chunks/d784d84d5b880e48.js +0 -1
  248. package/.next/static/chunks/16ff9833ae1bb3ae.js +0 -1
  249. package/.next/static/chunks/2204c0f16b23ec4c.js +0 -3
  250. package/.next/static/chunks/294dea6dbec43ca6.js +0 -1
  251. package/.next/static/chunks/7590e65bcaa41e8b.js +0 -1
  252. package/.next/static/chunks/b6976cf6c48996e5.js +0 -1
  253. package/.next/static/chunks/b8353eb8c6fb895e.js +0 -1
  254. package/.next/static/chunks/b845813463167db0.js +0 -5
  255. package/.next/static/chunks/bd9893e28f8f6a9a.css +0 -1
  256. package/.next/static/chunks/d784d84d5b880e48.js +0 -1
  257. /package/.next/standalone/packages/ui/.next/static/{6nq7WNafPv5Bf_7mWgRQ- → 8PwFWS-09QjFSbDbfp15t}/_buildManifest.js +0 -0
  258. /package/.next/standalone/packages/ui/.next/static/{6nq7WNafPv5Bf_7mWgRQ- → 8PwFWS-09QjFSbDbfp15t}/_clientMiddlewareManifest.json +0 -0
  259. /package/.next/standalone/packages/ui/.next/static/{6nq7WNafPv5Bf_7mWgRQ- → 8PwFWS-09QjFSbDbfp15t}/_ssgManifest.js +0 -0
  260. /package/.next/static/{6nq7WNafPv5Bf_7mWgRQ- → 8PwFWS-09QjFSbDbfp15t}/_buildManifest.js +0 -0
  261. /package/.next/static/{6nq7WNafPv5Bf_7mWgRQ- → 8PwFWS-09QjFSbDbfp15t}/_clientMiddlewareManifest.json +0 -0
  262. /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: 2em;
287
- margin-bottom: 0.75em;
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: 2.25em;
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.3em;
296
+ padding-bottom: 0.25em;
297
297
  }
298
298
 
299
299
  .prose h2 {
300
- font-size: 1.875em;
300
+ font-size: 1.65em;
301
301
  border-bottom: 1px solid hsl(214.3 31.8% 91.4%);
302
- padding-bottom: 0.3em;
302
+ padding-bottom: 0.25em;
303
303
  }
304
304
 
305
- .prose h3 { font-size: 1.5em; }
306
- .prose h4 { font-size: 1.25em; }
307
- .prose h5 { font-size: 1.125em; }
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: 1.25em;
312
- margin-bottom: 1.25em;
313
- line-height: 1.75;
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.75em 0;
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.5em;
373
- padding-bottom: 0.5em;
374
- margin: 1.5em 0;
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, Viewport } from "next";
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
  );