From 6b3304ecaa06faa812e76536cc448eb738b8fb40 Mon Sep 17 00:00:00 2001 From: JohnDoe6345789 Date: Fri, 26 Dec 2025 01:16:23 +0000 Subject: [PATCH] docs: nextjs,frontends,prisma (6 files) --- .../entities/lua_script/get_lua_script.hpp | 2 +- docs/codegen-studio.md | 1 + .../src/app/codegen/CodegenStudioClient.tsx | 23 ++ .../components/LuaBlocksEditor.module.scss | 255 ++++++++++++++++++ frontends/nextjs/src/lib/types/level-types.ts | 3 + prisma/schema.prisma | 3 + 6 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 frontends/nextjs/src/components/LuaBlocksEditor.module.scss diff --git a/dbal/cpp/src/entities/lua_script/get_lua_script.hpp b/dbal/cpp/src/entities/lua_script/get_lua_script.hpp index 6d76b02f5..a81bdd12e 100644 --- a/dbal/cpp/src/entities/lua_script/get_lua_script.hpp +++ b/dbal/cpp/src/entities/lua_script/get_lua_script.hpp @@ -18,7 +18,7 @@ namespace lua_script { */ inline Result get(InMemoryStore& store, const std::string& id) { if (id.empty()) { - return Error::validationError("Script ID cannot be empty"); + return Error::validationError("Lua script ID cannot be empty"); } auto it = store.lua_scripts.find(id); diff --git a/docs/codegen-studio.md b/docs/codegen-studio.md index c0224c973..8d439324d 100644 --- a/docs/codegen-studio.md +++ b/docs/codegen-studio.md @@ -35,6 +35,7 @@ The runtime-specific paragraph is drawn from the `runtime` value, and the CLI st - **Experience**: A Material UI-powered scaffold designer that bundles the same payload used by the API and streams the ZIP for download. - **Feedback**: Inline alerts surface success or failure so teams can iteratively tune briefs before sharing the starter kit with collaborators. - **Preview**: A manifest panel summarizes the generated values (runtime, tone, package, timestamp) after each export. +- **Bundle contents**: The UI also renders the file list that will land inside the archive so creators can make last-second adjustments. ## Development tooling diff --git a/frontends/nextjs/src/app/codegen/CodegenStudioClient.tsx b/frontends/nextjs/src/app/codegen/CodegenStudioClient.tsx index 54826476b..48bcce1aa 100644 --- a/frontends/nextjs/src/app/codegen/CodegenStudioClient.tsx +++ b/frontends/nextjs/src/app/codegen/CodegenStudioClient.tsx @@ -93,6 +93,21 @@ export default function CodegenStudioClient() { } }, [form.runtime]) + const previewFiles = useMemo(() => { + const root = form.projectName + .toLowerCase() + .trim() + .replace(/[^a-z0-9_-]+/g, '-') + .replace(/^-+|-+$/g, '') || 'metabuilder-starter' + return [ + `${root}/README.md`, + `${root}/package.json`, + `${root}/src/app/page.tsx`, + `${root}/cli/main.cpp`, + `${root}/spec.json`, + ] + }, [form.projectName]) + const handleChange = (key: keyof FormState) => (event: ChangeEvent) => { setForm((prev) => ({ ...prev, [key]: event.target.value })) } @@ -209,6 +224,14 @@ export default function CodegenStudioClient() { )} + + Bundle contents + {previewFiles.map((entry) => ( + + • {entry} + + ))} + diff --git a/frontends/nextjs/src/components/LuaBlocksEditor.module.scss b/frontends/nextjs/src/components/LuaBlocksEditor.module.scss new file mode 100644 index 000000000..a62b2b7db --- /dev/null +++ b/frontends/nextjs/src/components/LuaBlocksEditor.module.scss @@ -0,0 +1,255 @@ +@use '../styles/variables' as *; + +.root { + --block-basics: #f59e0b; + --block-basics-dark: #d97706; + --block-basics-soft: #fff6df; + --block-basics-border: #fbd38d; + + --block-logic: #0ea5e9; + --block-logic-dark: #0284c7; + --block-logic-soft: #e0f2fe; + --block-logic-border: #bae6fd; + + --block-loops: #22c55e; + --block-loops-dark: #16a34a; + --block-loops-soft: #dcfce7; + --block-loops-border: #bbf7d0; + + --block-data: #14b8a6; + --block-data-dark: #0d9488; + --block-data-soft: #ccfbf1; + --block-data-border: #99f6e4; + + --block-functions: #ef4444; + --block-functions-dark: #dc2626; + --block-functions-soft: #fee2e2; + --block-functions-border: #fecaca; +} + +.workspaceSurface { + border-radius: $radius-xl; + padding: $space-6; + background: linear-gradient(135deg, #f8fafc, #ffffff); + border: 1px solid $color-neutral-200; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9); + min-height: 240px; +} + +.blockStack { + display: grid; + gap: $space-4; +} + +.blockCard { + --block-accent: var(--block-basics); + --block-accent-dark: var(--block-basics-dark); + --block-bg: var(--block-basics-soft); + --block-border: var(--block-basics-border); + + border-radius: $radius-xl; + background: var(--block-bg); + border: 1px solid var(--block-border); + box-shadow: $shadow-sm; + overflow: hidden; +} + +.blockCard[data-category='Basics'] { + --block-accent: var(--block-basics); + --block-accent-dark: var(--block-basics-dark); + --block-bg: var(--block-basics-soft); + --block-border: var(--block-basics-border); +} + +.blockCard[data-category='Logic'] { + --block-accent: var(--block-logic); + --block-accent-dark: var(--block-logic-dark); + --block-bg: var(--block-logic-soft); + --block-border: var(--block-logic-border); +} + +.blockCard[data-category='Loops'] { + --block-accent: var(--block-loops); + --block-accent-dark: var(--block-loops-dark); + --block-bg: var(--block-loops-soft); + --block-border: var(--block-loops-border); +} + +.blockCard[data-category='Data'] { + --block-accent: var(--block-data); + --block-accent-dark: var(--block-data-dark); + --block-bg: var(--block-data-soft); + --block-border: var(--block-data-border); +} + +.blockCard[data-category='Functions'] { + --block-accent: var(--block-functions); + --block-accent-dark: var(--block-functions-dark); + --block-bg: var(--block-functions-soft); + --block-border: var(--block-functions-border); +} + +.blockHeader { + display: flex; + align-items: center; + justify-content: space-between; + gap: $space-3; + padding: $space-3 $space-4; + background: linear-gradient(135deg, var(--block-accent), var(--block-accent-dark)); + color: #ffffff; + position: relative; +} + +.blockTitle { + font-family: var(--font-family-heading); + font-weight: $font-weight-semibold; + font-size: $font-size-base; +} + +.blockActions { + display: inline-flex; + align-items: center; + gap: $space-1; +} + +.blockFields { + display: grid; + gap: $space-3; + padding: $space-4; +} + +.blockFieldLabel { + display: block; + font-size: $font-size-xs; + font-weight: $font-weight-semibold; + text-transform: uppercase; + letter-spacing: 0.06em; + color: $color-neutral-700; + margin-bottom: $space-2; +} + +.blockSection { + border-radius: $radius-lg; + border: 1px dashed $color-neutral-300; + background: rgba(255, 255, 255, 0.75); + padding: $space-3; + margin: $space-3 $space-4 $space-4; +} + +.blockSectionHeader { + display: flex; + align-items: center; + justify-content: space-between; + gap: $space-3; + margin-bottom: $space-3; +} + +.blockSectionTitle { + font-weight: $font-weight-semibold; + color: $color-neutral-800; + font-size: $font-size-sm; +} + +.blockSectionBody { + display: grid; + gap: $space-3; +} + +.blockEmpty { + text-align: center; + padding: $space-4; + font-size: $font-size-sm; + color: $color-neutral-600; + border-radius: $radius-md; + border: 1px dashed $color-neutral-300; + background: rgba(255, 255, 255, 0.7); +} + +.libraryBlock { + border-radius: $radius-lg; + padding: $space-3; + border: 1px solid $color-neutral-200; + background: #ffffff; + cursor: pointer; + transition: transform $transition-fast, box-shadow $transition-fast, border-color $transition-fast; + box-shadow: $shadow-sm; +} + +.libraryBlock:hover { + transform: translateY(-1px); + box-shadow: $shadow-md; + border-color: $color-neutral-300; +} + +.libraryBlockTitle { + font-weight: $font-weight-semibold; + color: $color-neutral-900; +} + +.libraryBlockDesc { + font-size: $font-size-xs; + color: $color-neutral-600; +} + +.libraryBlock[data-category='Basics'] { + border-left: 4px solid var(--block-basics); +} + +.libraryBlock[data-category='Logic'] { + border-left: 4px solid var(--block-logic); +} + +.libraryBlock[data-category='Loops'] { + border-left: 4px solid var(--block-loops); +} + +.libraryBlock[data-category='Data'] { + border-left: 4px solid var(--block-data); +} + +.libraryBlock[data-category='Functions'] { + border-left: 4px solid var(--block-functions); +} + +.menuSwatch { + width: 12px; + height: 12px; + border-radius: 999px; + border: 1px solid rgba(15, 23, 42, 0.2); + background: var(--block-basics); +} + +.menuSwatch[data-category='Basics'] { + background: var(--block-basics); +} + +.menuSwatch[data-category='Logic'] { + background: var(--block-logic); +} + +.menuSwatch[data-category='Loops'] { + background: var(--block-loops); +} + +.menuSwatch[data-category='Data'] { + background: var(--block-data); +} + +.menuSwatch[data-category='Functions'] { + background: var(--block-functions); +} + +.codePreview { + border-radius: $radius-lg; + background: #0f172a; + color: #e2e8f0; + padding: $space-4; + font-family: var(--font-family-mono); + font-size: $font-size-sm; + overflow-x: auto; +} + +.codePreview pre { + margin: 0; + white-space: pre-wrap; +} diff --git a/frontends/nextjs/src/lib/types/level-types.ts b/frontends/nextjs/src/lib/types/level-types.ts index 176e0685d..d383b8733 100644 --- a/frontends/nextjs/src/lib/types/level-types.ts +++ b/frontends/nextjs/src/lib/types/level-types.ts @@ -99,6 +99,9 @@ export interface LuaScript { code: string parameters: Array<{ name: string; type: string }> returnType?: string + isSandboxed?: boolean + allowedGlobals?: string[] + timeoutMs?: number } export interface PageConfig { diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 904b2699b..fc17869eb 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -61,6 +61,9 @@ model LuaScript { code String parameters String returnType String? + isSandboxed Boolean @default(true) + allowedGlobals String @default("[]") + timeoutMs Int @default(5000) } model PageConfig {