mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 21:54:56 +00:00
Generated by Spark: User might not want every designer feature, make it so we can turn them on and off
This commit is contained in:
411
src/App.tsx
411
src/App.tsx
@@ -6,8 +6,8 @@ import { Button } from '@/components/ui/button'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Card } from '@/components/ui/card'
|
||||
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable'
|
||||
import { Code, Database, Tree, PaintBrush, Download, Sparkle, Flask, BookOpen, Play, Wrench, Gear, Cube, FileText, ChartBar, Keyboard, FlowArrow } from '@phosphor-icons/react'
|
||||
import { ProjectFile, PrismaModel, ComponentNode, ComponentTree, ThemeConfig, PlaywrightTest, StorybookStory, UnitTest, FlaskConfig, NextJsConfig, NpmSettings, Workflow, Lambda } from '@/types/project'
|
||||
import { Code, Database, Tree, PaintBrush, Download, Sparkle, Flask, BookOpen, Play, Wrench, Gear, Cube, FileText, ChartBar, Keyboard, FlowArrow, Faders } from '@phosphor-icons/react'
|
||||
import { ProjectFile, PrismaModel, ComponentNode, ComponentTree, ThemeConfig, PlaywrightTest, StorybookStory, UnitTest, FlaskConfig, NextJsConfig, NpmSettings, Workflow, Lambda, FeatureToggles } from '@/types/project'
|
||||
import { CodeEditor } from '@/components/CodeEditor'
|
||||
import { ModelDesigner } from '@/components/ModelDesigner'
|
||||
import { ComponentTreeBuilder } from '@/components/ComponentTreeBuilder'
|
||||
@@ -26,6 +26,7 @@ import { DocumentationView } from '@/components/DocumentationView'
|
||||
import { SassStylesShowcase } from '@/components/SassStylesShowcase'
|
||||
import { ProjectDashboard } from '@/components/ProjectDashboard'
|
||||
import { KeyboardShortcutsDialog } from '@/components/KeyboardShortcutsDialog'
|
||||
import { FeatureToggleSettings } from '@/components/FeatureToggleSettings'
|
||||
import { useKeyboardShortcuts } from '@/hooks/use-keyboard-shortcuts'
|
||||
import { generateNextJSProject, generatePrismaSchema, generateMUITheme, generatePlaywrightTests, generateStorybookStories, generateUnitTests, generateFlaskApp } from '@/lib/generators'
|
||||
import { AIService } from '@/lib/ai-service'
|
||||
@@ -78,6 +79,23 @@ const DEFAULT_NPM_SETTINGS: NpmSettings = {
|
||||
packageManager: 'npm',
|
||||
}
|
||||
|
||||
const DEFAULT_FEATURE_TOGGLES: FeatureToggles = {
|
||||
codeEditor: true,
|
||||
models: true,
|
||||
components: true,
|
||||
componentTrees: true,
|
||||
workflows: true,
|
||||
lambdas: true,
|
||||
styling: true,
|
||||
flaskApi: true,
|
||||
playwright: true,
|
||||
storybook: true,
|
||||
unitTests: true,
|
||||
errorRepair: true,
|
||||
documentation: true,
|
||||
sassStyles: true,
|
||||
}
|
||||
|
||||
const DEFAULT_THEME: ThemeConfig = {
|
||||
variants: [
|
||||
{
|
||||
@@ -162,6 +180,7 @@ function App() {
|
||||
const [flaskConfig, setFlaskConfig] = useKV<FlaskConfig>('project-flask-config', DEFAULT_FLASK_CONFIG)
|
||||
const [nextjsConfig, setNextjsConfig] = useKV<NextJsConfig>('project-nextjs-config', DEFAULT_NEXTJS_CONFIG)
|
||||
const [npmSettings, setNpmSettings] = useKV<NpmSettings>('project-npm-settings', DEFAULT_NPM_SETTINGS)
|
||||
const [featureToggles, setFeatureToggles] = useKV<FeatureToggles>('project-feature-toggles', DEFAULT_FEATURE_TOGGLES)
|
||||
const [activeFileId, setActiveFileId] = useState<string | null>((files || [])[0]?.id || null)
|
||||
const [activeTab, setActiveTab] = useState('dashboard')
|
||||
const [exportDialogOpen, setExportDialogOpen] = useState(false)
|
||||
@@ -181,6 +200,7 @@ function App() {
|
||||
const safeFlaskConfig = flaskConfig || DEFAULT_FLASK_CONFIG
|
||||
const safeNextjsConfig = nextjsConfig || DEFAULT_NEXTJS_CONFIG
|
||||
const safeNpmSettings = npmSettings || DEFAULT_NPM_SETTINGS
|
||||
const safeFeatureToggles = featureToggles || DEFAULT_FEATURE_TOGGLES
|
||||
|
||||
useEffect(() => {
|
||||
if (!theme || !theme.variants || theme.variants.length === 0) {
|
||||
@@ -188,6 +208,12 @@ function App() {
|
||||
}
|
||||
}, [theme, setTheme])
|
||||
|
||||
useEffect(() => {
|
||||
if (!featureToggles) {
|
||||
setFeatureToggles(DEFAULT_FEATURE_TOGGLES)
|
||||
}
|
||||
}, [featureToggles, setFeatureToggles])
|
||||
|
||||
const { errors: autoDetectedErrors } = useAutoRepair(safeFiles, false)
|
||||
|
||||
useKeyboardShortcuts([
|
||||
@@ -197,48 +223,48 @@ function App() {
|
||||
description: 'Go to Dashboard',
|
||||
action: () => setActiveTab('dashboard'),
|
||||
},
|
||||
{
|
||||
...(safeFeatureToggles.codeEditor ? [{
|
||||
key: '2',
|
||||
ctrl: true,
|
||||
description: 'Go to Code Editor',
|
||||
action: () => setActiveTab('code'),
|
||||
},
|
||||
{
|
||||
}] : []),
|
||||
...(safeFeatureToggles.models ? [{
|
||||
key: '3',
|
||||
ctrl: true,
|
||||
description: 'Go to Models',
|
||||
action: () => setActiveTab('models'),
|
||||
},
|
||||
{
|
||||
}] : []),
|
||||
...(safeFeatureToggles.components ? [{
|
||||
key: '4',
|
||||
ctrl: true,
|
||||
description: 'Go to Components',
|
||||
action: () => setActiveTab('components'),
|
||||
},
|
||||
{
|
||||
}] : []),
|
||||
...(safeFeatureToggles.componentTrees ? [{
|
||||
key: '5',
|
||||
ctrl: true,
|
||||
description: 'Go to Component Trees',
|
||||
action: () => setActiveTab('component-trees'),
|
||||
},
|
||||
{
|
||||
}] : []),
|
||||
...(safeFeatureToggles.workflows ? [{
|
||||
key: '6',
|
||||
ctrl: true,
|
||||
description: 'Go to Workflows',
|
||||
action: () => setActiveTab('workflows'),
|
||||
},
|
||||
{
|
||||
}] : []),
|
||||
...(safeFeatureToggles.lambdas ? [{
|
||||
key: '7',
|
||||
ctrl: true,
|
||||
description: 'Go to Lambdas',
|
||||
action: () => setActiveTab('lambdas'),
|
||||
},
|
||||
{
|
||||
}] : []),
|
||||
...(safeFeatureToggles.styling ? [{
|
||||
key: '8',
|
||||
ctrl: true,
|
||||
description: 'Go to Styling',
|
||||
action: () => setActiveTab('styling'),
|
||||
},
|
||||
}] : []),
|
||||
{
|
||||
key: 'e',
|
||||
ctrl: true,
|
||||
@@ -444,7 +470,7 @@ Navigate to the backend directory and follow the setup instructions.
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{autoDetectedErrors.length > 0 && (
|
||||
{safeFeatureToggles.errorRepair && autoDetectedErrors.length > 0 && (
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setActiveTab('errors')}
|
||||
@@ -454,6 +480,14 @@ Navigate to the backend directory and follow the setup instructions.
|
||||
{autoDetectedErrors.length} {autoDetectedErrors.length === 1 ? 'Error' : 'Errors'}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setActiveTab('features')}
|
||||
title="Toggle Features"
|
||||
>
|
||||
<Faders size={20} />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
@@ -481,71 +515,103 @@ Navigate to the backend directory and follow the setup instructions.
|
||||
<ChartBar size={18} />
|
||||
Dashboard
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="code" className="gap-2">
|
||||
<Code size={18} />
|
||||
Code Editor
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="models" className="gap-2">
|
||||
<Database size={18} />
|
||||
Models
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="components" className="gap-2">
|
||||
<Tree size={18} />
|
||||
Components
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="component-trees" className="gap-2">
|
||||
<Tree size={18} />
|
||||
Component Trees
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="workflows" className="gap-2">
|
||||
<FlowArrow size={18} />
|
||||
Workflows
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="lambdas" className="gap-2">
|
||||
<Code size={18} />
|
||||
Lambdas
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="styling" className="gap-2">
|
||||
<PaintBrush size={18} />
|
||||
Styling
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="flask" className="gap-2">
|
||||
<Flask size={18} />
|
||||
Flask API
|
||||
</TabsTrigger>
|
||||
{safeFeatureToggles.codeEditor && (
|
||||
<TabsTrigger value="code" className="gap-2">
|
||||
<Code size={18} />
|
||||
Code Editor
|
||||
</TabsTrigger>
|
||||
)}
|
||||
{safeFeatureToggles.models && (
|
||||
<TabsTrigger value="models" className="gap-2">
|
||||
<Database size={18} />
|
||||
Models
|
||||
</TabsTrigger>
|
||||
)}
|
||||
{safeFeatureToggles.components && (
|
||||
<TabsTrigger value="components" className="gap-2">
|
||||
<Tree size={18} />
|
||||
Components
|
||||
</TabsTrigger>
|
||||
)}
|
||||
{safeFeatureToggles.componentTrees && (
|
||||
<TabsTrigger value="component-trees" className="gap-2">
|
||||
<Tree size={18} />
|
||||
Component Trees
|
||||
</TabsTrigger>
|
||||
)}
|
||||
{safeFeatureToggles.workflows && (
|
||||
<TabsTrigger value="workflows" className="gap-2">
|
||||
<FlowArrow size={18} />
|
||||
Workflows
|
||||
</TabsTrigger>
|
||||
)}
|
||||
{safeFeatureToggles.lambdas && (
|
||||
<TabsTrigger value="lambdas" className="gap-2">
|
||||
<Code size={18} />
|
||||
Lambdas
|
||||
</TabsTrigger>
|
||||
)}
|
||||
{safeFeatureToggles.styling && (
|
||||
<TabsTrigger value="styling" className="gap-2">
|
||||
<PaintBrush size={18} />
|
||||
Styling
|
||||
</TabsTrigger>
|
||||
)}
|
||||
{safeFeatureToggles.flaskApi && (
|
||||
<TabsTrigger value="flask" className="gap-2">
|
||||
<Flask size={18} />
|
||||
Flask API
|
||||
</TabsTrigger>
|
||||
)}
|
||||
<TabsTrigger value="settings" className="gap-2">
|
||||
<Gear size={18} />
|
||||
Settings
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="playwright" className="gap-2">
|
||||
<Play size={18} />
|
||||
Playwright
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="storybook" className="gap-2">
|
||||
<BookOpen size={18} />
|
||||
Storybook
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="unit-tests" className="gap-2">
|
||||
<Cube size={18} />
|
||||
Unit Tests
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="errors" className="gap-2">
|
||||
<Wrench size={18} />
|
||||
Error Repair
|
||||
{autoDetectedErrors.length > 0 && (
|
||||
<Badge variant="destructive" className="ml-1">
|
||||
{autoDetectedErrors.length}
|
||||
</Badge>
|
||||
)}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="docs" className="gap-2">
|
||||
<FileText size={18} />
|
||||
Documentation
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="sass" className="gap-2">
|
||||
<PaintBrush size={18} />
|
||||
Sass Styles
|
||||
<TabsTrigger value="features" className="gap-2">
|
||||
<Faders size={18} />
|
||||
Features
|
||||
</TabsTrigger>
|
||||
{safeFeatureToggles.playwright && (
|
||||
<TabsTrigger value="playwright" className="gap-2">
|
||||
<Play size={18} />
|
||||
Playwright
|
||||
</TabsTrigger>
|
||||
)}
|
||||
{safeFeatureToggles.storybook && (
|
||||
<TabsTrigger value="storybook" className="gap-2">
|
||||
<BookOpen size={18} />
|
||||
Storybook
|
||||
</TabsTrigger>
|
||||
)}
|
||||
{safeFeatureToggles.unitTests && (
|
||||
<TabsTrigger value="unit-tests" className="gap-2">
|
||||
<Cube size={18} />
|
||||
Unit Tests
|
||||
</TabsTrigger>
|
||||
)}
|
||||
{safeFeatureToggles.errorRepair && (
|
||||
<TabsTrigger value="errors" className="gap-2">
|
||||
<Wrench size={18} />
|
||||
Error Repair
|
||||
{autoDetectedErrors.length > 0 && (
|
||||
<Badge variant="destructive" className="ml-1">
|
||||
{autoDetectedErrors.length}
|
||||
</Badge>
|
||||
)}
|
||||
</TabsTrigger>
|
||||
)}
|
||||
{safeFeatureToggles.documentation && (
|
||||
<TabsTrigger value="docs" className="gap-2">
|
||||
<FileText size={18} />
|
||||
Documentation
|
||||
</TabsTrigger>
|
||||
)}
|
||||
{safeFeatureToggles.sassStyles && (
|
||||
<TabsTrigger value="sass" className="gap-2">
|
||||
<PaintBrush size={18} />
|
||||
Sass Styles
|
||||
</TabsTrigger>
|
||||
)}
|
||||
</TabsList>
|
||||
</div>
|
||||
|
||||
@@ -563,68 +629,84 @@ Navigate to the backend directory and follow the setup instructions.
|
||||
/>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="code" className="h-full m-0">
|
||||
<ResizablePanelGroup direction="horizontal">
|
||||
<ResizablePanel defaultSize={20} minSize={15} maxSize={30}>
|
||||
<FileExplorer
|
||||
files={safeFiles}
|
||||
activeFileId={activeFileId}
|
||||
onFileSelect={setActiveFileId}
|
||||
onFileAdd={handleFileAdd}
|
||||
/>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel defaultSize={80}>
|
||||
<CodeEditor
|
||||
files={safeFiles}
|
||||
activeFileId={activeFileId}
|
||||
onFileChange={handleFileChange}
|
||||
onFileSelect={setActiveFileId}
|
||||
onFileClose={handleFileClose}
|
||||
/>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</TabsContent>
|
||||
{safeFeatureToggles.codeEditor && (
|
||||
<TabsContent value="code" className="h-full m-0">
|
||||
<ResizablePanelGroup direction="horizontal">
|
||||
<ResizablePanel defaultSize={20} minSize={15} maxSize={30}>
|
||||
<FileExplorer
|
||||
files={safeFiles}
|
||||
activeFileId={activeFileId}
|
||||
onFileSelect={setActiveFileId}
|
||||
onFileAdd={handleFileAdd}
|
||||
/>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel defaultSize={80}>
|
||||
<CodeEditor
|
||||
files={safeFiles}
|
||||
activeFileId={activeFileId}
|
||||
onFileChange={handleFileChange}
|
||||
onFileSelect={setActiveFileId}
|
||||
onFileClose={handleFileClose}
|
||||
/>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
<TabsContent value="models" className="h-full m-0">
|
||||
<ModelDesigner models={safeModels} onModelsChange={setModels} />
|
||||
</TabsContent>
|
||||
{safeFeatureToggles.models && (
|
||||
<TabsContent value="models" className="h-full m-0">
|
||||
<ModelDesigner models={safeModels} onModelsChange={setModels} />
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
<TabsContent value="components" className="h-full m-0">
|
||||
<ComponentTreeBuilder
|
||||
components={safeComponents}
|
||||
onComponentsChange={setComponents}
|
||||
/>
|
||||
</TabsContent>
|
||||
{safeFeatureToggles.components && (
|
||||
<TabsContent value="components" className="h-full m-0">
|
||||
<ComponentTreeBuilder
|
||||
components={safeComponents}
|
||||
onComponentsChange={setComponents}
|
||||
/>
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
<TabsContent value="component-trees" className="h-full m-0">
|
||||
<ComponentTreeManager
|
||||
trees={safeComponentTrees}
|
||||
onTreesChange={setComponentTrees}
|
||||
/>
|
||||
</TabsContent>
|
||||
{safeFeatureToggles.componentTrees && (
|
||||
<TabsContent value="component-trees" className="h-full m-0">
|
||||
<ComponentTreeManager
|
||||
trees={safeComponentTrees}
|
||||
onTreesChange={setComponentTrees}
|
||||
/>
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
<TabsContent value="workflows" className="h-full m-0">
|
||||
<WorkflowDesigner
|
||||
workflows={safeWorkflows}
|
||||
onWorkflowsChange={setWorkflows}
|
||||
/>
|
||||
</TabsContent>
|
||||
{safeFeatureToggles.workflows && (
|
||||
<TabsContent value="workflows" className="h-full m-0">
|
||||
<WorkflowDesigner
|
||||
workflows={safeWorkflows}
|
||||
onWorkflowsChange={setWorkflows}
|
||||
/>
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
<TabsContent value="lambdas" className="h-full m-0">
|
||||
<LambdaDesigner
|
||||
lambdas={safeLambdas}
|
||||
onLambdasChange={setLambdas}
|
||||
/>
|
||||
</TabsContent>
|
||||
{safeFeatureToggles.lambdas && (
|
||||
<TabsContent value="lambdas" className="h-full m-0">
|
||||
<LambdaDesigner
|
||||
lambdas={safeLambdas}
|
||||
onLambdasChange={setLambdas}
|
||||
/>
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
<TabsContent value="styling" className="h-full m-0">
|
||||
<StyleDesigner theme={safeTheme} onThemeChange={setTheme} />
|
||||
</TabsContent>
|
||||
{safeFeatureToggles.styling && (
|
||||
<TabsContent value="styling" className="h-full m-0">
|
||||
<StyleDesigner theme={safeTheme} onThemeChange={setTheme} />
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
<TabsContent value="flask" className="h-full m-0">
|
||||
<FlaskDesigner config={safeFlaskConfig} onConfigChange={setFlaskConfig} />
|
||||
</TabsContent>
|
||||
{safeFeatureToggles.flaskApi && (
|
||||
<TabsContent value="flask" className="h-full m-0">
|
||||
<FlaskDesigner config={safeFlaskConfig} onConfigChange={setFlaskConfig} />
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
<TabsContent value="settings" className="h-full m-0">
|
||||
<ProjectSettingsDesigner
|
||||
@@ -635,33 +717,52 @@ Navigate to the backend directory and follow the setup instructions.
|
||||
/>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="playwright" className="h-full m-0">
|
||||
<PlaywrightDesigner tests={safePlaywrightTests} onTestsChange={setPlaywrightTests} />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="storybook" className="h-full m-0">
|
||||
<StorybookDesigner stories={safeStorybookStories} onStoriesChange={setStorybookStories} />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="unit-tests" className="h-full m-0">
|
||||
<UnitTestDesigner tests={safeUnitTests} onTestsChange={setUnitTests} />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="errors" className="h-full m-0">
|
||||
<ErrorPanel
|
||||
files={safeFiles}
|
||||
onFileChange={handleFileChange}
|
||||
onFileSelect={setActiveFileId}
|
||||
<TabsContent value="features" className="h-full m-0">
|
||||
<FeatureToggleSettings
|
||||
features={safeFeatureToggles}
|
||||
onFeaturesChange={setFeatureToggles}
|
||||
/>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="docs" className="h-full m-0">
|
||||
<DocumentationView />
|
||||
</TabsContent>
|
||||
{safeFeatureToggles.playwright && (
|
||||
<TabsContent value="playwright" className="h-full m-0">
|
||||
<PlaywrightDesigner tests={safePlaywrightTests} onTestsChange={setPlaywrightTests} />
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
<TabsContent value="sass" className="h-full m-0">
|
||||
<SassStylesShowcase />
|
||||
</TabsContent>
|
||||
{safeFeatureToggles.storybook && (
|
||||
<TabsContent value="storybook" className="h-full m-0">
|
||||
<StorybookDesigner stories={safeStorybookStories} onStoriesChange={setStorybookStories} />
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
{safeFeatureToggles.unitTests && (
|
||||
<TabsContent value="unit-tests" className="h-full m-0">
|
||||
<UnitTestDesigner tests={safeUnitTests} onTestsChange={setUnitTests} />
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
{safeFeatureToggles.errorRepair && (
|
||||
<TabsContent value="errors" className="h-full m-0">
|
||||
<ErrorPanel
|
||||
files={safeFiles}
|
||||
onFileChange={handleFileChange}
|
||||
onFileSelect={setActiveFileId}
|
||||
/>
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
{safeFeatureToggles.documentation && (
|
||||
<TabsContent value="docs" className="h-full m-0">
|
||||
<DocumentationView />
|
||||
</TabsContent>
|
||||
)}
|
||||
|
||||
{safeFeatureToggles.sassStyles && (
|
||||
<TabsContent value="sass" className="h-full m-0">
|
||||
<SassStylesShowcase />
|
||||
</TabsContent>
|
||||
)}
|
||||
</div>
|
||||
</Tabs>
|
||||
|
||||
|
||||
148
src/components/FeatureToggleSettings.tsx
Normal file
148
src/components/FeatureToggleSettings.tsx
Normal file
@@ -0,0 +1,148 @@
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { FeatureToggles } from '@/types/project'
|
||||
import { Code, Database, Tree, PaintBrush, Flask, Play, BookOpen, Cube, Wrench, FileText, FlowArrow } from '@phosphor-icons/react'
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
|
||||
interface FeatureToggleSettingsProps {
|
||||
features: FeatureToggles
|
||||
onFeaturesChange: (features: FeatureToggles) => void
|
||||
}
|
||||
|
||||
const featuresList = [
|
||||
{
|
||||
key: 'codeEditor' as keyof FeatureToggles,
|
||||
label: 'Code Editor',
|
||||
description: 'Monaco-based code editor with syntax highlighting',
|
||||
icon: Code
|
||||
},
|
||||
{
|
||||
key: 'models' as keyof FeatureToggles,
|
||||
label: 'Database Models',
|
||||
description: 'Prisma schema designer for database models',
|
||||
icon: Database
|
||||
},
|
||||
{
|
||||
key: 'components' as keyof FeatureToggles,
|
||||
label: 'Component Builder',
|
||||
description: 'Visual component tree builder for React components',
|
||||
icon: Tree
|
||||
},
|
||||
{
|
||||
key: 'componentTrees' as keyof FeatureToggles,
|
||||
label: 'Component Trees Manager',
|
||||
description: 'Manage multiple component tree configurations',
|
||||
icon: Tree
|
||||
},
|
||||
{
|
||||
key: 'workflows' as keyof FeatureToggles,
|
||||
label: 'Workflow Designer',
|
||||
description: 'n8n-style visual workflow automation builder',
|
||||
icon: FlowArrow
|
||||
},
|
||||
{
|
||||
key: 'lambdas' as keyof FeatureToggles,
|
||||
label: 'Lambda Functions',
|
||||
description: 'Serverless function editor with multiple runtimes',
|
||||
icon: Code
|
||||
},
|
||||
{
|
||||
key: 'styling' as keyof FeatureToggles,
|
||||
label: 'Theme Designer',
|
||||
description: 'Material UI theme customization and styling',
|
||||
icon: PaintBrush
|
||||
},
|
||||
{
|
||||
key: 'flaskApi' as keyof FeatureToggles,
|
||||
label: 'Flask API Designer',
|
||||
description: 'Python Flask backend API endpoint designer',
|
||||
icon: Flask
|
||||
},
|
||||
{
|
||||
key: 'playwright' as keyof FeatureToggles,
|
||||
label: 'Playwright Tests',
|
||||
description: 'E2E testing with Playwright configuration',
|
||||
icon: Play
|
||||
},
|
||||
{
|
||||
key: 'storybook' as keyof FeatureToggles,
|
||||
label: 'Storybook Stories',
|
||||
description: 'Component documentation and development',
|
||||
icon: BookOpen
|
||||
},
|
||||
{
|
||||
key: 'unitTests' as keyof FeatureToggles,
|
||||
label: 'Unit Tests',
|
||||
description: 'Component and function unit test designer',
|
||||
icon: Cube
|
||||
},
|
||||
{
|
||||
key: 'errorRepair' as keyof FeatureToggles,
|
||||
label: 'Error Repair',
|
||||
description: 'Auto-detect and fix code errors',
|
||||
icon: Wrench
|
||||
},
|
||||
{
|
||||
key: 'documentation' as keyof FeatureToggles,
|
||||
label: 'Documentation',
|
||||
description: 'Project documentation, roadmap, and guides',
|
||||
icon: FileText
|
||||
},
|
||||
{
|
||||
key: 'sassStyles' as keyof FeatureToggles,
|
||||
label: 'Sass Styles',
|
||||
description: 'Custom Sass/SCSS styling showcase',
|
||||
icon: PaintBrush
|
||||
},
|
||||
]
|
||||
|
||||
export function FeatureToggleSettings({ features, onFeaturesChange }: FeatureToggleSettingsProps) {
|
||||
const handleToggle = (key: keyof FeatureToggles, value: boolean) => {
|
||||
onFeaturesChange({
|
||||
...features,
|
||||
[key]: value,
|
||||
})
|
||||
}
|
||||
|
||||
const enabledCount = Object.values(features).filter(Boolean).length
|
||||
const totalCount = Object.keys(features).length
|
||||
|
||||
return (
|
||||
<div className="h-full p-6 bg-background">
|
||||
<div className="mb-6">
|
||||
<h2 className="text-2xl font-bold mb-2">Feature Toggles</h2>
|
||||
<p className="text-muted-foreground">
|
||||
Enable or disable features to customize your workspace. {enabledCount} of {totalCount} features enabled.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ScrollArea className="h-[calc(100vh-200px)]">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 pr-4">
|
||||
{featuresList.map(({ key, label, description, icon: Icon }) => (
|
||||
<Card key={key}>
|
||||
<CardHeader className="pb-3">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className={`p-2 rounded-lg ${features[key] ? 'bg-primary text-primary-foreground' : 'bg-muted text-muted-foreground'}`}>
|
||||
<Icon size={20} weight="duotone" />
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle className="text-base">{label}</CardTitle>
|
||||
<CardDescription className="text-xs mt-1">{description}</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
id={key}
|
||||
checked={features[key]}
|
||||
onCheckedChange={(checked) => handleToggle(key, checked)}
|
||||
/>
|
||||
</div>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -259,6 +259,23 @@ export interface LambdaTrigger {
|
||||
config: Record<string, any>
|
||||
}
|
||||
|
||||
export interface FeatureToggles {
|
||||
codeEditor: boolean
|
||||
models: boolean
|
||||
components: boolean
|
||||
componentTrees: boolean
|
||||
workflows: boolean
|
||||
lambdas: boolean
|
||||
styling: boolean
|
||||
flaskApi: boolean
|
||||
playwright: boolean
|
||||
storybook: boolean
|
||||
unitTests: boolean
|
||||
errorRepair: boolean
|
||||
documentation: boolean
|
||||
sassStyles: boolean
|
||||
}
|
||||
|
||||
export interface Project {
|
||||
name: string
|
||||
files: ProjectFile[]
|
||||
@@ -274,4 +291,5 @@ export interface Project {
|
||||
flaskConfig?: FlaskConfig
|
||||
nextjsConfig?: NextJsConfig
|
||||
npmSettings?: NpmSettings
|
||||
featureToggles?: FeatureToggles
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user