mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-25 22:34:56 +00:00
code: tsx,storybook,src (1 files)
This commit is contained in:
345
storybook/src/components/registry.tsx
Normal file
345
storybook/src/components/registry.tsx
Normal file
@@ -0,0 +1,345 @@
|
||||
/**
|
||||
* Component Registry
|
||||
* Maps Lua component type names to React components
|
||||
*/
|
||||
|
||||
import React, { type ComponentType, type ReactNode } from 'react'
|
||||
|
||||
export interface LuaComponentProps {
|
||||
className?: string
|
||||
children?: ReactNode
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
type AnyComponent = ComponentType<LuaComponentProps>
|
||||
|
||||
/**
|
||||
* Basic UI Components
|
||||
* These mirror the components available in the main app's fakemui library
|
||||
*/
|
||||
|
||||
export const Box: React.FC<LuaComponentProps> = ({ className, children, ...props }) => (
|
||||
<div className={className} {...props}>{children}</div>
|
||||
)
|
||||
|
||||
export const Stack: React.FC<LuaComponentProps> = ({ className = 'flex flex-col gap-4', children }) => (
|
||||
<div className={className}>{children}</div>
|
||||
)
|
||||
|
||||
export const Flex: React.FC<LuaComponentProps> = ({ className = 'flex gap-4', children }) => (
|
||||
<div className={className}>{children}</div>
|
||||
)
|
||||
|
||||
export const Grid: React.FC<LuaComponentProps> = ({ className = 'grid grid-cols-2 gap-4', children }) => (
|
||||
<div className={className}>{children}</div>
|
||||
)
|
||||
|
||||
export const Container: React.FC<LuaComponentProps> = ({ className = 'max-w-7xl mx-auto px-4', children }) => (
|
||||
<div className={className}>{children}</div>
|
||||
)
|
||||
|
||||
export const Card: React.FC<LuaComponentProps> = ({ className = 'rounded-lg border shadow-sm bg-canvas', children }) => (
|
||||
<div className={className}>{children}</div>
|
||||
)
|
||||
|
||||
export const CardHeader: React.FC<LuaComponentProps> = ({ className = 'p-6 pb-2', children }) => (
|
||||
<div className={className}>{children}</div>
|
||||
)
|
||||
|
||||
export const CardContent: React.FC<LuaComponentProps> = ({ className = 'p-6 pt-0', children }) => (
|
||||
<div className={className}>{children}</div>
|
||||
)
|
||||
|
||||
export const CardActions: React.FC<LuaComponentProps> = ({ className = 'p-6 pt-0 flex gap-2', children }) => (
|
||||
<div className={className}>{children}</div>
|
||||
)
|
||||
|
||||
export const Paper: React.FC<LuaComponentProps> = ({ className = 'rounded border p-4 bg-canvas', children }) => (
|
||||
<div className={className}>{children}</div>
|
||||
)
|
||||
|
||||
interface TypographyProps extends LuaComponentProps {
|
||||
variant?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'body1' | 'body2' | 'caption' | 'overline'
|
||||
text?: string
|
||||
}
|
||||
|
||||
export const Typography: React.FC<TypographyProps> = ({
|
||||
variant = 'body1',
|
||||
text,
|
||||
className = '',
|
||||
children
|
||||
}) => {
|
||||
const content = text ?? children
|
||||
const variantClasses: Record<string, string> = {
|
||||
h1: 'text-4xl font-bold',
|
||||
h2: 'text-3xl font-bold',
|
||||
h3: 'text-2xl font-semibold',
|
||||
h4: 'text-xl font-semibold',
|
||||
h5: 'text-lg font-medium',
|
||||
h6: 'text-base font-medium',
|
||||
body1: 'text-base',
|
||||
body2: 'text-sm',
|
||||
caption: 'text-xs text-muted-foreground',
|
||||
overline: 'text-xs uppercase tracking-wide text-muted-foreground',
|
||||
}
|
||||
|
||||
const Element = variant.startsWith('h') ? variant as keyof JSX.IntrinsicElements : 'p'
|
||||
return <Element className={`${variantClasses[variant]} ${className}`}>{content}</Element>
|
||||
}
|
||||
|
||||
interface ButtonProps extends LuaComponentProps {
|
||||
variant?: 'contained' | 'outlined' | 'text'
|
||||
color?: 'primary' | 'secondary' | 'error'
|
||||
size?: 'small' | 'medium' | 'large'
|
||||
onClick?: () => void
|
||||
}
|
||||
|
||||
export const Button: React.FC<ButtonProps> = ({
|
||||
variant = 'contained',
|
||||
color = 'primary',
|
||||
size = 'medium',
|
||||
className = '',
|
||||
children,
|
||||
onClick,
|
||||
}) => {
|
||||
const baseClass = 'rounded font-medium transition-colors cursor-pointer'
|
||||
const sizeClasses = {
|
||||
small: 'px-2 py-1 text-sm',
|
||||
medium: 'px-4 py-2',
|
||||
large: 'px-6 py-3 text-lg',
|
||||
}
|
||||
const variantClasses = {
|
||||
contained: 'bg-accent text-accent-foreground hover:opacity-90',
|
||||
outlined: 'border border-accent text-accent hover:bg-accent/10',
|
||||
text: 'text-accent hover:bg-accent/10',
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
className={`${baseClass} ${sizeClasses[size]} ${variantClasses[variant]} ${className}`}
|
||||
onClick={onClick}
|
||||
style={{ backgroundColor: variant === 'contained' ? 'var(--color-accent)' : undefined }}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
interface IconProps extends LuaComponentProps {
|
||||
name: string
|
||||
size?: 'small' | 'medium' | 'large'
|
||||
}
|
||||
|
||||
export const Icon: React.FC<IconProps> = ({ name, size = 'medium', className = '' }) => {
|
||||
const sizeClasses = { small: 'text-sm', medium: 'text-xl', large: 'text-3xl' }
|
||||
// Simple emoji/text fallback for icons
|
||||
const iconMap: Record<string, string> = {
|
||||
users: '👥',
|
||||
settings: '⚙️',
|
||||
dashboard: '📊',
|
||||
home: '🏠',
|
||||
edit: '✏️',
|
||||
delete: '🗑️',
|
||||
add: '➕',
|
||||
check: '✓',
|
||||
close: '✕',
|
||||
arrow_up: '↑',
|
||||
arrow_down: '↓',
|
||||
trending_up: '📈',
|
||||
trending_down: '📉',
|
||||
}
|
||||
return <span className={`${sizeClasses[size]} ${className}`}>{iconMap[name] || `[${name}]`}</span>
|
||||
}
|
||||
|
||||
export const Divider: React.FC<LuaComponentProps> = ({ className = 'border-t my-4' }) => (
|
||||
<hr className={className} />
|
||||
)
|
||||
|
||||
export const Avatar: React.FC<LuaComponentProps & { src?: string; alt?: string }> = ({
|
||||
src,
|
||||
alt = 'Avatar',
|
||||
className = 'w-10 h-10 rounded-full bg-muted flex items-center justify-center'
|
||||
}) => (
|
||||
src ? <img src={src} alt={alt} className={className} /> : <div className={className}>{alt[0]}</div>
|
||||
)
|
||||
|
||||
interface TabsProps extends LuaComponentProps {
|
||||
value?: string
|
||||
items?: Array<{ value: string; label: string; content?: ReactNode }>
|
||||
}
|
||||
|
||||
export const Tabs: React.FC<TabsProps> = ({ items = [], className = '' }) => {
|
||||
const [active, setActive] = React.useState(items[0]?.value || '')
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<div className="flex border-b gap-4">
|
||||
{items.map(item => (
|
||||
<button
|
||||
key={item.value}
|
||||
className={`py-2 px-1 border-b-2 transition-colors ${
|
||||
active === item.value
|
||||
? 'border-accent text-accent'
|
||||
: 'border-transparent text-muted-foreground hover:text-foreground'
|
||||
}`}
|
||||
onClick={() => setActive(item.value)}
|
||||
>
|
||||
{item.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="py-4">
|
||||
{items.find(i => i.value === active)?.content}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const Tab: React.FC<LuaComponentProps & { label?: string; value?: string }> = ({
|
||||
label,
|
||||
children,
|
||||
className = 'py-2 px-4'
|
||||
}) => (
|
||||
<div className={className}>{label || children}</div>
|
||||
)
|
||||
|
||||
export const Alert: React.FC<LuaComponentProps & { severity?: 'info' | 'success' | 'warning' | 'error' }> = ({
|
||||
severity = 'info',
|
||||
className = '',
|
||||
children,
|
||||
}) => {
|
||||
const colors = {
|
||||
info: 'bg-blue-50 border-blue-200 text-blue-800',
|
||||
success: 'bg-green-50 border-green-200 text-green-800',
|
||||
warning: 'bg-yellow-50 border-yellow-200 text-yellow-800',
|
||||
error: 'bg-red-50 border-red-200 text-red-800',
|
||||
}
|
||||
return <div className={`p-4 rounded border ${colors[severity]} ${className}`}>{children}</div>
|
||||
}
|
||||
|
||||
export const Badge: React.FC<LuaComponentProps & { color?: string }> = ({
|
||||
color = 'default',
|
||||
className = '',
|
||||
children,
|
||||
}) => (
|
||||
<span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-muted ${className}`}>
|
||||
{children}
|
||||
</span>
|
||||
)
|
||||
|
||||
export const Chip: React.FC<LuaComponentProps & { label?: string }> = ({
|
||||
label,
|
||||
className = 'inline-flex items-center px-3 py-1 rounded-full text-sm bg-muted',
|
||||
children,
|
||||
}) => (
|
||||
<span className={className}>{label || children}</span>
|
||||
)
|
||||
|
||||
// Placeholder components for complex Lua package components
|
||||
export const Level4Header: React.FC<LuaComponentProps & { username?: string; nerdMode?: boolean }> = ({
|
||||
username = 'User',
|
||||
nerdMode = false,
|
||||
}) => (
|
||||
<header className="border-b p-4 flex items-center justify-between bg-canvas">
|
||||
<div className="flex items-center gap-4">
|
||||
<Typography variant="h5">Level 4 - Admin Panel</Typography>
|
||||
{nerdMode && <Badge>Nerd Mode</Badge>}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Avatar alt={username} />
|
||||
<span>{username}</span>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
|
||||
export const IntroSection: React.FC<LuaComponentProps & {
|
||||
eyebrow?: string
|
||||
title?: string
|
||||
description?: string
|
||||
}> = ({ eyebrow, title, description }) => (
|
||||
<section className="space-y-4">
|
||||
{eyebrow && <Typography variant="overline">{eyebrow}</Typography>}
|
||||
{title && <Typography variant="h2">{title}</Typography>}
|
||||
{description && <Typography variant="body1" className="text-muted-foreground">{description}</Typography>}
|
||||
</section>
|
||||
)
|
||||
|
||||
export const AppHeader: React.FC<LuaComponentProps> = ({ children }) => (
|
||||
<header className="border-b p-4 bg-canvas">{children}</header>
|
||||
)
|
||||
|
||||
export const AppFooter: React.FC<LuaComponentProps> = ({ children }) => (
|
||||
<footer className="border-t p-4 bg-canvas mt-auto">{children}</footer>
|
||||
)
|
||||
|
||||
export const Sidebar: React.FC<LuaComponentProps> = ({ children, className = 'w-64 border-r p-4 bg-canvas' }) => (
|
||||
<aside className={className}>{children}</aside>
|
||||
)
|
||||
|
||||
/**
|
||||
* Component Registry - maps Lua type names to React components
|
||||
*/
|
||||
export const componentRegistry: Record<string, AnyComponent> = {
|
||||
// Layout
|
||||
Box,
|
||||
Stack,
|
||||
Flex,
|
||||
Grid,
|
||||
Container,
|
||||
|
||||
// Surfaces
|
||||
Card,
|
||||
CardHeader,
|
||||
CardContent,
|
||||
CardActions,
|
||||
CardTitle: CardHeader,
|
||||
CardFooter: CardActions,
|
||||
Paper,
|
||||
|
||||
// Typography
|
||||
Typography,
|
||||
Text: Typography,
|
||||
|
||||
// Inputs
|
||||
Button,
|
||||
|
||||
// Display
|
||||
Icon,
|
||||
Avatar,
|
||||
Badge,
|
||||
Chip,
|
||||
Divider,
|
||||
Alert,
|
||||
|
||||
// Navigation
|
||||
Tabs,
|
||||
Tab,
|
||||
|
||||
// App-specific (from Lua packages)
|
||||
Level4Header,
|
||||
IntroSection,
|
||||
AppHeader,
|
||||
AppFooter,
|
||||
Sidebar,
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a component by its Lua type name
|
||||
*/
|
||||
export function getComponent(typeName: string): AnyComponent | undefined {
|
||||
return componentRegistry[typeName]
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom component
|
||||
*/
|
||||
export function registerComponent(typeName: string, component: AnyComponent): void {
|
||||
componentRegistry[typeName] = component
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a component type is registered
|
||||
*/
|
||||
export function hasComponent(typeName: string): boolean {
|
||||
return typeName in componentRegistry
|
||||
}
|
||||
Reference in New Issue
Block a user