mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
feat(ui): Update metadata and add new components for dashboard, form builder, and navigation menu
This commit is contained in:
@@ -2,11 +2,12 @@
|
||||
"packageId": "dashboard",
|
||||
"name": "Dashboard",
|
||||
"version": "1.0.0",
|
||||
"description": "Dashboard components",
|
||||
"description": "Dashboard layouts, stat cards, and widgets",
|
||||
"author": "MetaBuilder",
|
||||
"category": "ui",
|
||||
"dependencies": [],
|
||||
"exports": {
|
||||
"components": []
|
||||
"components": ["StatCard", "DashboardGrid", "Widget"],
|
||||
"scripts": ["stats", "layout"]
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,12 @@
|
||||
"packageId": "form_builder",
|
||||
"name": "Form Builder",
|
||||
"version": "1.0.0",
|
||||
"description": "Form builder components",
|
||||
"description": "Form fields, validation, and submission handling",
|
||||
"author": "MetaBuilder",
|
||||
"category": "ui",
|
||||
"dependencies": [],
|
||||
"exports": {
|
||||
"components": []
|
||||
"components": ["FormField", "EmailField", "PasswordField", "NumberField", "SearchBar"],
|
||||
"scripts": ["fields", "validate"]
|
||||
}
|
||||
}
|
||||
53
packages/form_builder/seed/scripts/fields.lua
Normal file
53
packages/form_builder/seed/scripts/fields.lua
Normal file
@@ -0,0 +1,53 @@
|
||||
local M = {}
|
||||
|
||||
function M.text(props)
|
||||
return {
|
||||
type = "Box",
|
||||
children = {
|
||||
props.label and { type = "Label", props = { text = props.label, htmlFor = props.name } } or nil,
|
||||
{ type = "Input", props = { name = props.name, placeholder = props.placeholder, required = props.required } }
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function M.email(props)
|
||||
return {
|
||||
type = "Box",
|
||||
children = {
|
||||
{ type = "Label", props = { text = props.label or "Email", htmlFor = props.name } },
|
||||
{ type = "Input", props = { name = props.name, type = "email", placeholder = "you@example.com" } }
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function M.password(props)
|
||||
return {
|
||||
type = "Box",
|
||||
children = {
|
||||
{ type = "Label", props = { text = props.label or "Password", htmlFor = props.name } },
|
||||
{ type = "Input", props = { name = props.name, type = "password", placeholder = "••••••••" } }
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function M.number(props)
|
||||
return {
|
||||
type = "Box",
|
||||
children = {
|
||||
props.label and { type = "Label", props = { text = props.label, htmlFor = props.name } } or nil,
|
||||
{ type = "Input", props = { name = props.name, type = "number", min = props.min, max = props.max } }
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function M.textarea(props)
|
||||
return {
|
||||
type = "Box",
|
||||
children = {
|
||||
props.label and { type = "Label", props = { text = props.label, htmlFor = props.name } } or nil,
|
||||
{ type = "TextArea", props = { name = props.name, rows = props.rows or 4, placeholder = props.placeholder } }
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
return M
|
||||
3
packages/form_builder/seed/scripts/init.lua
Normal file
3
packages/form_builder/seed/scripts/init.lua
Normal file
@@ -0,0 +1,3 @@
|
||||
local M = {}
|
||||
function M.on_install(ctx) return { message = "Form Builder installed", version = ctx.version } end
|
||||
return M
|
||||
7
packages/form_builder/seed/scripts/manifest.json
Normal file
7
packages/form_builder/seed/scripts/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scripts": [
|
||||
{ "file": "init.lua", "name": "init", "category": "lifecycle", "description": "Package lifecycle" },
|
||||
{ "file": "fields.lua", "name": "fields", "category": "ui", "description": "Form field renderers" },
|
||||
{ "file": "validate.lua", "name": "validate", "category": "validation", "description": "Field validation" }
|
||||
]
|
||||
}
|
||||
47
packages/form_builder/seed/scripts/validate.lua
Normal file
47
packages/form_builder/seed/scripts/validate.lua
Normal file
@@ -0,0 +1,47 @@
|
||||
local M = {}
|
||||
|
||||
function M.required(value)
|
||||
return value ~= nil and value ~= ""
|
||||
end
|
||||
|
||||
function M.email(value)
|
||||
if not value then return false end
|
||||
return string.match(value, "^[^@]+@[^@]+%.[^@]+$") ~= nil
|
||||
end
|
||||
|
||||
function M.minLength(value, min)
|
||||
return value and #value >= min
|
||||
end
|
||||
|
||||
function M.maxLength(value, max)
|
||||
return not value or #value <= max
|
||||
end
|
||||
|
||||
function M.pattern(value, pat)
|
||||
return value and string.match(value, pat) ~= nil
|
||||
end
|
||||
|
||||
function M.number(value)
|
||||
return tonumber(value) ~= nil
|
||||
end
|
||||
|
||||
function M.range(value, min, max)
|
||||
local n = tonumber(value)
|
||||
return n and n >= min and n <= max
|
||||
end
|
||||
|
||||
function M.validate_field(value, rules)
|
||||
local errors = {}
|
||||
for _, rule in ipairs(rules) do
|
||||
if rule.type == "required" and not M.required(value) then
|
||||
errors[#errors + 1] = rule.message or "Required"
|
||||
elseif rule.type == "email" and not M.email(value) then
|
||||
errors[#errors + 1] = rule.message or "Invalid email"
|
||||
elseif rule.type == "minLength" and not M.minLength(value, rule.min) then
|
||||
errors[#errors + 1] = rule.message or ("Min " .. rule.min .. " chars")
|
||||
end
|
||||
end
|
||||
return { valid = #errors == 0, errors = errors }
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -2,11 +2,12 @@
|
||||
"packageId": "nav_menu",
|
||||
"name": "Navigation Menu",
|
||||
"version": "1.0.0",
|
||||
"description": "Navigation menu components",
|
||||
"description": "Sidebar, navigation menus, and breadcrumbs",
|
||||
"author": "MetaBuilder",
|
||||
"category": "ui",
|
||||
"dependencies": [],
|
||||
"dependencies": ["ui_permissions"],
|
||||
"exports": {
|
||||
"components": []
|
||||
"components": ["Sidebar", "NavigationMenu", "Breadcrumbs"],
|
||||
"scripts": ["sidebar", "menu"]
|
||||
}
|
||||
}
|
||||
3
packages/nav_menu/seed/scripts/init.lua
Normal file
3
packages/nav_menu/seed/scripts/init.lua
Normal file
@@ -0,0 +1,3 @@
|
||||
local M = {}
|
||||
function M.on_install(ctx) return { message = "Nav Menu installed", version = ctx.version } end
|
||||
return M
|
||||
7
packages/nav_menu/seed/scripts/manifest.json
Normal file
7
packages/nav_menu/seed/scripts/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"scripts": [
|
||||
{ "file": "init.lua", "name": "init", "category": "lifecycle", "description": "Package lifecycle" },
|
||||
{ "file": "sidebar.lua", "name": "sidebar", "category": "ui", "description": "Sidebar rendering" },
|
||||
{ "file": "menu.lua", "name": "menu", "category": "ui", "description": "Navigation menu" }
|
||||
]
|
||||
}
|
||||
44
packages/nav_menu/seed/scripts/menu.lua
Normal file
44
packages/nav_menu/seed/scripts/menu.lua
Normal file
@@ -0,0 +1,44 @@
|
||||
local check = require("check")
|
||||
local M = {}
|
||||
|
||||
function M.render(props)
|
||||
local items = {}
|
||||
for _, item in ipairs(props.items or {}) do
|
||||
if M.can_show(props.user, item) then
|
||||
items[#items + 1] = M.item(item)
|
||||
end
|
||||
end
|
||||
return {
|
||||
type = "Flex",
|
||||
props = { className = "items-center gap-4" },
|
||||
children = items
|
||||
}
|
||||
end
|
||||
|
||||
function M.can_show(user, item)
|
||||
if not item.minLevel then return true end
|
||||
return check.can_access(user, item.minLevel)
|
||||
end
|
||||
|
||||
function M.item(item)
|
||||
if item.children then
|
||||
return {
|
||||
type = "DropdownMenu",
|
||||
children = {
|
||||
{ type = "DropdownMenuTrigger", props = { text = item.label } },
|
||||
{ type = "DropdownMenuContent", children = M.sub_items(item.children) }
|
||||
}
|
||||
}
|
||||
end
|
||||
return { type = "Button", props = { variant = "ghost", text = item.label, onClick = "navigate", data = item.path } }
|
||||
end
|
||||
|
||||
function M.sub_items(children)
|
||||
local items = {}
|
||||
for _, c in ipairs(children) do
|
||||
items[#items + 1] = { type = "DropdownMenuItem", props = { text = c.label, onClick = "navigate", data = c.path } }
|
||||
end
|
||||
return items
|
||||
end
|
||||
|
||||
return M
|
||||
42
packages/nav_menu/seed/scripts/sidebar.lua
Normal file
42
packages/nav_menu/seed/scripts/sidebar.lua
Normal file
@@ -0,0 +1,42 @@
|
||||
local M = {}
|
||||
|
||||
function M.render(props)
|
||||
local items = {}
|
||||
for _, item in ipairs(props.items or {}) do
|
||||
items[#items + 1] = M.item(item, props.currentPath)
|
||||
end
|
||||
return {
|
||||
type = "Box",
|
||||
props = { className = "w-64 border-r h-screen bg-sidebar" },
|
||||
children = {
|
||||
M.header(props),
|
||||
{ type = "Stack", props = { spacing = 1, className = "p-4" }, children = items }
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function M.header(props)
|
||||
return {
|
||||
type = "Box",
|
||||
props = { className = "p-4 border-b" },
|
||||
children = {
|
||||
{ type = "Typography", props = { variant = "h6", text = props.title or "Menu" } }
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function M.item(item, currentPath)
|
||||
local active = currentPath == item.path
|
||||
return {
|
||||
type = "Button",
|
||||
props = {
|
||||
variant = active and "secondary" or "ghost",
|
||||
className = "w-full justify-start",
|
||||
text = item.label,
|
||||
onClick = "navigate",
|
||||
data = item.path
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user