@autoview/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +407 -0
- package/lib/AutoViewAgent.d.ts +109 -0
- package/lib/AutoViewAgent.js +123 -0
- package/lib/AutoViewAgent.js.map +1 -0
- package/lib/agent/emitMcpServer.d.ts +15 -0
- package/lib/agent/emitMcpServer.js +157 -0
- package/lib/agent/emitMcpServer.js.map +1 -0
- package/lib/agent/emitReport.d.ts +14 -0
- package/lib/agent/emitReport.js +85 -0
- package/lib/agent/emitReport.js.map +1 -0
- package/lib/agent/toolSurface.d.ts +130 -0
- package/lib/agent/toolSurface.js +342 -0
- package/lib/agent/toolSurface.js.map +1 -0
- package/lib/agent/verifyAgentTasks.d.ts +87 -0
- package/lib/agent/verifyAgentTasks.js +126 -0
- package/lib/agent/verifyAgentTasks.js.map +1 -0
- package/lib/cli/main.d.ts +2 -0
- package/lib/cli/main.js +295 -0
- package/lib/cli/main.js.map +1 -0
- package/lib/compiler/AutoViewInterfaceCompiler.d.ts +27 -0
- package/lib/compiler/AutoViewInterfaceCompiler.js +68 -0
- package/lib/compiler/AutoViewInterfaceCompiler.js.map +1 -0
- package/lib/constants/AutoViewFrontendTemplate.d.ts +1 -0
- package/lib/constants/AutoViewFrontendTemplate.js +46 -0
- package/lib/constants/AutoViewFrontendTemplate.js.map +1 -0
- package/lib/constants/AutoViewSystemPromptConstant.d.ts +5 -0
- package/lib/constants/AutoViewSystemPromptConstant.js +4 -0
- package/lib/constants/AutoViewSystemPromptConstant.js.map +1 -0
- package/lib/context/IAutoViewAgentContext.d.ts +60 -0
- package/lib/context/IAutoViewAgentContext.js +3 -0
- package/lib/context/IAutoViewAgentContext.js.map +1 -0
- package/lib/fromSwagger.d.ts +53 -0
- package/lib/fromSwagger.js +513 -0
- package/lib/fromSwagger.js.map +1 -0
- package/lib/generateDeterministic.d.ts +26 -0
- package/lib/generateDeterministic.js +75 -0
- package/lib/generateDeterministic.js.map +1 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.js +41 -0
- package/lib/index.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoView.d.ts +17 -0
- package/lib/orchestrate/orchestrateAutoView.js +491 -0
- package/lib/orchestrate/orchestrateAutoView.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewProductPlan.d.ts +37 -0
- package/lib/orchestrate/orchestrateAutoViewProductPlan.js +109 -0
- package/lib/orchestrate/orchestrateAutoViewProductPlan.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewRender.d.ts +133 -0
- package/lib/orchestrate/orchestrateAutoViewRender.js +943 -0
- package/lib/orchestrate/orchestrateAutoViewRender.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewRenderDeterministic.d.ts +24 -0
- package/lib/orchestrate/orchestrateAutoViewRenderDeterministic.js +92 -0
- package/lib/orchestrate/orchestrateAutoViewRenderDeterministic.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewReview.d.ts +48 -0
- package/lib/orchestrate/orchestrateAutoViewReview.js +328 -0
- package/lib/orchestrate/orchestrateAutoViewReview.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewScaffold.d.ts +45 -0
- package/lib/orchestrate/orchestrateAutoViewScaffold.js +586 -0
- package/lib/orchestrate/orchestrateAutoViewScaffold.js.map +1 -0
- package/lib/orchestrate/orchestrateAutoViewSdkStudy.d.ts +26 -0
- package/lib/orchestrate/orchestrateAutoViewSdkStudy.js +85 -0
- package/lib/orchestrate/orchestrateAutoViewSdkStudy.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewProductPlan.d.ts +96 -0
- package/lib/orchestrate/structures/IAutoViewProductPlan.js +3 -0
- package/lib/orchestrate/structures/IAutoViewProductPlan.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewProductPlanApplication.d.ts +38 -0
- package/lib/orchestrate/structures/IAutoViewProductPlanApplication.js +3 -0
- package/lib/orchestrate/structures/IAutoViewProductPlanApplication.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewRenderApplication.d.ts +38 -0
- package/lib/orchestrate/structures/IAutoViewRenderApplication.js +3 -0
- package/lib/orchestrate/structures/IAutoViewRenderApplication.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewReviewApplication.d.ts +40 -0
- package/lib/orchestrate/structures/IAutoViewReviewApplication.js +3 -0
- package/lib/orchestrate/structures/IAutoViewReviewApplication.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewSdkMap.d.ts +63 -0
- package/lib/orchestrate/structures/IAutoViewSdkMap.js +3 -0
- package/lib/orchestrate/structures/IAutoViewSdkMap.js.map +1 -0
- package/lib/orchestrate/structures/IAutoViewSdkStudyApplication.d.ts +37 -0
- package/lib/orchestrate/structures/IAutoViewSdkStudyApplication.js +3 -0
- package/lib/orchestrate/structures/IAutoViewSdkStudyApplication.js.map +1 -0
- package/lib/orchestrate/utils/HistoryMessage.d.ts +10 -0
- package/lib/orchestrate/utils/HistoryMessage.js +25 -0
- package/lib/orchestrate/utils/HistoryMessage.js.map +1 -0
- package/lib/orchestrate/utils/auditFrontendRuntime.d.ts +53 -0
- package/lib/orchestrate/utils/auditFrontendRuntime.js +362 -0
- package/lib/orchestrate/utils/auditFrontendRuntime.js.map +1 -0
- package/lib/orchestrate/utils/buildDeterministicPlan.d.ts +4 -0
- package/lib/orchestrate/utils/buildDeterministicPlan.js +233 -0
- package/lib/orchestrate/utils/buildDeterministicPlan.js.map +1 -0
- package/lib/orchestrate/utils/buildDeterministicSdkMap.d.ts +22 -0
- package/lib/orchestrate/utils/buildDeterministicSdkMap.js +154 -0
- package/lib/orchestrate/utils/buildDeterministicSdkMap.js.map +1 -0
- package/lib/orchestrate/utils/cacheNodeModules.d.ts +31 -0
- package/lib/orchestrate/utils/cacheNodeModules.js +134 -0
- package/lib/orchestrate/utils/cacheNodeModules.js.map +1 -0
- package/lib/orchestrate/utils/describeEndpointPropsShape.d.ts +37 -0
- package/lib/orchestrate/utils/describeEndpointPropsShape.js +192 -0
- package/lib/orchestrate/utils/describeEndpointPropsShape.js.map +1 -0
- package/lib/orchestrate/utils/describeEndpointRequestBodyShape.d.ts +22 -0
- package/lib/orchestrate/utils/describeEndpointRequestBodyShape.js +29 -0
- package/lib/orchestrate/utils/describeEndpointRequestBodyShape.js.map +1 -0
- package/lib/orchestrate/utils/describeEndpointResponseShape.d.ts +19 -0
- package/lib/orchestrate/utils/describeEndpointResponseShape.js +30 -0
- package/lib/orchestrate/utils/describeEndpointResponseShape.js.map +1 -0
- package/lib/orchestrate/utils/executeCachedBatch.d.ts +22 -0
- package/lib/orchestrate/utils/executeCachedBatch.js +64 -0
- package/lib/orchestrate/utils/executeCachedBatch.js.map +1 -0
- package/lib/orchestrate/utils/loadShoppingFixture.d.ts +33 -0
- package/lib/orchestrate/utils/loadShoppingFixture.js +17 -0
- package/lib/orchestrate/utils/loadShoppingFixture.js.map +1 -0
- package/lib/orchestrate/utils/normalizeProductPlanPaths.d.ts +24 -0
- package/lib/orchestrate/utils/normalizeProductPlanPaths.js +77 -0
- package/lib/orchestrate/utils/normalizeProductPlanPaths.js.map +1 -0
- package/lib/orchestrate/utils/renderJsonSchema.d.ts +23 -0
- package/lib/orchestrate/utils/renderJsonSchema.js +122 -0
- package/lib/orchestrate/utils/renderJsonSchema.js.map +1 -0
- package/lib/orchestrate/utils/renderResourcePage.d.ts +36 -0
- package/lib/orchestrate/utils/renderResourcePage.js +1415 -0
- package/lib/orchestrate/utils/renderResourcePage.js.map +1 -0
- package/lib/orchestrate/utils/validateFrontendTypecheck.d.ts +109 -0
- package/lib/orchestrate/utils/validateFrontendTypecheck.js +274 -0
- package/lib/orchestrate/utils/validateFrontendTypecheck.js.map +1 -0
- package/lib/preview/renderPreview.d.ts +22 -0
- package/lib/preview/renderPreview.js +198 -0
- package/lib/preview/renderPreview.js.map +1 -0
- package/lib/typings/compiler.d.ts +39 -0
- package/lib/typings/compiler.js +3 -0
- package/lib/typings/compiler.js.map +1 -0
- package/lib/typings/events.d.ts +106 -0
- package/lib/typings/events.js +3 -0
- package/lib/typings/events.js.map +1 -0
- package/lib/typings/index.d.ts +10 -0
- package/lib/typings/index.js +27 -0
- package/lib/typings/index.js.map +1 -0
- package/lib/typings/misc.d.ts +78 -0
- package/lib/typings/misc.js +3 -0
- package/lib/typings/misc.js.map +1 -0
- package/lib/utils/ArrayUtil.d.ts +8 -0
- package/lib/utils/ArrayUtil.js +30 -0
- package/lib/utils/ArrayUtil.js.map +1 -0
- package/lib/utils/StringUtil.d.ts +11 -0
- package/lib/utils/StringUtil.js +28 -0
- package/lib/utils/StringUtil.js.map +1 -0
- package/lib/utils/classifyEndpoints.d.ts +62 -0
- package/lib/utils/classifyEndpoints.js +216 -0
- package/lib/utils/classifyEndpoints.js.map +1 -0
- package/lib/utils/endpointFilter.d.ts +26 -0
- package/lib/utils/endpointFilter.js +0 -0
- package/lib/utils/endpointFilter.js.map +1 -0
- package/lib/utils/extractFields.d.ts +85 -0
- package/lib/utils/extractFields.js +231 -0
- package/lib/utils/extractFields.js.map +1 -0
- package/lib/utils/index.d.ts +13 -0
- package/lib/utils/index.js +30 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/normalizeForNestia.d.ts +34 -0
- package/lib/utils/normalizeForNestia.js +133 -0
- package/lib/utils/normalizeForNestia.js.map +1 -0
- package/lib/utils/resourcePlan.d.ts +39 -0
- package/lib/utils/resourcePlan.js +95 -0
- package/lib/utils/resourcePlan.js.map +1 -0
- package/lib/utils/sliceDocument.d.ts +17 -0
- package/lib/utils/sliceDocument.js +114 -0
- package/lib/utils/sliceDocument.js.map +1 -0
- package/lib/utils/toEndpoints.d.ts +90 -0
- package/lib/utils/toEndpoints.js +227 -0
- package/lib/utils/toEndpoints.js.map +1 -0
- package/lib/verify/runWorkflows.d.ts +25 -0
- package/lib/verify/runWorkflows.js +366 -0
- package/lib/verify/runWorkflows.js.map +1 -0
- package/lib/verify/workflows.d.ts +53 -0
- package/lib/verify/workflows.js +107 -0
- package/lib/verify/workflows.js.map +1 -0
- package/package.json +82 -0
- package/prompts/AUTOVIEW_RENDER.md +398 -0
- package/prompts/AUTOVIEW_REVIEW.md +60 -0
- package/prompts/AUTOVIEW_SDK_STUDY.md +89 -0
- package/src/AutoViewAgent.ts +222 -0
- package/src/agent/emitMcpServer.integration.test.ts +168 -0
- package/src/agent/emitMcpServer.test.ts +51 -0
- package/src/agent/emitMcpServer.ts +178 -0
- package/src/agent/emitReport.ts +117 -0
- package/src/agent/toolSurface.test.ts +243 -0
- package/src/agent/toolSurface.ts +501 -0
- package/src/agent/verifyAgentTasks.test.ts +106 -0
- package/src/agent/verifyAgentTasks.ts +171 -0
- package/src/cli/main.ts +363 -0
- package/src/compiler/AutoViewInterfaceCompiler.ts +69 -0
- package/src/constants/AutoViewFrontendTemplate.ts +42 -0
- package/src/constants/AutoViewSystemPromptConstant.ts +6 -0
- package/src/context/IAutoViewAgentContext.ts +84 -0
- package/src/fromSwagger.test.ts +269 -0
- package/src/fromSwagger.ts +500 -0
- package/src/generateDeterministic.test.ts +39 -0
- package/src/generateDeterministic.ts +77 -0
- package/src/index.ts +30 -0
- package/src/orchestrate/orchestrateAutoView.ts +590 -0
- package/src/orchestrate/orchestrateAutoViewProductPlan.ts +121 -0
- package/src/orchestrate/orchestrateAutoViewRender.ts +1117 -0
- package/src/orchestrate/orchestrateAutoViewRenderDeterministic.ts +101 -0
- package/src/orchestrate/orchestrateAutoViewReview.ts +272 -0
- package/src/orchestrate/orchestrateAutoViewScaffold.ts +627 -0
- package/src/orchestrate/orchestrateAutoViewSdkStudy.ts +90 -0
- package/src/orchestrate/renderNavTs.test.ts +74 -0
- package/src/orchestrate/structures/IAutoViewProductPlan.ts +119 -0
- package/src/orchestrate/structures/IAutoViewProductPlanApplication.ts +41 -0
- package/src/orchestrate/structures/IAutoViewRenderApplication.ts +40 -0
- package/src/orchestrate/structures/IAutoViewReviewApplication.ts +42 -0
- package/src/orchestrate/structures/IAutoViewSdkMap.ts +72 -0
- package/src/orchestrate/structures/IAutoViewSdkStudyApplication.ts +40 -0
- package/src/orchestrate/utils/HistoryMessage.ts +41 -0
- package/src/orchestrate/utils/auditFrontendRuntime.test.ts +18 -0
- package/src/orchestrate/utils/auditFrontendRuntime.ts +454 -0
- package/src/orchestrate/utils/buildDeterministicPlan.test.ts +170 -0
- package/src/orchestrate/utils/buildDeterministicPlan.ts +289 -0
- package/src/orchestrate/utils/buildDeterministicSdkMap.test.ts +90 -0
- package/src/orchestrate/utils/buildDeterministicSdkMap.ts +169 -0
- package/src/orchestrate/utils/cacheNodeModules.ts +136 -0
- package/src/orchestrate/utils/describeEndpointPropsShape.test.ts +86 -0
- package/src/orchestrate/utils/describeEndpointPropsShape.ts +202 -0
- package/src/orchestrate/utils/describeEndpointRequestBodyShape.test.ts +87 -0
- package/src/orchestrate/utils/describeEndpointRequestBodyShape.ts +31 -0
- package/src/orchestrate/utils/describeEndpointResponseShape.test.ts +70 -0
- package/src/orchestrate/utils/describeEndpointResponseShape.ts +32 -0
- package/src/orchestrate/utils/executeCachedBatch.ts +59 -0
- package/src/orchestrate/utils/loadShoppingFixture.ts +52 -0
- package/src/orchestrate/utils/normalizeProductPlanPaths.ts +92 -0
- package/src/orchestrate/utils/renderJsonSchema.test.ts +162 -0
- package/src/orchestrate/utils/renderJsonSchema.ts +133 -0
- package/src/orchestrate/utils/renderResourcePage.test.ts +468 -0
- package/src/orchestrate/utils/renderResourcePage.ts +1624 -0
- package/src/orchestrate/utils/validateFrontendTypecheck.test.ts +32 -0
- package/src/orchestrate/utils/validateFrontendTypecheck.ts +335 -0
- package/src/preview/renderPreview.ts +273 -0
- package/src/typings/compiler.ts +47 -0
- package/src/typings/events.ts +155 -0
- package/src/typings/index.ts +10 -0
- package/src/typings/misc.ts +93 -0
- package/src/utils/ArrayUtil.ts +16 -0
- package/src/utils/StringUtil.ts +29 -0
- package/src/utils/classifyEndpoints.test.ts +86 -0
- package/src/utils/classifyEndpoints.ts +291 -0
- package/src/utils/endpointFilter.test.ts +50 -0
- package/src/utils/endpointFilter.ts +0 -0
- package/src/utils/extractFields.test.ts +82 -0
- package/src/utils/extractFields.ts +306 -0
- package/src/utils/index.ts +13 -0
- package/src/utils/normalizeForNestia.test.ts +93 -0
- package/src/utils/normalizeForNestia.ts +139 -0
- package/src/utils/resourcePlan.test.ts +104 -0
- package/src/utils/resourcePlan.ts +180 -0
- package/src/utils/sliceDocument.test.ts +85 -0
- package/src/utils/sliceDocument.ts +119 -0
- package/src/utils/toEndpoints.test.ts +251 -0
- package/src/utils/toEndpoints.ts +343 -0
- package/src/verify/runWorkflows.ts +403 -0
- package/src/verify/workflows.test.ts +117 -0
- package/src/verify/workflows.ts +154 -0
- package/template/CLAUDE.md +140 -0
- package/template/Dockerfile +31 -0
- package/template/PROMPT.md +80 -0
- package/template/SANDBOX.md +70 -0
- package/template/app/api/health/route.ts +10 -0
- package/template/app/globals.css +97 -0
- package/template/app/layout.tsx +30 -0
- package/template/app/page.tsx +19 -0
- package/template/components/AppShell.tsx +114 -0
- package/template/components/auto/CatalogGrid.tsx +159 -0
- package/template/components/auto/ConfirmButton.tsx +67 -0
- package/template/components/auto/EmbeddedCollection.tsx +144 -0
- package/template/components/auto/ResourceDashboard.tsx +104 -0
- package/template/components/auto/ResourceDetail.tsx +93 -0
- package/template/components/auto/ResourceForm.tsx +235 -0
- package/template/components/auto/ResourceIcon.tsx +88 -0
- package/template/components/auto/ResourceLanding.tsx +155 -0
- package/template/components/auto/ResourceTable.tsx +223 -0
- package/template/components/auto/formatValue.tsx +186 -0
- package/template/components/auto/types.ts +42 -0
- package/template/components/ui/badge.tsx +40 -0
- package/template/components/ui/button.tsx +57 -0
- package/template/components/ui/card.tsx +86 -0
- package/template/components/ui/dialog.tsx +119 -0
- package/template/components/ui/input.tsx +23 -0
- package/template/components/ui/label.tsx +24 -0
- package/template/components/ui/pagination.tsx +117 -0
- package/template/components/ui/select.tsx +92 -0
- package/template/components/ui/sheet.tsx +135 -0
- package/template/components/ui/skeleton.tsx +15 -0
- package/template/components/ui/table.tsx +120 -0
- package/template/components/ui/tabs.tsx +55 -0
- package/template/lib/utils.ts +35 -0
- package/template/next.config.mjs +52 -0
- package/template/package.json +46 -0
- package/template/postcss.config.js +6 -0
- package/template/scripts/start-shopping-backend.sh +56 -0
- package/template/tailwind.config.ts +96 -0
- package/template/tsconfig.json +29 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Frontend Generation Guide
|
|
2
|
+
|
|
3
|
+
> Sourced from
|
|
4
|
+
> [`samchon/shopping/packages/frontend/CLAUDE.md`](https://github.com/samchon/shopping/blob/master/packages/frontend/CLAUDE.md).
|
|
5
|
+
>
|
|
6
|
+
> AutoBE bundles this guide into every generated project so that a coding
|
|
7
|
+
> agent (e.g. Codex CLI, Claude Code, Cursor) can produce a Next.js + shadcn/ui
|
|
8
|
+
> frontend on top of the AutoBE-generated SDK without further instruction.
|
|
9
|
+
|
|
10
|
+
## Goal
|
|
11
|
+
This project should produce a frontend that understands the SDK well.
|
|
12
|
+
|
|
13
|
+
Do not let raw SDK shapes take over the UI.
|
|
14
|
+
|
|
15
|
+
- Keep SDK-specific code in an adapter layer.
|
|
16
|
+
- Let the UI depend on normalized domain models and hooks.
|
|
17
|
+
|
|
18
|
+
## Stack
|
|
19
|
+
Use a fixed base unless the user explicitly wants something else.
|
|
20
|
+
|
|
21
|
+
- Use `TypeScript + Next.js + shadcn/ui` unless the user approves another stack.
|
|
22
|
+
- Use environment variables for the API host.
|
|
23
|
+
- Default API host: `http://127.0.0.1:37001`.
|
|
24
|
+
- Add libraries only when they solve a real problem.
|
|
25
|
+
|
|
26
|
+
## Start
|
|
27
|
+
Before designing screens, make the SDK surface clear.
|
|
28
|
+
|
|
29
|
+
- Scaffold the app.
|
|
30
|
+
- Install the SDK.
|
|
31
|
+
- Read `../api/src/**/*.ts` files carefully — the SDK was generated by AutoBE
|
|
32
|
+
and lives under `src/api/` in this same archive.
|
|
33
|
+
- Read the comments too.
|
|
34
|
+
- Treat code, types, and comments as the source of truth.
|
|
35
|
+
- Map the main APIs, DTOs, and constraints before designing the UI.
|
|
36
|
+
|
|
37
|
+
## Account Guidance
|
|
38
|
+
If the AutoBE backend exposes seed/operator accounts, document them in
|
|
39
|
+
`wiki/` and reuse them anywhere the login flow is introduced. When the
|
|
40
|
+
backend has no fixed accounts, expose membership signup as the first-class
|
|
41
|
+
entry point.
|
|
42
|
+
|
|
43
|
+
## Design
|
|
44
|
+
The code structure should keep replacement cost low if the SDK changes later.
|
|
45
|
+
|
|
46
|
+
- Keep SDK code in a dedicated adapter layer (`src/lib/api/`).
|
|
47
|
+
- Do not spread SDK types across screens and components.
|
|
48
|
+
- Explain any non-default choice for routing, state, fetching, styling, forms,
|
|
49
|
+
testing, or browser automation.
|
|
50
|
+
|
|
51
|
+
## Product
|
|
52
|
+
Read the SDK broadly.
|
|
53
|
+
|
|
54
|
+
Do not turn every endpoint into a feature. Prefer a clear product over full
|
|
55
|
+
endpoint coverage.
|
|
56
|
+
|
|
57
|
+
- Do not force every API into the UI.
|
|
58
|
+
- Leave out APIs that are redundant, diagnostic, cluttering, or harmful to the
|
|
59
|
+
main flow.
|
|
60
|
+
- Note intentional omissions in `wiki/`.
|
|
61
|
+
- Do not invent features the SDK does not support.
|
|
62
|
+
- Handle loading, empty, error, retry, and invalidation states.
|
|
63
|
+
- Finish the main user flows before adding secondary controls.
|
|
64
|
+
|
|
65
|
+
## Visual Style
|
|
66
|
+
The default direction is a simple prototype-first UI.
|
|
67
|
+
|
|
68
|
+
It is only a default. If the user gives a different direction, or if the
|
|
69
|
+
existing product style is already clear, follow that instead.
|
|
70
|
+
|
|
71
|
+
- The UI must work well on mobile, tablet, and desktop.
|
|
72
|
+
- Start from real UI parts such as lists, tables, forms, detail views,
|
|
73
|
+
dialogs, and pagination.
|
|
74
|
+
- Keep the layout readable and content-first.
|
|
75
|
+
- Avoid decorative choices that hurt clarity or usability.
|
|
76
|
+
|
|
77
|
+
## Workflow
|
|
78
|
+
Docs and helper commands should follow the code instead of drifting away from
|
|
79
|
+
it.
|
|
80
|
+
|
|
81
|
+
- Keep `wiki/` aligned with the code.
|
|
82
|
+
- Update docs when architecture, package choices, user flows, or omissions
|
|
83
|
+
change.
|
|
84
|
+
- If a useful project command does not exist yet, create it before relying on
|
|
85
|
+
it.
|
|
86
|
+
|
|
87
|
+
## Testing
|
|
88
|
+
Testing should prove that the rendered product still works.
|
|
89
|
+
|
|
90
|
+
For frontend-only work, keep the test program focused on the frontend itself.
|
|
91
|
+
Do not boot the backend, judge backend health, or let CI drift into server
|
|
92
|
+
checks.
|
|
93
|
+
|
|
94
|
+
The SDK already supports simulation through the connection object. When
|
|
95
|
+
`simulate: true` is set, the SDK returns simulated responses instead of
|
|
96
|
+
calling the real backend. For frontend tests, treat this as API mocking at
|
|
97
|
+
the SDK boundary.
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
const connection: IConnection = {
|
|
101
|
+
host: "http://127.0.0.1:...",
|
|
102
|
+
simulate: true,
|
|
103
|
+
};
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
- If the repo does not have a suitable test stack yet, add one.
|
|
107
|
+
- Keep a browser-first test program for the main user flows.
|
|
108
|
+
- Prefer Playwright for end-to-end and UI review work unless the user wants
|
|
109
|
+
something else.
|
|
110
|
+
- Do not add backend health, startup, or server-state checks to the frontend
|
|
111
|
+
test program or its GitHub Actions workflow.
|
|
112
|
+
- If integration testing is needed, keep it as a separate test program.
|
|
113
|
+
- Keep local test commands and GitHub Actions aligned when the test setup
|
|
114
|
+
changes.
|
|
115
|
+
|
|
116
|
+
## UI Review
|
|
117
|
+
UI work is not done when the code compiles.
|
|
118
|
+
|
|
119
|
+
It is done after the flow has been used and checked.
|
|
120
|
+
|
|
121
|
+
- Run the flow yourself.
|
|
122
|
+
- Prefer direct browser interaction.
|
|
123
|
+
- Install browser automation before falling back.
|
|
124
|
+
- Check the UI at mobile, tablet, and desktop sizes.
|
|
125
|
+
- Verify that controls cause observable changes.
|
|
126
|
+
- Verify that search, sort, pagination, page size, toggles, dialogs, and forms
|
|
127
|
+
actually work when present.
|
|
128
|
+
- Do one final pass for layout and copy before calling the work done.
|
|
129
|
+
- Fall back to screenshots or raw API checks only when browser automation is
|
|
130
|
+
not available.
|
|
131
|
+
|
|
132
|
+
## Done
|
|
133
|
+
Done means the product works, not just that files were written.
|
|
134
|
+
|
|
135
|
+
- The app starts.
|
|
136
|
+
- Core flows work.
|
|
137
|
+
- The UI is coherent.
|
|
138
|
+
- The docs match the code.
|
|
139
|
+
- The tests match the code.
|
|
140
|
+
- If an SDK feature makes the product worse, simplify it or leave it out.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Next.js standalone build optimized for the in-house Sandbox platform.
|
|
2
|
+
# - Multi-stage so the runtime layer carries only `.next/standalone/` and
|
|
3
|
+
# `public/`, not the full `node_modules/`.
|
|
4
|
+
# - Listens on the port supplied by `PORT` (defaults to 3000) so the sandbox
|
|
5
|
+
# ingress can route to it.
|
|
6
|
+
# - The build expects `output: "standalone"` in `next.config.mjs`. The
|
|
7
|
+
# `PROMPT.md` instructs the coding agent to set that flag.
|
|
8
|
+
|
|
9
|
+
FROM node:20-alpine AS deps
|
|
10
|
+
WORKDIR /app
|
|
11
|
+
COPY package.json package-lock.json* ./
|
|
12
|
+
RUN npm ci --no-audit --no-fund
|
|
13
|
+
|
|
14
|
+
FROM node:20-alpine AS build
|
|
15
|
+
WORKDIR /app
|
|
16
|
+
COPY --from=deps /app/node_modules ./node_modules
|
|
17
|
+
COPY . .
|
|
18
|
+
RUN npm run build
|
|
19
|
+
|
|
20
|
+
FROM node:20-alpine AS runtime
|
|
21
|
+
WORKDIR /app
|
|
22
|
+
ENV NODE_ENV=production
|
|
23
|
+
ENV PORT=3000
|
|
24
|
+
ENV HOSTNAME=0.0.0.0
|
|
25
|
+
COPY --from=build /app/public ./public
|
|
26
|
+
COPY --from=build /app/.next/standalone ./
|
|
27
|
+
COPY --from=build /app/.next/static ./.next/static
|
|
28
|
+
EXPOSE 3000
|
|
29
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
|
|
30
|
+
CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:${PORT}/api/health || exit 1
|
|
31
|
+
CMD ["node", "server.js"]
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Frontend Generation — Master Prompt
|
|
2
|
+
|
|
3
|
+
> Paste this entire file into Codex CLI (or any coding agent) as the opening
|
|
4
|
+
> message. The agent will read the SDK, follow `frontend/CLAUDE.md`, and
|
|
5
|
+
> produce a runnable Next.js + shadcn/ui application.
|
|
6
|
+
|
|
7
|
+
You are building a frontend application on top of a TypeScript SDK that
|
|
8
|
+
AutoBE has just generated. Your job is to produce a product, not a catalog.
|
|
9
|
+
|
|
10
|
+
## Inputs in this archive
|
|
11
|
+
|
|
12
|
+
- `frontend/CLAUDE.md` — your operating manual. Follow it strictly.
|
|
13
|
+
- `frontend/SANDBOX.md` — deployment constraints for the in-house Sandbox
|
|
14
|
+
platform. **Mandatory** if the operator plans to deploy this app.
|
|
15
|
+
- `frontend/Dockerfile` — keep this file. The Sandbox build pipeline expects
|
|
16
|
+
it as-is (Next.js standalone, node 20-alpine, healthcheck on `/api/health`).
|
|
17
|
+
- `src/api/**` — the SDK that AutoBE generated. Read every file, including
|
|
18
|
+
the JSDoc comments, before you write a single UI component.
|
|
19
|
+
- `docs/openapi.json` — the OpenAPI document the SDK was generated from. Use
|
|
20
|
+
it only as a cross-reference; the SDK is the source of truth.
|
|
21
|
+
|
|
22
|
+
## Task
|
|
23
|
+
|
|
24
|
+
1. **Study** the SDK. Build a mental map of the resources, actors (e.g.
|
|
25
|
+
customer, seller, administrator, guest), and end-to-end user journeys
|
|
26
|
+
the SDK supports. Write your findings into `frontend/wiki/sdk-map.md`.
|
|
27
|
+
2. **Plan the product**, not the endpoint catalog. Decide which screens
|
|
28
|
+
exist (e.g. Catalog, Cart, Order detail, Admin sales) and what each
|
|
29
|
+
screen does. Each screen typically composes several SDK calls into one
|
|
30
|
+
coherent flow. Record the plan in `frontend/wiki/product-plan.md`,
|
|
31
|
+
including intentional omissions.
|
|
32
|
+
3. **Scaffold** a Next.js 15 + shadcn/ui project inside `frontend/`. Wire
|
|
33
|
+
the SDK through an adapter layer (`frontend/src/lib/api/`). Use
|
|
34
|
+
`simulate: true` on the SDK connection by default so the app stays
|
|
35
|
+
browsable without a live backend. **Set `output: "standalone"`** in
|
|
36
|
+
`next.config.mjs` — the Sandbox Dockerfile depends on this. **Add the
|
|
37
|
+
healthcheck route** `app/api/health/route.ts` that returns
|
|
38
|
+
`Response.json({ status: "ok" })` for `GET`.
|
|
39
|
+
4. **Implement** the planned screens. Use shadcn/ui primitives (Button,
|
|
40
|
+
Card, Table, Dialog, Sheet, Tabs, Form, Select, Pagination, ...) and
|
|
41
|
+
Tailwind utilities. Components must work on mobile, tablet, and desktop.
|
|
42
|
+
Handle loading, empty, error, retry, and invalidation states.
|
|
43
|
+
5. **Verify**. Run the dev server, click through every main flow yourself,
|
|
44
|
+
and capture screenshots into `frontend/wiki/screenshots/`. If a flow is
|
|
45
|
+
awkward because the SDK is awkward, note it in
|
|
46
|
+
`frontend/wiki/sdk-feedback.md` — this feedback is the whole reason the
|
|
47
|
+
frontend exists.
|
|
48
|
+
|
|
49
|
+
## Quality bar
|
|
50
|
+
|
|
51
|
+
- The app boots cleanly with `npm run dev`.
|
|
52
|
+
- The home page is a real landing surface, not a list of API endpoints.
|
|
53
|
+
- Every navigation entry leads to a screen that does something useful.
|
|
54
|
+
- Forms validate on the client and surface server errors gracefully.
|
|
55
|
+
- Lists support pagination, sort, and any filters the SDK exposes.
|
|
56
|
+
- `npm run lint` and `npm run typecheck` both pass.
|
|
57
|
+
- `docker build .` succeeds, and `docker run -p 3000:3000 <image>` exposes
|
|
58
|
+
`GET /api/health` returning `200 { status: "ok" }`. The Sandbox build
|
|
59
|
+
pipeline runs the same `docker build` so this is the deploy gate.
|
|
60
|
+
- `README.md` declares the Sandbox spec (Port, Healthcheck, Dockerfile,
|
|
61
|
+
Env vars) exactly as `frontend/SANDBOX.md` requires.
|
|
62
|
+
|
|
63
|
+
## Deployment target
|
|
64
|
+
|
|
65
|
+
This app deploys to the in-house Sandbox platform via Slack
|
|
66
|
+
`/sandbox-server-infra-setup`. **Do not** generate `vercel.json`,
|
|
67
|
+
`netlify.toml`, or any other public-PaaS config — the operator runs the
|
|
68
|
+
Slack command on a private GitHub repo and Sandbox handles the rest.
|
|
69
|
+
`frontend/SANDBOX.md` lists the exact artifacts the platform expects.
|
|
70
|
+
|
|
71
|
+
## What "done" looks like
|
|
72
|
+
|
|
73
|
+
A non-technical user can open the dev server URL, log in (or use the
|
|
74
|
+
`simulate: true` default), browse the main resources, perform the primary
|
|
75
|
+
CRUD or transactional flows, and form a real opinion about whether the API
|
|
76
|
+
underneath is well-designed. If they cannot — if the UI exposes the API's
|
|
77
|
+
awkwardness — that is valuable signal, not a failure. Write it down in
|
|
78
|
+
`frontend/wiki/sdk-feedback.md`.
|
|
79
|
+
|
|
80
|
+
Start by reading `frontend/CLAUDE.md` in full, then read `src/api/`.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Sandbox Deployment Guide
|
|
2
|
+
|
|
3
|
+
This frontend is generated to deploy on the in-house **Sandbox platform**.
|
|
4
|
+
Vercel and other public PaaS are **out of scope** — do not introduce them.
|
|
5
|
+
|
|
6
|
+
## Required artifacts in the repo
|
|
7
|
+
|
|
8
|
+
The coding agent must produce all of the following at the **repo root** of
|
|
9
|
+
the frontend project. The sandbox `/sandbox-server-infra-setup` command
|
|
10
|
+
reads these to provision the service.
|
|
11
|
+
|
|
12
|
+
| Path | Contents |
|
|
13
|
+
| ------------------- | ------------------------------------------------------------------------ |
|
|
14
|
+
| `Dockerfile` | Multi-stage Next.js standalone build. The template ships one — keep it. |
|
|
15
|
+
| `next.config.mjs` | Must include `output: "standalone"`. |
|
|
16
|
+
| `app/api/health/route.ts` | `GET` returning `200 { status: "ok" }` — wired into the Docker `HEALTHCHECK`. |
|
|
17
|
+
| `README.md` | Lists port, healthcheck path, Dockerfile spec, and env vars (below). |
|
|
18
|
+
|
|
19
|
+
## README spec — required sections
|
|
20
|
+
|
|
21
|
+
The sandbox setup reads these from the README:
|
|
22
|
+
|
|
23
|
+
```markdown
|
|
24
|
+
## Sandbox
|
|
25
|
+
|
|
26
|
+
- Port: 3000
|
|
27
|
+
- Healthcheck: `GET /api/health`
|
|
28
|
+
- Dockerfile: ./Dockerfile (Next.js standalone, node 20-alpine)
|
|
29
|
+
- Env vars (Secret Manager):
|
|
30
|
+
- `NEXT_PUBLIC_API_HOST` — AutoBE backend base URL inside sandbox
|
|
31
|
+
- `MONGO_URL` — autowired by sandbox; do not set manually
|
|
32
|
+
- (anything else this project introduces)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Repo layout — required
|
|
36
|
+
|
|
37
|
+
- **Private repo**, not internal.
|
|
38
|
+
- `dev` environment ↔ `develop` branch.
|
|
39
|
+
- `prod` environment ↔ `main` branch (requires Platform + Security review).
|
|
40
|
+
- If the frontend lives in a sub-folder of a monorepo, the agent must
|
|
41
|
+
document that path so the sandbox setup picks the right `Dockerfile`.
|
|
42
|
+
|
|
43
|
+
## Deploy procedure (operator)
|
|
44
|
+
|
|
45
|
+
1. Push the repo (private). Verify `develop` branch exists.
|
|
46
|
+
2. In Slack `#platform-team`, run `/sandbox-server-infra-setup`.
|
|
47
|
+
3. Select the repo, environment (`dev` first), and enter the reason for
|
|
48
|
+
the request.
|
|
49
|
+
4. Secret Manager is auto-wired; set values according to the env var list
|
|
50
|
+
in the README before promoting to `prod`.
|
|
51
|
+
5. For `prod` rollout, request Platform + Security review.
|
|
52
|
+
|
|
53
|
+
## What the coding agent should NOT do
|
|
54
|
+
|
|
55
|
+
- Do not generate `vercel.json`, `netlify.toml`, or any other public PaaS
|
|
56
|
+
config.
|
|
57
|
+
- Do not embed secrets in source. Reference them through `process.env.*`
|
|
58
|
+
and document them in the README's Sandbox section.
|
|
59
|
+
- Do not change the Dockerfile's `PORT` / `HOSTNAME` / `EXPOSE 3000`
|
|
60
|
+
without also updating the README.
|
|
61
|
+
- Do not remove the `/api/health` route — the Dockerfile `HEALTHCHECK`
|
|
62
|
+
depends on it.
|
|
63
|
+
|
|
64
|
+
## Why this exists
|
|
65
|
+
|
|
66
|
+
The internal Sandbox platform replaces hand-rolled Kubernetes wiring
|
|
67
|
+
(yml + Dockerfile + chart + secrets) with a single Slack command that
|
|
68
|
+
provisions everything in 5–10 minutes from a standardized template. The
|
|
69
|
+
template assumes the four artifacts above. Missing any one of them turns
|
|
70
|
+
a 5-minute deploy back into a half-day infra ticket.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Sandbox HEALTHCHECK endpoint. The Dockerfile invokes
|
|
2
|
+
// `GET /api/health` every 30s — return `{ status: "ok" }` so the container
|
|
3
|
+
// is marked healthy in the sandbox dashboard. Do not remove or rename.
|
|
4
|
+
|
|
5
|
+
export const dynamic = "force-static";
|
|
6
|
+
export const revalidate = false;
|
|
7
|
+
|
|
8
|
+
export function GET(): Response {
|
|
9
|
+
return Response.json({ status: "ok" });
|
|
10
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* SpaceX theme — pure black, white, near-zero radius, industrial.
|
|
7
|
+
* Dark IS the default (SpaceX has no light mode), so the values live in
|
|
8
|
+
* `:root`; `.dark` mirrors them. Monochrome on purpose: color is reserved
|
|
9
|
+
* for status (success/warning/destructive) so state reads instantly against
|
|
10
|
+
* the black. Every Resource* component reads these tokens — re-skinning the
|
|
11
|
+
* whole generated app is a single edit here.
|
|
12
|
+
*/
|
|
13
|
+
@layer base {
|
|
14
|
+
:root {
|
|
15
|
+
--background: 0 0% 0%;
|
|
16
|
+
--foreground: 0 0% 100%;
|
|
17
|
+
|
|
18
|
+
--card: 0 0% 5%;
|
|
19
|
+
--card-foreground: 0 0% 100%;
|
|
20
|
+
--popover: 0 0% 5%;
|
|
21
|
+
--popover-foreground: 0 0% 100%;
|
|
22
|
+
|
|
23
|
+
/* Brand: white-on-black CTA, SpaceX "ORDER NOW" style. */
|
|
24
|
+
--primary: 0 0% 100%;
|
|
25
|
+
--primary-foreground: 0 0% 0%;
|
|
26
|
+
|
|
27
|
+
--secondary: 0 0% 12%;
|
|
28
|
+
--secondary-foreground: 0 0% 100%;
|
|
29
|
+
--muted: 0 0% 11%;
|
|
30
|
+
--muted-foreground: 0 0% 60%;
|
|
31
|
+
|
|
32
|
+
/* Accent = subtle lift on hover / active nav, still monochrome. */
|
|
33
|
+
--accent: 0 0% 14%;
|
|
34
|
+
--accent-foreground: 0 0% 100%;
|
|
35
|
+
|
|
36
|
+
/* Semantic status colors — the only color in the system. */
|
|
37
|
+
--success: 145 63% 45%;
|
|
38
|
+
--success-foreground: 0 0% 0%;
|
|
39
|
+
--warning: 38 92% 55%;
|
|
40
|
+
--warning-foreground: 0 0% 0%;
|
|
41
|
+
--destructive: 0 72% 52%;
|
|
42
|
+
--destructive-foreground: 0 0% 100%;
|
|
43
|
+
|
|
44
|
+
--border: 0 0% 16%;
|
|
45
|
+
--input: 0 0% 18%;
|
|
46
|
+
--ring: 0 0% 80%;
|
|
47
|
+
|
|
48
|
+
--radius: 0.125rem;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.dark {
|
|
52
|
+
--background: 0 0% 0%;
|
|
53
|
+
--foreground: 0 0% 100%;
|
|
54
|
+
|
|
55
|
+
--card: 0 0% 5%;
|
|
56
|
+
--card-foreground: 0 0% 100%;
|
|
57
|
+
--popover: 0 0% 5%;
|
|
58
|
+
--popover-foreground: 0 0% 100%;
|
|
59
|
+
|
|
60
|
+
--primary: 0 0% 100%;
|
|
61
|
+
--primary-foreground: 0 0% 0%;
|
|
62
|
+
|
|
63
|
+
--secondary: 0 0% 12%;
|
|
64
|
+
--secondary-foreground: 0 0% 100%;
|
|
65
|
+
--muted: 0 0% 11%;
|
|
66
|
+
--muted-foreground: 0 0% 60%;
|
|
67
|
+
|
|
68
|
+
--accent: 0 0% 14%;
|
|
69
|
+
--accent-foreground: 0 0% 100%;
|
|
70
|
+
|
|
71
|
+
--success: 145 63% 45%;
|
|
72
|
+
--success-foreground: 0 0% 0%;
|
|
73
|
+
--warning: 38 92% 55%;
|
|
74
|
+
--warning-foreground: 0 0% 0%;
|
|
75
|
+
--destructive: 0 72% 52%;
|
|
76
|
+
--destructive-foreground: 0 0% 100%;
|
|
77
|
+
|
|
78
|
+
--border: 0 0% 16%;
|
|
79
|
+
--input: 0 0% 18%;
|
|
80
|
+
--ring: 0 0% 80%;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@layer base {
|
|
85
|
+
* {
|
|
86
|
+
@apply border-border;
|
|
87
|
+
}
|
|
88
|
+
body {
|
|
89
|
+
@apply bg-background text-foreground;
|
|
90
|
+
font-feature-settings: "tnum" 1, "calt" 1;
|
|
91
|
+
-webkit-font-smoothing: antialiased;
|
|
92
|
+
}
|
|
93
|
+
/* Headings carry the industrial, wide-tracked SpaceX voice. */
|
|
94
|
+
h1, h2 {
|
|
95
|
+
@apply uppercase tracking-wide;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import { Archivo } from "next/font/google";
|
|
3
|
+
import "./globals.css";
|
|
4
|
+
|
|
5
|
+
// Archivo — a grotesque with the industrial, slightly condensed character of
|
|
6
|
+
// SpaceX's D-DIN. Carries the whole UI; headings go uppercase + tracked in CSS.
|
|
7
|
+
const archivo = Archivo({
|
|
8
|
+
subsets: ["latin"],
|
|
9
|
+
variable: "--font-sans",
|
|
10
|
+
display: "swap",
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export const metadata: Metadata = {
|
|
14
|
+
title: "AutoBE Frontend",
|
|
15
|
+
description: "Generated by the AutoView agent on top of an AutoBE SDK.",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default function RootLayout({
|
|
19
|
+
children,
|
|
20
|
+
}: {
|
|
21
|
+
children: React.ReactNode;
|
|
22
|
+
}) {
|
|
23
|
+
return (
|
|
24
|
+
<html lang="en" className={`dark ${archivo.variable}`} suppressHydrationWarning>
|
|
25
|
+
<body className="min-h-screen bg-background font-sans antialiased">
|
|
26
|
+
{children}
|
|
27
|
+
</body>
|
|
28
|
+
</html>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Placeholder landing page. The AutoView agent (or a coding agent following
|
|
2
|
+
// `frontend/PROMPT.md`) replaces this file with the real entry point based
|
|
3
|
+
// on the SDK's actor flow — e.g. a storefront for shopping APIs, a
|
|
4
|
+
// dashboard for admin APIs, etc.
|
|
5
|
+
|
|
6
|
+
export default function HomePage() {
|
|
7
|
+
return (
|
|
8
|
+
<main className="container mx-auto py-16">
|
|
9
|
+
<h1 className="text-3xl font-bold tracking-tight">AutoBE Frontend</h1>
|
|
10
|
+
<p className="mt-3 text-muted-foreground">
|
|
11
|
+
This app has not been customized yet. Follow{" "}
|
|
12
|
+
<code className="rounded bg-muted px-1.5 py-0.5 font-mono text-sm">
|
|
13
|
+
frontend/PROMPT.md
|
|
14
|
+
</code>{" "}
|
|
15
|
+
to scaffold the product on top of the generated SDK.
|
|
16
|
+
</p>
|
|
17
|
+
</main>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Home } from "lucide-react";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import { usePathname } from "next/navigation";
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
|
|
8
|
+
import { ResourceIcon } from "@/components/auto/ResourceIcon";
|
|
9
|
+
import { cn } from "@/lib/utils";
|
|
10
|
+
import { APP_NAME, NAV, type NavItem } from "@/src/lib/nav";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Application chrome shared by every generated page: a persistent left sidebar
|
|
14
|
+
* with the resource navigation (grouped) and a slim top header. Turns the
|
|
15
|
+
* generated pages from bare centered columns into a real admin product. Static
|
|
16
|
+
* and swagger-agnostic — the nav itself is generated into `@/src/lib/nav`.
|
|
17
|
+
*/
|
|
18
|
+
export function AppShell({ children }: { children: React.ReactNode }) {
|
|
19
|
+
const pathname = usePathname();
|
|
20
|
+
const groups = groupNav(NAV);
|
|
21
|
+
|
|
22
|
+
const isActive = (href: string) =>
|
|
23
|
+
pathname === href || pathname.startsWith(`${href}/`);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div className="min-h-screen bg-muted/20">
|
|
27
|
+
<div className="flex">
|
|
28
|
+
<aside className="sticky top-0 hidden h-screen w-60 shrink-0 flex-col border-r bg-background md:flex">
|
|
29
|
+
<Link
|
|
30
|
+
href="/"
|
|
31
|
+
className="flex h-14 items-center gap-2.5 border-b px-5"
|
|
32
|
+
>
|
|
33
|
+
<span className="flex h-6 w-6 items-center justify-center rounded bg-primary text-xs font-bold text-primary-foreground">
|
|
34
|
+
{APP_NAME.charAt(0).toUpperCase()}
|
|
35
|
+
</span>
|
|
36
|
+
<span className="truncate text-sm font-semibold tracking-tight">
|
|
37
|
+
{APP_NAME}
|
|
38
|
+
</span>
|
|
39
|
+
</Link>
|
|
40
|
+
<nav className="flex-1 space-y-5 overflow-y-auto p-3">
|
|
41
|
+
<Link href="/" className={navLinkClass(pathname === "/")}>
|
|
42
|
+
<Home className="h-4 w-4 shrink-0 opacity-70" />
|
|
43
|
+
<span className="truncate">Home</span>
|
|
44
|
+
</Link>
|
|
45
|
+
{groups.map(([group, items]) => (
|
|
46
|
+
<div key={group}>
|
|
47
|
+
<p className="mb-1 px-3 text-[11px] font-medium uppercase tracking-wider text-muted-foreground">
|
|
48
|
+
{group}
|
|
49
|
+
</p>
|
|
50
|
+
<div className="space-y-0.5">
|
|
51
|
+
{items.map((item) => (
|
|
52
|
+
<Link
|
|
53
|
+
key={item.href}
|
|
54
|
+
href={item.href}
|
|
55
|
+
className={navLinkClass(isActive(item.href))}
|
|
56
|
+
>
|
|
57
|
+
<ResourceIcon
|
|
58
|
+
name={item.href}
|
|
59
|
+
className="h-4 w-4 shrink-0 opacity-70"
|
|
60
|
+
/>
|
|
61
|
+
<span className="truncate">{item.title}</span>
|
|
62
|
+
</Link>
|
|
63
|
+
))}
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
))}
|
|
67
|
+
</nav>
|
|
68
|
+
<div className="border-t px-4 py-3 text-[11px] text-muted-foreground">
|
|
69
|
+
Generated by AutoView
|
|
70
|
+
</div>
|
|
71
|
+
</aside>
|
|
72
|
+
|
|
73
|
+
<div className="flex min-w-0 flex-1 flex-col">
|
|
74
|
+
<header className="sticky top-0 z-10 flex h-14 items-center gap-3 border-b bg-background/80 px-5 backdrop-blur md:px-8">
|
|
75
|
+
<Link href="/" className="text-sm font-semibold md:hidden">
|
|
76
|
+
{APP_NAME}
|
|
77
|
+
</Link>
|
|
78
|
+
<nav className="flex gap-1 overflow-x-auto md:hidden">
|
|
79
|
+
{NAV.slice(0, 6).map((item) => (
|
|
80
|
+
<Link
|
|
81
|
+
key={item.href}
|
|
82
|
+
href={item.href}
|
|
83
|
+
className="whitespace-nowrap rounded px-2 py-1 text-xs text-muted-foreground hover:bg-muted"
|
|
84
|
+
>
|
|
85
|
+
{item.title}
|
|
86
|
+
</Link>
|
|
87
|
+
))}
|
|
88
|
+
</nav>
|
|
89
|
+
</header>
|
|
90
|
+
<main className="min-w-0 flex-1">{children}</main>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function navLinkClass(active: boolean): string {
|
|
98
|
+
return cn(
|
|
99
|
+
"flex items-center gap-2.5 rounded-md px-3 py-1.5 text-sm font-medium transition-colors",
|
|
100
|
+
active
|
|
101
|
+
? "bg-muted text-foreground"
|
|
102
|
+
: "text-muted-foreground hover:bg-muted/60 hover:text-foreground",
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function groupNav(items: NavItem[]): Array<[string, NavItem[]]> {
|
|
107
|
+
const map = new Map<string, NavItem[]>();
|
|
108
|
+
for (const item of items) {
|
|
109
|
+
const bucket = map.get(item.group) ?? [];
|
|
110
|
+
bucket.push(item);
|
|
111
|
+
map.set(item.group, bucket);
|
|
112
|
+
}
|
|
113
|
+
return [...map.entries()];
|
|
114
|
+
}
|