diff --git a/fakemui/icons/AccountCircle.tsx b/fakemui/icons/AccountCircle.tsx new file mode 100644 index 000000000..7979a6525 --- /dev/null +++ b/fakemui/icons/AccountCircle.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const AccountCircle = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/AspectRatio.tsx b/fakemui/icons/AspectRatio.tsx new file mode 100644 index 000000000..5d53dd7da --- /dev/null +++ b/fakemui/icons/AspectRatio.tsx @@ -0,0 +1,12 @@ +import React from 'react' +import { Icon, IconProps } from './Icon' + +export const AspectRatio = (props: IconProps) => ( + + + + + + + +) diff --git a/fakemui/icons/Checkbox.tsx b/fakemui/icons/Checkbox.tsx new file mode 100644 index 000000000..60ea74336 --- /dev/null +++ b/fakemui/icons/Checkbox.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const Checkbox = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/ClosedCaption.tsx b/fakemui/icons/ClosedCaption.tsx new file mode 100644 index 000000000..1be9be583 --- /dev/null +++ b/fakemui/icons/ClosedCaption.tsx @@ -0,0 +1,12 @@ +import React from 'react' +import { Icon, IconProps } from './Icon' + +export const ClosedCaption = (props: IconProps) => ( + + + + + + + +) diff --git a/fakemui/icons/CropFree.tsx b/fakemui/icons/CropFree.tsx new file mode 100644 index 000000000..f9680e32a --- /dev/null +++ b/fakemui/icons/CropFree.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const CropFree = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/CropPortrait.tsx b/fakemui/icons/CropPortrait.tsx new file mode 100644 index 000000000..eb6f693d7 --- /dev/null +++ b/fakemui/icons/CropPortrait.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const CropPortrait = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/FormatAlignLeft.tsx b/fakemui/icons/FormatAlignLeft.tsx new file mode 100644 index 000000000..52d2a1bd2 --- /dev/null +++ b/fakemui/icons/FormatAlignLeft.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const FormatAlignLeft = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/Gamepad.tsx b/fakemui/icons/Gamepad.tsx new file mode 100644 index 000000000..0cdfd1e08 --- /dev/null +++ b/fakemui/icons/Gamepad.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import { Icon, IconProps } from './Icon' + +export const Gamepad = (props: IconProps) => ( + + + + + + + + + +) diff --git a/fakemui/icons/GridView.tsx b/fakemui/icons/GridView.tsx new file mode 100644 index 000000000..4c9862165 --- /dev/null +++ b/fakemui/icons/GridView.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const GridView = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/Headphones.tsx b/fakemui/icons/Headphones.tsx new file mode 100644 index 000000000..85537ace5 --- /dev/null +++ b/fakemui/icons/Headphones.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import { Icon, IconProps } from './Icon' + +export const Headphones = (props: IconProps) => ( + + + + + +) diff --git a/fakemui/icons/HighQuality.tsx b/fakemui/icons/HighQuality.tsx new file mode 100644 index 000000000..a9db5d265 --- /dev/null +++ b/fakemui/icons/HighQuality.tsx @@ -0,0 +1,15 @@ +import React from 'react' +import { Icon, IconProps } from './Icon' + +export const HighQuality = (props: IconProps) => ( + + + + + + + + + + +) diff --git a/fakemui/icons/Joystick.tsx b/fakemui/icons/Joystick.tsx new file mode 100644 index 000000000..c454cd5f0 --- /dev/null +++ b/fakemui/icons/Joystick.tsx @@ -0,0 +1,11 @@ +import React from 'react' +import { Icon, IconProps } from './Icon' + +export const Joystick = (props: IconProps) => ( + + + + + + +) diff --git a/fakemui/icons/LocalOffer.tsx b/fakemui/icons/LocalOffer.tsx new file mode 100644 index 000000000..d92ba5bc1 --- /dev/null +++ b/fakemui/icons/LocalOffer.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const LocalOffer = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/LooksOne.tsx b/fakemui/icons/LooksOne.tsx new file mode 100644 index 000000000..34ac8ba6c --- /dev/null +++ b/fakemui/icons/LooksOne.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const LooksOne = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/Mic.tsx b/fakemui/icons/Mic.tsx new file mode 100644 index 000000000..db1fb8d13 --- /dev/null +++ b/fakemui/icons/Mic.tsx @@ -0,0 +1,11 @@ +import React from 'react' +import { Icon, IconProps } from './Icon' + +export const Mic = (props: IconProps) => ( + + + + + + +) diff --git a/fakemui/icons/MicOff.tsx b/fakemui/icons/MicOff.tsx new file mode 100644 index 000000000..d272603fb --- /dev/null +++ b/fakemui/icons/MicOff.tsx @@ -0,0 +1,12 @@ +import React from 'react' +import { Icon, IconProps } from './Icon' + +export const MicOff = (props: IconProps) => ( + + + + + + + +) diff --git a/fakemui/icons/Minus.tsx b/fakemui/icons/Minus.tsx new file mode 100644 index 000000000..a3d3c5359 --- /dev/null +++ b/fakemui/icons/Minus.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const Minus = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/Radio.tsx b/fakemui/icons/Radio.tsx new file mode 100644 index 000000000..bd4636544 --- /dev/null +++ b/fakemui/icons/Radio.tsx @@ -0,0 +1,13 @@ +import React from 'react' +import { Icon, IconProps } from './Icon' + +export const Radio = (props: IconProps) => ( + + + + + + + + +) diff --git a/fakemui/icons/Repeat.tsx b/fakemui/icons/Repeat.tsx new file mode 100644 index 000000000..aaaab44ef --- /dev/null +++ b/fakemui/icons/Repeat.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import { Icon, IconProps } from './Icon' + +export const Repeat = (props: IconProps) => ( + + + + + +) diff --git a/fakemui/icons/RepeatOne.tsx b/fakemui/icons/RepeatOne.tsx new file mode 100644 index 000000000..938388651 --- /dev/null +++ b/fakemui/icons/RepeatOne.tsx @@ -0,0 +1,11 @@ +import React from 'react' +import { Icon, IconProps } from './Icon' + +export const RepeatOne = (props: IconProps) => ( + + + + + 1 + +) diff --git a/fakemui/icons/Shuffle.tsx b/fakemui/icons/Shuffle.tsx new file mode 100644 index 000000000..231591990 --- /dev/null +++ b/fakemui/icons/Shuffle.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import { Icon, IconProps } from './Icon' + +export const Shuffle = (props: IconProps) => ( + + + + + + + + + +) diff --git a/fakemui/icons/Speed.tsx b/fakemui/icons/Speed.tsx new file mode 100644 index 000000000..891973aba --- /dev/null +++ b/fakemui/icons/Speed.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import { Icon, IconProps } from './Icon' + +export const Speed = (props: IconProps) => ( + + + + + + + + + +) diff --git a/fakemui/icons/Subtitles.tsx b/fakemui/icons/Subtitles.tsx new file mode 100644 index 000000000..35c5a7f22 --- /dev/null +++ b/fakemui/icons/Subtitles.tsx @@ -0,0 +1,13 @@ +import React from 'react' +import { Icon, IconProps } from './Icon' + +export const Subtitles = (props: IconProps) => ( + + + + + + + + +) diff --git a/fakemui/icons/TableChart.tsx b/fakemui/icons/TableChart.tsx new file mode 100644 index 000000000..8991bc5ac --- /dev/null +++ b/fakemui/icons/TableChart.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const TableChart = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/TextFields.tsx b/fakemui/icons/TextFields.tsx new file mode 100644 index 000000000..68c916bcc --- /dev/null +++ b/fakemui/icons/TextFields.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const TextFields = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/Timer.tsx b/fakemui/icons/Timer.tsx new file mode 100644 index 000000000..68042e538 --- /dev/null +++ b/fakemui/icons/Timer.tsx @@ -0,0 +1,13 @@ +import React from 'react' +import { Icon, IconProps } from './Icon' + +export const Timer = (props: IconProps) => ( + + + + + + + + +) diff --git a/fakemui/icons/ToggleOn.tsx b/fakemui/icons/ToggleOn.tsx new file mode 100644 index 000000000..825e56874 --- /dev/null +++ b/fakemui/icons/ToggleOn.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const ToggleOn = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/TouchApp.tsx b/fakemui/icons/TouchApp.tsx new file mode 100644 index 000000000..93c2f6980 --- /dev/null +++ b/fakemui/icons/TouchApp.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const TouchApp = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/Verified.tsx b/fakemui/icons/Verified.tsx new file mode 100644 index 000000000..9e41926f5 --- /dev/null +++ b/fakemui/icons/Verified.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const Verified = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/ViewColumn.tsx b/fakemui/icons/ViewColumn.tsx new file mode 100644 index 000000000..30224ec8c --- /dev/null +++ b/fakemui/icons/ViewColumn.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const ViewColumn = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/ViewStream.tsx b/fakemui/icons/ViewStream.tsx new file mode 100644 index 000000000..25b8d2cca --- /dev/null +++ b/fakemui/icons/ViewStream.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from './Icon' + +export const ViewStream = (props: IconProps) => ( + + + +) diff --git a/fakemui/icons/index.ts b/fakemui/icons/index.ts index 5b5008f3b..c2e50b41a 100644 --- a/fakemui/icons/index.ts +++ b/fakemui/icons/index.ts @@ -279,3 +279,56 @@ export { Notifications } from './Notifications' export { NotificationsOff } from './NotificationsOff' export { ContentCopy } from './ContentCopy' export { ContentPaste } from './ContentPaste' + +// Component Icon Map +export { Article } from './Article' +export { Checkbox } from './Checkbox' +export { CropFree } from './CropFree' +export { CropPortrait } from './CropPortrait' +export { GridView } from './GridView' +export { LocalOffer } from './LocalOffer' +export { LooksOne } from './LooksOne' +export { Minus } from './Minus' +export { TableChart } from './TableChart' +export { TextFields } from './TextFields' +export { ToggleOn } from './ToggleOn' +export { TouchApp } from './TouchApp' +export { Verified } from './Verified' +export { ViewColumn } from './ViewColumn' +export { ViewStream } from './ViewStream' +export { AccountCircle } from './AccountCircle' +export { FormatAlignLeft } from './FormatAlignLeft' + +// Media Center Icons +export { FilmSlate } from './FilmSlate' +export { Queue } from './Queue' +export { Tv } from './Tv' +export { Transform } from './Transform' +export { PictureAsPdf } from './PictureAsPdf' +export { Article } from './Article' +export { MenuBook } from './MenuBook' +export { SportsEsports } from './SportsEsports' +export { CameraAlt } from './CameraAlt' +export { FastForward } from './FastForward' +export { FastRewind } from './FastRewind' +export { Fullscreen } from './Fullscreen' +export { FullscreenExit } from './FullscreenExit' +export { People } from './People' +export { ArrowUpDown } from './ArrowUpDown' +export { SkipPrevious } from './SkipPrevious' +export { SkipNext } from './SkipNext' +export { Shuffle } from './Shuffle' +export { Repeat } from './Repeat' +export { RepeatOne } from './RepeatOne' +export { Gamepad } from './Gamepad' +export { Joystick } from './Joystick' +export { Radio } from './Radio' +export { Headphones } from './Headphones' +export { Mic } from './Mic' +export { MicOff } from './MicOff' +export { Subtitles } from './Subtitles' +export { ClosedCaption } from './ClosedCaption' +export { HighQuality } from './HighQuality' +export { AspectRatio } from './AspectRatio' +export { Speed } from './Speed' +export { Timer } from './Timer' diff --git a/frontends/nextjs/src/lib/rendering/component-registry.ts b/frontends/nextjs/src/lib/rendering/component-registry.ts new file mode 100644 index 000000000..5e63c2016 --- /dev/null +++ b/frontends/nextjs/src/lib/rendering/component-registry.ts @@ -0,0 +1,224 @@ +/** + * Maps Lua component type names to fakemui React components + * Used by the declarative renderer to resolve component types from Lua packages + */ + +import { + Box, + Stack, + Grid, + Container, + Flex, + Paper, + Card, + CardHeader, + CardContent, + CardActions, + Button, + IconButton, + Input, + TextField, + Textarea, + Select, + NativeSelect, + Checkbox, + Radio, + RadioGroup, + Switch, + Slider, + FormControl, + FormGroup, + FormLabel, + FormHelperText, + ButtonGroup, + Typography, + Avatar, + Badge, + Chip, + Divider, + List, + ListItem, + ListItemText, + ListItemIcon, + Table, + TableHead, + TableBody, + TableRow, + TableCell, + TableContainer, + Tabs, + Tab, + Dialog, + DialogTitle, + DialogContent, + DialogActions, + Alert, + Snackbar, + Menu, + MenuItem, + Tooltip, + AppBar, + Toolbar, + Breadcrumbs, + Link, + CircularProgress, + LinearProgress, + Skeleton, + Accordion, + AccordionSummary, + AccordionDetails, + Stepper, + Step, + StepLabel, + Pagination, +} from '@/fakemui' + +import type { ComponentType } from 'react' + +/** + * Type definition for component props from Lua + */ +export interface LuaComponentProps { + [key: string]: unknown + children?: React.ReactNode +} + +/** + * Component registry mapping Lua type names to React components + */ +export const componentRegistry: Record> = { + // Layout + Box, + Stack, + Grid, + Container, + Flex, + + // Surfaces + Paper, + Card, + CardHeader, + CardContent, + CardActions, + CardTitle: CardHeader, // Alias + CardFooter: CardActions, // Alias + + // Inputs + Button, + IconButton, + ButtonGroup, + Input, + TextField, + TextArea: Textarea, + Textarea, + Select, + NativeSelect, + Checkbox, + Radio, + RadioGroup, + Switch, + Slider, + + // Form elements + FormControl, + FormGroup, + FormLabel, + FormHelperText, + + // Typography & Data Display + Typography, + Text: Typography, + Avatar, + Badge, + Chip, + Divider, + + // Lists + List, + ListItem, + ListItemText, + ListItemIcon, + + // Tables + Table, + TableHead, + TableHeader: TableHead, // Alias + TableBody, + TableRow, + TableCell, + TableContainer, + + // Navigation + Tabs, + Tab, + TabsList: Tabs, // Map to Tabs container + TabsTrigger: Tab, // Map to Tab + TabsContent: Box, // Content wrapper + Breadcrumbs, + Link, + Menu, + MenuItem, + Pagination, + Stepper, + Step, + StepLabel, + + // Feedback + Alert, + Snackbar, + Toast: Snackbar, // Alias + Dialog, + DialogTitle, + DialogContent, + DialogActions, + CircularProgress, + LinearProgress, + Progress: LinearProgress, // Alias + Spinner: CircularProgress, // Alias + Skeleton, + + // Surfaces + AppBar, + Toolbar, + Accordion, + AccordionSummary, + AccordionDetails, + + // Utils + Tooltip, +} + +/** + * Get a React component by its Lua type name + * @param typeName - The component type name from Lua + * @returns The corresponding React component or undefined + */ +export function getComponentByType(typeName: string): ComponentType | undefined { + return componentRegistry[typeName] +} + +/** + * Check if a component type is registered + * @param typeName - The component type name to check + * @returns True if the component is registered + */ +export function hasComponent(typeName: string): boolean { + return typeName in componentRegistry +} + +/** + * Get all registered component type names + * @returns Array of component type names + */ +export function getRegisteredComponentTypes(): string[] { + return Object.keys(componentRegistry) +} + +/** + * Register a custom component for Lua rendering + * @param typeName - The type name to use in Lua + * @param component - The React component to render + */ +export function registerComponent(typeName: string, component: ComponentType): void { + componentRegistry[typeName] = component +} diff --git a/frontends/nextjs/tsconfig.json b/frontends/nextjs/tsconfig.json index 407c3629c..131d94958 100644 --- a/frontends/nextjs/tsconfig.json +++ b/frontends/nextjs/tsconfig.json @@ -29,6 +29,12 @@ "@/*": [ "./src/*" ], + "@/fakemui": [ + "../../fakemui" + ], + "@/fakemui/*": [ + "../../fakemui/*" + ], "@/dbal": [ "../../dbal/development/src" ], diff --git a/packages/ui_level3/seed/metadata.json b/packages/ui_level3/seed/metadata.json index 59ad99f46..cf28a8f60 100644 --- a/packages/ui_level3/seed/metadata.json +++ b/packages/ui_level3/seed/metadata.json @@ -26,11 +26,13 @@ "tests": { "scripts": [ "tests/metadata.test.lua", - "tests/components.test.lua" + "tests/components.test.lua", + "tests/moderation.test.lua" ], "cases": [ "tests/metadata.cases.json", - "tests/components.cases.json" + "tests/components.cases.json", + "tests/moderation.cases.json" ] }, "minLevel": 3