@builderos/create-agent-os 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/bin/cli.js +133 -0
- package/package.json +40 -0
- package/src/template/App.tsx +68 -0
- package/src/template/agent-os/commands/create-tasks/1-get-spec-requirements.md +19 -0
- package/src/template/agent-os/commands/create-tasks/2-create-tasks-list.md +234 -0
- package/src/template/agent-os/commands/create-tasks/create-tasks.md +254 -0
- package/src/template/agent-os/commands/design-screen/design-screen.md +32 -0
- package/src/template/agent-os/commands/design-shell/design-shell.md +34 -0
- package/src/template/agent-os/commands/design-tokens/design-tokens.md +36 -0
- package/src/template/agent-os/commands/export-product/export-product.md +44 -0
- package/src/template/agent-os/commands/implement-tasks/1-determine-tasks.md +13 -0
- package/src/template/agent-os/commands/implement-tasks/2-implement-tasks.md +63 -0
- package/src/template/agent-os/commands/implement-tasks/3-verify-implementation.md +113 -0
- package/src/template/agent-os/commands/implement-tasks/implement-tasks.md +207 -0
- package/src/template/agent-os/commands/initialize-design/initialize-design.md +54 -0
- package/src/template/agent-os/commands/orchestrate-tasks/orchestrate-tasks.md +180 -0
- package/src/template/agent-os/commands/plan-product/1-product-concept.md +53 -0
- package/src/template/agent-os/commands/plan-product/2-create-mission.md +78 -0
- package/src/template/agent-os/commands/plan-product/3-create-roadmap.md +73 -0
- package/src/template/agent-os/commands/plan-product/4-create-tech-stack.md +46 -0
- package/src/template/agent-os/commands/plan-product/plan-product.md +241 -0
- package/src/template/agent-os/commands/sample-data/sample-data.md +51 -0
- package/src/template/agent-os/commands/scaffold-implementation/scaffold-implementation.md +36 -0
- package/src/template/agent-os/commands/screenshot-design/screenshot-design.md +21 -0
- package/src/template/agent-os/commands/shape-spec/1-initialize-spec.md +95 -0
- package/src/template/agent-os/commands/shape-spec/2-shape-spec.md +300 -0
- package/src/template/agent-os/commands/shape-spec/shape-spec.md +40 -0
- package/src/template/agent-os/commands/write-spec/write-spec.md +134 -0
- package/src/template/agent-os/config.yml +13 -0
- package/src/template/agent-os/product/mission.md +29 -0
- package/src/template/agent-os/product/roadmap.md +9 -0
- package/src/template/agent-os/product/tech-stack.md +14 -0
- package/src/template/agent-os/specs/README.md +1 -0
- package/src/template/agent-os/standards/backend/api.md +10 -0
- package/src/template/agent-os/standards/backend/migrations.md +9 -0
- package/src/template/agent-os/standards/backend/models.md +10 -0
- package/src/template/agent-os/standards/backend/queries.md +9 -0
- package/src/template/agent-os/standards/frontend/accessibility.md +10 -0
- package/src/template/agent-os/standards/frontend/components.md +11 -0
- package/src/template/agent-os/standards/frontend/css.md +7 -0
- package/src/template/agent-os/standards/frontend/responsive.md +11 -0
- package/src/template/agent-os/standards/global/coding-style.md +10 -0
- package/src/template/agent-os/standards/global/commenting.md +5 -0
- package/src/template/agent-os/standards/global/conventions.md +11 -0
- package/src/template/agent-os/standards/global/error-handling.md +9 -0
- package/src/template/agent-os/standards/global/tech-stack.md +31 -0
- package/src/template/agent-os/standards/global/validation.md +11 -0
- package/src/template/agent-os/standards/testing/test-writing.md +9 -0
- package/src/template/agent-os-ui/README.md +73 -0
- package/src/template/agent-os-ui/package-lock.json +5028 -0
- package/src/template/agent-os-ui/package.json +52 -0
- package/src/template/agent-os-ui/postcss.config.js +6 -0
- package/src/template/agent-os-ui/src/components/AgentShell.tsx +31 -0
- package/src/template/agent-os-ui/src/components/AgentSidebar.tsx +65 -0
- package/src/template/agent-os-ui/src/components/GuidanceCard.tsx +75 -0
- package/src/template/agent-os-ui/src/components/MarkdownViewer.tsx +25 -0
- package/src/template/agent-os-ui/src/components/PromptButton.tsx +28 -0
- package/src/template/agent-os-ui/src/components/StatusItem.tsx +45 -0
- package/src/template/agent-os-ui/src/components/ThemeToggle.tsx +72 -0
- package/src/template/agent-os-ui/src/index.ts +11 -0
- package/src/template/agent-os-ui/src/style.css +3 -0
- package/src/template/agent-os-ui/tailwind.config.js +50 -0
- package/src/template/agent-os-ui/tsconfig.json +33 -0
- package/src/template/agent-os-ui/vite.config.ts +32 -0
- package/src/template/control-center/backend/backend.log +2 -0
- package/src/template/control-center/backend/index.js +228 -0
- package/src/template/control-center/backend/package-lock.json +951 -0
- package/src/template/control-center/backend/package.json +19 -0
- package/src/template/control-center/frontend/README.md +73 -0
- package/src/template/control-center/frontend/eslint.config.js +23 -0
- package/src/template/control-center/frontend/index.html +21 -0
- package/src/template/control-center/frontend/package-lock.json +5752 -0
- package/src/template/control-center/frontend/package.json +42 -0
- package/src/template/control-center/frontend/public/runtime-config.json +11 -0
- package/src/template/control-center/frontend/public/vite.svg +1 -0
- package/src/template/control-center/frontend/src/App.css +42 -0
- package/src/template/control-center/frontend/src/App.tsx +738 -0
- package/src/template/control-center/frontend/src/assets/react.svg +1 -0
- package/src/template/control-center/frontend/src/components/ThemeToggle.tsx +64 -0
- package/src/template/control-center/frontend/src/components/ui/ToastContext.tsx +81 -0
- package/src/template/control-center/frontend/src/index.css +194 -0
- package/src/template/control-center/frontend/src/main.tsx +14 -0
- package/src/template/control-center/frontend/src/vite-env.d.ts +1 -0
- package/src/template/control-center/frontend/tsconfig.app.json +28 -0
- package/src/template/control-center/frontend/tsconfig.json +7 -0
- package/src/template/control-center/frontend/tsconfig.node.json +26 -0
- package/src/template/control-center/frontend/vite.config.ts +22 -0
- package/src/template/design/.claude/commands/design-os/data-model.md +122 -0
- package/src/template/design/.claude/commands/design-os/design-screen.md +309 -0
- package/src/template/design/.claude/commands/design-os/design-shell.md +238 -0
- package/src/template/design/.claude/commands/design-os/design-tokens.md +166 -0
- package/src/template/design/.claude/commands/design-os/export-product.md +1105 -0
- package/src/template/design/.claude/commands/design-os/product-roadmap.md +121 -0
- package/src/template/design/.claude/commands/design-os/product-vision.md +99 -0
- package/src/template/design/.claude/commands/design-os/sample-data.md +263 -0
- package/src/template/design/.claude/commands/design-os/screenshot-design.md +112 -0
- package/src/template/design/.claude/commands/design-os/shape-section.md +138 -0
- package/src/template/design/.claude/skills/frontend-design/SKILL.md +42 -0
- package/src/template/design/.github/CODE_OF_CONDUCT.md +5 -0
- package/src/template/design/.github/CONTRIBUTING.md +51 -0
- package/src/template/design/.github/ISSUE_TEMPLATE/config.yml +22 -0
- package/src/template/design/.github/PULL_REQUEST_TEMPLATE.md +20 -0
- package/src/template/design/.github/SECURITY.yml +5 -0
- package/src/template/design/.github/SUPPORT.md +19 -0
- package/src/template/design/.github/workflows/pr-decline.yml +135 -0
- package/src/template/design/.github/workflows/stale.yml +25 -0
- package/src/template/design/CHANGELOG.md +13 -0
- package/src/template/design/LICENSE +21 -0
- package/src/template/design/README.md +54 -0
- package/src/template/design/agents.md +218 -0
- package/src/template/design/claude.md +1 -0
- package/src/template/design/components.json +22 -0
- package/src/template/design/docs/codebase-implementation.md +153 -0
- package/src/template/design/docs/design-section.md +135 -0
- package/src/template/design/docs/export.md +149 -0
- package/src/template/design/docs/getting-started.md +59 -0
- package/src/template/design/docs/index.md +56 -0
- package/src/template/design/docs/product-planning.md +113 -0
- package/src/template/design/docs/requirements.md +22 -0
- package/src/template/design/docs/usage.md +62 -0
- package/src/template/design/eslint.config.js +23 -0
- package/src/template/design/index.html +21 -0
- package/src/template/design/package-lock.json +5473 -0
- package/src/template/design/package.json +47 -0
- package/src/template/design/product-plan.zip +0 -0
- package/src/template/design/public/vite.svg +1 -0
- package/src/template/design/src/assets/react.svg +1 -0
- package/src/template/design/src/components/AppLayout.tsx +95 -0
- package/src/template/design/src/components/DataCard.tsx +139 -0
- package/src/template/design/src/components/DataModelPage.tsx +120 -0
- package/src/template/design/src/components/DesignPage.tsx +284 -0
- package/src/template/design/src/components/EmptyState.tsx +155 -0
- package/src/template/design/src/components/ExportPage.tsx +344 -0
- package/src/template/design/src/components/NextPhaseButton.tsx +33 -0
- package/src/template/design/src/components/PhaseNav.tsx +152 -0
- package/src/template/design/src/components/PhaseWarningBanner.tsx +81 -0
- package/src/template/design/src/components/ProductOverviewCard.tsx +102 -0
- package/src/template/design/src/components/ProductPage.tsx +97 -0
- package/src/template/design/src/components/ScreenDesignPage.tsx +370 -0
- package/src/template/design/src/components/ScreenDesignsCard.tsx +49 -0
- package/src/template/design/src/components/SectionPage.tsx +256 -0
- package/src/template/design/src/components/SectionsCard.tsx +47 -0
- package/src/template/design/src/components/SectionsPage.tsx +181 -0
- package/src/template/design/src/components/ShellCard.tsx +85 -0
- package/src/template/design/src/components/ShellDesignPage.tsx +242 -0
- package/src/template/design/src/components/SpecCard.tsx +121 -0
- package/src/template/design/src/components/StepIndicator.tsx +75 -0
- package/src/template/design/src/components/ThemeToggle.tsx +86 -0
- package/src/template/design/src/components/ui/ToastContext.tsx +81 -0
- package/src/template/design/src/components/ui/avatar.tsx +53 -0
- package/src/template/design/src/components/ui/badge.tsx +46 -0
- package/src/template/design/src/components/ui/button.tsx +60 -0
- package/src/template/design/src/components/ui/card.tsx +92 -0
- package/src/template/design/src/components/ui/collapsible.tsx +48 -0
- package/src/template/design/src/components/ui/dialog.tsx +143 -0
- package/src/template/design/src/components/ui/dropdown-menu.tsx +255 -0
- package/src/template/design/src/components/ui/input.tsx +21 -0
- package/src/template/design/src/components/ui/label.tsx +22 -0
- package/src/template/design/src/components/ui/progress.tsx +24 -0
- package/src/template/design/src/components/ui/scroll-area.tsx +18 -0
- package/src/template/design/src/components/ui/select.tsx +67 -0
- package/src/template/design/src/components/ui/separator.tsx +28 -0
- package/src/template/design/src/components/ui/sheet.tsx +137 -0
- package/src/template/design/src/components/ui/skeleton.tsx +13 -0
- package/src/template/design/src/components/ui/switch.tsx +46 -0
- package/src/template/design/src/components/ui/table.tsx +116 -0
- package/src/template/design/src/components/ui/tabs.tsx +64 -0
- package/src/template/design/src/index.css +284 -0
- package/src/template/design/src/lib/data-model-loader.ts +91 -0
- package/src/template/design/src/lib/design-system-loader.ts +101 -0
- package/src/template/design/src/lib/product-loader.ts +221 -0
- package/src/template/design/src/lib/router.tsx +52 -0
- package/src/template/design/src/lib/section-loader.ts +272 -0
- package/src/template/design/src/lib/shell-loader.ts +175 -0
- package/src/template/design/src/lib/utils.ts +6 -0
- package/src/template/design/src/main.tsx +15 -0
- package/src/template/design/src/sections/.gitkeep +0 -0
- package/src/template/design/src/sections/ai-orchestration-engine-oai/OrchestrationEngine.tsx +348 -0
- package/src/template/design/src/sections/core-platform-shell/AppShell.tsx +403 -0
- package/src/template/design/src/sections/gemini-live-integration/GeminiIntegration.tsx +332 -0
- package/src/template/design/src/sections/interactive-2d-canvas/WhiteboardCanvas.tsx +334 -0
- package/src/template/design/src/sections/participation-equity-tracker/EquityTracker.tsx +383 -0
- package/src/template/design/src/sections/persistent-memory-system/PersistentMemory.tsx +308 -0
- package/src/template/design/src/sections/real-time-communication-layer/VideoSession.tsx +342 -0
- package/src/template/design/src/sections/visual-intelligence-agents/VisualAgents.tsx +311 -0
- package/src/template/design/src/types/product.ts +97 -0
- package/src/template/design/src/types/section.ts +33 -0
- package/src/template/design/tsconfig.app.json +34 -0
- package/src/template/design/tsconfig.json +13 -0
- package/src/template/design/tsconfig.node.json +26 -0
- package/src/template/design/vite.config.ts +18 -0
- package/src/template/package.json +27 -0
- package/src/template/vite.config.ts +16 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { useMemo } from 'react'
|
|
2
|
+
import { useParams, Link, useNavigate } from 'react-router-dom'
|
|
3
|
+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
|
4
|
+
import { AppLayout } from '@/components/AppLayout'
|
|
5
|
+
import { EmptyState } from '@/components/EmptyState'
|
|
6
|
+
import { PhaseWarningBanner } from '@/components/PhaseWarningBanner'
|
|
7
|
+
import { SpecCard } from '@/components/SpecCard'
|
|
8
|
+
import { DataCard } from '@/components/DataCard'
|
|
9
|
+
import { StepIndicator, type StepStatus } from '@/components/StepIndicator'
|
|
10
|
+
import { loadProductData } from '@/lib/product-loader'
|
|
11
|
+
import { loadSectionData } from '@/lib/section-loader'
|
|
12
|
+
import { ChevronRight, Layout, Image, Download, ArrowRight, LayoutList } from 'lucide-react'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Determine the status of each step based on what data exists
|
|
16
|
+
* Steps: 1. Section Overview (Spec), 2. Sample Data, 3. Screen Designs, 4. Screenshots
|
|
17
|
+
*/
|
|
18
|
+
function getStepStatuses(sectionData: ReturnType<typeof loadSectionData> | null): StepStatus[] {
|
|
19
|
+
const hasSpec = !!sectionData?.specParsed
|
|
20
|
+
const hasData = !!sectionData?.data
|
|
21
|
+
const hasScreenDesigns = !!(sectionData?.screenDesigns && sectionData.screenDesigns.length > 0)
|
|
22
|
+
const hasScreenshots = !!(sectionData?.screenshots && sectionData.screenshots.length > 0)
|
|
23
|
+
|
|
24
|
+
const steps: boolean[] = [hasSpec, hasData, hasScreenDesigns, hasScreenshots]
|
|
25
|
+
const firstIncomplete = steps.findIndex((done) => !done)
|
|
26
|
+
|
|
27
|
+
return steps.map((done, index) => {
|
|
28
|
+
if (done) return 'completed'
|
|
29
|
+
if (index === firstIncomplete) return 'current'
|
|
30
|
+
return 'upcoming'
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Check if the required steps for a section are complete (Spec, Data, Screen Designs)
|
|
36
|
+
* Screenshots are optional and don't count toward completion
|
|
37
|
+
*/
|
|
38
|
+
function areRequiredStepsComplete(sectionData: ReturnType<typeof loadSectionData> | null): boolean {
|
|
39
|
+
const hasSpec = !!sectionData?.specParsed
|
|
40
|
+
const hasData = !!sectionData?.data
|
|
41
|
+
const hasScreenDesigns = !!(sectionData?.screenDesigns && sectionData.screenDesigns.length > 0)
|
|
42
|
+
return hasSpec && hasData && hasScreenDesigns
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function SectionPage() {
|
|
46
|
+
const { sectionId } = useParams<{ sectionId: string }>()
|
|
47
|
+
const navigate = useNavigate()
|
|
48
|
+
|
|
49
|
+
// Load product data to get section info
|
|
50
|
+
const productData = useMemo(() => loadProductData(), [])
|
|
51
|
+
const sections = productData.roadmap?.sections || []
|
|
52
|
+
const section = sections.find((s) => s.id === sectionId)
|
|
53
|
+
const currentIndex = sections.findIndex((s) => s.id === sectionId)
|
|
54
|
+
|
|
55
|
+
// Load section-specific data (spec, data.json, screen designs, screenshots)
|
|
56
|
+
const sectionData = useMemo(
|
|
57
|
+
() => (sectionId ? loadSectionData(sectionId) : null),
|
|
58
|
+
[sectionId]
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
// Handle missing section
|
|
62
|
+
if (!section) {
|
|
63
|
+
return (
|
|
64
|
+
<AppLayout backTo="/sections" backLabel="Sections">
|
|
65
|
+
<div className="text-center py-12">
|
|
66
|
+
<p className="text-stone-600 dark:text-stone-400">
|
|
67
|
+
Section not found: {sectionId}
|
|
68
|
+
</p>
|
|
69
|
+
</div>
|
|
70
|
+
</AppLayout>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const stepStatuses = getStepStatuses(sectionData)
|
|
75
|
+
const requiredStepsComplete = areRequiredStepsComplete(sectionData)
|
|
76
|
+
|
|
77
|
+
// Next section navigation logic
|
|
78
|
+
const isLastSection = currentIndex === sections.length - 1 || currentIndex === -1
|
|
79
|
+
const nextSection = !isLastSection ? sections[currentIndex + 1] : null
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<AppLayout backTo="/sections" backLabel="Sections" title={section.title}>
|
|
83
|
+
<div className="space-y-6">
|
|
84
|
+
{/* Page intro */}
|
|
85
|
+
<div className="mb-8">
|
|
86
|
+
<h1 className="text-2xl font-semibold text-stone-900 dark:text-stone-100 mb-2">
|
|
87
|
+
{section.title}
|
|
88
|
+
</h1>
|
|
89
|
+
<p className="text-stone-600 dark:text-stone-400">
|
|
90
|
+
{section.description}
|
|
91
|
+
</p>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
{/* Warning banner for incomplete prerequisite phases */}
|
|
95
|
+
<PhaseWarningBanner />
|
|
96
|
+
|
|
97
|
+
{/* Step 1: Section Overview (Spec) */}
|
|
98
|
+
<StepIndicator step={1} status={stepStatuses[0]}>
|
|
99
|
+
<SpecCard
|
|
100
|
+
spec={sectionData?.specParsed || null}
|
|
101
|
+
sectionTitle={section?.title || "Section Overview"}
|
|
102
|
+
sectionId={sectionId}
|
|
103
|
+
/>
|
|
104
|
+
</StepIndicator>
|
|
105
|
+
|
|
106
|
+
{/* Step 2: Sample Data */}
|
|
107
|
+
<StepIndicator step={2} status={stepStatuses[1]}>
|
|
108
|
+
<DataCard
|
|
109
|
+
data={sectionData?.data || null}
|
|
110
|
+
sectionTitle={section?.title}
|
|
111
|
+
sectionId={sectionId}
|
|
112
|
+
/>
|
|
113
|
+
</StepIndicator>
|
|
114
|
+
|
|
115
|
+
{/* Step 3: Screen Designs */}
|
|
116
|
+
<StepIndicator step={3} status={stepStatuses[2]}>
|
|
117
|
+
{!sectionData?.screenDesigns || sectionData.screenDesigns.length === 0 ? (
|
|
118
|
+
<EmptyState
|
|
119
|
+
type="screen-designs"
|
|
120
|
+
context={section?.title}
|
|
121
|
+
contextId={sectionId}
|
|
122
|
+
/>
|
|
123
|
+
) : (
|
|
124
|
+
<Card className="border-stone-200 dark:border-stone-700 shadow-sm">
|
|
125
|
+
<CardHeader className="pb-4">
|
|
126
|
+
<CardTitle className="text-lg font-semibold text-stone-900 dark:text-stone-100">
|
|
127
|
+
Screen Designs
|
|
128
|
+
<span className="ml-2 text-sm font-normal text-stone-500 dark:text-stone-400">
|
|
129
|
+
({sectionData.screenDesigns.length})
|
|
130
|
+
</span>
|
|
131
|
+
</CardTitle>
|
|
132
|
+
</CardHeader>
|
|
133
|
+
<CardContent className="p-0">
|
|
134
|
+
<ul className="divide-y divide-stone-200 dark:divide-stone-700">
|
|
135
|
+
{sectionData.screenDesigns.map((screenDesign) => (
|
|
136
|
+
<li key={screenDesign.name}>
|
|
137
|
+
<Link
|
|
138
|
+
to={`/sections/${sectionId}/screen-designs/${screenDesign.name}`}
|
|
139
|
+
className="flex items-center justify-between gap-4 px-6 py-4 hover:bg-stone-50 dark:hover:bg-stone-800/50 transition-colors"
|
|
140
|
+
>
|
|
141
|
+
<div className="flex items-center gap-3 min-w-0">
|
|
142
|
+
<div className="w-8 h-8 rounded-md bg-stone-200 dark:bg-stone-700 flex items-center justify-center shrink-0">
|
|
143
|
+
<Layout className="w-4 h-4 text-stone-600 dark:text-stone-300" strokeWidth={1.5} />
|
|
144
|
+
</div>
|
|
145
|
+
<span className="font-medium text-stone-900 dark:text-stone-100 truncate">
|
|
146
|
+
{screenDesign.name}
|
|
147
|
+
</span>
|
|
148
|
+
</div>
|
|
149
|
+
<ChevronRight className="w-4 h-4 text-stone-400 dark:text-stone-500 shrink-0" strokeWidth={1.5} />
|
|
150
|
+
</Link>
|
|
151
|
+
</li>
|
|
152
|
+
))}
|
|
153
|
+
</ul>
|
|
154
|
+
</CardContent>
|
|
155
|
+
</Card>
|
|
156
|
+
)}
|
|
157
|
+
</StepIndicator>
|
|
158
|
+
|
|
159
|
+
{/* Step 4: Screenshots */}
|
|
160
|
+
<StepIndicator step={4} status={stepStatuses[3]} isLast={!requiredStepsComplete}>
|
|
161
|
+
{!sectionData?.screenshots || sectionData.screenshots.length === 0 ? (
|
|
162
|
+
<EmptyState
|
|
163
|
+
type="screenshots"
|
|
164
|
+
context={section?.title}
|
|
165
|
+
contextId={sectionId}
|
|
166
|
+
/>
|
|
167
|
+
) : (
|
|
168
|
+
<Card className="border-stone-200 dark:border-stone-700 shadow-sm">
|
|
169
|
+
<CardHeader className="pb-4">
|
|
170
|
+
<CardTitle className="text-lg font-semibold text-stone-900 dark:text-stone-100">
|
|
171
|
+
Screenshots
|
|
172
|
+
<span className="ml-2 text-sm font-normal text-stone-500 dark:text-stone-400">
|
|
173
|
+
({sectionData.screenshots.length})
|
|
174
|
+
</span>
|
|
175
|
+
</CardTitle>
|
|
176
|
+
</CardHeader>
|
|
177
|
+
<CardContent>
|
|
178
|
+
<div className="grid grid-cols-2 gap-4">
|
|
179
|
+
{sectionData.screenshots.map((screenshot) => (
|
|
180
|
+
<div key={screenshot.name} className="group">
|
|
181
|
+
<div className="aspect-video rounded-lg overflow-hidden bg-stone-100 dark:bg-stone-800 border border-stone-200 dark:border-stone-700">
|
|
182
|
+
<img
|
|
183
|
+
src={screenshot.url}
|
|
184
|
+
alt={screenshot.name}
|
|
185
|
+
className="w-full h-full object-cover"
|
|
186
|
+
/>
|
|
187
|
+
</div>
|
|
188
|
+
<div className="mt-2 flex items-center justify-between gap-2">
|
|
189
|
+
<p className="text-sm text-stone-600 dark:text-stone-400 truncate">
|
|
190
|
+
{screenshot.name}
|
|
191
|
+
</p>
|
|
192
|
+
<a
|
|
193
|
+
href={screenshot.url}
|
|
194
|
+
download={`${screenshot.name}.png`}
|
|
195
|
+
className="shrink-0 p-1.5 rounded-md text-stone-400 hover:text-stone-600 dark:text-stone-500 dark:hover:text-stone-300 hover:bg-stone-100 dark:hover:bg-stone-800 transition-colors"
|
|
196
|
+
title="Download screenshot"
|
|
197
|
+
>
|
|
198
|
+
<Download className="w-4 h-4" strokeWidth={1.5} />
|
|
199
|
+
</a>
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
))}
|
|
203
|
+
</div>
|
|
204
|
+
</CardContent>
|
|
205
|
+
</Card>
|
|
206
|
+
)}
|
|
207
|
+
</StepIndicator>
|
|
208
|
+
|
|
209
|
+
{/* Next Step - shown when required steps (Spec, Data, Screen Designs) are complete */}
|
|
210
|
+
{requiredStepsComplete && (
|
|
211
|
+
<StepIndicator step={5} status="current" isLast>
|
|
212
|
+
<div className="space-y-3">
|
|
213
|
+
{/* If there's a next section, show two options */}
|
|
214
|
+
{nextSection ? (
|
|
215
|
+
<>
|
|
216
|
+
<button
|
|
217
|
+
onClick={() => navigate(`/sections/${nextSection.id}`)}
|
|
218
|
+
className="w-full flex items-center justify-between gap-4 px-6 py-4 bg-stone-900 dark:bg-stone-100 text-stone-100 dark:text-stone-900 rounded-lg hover:bg-stone-800 dark:hover:bg-stone-200 transition-colors group"
|
|
219
|
+
>
|
|
220
|
+
<div className="flex items-center gap-3">
|
|
221
|
+
<ArrowRight className="w-5 h-5" strokeWidth={1.5} />
|
|
222
|
+
<span className="font-medium">Continue to {nextSection.title}</span>
|
|
223
|
+
</div>
|
|
224
|
+
<ArrowRight className="w-5 h-5 transition-transform group-hover:translate-x-1" strokeWidth={1.5} />
|
|
225
|
+
</button>
|
|
226
|
+
<button
|
|
227
|
+
onClick={() => navigate('/sections')}
|
|
228
|
+
className="w-full flex items-center justify-between gap-4 px-6 py-4 bg-stone-100 dark:bg-stone-800 text-stone-700 dark:text-stone-300 rounded-lg hover:bg-stone-200 dark:hover:bg-stone-700 transition-colors group"
|
|
229
|
+
>
|
|
230
|
+
<div className="flex items-center gap-3">
|
|
231
|
+
<LayoutList className="w-5 h-5" strokeWidth={1.5} />
|
|
232
|
+
<span className="font-medium">View All Sections</span>
|
|
233
|
+
</div>
|
|
234
|
+
<ChevronRight className="w-5 h-5 transition-transform group-hover:translate-x-1" strokeWidth={1.5} />
|
|
235
|
+
</button>
|
|
236
|
+
</>
|
|
237
|
+
) : (
|
|
238
|
+
/* If this is the last or only section, show single link back to sections */
|
|
239
|
+
<button
|
|
240
|
+
onClick={() => navigate('/sections')}
|
|
241
|
+
className="w-full flex items-center justify-between gap-4 px-6 py-4 bg-stone-900 dark:bg-stone-100 text-stone-100 dark:text-stone-900 rounded-lg hover:bg-stone-800 dark:hover:bg-stone-200 transition-colors group"
|
|
242
|
+
>
|
|
243
|
+
<div className="flex items-center gap-3">
|
|
244
|
+
<LayoutList className="w-5 h-5" strokeWidth={1.5} />
|
|
245
|
+
<span className="font-medium">Back to All Sections</span>
|
|
246
|
+
</div>
|
|
247
|
+
<ArrowRight className="w-5 h-5 transition-transform group-hover:translate-x-1" strokeWidth={1.5} />
|
|
248
|
+
</button>
|
|
249
|
+
)}
|
|
250
|
+
</div>
|
|
251
|
+
</StepIndicator>
|
|
252
|
+
)}
|
|
253
|
+
</div>
|
|
254
|
+
</AppLayout>
|
|
255
|
+
)
|
|
256
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
|
2
|
+
import { ChevronRight } from 'lucide-react'
|
|
3
|
+
import type { ProductRoadmap } from '@/types/product'
|
|
4
|
+
|
|
5
|
+
interface SectionsCardProps {
|
|
6
|
+
roadmap: ProductRoadmap
|
|
7
|
+
onSectionClick: (sectionId: string) => void
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function SectionsCard({ roadmap, onSectionClick }: SectionsCardProps) {
|
|
11
|
+
return (
|
|
12
|
+
<Card className="border-stone-200 dark:border-stone-700 shadow-sm">
|
|
13
|
+
<CardHeader className="pb-4">
|
|
14
|
+
<CardTitle className="text-lg font-semibold text-stone-900 dark:text-stone-100">
|
|
15
|
+
Sections
|
|
16
|
+
</CardTitle>
|
|
17
|
+
</CardHeader>
|
|
18
|
+
<CardContent className="p-0">
|
|
19
|
+
<ul className="divide-y divide-stone-200 dark:divide-stone-700">
|
|
20
|
+
{roadmap.sections.map((section) => (
|
|
21
|
+
<li key={section.id}>
|
|
22
|
+
<button
|
|
23
|
+
onClick={() => onSectionClick(section.id)}
|
|
24
|
+
className="w-full px-6 py-4 flex items-center justify-between gap-4 text-left hover:bg-stone-50 dark:hover:bg-stone-800/50 transition-colors"
|
|
25
|
+
>
|
|
26
|
+
<div className="flex items-start gap-4 min-w-0">
|
|
27
|
+
<span className="shrink-0 w-6 h-6 rounded-full bg-stone-200 dark:bg-stone-700 text-stone-600 dark:text-stone-300 text-xs font-medium flex items-center justify-center">
|
|
28
|
+
{section.order}
|
|
29
|
+
</span>
|
|
30
|
+
<div className="min-w-0">
|
|
31
|
+
<h3 className="font-medium text-stone-900 dark:text-stone-100 truncate">
|
|
32
|
+
{section.title}
|
|
33
|
+
</h3>
|
|
34
|
+
<p className="text-sm text-stone-500 dark:text-stone-400 mt-0.5 line-clamp-1">
|
|
35
|
+
{section.description}
|
|
36
|
+
</p>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
<ChevronRight className="w-4 h-4 text-stone-400 dark:text-stone-500 flex-shrink-0" strokeWidth={1.5} />
|
|
40
|
+
</button>
|
|
41
|
+
</li>
|
|
42
|
+
))}
|
|
43
|
+
</ul>
|
|
44
|
+
</CardContent>
|
|
45
|
+
</Card>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { useMemo } from 'react'
|
|
2
|
+
import { useNavigate } from 'react-router-dom'
|
|
3
|
+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
|
4
|
+
import { AppLayout } from '@/components/AppLayout'
|
|
5
|
+
import { EmptyState } from '@/components/EmptyState'
|
|
6
|
+
import { PhaseWarningBanner } from '@/components/PhaseWarningBanner'
|
|
7
|
+
import { NextPhaseButton } from '@/components/NextPhaseButton'
|
|
8
|
+
import { loadProductData } from '@/lib/product-loader'
|
|
9
|
+
import { getSectionScreenDesigns, getSectionScreenshots, hasSectionSpec, hasSectionData } from '@/lib/section-loader'
|
|
10
|
+
import { ChevronRight, Check, Circle } from 'lucide-react'
|
|
11
|
+
|
|
12
|
+
interface SectionProgress {
|
|
13
|
+
hasSpec: boolean
|
|
14
|
+
hasData: boolean
|
|
15
|
+
hasScreenDesigns: boolean
|
|
16
|
+
screenDesignCount: number
|
|
17
|
+
hasScreenshots: boolean
|
|
18
|
+
screenshotCount: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function getSectionProgress(sectionId: string): SectionProgress {
|
|
22
|
+
const screenDesigns = getSectionScreenDesigns(sectionId)
|
|
23
|
+
const screenshots = getSectionScreenshots(sectionId)
|
|
24
|
+
return {
|
|
25
|
+
hasSpec: hasSectionSpec(sectionId),
|
|
26
|
+
hasData: hasSectionData(sectionId),
|
|
27
|
+
hasScreenDesigns: screenDesigns.length > 0,
|
|
28
|
+
screenDesignCount: screenDesigns.length,
|
|
29
|
+
hasScreenshots: screenshots.length > 0,
|
|
30
|
+
screenshotCount: screenshots.length,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function SectionsPage() {
|
|
35
|
+
const navigate = useNavigate()
|
|
36
|
+
const productData = useMemo(() => loadProductData(), [])
|
|
37
|
+
|
|
38
|
+
const sections = productData.roadmap?.sections || []
|
|
39
|
+
|
|
40
|
+
// Calculate progress for each section
|
|
41
|
+
const sectionProgressMap = useMemo(() => {
|
|
42
|
+
const map: Record<string, SectionProgress> = {}
|
|
43
|
+
for (const section of sections) {
|
|
44
|
+
map[section.id] = getSectionProgress(section.id)
|
|
45
|
+
}
|
|
46
|
+
return map
|
|
47
|
+
}, [sections])
|
|
48
|
+
|
|
49
|
+
// Count completed sections (those with spec, data, AND screen designs)
|
|
50
|
+
const completedSections = sections.filter(s => {
|
|
51
|
+
const p = sectionProgressMap[s.id]
|
|
52
|
+
return p?.hasSpec && p?.hasData && p?.hasScreenDesigns
|
|
53
|
+
}).length
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<AppLayout>
|
|
57
|
+
<div className="space-y-6">
|
|
58
|
+
{/* Page intro */}
|
|
59
|
+
<div className="mb-8">
|
|
60
|
+
<h1 className="text-2xl font-semibold text-stone-900 dark:text-stone-100 mb-2">
|
|
61
|
+
Sections
|
|
62
|
+
</h1>
|
|
63
|
+
<p className="text-stone-600 dark:text-stone-400">
|
|
64
|
+
Design each section of your product with specifications, sample data, and screen designs.
|
|
65
|
+
</p>
|
|
66
|
+
{sections.length > 0 && (
|
|
67
|
+
<p className="text-sm text-stone-500 dark:text-stone-400 mt-2">
|
|
68
|
+
{completedSections} of {sections.length} sections completed
|
|
69
|
+
</p>
|
|
70
|
+
)}
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
{/* Warning banner for incomplete prerequisite phases */}
|
|
74
|
+
<PhaseWarningBanner />
|
|
75
|
+
|
|
76
|
+
{/* Sections list */}
|
|
77
|
+
{sections.length === 0 ? (
|
|
78
|
+
<EmptyState type="roadmap" />
|
|
79
|
+
) : (
|
|
80
|
+
<Card className="border-stone-200 dark:border-stone-700 shadow-sm">
|
|
81
|
+
<CardHeader className="pb-2">
|
|
82
|
+
<CardTitle className="text-lg font-semibold text-stone-900 dark:text-stone-100">
|
|
83
|
+
All Sections
|
|
84
|
+
</CardTitle>
|
|
85
|
+
</CardHeader>
|
|
86
|
+
<CardContent className="p-0">
|
|
87
|
+
<ul className="divide-y divide-stone-200 dark:divide-stone-700">
|
|
88
|
+
{sections.map((section) => {
|
|
89
|
+
const progress = sectionProgressMap[section.id]
|
|
90
|
+
const isComplete = progress?.hasSpec && progress?.hasData && progress?.hasScreenDesigns
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<li key={section.id}>
|
|
94
|
+
<button
|
|
95
|
+
onClick={() => navigate(`/sections/${section.id}`)}
|
|
96
|
+
className="w-full px-6 py-4 flex items-center justify-between gap-4 text-left hover:bg-stone-50 dark:hover:bg-stone-800/50 transition-colors"
|
|
97
|
+
>
|
|
98
|
+
<div className="flex items-start gap-4 min-w-0">
|
|
99
|
+
{/* Status indicator */}
|
|
100
|
+
<div className="shrink-0 mt-0.5">
|
|
101
|
+
{isComplete ? (
|
|
102
|
+
<div className="w-6 h-6 rounded-full bg-lime-100 dark:bg-lime-900/30 flex items-center justify-center">
|
|
103
|
+
<Check className="w-3.5 h-3.5 text-lime-600 dark:text-lime-400" strokeWidth={2.5} />
|
|
104
|
+
</div>
|
|
105
|
+
) : (
|
|
106
|
+
<div className="w-6 h-6 rounded-full bg-stone-200 dark:bg-stone-700 flex items-center justify-center">
|
|
107
|
+
<span className="text-xs font-medium text-stone-600 dark:text-stone-400">
|
|
108
|
+
{section.order}
|
|
109
|
+
</span>
|
|
110
|
+
</div>
|
|
111
|
+
)}
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<div className="min-w-0 flex-1">
|
|
115
|
+
<h3 className="font-medium text-stone-900 dark:text-stone-100 truncate">
|
|
116
|
+
{section.title}
|
|
117
|
+
</h3>
|
|
118
|
+
<p className="text-sm text-stone-500 dark:text-stone-400 mt-0.5 line-clamp-1">
|
|
119
|
+
{section.description}
|
|
120
|
+
</p>
|
|
121
|
+
|
|
122
|
+
{/* Progress indicators */}
|
|
123
|
+
<div className="flex items-center gap-3 mt-2">
|
|
124
|
+
<ProgressDot label="Spec" done={progress?.hasSpec} />
|
|
125
|
+
<ProgressDot label="Data" done={progress?.hasData} />
|
|
126
|
+
<ProgressDot
|
|
127
|
+
label={progress?.screenDesignCount ? `${progress.screenDesignCount} screen design${progress.screenDesignCount !== 1 ? 's' : ''}` : 'Screen Designs'}
|
|
128
|
+
done={progress?.hasScreenDesigns}
|
|
129
|
+
/>
|
|
130
|
+
<ProgressDot
|
|
131
|
+
label={progress?.screenshotCount ? `${progress.screenshotCount} screenshot${progress.screenshotCount !== 1 ? 's' : ''}` : 'Screenshots'}
|
|
132
|
+
done={progress?.hasScreenshots}
|
|
133
|
+
optional
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<ChevronRight className="w-4 h-4 text-stone-400 dark:text-stone-500 flex-shrink-0" strokeWidth={1.5} />
|
|
140
|
+
</button>
|
|
141
|
+
</li>
|
|
142
|
+
)
|
|
143
|
+
})}
|
|
144
|
+
</ul>
|
|
145
|
+
</CardContent>
|
|
146
|
+
</Card>
|
|
147
|
+
)}
|
|
148
|
+
|
|
149
|
+
{/* Next Phase Button - shown when all sections are complete */}
|
|
150
|
+
{sections.length > 0 && completedSections === sections.length && (
|
|
151
|
+
<NextPhaseButton nextPhase="export" />
|
|
152
|
+
)}
|
|
153
|
+
</div>
|
|
154
|
+
</AppLayout>
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
interface ProgressDotProps {
|
|
159
|
+
label: string
|
|
160
|
+
done?: boolean
|
|
161
|
+
optional?: boolean
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function ProgressDot({ label, done, optional }: ProgressDotProps) {
|
|
165
|
+
return (
|
|
166
|
+
<span className={`flex items-center gap-1 text-xs ${
|
|
167
|
+
done
|
|
168
|
+
? 'text-stone-700 dark:text-stone-300'
|
|
169
|
+
: optional
|
|
170
|
+
? 'text-stone-300 dark:text-stone-600'
|
|
171
|
+
: 'text-stone-400 dark:text-stone-500'
|
|
172
|
+
}`}>
|
|
173
|
+
{done ? (
|
|
174
|
+
<Check className="w-3 h-3 text-lime-600 dark:text-lime-400" strokeWidth={2.5} />
|
|
175
|
+
) : (
|
|
176
|
+
<Circle className={`w-3 h-3 ${optional ? 'opacity-50' : ''}`} strokeWidth={1.5} />
|
|
177
|
+
)}
|
|
178
|
+
{label}
|
|
179
|
+
</span>
|
|
180
|
+
)
|
|
181
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import { Link } from 'react-router-dom'
|
|
3
|
+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
|
4
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
|
|
5
|
+
import { ChevronDown, ChevronRight, PanelLeft, Layout } from 'lucide-react'
|
|
6
|
+
import type { ShellInfo } from '@/types/product'
|
|
7
|
+
|
|
8
|
+
interface ShellCardProps {
|
|
9
|
+
shell: ShellInfo
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function ShellCard({ shell }: ShellCardProps) {
|
|
13
|
+
const [navigationOpen, setNavigationOpen] = useState(false)
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Card className="border-stone-200 dark:border-stone-700 shadow-sm">
|
|
17
|
+
<CardHeader className="pb-4">
|
|
18
|
+
<CardTitle className="text-lg font-semibold text-stone-900 dark:text-stone-100 flex items-center gap-2">
|
|
19
|
+
<PanelLeft className="w-5 h-5 text-stone-500 dark:text-stone-400" strokeWidth={1.5} />
|
|
20
|
+
Application Shell
|
|
21
|
+
</CardTitle>
|
|
22
|
+
</CardHeader>
|
|
23
|
+
<CardContent className="space-y-4">
|
|
24
|
+
{/* Overview */}
|
|
25
|
+
{shell.spec && shell.spec.overview && (
|
|
26
|
+
<p className="text-stone-600 dark:text-stone-400 leading-relaxed">
|
|
27
|
+
{shell.spec.overview}
|
|
28
|
+
</p>
|
|
29
|
+
)}
|
|
30
|
+
|
|
31
|
+
{/* Navigation - Collapsible */}
|
|
32
|
+
{shell.spec && shell.spec.navigationItems.length > 0 && (
|
|
33
|
+
<Collapsible open={navigationOpen} onOpenChange={setNavigationOpen}>
|
|
34
|
+
<CollapsibleTrigger className="flex items-center justify-between w-full py-2 text-left group">
|
|
35
|
+
<span className="text-sm font-medium text-stone-500 dark:text-stone-400 uppercase tracking-wide">
|
|
36
|
+
Navigation
|
|
37
|
+
<span className="ml-2 text-stone-400 dark:text-stone-500 normal-case tracking-normal">
|
|
38
|
+
({shell.spec.navigationItems.length})
|
|
39
|
+
</span>
|
|
40
|
+
</span>
|
|
41
|
+
<ChevronDown
|
|
42
|
+
className={`w-4 h-4 text-stone-400 dark:text-stone-500 transition-transform ${
|
|
43
|
+
navigationOpen ? 'rotate-180' : ''
|
|
44
|
+
}`}
|
|
45
|
+
strokeWidth={1.5}
|
|
46
|
+
/>
|
|
47
|
+
</CollapsibleTrigger>
|
|
48
|
+
<CollapsibleContent>
|
|
49
|
+
<ul className="space-y-2 pt-2 ml-1">
|
|
50
|
+
{shell.spec.navigationItems.map((item, index) => (
|
|
51
|
+
<li key={index} className="flex items-start gap-3">
|
|
52
|
+
<span className="w-1.5 h-1.5 rounded-full bg-stone-400 dark:bg-stone-500 mt-2 shrink-0" />
|
|
53
|
+
<span className="text-stone-600 dark:text-stone-400">
|
|
54
|
+
{item}
|
|
55
|
+
</span>
|
|
56
|
+
</li>
|
|
57
|
+
))}
|
|
58
|
+
</ul>
|
|
59
|
+
</CollapsibleContent>
|
|
60
|
+
</Collapsible>
|
|
61
|
+
)}
|
|
62
|
+
|
|
63
|
+
{/* View Shell Design Link */}
|
|
64
|
+
{shell.hasComponents && (
|
|
65
|
+
<div className="pt-2 border-t border-stone-100 dark:border-stone-800">
|
|
66
|
+
<Link
|
|
67
|
+
to="/shell/design"
|
|
68
|
+
className="flex items-center justify-between gap-4 py-2 hover:text-stone-900 dark:hover:text-stone-100 transition-colors group"
|
|
69
|
+
>
|
|
70
|
+
<div className="flex items-center gap-3">
|
|
71
|
+
<div className="w-8 h-8 rounded-md bg-stone-200 dark:bg-stone-700 flex items-center justify-center">
|
|
72
|
+
<Layout className="w-4 h-4 text-stone-600 dark:text-stone-300" strokeWidth={1.5} />
|
|
73
|
+
</div>
|
|
74
|
+
<span className="font-medium text-stone-700 dark:text-stone-300 group-hover:text-stone-900 dark:group-hover:text-stone-100">
|
|
75
|
+
View Shell Design
|
|
76
|
+
</span>
|
|
77
|
+
</div>
|
|
78
|
+
<ChevronRight className="w-4 h-4 text-stone-400 dark:text-stone-500" strokeWidth={1.5} />
|
|
79
|
+
</Link>
|
|
80
|
+
</div>
|
|
81
|
+
)}
|
|
82
|
+
</CardContent>
|
|
83
|
+
</Card>
|
|
84
|
+
)
|
|
85
|
+
}
|