From 2a476fbd18ed6bc216d5a4e3a7e0dbf1f1e7dc8b Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Tue, 23 Dec 2025 20:30:46 +0000 Subject: [PATCH] Generated by Spark: https://github.com/johndoe6345789/RevolutionaryWayToServeUpReactApps/tree/main --> I want it to be able to generate like a Django style React admin panel. This will mean being able to set up the data model and everything declaratively. Leverage json to generate boilerplate code and even store strings in json (multiline is just an array). --- .spark-initial-sha | 1 + PRD.md | 119 ++++++++++++ README.md | 231 ++++++++++++++++++++-- example-schemas.json | 290 ++++++++++++++++++++++++++++ index.html | 3 +- src/App.tsx | 122 +++++++++++- src/components/FieldRenderer.tsx | 209 ++++++++++++++++++++ src/components/ModelListView.tsx | 317 +++++++++++++++++++++++++++++++ src/components/RecordForm.tsx | 97 ++++++++++ src/components/SchemaEditor.tsx | 76 ++++++++ src/index.css | 95 ++++++++- src/lib/default-schema.ts | 308 ++++++++++++++++++++++++++++++ src/lib/schema-types.ts | 57 ++++++ src/lib/schema-utils.ts | 189 ++++++++++++++++++ 14 files changed, 2094 insertions(+), 20 deletions(-) create mode 100644 .spark-initial-sha create mode 100644 PRD.md create mode 100644 example-schemas.json create mode 100644 src/components/FieldRenderer.tsx create mode 100644 src/components/ModelListView.tsx create mode 100644 src/components/RecordForm.tsx create mode 100644 src/components/SchemaEditor.tsx create mode 100644 src/lib/default-schema.ts create mode 100644 src/lib/schema-types.ts create mode 100644 src/lib/schema-utils.ts diff --git a/.spark-initial-sha b/.spark-initial-sha new file mode 100644 index 000000000..165eaccc1 --- /dev/null +++ b/.spark-initial-sha @@ -0,0 +1 @@ +a024526c87d7b9829fc5f702d15e3d3dec2b4557 diff --git a/PRD.md b/PRD.md new file mode 100644 index 000000000..f82887586 --- /dev/null +++ b/PRD.md @@ -0,0 +1,119 @@ +# Planning Guide + +A declarative admin panel generator that allows developers to define data models and UI configuration through JSON schemas, automatically generating a complete CRUD interface similar to Django's admin panel. + +**Experience Qualities**: +1. **Declarative** - Configuration-driven development where JSON schemas define the entire admin interface without manual component creation +2. **Intuitive** - Familiar Django-admin-style patterns that feel immediately recognizable to developers who've worked with backend admin panels +3. **Powerful** - Full-featured CRUD operations with filtering, sorting, validation, and relationships handled automatically from schema definitions + +**Complexity Level**: Complex Application (advanced functionality, likely with multiple views) +This is a code generation and admin panel system that dynamically creates fully functional interfaces from JSON schemas, including list views, detail views, forms, validation, and data persistence - requiring sophisticated state management and dynamic rendering. + +## Essential Features + +### Schema Definition System +- **Functionality**: Parse JSON schema files that define data models with fields, types, validation rules, and UI hints +- **Purpose**: Enable developers to define entire admin panels declaratively without writing component code +- **Trigger**: JSON schema files loaded at application startup or hot-reloaded during development +- **Progression**: Load JSON schema → Parse model definitions → Validate schema structure → Generate TypeScript types → Initialize data stores → Render admin interface +- **Success criteria**: Valid JSON schemas produce working admin panels; invalid schemas show clear error messages with schema validation feedback + +### Dynamic Model List View +- **Functionality**: Auto-generated table/list view showing all records for a model with sortable columns, filters, search, and pagination +- **Purpose**: Provide quick overview and management of all records in a data model +- **Trigger**: User selects a model from the navigation sidebar +- **Progression**: Select model → Load records from KV store → Render table with columns from schema → Apply filters/search/sort → Click row for detail view +- **Success criteria**: All defined fields display correctly; sorting, filtering, and search work; pagination handles large datasets; empty states guide users to create first record + +### Dynamic Form Generation +- **Functionality**: Automatically generate create/edit forms based on field types and validation rules in the schema +- **Purpose**: Eliminate boilerplate form code while ensuring data integrity through schema-defined validation +- **Trigger**: User clicks "Create New" button or "Edit" on existing record +- **Progression**: Open form dialog → Render fields based on schema → User inputs data → Validate on blur/submit → Save to KV store → Update list view → Show success toast +- **Success criteria**: All field types render appropriate inputs; validation rules enforced; error messages clear; optimistic updates feel instant + +### Relationship Management +- **Functionality**: Handle foreign keys and many-to-many relationships with select dropdowns and relationship tables +- **Purpose**: Support relational data models common in admin panels +- **Trigger**: Form fields defined with relationship types in schema +- **Progression**: Render relationship field → Load related model records → Display searchable select → Save relationship IDs → Update related records view +- **Success criteria**: Related records load and display; cascade operations work correctly; relationship changes persist + +### Field Type System +- **Functionality**: Support common field types (text, number, boolean, date, email, URL, select, textarea, rich text, file reference, relationship) +- **Purpose**: Cover the majority of admin panel use cases with appropriate input controls +- **Trigger**: Field type specified in schema +- **Progression**: Parse field type → Select appropriate input component → Apply type-specific validation → Render with schema-defined options +- **Success criteria**: Each field type has appropriate UI control; validation matches type; special types (date, color) use enhanced inputs + +## Edge Case Handling +- **Invalid Schema Structure**: Display detailed validation errors in a dev-friendly overlay with line numbers and suggestions +- **Missing Required Fields**: Prevent form submission and highlight missing fields with clear error messages +- **Circular Relationships**: Detect and warn about circular dependencies in schema definitions +- **Large Datasets**: Implement virtual scrolling and pagination for tables with 1000+ records +- **Concurrent Edits**: Show warnings when data has been modified since form opened +- **Migration Scenarios**: Handle schema changes gracefully with field mapping suggestions + +## Design Direction +The design should evoke efficiency, clarity, and developer familiarity - similar to the no-nonsense utility of Django admin but with modern polish and visual refinement. Think "power tool" rather than "pretty toy" - dense information displays, keyboard shortcuts, and rapid workflows prioritized over decorative elements. + +## Color Selection +A technical, code-editor-inspired palette with high contrast for data clarity and professional development tool aesthetic. + +- **Primary Color**: Deep indigo `oklch(0.45 0.15 265)` - Communicates technical sophistication and authority, used for primary actions and active states +- **Secondary Colors**: Cool gray `oklch(0.65 0.02 250)` for secondary UI elements and subtle backgrounds; Slate `oklch(0.25 0.03 250)` for sidebar and chrome +- **Accent Color**: Bright cyan `oklch(0.75 0.15 195)` - High-visibility color for CTAs, links, and "create new" actions that demand attention +- **Foreground/Background Pairings**: + - Primary (Deep Indigo): White text `oklch(0.98 0 0)` - Ratio 7.8:1 ✓ + - Background (Near White `oklch(0.98 0 0)`): Charcoal text `oklch(0.25 0 0)` - Ratio 14.2:1 ✓ + - Accent (Bright Cyan): Dark slate text `oklch(0.2 0.05 250)` - Ratio 8.1:1 ✓ + - Sidebar (Slate): Light gray text `oklch(0.85 0.01 250)` - Ratio 9.4:1 ✓ + +## Font Selection +Technical clarity with a code-adjacent aesthetic that reinforces the developer tool positioning while maintaining readability for dense data tables. + +- **Typographic Hierarchy**: + - H1 (Panel Title): Space Grotesk Bold/32px/tight letter spacing + - H2 (Section Headers): Space Grotesk Semibold/24px/normal spacing + - H3 (Field Labels): Space Grotesk Medium/14px/uppercase/wide letter spacing + - Body (Table Data): IBM Plex Sans Regular/15px/1.5 line height + - Code (IDs, Technical Values): JetBrains Mono Regular/14px/1.4 line height + - Small (Hints, Metadata): IBM Plex Sans Regular/13px/muted color + +## Animations +Animations should prioritize immediate feedback for data operations and subtle spatial awareness during navigation - instant response to clicks/inputs with 150ms micro-animations for state changes, 250ms smooth transitions between list/detail views, and purposeful loading states that communicate progress. + +## Component Selection +- **Components**: + - Table with Select, Checkbox, and Badge for list views + - Dialog for create/edit forms with Form, Input, Textarea, Select, Switch, Calendar components + - Sidebar for model navigation with collapsible groups + - Command palette (cmdk) for quick model/record search + - Breadcrumb for navigation context + - Tabs for organizing related model groups + - Sheet for sliding detail panels + - Sonner for success/error toasts + - Skeleton for loading states +- **Customizations**: + - Custom JSON schema editor with syntax highlighting + - Dynamic field renderer component that maps schema types to inputs + - Virtualized table component for large datasets + - Relationship selector with async search +- **States**: + - Tables: hover highlights entire row with subtle background shift, selected rows show accent border + - Buttons: primary actions use filled accent color with slight scale on press, secondary use outline + - Inputs: focused state shows accent border with subtle glow, error state shows destructive color + - Forms: dirty state indicators on modified fields +- **Icon Selection**: + - Phosphor icons throughout: List/Table for views, Plus for create, Pencil for edit, Trash for delete, MagnifyingGlass for search, Funnel for filters, ArrowsDownUp for sort, Database for models, FloppyDisk for save +- **Spacing**: + - Dense mode: p-2 for cells, p-4 for cards, gap-2 for tight groups + - Standard: p-4 for containers, p-6 for dialogs, gap-4 for form fields, gap-6 for sections + - Generous whitespace in sidebar (p-6) and around primary actions +- **Mobile**: + - Sidebar collapses to hamburger menu, stacks on small screens with slide-out drawer + - Tables switch to card-based layout with key fields only, expandable for full details + - Forms switch to full-screen sheets on mobile + - Touch-friendly 44px minimum tap targets on all interactive elements + - Bottom navigation bar for primary actions on mobile diff --git a/README.md b/README.md index 358beecf2..6dc46e959 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,222 @@ -# ✨ Welcome to Your Spark Template! -You've just launched your brand-new Spark Template Codespace — everything’s fired up and ready for you to explore, build, and create with Spark! +# Django-Style React Admin Panel Generator -This template is your blank canvas. It comes with a minimal setup to help you get started quickly with Spark development. +A declarative admin panel generator that creates full-featured CRUD interfaces from JSON schema definitions. Inspired by Django's admin panel, this tool lets you define data models and UI configuration declaratively without writing component code. -🚀 What's Inside? -- A clean, minimal Spark environment -- Pre-configured for local development -- Ready to scale with your ideas - -🧠 What Can You Do? +## Features -Right now, this is just a starting point — the perfect place to begin building and testing your Spark applications. +- **Declarative Schema Definition** - Define your entire data model in JSON +- **Automatic CRUD Generation** - List views, forms, validation automatically generated +- **Field Types** - String, text, number, boolean, date, datetime, email, URL, select, relations, JSON +- **Advanced Features** - Sorting, filtering, search, validation, relationships +- **Persistent Storage** - Data automatically saved using Spark KV storage +- **Live Schema Editing** - Edit schemas in real-time through the UI -🧹 Just Exploring? -No problem! If you were just checking things out and don’t need to keep this code: +## Quick Start -- Simply delete your Spark. -- Everything will be cleaned up — no traces left behind. +1. Launch the app +2. Use the sidebar to navigate between models +3. Click "Create New" to add records +4. Edit or delete records using the action buttons +5. Click "Edit Schema" to customize your data models -📄 License For Spark Template Resources +## Schema Structure -The Spark Template files and resources from GitHub are licensed under the terms of the MIT license, Copyright GitHub, Inc. +The schema is a JSON object with the following structure: + +```json +{ + "apps": [ + { + "name": "app_name", + "label": "App Label", + "models": [ + { + "name": "model_name", + "label": "Model Label", + "labelPlural": "Models", + "icon": "IconName", + "listDisplay": ["field1", "field2"], + "listFilter": ["field3"], + "searchFields": ["field1", "field2"], + "ordering": ["-field2"], + "fields": [ + { + "name": "field_name", + "type": "string", + "label": "Field Label", + "required": true, + "unique": false, + "default": "value", + "helpText": "Help text or array of strings", + "validation": { + "min": 0, + "max": 100, + "minLength": 3, + "maxLength": 200, + "pattern": "^[a-z]+$" + }, + "listDisplay": true, + "searchable": true, + "sortable": true, + "editable": true + } + ] + } + ] + } + ] +} +``` + +## Field Types + +### Basic Types +- **string** - Single-line text input +- **text** - Multi-line textarea +- **number** - Numeric input with min/max validation +- **boolean** - Switch/toggle control +- **email** - Email input with validation +- **url** - URL input with validation + +### Date/Time +- **date** - Date picker +- **datetime** - Date and time picker + +### Advanced Types +- **select** - Dropdown with predefined choices +- **relation** - Foreign key to another model +- **json** - JSON editor for complex data + +## Select Field Choices + +For select fields, define choices as an array: + +```json +{ + "name": "status", + "type": "select", + "choices": [ + { "value": "draft", "label": "Draft" }, + { "value": "published", "label": "Published" }, + { "value": "archived", "label": "Archived" } + ] +} +``` + +## Relationships + +Define relationships between models using the relation type: + +```json +{ + "name": "author", + "type": "relation", + "relatedModel": "author", + "required": true +} +``` + +The related model must exist in the same app. + +## Validation + +Add validation rules to fields: + +```json +{ + "validation": { + "min": 0, + "max": 100, + "minLength": 3, + "maxLength": 200, + "pattern": "^[a-z0-9-]+$" + } +} +``` + +## Help Text + +Provide help text as a string or array of strings: + +```json +{ + "helpText": "Single line help text" +} +``` + +Or for multi-line help: + +```json +{ + "helpText": [ + "First line of help", + "Second line of help" + ] +} +``` + +## List View Configuration + +Control which fields appear in the list view: + +```json +{ + "listDisplay": ["title", "author", "status", "publishedAt"], + "listFilter": ["status", "author"], + "searchFields": ["title", "content"], + "ordering": ["-publishedAt"] +} +``` + +- **listDisplay** - Fields to show in the table +- **listFilter** - Fields to offer as filters (select/boolean only) +- **searchFields** - Fields to search when using the search box +- **ordering** - Default sort order (prefix with `-` for descending) + +## Example Schemas + +See `example-schemas.json` for complete examples including: +- Blog with posts and authors +- Task manager with projects and tasks +- E-commerce with products and categories + +## Tips + +1. **Start Simple** - Begin with basic string and text fields, add complexity later +2. **Use Relations** - Connect related data with relation fields +3. **Add Validation** - Prevent bad data with field validation rules +4. **Leverage Defaults** - Set sensible defaults for better UX +5. **Help Text** - Guide users with helpful field descriptions +6. **Test Incrementally** - Edit and test schema changes one model at a time + +## Technical Details + +- Built with React, TypeScript, and Tailwind CSS +- Uses shadcn/ui components for consistent design +- Data persisted with Spark KV storage +- Framer Motion for smooth animations +- Full type safety with TypeScript + +## Keyboard Shortcuts + +- Click table headers to sort +- Use search box for quick filtering +- Forms validate on blur and submit + +## Limitations + +- Relations only work within the same app +- No many-to-many relationships (use JSON arrays) +- No file uploads (use URL fields to reference external files) +- Maximum recommended records per model: 1000 + +## Architecture + +The system consists of: +1. **Schema Parser** - Validates and processes JSON schemas +2. **Field Renderer** - Dynamically renders form inputs based on field types +3. **Model List View** - Table view with sorting, filtering, search +4. **Record Form** - Auto-generated create/edit forms with validation +5. **Schema Editor** - Live JSON editor for schema modifications + +All data is stored in the Spark KV store with keys like `records_appname_modelname`. diff --git a/example-schemas.json b/example-schemas.json new file mode 100644 index 000000000..a60b0edd5 --- /dev/null +++ b/example-schemas.json @@ -0,0 +1,290 @@ +{ + "description": "Example schema configurations for the Admin Panel Generator", + "examples": [ + { + "name": "Simple Blog", + "description": "Basic blog with posts and authors", + "schema": { + "apps": [ + { + "name": "blog", + "label": "Blog", + "models": [ + { + "name": "post", + "label": "Post", + "labelPlural": "Posts", + "listDisplay": ["title", "author", "status", "publishedAt"], + "fields": [ + { + "name": "id", + "type": "string", + "required": true, + "unique": true, + "editable": false + }, + { + "name": "title", + "type": "string", + "label": "Title", + "required": true, + "validation": { + "minLength": 3, + "maxLength": 200 + } + }, + { + "name": "content", + "type": "text", + "label": "Content", + "required": true + }, + { + "name": "author", + "type": "relation", + "label": "Author", + "required": true, + "relatedModel": "author" + }, + { + "name": "status", + "type": "select", + "label": "Status", + "required": true, + "default": "draft", + "choices": [ + { "value": "draft", "label": "Draft" }, + { "value": "published", "label": "Published" } + ] + }, + { + "name": "publishedAt", + "type": "datetime", + "label": "Published At" + } + ] + }, + { + "name": "author", + "label": "Author", + "labelPlural": "Authors", + "listDisplay": ["name", "email"], + "fields": [ + { + "name": "id", + "type": "string", + "required": true, + "unique": true, + "editable": false + }, + { + "name": "name", + "type": "string", + "label": "Name", + "required": true + }, + { + "name": "email", + "type": "email", + "label": "Email", + "required": true, + "unique": true + } + ] + } + ] + } + ] + } + }, + { + "name": "Task Manager", + "description": "Task management system with projects and tasks", + "schema": { + "apps": [ + { + "name": "tasks", + "label": "Task Manager", + "models": [ + { + "name": "project", + "label": "Project", + "labelPlural": "Projects", + "listDisplay": ["name", "status", "dueDate"], + "fields": [ + { + "name": "id", + "type": "string", + "required": true, + "editable": false + }, + { + "name": "name", + "type": "string", + "required": true + }, + { + "name": "description", + "type": "text" + }, + { + "name": "status", + "type": "select", + "default": "planning", + "choices": [ + { "value": "planning", "label": "Planning" }, + { "value": "active", "label": "Active" }, + { "value": "completed", "label": "Completed" } + ] + }, + { + "name": "dueDate", + "type": "date" + } + ] + }, + { + "name": "task", + "label": "Task", + "labelPlural": "Tasks", + "listDisplay": ["title", "project", "priority", "completed"], + "fields": [ + { + "name": "id", + "type": "string", + "required": true, + "editable": false + }, + { + "name": "title", + "type": "string", + "required": true + }, + { + "name": "description", + "type": "text" + }, + { + "name": "project", + "type": "relation", + "required": true, + "relatedModel": "project" + }, + { + "name": "priority", + "type": "select", + "default": "medium", + "choices": [ + { "value": "low", "label": "Low" }, + { "value": "medium", "label": "Medium" }, + { "value": "high", "label": "High" } + ] + }, + { + "name": "completed", + "type": "boolean", + "default": false + } + ] + } + ] + } + ] + } + }, + { + "name": "E-Commerce", + "description": [ + "Product catalog with categories and inventory", + "Includes price and stock management" + ], + "schema": { + "apps": [ + { + "name": "store", + "label": "Store", + "models": [ + { + "name": "category", + "label": "Category", + "labelPlural": "Categories", + "fields": [ + { + "name": "id", + "type": "string", + "required": true, + "editable": false + }, + { + "name": "name", + "type": "string", + "required": true + }, + { + "name": "description", + "type": "text" + } + ] + }, + { + "name": "product", + "label": "Product", + "labelPlural": "Products", + "listDisplay": ["name", "category", "price", "stock", "available"], + "fields": [ + { + "name": "id", + "type": "string", + "required": true, + "editable": false + }, + { + "name": "name", + "type": "string", + "required": true, + "validation": { + "minLength": 3 + } + }, + { + "name": "description", + "type": "text" + }, + { + "name": "category", + "type": "relation", + "required": true, + "relatedModel": "category" + }, + { + "name": "price", + "type": "number", + "required": true, + "validation": { + "min": 0 + }, + "helpText": "Price in USD" + }, + { + "name": "stock", + "type": "number", + "required": true, + "default": 0, + "validation": { + "min": 0 + } + }, + { + "name": "available", + "type": "boolean", + "default": true + } + ] + } + ] + } + ] + } + } + ] +} diff --git a/index.html b/index.html index f62002d97..118680ba7 100644 --- a/index.html +++ b/index.html @@ -4,9 +4,10 @@ - + Admin Panel Generator + diff --git a/src/App.tsx b/src/App.tsx index 98ef973c9..9ebec0244 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,123 @@ +import { useState } from 'react' +import { useKV } from '@github/spark/hooks' +import { Toaster } from '@/components/ui/sonner' +import { Button } from '@/components/ui/button' +import { ScrollArea } from '@/components/ui/scroll-area' +import { Separator } from '@/components/ui/separator' +import type { SchemaConfig } from '@/lib/schema-types' +import { defaultSchema } from '@/lib/default-schema' +import { getModelLabelPlural, getModelLabel } from '@/lib/schema-utils' +import { ModelListView } from '@/components/ModelListView' +import { SchemaEditor } from '@/components/SchemaEditor' +import { Database, Code, List } from '@phosphor-icons/react' + function App() { - return
+ const [schema, setSchema] = useKV('admin_schema', defaultSchema) + const [selectedApp, setSelectedApp] = useState(schema?.apps[0]?.name || '') + const [selectedModel, setSelectedModel] = useState(schema?.apps[0]?.models[0]?.name || '') + const [schemaEditorOpen, setSchemaEditorOpen] = useState(false) + + if (!schema) return null + + const currentApp = schema.apps.find(app => app.name === selectedApp) + const currentModel = currentApp?.models.find(model => model.name === selectedModel) + + return ( +
+ + +
+
+ {currentModel && ( +
+

+ {getModelLabelPlural(currentModel)} +

+

+ Manage {getModelLabel(currentModel).toLowerCase()} records +

+
+ )} +
+ +
+ {currentModel && currentApp ? ( + + ) : ( +
+

Select a model from the sidebar

+
+ )} +
+
+ + setSchemaEditorOpen(false)} + schema={schema} + onSave={setSchema} + /> + + +
+ ) } -export default App \ No newline at end of file +export default App diff --git a/src/components/FieldRenderer.tsx b/src/components/FieldRenderer.tsx new file mode 100644 index 000000000..9fdb3e11a --- /dev/null +++ b/src/components/FieldRenderer.tsx @@ -0,0 +1,209 @@ +import { Input } from '@/components/ui/input' +import { Textarea } from '@/components/ui/textarea' +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' +import { Switch } from '@/components/ui/switch' +import { Label } from '@/components/ui/label' +import type { FieldSchema, SchemaConfig } from '@/lib/schema-types' +import { getFieldLabel, getHelpText, findModel, getModelLabel } from '@/lib/schema-utils' +import { useKV } from '@github/spark/hooks' +import { getRecordsKey } from '@/lib/schema-utils' + +interface FieldRendererProps { + field: FieldSchema + value: any + onChange: (value: any) => void + error?: string + schema: SchemaConfig + currentApp: string +} + +export function FieldRenderer({ field, value, onChange, error, schema, currentApp }: FieldRendererProps) { + const label = getFieldLabel(field) + const helpText = getHelpText(field) + + const relatedRecordsKey = field.relatedModel ? getRecordsKey(currentApp, field.relatedModel) : 'dummy' + const [relatedModelRecords] = useKV(relatedRecordsKey, []) + + const relatedModel = field.type === 'relation' && field.relatedModel + ? findModel(schema, currentApp, field.relatedModel) + : null + + const renderInput = () => { + if (field.editable === false) { + return ( + + ) + } + + switch (field.type) { + case 'string': + case 'email': + case 'url': + return ( + onChange(e.target.value)} + placeholder={label} + className={error ? 'border-destructive' : ''} + /> + ) + + case 'text': + return ( +