import { useState } from 'react' import { NextJsConfig, NpmSettings, NpmPackage } from '@/types/project' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { Switch } from '@/components/ui/switch' import { ScrollArea } from '@/components/ui/scroll-area' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Plus, Trash, Package, Cube, Code } from '@phosphor-icons/react' import { Badge } from '@/components/ui/badge' import { SeedDataManager } from '@/components/molecules' interface ProjectSettingsDesignerProps { nextjsConfig: NextJsConfig npmSettings: NpmSettings onNextjsConfigChange: (config: NextJsConfig | ((current: NextJsConfig) => NextJsConfig)) => void onNpmSettingsChange: (settings: NpmSettings | ((current: NpmSettings) => NpmSettings)) => void } export function ProjectSettingsDesigner({ nextjsConfig, npmSettings, onNextjsConfigChange, onNpmSettingsChange, }: ProjectSettingsDesignerProps) { const [packageDialogOpen, setPackageDialogOpen] = useState(false) const [editingPackage, setEditingPackage] = useState(null) const [scriptDialogOpen, setScriptDialogOpen] = useState(false) const [scriptKey, setScriptKey] = useState('') const [scriptValue, setScriptValue] = useState('') const [editingScriptKey, setEditingScriptKey] = useState(null) const handleAddPackage = () => { setEditingPackage({ id: `package-${Date.now()}`, name: '', version: 'latest', isDev: false, }) setPackageDialogOpen(true) } const handleEditPackage = (pkg: NpmPackage) => { setEditingPackage({ ...pkg }) setPackageDialogOpen(true) } const handleSavePackage = () => { if (!editingPackage || !editingPackage.name) return onNpmSettingsChange((current) => { const existingIndex = current.packages.findIndex((p) => p.id === editingPackage.id) if (existingIndex >= 0) { const updated = [...current.packages] updated[existingIndex] = editingPackage return { ...current, packages: updated } } else { return { ...current, packages: [...current.packages, editingPackage] } } }) setPackageDialogOpen(false) setEditingPackage(null) } const handleDeletePackage = (packageId: string) => { onNpmSettingsChange((current) => ({ ...current, packages: current.packages.filter((p) => p.id !== packageId), })) } const handleAddScript = () => { setScriptKey('') setScriptValue('') setEditingScriptKey(null) setScriptDialogOpen(true) } const handleEditScript = (key: string, value: string) => { setScriptKey(key) setScriptValue(value) setEditingScriptKey(key) setScriptDialogOpen(true) } const handleSaveScript = () => { if (!scriptKey || !scriptValue) return onNpmSettingsChange((current) => { const scripts = { ...current.scripts } if (editingScriptKey && editingScriptKey !== scriptKey) { delete scripts[editingScriptKey] } scripts[scriptKey] = scriptValue return { ...current, scripts } }) setScriptDialogOpen(false) setScriptKey('') setScriptValue('') setEditingScriptKey(null) } const handleDeleteScript = (key: string) => { onNpmSettingsChange((current) => { const scripts = { ...current.scripts } delete scripts[key] return { ...current, scripts } }) } return (

Project Settings

Configure Next.js and npm settings

Next.js Config NPM Packages Scripts Data
Application Settings Basic Next.js application configuration
onNextjsConfigChange((current) => ({ ...current, appName: e.target.value, })) } placeholder="my-nextjs-app" />
onNextjsConfigChange((current) => ({ ...current, importAlias: e.target.value, })) } placeholder="@/*" />

Used for module imports (e.g., import {'{'} Button {'}'} from "@/components")

Features Enable or disable Next.js features

Use TypeScript for type safety

onNextjsConfigChange((current) => ({ ...current, typescript: checked, })) } />

Code linting and formatting

onNextjsConfigChange((current) => ({ ...current, eslint: checked, })) } />

Utility-first CSS framework

onNextjsConfigChange((current) => ({ ...current, tailwind: checked, })) } />

Organize code inside src/ folder

onNextjsConfigChange((current) => ({ ...current, srcDirectory: checked, })) } />

Use the new App Router (vs Pages Router)

onNextjsConfigChange((current) => ({ ...current, appRouter: checked, })) } />

Faster incremental bundler

onNextjsConfigChange((current) => ({ ...current, turbopack: checked, })) } />

NPM Packages

Manage project dependencies

Dependencies

{npmSettings.packages .filter((pkg) => !pkg.isDev) .map((pkg) => (
{pkg.name} {pkg.version}
{pkg.description && (

{pkg.description}

)}
))} {npmSettings.packages.filter((pkg) => !pkg.isDev).length === 0 && (

No dependencies added yet

)}

Dev Dependencies

{npmSettings.packages .filter((pkg) => pkg.isDev) .map((pkg) => (
{pkg.name} {pkg.version} dev
{pkg.description && (

{pkg.description}

)}
))} {npmSettings.packages.filter((pkg) => pkg.isDev).length === 0 && (

No dev dependencies added yet

)}

NPM Scripts

Define custom commands for your project

{Object.entries(npmSettings.scripts).map(([key, value]) => (
{key}
{value}
))} {Object.keys(npmSettings.scripts).length === 0 && (

No scripts defined yet

)}
{editingPackage?.name ? 'Edit Package' : 'Add Package'} Configure npm package details {editingPackage && (
setEditingPackage({ ...editingPackage, name: e.target.value }) } placeholder="e.g., react-query, axios" />
setEditingPackage({ ...editingPackage, version: e.target.value }) } placeholder="latest, ^1.0.0, ~2.3.4" />
setEditingPackage({ ...editingPackage, description: e.target.value }) } placeholder="What is this package for?" />
setEditingPackage({ ...editingPackage, isDev: checked }) } />
)}
{editingScriptKey ? 'Edit Script' : 'Add Script'} Define a custom npm script command
setScriptKey(e.target.value)} placeholder="e.g., dev, build, test" />
setScriptValue(e.target.value)} placeholder="e.g., next dev, tsc --noEmit" />
) }