diff --git a/DEPENDENCY_CLEANUP.md b/DEPENDENCY_CLEANUP.md
new file mode 100644
index 000000000..68cef8ce9
--- /dev/null
+++ b/DEPENDENCY_CLEANUP.md
@@ -0,0 +1,348 @@
+# Dependency Cleanup Plan
+
+**Created:** 2025-12-30
+**Status:** Planning Phase
+**Goal:** Remove unnecessary dependencies from package.json
+
+---
+
+## Current Dependencies Analysis
+
+### MUI Dependencies (TO REMOVE)
+
+**Location:** `frontends/nextjs/package.json`
+
+```json
+"@emotion/react": "^11.14.0", // MUI peer dependency
+"@emotion/styled": "^11.14.1", // MUI peer dependency
+"@mui/icons-material": "^7.3.6", // ~500KB - Replace with fakemui icons
+"@mui/material": "^7.3.6", // ~1MB - Replace with fakemui
+"@mui/x-data-grid": "^8.23.0", // Replace with custom table
+"@mui/x-date-pickers": "^8.23.0", // Replace with native date input
+```
+
+**Total Size:** ~2-3 MB
+**Status:** ❌ Ready to remove after migration complete
+
+---
+
+## Dependencies to Keep
+
+### Essential Next.js & React
+```json
+"next": "16.1.1", // ✅ Core framework
+"react": "19.2.3", // ✅ Core library
+"react-dom": "19.2.3", // ✅ Core library
+```
+
+### Icons
+```json
+"@phosphor-icons/react": "^2.1.10", // ❌ Remove - Using fakemui custom icons
+```
+
+**✅ DECISION:** Full fakemui custom SVG icon system
+**Action:** Remove @phosphor-icons/react after icon migration complete
+
+### Form Handling
+```json
+"@hookform/resolvers": "^5.2.2", // ✅ Keep - Zod integration
+"react-hook-form": "^7.69.0", // ✅ Keep - Form state management
+"zod": "^4.2.1", // ✅ Keep - Schema validation
+```
+
+### Data Fetching & State
+```json
+"@tanstack/react-query": "^5.90.12", // ✅ Keep - Server state
+```
+
+### Database
+```json
+"@prisma/client": "^7.2.0", // ✅ Keep - Database ORM
+"@prisma/adapter-better-sqlite3": "^7.2.0", // ✅ Keep - SQLite adapter
+"better-sqlite3": "^12.5.0", // ✅ Keep - SQLite driver
+```
+
+### Code Editor
+```json
+"@monaco-editor/react": "^4.7.0", // ✅ Keep - Code editor
+```
+
+### Utilities
+```json
+"date-fns": "^4.1.0", // ✅ Keep - Date utilities
+"marked": "^17.0.1", // ✅ Keep - Markdown parsing
+"uuid": "^13.0.0", // ✅ Keep - UUID generation
+"jszip": "^3.10.1", // ✅ Keep - ZIP handling
+```
+
+### Animation & Visualization
+```json
+"motion": "^12.6.2", // ✅ Keep - Animation library
+"recharts": "^3.6.0", // ✅ Keep - Charts
+"d3": "^7.9.0", // ✅ Keep - Data visualization
+"three": "^0.182.0", // ✅ Keep - 3D graphics
+```
+
+### Lua Integration
+```json
+"fengari-web": "^0.1.4", // ✅ Keep - Lua in browser
+"fengari-interop": "^0.1.4", // ✅ Keep - Lua/JS interop
+```
+
+### AWS S3
+```json
+"@aws-sdk/client-s3": "^3.958.0", // ✅ Keep - S3 client
+"@aws-sdk/lib-storage": "^3.958.0", // ✅ Keep - Multipart upload
+"@aws-sdk/s3-request-presigner": "^3.958.0", // ✅ Keep - Presigned URLs
+```
+
+### GitHub Integration
+```json
+"@octokit/core": "^7.0.6", // ✅ Keep - GitHub API
+"octokit": "^5.0.5", // ✅ Keep - GitHub SDK
+"@github/spark": ">=0.43.1 <1", // ⚠️ Evaluate - What is this?
+```
+
+**Action Needed:** Verify @github/spark usage
+
+### Error Handling & Notifications
+```json
+"react-error-boundary": "^6.0.0", // ✅ Keep - Error boundaries
+"sonner": "^2.0.7", // ✅ Keep - Toast notifications
+```
+
+### Misc
+```json
+"@next/third-parties": "^16.1.1", // ⚠️ Evaluate - Scripts loader
+"server-only": "^0.0.1", // ✅ Keep - Server-only marker
+"sharp": "^0.34.5", // ✅ Keep - Image optimization
+```
+
+---
+
+## Removal Plan
+
+### Phase 1: Immediate Removal (After fakemui complete)
+
+**Remove:**
+- `@mui/material` ^7.3.6
+- `@mui/icons-material` ^7.3.6
+- `@emotion/react` ^11.14.0
+- `@emotion/styled` ^11.14.1
+
+**Bundle Size Savings:** ~1.5-2 MB
+
+**Prerequisites:**
+- ✅ All MUI components migrated to fakemui
+- ✅ All MUI icons replaced with fakemui icons
+- ✅ Theme system migrated to CSS variables
+- ✅ CssBaseline replaced with fakemui reset
+
+### Phase 2: Advanced Components (After Lua packages)
+
+**Remove:**
+- `@mui/x-data-grid` ^8.23.0
+- `@mui/x-date-pickers` ^8.23.0
+
+**Bundle Size Savings:** ~500 KB
+
+**Prerequisites:**
+- ✅ DataGrid replaced with fakemui Table or Lua package
+- ✅ DatePickers replaced with native HTML5 or Lua package
+
+### Phase 3: Icon Consolidation ✅ APPROVED
+
+**Remove:**
+- `@phosphor-icons/react` ^2.1.10
+
+**Bundle Size Savings:** ~200 KB
+
+**Decision:** Using fakemui custom SVG icons only (no third-party icon library)
+
+**Prerequisites:**
+- ✅ All icons migrated to fakemui/icons
+- ✅ Icon inventory complete (50-100 icons)
+- ✅ Pattern established for adding new icons as needed
+
+---
+
+## Dependencies to Evaluate
+
+### @github/spark
+**Current Version:** >=0.43.1 <1
+**Purpose:** Unknown - needs investigation
+**Action:** Search codebase for usage
+**Decision:** Keep or remove based on usage
+
+### @next/third-parties
+**Current Version:** ^16.1.1
+**Purpose:** Third-party script loading (Google Analytics, etc.)
+**Action:** Check if actively used
+**Decision:** Keep if used, remove if not
+
+---
+
+## Post-Migration package.json
+
+**Estimated Dependencies After Cleanup:** 35-40 packages (down from 45)
+**Estimated Bundle Size Reduction:** 2-3 MB (15-25%)
+
+### Final State
+```json
+{
+ "dependencies": {
+ // Core
+ "next": "16.1.1",
+ "react": "19.2.3",
+ "react-dom": "19.2.3",
+
+ // Forms & Validation
+ "@hookform/resolvers": "^5.2.2",
+ "react-hook-form": "^7.69.0",
+ "zod": "^4.2.1",
+
+ // Data & State
+ "@tanstack/react-query": "^5.90.12",
+ "@prisma/client": "^7.2.0",
+ "@prisma/adapter-better-sqlite3": "^7.2.0",
+ "better-sqlite3": "^12.5.0",
+
+ // Editor & Code
+ "@monaco-editor/react": "^4.7.0",
+
+ // Utilities
+ "date-fns": "^4.1.0",
+ "marked": "^17.0.1",
+ "uuid": "^13.0.0",
+ "jszip": "^3.10.1",
+
+ // Visualization
+ "motion": "^12.6.2",
+ "recharts": "^3.6.0",
+ "d3": "^7.9.0",
+ "three": "^0.182.0",
+
+ // Lua
+ "fengari-web": "^0.1.4",
+ "fengari-interop": "^0.1.4",
+
+ // AWS
+ "@aws-sdk/client-s3": "^3.958.0",
+ "@aws-sdk/lib-storage": "^3.958.0",
+ "@aws-sdk/s3-request-presigner": "^3.958.0",
+
+ // GitHub
+ "@octokit/core": "^7.0.6",
+ "octokit": "^5.0.5",
+
+ // UI & Feedback
+ "react-error-boundary": "^6.0.0",
+ "sonner": "^2.0.7",
+
+ // Misc
+ "server-only": "^0.0.1",
+ "sharp": "^0.34.5"
+ }
+}
+```
+
+---
+
+## Removal Commands
+
+### Phase 1: MUI Removal
+```bash
+cd frontends/nextjs
+npm uninstall @mui/material @mui/icons-material @emotion/react @emotion/styled
+```
+
+### Phase 2: MUI X Components
+```bash
+npm uninstall @mui/x-data-grid @mui/x-date-pickers
+```
+
+### Phase 3: Phosphor Icons
+```bash
+npm uninstall @phosphor-icons/react
+```
+
+---
+
+## Verification Steps
+
+After each removal phase:
+
+1. **Build Test**
+ ```bash
+ npm run build
+ ```
+
+2. **Type Check**
+ ```bash
+ npm run typecheck
+ ```
+
+3. **Unit Tests**
+ ```bash
+ npm run test:unit
+ ```
+
+4. **E2E Tests**
+ ```bash
+ npm run test:e2e
+ ```
+
+5. **Bundle Analysis**
+ ```bash
+ # Check bundle size
+ npm run build
+ # Compare .next/static/chunks sizes
+ ```
+
+---
+
+## Risk Mitigation
+
+### Backup Strategy
+```bash
+# Before removal
+git checkout -b mui-removal-phase-1
+cp package.json package.json.backup
+npm list > installed-packages.txt
+```
+
+### Rollback Plan
+```bash
+# If issues arise
+git checkout main
+npm install
+```
+
+### Staged Rollout
+1. Remove MUI deps but keep code
+2. Test thoroughly
+3. If successful, proceed
+4. If issues, restore deps and investigate
+
+---
+
+## Success Metrics
+
+- ✅ Zero MUI imports in codebase
+- ✅ All tests passing
+- ✅ No build errors
+- ✅ Bundle size reduced 15-25%
+- ✅ No visual regressions
+- ✅ Performance metrics maintained or improved
+
+---
+
+**Next Actions:**
+1. Complete MUI migration (see MUI_ELIMINATION_PLAN.md)
+2. Search for @github/spark usage
+3. Check @next/third-parties usage
+4. Execute Phase 1 removal
+5. Verify and test
+6. Proceed to Phase 2
+
+**Last Updated:** 2025-12-30
diff --git a/FAKEMUI_STRATEGY.md b/FAKEMUI_STRATEGY.md
new file mode 100644
index 000000000..4300a2f63
--- /dev/null
+++ b/FAKEMUI_STRATEGY.md
@@ -0,0 +1,397 @@
+# Fakemui Strategy - Zero Dependency UI System
+
+**Created:** 2025-12-30
+**Status:** Active Development
+**Goal:** Complete UI independence with zero third-party UI dependencies
+
+---
+
+## Executive Summary
+
+**Decision:** ✅ Full fakemui UI system
+- Zero MUI dependencies
+- Zero Phosphor Icons dependency
+- Zero Emotion/styled-components
+- Custom SVG icon system
+- SCSS-based styling with CSS variables
+
+**Bundle Size Target:** Reduce by 2-3 MB (15-25%)
+
+---
+
+## Architecture
+
+```
+fakemui/
+├── icons/ # Custom SVG icon system (~1KB per icon)
+│ ├── Icon.tsx # Base icon component
+│ ├── Plus.tsx # Individual icon components
+│ ├── Trash.tsx
+│ └── ...
+├── fakemui/ # React/TypeScript components
+│ ├── inputs/ # Form inputs, buttons
+│ ├── surfaces/ # Cards, papers, dialogs
+│ ├── layout/ # Box, Stack, Grid, Container
+│ ├── data-display/ # Typography, tables, lists
+│ ├── feedback/ # Alerts, progress, skeletons
+│ ├── navigation/ # Tabs, breadcrumbs, menus
+│ ├── utils/ # Modals, portals, transitions
+│ ├── atoms/ # Text, Label, Panel
+│ ├── lab/ # Experimental components
+│ └── x/ # Advanced components
+├── styles/ # SCSS styling system
+│ ├── _variables.scss # CSS custom properties
+│ ├── base.scss # Base element styles
+│ ├── components.scss # Component styles
+│ ├── atoms/ # Atomic component styles
+│ ├── global/ # Global styles, reset
+│ ├── mixins/ # Reusable SCSS mixins
+│ └── themes/ # Theme variants
+└── index.ts # Barrel export
+
+Total: ~150 components, ~80 SCSS files
+```
+
+---
+
+## Icon Strategy
+
+### ✅ APPROVED: Custom SVG System
+
+**Approach:**
+- Create SVG components as needed
+- Source from Heroicons, Lucide, Phosphor
+- ~1KB per icon (gzipped)
+- Zero runtime dependencies
+- Full TypeScript support
+
+**Current Icons:** 7
+**Target Phase 2:** 27 (core set)
+**Target Phase 3:** 50-100 (full migration)
+
+**See:** [fakemui/icons/README.md](fakemui/icons/README.md)
+
+---
+
+## Component Migration Path
+
+### From MUI → Fakemui
+
+| MUI Component | Fakemui Replacement | Status |
+|---------------|---------------------|--------|
+| `@mui/material/Button` | `fakemui/inputs/Button` | ✅ Ready |
+| `@mui/material/TextField` | `fakemui/inputs/TextField` | ✅ Ready |
+| `@mui/material/Card` | `fakemui/surfaces/Card` | ✅ Ready |
+| `@mui/material/Box` | `fakemui/layout/Box` | ✅ Ready |
+| `@mui/material/Stack` | `fakemui/layout/Stack` | ✅ Ready |
+| `@mui/material/Typography` | `fakemui/data-display/Typography` | ✅ Ready |
+| `@mui/icons-material/*` | `fakemui/icons/*` | 🚧 7/100 |
+| `@mui/x-data-grid` | Lua package or custom | ⏳ Planned |
+| `@mui/x-date-pickers` | Native HTML5 or Lua | ⏳ Planned |
+
+### From Phosphor → Fakemui
+
+| Phosphor Icon | Fakemui Icon | Status |
+|---------------|--------------|--------|
+| `` | `` | ✅ Done |
+| `` | `` | ✅ Done |
+| `` | `` | ✅ Done |
+| `` | `` | ✅ Done |
+| `` | `` | ✅ Done |
+| `` | `` | ✅ Done |
+| `` | `` | ✅ Done |
+| Others (100+) | Add as needed | ⏳ Ongoing |
+
+---
+
+## Styling Strategy
+
+### CSS Variables (Theme System)
+
+**Current:** `fakemui/styles/_variables.scss`
+- 70+ CSS custom properties
+- 5 theme variants (light, dark, midnight, forest, ocean)
+- Runtime theme switching
+- No JavaScript required
+
+**Example:**
+```scss
+:root {
+ --color-primary: #1976d2;
+ --color-bg: #ffffff;
+ --color-text: #000000;
+ --font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto;
+ --spacing-md: 16px;
+ --radius-md: 8px;
+ --shadow-sm: 0 2px 4px rgba(0,0,0,0.1);
+}
+```
+
+### SCSS Modules
+
+**Pattern:**
+```tsx
+// Component.tsx
+import styles from './Component.module.scss'
+
+export const Component = () => (
+
+
Title
+
+)
+
+// Component.module.scss
+.root {
+ padding: var(--spacing-md);
+ background: var(--color-bg-paper);
+}
+
+.title {
+ color: var(--color-text);
+ font-size: var(--font-size-lg);
+}
+```
+
+### Reset (Replaces CssBaseline)
+
+**Location:** `fakemui/styles/global/_reset.scss`
+- Modern CSS reset
+- Typography defaults
+- Form element normalization
+- Focus visible styles
+- Accessibility defaults
+
+---
+
+## Import Strategy
+
+### Before (MUI)
+```tsx
+import { Button, Card, Stack, Box } from '@mui/material'
+import { Add, Delete, Edit } from '@mui/icons-material'
+import { DataGrid } from '@mui/x-data-grid'
+```
+
+### After (Fakemui)
+```tsx
+import { Button, Card, Stack, Box, Plus, Trash, Edit } from '@/fakemui'
+// DataGrid becomes Lua package
+```
+
+**Benefits:**
+- Single import path
+- No version conflicts
+- Full control over API
+- Tree-shakeable
+- TypeScript native
+
+---
+
+## Lua Package Strategy
+
+### Components → Lua Packages
+
+**Workflow Editor:**
+- Package: `@packages/workflow_editor`
+- Components: WorkflowEditor, WorkflowNodeCard, WorkflowSidebar, etc.
+- UI: Uses fakemui for basic components
+
+**GitHub Viewer:**
+- Package: `@packages/github_actions_viewer`
+- Components: GitHubActionsFetcher, RunList, AnalysisPanel, etc.
+- UI: Custom table with fakemui primitives
+
+**Data Grid:**
+- Package: `@packages/data_grid` (TBD)
+- Replaces: `@mui/x-data-grid`
+- Features: Sorting, filtering, pagination, virtual scrolling
+
+**Date Picker:**
+- Option 1: Native HTML5 ``
+- Option 2: Lua package `@packages/date_picker`
+- Decision: Start with native, create package if needed
+
+---
+
+## Migration Phases
+
+### Phase 1: Foundation ✅ 60% Complete
+- [x] Create fakemui icon system
+- [x] Migrate LuaBlocksEditor
+- [x] Enhance CSS reset
+- [x] Document strategy
+- [ ] Update providers (remove MUI)
+- [ ] Finalize theme system
+
+### Phase 2: Atomic Components 🚧 Ready
+Target: 20 components
+- Button, IconButton, Fab
+- Input, Textarea, Select
+- Checkbox, Radio, Switch, Slider
+- Avatar, Badge, Icon, Label, Link, Text
+- Skeleton, Spinner, Progress, Tooltip, Separator
+
+### Phase 3: Molecules ⏳ Planned
+Target: 18 components
+- Card, Alert, Accordion
+- Breadcrumb, NavGroup, NavItem, NavLink
+- Dialog, DropdownMenu, Popover
+- RadioGroup, Select, ToggleGroup
+- Tabs components
+
+### Phase 4: Organisms ⏳ Planned
+Target: 22 components
+- Navigation, Sidebar, Pagination
+- AlertDialog, Command, Sheet
+- Form, Table
+
+### Phase 5: Lua Packages ⏳ Planned
+- workflow_editor
+- github_actions_viewer
+- (others as needed)
+
+### Phase 6: Cleanup ⏳ Planned
+- Remove all MUI dependencies
+- Remove Phosphor dependency
+- Final verification
+
+---
+
+## Performance Targets
+
+### Bundle Size
+| Phase | Current | Target | Savings |
+|-------|---------|--------|---------|
+| Before | ~12 MB | - | - |
+| After Phase 1 | ~11.5 MB | ~11.5 MB | 500 KB |
+| After Phase 2 | ~11 MB | ~10.5 MB | 1.5 MB |
+| After Phase 3 | ~10 MB | ~9.5 MB | 2.5 MB |
+
+### Load Time
+- First Contentful Paint (FCP): < 1.5s
+- Largest Contentful Paint (LCP): < 2.5s
+- Time to Interactive (TTI): < 3.5s
+
+### Runtime Performance
+- Zero styled-components runtime overhead
+- No Emotion runtime
+- Pure CSS for styling
+- Minimal JavaScript
+
+---
+
+## Developer Experience
+
+### Type Safety
+```tsx
+import { Button, ButtonProps } from '@/fakemui'
+
+// Full TypeScript support
+const MyButton: React.FC = (props) => (
+
+)
+```
+
+### Customization
+```tsx
+// CSS variables for theming
+
+
+// Class names for custom styling
+
+
+// SCSS modules
+
+```
+
+### Documentation
+- Component props in TypeScript
+- README for icon system
+- Migration guides
+- Code examples
+
+---
+
+## Success Metrics
+
+✅ **Technical:**
+- Zero `@mui/*` imports
+- Zero `@phosphor-icons/react` imports
+- Zero `@emotion/*` imports
+- 100% TypeScript coverage
+- All tests passing
+- No build errors
+
+✅ **Performance:**
+- 15-25% bundle size reduction
+- Maintained or improved load times
+- No visual regressions
+- Accessibility maintained
+
+✅ **Developer:**
+- Simple import pattern
+- Easy to extend
+- Well documented
+- Type-safe
+
+---
+
+## Risk Mitigation
+
+### Testing Strategy
+1. Unit tests for all components
+2. Visual regression tests
+3. Integration tests
+4. E2E tests
+5. Performance benchmarks
+
+### Rollback Plan
+```bash
+# Create backup branch
+git checkout -b mui-backup
+
+# If issues arise
+git checkout mui-backup
+npm install
+```
+
+### Staged Migration
+- Keep MUI installed during migration
+- Migrate page by page or component by component
+- Feature flags for new components
+- Gradual rollout
+
+---
+
+## Next Actions
+
+**Immediate:**
+1. ✅ Approve icon strategy (DONE)
+2. Update app providers to remove MUI
+3. Start Phase 2: Atomic components
+
+**This Week:**
+1. Migrate Button component
+2. Migrate Input component
+3. Add 10 more icons
+
+**This Month:**
+1. Complete Phase 2 (atoms)
+2. Start Phase 3 (molecules)
+3. Create first Lua package
+
+---
+
+## References
+
+- [MUI_ELIMINATION_PLAN.md](MUI_ELIMINATION_PLAN.md) - Detailed migration plan
+- [DEPENDENCY_CLEANUP.md](DEPENDENCY_CLEANUP.md) - Package.json cleanup
+- [fakemui/icons/README.md](fakemui/icons/README.md) - Icon system guide
+- [fakemui/SCSS_REVIEW.md](fakemui/SCSS_REVIEW.md) - SCSS architecture review
+- [fakemui/TYPESCRIPT_MIGRATION.md](fakemui/TYPESCRIPT_MIGRATION.md) - TypeScript patterns
+
+---
+
+**Last Updated:** 2025-12-30
+**Status:** Active - Phase 1 in progress
+**Next Review:** After Phase 2 completion
diff --git a/MUI_ELIMINATION_PLAN.md b/MUI_ELIMINATION_PLAN.md
index 64a7f51a8..11f808472 100644
--- a/MUI_ELIMINATION_PLAN.md
+++ b/MUI_ELIMINATION_PLAN.md
@@ -18,7 +18,7 @@
## Phase Overview
```
-Phase 1: Foundation (Weeks 1-2) ✓ Partially Complete
+Phase 1: Foundation (Weeks 1-2) ✅ 60% Complete
Phase 2: Atomic Components (Weeks 2-3) ⏳ Ready to start
Phase 3: Basic UI (Weeks 3-4) ⏳ Pending
Phase 4: Complex UI (Weeks 4-6) ⏳ Pending
@@ -26,6 +26,22 @@ Phase 5: Lua Packages (Weeks 6-8) ⏳ Pending
Phase 6: Cleanup (Week 8+) ⏳ Pending
```
+## Recent Progress (2025-12-30)
+
+**✅ Completed:**
+- Created fakemui icon system (7 icons)
+- Migrated LuaBlocksEditor to fakemui (8 files)
+- Enhanced fakemui CSS reset to replace CssBaseline
+- Documented all 160+ MUI files for migration
+- Created DEPENDENCY_CLEANUP.md plan
+- Audited package.json dependencies
+
+**📋 Ready to Execute:**
+- ✅ Icon strategy: Full fakemui custom icons (no Phosphor)
+- Phase 1: Update providers to remove MUI
+- Phase 2: Begin atomic component migration
+- Phase 3: Expand fakemui icon library as needed
+
---
## Category Breakdown
@@ -465,11 +481,12 @@ Phase 6: Cleanup (Week 8+) ⏳ Pending
| **Custom SVG** | Custom | ~5KB | Full control, zero deps | Manual maintenance |
| **Radix Icons** | 300+ | ~25KB | Radix-aligned | Smaller set |
-### Recommendation: Custom SVG System
-- **Why:** Already started with fakemui/icons
-- **Approach:** Add icons as needed from Heroicons/Lucide
-- **Benefit:** Zero dependencies, full control, tiny bundle
-- **Process:** Copy SVG paths when needed
+### ✅ DECISION: Custom SVG System (fakemui/icons)
+- **Why:** Full control, zero dependencies, already started
+- **Approach:** Add icons as needed from Heroicons/Lucide/Phosphor
+- **Benefit:** Zero dependencies, full control, tiny bundle (~1KB per icon)
+- **Process:** Copy SVG paths when needed, create TSX components
+- **Status:** APPROVED - Moving forward with this approach
---
diff --git a/fakemui/icons/README.md b/fakemui/icons/README.md
new file mode 100644
index 000000000..47e79b527
--- /dev/null
+++ b/fakemui/icons/README.md
@@ -0,0 +1,293 @@
+# Fakemui Icon System
+
+**Status:** Active Development
+**Philosophy:** Zero dependencies, add icons as needed
+**Source:** Copy from Heroicons, Lucide, Phosphor as required
+
+---
+
+## Quick Start
+
+```tsx
+import { Plus, Trash, Copy } from '@/fakemui'
+
+function MyComponent() {
+ return (
+
+ )
+}
+```
+
+---
+
+## Available Icons
+
+Current icon count: **7 icons**
+
+### Actions
+- `Plus` - Add, create, new
+- `Trash` - Delete, remove
+- `Copy` - Duplicate, copy
+
+### Navigation
+- `ArrowUp` - Move up, scroll up
+- `ArrowDown` - Move down, scroll down
+- `ArrowClockwise` - Refresh, reload, retry
+
+### Files
+- `FloppyDisk` - Save, export
+
+---
+
+## Icon Props
+
+All icons support the following props:
+
+```tsx
+interface IconProps extends React.SVGAttributes {
+ size?: number | string // Default: 24
+ weight?: 'thin' | 'light' | 'regular' | 'bold' // Default: 'regular'
+ // Plus all standard SVG attributes (className, onClick, etc.)
+}
+```
+
+### Examples
+
+```tsx
+// Size variants
+ // Small
+ // Default
+ // Large
+
+// Weight variants
+ // strokeWidth: 1
+ // strokeWidth: 1.5
+ // strokeWidth: 2 (default)
+ // strokeWidth: 2.5
+
+// Custom styling
+
+
+ console.log('clicked')} />
+```
+
+---
+
+## Adding New Icons
+
+### Step 1: Find the SVG
+
+**Recommended Sources:**
+- [Heroicons](https://heroicons.com/) - Tailwind's icon set
+- [Lucide](https://lucide.dev/) - Beautiful, consistent icons
+- [Phosphor Icons](https://phosphoricons.com/) - Flexible icon family
+
+### Step 2: Create the Component
+
+Create a new file in `fakemui/icons/IconName.tsx`:
+
+```tsx
+import React from 'react'
+import { Icon, IconProps } from './Icon'
+
+export const IconName = (props: IconProps) => (
+
+ {/* Paste SVG paths here */}
+
+
+
+)
+```
+
+**Important:**
+- Use viewBox="0 0 256 256" coordinate system (Phosphor standard)
+- Icons should be stroke-based, not fill-based
+- Remove any fill/stroke attributes from paths (Icon component handles this)
+
+### Step 3: Export from index.ts
+
+Add to `fakemui/icons/index.ts`:
+
+```ts
+export { IconName } from './IconName'
+```
+
+### Step 4: Export from main barrel
+
+Add to `fakemui/index.ts`:
+
+```ts
+// Icons
+export {
+ Icon,
+ Plus,
+ Trash,
+ Copy,
+ // ... existing icons
+ IconName, // Add your new icon
+} from './icons'
+```
+
+### Step 5: Update this README
+
+Add your icon to the "Available Icons" section above.
+
+---
+
+## Icon Conversion Guide
+
+### From Phosphor Icons
+
+Phosphor uses `viewBox="0 0 256 256"` - perfect for our system!
+
+```tsx
+// Source: https://phosphoricons.com/
+
+
+// fakemui component:
+export const Plus = (props: IconProps) => (
+
+
+
+
+)
+```
+
+### From Heroicons
+
+Heroicons uses `viewBox="0 0 24 24"` - needs scaling!
+
+```tsx
+// Source: https://heroicons.com/
+
+
+// Scale by 10.67 (256/24):
+export const Plus = (props: IconProps) => (
+
+
+
+)
+```
+
+### From Lucide
+
+Lucide uses `viewBox="0 0 24 24"` - same scaling as Heroicons.
+
+```tsx
+// Source: https://lucide.dev/
+
+
+// Scale coordinates:
+export const Plus = (props: IconProps) => (
+
+
+
+
+)
+```
+
+---
+
+## Icon Naming Conventions
+
+- **PascalCase** for component names: `ArrowUp`, `CheckCircle`, `UserPlus`
+- **Descriptive** names: prefer `Trash` over `Delete`, `Copy` over `Duplicate`
+- **Consistent** with existing patterns: `ArrowUp/Down/Left/Right`
+- **Action-oriented**: `Plus` (not `Add`), `Trash` (not `Remove`)
+
+---
+
+## Migration Progress
+
+### Phase 1: Core Actions (7/7) ✅
+- [x] Plus
+- [x] Trash
+- [x] Copy
+- [x] ArrowUp
+- [x] ArrowDown
+- [x] ArrowClockwise
+- [x] FloppyDisk
+
+### Phase 2: Common Icons (0/20) 🚧
+- [ ] Check
+- [ ] X (Close)
+- [ ] ChevronUp/Down/Left/Right (4 icons)
+- [ ] Search
+- [ ] Settings
+- [ ] User
+- [ ] Menu
+- [ ] Eye/EyeSlash
+- [ ] Edit (Pencil)
+- [ ] Calendar
+- [ ] Clock
+- [ ] Mail
+- [ ] Bell
+- [ ] Star
+- [ ] Heart
+- [ ] Share
+
+### Phase 3: Specialized Icons (0/30+) ⏳
+Add as needed based on component migration
+
+---
+
+## Icon Size Guidelines
+
+| Size | Use Case | Example |
+|------|----------|---------|
+| 12px | Tiny badges, indicators | Status dots |
+| 16px | Small UI elements | Inline icons, table cells |
+| 20px | Default UI | Buttons, inputs, cards |
+| 24px | Standard size | Menu items, toolbars |
+| 32px | Large UI | Headers, hero sections |
+| 48px+ | Feature icons | Landing pages, empty states |
+
+---
+
+## Performance Notes
+
+- Each icon is ~1KB gzipped
+- Tree-shakeable (only bundle icons you use)
+- No runtime dependencies
+- SSR-friendly
+- TypeScript definitions included
+
+---
+
+## Comparison to Icon Libraries
+
+| Library | Size (full) | Size (10 icons) | Dependencies |
+|---------|-------------|-----------------|--------------|
+| **fakemui** | ~10KB | ~10KB | Zero |
+| Phosphor Icons | 500KB | ~50KB | React |
+| Lucide React | 300KB | ~30KB | React |
+| Heroicons | 200KB | ~20KB | React |
+| MUI Icons | 1MB+ | ~100KB | MUI, Emotion |
+
+**Winner:** fakemui - smallest bundle, zero deps, full control
+
+---
+
+## Future Enhancements
+
+- [ ] Animated icon variants (spin, pulse, etc.)
+- [ ] Icon sprite system for even better performance
+- [ ] Auto-generate icons from Figma
+- [ ] Visual icon gallery/documentation
+- [ ] Dark mode variants (if needed)
+
+---
+
+**Last Updated:** 2025-12-30
+**Maintainer:** Metabuilder Team
diff --git a/packages/admin_dialog/seed/scripts/init.lua b/packages/admin_dialog/seed/scripts/init.lua
index 8b63ad3ec..1fa6daeb4 100644
--- a/packages/admin_dialog/seed/scripts/init.lua
+++ b/packages/admin_dialog/seed/scripts/init.lua
@@ -1,9 +1,19 @@
-- Admin Dialog initialization
+
+---@class AdminDialog
+---@field name string
+---@field version string
local M = {}
M.name = "admin_dialog"
M.version = "1.0.0"
+---@class InitResult
+---@field name string
+---@field version string
+---@field loaded boolean
+
+---@return InitResult
function M.init()
return {
name = M.name,
diff --git a/packages/admin_dialog/seed/scripts/settings.lua b/packages/admin_dialog/seed/scripts/settings.lua
index bd8fb1c8f..a99679e26 100644
--- a/packages/admin_dialog/seed/scripts/settings.lua
+++ b/packages/admin_dialog/seed/scripts/settings.lua
@@ -1,6 +1,14 @@
-- Admin settings dialog
+
+---@class SettingsDialog
local M = {}
+---@class UIComponent
+---@field type string
+---@field props? table
+---@field children? table
+
+---@return UIComponent
function M.render_general()
return {
type = "dialog",
@@ -17,6 +25,7 @@ function M.render_general()
}
end
+---@return UIComponent
function M.render_security()
return {
type = "dialog",
diff --git a/packages/admin_dialog/seed/scripts/settings/general.lua b/packages/admin_dialog/seed/scripts/settings/general.lua
index 599ee3b6b..418d403b8 100644
--- a/packages/admin_dialog/seed/scripts/settings/general.lua
+++ b/packages/admin_dialog/seed/scripts/settings/general.lua
@@ -1,4 +1,17 @@
-- Admin settings general section
+
+---@class SettingsSection
+---@field type string
+---@field id string
+---@field title string
+---@field fields SettingsField[]
+
+---@class SettingsField
+---@field id string
+---@field type string
+---@field label string
+
+---@return SettingsSection
local function general_settings()
return {
type = "settings_section",
diff --git a/packages/admin_dialog/seed/scripts/settings/init.lua b/packages/admin_dialog/seed/scripts/settings/init.lua
index 957607a20..9f68cdbf0 100644
--- a/packages/admin_dialog/seed/scripts/settings/init.lua
+++ b/packages/admin_dialog/seed/scripts/settings/init.lua
@@ -1,4 +1,8 @@
-- Admin settings module
+
+---@class SettingsModule
+---@field general function
+---@field security function
local settings = {
general = require("settings.general"),
security = require("settings.security")
diff --git a/packages/admin_dialog/seed/scripts/settings/security.lua b/packages/admin_dialog/seed/scripts/settings/security.lua
index be699850c..6445cb702 100644
--- a/packages/admin_dialog/seed/scripts/settings/security.lua
+++ b/packages/admin_dialog/seed/scripts/settings/security.lua
@@ -1,4 +1,17 @@
-- Admin settings security section
+
+---@class SettingsSection
+---@field type string
+---@field id string
+---@field title string
+---@field fields SettingsField[]
+
+---@class SettingsField
+---@field id string
+---@field type string
+---@field label string
+
+---@return SettingsSection
local function security_settings()
return {
type = "settings_section",
diff --git a/packages/admin_dialog/seed/scripts/user.lua b/packages/admin_dialog/seed/scripts/user.lua
index 694cb7547..0ad06c2a9 100644
--- a/packages/admin_dialog/seed/scripts/user.lua
+++ b/packages/admin_dialog/seed/scripts/user.lua
@@ -1,6 +1,20 @@
-- User management dialog
+
+---@class UserDialog
local M = {}
+---@class User
+---@field username string
+---@field email string
+---@field role string
+---@field active boolean
+
+---@class UIComponent
+---@field type string
+---@field props? table
+---@field children? table
+
+---@return UIComponent
function M.render_create()
return {
type = "dialog",
@@ -17,6 +31,8 @@ function M.render_create()
}
end
+---@param user User
+---@return UIComponent
function M.render_edit(user)
return {
type = "dialog",
diff --git a/packages/dashboard/seed/scripts/init.lua b/packages/dashboard/seed/scripts/init.lua
index 64b9a9b18..7f9f7e88b 100644
--- a/packages/dashboard/seed/scripts/init.lua
+++ b/packages/dashboard/seed/scripts/init.lua
@@ -1,3 +1,15 @@
+---@class DashboardScripts
local M = {}
+
+---@class InstallContext
+---@field version string
+
+---@class InstallResult
+---@field message string
+---@field version string
+
+---@param ctx InstallContext
+---@return InstallResult
function M.on_install(ctx) return { message = "Dashboard installed", version = ctx.version } end
+
return M
diff --git a/packages/dashboard/seed/scripts/layout.lua b/packages/dashboard/seed/scripts/layout.lua
index cec555eb6..1b8b543e6 100644
--- a/packages/dashboard/seed/scripts/layout.lua
+++ b/packages/dashboard/seed/scripts/layout.lua
@@ -1,5 +1,20 @@
+---@class Layout
local M = {}
+---@class UIComponent
+---@field type string
+---@field props? table
+---@field children? table
+
+---@class LayoutProps
+---@field header? table
+---@field footer? table
+---@field sidebar? table
+---@field children? table
+---@field className? string
+
+---@param props LayoutProps
+---@return UIComponent
function M.standard(props)
return {
type = "Box",
@@ -16,6 +31,8 @@ function M.standard(props)
}
end
+---@param props LayoutProps
+---@return UIComponent
function M.with_sidebar(props)
return {
type = "Flex",
diff --git a/packages/dashboard/seed/scripts/layout/flex.lua b/packages/dashboard/seed/scripts/layout/flex.lua
index a82499e20..24a9a1ffe 100644
--- a/packages/dashboard/seed/scripts/layout/flex.lua
+++ b/packages/dashboard/seed/scripts/layout/flex.lua
@@ -1,4 +1,15 @@
-- Dashboard flex layout
+
+---@class FlexLayoutConfig
+---@field type string
+---@field direction string
+---@field gap number
+---@field align string
+
+---@param direction? string Direction of flex layout (default: "row")
+---@param gap? number Gap between items in pixels (default: 16)
+---@param align? string Alignment of items (default: "stretch")
+---@return FlexLayoutConfig
local function flex(direction, gap, align)
return {
type = "flex",
diff --git a/packages/dashboard/seed/scripts/layout/grid.lua b/packages/dashboard/seed/scripts/layout/grid.lua
index 020a2efc3..ef4130709 100644
--- a/packages/dashboard/seed/scripts/layout/grid.lua
+++ b/packages/dashboard/seed/scripts/layout/grid.lua
@@ -1,4 +1,15 @@
-- Dashboard grid layout
+
+---@class GridLayoutConfig
+---@field type string
+---@field columns number
+---@field rows? number
+---@field gap number
+
+---@param columns? number Number of columns (default: 3)
+---@param rows? number Number of rows (optional)
+---@param gap? number Gap between items in pixels (default: 16)
+---@return GridLayoutConfig
local function grid(columns, rows, gap)
return {
type = "grid",
diff --git a/packages/dashboard/seed/scripts/layout/init.lua b/packages/dashboard/seed/scripts/layout/init.lua
index 337c2c3cb..7d69bac2a 100644
--- a/packages/dashboard/seed/scripts/layout/init.lua
+++ b/packages/dashboard/seed/scripts/layout/init.lua
@@ -1,4 +1,11 @@
-- Dashboard layout module
+
+---@class LayoutModule
+---@field grid fun(columns: number?, rows: number?, gap: number?): LayoutConfig
+---@field flex fun(direction: string?, gap: number?, align: string?): LayoutConfig
+---@field section fun(title: string, children: table?): LayoutConfig
+
+---@type LayoutModule
local layout = {
grid = require("layout.grid"),
flex = require("layout.flex"),
diff --git a/packages/dashboard/seed/scripts/layout/section.lua b/packages/dashboard/seed/scripts/layout/section.lua
index 33d5f9f8d..5a0395b2b 100644
--- a/packages/dashboard/seed/scripts/layout/section.lua
+++ b/packages/dashboard/seed/scripts/layout/section.lua
@@ -1,4 +1,13 @@
-- Dashboard section layout
+
+---@class SectionLayoutConfig
+---@field type string
+---@field title string
+---@field children table
+
+---@param title string Section title
+---@param children? table Child elements (default: {})
+---@return SectionLayoutConfig
local function section(title, children)
return {
type = "section",
diff --git a/packages/dashboard/seed/scripts/stats.lua b/packages/dashboard/seed/scripts/stats.lua
index 943c0324b..1d05d3967 100644
--- a/packages/dashboard/seed/scripts/stats.lua
+++ b/packages/dashboard/seed/scripts/stats.lua
@@ -1,5 +1,20 @@
+---@class Stats
local M = {}
+---@class UIComponent
+---@field type string
+---@field props? table
+---@field children? table
+
+---@class StatCardProps
+---@field label string
+---@field value number|string
+---@field change? string
+---@field positive? boolean
+---@field className? string
+
+---@param props StatCardProps
+---@return UIComponent
function M.card(props)
return {
type = "Card",
@@ -21,6 +36,8 @@ function M.card(props)
}
end
+---@param stats StatCardProps[]
+---@return UIComponent
function M.grid(stats)
local items = {}
for _, s in ipairs(stats) do
diff --git a/packages/dashboard/seed/scripts/stats/card.lua b/packages/dashboard/seed/scripts/stats/card.lua
index 6bae658bc..c0dbc1c3f 100644
--- a/packages/dashboard/seed/scripts/stats/card.lua
+++ b/packages/dashboard/seed/scripts/stats/card.lua
@@ -1,4 +1,17 @@
-- Dashboard stat card component
+
+---@class StatCardConfig
+---@field type string
+---@field title string
+---@field value string|number
+---@field icon? string
+---@field trend? table
+
+---@param title string Card title
+---@param value string|number Card value to display
+---@param icon? string Optional icon identifier
+---@param trend? table Optional trend indicator data
+---@return StatCardConfig
local function stat_card(title, value, icon, trend)
return {
type = "stat_card",
diff --git a/packages/dashboard/seed/scripts/stats/init.lua b/packages/dashboard/seed/scripts/stats/init.lua
index 6960028e8..002557ffd 100644
--- a/packages/dashboard/seed/scripts/stats/init.lua
+++ b/packages/dashboard/seed/scripts/stats/init.lua
@@ -1,4 +1,11 @@
-- Dashboard stats module
+
+---@class StatsModule
+---@field card fun(title: string, value: string|number, icon: string?, trend: table?): StatCardConfig
+---@field row fun(stats: table): StatRowConfig
+---@field trend fun(direction: string, value: string): TrendIndicatorConfig
+
+---@type StatsModule
local stats = {
card = require("stats.card"),
row = require("stats.row"),
diff --git a/packages/dashboard/seed/scripts/stats/row.lua b/packages/dashboard/seed/scripts/stats/row.lua
index 8f06daa79..2658426f3 100644
--- a/packages/dashboard/seed/scripts/stats/row.lua
+++ b/packages/dashboard/seed/scripts/stats/row.lua
@@ -1,4 +1,13 @@
-- Dashboard stat row layout
+
+---@class StatRowConfig
+---@field type string
+---@field layout string
+---@field gap number
+---@field children table
+
+---@param stats table Array of stat components to display in a row
+---@return StatRowConfig
local function stat_row(stats)
return {
type = "row",
diff --git a/packages/data_table/seed/scripts/columns.lua b/packages/data_table/seed/scripts/columns.lua
index fbf1a98cc..1ee210464 100644
--- a/packages/data_table/seed/scripts/columns.lua
+++ b/packages/data_table/seed/scripts/columns.lua
@@ -1,6 +1,48 @@
-- Column definition utilities
+
+---@class Columns
local M = {}
+---@class TextColumn
+---@field type "text"
+---@field id string Column identifier
+---@field label string Column header label
+---@field width string Column width (e.g., "auto", "100px")
+---@field sortable boolean Whether the column is sortable
+
+---@class NumberColumn
+---@field type "number"
+---@field id string Column identifier
+---@field label string Column header label
+---@field width string Column width (e.g., "100px")
+---@field sortable boolean Whether the column is sortable
+---@field align "right" Text alignment
+
+---@class DateColumn
+---@field type "date"
+---@field id string Column identifier
+---@field label string Column header label
+---@field format string Date format string (e.g., "YYYY-MM-DD")
+---@field sortable boolean Whether the column is sortable
+
+---@class Action
+---@field label string Action button label
+---@field handler string Action handler name
+
+---@class ActionColumn
+---@field type "actions"
+---@field id string Column identifier
+---@field label string Column header label (typically empty)
+---@field width string Column width (e.g., "120px")
+---@field actions Action[] Array of actions
+
+---@alias Column TextColumn | NumberColumn | DateColumn | ActionColumn
+
+---Create a text column definition
+---@param id string Column identifier
+---@param label string Column header label
+---@param width? string Column width (default: "auto")
+---@return TextColumn
function M.text_column(id, label, width)
return {
type = "text",
@@ -11,6 +53,11 @@ function M.text_column(id, label, width)
}
end
+---Create a number column definition
+---@param id string Column identifier
+---@param label string Column header label
+---@param width? string Column width (default: "100px")
+---@return NumberColumn
function M.number_column(id, label, width)
return {
type = "number",
@@ -22,6 +69,11 @@ function M.number_column(id, label, width)
}
end
+---Create a date column definition
+---@param id string Column identifier
+---@param label string Column header label
+---@param format? string Date format string (default: "YYYY-MM-DD")
+---@return DateColumn
function M.date_column(id, label, format)
return {
type = "date",
@@ -32,6 +84,10 @@ function M.date_column(id, label, format)
}
end
+---Create an action column definition
+---@param id string Column identifier
+---@param actions? Action[] Array of actions (default: {})
+---@return ActionColumn
function M.action_column(id, actions)
return {
type = "actions",
diff --git a/packages/data_table/seed/scripts/columns/text.lua b/packages/data_table/seed/scripts/columns/text.lua
index bdf8fa080..7ac0a4ea3 100644
--- a/packages/data_table/seed/scripts/columns/text.lua
+++ b/packages/data_table/seed/scripts/columns/text.lua
@@ -1,4 +1,17 @@
-- Text column definition
+
+---@class TextColumn
+---@field type "text"
+---@field id string Column identifier
+---@field label string Column header label
+---@field width string Column width (e.g., "auto", "100px")
+---@field sortable boolean Whether the column is sortable
+
+---Create a text column definition
+---@param id string Column identifier
+---@param label string Column header label
+---@param width? string Column width (default: "auto")
+---@return TextColumn
local function text_column(id, label, width)
return {
type = "text",
diff --git a/packages/data_table/seed/scripts/init.lua b/packages/data_table/seed/scripts/init.lua
index 2baeda206..5513ec7ab 100644
--- a/packages/data_table/seed/scripts/init.lua
+++ b/packages/data_table/seed/scripts/init.lua
@@ -1,9 +1,20 @@
-- Data Table initialization
+
+---@class DataTable
+---@field name string
+---@field version string
local M = {}
M.name = "data_table"
M.version = "1.0.0"
+---@class DataTableInitResult
+---@field name string
+---@field version string
+---@field loaded boolean
+
+---Initialize the data table module
+---@return DataTableInitResult
function M.init()
return {
name = M.name,
diff --git a/packages/data_table/seed/scripts/pagination.lua b/packages/data_table/seed/scripts/pagination.lua
index e592bd79d..d25c62f63 100644
--- a/packages/data_table/seed/scripts/pagination.lua
+++ b/packages/data_table/seed/scripts/pagination.lua
@@ -1,6 +1,33 @@
-- Pagination utilities
+
+---@class Pagination
local M = {}
+---@class PaginationState
+---@field total integer Total number of items
+---@field page integer Current page number (1-indexed)
+---@field per_page integer Items per page
+---@field pages integer Total number of pages
+---@field has_prev boolean Whether there is a previous page
+---@field has_next boolean Whether there is a next page
+
+---@class PaginationProps
+---@field current integer Current page number
+---@field total integer Total number of pages
+---@field show_prev boolean Whether to show previous button
+---@field show_next boolean Whether to show next button
+---@field on_prev string Event handler name for previous button
+---@field on_next string Event handler name for next button
+
+---@class PaginationComponent
+---@field type "pagination"
+---@field props PaginationProps
+
+---Calculate pagination state
+---@param total integer Total number of items
+---@param page integer Current page number (1-indexed)
+---@param per_page integer Items per page
+---@return PaginationState
function M.calculate(total, page, per_page)
local pages = math.ceil(total / per_page)
return {
@@ -13,6 +40,9 @@ function M.calculate(total, page, per_page)
}
end
+---Render pagination component
+---@param pagination PaginationState
+---@return PaginationComponent
function M.render(pagination)
return {
type = "pagination",
diff --git a/packages/data_table/seed/scripts/rows.lua b/packages/data_table/seed/scripts/rows.lua
index 16f8bbda2..5549239ff 100644
--- a/packages/data_table/seed/scripts/rows.lua
+++ b/packages/data_table/seed/scripts/rows.lua
@@ -1,6 +1,31 @@
-- Row rendering utilities
+
+---@class Rows
local M = {}
+---@class TextCell
+---@field type "text"
+---@field content string Cell content
+---@field align? "right" Text alignment (optional)
+
+---@class ActionsCell
+---@field type "actions"
+---@field buttons Action[] Action buttons for the cell
+
+---@alias Cell TextCell | ActionsCell
+
+---@class Row
+---@field index integer Row index (1-indexed)
+---@field cells Cell[] Array of rendered cells
+---@field selected boolean Whether the row is selected
+
+---@class RowData
+---@field [string] any Key-value pairs representing row data
+
+---Render a single cell based on column type
+---@param column Column Column definition
+---@param value any Cell value
+---@return Cell
function M.render_cell(column, value)
if column.type == "date" then
return { type = "text", content = value }
@@ -13,6 +38,11 @@ function M.render_cell(column, value)
end
end
+---Render a single row with all its cells
+---@param columns Column[] Array of column definitions
+---@param data RowData Row data object
+---@param index integer Row index (1-indexed)
+---@return Row
function M.render_row(columns, data, index)
local cells = {}
for _, col in ipairs(columns) do
@@ -25,6 +55,10 @@ function M.render_row(columns, data, index)
}
end
+---Render multiple rows from data list
+---@param columns Column[] Array of column definitions
+---@param data_list RowData[] Array of row data objects
+---@return Row[]
function M.render_rows(columns, data_list)
local rows = {}
for i, data in ipairs(data_list) do
diff --git a/packages/form_builder/seed/scripts/fields.lua b/packages/form_builder/seed/scripts/fields.lua
index 988bff6df..d857368c0 100644
--- a/packages/form_builder/seed/scripts/fields.lua
+++ b/packages/form_builder/seed/scripts/fields.lua
@@ -1,5 +1,39 @@
+---@class Fields
local M = {}
+---@class UIComponent
+---@field type string
+---@field props? table
+---@field children? UIComponent[]
+
+---@class TextFieldProps
+---@field name string
+---@field label? string
+---@field placeholder? string
+---@field required? boolean
+
+---@class EmailFieldProps
+---@field name string
+---@field label? string
+
+---@class PasswordFieldProps
+---@field name string
+---@field label? string
+
+---@class NumberFieldProps
+---@field name string
+---@field label? string
+---@field min? number
+---@field max? number
+
+---@class TextAreaFieldProps
+---@field name string
+---@field label? string
+---@field placeholder? string
+---@field rows? number
+
+---@param props TextFieldProps
+---@return UIComponent
function M.text(props)
return {
type = "Box",
@@ -10,6 +44,8 @@ function M.text(props)
}
end
+---@param props EmailFieldProps
+---@return UIComponent
function M.email(props)
return {
type = "Box",
@@ -20,6 +56,8 @@ function M.email(props)
}
end
+---@param props PasswordFieldProps
+---@return UIComponent
function M.password(props)
return {
type = "Box",
@@ -30,6 +68,8 @@ function M.password(props)
}
end
+---@param props NumberFieldProps
+---@return UIComponent
function M.number(props)
return {
type = "Box",
@@ -40,6 +80,8 @@ function M.number(props)
}
end
+---@param props TextAreaFieldProps
+---@return UIComponent
function M.textarea(props)
return {
type = "Box",
diff --git a/packages/form_builder/seed/scripts/init.lua b/packages/form_builder/seed/scripts/init.lua
index 129974c10..917e9f5d4 100644
--- a/packages/form_builder/seed/scripts/init.lua
+++ b/packages/form_builder/seed/scripts/init.lua
@@ -1,3 +1,15 @@
+---@class FormBuilder
local M = {}
+
+---@class InstallContext
+---@field version string
+
+---@class InstallResult
+---@field message string
+---@field version string
+
+---@param ctx InstallContext
+---@return InstallResult
function M.on_install(ctx) return { message = "Form Builder installed", version = ctx.version } end
+
return M
diff --git a/packages/nav_menu/seed/scripts/init.lua b/packages/nav_menu/seed/scripts/init.lua
index 7a9bfe874..4b96bf593 100644
--- a/packages/nav_menu/seed/scripts/init.lua
+++ b/packages/nav_menu/seed/scripts/init.lua
@@ -1,3 +1,17 @@
+---@class NavMenuModule
local M = {}
-function M.on_install(ctx) return { message = "Nav Menu installed", version = ctx.version } end
+
+---@class InstallContext
+---@field version string
+
+---@class InstallResult
+---@field message string
+---@field version string
+
+---@param ctx InstallContext
+---@return InstallResult
+function M.on_install(ctx)
+ return { message = "Nav Menu installed", version = ctx.version }
+end
+
return M
diff --git a/packages/nav_menu/seed/scripts/items/divider.lua b/packages/nav_menu/seed/scripts/items/divider.lua
index e3fc71ba4..3454e1034 100644
--- a/packages/nav_menu/seed/scripts/items/divider.lua
+++ b/packages/nav_menu/seed/scripts/items/divider.lua
@@ -1,4 +1,9 @@
-- Nav menu divider component
+
+---@class MenuDivider
+---@field type string
+
+---@return MenuDivider
local function menu_divider()
return {
type = "divider"
diff --git a/packages/nav_menu/seed/scripts/items/group.lua b/packages/nav_menu/seed/scripts/items/group.lua
index c31bec9c3..060a66e7c 100644
--- a/packages/nav_menu/seed/scripts/items/group.lua
+++ b/packages/nav_menu/seed/scripts/items/group.lua
@@ -1,4 +1,15 @@
-- Nav menu group component
+
+---@class MenuGroup
+---@field type string
+---@field label string
+---@field icon? string
+---@field children table
+
+---@param label string
+---@param children? table
+---@param icon? string
+---@return MenuGroup
local function menu_group(label, children, icon)
return {
type = "menu_group",
diff --git a/packages/nav_menu/seed/scripts/items/init.lua b/packages/nav_menu/seed/scripts/items/init.lua
index c3200eb50..c805d9cd4 100644
--- a/packages/nav_menu/seed/scripts/items/init.lua
+++ b/packages/nav_menu/seed/scripts/items/init.lua
@@ -1,4 +1,9 @@
-- Nav menu items module
+
+---@class MenuItemsModule
+---@field item fun(label: string, path: string, icon?: string): MenuItemData
+---@field group fun(label: string, children?: table, icon?: string): MenuGroup
+---@field divider fun(): MenuDivider
local items = {
item = require("items.item"),
group = require("items.group"),
diff --git a/packages/nav_menu/seed/scripts/items/item.lua b/packages/nav_menu/seed/scripts/items/item.lua
index 961dc5a25..1fc60a82b 100644
--- a/packages/nav_menu/seed/scripts/items/item.lua
+++ b/packages/nav_menu/seed/scripts/items/item.lua
@@ -1,4 +1,15 @@
-- Nav menu item component
+
+---@class MenuItemData
+---@field type string
+---@field label string
+---@field path string
+---@field icon? string
+
+---@param label string
+---@param path string
+---@param icon? string
+---@return MenuItemData
local function menu_item(label, path, icon)
return {
type = "menu_item",
diff --git a/packages/nav_menu/seed/scripts/menu.lua b/packages/nav_menu/seed/scripts/menu.lua
index 2e46a8f1e..799f0497d 100644
--- a/packages/nav_menu/seed/scripts/menu.lua
+++ b/packages/nav_menu/seed/scripts/menu.lua
@@ -1,6 +1,28 @@
local check = require("check")
+
+---@class MenuModule
local M = {}
+---@class UIComponent
+---@field type string
+---@field props? table
+---@field children? table
+
+---@class MenuItem
+---@field label string
+---@field path? string
+---@field minLevel? number
+---@field children? MenuItem[]
+
+---@class User
+---@field level? number
+
+---@class MenuProps
+---@field items MenuItem[]
+---@field user User
+
+---@param props MenuProps
+---@return UIComponent
function M.render(props)
local items = {}
for _, item in ipairs(props.items or {}) do
@@ -15,11 +37,16 @@ function M.render(props)
}
end
+---@param user User
+---@param item MenuItem
+---@return boolean
function M.can_show(user, item)
if not item.minLevel then return true end
return check.can_access(user, item.minLevel)
end
+---@param item MenuItem
+---@return UIComponent
function M.item(item)
if item.children then
return {
@@ -33,6 +60,8 @@ function M.item(item)
return { type = "Button", props = { variant = "ghost", text = item.label, onClick = "navigate", data = item.path } }
end
+---@param children MenuItem[]
+---@return UIComponent[]
function M.sub_items(children)
local items = {}
for _, c in ipairs(children) do
diff --git a/packages/nav_menu/seed/scripts/sidebar.lua b/packages/nav_menu/seed/scripts/sidebar.lua
index 62e5fa01f..d32833715 100644
--- a/packages/nav_menu/seed/scripts/sidebar.lua
+++ b/packages/nav_menu/seed/scripts/sidebar.lua
@@ -1,5 +1,22 @@
+---@class SidebarModule
local M = {}
+---@class UIComponent
+---@field type string
+---@field props? table
+---@field children? table
+
+---@class SidebarItem
+---@field label string
+---@field path string
+
+---@class SidebarProps
+---@field items SidebarItem[]
+---@field currentPath? string
+---@field title? string
+
+---@param props SidebarProps
+---@return UIComponent
function M.render(props)
local items = {}
for _, item in ipairs(props.items or {}) do
@@ -15,6 +32,8 @@ function M.render(props)
}
end
+---@param props SidebarProps
+---@return UIComponent
function M.header(props)
return {
type = "Box",
@@ -25,6 +44,9 @@ function M.header(props)
}
end
+---@param item SidebarItem
+---@param currentPath? string
+---@return UIComponent
function M.item(item, currentPath)
local active = currentPath == item.path
return {
diff --git a/packages/notification_center/seed/scripts/init.lua b/packages/notification_center/seed/scripts/init.lua
index a182cfb20..e3b67c0a9 100644
--- a/packages/notification_center/seed/scripts/init.lua
+++ b/packages/notification_center/seed/scripts/init.lua
@@ -1,9 +1,19 @@
-- Notification Center initialization
+
+---@class NotificationCenter
+---@field name string
+---@field version string
local M = {}
M.name = "notification_center"
M.version = "1.0.0"
+---@class NotificationCenterInfo
+---@field name string
+---@field version string
+---@field loaded boolean
+
+---@return NotificationCenterInfo
function M.init()
return {
name = M.name,
diff --git a/packages/notification_center/seed/scripts/list.lua b/packages/notification_center/seed/scripts/list.lua
index af9f7bf0d..fdd7e6218 100644
--- a/packages/notification_center/seed/scripts/list.lua
+++ b/packages/notification_center/seed/scripts/list.lua
@@ -1,6 +1,25 @@
-- Notification list utilities
+
+---@class NotificationListUtils
local M = {}
+---@class Notification
+---@field id string|number
+---@field title string
+---@field message string
+---@field created_at string|number
+---@field read? boolean
+---@field icon? string
+
+---@class UIComponent
+---@field type string
+---@field props? table
+---@field children? table
+---@field content? string
+---@field variant? string
+
+---@param notification Notification
+---@return UIComponent
function M.render_item(notification)
return {
type = "notification_item",
@@ -15,6 +34,8 @@ function M.render_item(notification)
}
end
+---@param notifications Notification[]
+---@return UIComponent
function M.render_list(notifications)
local items = {}
for _, n in ipairs(notifications) do
@@ -26,6 +47,8 @@ function M.render_list(notifications)
}
end
+---@param count number
+---@return UIComponent|nil
function M.render_badge(count)
if count > 0 then
return {
diff --git a/packages/notification_center/seed/scripts/list/init.lua b/packages/notification_center/seed/scripts/list/init.lua
index e0a745c2a..8e76c2bff 100644
--- a/packages/notification_center/seed/scripts/list/init.lua
+++ b/packages/notification_center/seed/scripts/list/init.lua
@@ -1,4 +1,8 @@
-- Notification list module
+
+---@class NotificationListModule
+---@field item fun(id: string|number, title: string, message: string, timestamp: string|number, read?: boolean): UIComponent
+---@field container fun(notifications?: table[]): UIComponent
local list = {
item = require("list.item"),
container = require("list.container")
diff --git a/packages/notification_center/seed/scripts/summary.lua b/packages/notification_center/seed/scripts/summary.lua
index 086b00229..ead7b328d 100644
--- a/packages/notification_center/seed/scripts/summary.lua
+++ b/packages/notification_center/seed/scripts/summary.lua
@@ -1,5 +1,9 @@
-- Notification summary card component logic
local json = require("json")
+
+---@class NotificationSummary
+---@field severityClasses table
+---@field defaultItems SummaryItem[]
local M = {}
-- Load config from JSON file
@@ -7,7 +11,35 @@ local config = json.load("summary.json")
M.severityClasses = config.severityClasses
M.defaultItems = config.defaultItems
+---@class SummaryItem
+---@field label string
+---@field count? number
+---@field severity? "info"|"success"|"warning"|"error"
+---@field hint? string
+
+---@class EnrichedSummaryItem
+---@field label string
+---@field count number
+---@field severity "info"|"success"|"warning"|"error"
+---@field hint? string
+---@field classes string
+
+---@class SummaryProps
+---@field title? string
+---@field subtitle? string
+---@field totalLabel? string
+---@field items? SummaryItem[]
+
+---@class SummaryData
+---@field title string
+---@field subtitle? string
+---@field totalLabel string
+---@field total number
+---@field items EnrichedSummaryItem[]
+
-- Calculate total from items
+---@param items SummaryItem[]
+---@return number
function M.calculateTotal(items)
local total = 0
for _, item in ipairs(items) do
@@ -20,23 +52,27 @@ function M.calculateTotal(items)
end
-- Get severity class for an item
+---@param severity? "info"|"success"|"warning"|"error"
+---@return string
function M.getSeverityClass(severity)
return M.severityClasses[severity or "info"] or M.severityClasses.info
end
-- Prepare summary data
+---@param props SummaryProps
+---@return SummaryData
function M.prepareSummary(props)
local title = props.title or "Notification Summary"
local subtitle = props.subtitle
local totalLabel = props.totalLabel or "Total"
local items = props.items
-
+
if not items or #items == 0 then
items = M.defaultItems
end
-
+
local total = M.calculateTotal(items)
-
+
-- Enrich items with severity classes
local enrichedItems = {}
for i, item in ipairs(items) do
@@ -48,7 +84,7 @@ function M.prepareSummary(props)
classes = M.getSeverityClass(item.severity)
}
end
-
+
return {
title = title,
subtitle = subtitle,
diff --git a/packages/notification_center/seed/scripts/toast.lua b/packages/notification_center/seed/scripts/toast.lua
index fd4bfe393..545a97cb3 100644
--- a/packages/notification_center/seed/scripts/toast.lua
+++ b/packages/notification_center/seed/scripts/toast.lua
@@ -1,6 +1,18 @@
-- Toast notification utilities
+
+---@class ToastUtils
local M = {}
+---@class Toast
+---@field type string
+---@field variant "info"|"success"|"warning"|"error"
+---@field message string
+---@field duration number
+---@field icon string
+
+---@param message string
+---@param duration? number
+---@return Toast
function M.success(message, duration)
return {
type = "toast",
@@ -11,6 +23,9 @@ function M.success(message, duration)
}
end
+---@param message string
+---@param duration? number
+---@return Toast
function M.error(message, duration)
return {
type = "toast",
@@ -21,6 +36,9 @@ function M.error(message, duration)
}
end
+---@param message string
+---@param duration? number
+---@return Toast
function M.warning(message, duration)
return {
type = "toast",
@@ -31,6 +49,9 @@ function M.warning(message, duration)
}
end
+---@param message string
+---@param duration? number
+---@return Toast
function M.info(message, duration)
return {
type = "toast",
diff --git a/packages/stream_cast/seed/scripts/lua/audience_pulse.lua b/packages/stream_cast/seed/scripts/lua/audience_pulse.lua
index 3bec8cbf1..521865951 100644
--- a/packages/stream_cast/seed/scripts/lua/audience_pulse.lua
+++ b/packages/stream_cast/seed/scripts/lua/audience_pulse.lua
@@ -1,5 +1,17 @@
+---@class AudiencePulse
local M = {}
+---@class Metrics
+---@field messagesPerMinute? number
+---@field reactionsPerMinute? number
+---@field viewers? number
+
+---@class PulseResult
+---@field score number
+---@field tier "surging"|"steady"|"cooling"
+
+---@param metrics Metrics
+---@return PulseResult
function M.score(metrics)
local messages = metrics.messagesPerMinute or 0
local reactions = metrics.reactionsPerMinute or 0
diff --git a/packages/stream_cast/seed/scripts/lua/init.lua b/packages/stream_cast/seed/scripts/lua/init.lua
index 9d1afc233..f563b8d17 100644
--- a/packages/stream_cast/seed/scripts/lua/init.lua
+++ b/packages/stream_cast/seed/scripts/lua/init.lua
@@ -1,9 +1,23 @@
+---@class StreamCast
local M = {}
+---@class InstallContext
+---@field version? string
+
+---@class InstallResult
+---@field message string
+---@field version? string
+
+---@class UninstallResult
+---@field message string
+
+---@param context InstallContext
+---@return InstallResult
function M.on_install(context)
return { message = "Stream Cast installed", version = context.version }
end
+---@return UninstallResult
function M.on_uninstall()
return { message = "Stream Cast removed" }
end
diff --git a/packages/stream_cast/seed/scripts/lua/scene_router.lua b/packages/stream_cast/seed/scripts/lua/scene_router.lua
index 1e121e4d4..5470fe90c 100644
--- a/packages/stream_cast/seed/scripts/lua/scene_router.lua
+++ b/packages/stream_cast/seed/scripts/lua/scene_router.lua
@@ -1,11 +1,15 @@
+---@class SceneRouter
local M = {}
+---@type table
local routes = {
intro = "studio_a",
main = "studio_b",
qa = "studio_c"
}
+---@param scene string
+---@return string
function M.route(scene)
return routes[scene] or "studio_b"
end
diff --git a/packages/stream_cast/seed/scripts/lua/schedule.lua b/packages/stream_cast/seed/scripts/lua/schedule.lua
index f6592e012..df2cf340b 100644
--- a/packages/stream_cast/seed/scripts/lua/schedule.lua
+++ b/packages/stream_cast/seed/scripts/lua/schedule.lua
@@ -1,5 +1,12 @@
+---@class Schedule
local M = {}
+---@class ScheduleEntry
+---@field scene string
+
+---@param schedule ScheduleEntry[]
+---@param current_index? number
+---@return string?
function M.next_scene(schedule, current_index)
local index = current_index or 1
local entry = schedule[index]
diff --git a/packages/ui_auth/seed/scripts/denied.lua b/packages/ui_auth/seed/scripts/denied.lua
index 3a71b3113..6e5f65b9a 100644
--- a/packages/ui_auth/seed/scripts/denied.lua
+++ b/packages/ui_auth/seed/scripts/denied.lua
@@ -1,5 +1,19 @@
+---@class AccessDenied
local M = {}
+---@class DeniedProps
+---@field title? string
+---@field description? string
+---@field actionLabel? string
+---@field onAction? string
+
+---@class UIComponent
+---@field type string
+---@field props? table
+---@field children? table
+
+---@param props DeniedProps
+---@return UIComponent
function M.render(props)
return {
type = "Stack",
diff --git a/packages/ui_auth/seed/scripts/gate.lua b/packages/ui_auth/seed/scripts/gate.lua
index febf8549c..a17194882 100644
--- a/packages/ui_auth/seed/scripts/gate.lua
+++ b/packages/ui_auth/seed/scripts/gate.lua
@@ -1,6 +1,28 @@
local check = require("check")
+
+---@class AuthGate
local M = {}
+---@class User
+---@field id string
+---@field level? number
+
+---@class GateContext
+---@field user? User
+---@field requiredLevel? number
+---@field children? table
+
+---@class CheckResult
+---@field allowed boolean
+---@field reason? string
+---@field redirect? string
+
+---@class UIComponent
+---@field type string
+---@field props? table
+
+---@param ctx GateContext
+---@return CheckResult
function M.check(ctx)
if not ctx.user then
return { allowed = false, reason = "not_authenticated", redirect = "/login" }
@@ -11,6 +33,8 @@ function M.check(ctx)
return { allowed = true }
end
+---@param ctx GateContext
+---@return UIComponent|table
function M.wrap(ctx)
local result = M.check(ctx)
if not result.allowed then
diff --git a/packages/ui_auth/seed/scripts/init.lua b/packages/ui_auth/seed/scripts/init.lua
index ea0f850a5..75536fd34 100644
--- a/packages/ui_auth/seed/scripts/init.lua
+++ b/packages/ui_auth/seed/scripts/init.lua
@@ -1,3 +1,15 @@
+---@class UIAuth
local M = {}
+
+---@class InstallContext
+---@field version string
+
+---@class InstallResult
+---@field message string
+---@field version string
+
+---@param ctx InstallContext
+---@return InstallResult
function M.on_install(ctx) return { message = "Auth UI installed", version = ctx.version } end
+
return M
diff --git a/packages/ui_dialogs/seed/scripts/alert.lua b/packages/ui_dialogs/seed/scripts/alert.lua
index 211652af7..2e3ed77a7 100644
--- a/packages/ui_dialogs/seed/scripts/alert.lua
+++ b/packages/ui_dialogs/seed/scripts/alert.lua
@@ -1,5 +1,19 @@
+---@class Alert
local M = {}
+---@class AlertProps
+---@field open boolean
+---@field variant? "info"|"warning"|"error"
+---@field title string
+---@field message string
+
+---@class UIComponent
+---@field type string
+---@field props? table
+---@field children? table
+
+---@param props AlertProps
+---@return UIComponent
function M.render(props)
local variant = props.variant or "info"
local icon = variant == "error" and "alert-circle" or variant == "warning" and "alert-triangle" or "info"
diff --git a/packages/ui_dialogs/seed/scripts/confirm.lua b/packages/ui_dialogs/seed/scripts/confirm.lua
index f2accd33e..d89a3707e 100644
--- a/packages/ui_dialogs/seed/scripts/confirm.lua
+++ b/packages/ui_dialogs/seed/scripts/confirm.lua
@@ -1,5 +1,20 @@
+---@class Confirm
local M = {}
+---@class ConfirmProps
+---@field open boolean
+---@field title? string
+---@field message string
+---@field confirmText? string
+---@field destructive? boolean
+
+---@class UIComponent
+---@field type string
+---@field props? table
+---@field children? table
+
+---@param props ConfirmProps
+---@return UIComponent
function M.render(props)
return {
type = "Dialog",
diff --git a/packages/ui_dialogs/seed/scripts/init.lua b/packages/ui_dialogs/seed/scripts/init.lua
index c5e9a3edd..5d1be5c9c 100644
--- a/packages/ui_dialogs/seed/scripts/init.lua
+++ b/packages/ui_dialogs/seed/scripts/init.lua
@@ -1,3 +1,15 @@
+---@class UIDialogs
local M = {}
+
+---@class InstallContext
+---@field version string
+
+---@class InstallResult
+---@field message string
+---@field version string
+
+---@param ctx InstallContext
+---@return InstallResult
function M.on_install(ctx) return { message = "UI Dialogs installed", version = ctx.version } end
+
return M
diff --git a/packages/ui_footer/seed/scripts/init.lua b/packages/ui_footer/seed/scripts/init.lua
index 24917828b..af33f4df7 100644
--- a/packages/ui_footer/seed/scripts/init.lua
+++ b/packages/ui_footer/seed/scripts/init.lua
@@ -1,5 +1,15 @@
+---@class UIFooter
local M = {}
+---@class InstallContext
+---@field version string
+
+---@class InstallResult
+---@field message string
+---@field version string
+
+---@param ctx InstallContext
+---@return InstallResult
function M.on_install(ctx)
return { message = "App Footer installed", version = ctx.version }
end
diff --git a/packages/ui_footer/seed/scripts/render.lua b/packages/ui_footer/seed/scripts/render.lua
index 2a989d3d2..801a7b187 100644
--- a/packages/ui_footer/seed/scripts/render.lua
+++ b/packages/ui_footer/seed/scripts/render.lua
@@ -1,5 +1,16 @@
+---@class FooterRender
local M = {}
+---@class FooterProps
+---@field text? string
+
+---@class UIComponent
+---@field type string
+---@field props? table
+---@field children? table
+
+---@param props FooterProps
+---@return UIComponent
function M.render(props)
local text = props.text or "© 2024 MetaBuilder. Built with visual workflows."
return {
diff --git a/packages/ui_header/seed/scripts/init.lua b/packages/ui_header/seed/scripts/init.lua
index 36c588368..68146394d 100644
--- a/packages/ui_header/seed/scripts/init.lua
+++ b/packages/ui_header/seed/scripts/init.lua
@@ -1,5 +1,15 @@
+---@class UIHeader
local M = {}
+---@class InstallContext
+---@field version string
+
+---@class InstallResult
+---@field message string
+---@field version string
+
+---@param ctx InstallContext
+---@return InstallResult
function M.on_install(ctx)
return { message = "App Header installed", version = ctx.version }
end
diff --git a/packages/ui_home/seed/scripts/init.lua b/packages/ui_home/seed/scripts/init.lua
index c099a4971..3884052ef 100644
--- a/packages/ui_home/seed/scripts/init.lua
+++ b/packages/ui_home/seed/scripts/init.lua
@@ -1,9 +1,23 @@
+---@class UIHome
local M = {}
+---@class InstallContext
+---@field version string
+
+---@class InstallResult
+---@field message string
+---@field version string
+
+---@class UninstallResult
+---@field message string
+
+---@param ctx InstallContext
+---@return InstallResult
function M.on_install(ctx)
return { message = "Home Page installed", version = ctx.version }
end
+---@return UninstallResult
function M.on_uninstall()
return { message = "Home Page removed" }
end
diff --git a/packages/ui_intro/seed/scripts/init.lua b/packages/ui_intro/seed/scripts/init.lua
index a916b646c..b7b013bd7 100644
--- a/packages/ui_intro/seed/scripts/init.lua
+++ b/packages/ui_intro/seed/scripts/init.lua
@@ -1,5 +1,15 @@
+---@class UIIntro
local M = {}
+---@class InstallContext
+---@field version string
+
+---@class InstallResult
+---@field message string
+---@field version string
+
+---@param ctx InstallContext
+---@return InstallResult
function M.on_install(ctx)
return { message = "Intro Section installed", version = ctx.version }
end
diff --git a/packages/ui_level2/seed/scripts/init.lua b/packages/ui_level2/seed/scripts/init.lua
index ba6f2947a..3afef8aa6 100644
--- a/packages/ui_level2/seed/scripts/init.lua
+++ b/packages/ui_level2/seed/scripts/init.lua
@@ -1,3 +1,15 @@
+---@class UILevel2
local M = {}
+
+---@class InstallContext
+---@field version string
+
+---@class InstallResult
+---@field message string
+---@field version string
+
+---@param ctx InstallContext
+---@return InstallResult
function M.on_install(ctx) return { message = "Level 2 installed", version = ctx.version } end
+
return M
diff --git a/packages/ui_level3/seed/scripts/init.lua b/packages/ui_level3/seed/scripts/init.lua
index a5e116d85..3c7b597b8 100644
--- a/packages/ui_level3/seed/scripts/init.lua
+++ b/packages/ui_level3/seed/scripts/init.lua
@@ -1,3 +1,15 @@
+---@class UILevel3
local M = {}
+
+---@class InstallContext
+---@field version string
+
+---@class InstallResult
+---@field message string
+---@field version string
+
+---@param ctx InstallContext
+---@return InstallResult
function M.on_install(ctx) return { message = "Level 3 installed", version = ctx.version } end
+
return M
diff --git a/packages/ui_level4/seed/scripts/init.lua b/packages/ui_level4/seed/scripts/init.lua
index 7af2f4f94..53138099b 100644
--- a/packages/ui_level4/seed/scripts/init.lua
+++ b/packages/ui_level4/seed/scripts/init.lua
@@ -1,3 +1,15 @@
+---@class UILevel4
local M = {}
+
+---@class InstallContext
+---@field version string
+
+---@class InstallResult
+---@field message string
+---@field version string
+
+---@param ctx InstallContext
+---@return InstallResult
function M.on_install(ctx) return { message = "Level 4 installed", version = ctx.version } end
+
return M
diff --git a/packages/ui_level5/seed/scripts/init.lua b/packages/ui_level5/seed/scripts/init.lua
index 558a01a60..eadef87dc 100644
--- a/packages/ui_level5/seed/scripts/init.lua
+++ b/packages/ui_level5/seed/scripts/init.lua
@@ -1,3 +1,15 @@
+---@class UILevel5
local M = {}
+
+---@class InstallContext
+---@field version string
+
+---@class InstallResult
+---@field message string
+---@field version string
+
+---@param ctx InstallContext
+---@return InstallResult
function M.on_install(ctx) return { message = "Level 5 installed", version = ctx.version } end
+
return M
diff --git a/packages/ui_level6/seed/scripts/init.lua b/packages/ui_level6/seed/scripts/init.lua
index 61d2a7e44..1912dd752 100644
--- a/packages/ui_level6/seed/scripts/init.lua
+++ b/packages/ui_level6/seed/scripts/init.lua
@@ -1,10 +1,24 @@
-- Level 6 (Supergod) package initialization
local levels = require("ui_permissions.levels")
+---@class UILevel6
local M = {}
+---@type number
M.REQUIRED_LEVEL = levels.SUPERGOD
+---@class User
+---@field level number
+
+---@class InitContext
+---@field user User
+
+---@class InitResult
+---@field allowed boolean
+---@field redirect? string
+
+---@param context InitContext
+---@return InitResult
function M.init(context)
if context.user.level < M.REQUIRED_LEVEL then
return { allowed = false, redirect = "/access-denied" }
diff --git a/packages/ui_login/seed/scripts/actions.lua b/packages/ui_login/seed/scripts/actions.lua
index d2f3bd921..c6de2cdf8 100644
--- a/packages/ui_login/seed/scripts/actions.lua
+++ b/packages/ui_login/seed/scripts/actions.lua
@@ -1,6 +1,38 @@
local validate = require("validate")
+
+---@class LoginActions
local M = {}
+---@class LoginForm
+---@field username string
+---@field password string
+
+---@class RegisterForm
+---@field username string
+---@field email string
+---@field password string
+
+---@class ValidationError
+---@field field string
+---@field message string
+
+---@class LoginSuccess
+---@field success true
+---@field action "login"
+---@field username string
+
+---@class RegisterSuccess
+---@field success true
+---@field action "register"
+---@field username string
+---@field email string
+
+---@class ActionFailure
+---@field success false
+---@field errors ValidationError[]
+
+---@param form LoginForm
+---@return LoginSuccess|ActionFailure
function M.handleLogin(form)
local result = validate.login(form)
if not result.valid then
@@ -9,6 +41,8 @@ function M.handleLogin(form)
return { success = true, action = "login", username = form.username }
end
+---@param form RegisterForm
+---@return RegisterSuccess|ActionFailure
function M.handleRegister(form)
local result = validate.register(form)
if not result.valid then
diff --git a/packages/ui_login/seed/scripts/init.lua b/packages/ui_login/seed/scripts/init.lua
index a5cf908e1..e2635cd8f 100644
--- a/packages/ui_login/seed/scripts/init.lua
+++ b/packages/ui_login/seed/scripts/init.lua
@@ -1,9 +1,23 @@
+---@class UILogin
local M = {}
+---@class InstallContext
+---@field version string
+
+---@class InstallResult
+---@field message string
+---@field version string
+
+---@class UninstallResult
+---@field message string
+
+---@param ctx InstallContext
+---@return InstallResult
function M.on_install(ctx)
return { message = "Login Page installed", version = ctx.version }
end
+---@return UninstallResult
function M.on_uninstall()
return { message = "Login Page removed" }
end
diff --git a/packages/ui_permissions/seed/scripts/init.lua b/packages/ui_permissions/seed/scripts/init.lua
index d72dabaeb..47de7e817 100644
--- a/packages/ui_permissions/seed/scripts/init.lua
+++ b/packages/ui_permissions/seed/scripts/init.lua
@@ -1,9 +1,23 @@
+---@class UIPermissions
local M = {}
+---@class InstallContext
+---@field version string
+
+---@class InstallResult
+---@field message string
+---@field version string
+
+---@class UninstallResult
+---@field message string
+
+---@param ctx InstallContext
+---@return InstallResult
function M.on_install(ctx)
return { message = "UI Permissions installed", version = ctx.version }
end
+---@return UninstallResult
function M.on_uninstall()
return { message = "UI Permissions removed" }
end