mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 13:44:54 +00:00
Generated by Spark: Create seed data templates for different project types (e-commerce, blog, dashboard)
This commit is contained in:
@@ -32,6 +32,7 @@ const componentMap: Record<string, React.LazyExoticComponent<any>> = {
|
||||
PWASettings: lazy(() => import('@/components/PWASettings').then(m => ({ default: m.PWASettings }))),
|
||||
FaviconDesigner: lazy(() => import('@/components/FaviconDesigner').then(m => ({ default: m.FaviconDesigner }))),
|
||||
FeatureIdeaCloud: lazy(() => import('@/components/FeatureIdeaCloud').then(m => ({ default: m.FeatureIdeaCloud }))),
|
||||
TemplateSelector: lazy(() => import('@/components/TemplateSelector').then(m => ({ default: m.TemplateSelector }))),
|
||||
}
|
||||
|
||||
const GlobalSearch = lazy(() => import('@/components/GlobalSearch').then(m => ({ default: m.GlobalSearch })))
|
||||
|
||||
198
src/components/TemplateExplorer.tsx
Normal file
198
src/components/TemplateExplorer.tsx
Normal file
@@ -0,0 +1,198 @@
|
||||
import { useState } from 'react'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { useSeedTemplates } from '@/hooks/data/use-seed-templates'
|
||||
import { Copy, Download } from '@phosphor-icons/react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
export function TemplateExplorer() {
|
||||
const { templates } = useSeedTemplates()
|
||||
const [selectedTemplate, setSelectedTemplate] = useState(templates[0]?.id || 'default')
|
||||
|
||||
const currentTemplate = templates.find(t => t.id === selectedTemplate)
|
||||
|
||||
const copyToClipboard = (text: string) => {
|
||||
navigator.clipboard.writeText(text)
|
||||
toast.success('Copied to clipboard')
|
||||
}
|
||||
|
||||
const downloadJSON = () => {
|
||||
if (!currentTemplate) return
|
||||
|
||||
const dataStr = JSON.stringify(currentTemplate.data, null, 2)
|
||||
const blob = new Blob([dataStr], { type: 'application/json' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = `${currentTemplate.id}-template.json`
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
URL.revokeObjectURL(url)
|
||||
|
||||
toast.success('Template downloaded')
|
||||
}
|
||||
|
||||
const exportCurrentData = async () => {
|
||||
const keys = await window.spark.kv.keys()
|
||||
const data: Record<string, any> = {}
|
||||
|
||||
for (const key of keys) {
|
||||
data[key] = await window.spark.kv.get(key)
|
||||
}
|
||||
|
||||
const dataStr = JSON.stringify(data, null, 2)
|
||||
const blob = new Blob([dataStr], { type: 'application/json' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = 'current-project-data.json'
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
URL.revokeObjectURL(url)
|
||||
|
||||
toast.success('Current project data exported')
|
||||
}
|
||||
|
||||
if (!currentTemplate) return null
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold mb-2">Template Explorer</h2>
|
||||
<p className="text-muted-foreground">
|
||||
Browse and inspect template structures
|
||||
</p>
|
||||
</div>
|
||||
<Button onClick={exportCurrentData} variant="outline">
|
||||
<Download className="mr-2" size={16} />
|
||||
Export Current Data
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
<div className="space-y-2">
|
||||
{templates.map((template) => (
|
||||
<Card
|
||||
key={template.id}
|
||||
className={`cursor-pointer transition-colors ${
|
||||
selectedTemplate === template.id ? 'border-primary bg-accent/50' : 'hover:bg-accent/20'
|
||||
}`}
|
||||
onClick={() => setSelectedTemplate(template.id)}
|
||||
>
|
||||
<CardHeader className="p-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-2xl">{template.icon}</span>
|
||||
<CardTitle className="text-sm">{template.name}</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Card className="col-span-3">
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-4xl">{currentTemplate.icon}</span>
|
||||
<div>
|
||||
<CardTitle>{currentTemplate.name}</CardTitle>
|
||||
<CardDescription>{currentTemplate.description}</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
<Button onClick={downloadJSON} variant="outline" size="sm">
|
||||
<Download className="mr-2" size={16} />
|
||||
Download
|
||||
</Button>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Tabs defaultValue="overview">
|
||||
<TabsList className="grid w-full grid-cols-3">
|
||||
<TabsTrigger value="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger value="structure">Structure</TabsTrigger>
|
||||
<TabsTrigger value="json">JSON</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="overview" className="space-y-4">
|
||||
<div>
|
||||
<h3 className="font-semibold mb-2">Features</h3>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{currentTemplate.features.map((feature, idx) => (
|
||||
<Badge key={idx} variant="secondary">
|
||||
{feature}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{Object.entries(currentTemplate.data).map(([key, value]) => (
|
||||
<Card key={key}>
|
||||
<CardHeader className="p-4">
|
||||
<CardTitle className="text-sm">{key.replace('project-', '')}</CardTitle>
|
||||
<CardDescription>
|
||||
{Array.isArray(value) ? `${value.length} items` : 'Configuration'}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="structure" className="space-y-4">
|
||||
<ScrollArea className="h-[500px]">
|
||||
{Object.entries(currentTemplate.data).map(([key, value]) => (
|
||||
<div key={key} className="mb-4 p-4 border rounded-lg">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h3 className="font-semibold">{key}</h3>
|
||||
<Badge variant="outline">
|
||||
{Array.isArray(value) ? `${value.length} items` : 'object'}
|
||||
</Badge>
|
||||
</div>
|
||||
{Array.isArray(value) && value.length > 0 && (
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{value.slice(0, 3).map((item: any, idx: number) => (
|
||||
<div key={idx} className="py-1">
|
||||
• {item.name || item.title || item.id}
|
||||
</div>
|
||||
))}
|
||||
{value.length > 3 && (
|
||||
<div className="py-1 italic">... and {value.length - 3} more</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</ScrollArea>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="json">
|
||||
<div className="relative">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="absolute right-2 top-2 z-10"
|
||||
onClick={() => copyToClipboard(JSON.stringify(currentTemplate.data, null, 2))}
|
||||
>
|
||||
<Copy size={16} />
|
||||
</Button>
|
||||
<ScrollArea className="h-[500px]">
|
||||
<pre className="text-xs p-4 bg-muted rounded-lg">
|
||||
{JSON.stringify(currentTemplate.data, null, 2)}
|
||||
</pre>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
173
src/components/TemplateSelector.tsx
Normal file
173
src/components/TemplateSelector.tsx
Normal file
@@ -0,0 +1,173 @@
|
||||
import { useState } from 'react'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { useSeedTemplates, type TemplateType } from '@/hooks/data/use-seed-templates'
|
||||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert'
|
||||
import { TemplateExplorer } from './TemplateExplorer'
|
||||
import { toast } from 'sonner'
|
||||
import { Download, Package, Plus, Trash } from '@phosphor-icons/react'
|
||||
|
||||
export function TemplateSelector() {
|
||||
const { templates, isLoading, clearAndLoadTemplate, mergeTemplate } = useSeedTemplates()
|
||||
const [selectedTemplate, setSelectedTemplate] = useState<TemplateType | null>(null)
|
||||
const [showConfirmDialog, setShowConfirmDialog] = useState(false)
|
||||
const [actionType, setActionType] = useState<'replace' | 'merge'>('replace')
|
||||
|
||||
const handleSelectTemplate = (templateId: TemplateType, action: 'replace' | 'merge') => {
|
||||
setSelectedTemplate(templateId)
|
||||
setActionType(action)
|
||||
setShowConfirmDialog(true)
|
||||
}
|
||||
|
||||
const handleConfirmLoad = async () => {
|
||||
if (!selectedTemplate) return
|
||||
|
||||
setShowConfirmDialog(false)
|
||||
|
||||
const success = actionType === 'replace'
|
||||
? await clearAndLoadTemplate(selectedTemplate)
|
||||
: await mergeTemplate(selectedTemplate)
|
||||
|
||||
if (success) {
|
||||
toast.success(`Template loaded successfully!`, {
|
||||
description: `${actionType === 'replace' ? 'Replaced' : 'Merged'} with ${selectedTemplate} template`
|
||||
})
|
||||
window.location.reload()
|
||||
} else {
|
||||
toast.error('Failed to load template', {
|
||||
description: 'Please try again or check the console for errors'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tabs defaultValue="templates" className="w-full">
|
||||
<TabsList>
|
||||
<TabsTrigger value="templates">Load Templates</TabsTrigger>
|
||||
<TabsTrigger value="explorer">Explore Templates</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="templates" className="space-y-6 mt-6">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold mb-2">Project Templates</h2>
|
||||
<p className="text-muted-foreground">
|
||||
Start your project with pre-configured templates including models, components, and workflows
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{templates.map((template) => (
|
||||
<Card key={template.id} className="relative overflow-hidden hover:shadow-lg transition-shadow">
|
||||
<CardHeader>
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-4xl">{template.icon}</span>
|
||||
<div>
|
||||
<CardTitle className="text-xl">{template.name}</CardTitle>
|
||||
<CardDescription className="mt-1">
|
||||
{template.description}
|
||||
</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{template.features.map((feature, idx) => (
|
||||
<Badge key={idx} variant="secondary" className="text-xs">
|
||||
{feature}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="default"
|
||||
size="sm"
|
||||
onClick={() => handleSelectTemplate(template.id, 'replace')}
|
||||
disabled={isLoading}
|
||||
className="flex-1"
|
||||
>
|
||||
<Download className="mr-2" size={16} />
|
||||
Load Template
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => handleSelectTemplate(template.id, 'merge')}
|
||||
disabled={isLoading}
|
||||
className="flex-1"
|
||||
>
|
||||
<Plus className="mr-2" size={16} />
|
||||
Merge
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Alert>
|
||||
<Package size={16} />
|
||||
<AlertDescription>
|
||||
<strong>Load Template:</strong> Replaces all existing data with the selected template.
|
||||
<br />
|
||||
<strong>Merge:</strong> Adds template data to your existing project without removing current data.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="explorer" className="mt-6">
|
||||
<TemplateExplorer />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
<Dialog open={showConfirmDialog} onOpenChange={setShowConfirmDialog}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{actionType === 'replace' ? 'Replace Project Data?' : 'Merge Template Data?'}
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
{actionType === 'replace' ? (
|
||||
<>
|
||||
This will <strong className="text-destructive">delete all existing data</strong> and load the{' '}
|
||||
<strong>{selectedTemplate}</strong> template. This action cannot be undone.
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
This will <strong>add</strong> the <strong>{selectedTemplate}</strong> template data to your
|
||||
existing project without removing current data.
|
||||
</>
|
||||
)}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setShowConfirmDialog(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant={actionType === 'replace' ? 'destructive' : 'default'}
|
||||
onClick={handleConfirmLoad}
|
||||
>
|
||||
{actionType === 'replace' ? (
|
||||
<>
|
||||
<Trash className="mr-2" size={16} />
|
||||
Replace All Data
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Plus className="mr-2" size={16} />
|
||||
Merge Data
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
export * from './atoms'
|
||||
export * from './molecules'
|
||||
export * from './organisms'
|
||||
export * from './TemplateSelector'
|
||||
export * from './TemplateExplorer'
|
||||
|
||||
@@ -253,13 +253,22 @@
|
||||
"order": 19,
|
||||
"props": {}
|
||||
},
|
||||
{
|
||||
"id": "templates",
|
||||
"title": "Templates",
|
||||
"icon": "Package",
|
||||
"component": "TemplateSelector",
|
||||
"enabled": true,
|
||||
"order": 20,
|
||||
"props": {}
|
||||
},
|
||||
{
|
||||
"id": "features",
|
||||
"title": "Features",
|
||||
"icon": "ToggleRight",
|
||||
"component": "FeatureToggleSettings",
|
||||
"enabled": true,
|
||||
"order": 20,
|
||||
"order": 21,
|
||||
"props": {
|
||||
"state": ["features:featureToggles"],
|
||||
"actions": ["onFeaturesChange:setFeatureToggles"]
|
||||
|
||||
262
src/config/seed-templates/README.md
Normal file
262
src/config/seed-templates/README.md
Normal file
@@ -0,0 +1,262 @@
|
||||
# Seed Data Templates
|
||||
|
||||
This directory contains pre-configured project templates that provide complete starting points for different application types.
|
||||
|
||||
## Available Templates
|
||||
|
||||
### 🚀 Default Project
|
||||
**File:** `../seed-data.json`
|
||||
|
||||
Basic starter template with common components and models for general-purpose applications.
|
||||
|
||||
**Features:**
|
||||
- Basic User and Post models
|
||||
- Simple file structure
|
||||
- User registration workflow
|
||||
- Foundation components (Button, Card)
|
||||
- Sample tests and stories
|
||||
|
||||
**Best for:** Learning, prototyping, or building custom applications from scratch
|
||||
|
||||
---
|
||||
|
||||
### 🛍️ E-Commerce Store
|
||||
**File:** `e-commerce.json`
|
||||
|
||||
Complete online store setup with product catalog, shopping cart, and order management.
|
||||
|
||||
**Features:**
|
||||
- **Models:**
|
||||
- Product (with variants, pricing, inventory)
|
||||
- Category (hierarchical)
|
||||
- Order & OrderItem
|
||||
- Customer (with addresses)
|
||||
|
||||
- **Components:**
|
||||
- ProductCard
|
||||
- CartItem
|
||||
- CheckoutSummary
|
||||
|
||||
- **Workflows:**
|
||||
- Order processing (payment → inventory → notifications)
|
||||
|
||||
- **Lambda Functions:**
|
||||
- calculateShipping
|
||||
- processRefund
|
||||
|
||||
- **Pages:**
|
||||
- Product listing with Hero
|
||||
- Shopping cart
|
||||
- Checkout flow
|
||||
|
||||
**Best for:** Online stores, marketplaces, retail platforms
|
||||
|
||||
---
|
||||
|
||||
### 📝 Blog Platform
|
||||
**File:** `blog.json`
|
||||
|
||||
Content-focused blogging platform with author management, comments, and newsletter.
|
||||
|
||||
**Features:**
|
||||
- **Models:**
|
||||
- Post (with SEO fields, read time, tags)
|
||||
- Author (with bio, social links)
|
||||
- Category
|
||||
- Comment (with threading support)
|
||||
- Newsletter subscribers
|
||||
|
||||
- **Components:**
|
||||
- PostCard (with metadata)
|
||||
- AuthorCard
|
||||
- CommentSection
|
||||
|
||||
- **Workflows:**
|
||||
- Post publishing (draft → SEO → review → publish → notify)
|
||||
|
||||
- **Lambda Functions:**
|
||||
- generateSEO (auto-generate meta tags)
|
||||
- sendNewsletter
|
||||
|
||||
- **Pages:**
|
||||
- Blog grid with featured post
|
||||
- Individual post view
|
||||
- Author profile pages
|
||||
|
||||
**Best for:** Blogs, magazines, content sites, news platforms
|
||||
|
||||
---
|
||||
|
||||
### 📊 Analytics Dashboard
|
||||
**File:** `dashboard.json`
|
||||
|
||||
Data visualization dashboard with real-time metrics, user management, and reporting.
|
||||
|
||||
**Features:**
|
||||
- **Models:**
|
||||
- Metric (time-series data with trends)
|
||||
- User (roles, status, activity tracking)
|
||||
- Activity (audit logging)
|
||||
- Report (generated reports with filters)
|
||||
- Alert (notification system)
|
||||
|
||||
- **Components:**
|
||||
- StatCard (with trends and sparklines)
|
||||
- DataTable (sortable, filterable, exportable)
|
||||
- ChartCard (multiple chart types)
|
||||
|
||||
- **Workflows:**
|
||||
- Alert processing (threshold → severity check → notifications)
|
||||
|
||||
- **Lambda Functions:**
|
||||
- aggregateMetrics (scheduled hourly)
|
||||
- generateReport (on-demand)
|
||||
|
||||
- **Pages:**
|
||||
- Main dashboard with stats and charts
|
||||
- Analytics page with date range picker
|
||||
- User management with filters
|
||||
|
||||
**Best for:** Admin panels, analytics platforms, SaaS dashboards, monitoring tools
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
### Using the Template Selector UI
|
||||
|
||||
1. Navigate to the **Templates** tab in the application
|
||||
2. Browse available templates
|
||||
3. Choose an action:
|
||||
- **Load Template**: Replaces all existing data (⚠️ destructive)
|
||||
- **Merge**: Adds template data to existing project
|
||||
|
||||
### Programmatic Usage
|
||||
|
||||
```typescript
|
||||
import { useSeedTemplates } from '@/hooks/data/use-seed-templates'
|
||||
|
||||
function MyComponent() {
|
||||
const { templates, loadTemplate, clearAndLoadTemplate, mergeTemplate } = useSeedTemplates()
|
||||
|
||||
// Load template (preserves existing data)
|
||||
await loadTemplate('e-commerce')
|
||||
|
||||
// Replace all data with template
|
||||
await clearAndLoadTemplate('blog')
|
||||
|
||||
// Merge template with existing data
|
||||
await mergeTemplate('dashboard')
|
||||
}
|
||||
```
|
||||
|
||||
### Manual Loading
|
||||
|
||||
```typescript
|
||||
import ecommerceTemplate from '@/config/seed-templates/e-commerce.json'
|
||||
|
||||
// Load each data type
|
||||
for (const [key, value] of Object.entries(ecommerceTemplate)) {
|
||||
await window.spark.kv.set(key, value)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Template Structure
|
||||
|
||||
Each template is a JSON file with the following keys:
|
||||
|
||||
```json
|
||||
{
|
||||
"project-files": [], // TypeScript/React files
|
||||
"project-models": [], // Data models (Prisma-style)
|
||||
"project-components": [], // UI component definitions
|
||||
"project-component-trees": [], // Component hierarchies
|
||||
"project-workflows": [], // Visual workflow definitions
|
||||
"project-lambdas": [], // Serverless functions
|
||||
"project-playwright-tests": [],// E2E tests
|
||||
"project-storybook-stories": [],// Component stories
|
||||
"project-unit-tests": [] // Unit test definitions
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Creating Custom Templates
|
||||
|
||||
1. **Export current project data:**
|
||||
```typescript
|
||||
const keys = await window.spark.kv.keys()
|
||||
const data = {}
|
||||
for (const key of keys) {
|
||||
data[key] = await window.spark.kv.get(key)
|
||||
}
|
||||
console.log(JSON.stringify(data, null, 2))
|
||||
```
|
||||
|
||||
2. **Create a new JSON file** in this directory
|
||||
|
||||
3. **Add to the templates list** in `use-seed-templates.ts`:
|
||||
```typescript
|
||||
import myTemplate from '@/config/seed-templates/my-template.json'
|
||||
|
||||
const templates: Template[] = [
|
||||
// ...existing templates
|
||||
{
|
||||
id: 'my-template',
|
||||
name: 'My Custom Template',
|
||||
description: 'Description here',
|
||||
icon: '🎨',
|
||||
data: myTemplate,
|
||||
features: ['Feature 1', 'Feature 2']
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### When to Load vs Merge
|
||||
|
||||
- **Load (Replace):** Starting a new project, switching project types, or resetting to a clean state
|
||||
- **Merge:** Adding features from another template, combining template elements, or expanding functionality
|
||||
|
||||
### ID Conventions
|
||||
|
||||
Use prefixed IDs to avoid conflicts:
|
||||
- `file-ecom-1`, `file-blog-1`, `file-dash-1`
|
||||
- `model-ecom-1`, `model-blog-1`, `model-dash-1`
|
||||
- `comp-ecom-1`, `comp-blog-1`, `comp-dash-1`
|
||||
|
||||
### Real-World Data
|
||||
|
||||
Templates include realistic:
|
||||
- Model field definitions
|
||||
- Component configurations
|
||||
- Workflow logic
|
||||
- Function implementations
|
||||
|
||||
This allows immediate testing and provides clear examples for customization.
|
||||
|
||||
---
|
||||
|
||||
## Template Maintenance
|
||||
|
||||
When updating templates:
|
||||
|
||||
1. **Validate JSON** structure matches expected schema
|
||||
2. **Test loading** in a fresh project
|
||||
3. **Verify IDs** are unique within the template
|
||||
4. **Check relationships** between models reference valid relations
|
||||
5. **Update documentation** when adding new features
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
For questions or issues with templates:
|
||||
- Check the main project documentation
|
||||
- Review existing template structures
|
||||
- Test in development before production use
|
||||
672
src/config/seed-templates/blog.json
Normal file
672
src/config/seed-templates/blog.json
Normal file
@@ -0,0 +1,672 @@
|
||||
{
|
||||
"project-files": [
|
||||
{
|
||||
"id": "file-blog-1",
|
||||
"name": "page.tsx",
|
||||
"path": "/src/app/page.tsx",
|
||||
"content": "'use client'\n\nimport { BlogGrid } from '@/components/BlogGrid'\nimport { FeaturedPost } from '@/components/FeaturedPost'\nimport { Container, Box } from '@mui/material'\n\nexport default function Home() {\n return (\n <Box>\n <Container maxWidth=\"lg\" sx={{ py: 6 }}>\n <FeaturedPost />\n <BlogGrid />\n </Container>\n </Box>\n )\n}",
|
||||
"language": "typescript"
|
||||
},
|
||||
{
|
||||
"id": "file-blog-2",
|
||||
"name": "post.tsx",
|
||||
"path": "/src/app/post/[slug]/page.tsx",
|
||||
"content": "'use client'\n\nimport { PostContent } from '@/components/PostContent'\nimport { PostMeta } from '@/components/PostMeta'\nimport { RelatedPosts } from '@/components/RelatedPosts'\nimport { Container, Box } from '@mui/material'\n\nexport default function PostPage({ params }: { params: { slug: string } }) {\n return (\n <Container maxWidth=\"md\" sx={{ py: 6 }}>\n <PostMeta />\n <PostContent />\n <Box sx={{ mt: 8 }}>\n <RelatedPosts />\n </Box>\n </Container>\n )\n}",
|
||||
"language": "typescript"
|
||||
},
|
||||
{
|
||||
"id": "file-blog-3",
|
||||
"name": "author.tsx",
|
||||
"path": "/src/app/author/[id]/page.tsx",
|
||||
"content": "'use client'\n\nimport { AuthorProfile } from '@/components/AuthorProfile'\nimport { AuthorPosts } from '@/components/AuthorPosts'\nimport { Container } from '@mui/material'\n\nexport default function AuthorPage({ params }: { params: { id: string } }) {\n return (\n <Container maxWidth=\"lg\" sx={{ py: 6 }}>\n <AuthorProfile authorId={params.id} />\n <AuthorPosts authorId={params.id} />\n </Container>\n )\n}",
|
||||
"language": "typescript"
|
||||
}
|
||||
],
|
||||
"project-models": [
|
||||
{
|
||||
"id": "model-blog-1",
|
||||
"name": "Post",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-blog-1",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-blog-2",
|
||||
"name": "title",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-3",
|
||||
"name": "slug",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-4",
|
||||
"name": "excerpt",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-5",
|
||||
"name": "content",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-6",
|
||||
"name": "featuredImage",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-7",
|
||||
"name": "published",
|
||||
"type": "Boolean",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "false"
|
||||
},
|
||||
{
|
||||
"id": "field-blog-8",
|
||||
"name": "authorId",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"relation": "Author"
|
||||
},
|
||||
{
|
||||
"id": "field-blog-9",
|
||||
"name": "categoryId",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"relation": "Category"
|
||||
},
|
||||
{
|
||||
"id": "field-blog-10",
|
||||
"name": "tags",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": true
|
||||
},
|
||||
{
|
||||
"id": "field-blog-11",
|
||||
"name": "viewCount",
|
||||
"type": "Int",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "0"
|
||||
},
|
||||
{
|
||||
"id": "field-blog-12",
|
||||
"name": "readTime",
|
||||
"type": "Int",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-13",
|
||||
"name": "publishedAt",
|
||||
"type": "DateTime",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-14",
|
||||
"name": "createdAt",
|
||||
"type": "DateTime",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "now()"
|
||||
},
|
||||
{
|
||||
"id": "field-blog-15",
|
||||
"name": "updatedAt",
|
||||
"type": "DateTime",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "now()"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "model-blog-2",
|
||||
"name": "Author",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-blog-16",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-blog-17",
|
||||
"name": "name",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-18",
|
||||
"name": "email",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-19",
|
||||
"name": "bio",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-20",
|
||||
"name": "avatar",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-21",
|
||||
"name": "website",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-22",
|
||||
"name": "social",
|
||||
"type": "Json",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-23",
|
||||
"name": "createdAt",
|
||||
"type": "DateTime",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "now()"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "model-blog-3",
|
||||
"name": "Category",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-blog-24",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-blog-25",
|
||||
"name": "name",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-26",
|
||||
"name": "slug",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-27",
|
||||
"name": "description",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-28",
|
||||
"name": "color",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "model-blog-4",
|
||||
"name": "Comment",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-blog-29",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-blog-30",
|
||||
"name": "postId",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"relation": "Post"
|
||||
},
|
||||
{
|
||||
"id": "field-blog-31",
|
||||
"name": "authorName",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-32",
|
||||
"name": "authorEmail",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-33",
|
||||
"name": "content",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-34",
|
||||
"name": "approved",
|
||||
"type": "Boolean",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "false"
|
||||
},
|
||||
{
|
||||
"id": "field-blog-35",
|
||||
"name": "parentId",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"relation": "Comment"
|
||||
},
|
||||
{
|
||||
"id": "field-blog-36",
|
||||
"name": "createdAt",
|
||||
"type": "DateTime",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "now()"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "model-blog-5",
|
||||
"name": "Newsletter",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-blog-37",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-blog-38",
|
||||
"name": "email",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-39",
|
||||
"name": "name",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-blog-40",
|
||||
"name": "subscribed",
|
||||
"type": "Boolean",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "true"
|
||||
},
|
||||
{
|
||||
"id": "field-blog-41",
|
||||
"name": "subscribedAt",
|
||||
"type": "DateTime",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "now()"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"project-components": [
|
||||
{
|
||||
"id": "comp-blog-1",
|
||||
"type": "PostCard",
|
||||
"name": "PostCard",
|
||||
"props": {
|
||||
"showExcerpt": true,
|
||||
"showAuthor": true,
|
||||
"showDate": true,
|
||||
"showReadTime": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "comp-blog-2",
|
||||
"type": "AuthorCard",
|
||||
"name": "AuthorCard",
|
||||
"props": {
|
||||
"showBio": true,
|
||||
"showSocialLinks": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "comp-blog-3",
|
||||
"type": "CommentSection",
|
||||
"name": "CommentSection",
|
||||
"props": {
|
||||
"allowReplies": true,
|
||||
"requireModeration": true
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
],
|
||||
"project-workflows": [
|
||||
{
|
||||
"id": "workflow-blog-1",
|
||||
"name": "Post Publishing Workflow",
|
||||
"description": "Content review and publishing workflow",
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-blog-1",
|
||||
"type": "trigger",
|
||||
"name": "Draft Created",
|
||||
"position": { "x": 100, "y": 100 },
|
||||
"data": { "label": "Author Creates Draft" },
|
||||
"config": { "triggerType": "event" }
|
||||
},
|
||||
{
|
||||
"id": "node-blog-2",
|
||||
"type": "action",
|
||||
"name": "Generate SEO",
|
||||
"position": { "x": 300, "y": 100 },
|
||||
"data": { "label": "Auto-generate meta tags" }
|
||||
},
|
||||
{
|
||||
"id": "node-blog-3",
|
||||
"type": "action",
|
||||
"name": "Calculate Read Time",
|
||||
"position": { "x": 500, "y": 100 },
|
||||
"data": { "label": "Estimate reading time" }
|
||||
},
|
||||
{
|
||||
"id": "node-blog-4",
|
||||
"type": "notification",
|
||||
"name": "Notify Editor",
|
||||
"position": { "x": 700, "y": 100 },
|
||||
"data": { "label": "Send review request" }
|
||||
},
|
||||
{
|
||||
"id": "node-blog-5",
|
||||
"type": "condition",
|
||||
"name": "Approved?",
|
||||
"position": { "x": 900, "y": 100 },
|
||||
"data": { "label": "Editor review" }
|
||||
},
|
||||
{
|
||||
"id": "node-blog-6",
|
||||
"type": "action",
|
||||
"name": "Publish",
|
||||
"position": { "x": 1100, "y": 50 },
|
||||
"data": { "label": "Make post live" }
|
||||
},
|
||||
{
|
||||
"id": "node-blog-7",
|
||||
"type": "notification",
|
||||
"name": "Send to Subscribers",
|
||||
"position": { "x": 1300, "y": 50 },
|
||||
"data": { "label": "Email newsletter" }
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{ "id": "conn-blog-1", "source": "node-blog-1", "target": "node-blog-2" },
|
||||
{ "id": "conn-blog-2", "source": "node-blog-2", "target": "node-blog-3" },
|
||||
{ "id": "conn-blog-3", "source": "node-blog-3", "target": "node-blog-4" },
|
||||
{ "id": "conn-blog-4", "source": "node-blog-4", "target": "node-blog-5" },
|
||||
{ "id": "conn-blog-5", "source": "node-blog-5", "target": "node-blog-6", "condition": "approved" },
|
||||
{ "id": "conn-blog-6", "source": "node-blog-6", "target": "node-blog-7" }
|
||||
],
|
||||
"isActive": true,
|
||||
"createdAt": 1704067200000,
|
||||
"updatedAt": 1704067200000
|
||||
}
|
||||
],
|
||||
"project-lambdas": [
|
||||
{
|
||||
"id": "lambda-blog-1",
|
||||
"name": "generateSEO",
|
||||
"description": "Auto-generate SEO metadata for blog posts",
|
||||
"code": "export async function handler(event) {\n const { title, content, excerpt } = event;\n const keywords = extractKeywords(content);\n const description = excerpt || content.substring(0, 160);\n return {\n statusCode: 200,\n body: JSON.stringify({\n meta: {\n title: `${title} | My Blog`,\n description,\n keywords\n }\n })\n };\n}",
|
||||
"language": "typescript",
|
||||
"runtime": "nodejs20.x",
|
||||
"handler": "index.handler",
|
||||
"timeout": 10,
|
||||
"memory": 256,
|
||||
"environment": {},
|
||||
"triggers": [
|
||||
{
|
||||
"id": "trigger-blog-1",
|
||||
"type": "http",
|
||||
"config": { "method": "POST", "path": "/api/seo" }
|
||||
}
|
||||
],
|
||||
"createdAt": 1704067200000,
|
||||
"updatedAt": 1704067200000
|
||||
},
|
||||
{
|
||||
"id": "lambda-blog-2",
|
||||
"name": "sendNewsletter",
|
||||
"description": "Send email to newsletter subscribers",
|
||||
"code": "export async function handler(event) {\n const { postId, title, excerpt } = event;\n // Send newsletter emails\n return {\n statusCode: 200,\n body: JSON.stringify({ sent: true })\n };\n}",
|
||||
"language": "typescript",
|
||||
"runtime": "nodejs20.x",
|
||||
"handler": "index.handler",
|
||||
"timeout": 60,
|
||||
"memory": 512,
|
||||
"environment": {},
|
||||
"triggers": [
|
||||
{
|
||||
"id": "trigger-blog-2",
|
||||
"type": "event",
|
||||
"config": { "event": "post.published" }
|
||||
}
|
||||
],
|
||||
"createdAt": 1704067200000,
|
||||
"updatedAt": 1704067200000
|
||||
}
|
||||
],
|
||||
"project-playwright-tests": [
|
||||
{
|
||||
"id": "test-blog-1",
|
||||
"name": "Read and Comment Flow",
|
||||
"description": "Test reading a post and leaving a comment",
|
||||
"pageUrl": "/",
|
||||
"steps": [
|
||||
{ "id": "step-blog-1", "action": "navigate", "value": "/" },
|
||||
{ "id": "step-blog-2", "action": "click", "selector": ".post-card:first-child" },
|
||||
{ "id": "step-blog-3", "action": "expect", "selector": ".post-content", "assertion": "toBeVisible" },
|
||||
{ "id": "step-blog-4", "action": "scroll", "selector": ".comment-section" },
|
||||
{ "id": "step-blog-5", "action": "fill", "selector": "#comment-name", "value": "John Doe" },
|
||||
{ "id": "step-blog-6", "action": "fill", "selector": "#comment-email", "value": "john@example.com" },
|
||||
{ "id": "step-blog-7", "action": "fill", "selector": "#comment-text", "value": "Great article!" },
|
||||
{ "id": "step-blog-8", "action": "click", "selector": "button[data-testid='submit-comment']" },
|
||||
{ "id": "step-blog-9", "action": "expect", "selector": ".comment-success", "assertion": "toBeVisible" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"project-storybook-stories": [
|
||||
{
|
||||
"id": "story-blog-1",
|
||||
"componentName": "PostCard",
|
||||
"storyName": "Default",
|
||||
"args": {
|
||||
"title": "Getting Started with React",
|
||||
"excerpt": "Learn the basics of React development",
|
||||
"author": "Jane Smith",
|
||||
"date": "2024-01-15",
|
||||
"readTime": 5,
|
||||
"image": "/images/post.jpg"
|
||||
},
|
||||
"description": "Blog post card component",
|
||||
"category": "Blog"
|
||||
},
|
||||
{
|
||||
"id": "story-blog-2",
|
||||
"componentName": "AuthorCard",
|
||||
"storyName": "WithSocial",
|
||||
"args": {
|
||||
"name": "Jane Smith",
|
||||
"bio": "Tech writer and developer",
|
||||
"avatar": "/images/author.jpg",
|
||||
"social": {
|
||||
"twitter": "@janesmith",
|
||||
"github": "janesmith"
|
||||
}
|
||||
},
|
||||
"description": "Author profile card",
|
||||
"category": "Blog"
|
||||
}
|
||||
],
|
||||
"project-unit-tests": [
|
||||
{
|
||||
"id": "test-blog-unit-1",
|
||||
"name": "Post Utilities",
|
||||
"description": "Test post formatting and utilities",
|
||||
"testType": "utility",
|
||||
"targetFile": "/src/utils/post.ts",
|
||||
"testCases": [
|
||||
{
|
||||
"id": "case-blog-1",
|
||||
"description": "calculates read time correctly",
|
||||
"assertions": ["expect(calculateReadTime(content)).toBe(5)"]
|
||||
},
|
||||
{
|
||||
"id": "case-blog-2",
|
||||
"description": "generates slug from title",
|
||||
"assertions": ["expect(slugify('Hello World')).toBe('hello-world')"]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"project-component-trees": [
|
||||
{
|
||||
"id": "tree-blog-1",
|
||||
"name": "Blog Layout",
|
||||
"description": "Main blog layout with sidebar",
|
||||
"rootNodes": [
|
||||
{
|
||||
"id": "root-blog-1",
|
||||
"type": "Container",
|
||||
"name": "BlogContainer",
|
||||
"props": { "maxWidth": "lg" },
|
||||
"children": [
|
||||
{
|
||||
"id": "header-blog-1",
|
||||
"type": "Box",
|
||||
"name": "BlogHeader",
|
||||
"props": { "sx": { "py": 4, "borderBottom": 1 } },
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "main-blog-1",
|
||||
"type": "Grid",
|
||||
"name": "MainGrid",
|
||||
"props": { "container": true, "spacing": 4 },
|
||||
"children": [
|
||||
{
|
||||
"id": "content-blog-1",
|
||||
"type": "Grid",
|
||||
"name": "ContentColumn",
|
||||
"props": { "item": true, "xs": 12, "md": 8 },
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "sidebar-blog-1",
|
||||
"type": "Grid",
|
||||
"name": "Sidebar",
|
||||
"props": { "item": true, "xs": 12, "md": 4 },
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"createdAt": 1704067200000,
|
||||
"updatedAt": 1704067200000
|
||||
}
|
||||
]
|
||||
}
|
||||
617
src/config/seed-templates/dashboard.json
Normal file
617
src/config/seed-templates/dashboard.json
Normal file
@@ -0,0 +1,617 @@
|
||||
{
|
||||
"project-files": [
|
||||
{
|
||||
"id": "file-dash-1",
|
||||
"name": "page.tsx",
|
||||
"path": "/src/app/page.tsx",
|
||||
"content": "'use client'\n\nimport { DashboardStats } from '@/components/DashboardStats'\nimport { RecentActivity } from '@/components/RecentActivity'\nimport { AnalyticsCharts } from '@/components/AnalyticsCharts'\nimport { Grid, Container, Box } from '@mui/material'\n\nexport default function Dashboard() {\n return (\n <Container maxWidth=\"xl\" sx={{ py: 4 }}>\n <Grid container spacing={3}>\n <Grid item xs={12}>\n <DashboardStats />\n </Grid>\n <Grid item xs={12} lg={8}>\n <AnalyticsCharts />\n </Grid>\n <Grid item xs={12} lg={4}>\n <RecentActivity />\n </Grid>\n </Grid>\n </Container>\n )\n}",
|
||||
"language": "typescript"
|
||||
},
|
||||
{
|
||||
"id": "file-dash-2",
|
||||
"name": "analytics.tsx",
|
||||
"path": "/src/app/analytics/page.tsx",
|
||||
"content": "'use client'\n\nimport { AnalyticsDashboard } from '@/components/AnalyticsDashboard'\nimport { DateRangePicker } from '@/components/DateRangePicker'\nimport { Container, Box, Typography } from '@mui/material'\n\nexport default function AnalyticsPage() {\n return (\n <Container maxWidth=\"xl\" sx={{ py: 4 }}>\n <Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 4 }}>\n <Typography variant=\"h4\">Analytics</Typography>\n <DateRangePicker />\n </Box>\n <AnalyticsDashboard />\n </Container>\n )\n}",
|
||||
"language": "typescript"
|
||||
},
|
||||
{
|
||||
"id": "file-dash-3",
|
||||
"name": "users.tsx",
|
||||
"path": "/src/app/users/page.tsx",
|
||||
"content": "'use client'\n\nimport { UserTable } from '@/components/UserTable'\nimport { UserFilters } from '@/components/UserFilters'\nimport { Container, Box, Typography, Button } from '@mui/material'\nimport { Plus } from '@phosphor-icons/react'\n\nexport default function UsersPage() {\n return (\n <Container maxWidth=\"xl\" sx={{ py: 4 }}>\n <Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 4 }}>\n <Typography variant=\"h4\">Users</Typography>\n <Button variant=\"contained\" startIcon={<Plus />}>\n Add User\n </Button>\n </Box>\n <UserFilters />\n <UserTable />\n </Container>\n )\n}",
|
||||
"language": "typescript"
|
||||
}
|
||||
],
|
||||
"project-models": [
|
||||
{
|
||||
"id": "model-dash-1",
|
||||
"name": "Metric",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-dash-1",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-dash-2",
|
||||
"name": "name",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-3",
|
||||
"name": "value",
|
||||
"type": "Float",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-4",
|
||||
"name": "previousValue",
|
||||
"type": "Float",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-5",
|
||||
"name": "unit",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-6",
|
||||
"name": "category",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-7",
|
||||
"name": "timestamp",
|
||||
"type": "DateTime",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "now()"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "model-dash-2",
|
||||
"name": "User",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-dash-8",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-dash-9",
|
||||
"name": "email",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-10",
|
||||
"name": "name",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-11",
|
||||
"name": "role",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "user"
|
||||
},
|
||||
{
|
||||
"id": "field-dash-12",
|
||||
"name": "status",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "active"
|
||||
},
|
||||
{
|
||||
"id": "field-dash-13",
|
||||
"name": "avatar",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-14",
|
||||
"name": "lastLogin",
|
||||
"type": "DateTime",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-15",
|
||||
"name": "createdAt",
|
||||
"type": "DateTime",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "now()"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "model-dash-3",
|
||||
"name": "Activity",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-dash-16",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-dash-17",
|
||||
"name": "userId",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"relation": "User"
|
||||
},
|
||||
{
|
||||
"id": "field-dash-18",
|
||||
"name": "action",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-19",
|
||||
"name": "resource",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-20",
|
||||
"name": "resourceId",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-21",
|
||||
"name": "metadata",
|
||||
"type": "Json",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-22",
|
||||
"name": "timestamp",
|
||||
"type": "DateTime",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "now()"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "model-dash-4",
|
||||
"name": "Report",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-dash-23",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-dash-24",
|
||||
"name": "name",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-25",
|
||||
"name": "type",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-26",
|
||||
"name": "data",
|
||||
"type": "Json",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-27",
|
||||
"name": "filters",
|
||||
"type": "Json",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-28",
|
||||
"name": "generatedBy",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"relation": "User"
|
||||
},
|
||||
{
|
||||
"id": "field-dash-29",
|
||||
"name": "createdAt",
|
||||
"type": "DateTime",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "now()"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "model-dash-5",
|
||||
"name": "Alert",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-dash-30",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-dash-31",
|
||||
"name": "title",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-32",
|
||||
"name": "message",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-dash-33",
|
||||
"name": "severity",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "info"
|
||||
},
|
||||
{
|
||||
"id": "field-dash-34",
|
||||
"name": "read",
|
||||
"type": "Boolean",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "false"
|
||||
},
|
||||
{
|
||||
"id": "field-dash-35",
|
||||
"name": "userId",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"relation": "User"
|
||||
},
|
||||
{
|
||||
"id": "field-dash-36",
|
||||
"name": "createdAt",
|
||||
"type": "DateTime",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "now()"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"project-components": [
|
||||
{
|
||||
"id": "comp-dash-1",
|
||||
"type": "StatCard",
|
||||
"name": "StatCard",
|
||||
"props": {
|
||||
"showTrend": true,
|
||||
"showSparkline": true,
|
||||
"elevation": 2
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "comp-dash-2",
|
||||
"type": "DataTable",
|
||||
"name": "DataTable",
|
||||
"props": {
|
||||
"sortable": true,
|
||||
"filterable": true,
|
||||
"paginated": true,
|
||||
"exportable": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "comp-dash-3",
|
||||
"type": "ChartCard",
|
||||
"name": "ChartCard",
|
||||
"props": {
|
||||
"chartType": "line",
|
||||
"showLegend": true,
|
||||
"interactive": true
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
],
|
||||
"project-workflows": [
|
||||
{
|
||||
"id": "workflow-dash-1",
|
||||
"name": "Alert Processing Workflow",
|
||||
"description": "Process and route system alerts to users",
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-dash-1",
|
||||
"type": "trigger",
|
||||
"name": "Metric Threshold",
|
||||
"position": { "x": 100, "y": 100 },
|
||||
"data": { "label": "Threshold Exceeded" },
|
||||
"config": { "triggerType": "condition" }
|
||||
},
|
||||
{
|
||||
"id": "node-dash-2",
|
||||
"type": "action",
|
||||
"name": "Create Alert",
|
||||
"position": { "x": 300, "y": 100 },
|
||||
"data": { "label": "Generate alert record" }
|
||||
},
|
||||
{
|
||||
"id": "node-dash-3",
|
||||
"type": "condition",
|
||||
"name": "Check Severity",
|
||||
"position": { "x": 500, "y": 100 },
|
||||
"data": { "label": "Evaluate priority" }
|
||||
},
|
||||
{
|
||||
"id": "node-dash-4",
|
||||
"type": "notification",
|
||||
"name": "Push Notification",
|
||||
"position": { "x": 700, "y": 50 },
|
||||
"data": { "label": "Send push" }
|
||||
},
|
||||
{
|
||||
"id": "node-dash-5",
|
||||
"type": "notification",
|
||||
"name": "Email Notification",
|
||||
"position": { "x": 700, "y": 100 },
|
||||
"data": { "label": "Send email" }
|
||||
},
|
||||
{
|
||||
"id": "node-dash-6",
|
||||
"type": "database",
|
||||
"name": "Log Activity",
|
||||
"position": { "x": 900, "y": 100 },
|
||||
"data": { "label": "Record activity" }
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{ "id": "conn-dash-1", "source": "node-dash-1", "target": "node-dash-2" },
|
||||
{ "id": "conn-dash-2", "source": "node-dash-2", "target": "node-dash-3" },
|
||||
{ "id": "conn-dash-3", "source": "node-dash-3", "target": "node-dash-4", "condition": "critical" },
|
||||
{ "id": "conn-dash-4", "source": "node-dash-3", "target": "node-dash-5", "condition": "warning" },
|
||||
{ "id": "conn-dash-5", "source": "node-dash-4", "target": "node-dash-6" },
|
||||
{ "id": "conn-dash-6", "source": "node-dash-5", "target": "node-dash-6" }
|
||||
],
|
||||
"isActive": true,
|
||||
"createdAt": 1704067200000,
|
||||
"updatedAt": 1704067200000
|
||||
}
|
||||
],
|
||||
"project-lambdas": [
|
||||
{
|
||||
"id": "lambda-dash-1",
|
||||
"name": "aggregateMetrics",
|
||||
"description": "Aggregate and calculate metrics from raw data",
|
||||
"code": "export async function handler(event) {\n const { timeRange, metricTypes } = event;\n // Aggregate metrics from database\n const metrics = {\n totalUsers: 1234,\n activeUsers: 987,\n revenue: 45678.90,\n conversions: 234\n };\n return {\n statusCode: 200,\n body: JSON.stringify({ metrics })\n };\n}",
|
||||
"language": "typescript",
|
||||
"runtime": "nodejs20.x",
|
||||
"handler": "index.handler",
|
||||
"timeout": 30,
|
||||
"memory": 512,
|
||||
"environment": {},
|
||||
"triggers": [
|
||||
{
|
||||
"id": "trigger-dash-1",
|
||||
"type": "schedule",
|
||||
"config": { "schedule": "0 * * * *" }
|
||||
}
|
||||
],
|
||||
"createdAt": 1704067200000,
|
||||
"updatedAt": 1704067200000
|
||||
},
|
||||
{
|
||||
"id": "lambda-dash-2",
|
||||
"name": "generateReport",
|
||||
"description": "Generate analytics reports in various formats",
|
||||
"code": "export async function handler(event) {\n const { reportType, filters, format } = event;\n // Generate report data\n return {\n statusCode: 200,\n body: JSON.stringify({ reportUrl: '/reports/123.pdf' })\n };\n}",
|
||||
"language": "typescript",
|
||||
"runtime": "nodejs20.x",
|
||||
"handler": "index.handler",
|
||||
"timeout": 60,
|
||||
"memory": 1024,
|
||||
"environment": {},
|
||||
"triggers": [
|
||||
{
|
||||
"id": "trigger-dash-2",
|
||||
"type": "http",
|
||||
"config": { "method": "POST", "path": "/api/reports" }
|
||||
}
|
||||
],
|
||||
"createdAt": 1704067200000,
|
||||
"updatedAt": 1704067200000
|
||||
}
|
||||
],
|
||||
"project-playwright-tests": [
|
||||
{
|
||||
"id": "test-dash-1",
|
||||
"name": "Dashboard Navigation",
|
||||
"description": "Test navigating through dashboard sections",
|
||||
"pageUrl": "/",
|
||||
"steps": [
|
||||
{ "id": "step-dash-1", "action": "navigate", "value": "/" },
|
||||
{ "id": "step-dash-2", "action": "expect", "selector": ".stat-card", "assertion": "toBeVisible" },
|
||||
{ "id": "step-dash-3", "action": "click", "selector": "a[href='/analytics']" },
|
||||
{ "id": "step-dash-4", "action": "expect", "selector": ".analytics-chart", "assertion": "toBeVisible" },
|
||||
{ "id": "step-dash-5", "action": "click", "selector": "a[href='/users']" },
|
||||
{ "id": "step-dash-6", "action": "expect", "selector": ".user-table", "assertion": "toBeVisible" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"project-storybook-stories": [
|
||||
{
|
||||
"id": "story-dash-1",
|
||||
"componentName": "StatCard",
|
||||
"storyName": "WithTrend",
|
||||
"args": {
|
||||
"title": "Total Revenue",
|
||||
"value": "$45,678",
|
||||
"trend": 12.5,
|
||||
"trendDirection": "up"
|
||||
},
|
||||
"description": "Stat card with trend indicator",
|
||||
"category": "Dashboard"
|
||||
},
|
||||
{
|
||||
"id": "story-dash-2",
|
||||
"componentName": "ChartCard",
|
||||
"storyName": "LineChart",
|
||||
"args": {
|
||||
"title": "User Growth",
|
||||
"data": [],
|
||||
"chartType": "line"
|
||||
},
|
||||
"description": "Chart card with line visualization",
|
||||
"category": "Dashboard"
|
||||
}
|
||||
],
|
||||
"project-unit-tests": [
|
||||
{
|
||||
"id": "test-dash-unit-1",
|
||||
"name": "Metric Calculations",
|
||||
"description": "Test dashboard metric calculation utilities",
|
||||
"testType": "utility",
|
||||
"targetFile": "/src/utils/metrics.ts",
|
||||
"testCases": [
|
||||
{
|
||||
"id": "case-dash-1",
|
||||
"description": "calculates percentage change",
|
||||
"assertions": ["expect(calculateChange(100, 120)).toBe(20)"]
|
||||
},
|
||||
{
|
||||
"id": "case-dash-2",
|
||||
"description": "formats large numbers",
|
||||
"assertions": ["expect(formatNumber(1234567)).toBe('1.23M')"]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"project-component-trees": [
|
||||
{
|
||||
"id": "tree-dash-1",
|
||||
"name": "Dashboard Layout",
|
||||
"description": "Main dashboard layout with sidebar navigation",
|
||||
"rootNodes": [
|
||||
{
|
||||
"id": "root-dash-1",
|
||||
"type": "Box",
|
||||
"name": "DashboardWrapper",
|
||||
"props": { "sx": { "display": "flex", "minHeight": "100vh" } },
|
||||
"children": [
|
||||
{
|
||||
"id": "sidebar-dash-1",
|
||||
"type": "Drawer",
|
||||
"name": "Sidebar",
|
||||
"props": { "variant": "permanent", "sx": { "width": 240 } },
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "main-dash-1",
|
||||
"type": "Box",
|
||||
"name": "MainContent",
|
||||
"props": { "sx": { "flexGrow": 1, "p": 3 } },
|
||||
"children": [
|
||||
{
|
||||
"id": "appbar-dash-1",
|
||||
"type": "AppBar",
|
||||
"name": "TopBar",
|
||||
"props": { "position": "sticky", "elevation": 0 },
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "content-dash-1",
|
||||
"type": "Container",
|
||||
"name": "PageContent",
|
||||
"props": { "maxWidth": "xl", "sx": { "mt": 4 } },
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"createdAt": 1704067200000,
|
||||
"updatedAt": 1704067200000
|
||||
}
|
||||
]
|
||||
}
|
||||
635
src/config/seed-templates/e-commerce.json
Normal file
635
src/config/seed-templates/e-commerce.json
Normal file
@@ -0,0 +1,635 @@
|
||||
{
|
||||
"project-files": [
|
||||
{
|
||||
"id": "file-ecom-1",
|
||||
"name": "page.tsx",
|
||||
"path": "/src/app/page.tsx",
|
||||
"content": "'use client'\n\nimport { ProductGrid } from '@/components/ProductGrid'\nimport { Hero } from '@/components/Hero'\nimport { Box, Container } from '@mui/material'\n\nexport default function Home() {\n return (\n <Box>\n <Hero \n title=\"Summer Collection 2024\"\n subtitle=\"Discover our latest arrivals\"\n ctaText=\"Shop Now\"\n />\n <Container maxWidth=\"xl\" sx={{ py: 6 }}>\n <ProductGrid />\n </Container>\n </Box>\n )\n}",
|
||||
"language": "typescript"
|
||||
},
|
||||
{
|
||||
"id": "file-ecom-2",
|
||||
"name": "cart.tsx",
|
||||
"path": "/src/app/cart/page.tsx",
|
||||
"content": "'use client'\n\nimport { Cart } from '@/components/Cart'\nimport { Container, Typography, Box } from '@mui/material'\n\nexport default function CartPage() {\n return (\n <Container maxWidth=\"lg\" sx={{ py: 6 }}>\n <Typography variant=\"h3\" gutterBottom>\n Shopping Cart\n </Typography>\n <Cart />\n </Container>\n )\n}",
|
||||
"language": "typescript"
|
||||
},
|
||||
{
|
||||
"id": "file-ecom-3",
|
||||
"name": "checkout.tsx",
|
||||
"path": "/src/app/checkout/page.tsx",
|
||||
"content": "'use client'\n\nimport { CheckoutForm } from '@/components/CheckoutForm'\nimport { Container, Typography } from '@mui/material'\n\nexport default function CheckoutPage() {\n return (\n <Container maxWidth=\"md\" sx={{ py: 6 }}>\n <Typography variant=\"h3\" gutterBottom>\n Checkout\n </Typography>\n <CheckoutForm />\n </Container>\n )\n}",
|
||||
"language": "typescript"
|
||||
}
|
||||
],
|
||||
"project-models": [
|
||||
{
|
||||
"id": "model-ecom-1",
|
||||
"name": "Product",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-ecom-1",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-2",
|
||||
"name": "name",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-3",
|
||||
"name": "description",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-4",
|
||||
"name": "price",
|
||||
"type": "Float",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-5",
|
||||
"name": "salePrice",
|
||||
"type": "Float",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-6",
|
||||
"name": "stock",
|
||||
"type": "Int",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "0"
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-7",
|
||||
"name": "sku",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-8",
|
||||
"name": "images",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": true
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-9",
|
||||
"name": "categoryId",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"relation": "Category"
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-10",
|
||||
"name": "createdAt",
|
||||
"type": "DateTime",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "now()"
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-11",
|
||||
"name": "updatedAt",
|
||||
"type": "DateTime",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "now()"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "model-ecom-2",
|
||||
"name": "Category",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-ecom-12",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-13",
|
||||
"name": "name",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-14",
|
||||
"name": "slug",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-15",
|
||||
"name": "description",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-16",
|
||||
"name": "parentId",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"relation": "Category"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "model-ecom-3",
|
||||
"name": "Order",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-ecom-17",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-18",
|
||||
"name": "orderNumber",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-19",
|
||||
"name": "customerId",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"relation": "Customer"
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-20",
|
||||
"name": "status",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "pending"
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-21",
|
||||
"name": "subtotal",
|
||||
"type": "Float",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-22",
|
||||
"name": "tax",
|
||||
"type": "Float",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-23",
|
||||
"name": "shipping",
|
||||
"type": "Float",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-24",
|
||||
"name": "total",
|
||||
"type": "Float",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-25",
|
||||
"name": "createdAt",
|
||||
"type": "DateTime",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "now()"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "model-ecom-4",
|
||||
"name": "OrderItem",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-ecom-26",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-27",
|
||||
"name": "orderId",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"relation": "Order"
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-28",
|
||||
"name": "productId",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"relation": "Product"
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-29",
|
||||
"name": "quantity",
|
||||
"type": "Int",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-30",
|
||||
"name": "price",
|
||||
"type": "Float",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-31",
|
||||
"name": "total",
|
||||
"type": "Float",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "model-ecom-5",
|
||||
"name": "Customer",
|
||||
"fields": [
|
||||
{
|
||||
"id": "field-ecom-32",
|
||||
"name": "id",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false,
|
||||
"defaultValue": "uuid()"
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-33",
|
||||
"name": "email",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": true,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-34",
|
||||
"name": "firstName",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-35",
|
||||
"name": "lastName",
|
||||
"type": "String",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-36",
|
||||
"name": "phone",
|
||||
"type": "String",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-37",
|
||||
"name": "addresses",
|
||||
"type": "Json",
|
||||
"isRequired": false,
|
||||
"isUnique": false,
|
||||
"isArray": false
|
||||
},
|
||||
{
|
||||
"id": "field-ecom-38",
|
||||
"name": "createdAt",
|
||||
"type": "DateTime",
|
||||
"isRequired": true,
|
||||
"isUnique": false,
|
||||
"isArray": false,
|
||||
"defaultValue": "now()"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"project-components": [
|
||||
{
|
||||
"id": "comp-ecom-1",
|
||||
"type": "ProductCard",
|
||||
"name": "ProductCard",
|
||||
"props": {
|
||||
"elevation": 1,
|
||||
"showRating": true,
|
||||
"showQuickView": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "comp-ecom-2",
|
||||
"type": "CartItem",
|
||||
"name": "CartItem",
|
||||
"props": {
|
||||
"showImage": true,
|
||||
"allowQuantityEdit": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "comp-ecom-3",
|
||||
"type": "CheckoutSummary",
|
||||
"name": "CheckoutSummary",
|
||||
"props": {
|
||||
"showTax": true,
|
||||
"showShipping": true,
|
||||
"showPromoCode": true
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
],
|
||||
"project-workflows": [
|
||||
{
|
||||
"id": "workflow-ecom-1",
|
||||
"name": "Order Processing Workflow",
|
||||
"description": "Complete order fulfillment from payment to shipping",
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-ecom-1",
|
||||
"type": "trigger",
|
||||
"name": "Order Placed",
|
||||
"position": { "x": 100, "y": 100 },
|
||||
"data": { "label": "Order Created" },
|
||||
"config": { "triggerType": "event" }
|
||||
},
|
||||
{
|
||||
"id": "node-ecom-2",
|
||||
"type": "action",
|
||||
"name": "Process Payment",
|
||||
"position": { "x": 300, "y": 100 },
|
||||
"data": { "label": "Charge Customer" }
|
||||
},
|
||||
{
|
||||
"id": "node-ecom-3",
|
||||
"type": "condition",
|
||||
"name": "Payment Success?",
|
||||
"position": { "x": 500, "y": 100 },
|
||||
"data": { "label": "Check Payment" }
|
||||
},
|
||||
{
|
||||
"id": "node-ecom-4",
|
||||
"type": "action",
|
||||
"name": "Update Inventory",
|
||||
"position": { "x": 700, "y": 50 },
|
||||
"data": { "label": "Reduce Stock" }
|
||||
},
|
||||
{
|
||||
"id": "node-ecom-5",
|
||||
"type": "notification",
|
||||
"name": "Send Confirmation",
|
||||
"position": { "x": 900, "y": 50 },
|
||||
"data": { "label": "Email Customer" }
|
||||
},
|
||||
{
|
||||
"id": "node-ecom-6",
|
||||
"type": "notification",
|
||||
"name": "Payment Failed",
|
||||
"position": { "x": 700, "y": 150 },
|
||||
"data": { "label": "Notify Failure" }
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{ "id": "conn-ecom-1", "source": "node-ecom-1", "target": "node-ecom-2" },
|
||||
{ "id": "conn-ecom-2", "source": "node-ecom-2", "target": "node-ecom-3" },
|
||||
{ "id": "conn-ecom-3", "source": "node-ecom-3", "target": "node-ecom-4", "condition": "success" },
|
||||
{ "id": "conn-ecom-4", "source": "node-ecom-4", "target": "node-ecom-5" },
|
||||
{ "id": "conn-ecom-5", "source": "node-ecom-3", "target": "node-ecom-6", "condition": "failure" }
|
||||
],
|
||||
"isActive": true,
|
||||
"createdAt": 1704067200000,
|
||||
"updatedAt": 1704067200000
|
||||
}
|
||||
],
|
||||
"project-lambdas": [
|
||||
{
|
||||
"id": "lambda-ecom-1",
|
||||
"name": "calculateShipping",
|
||||
"description": "Calculate shipping costs based on order details",
|
||||
"code": "export async function handler(event) {\n const { items, destination } = event;\n const weight = items.reduce((sum, item) => sum + item.weight * item.quantity, 0);\n const baseRate = 5.99;\n const weightRate = weight * 0.50;\n const total = baseRate + weightRate;\n return {\n statusCode: 200,\n body: JSON.stringify({ shipping: total })\n };\n}",
|
||||
"language": "typescript",
|
||||
"runtime": "nodejs20.x",
|
||||
"handler": "index.handler",
|
||||
"timeout": 10,
|
||||
"memory": 128,
|
||||
"environment": {},
|
||||
"triggers": [
|
||||
{
|
||||
"id": "trigger-ecom-1",
|
||||
"type": "http",
|
||||
"config": { "method": "POST", "path": "/api/shipping" }
|
||||
}
|
||||
],
|
||||
"createdAt": 1704067200000,
|
||||
"updatedAt": 1704067200000
|
||||
},
|
||||
{
|
||||
"id": "lambda-ecom-2",
|
||||
"name": "processRefund",
|
||||
"description": "Handle order refunds and inventory restoration",
|
||||
"code": "export async function handler(event) {\n const { orderId, reason } = event;\n // Process refund logic\n return {\n statusCode: 200,\n body: JSON.stringify({ refunded: true, orderId })\n };\n}",
|
||||
"language": "typescript",
|
||||
"runtime": "nodejs20.x",
|
||||
"handler": "index.handler",
|
||||
"timeout": 30,
|
||||
"memory": 256,
|
||||
"environment": {},
|
||||
"triggers": [
|
||||
{
|
||||
"id": "trigger-ecom-2",
|
||||
"type": "http",
|
||||
"config": { "method": "POST", "path": "/api/refunds" }
|
||||
}
|
||||
],
|
||||
"createdAt": 1704067200000,
|
||||
"updatedAt": 1704067200000
|
||||
}
|
||||
],
|
||||
"project-playwright-tests": [
|
||||
{
|
||||
"id": "test-ecom-1",
|
||||
"name": "Complete Purchase Flow",
|
||||
"description": "Test end-to-end purchase workflow",
|
||||
"pageUrl": "/",
|
||||
"steps": [
|
||||
{ "id": "step-ecom-1", "action": "navigate", "value": "/" },
|
||||
{ "id": "step-ecom-2", "action": "click", "selector": ".product-card:first-child" },
|
||||
{ "id": "step-ecom-3", "action": "click", "selector": "button[data-testid='add-to-cart']" },
|
||||
{ "id": "step-ecom-4", "action": "click", "selector": "a[href='/cart']" },
|
||||
{ "id": "step-ecom-5", "action": "expect", "selector": ".cart-item", "assertion": "toBeVisible" },
|
||||
{ "id": "step-ecom-6", "action": "click", "selector": "button[data-testid='checkout']" },
|
||||
{ "id": "step-ecom-7", "action": "fill", "selector": "#email", "value": "customer@example.com" },
|
||||
{ "id": "step-ecom-8", "action": "fill", "selector": "#cardNumber", "value": "4242424242424242" },
|
||||
{ "id": "step-ecom-9", "action": "click", "selector": "button[type='submit']" },
|
||||
{ "id": "step-ecom-10", "action": "expect", "selector": ".success-message", "assertion": "toBeVisible" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"project-storybook-stories": [
|
||||
{
|
||||
"id": "story-ecom-1",
|
||||
"componentName": "ProductCard",
|
||||
"storyName": "Default",
|
||||
"args": {
|
||||
"name": "Premium T-Shirt",
|
||||
"price": 29.99,
|
||||
"image": "/images/product.jpg",
|
||||
"rating": 4.5
|
||||
},
|
||||
"description": "Product card with image and details",
|
||||
"category": "E-Commerce"
|
||||
},
|
||||
{
|
||||
"id": "story-ecom-2",
|
||||
"componentName": "ProductCard",
|
||||
"storyName": "OnSale",
|
||||
"args": {
|
||||
"name": "Premium T-Shirt",
|
||||
"price": 29.99,
|
||||
"salePrice": 19.99,
|
||||
"image": "/images/product.jpg",
|
||||
"rating": 4.5
|
||||
},
|
||||
"description": "Product card with sale price",
|
||||
"category": "E-Commerce"
|
||||
}
|
||||
],
|
||||
"project-unit-tests": [
|
||||
{
|
||||
"id": "test-ecom-unit-1",
|
||||
"name": "Cart Calculations",
|
||||
"description": "Test cart total and tax calculations",
|
||||
"testType": "utility",
|
||||
"targetFile": "/src/utils/cart.ts",
|
||||
"testCases": [
|
||||
{
|
||||
"id": "case-ecom-1",
|
||||
"description": "calculates subtotal correctly",
|
||||
"assertions": ["expect(calculateSubtotal(items)).toBe(99.97)"]
|
||||
},
|
||||
{
|
||||
"id": "case-ecom-2",
|
||||
"description": "applies tax correctly",
|
||||
"assertions": ["expect(calculateTax(100, 0.08)).toBe(8.00)"]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"project-component-trees": [
|
||||
{
|
||||
"id": "tree-ecom-1",
|
||||
"name": "E-Commerce Layout",
|
||||
"description": "Main store layout with header, navigation, and footer",
|
||||
"rootNodes": [
|
||||
{
|
||||
"id": "root-ecom-1",
|
||||
"type": "Container",
|
||||
"name": "StoreContainer",
|
||||
"props": { "maxWidth": "xl" },
|
||||
"children": [
|
||||
{
|
||||
"id": "header-ecom-1",
|
||||
"type": "AppBar",
|
||||
"name": "StoreHeader",
|
||||
"props": { "position": "sticky", "elevation": 1 },
|
||||
"children": [
|
||||
{
|
||||
"id": "nav-ecom-1",
|
||||
"type": "Toolbar",
|
||||
"name": "Navigation",
|
||||
"props": {},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "main-ecom-1",
|
||||
"type": "Box",
|
||||
"name": "MainContent",
|
||||
"props": { "sx": { "minHeight": "80vh" } },
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "footer-ecom-1",
|
||||
"type": "Box",
|
||||
"name": "Footer",
|
||||
"props": { "sx": { "py": 6, "bgcolor": "grey.100" } },
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"createdAt": 1704067200000,
|
||||
"updatedAt": 1704067200000
|
||||
}
|
||||
]
|
||||
}
|
||||
3
src/config/seed-templates/index.ts
Normal file
3
src/config/seed-templates/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export { default as ecommerceTemplate } from './e-commerce.json'
|
||||
export { default as blogTemplate } from './blog.json'
|
||||
export { default as dashboardTemplate } from './dashboard.json'
|
||||
@@ -4,3 +4,5 @@ export * from './use-search'
|
||||
export * from './use-debounce'
|
||||
export * from './use-sort'
|
||||
export * from './use-pagination'
|
||||
export * from './use-seed-data'
|
||||
export * from './use-seed-templates'
|
||||
|
||||
153
src/hooks/data/use-seed-templates.ts
Normal file
153
src/hooks/data/use-seed-templates.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import { useState } from 'react'
|
||||
import { ecommerceTemplate, blogTemplate, dashboardTemplate } from '@/config/seed-templates'
|
||||
import defaultTemplate from '@/config/seed-data.json'
|
||||
|
||||
export type TemplateType = 'default' | 'e-commerce' | 'blog' | 'dashboard'
|
||||
|
||||
interface Template {
|
||||
id: TemplateType
|
||||
name: string
|
||||
description: string
|
||||
icon: string
|
||||
data: Record<string, any>
|
||||
features: string[]
|
||||
}
|
||||
|
||||
const templates: Template[] = [
|
||||
{
|
||||
id: 'default',
|
||||
name: 'Default Project',
|
||||
description: 'Basic starter template with common components',
|
||||
icon: '🚀',
|
||||
data: defaultTemplate,
|
||||
features: ['Basic models', 'Sample components', 'User workflow']
|
||||
},
|
||||
{
|
||||
id: 'e-commerce',
|
||||
name: 'E-Commerce Store',
|
||||
description: 'Complete online store with products, cart, and checkout',
|
||||
icon: '🛍️',
|
||||
data: ecommerceTemplate,
|
||||
features: [
|
||||
'Product catalog',
|
||||
'Shopping cart',
|
||||
'Order management',
|
||||
'Customer accounts',
|
||||
'Payment processing'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'blog',
|
||||
name: 'Blog Platform',
|
||||
description: 'Content-focused blog with authors, posts, and comments',
|
||||
icon: '📝',
|
||||
data: blogTemplate,
|
||||
features: [
|
||||
'Post management',
|
||||
'Author profiles',
|
||||
'Comment system',
|
||||
'Newsletter',
|
||||
'SEO optimization'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'dashboard',
|
||||
name: 'Analytics Dashboard',
|
||||
description: 'Data visualization dashboard with metrics and reports',
|
||||
icon: '📊',
|
||||
data: dashboardTemplate,
|
||||
features: [
|
||||
'Real-time metrics',
|
||||
'Data visualization',
|
||||
'User management',
|
||||
'Activity logging',
|
||||
'Alert system'
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
export function useSeedTemplates() {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
const getTemplates = () => templates
|
||||
|
||||
const getTemplate = (id: TemplateType): Template | undefined => {
|
||||
return templates.find(t => t.id === id)
|
||||
}
|
||||
|
||||
const loadTemplate = async (templateId: TemplateType) => {
|
||||
setIsLoading(true)
|
||||
try {
|
||||
const template = getTemplate(templateId)
|
||||
if (!template) {
|
||||
throw new Error(`Template ${templateId} not found`)
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(template.data)) {
|
||||
await window.spark.kv.set(key, value)
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('Failed to load template:', error)
|
||||
return false
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const clearAndLoadTemplate = async (templateId: TemplateType) => {
|
||||
setIsLoading(true)
|
||||
try {
|
||||
const keys = await window.spark.kv.keys()
|
||||
for (const key of keys) {
|
||||
await window.spark.kv.delete(key)
|
||||
}
|
||||
|
||||
const success = await loadTemplate(templateId)
|
||||
return success
|
||||
} catch (error) {
|
||||
console.error('Failed to clear and load template:', error)
|
||||
return false
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const mergeTemplate = async (templateId: TemplateType) => {
|
||||
setIsLoading(true)
|
||||
try {
|
||||
const template = getTemplate(templateId)
|
||||
if (!template) {
|
||||
throw new Error(`Template ${templateId} not found`)
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(template.data)) {
|
||||
const existingData = await window.spark.kv.get<any[]>(key)
|
||||
if (existingData && Array.isArray(existingData) && Array.isArray(value)) {
|
||||
const mergedData = [...existingData, ...value]
|
||||
await window.spark.kv.set(key, mergedData)
|
||||
} else {
|
||||
await window.spark.kv.set(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('Failed to merge template:', error)
|
||||
return false
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
templates,
|
||||
isLoading,
|
||||
getTemplates,
|
||||
getTemplate,
|
||||
loadTemplate,
|
||||
clearAndLoadTemplate,
|
||||
mergeTemplate
|
||||
}
|
||||
}
|
||||
@@ -13,3 +13,4 @@ export * from './config/use-feature-flags'
|
||||
export * from './ai/use-ai-generation'
|
||||
|
||||
export * from './data/use-seed-data'
|
||||
export * from './data/use-seed-templates'
|
||||
|
||||
Reference in New Issue
Block a user