scaffold_component
Generate component templates for forms, lists, detail views, cards, modals, and navigation elements with optional features like validation, internationalization, state management, data fetching, animations, and drag-and-drop functionality.
Instructions
Generate a NoJS component template following framework conventions
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| type | Yes | Component type to scaffold | |
| features | No | Optional features to include: "validation", "i18n", "state", "fetch", "animation", "dnd" |
Implementation Reference
- src/tools/index.ts:287-421 (handler)The `scaffold_component` tool is defined and implemented directly in `src/tools/index.ts`. It takes a `type` and an optional list of `features`, and returns a string containing a scaffolded HTML template for a NoJS component.
// ── scaffold_component ── server.tool( "scaffold_component", "Generate a NoJS component template following framework conventions", { type: z .enum(["form", "list", "detail", "card", "modal", "nav"]) .describe("Component type to scaffold"), features: z .array(z.string()) .optional() .describe( 'Optional features to include: "validation", "i18n", "state", "fetch", "animation", "dnd"' ), }, async ({ type, features = [] }) => { const templates: Record<string, string> = { form: `<div state="{ email: '', password: '', loading: false }"> <h2>Login</h2> <form validate on:submit.prevent="loading = true"> <div class="field"> <label>Email</label> <input model="email" type="email" validate="required,email" error-required="Email is required" error-email="Invalid email"> </div> <div class="field"> <label>Password</label> <input model="password" type="password" validate="required" error-required="Password is required"> </div> <p if="$form.firstError" class="error" bind="$form.firstError"></p> <button type="submit" class-disabled="!$form.valid || loading"> <span hide="loading">Submit</span> <span show="loading">Loading...</span> </button> </form> </div>`, list: `<div state="{ search: '' }"> <input model="search" placeholder="Search..."> <div get="/items" as="items"> <div each="item in items" key="item.id" animate="fadeIn" animate-stagger="50"> <h3 bind="item.title"></h3> <p bind="item.description | truncate(100)"></p> </div> <p if="items.length === 0">No items found.</p> </div> </div>`, detail: `<div get="/items/{$route.params.id}" as="item"> <template if="item"> <h1 bind="item.title"></h1> <p bind="item.description"></p> <span bind="item.createdAt | relative"></span> </template> <template else> <p>Loading...</p> </template> </div>`, card: `<div class="card" state="{ expanded: false }"> <div class="card-header"> <h3 bind="title"></h3> <button on:click="expanded = !expanded"> <span hide="expanded">▸</span> <span show="expanded">▾</span> </button> </div> <div class="card-body" show="expanded" animate="slideDown"> <p bind="description"></p> </div> </div>`, modal: `<div state="{ open: false }"> <button on:click="open = true">Open Modal</button> <div class="modal-overlay" show="open" on:click.self="open = false" animate-enter="fadeIn" animate-leave="fadeOut"> <div class="modal-content" animate-enter="slideUp" animate-leave="slideDown"> <div class="modal-header"> <h2>Modal Title</h2> <button on:click="open = false">×</button> </div> <div class="modal-body"> <p>Modal content goes here.</p> </div> <div class="modal-footer"> <button on:click="open = false">Close</button> </div> </div> </div> </div>`, nav: `<nav class="navbar"> <a route="/" class="logo">App</a> <div class="nav-links"> <a route="/" route-active="active">Home</a> <a route="/features" route-active="active">Features</a> <a route="/about" route-active="active">About</a> <a route="/contact" route-active="active">Contact</a> </div> </nav>`, }; let html = templates[type] || templates["card"]; let description = `NoJS ${type} component template`; // Add feature hints const featureNotes: string[] = []; if (features.includes("i18n")) { featureNotes.push( "Add t=\"key\" to text elements for i18n support" ); } if (features.includes("animation")) { featureNotes.push( 'Add animate="fadeIn" or transition="slide" for animations' ); } if (features.includes("dnd")) { featureNotes.push( "Add drag/drop attributes for drag-and-drop support" ); } let output = `## Generated ${type} template\n\n\`\`\`html\n${html}\n\`\`\`\n`; if (featureNotes.length > 0) { output += `\n## Feature Notes\n\n${featureNotes.map((n) => `- ${n}`).join("\n")}\n`; } return { content: [{ type: "text" as const, text: output }], }; } );