mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
Enhance module definitions and add type annotations across various packages
- Added type annotations and class definitions in the dashboard layout, stats, and data table modules for improved type safety and documentation. - Introduced new classes for UI components, props, and configuration in the form builder, navigation menu, notification center, and UI dialogs packages. - Implemented detailed type definitions for actions, fields, and pagination components to streamline usage and enhance clarity. - Updated initialization functions in multiple packages to include versioning and installation context. - Improved structure and readability of the codebase by organizing and documenting component properties and methods.
This commit is contained in:
348
DEPENDENCY_CLEANUP.md
Normal file
348
DEPENDENCY_CLEANUP.md
Normal file
@@ -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
|
||||
397
FAKEMUI_STRATEGY.md
Normal file
397
FAKEMUI_STRATEGY.md
Normal file
@@ -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 |
|
||||
|---------------|--------------|--------|
|
||||
| `<Plus />` | `<Plus />` | ✅ Done |
|
||||
| `<Trash />` | `<Trash />` | ✅ Done |
|
||||
| `<Copy />` | `<Copy />` | ✅ Done |
|
||||
| `<ArrowUp />` | `<ArrowUp />` | ✅ Done |
|
||||
| `<ArrowDown />` | `<ArrowDown />` | ✅ Done |
|
||||
| `<ArrowClockwise />` | `<ArrowClockwise />` | ✅ Done |
|
||||
| `<FloppyDisk />` | `<FloppyDisk />` | ✅ 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 = () => (
|
||||
<div className={styles.root}>
|
||||
<h2 className={styles.title}>Title</h2>
|
||||
</div>
|
||||
)
|
||||
|
||||
// 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 `<input type="date">`
|
||||
- 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<ButtonProps> = (props) => (
|
||||
<Button {...props} primary />
|
||||
)
|
||||
```
|
||||
|
||||
### Customization
|
||||
```tsx
|
||||
// CSS variables for theming
|
||||
<Button style={{ '--color-primary': 'red' }} />
|
||||
|
||||
// Class names for custom styling
|
||||
<Button className="my-custom-button" />
|
||||
|
||||
// SCSS modules
|
||||
<Button className={styles.customButton} />
|
||||
```
|
||||
|
||||
### 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
|
||||
@@ -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
|
||||
|
||||
---
|
||||
|
||||
|
||||
293
fakemui/icons/README.md
Normal file
293
fakemui/icons/README.md
Normal file
@@ -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 (
|
||||
<button>
|
||||
<Plus size={20} weight="bold" />
|
||||
Add Item
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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<SVGElement> {
|
||||
size?: number | string // Default: 24
|
||||
weight?: 'thin' | 'light' | 'regular' | 'bold' // Default: 'regular'
|
||||
// Plus all standard SVG attributes (className, onClick, etc.)
|
||||
}
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```tsx
|
||||
// Size variants
|
||||
<Plus size={16} /> // Small
|
||||
<Plus size={24} /> // Default
|
||||
<Plus size={32} /> // Large
|
||||
|
||||
// Weight variants
|
||||
<Plus weight="thin" /> // strokeWidth: 1
|
||||
<Plus weight="light" /> // strokeWidth: 1.5
|
||||
<Plus weight="regular" /> // strokeWidth: 2 (default)
|
||||
<Plus weight="bold" /> // strokeWidth: 2.5
|
||||
|
||||
// Custom styling
|
||||
<Plus className="text-blue-500" />
|
||||
<Plus style={{ color: 'red' }} />
|
||||
<Plus onClick={() => 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) => (
|
||||
<Icon {...props}>
|
||||
{/* Paste SVG paths here */}
|
||||
<path d="..." />
|
||||
<line x1="..." y1="..." x2="..." y2="..." />
|
||||
</Icon>
|
||||
)
|
||||
```
|
||||
|
||||
**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/
|
||||
<svg viewBox="0 0 256 256">
|
||||
<line x1="40" y1="128" x2="216" y2="128" />
|
||||
<line x1="128" y1="40" x2="128" y2="216" />
|
||||
</svg>
|
||||
|
||||
// fakemui component:
|
||||
export const Plus = (props: IconProps) => (
|
||||
<Icon {...props}>
|
||||
<line x1="40" y1="128" x2="216" y2="128" />
|
||||
<line x1="128" y1="40" x2="128" y2="216" />
|
||||
</Icon>
|
||||
)
|
||||
```
|
||||
|
||||
### From Heroicons
|
||||
|
||||
Heroicons uses `viewBox="0 0 24 24"` - needs scaling!
|
||||
|
||||
```tsx
|
||||
// Source: https://heroicons.com/
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
|
||||
// Scale by 10.67 (256/24):
|
||||
export const Plus = (props: IconProps) => (
|
||||
<Icon {...props}>
|
||||
<path d="M128 48v160m80-80h-160" />
|
||||
</Icon>
|
||||
)
|
||||
```
|
||||
|
||||
### From Lucide
|
||||
|
||||
Lucide uses `viewBox="0 0 24 24"` - same scaling as Heroicons.
|
||||
|
||||
```tsx
|
||||
// Source: https://lucide.dev/
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
|
||||
// Scale coordinates:
|
||||
export const Plus = (props: IconProps) => (
|
||||
<Icon {...props}>
|
||||
<path d="M53 128h149" />
|
||||
<path d="M128 53v149" />
|
||||
</Icon>
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
-- Nav menu divider component
|
||||
|
||||
---@class MenuDivider
|
||||
---@field type string
|
||||
|
||||
---@return MenuDivider
|
||||
local function menu_divider()
|
||||
return {
|
||||
type = "divider"
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
-- Notification summary card component logic
|
||||
local json = require("json")
|
||||
|
||||
---@class NotificationSummary
|
||||
---@field severityClasses table<string, string>
|
||||
---@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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
---@class SceneRouter
|
||||
local M = {}
|
||||
|
||||
---@type table<string, string>
|
||||
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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user