feat(form_builder): add contact form with validation and submission handling

- Created contact-form.json defining the structure and validation for the contact form.
- Added package.json for form_builder package with dependencies and exports.
- Implemented functions.json for form field handlers and validation functions.
- Configured storybook for form_builder with various form field stories.
- Established style tokens for form fields including colors and spacing.
- Defined validation patterns and functions for form fields in validators.json.

feat(notification_center): introduce notification components and event handling

- Added ui.json for notification components including summary, toast, and list.
- Created schema.json for Notification entity with fields and relations.
- Implemented event handlers for notification events in handlers.json.
- Established package.json for notification_center with components and scripts.
- Developed functions.json for notification management and display functions.
- Configured storybook for notification_center with various notification stories.
- Defined style tokens for notifications including colors and spacing.
This commit is contained in:
2026-01-02 15:34:42 +00:00
parent 59a473dfb8
commit af80a8e761
14 changed files with 1538 additions and 0 deletions

View File

@@ -0,0 +1,433 @@
{
"$schema": "https://metabuilder.dev/schemas/json-script-components.schema.json",
"schemaVersion": "2.0.0",
"package": "form_builder",
"description": "Reusable form field components with built-in validation",
"components": [
{
"id": "form_field",
"name": "FormField",
"description": "Generic form field with label, validation, and error display",
"props": [
{
"name": "name",
"type": "string",
"required": true
},
{
"name": "label",
"type": "string",
"required": true
},
{
"name": "type",
"type": "string",
"default": "text",
"enum": ["text", "email", "password", "number", "tel", "url", "textarea"]
},
{
"name": "placeholder",
"type": "string",
"required": false
},
{
"name": "required",
"type": "boolean",
"default": false
},
{
"name": "helperText",
"type": "string",
"required": false
},
{
"name": "rows",
"type": "number",
"default": 3
},
{
"name": "value",
"type": "string",
"default": ""
}
],
"state": [
{
"name": "error",
"type": "string",
"default": ""
},
{
"name": "touched",
"type": "boolean",
"default": false
}
],
"handlers": {
"onChange": "fields.handleChange",
"onBlur": "fields.handleBlur",
"validate": "validate.validateField"
},
"render": {
"type": "element",
"template": {
"type": "Box",
"className": "form-field",
"children": [
{
"type": "Label",
"htmlFor": "{{name}}",
"children": [
"{{label}}",
{
"type": "conditional",
"condition": "{{required}}",
"then": {
"type": "span",
"className": "text-red-500",
"children": " *"
}
}
]
},
{
"type": "conditional",
"condition": "{{type === 'textarea'}}",
"then": {
"type": "Textarea",
"id": "{{name}}",
"name": "{{name}}",
"placeholder": "{{placeholder}}",
"required": "{{required}}",
"rows": "{{rows}}",
"value": "{{value}}",
"onChange": "onChange",
"onBlur": "onBlur"
},
"else": {
"type": "Input",
"id": "{{name}}",
"name": "{{name}}",
"type": "{{type}}",
"placeholder": "{{placeholder}}",
"required": "{{required}}",
"value": "{{value}}",
"onChange": "onChange",
"onBlur": "onBlur"
}
},
{
"type": "conditional",
"condition": "{{helperText && !error}}",
"then": {
"type": "Text",
"variant": "caption",
"color": "secondary",
"children": "{{helperText}}"
}
},
{
"type": "conditional",
"condition": "{{error && touched}}",
"then": {
"type": "Text",
"variant": "caption",
"color": "error",
"children": "{{error}}"
}
}
]
}
}
},
{
"id": "email_field",
"name": "EmailField",
"description": "Email input field with validation",
"props": [
{
"name": "name",
"type": "string",
"default": "email"
},
{
"name": "label",
"type": "string",
"default": "Email"
},
{
"name": "required",
"type": "boolean",
"default": true
}
],
"handlers": {
"validate": "validate.validateEmail"
},
"render": {
"type": "element",
"template": {
"type": "FormField",
"name": "{{name}}",
"label": "{{label}}",
"type": "email",
"required": "{{required}}",
"placeholder": "you@example.com"
}
}
},
{
"id": "password_field",
"name": "PasswordField",
"description": "Password input field with show/hide toggle",
"props": [
{
"name": "name",
"type": "string",
"default": "password"
},
{
"name": "label",
"type": "string",
"default": "Password"
},
{
"name": "required",
"type": "boolean",
"default": true
},
{
"name": "showStrength",
"type": "boolean",
"default": false
}
],
"state": [
{
"name": "showPassword",
"type": "boolean",
"default": false
}
],
"handlers": {
"toggleVisibility": "fields.togglePasswordVisibility",
"validate": "validate.validatePassword"
},
"render": {
"type": "element",
"template": {
"type": "Box",
"className": "password-field",
"children": [
{
"type": "FormField",
"name": "{{name}}",
"label": "{{label}}",
"type": "{{showPassword ? 'text' : 'password'}}",
"required": "{{required}}"
},
{
"type": "Button",
"variant": "ghost",
"size": "sm",
"onClick": "toggleVisibility",
"children": "{{showPassword ? 'Hide' : 'Show'}}"
}
]
}
}
},
{
"id": "search_bar",
"name": "SearchBar",
"description": "Search input with icon and clear button",
"props": [
{
"name": "placeholder",
"type": "string",
"default": "Search..."
},
{
"name": "value",
"type": "string",
"default": ""
}
],
"handlers": {
"onChange": "fields.handleSearch",
"onClear": "fields.clearSearch"
},
"render": {
"type": "element",
"template": {
"type": "Box",
"className": "search-bar",
"children": [
{
"type": "Icon",
"name": "Search",
"size": 20
},
{
"type": "Input",
"type": "search",
"placeholder": "{{placeholder}}",
"value": "{{value}}",
"onChange": "onChange"
},
{
"type": "conditional",
"condition": "{{value}}",
"then": {
"type": "Button",
"variant": "ghost",
"size": "sm",
"onClick": "onClear",
"children": [
{
"type": "Icon",
"name": "X",
"size": 16
}
]
}
}
]
}
}
},
{
"id": "contact_form",
"name": "ContactForm",
"description": "Complete contact form with name, email, and message",
"props": [
{
"name": "title",
"type": "string",
"default": "Contact form"
},
{
"name": "description",
"type": "string",
"default": "Collect a name, email, and short message with simple validation."
},
{
"name": "submitLabel",
"type": "string",
"default": "Send message"
}
],
"state": [
{
"name": "submitted",
"type": "boolean",
"default": false
},
{
"name": "loading",
"type": "boolean",
"default": false
}
],
"handlers": {
"onSubmit": "contact_form.handleSubmit",
"validate": "contact_form.validate"
},
"render": {
"type": "element",
"template": {
"type": "Card",
"className": "max-w-xl",
"children": [
{
"type": "CardHeader",
"children": [
{
"type": "CardTitle",
"text": "{{title}}"
},
{
"type": "CardDescription",
"text": "{{description}}"
}
]
},
{
"type": "CardContent",
"children": [
{
"type": "conditional",
"condition": "{{!submitted}}",
"then": {
"type": "form",
"className": "space-y-4",
"onSubmit": "onSubmit",
"children": [
{
"type": "FormField",
"name": "name",
"label": "Name",
"placeholder": "Your name",
"required": true
},
{
"type": "FormField",
"name": "email",
"label": "Email",
"type": "email",
"placeholder": "you@example.com",
"required": true,
"helperText": "We will only use this to reply to your note."
},
{
"type": "FormField",
"name": "message",
"label": "Message",
"type": "textarea",
"placeholder": "How can we help?",
"required": true,
"rows": 4
},
{
"type": "Button",
"type": "submit",
"disabled": "{{loading}}",
"children": "{{loading ? 'Sending...' : submitLabel}}"
}
]
},
"else": {
"type": "Box",
"className": "text-center py-8",
"children": [
{
"type": "Icon",
"name": "CheckCircle",
"size": 48,
"color": "success"
},
{
"type": "Text",
"variant": "h6",
"children": "Message sent"
},
{
"type": "Text",
"variant": "body2",
"color": "secondary",
"children": "Thanks for reaching out. We will get back to you shortly."
}
]
}
}
]
}
]
}
}
}
],
"exports": {
"components": ["FormField", "EmailField", "PasswordField", "NumberField", "SearchBar", "ContactForm"]
}
}

View File

@@ -0,0 +1,71 @@
{
"$schema": "https://metabuilder.dev/schemas/forms.schema.json",
"schemaVersion": "1.0.0",
"package": "form_builder",
"description": "Form definitions for form builder package",
"forms": [
{
"id": "contact_form",
"name": "ContactForm",
"title": "Contact Us",
"description": "Send us a message",
"layout": "vertical",
"fields": [
{
"name": "name",
"type": "text",
"label": "Name",
"placeholder": "Your name",
"required": true,
"validation": {
"required": "Name is required",
"minLength": 2,
"maxLength": 100,
"messages": {
"minLength": "Name must be at least 2 characters",
"maxLength": "Name cannot exceed 100 characters"
}
}
},
{
"name": "email",
"type": "email",
"label": "Email",
"placeholder": "you@example.com",
"required": true,
"helpText": "We will only use this to reply to your note.",
"validation": {
"required": "Email is required",
"email": true,
"messages": {
"email": "Please enter a valid email address"
}
}
},
{
"name": "message",
"type": "textarea",
"label": "Message",
"placeholder": "How can we help?",
"required": true,
"rows": 4,
"validation": {
"required": "Message is required",
"minLength": 10,
"maxLength": 1000,
"messages": {
"minLength": "Message must be at least 10 characters",
"maxLength": "Message cannot exceed 1000 characters"
}
}
}
],
"submitButton": {
"label": "Send message",
"variant": "primary"
},
"onSubmit": "contact_form.handleSubmit",
"successMessage": "Thanks for reaching out. We will get back to you shortly."
}
]
}

View File

@@ -0,0 +1,53 @@
{
"$schema": "https://metabuilder.dev/schemas/package-metadata.schema.json",
"packageId": "form_builder",
"name": "Form Builder",
"version": "1.0.0",
"description": "Form fields, validation, and submission handling",
"author": "MetaBuilder",
"license": "MIT",
"category": "ui",
"minLevel": 1,
"primary": false,
"dependencies": {},
"devDependencies": {
"lua_test": "*"
},
"exports": {
"components": [
"FormField",
"EmailField",
"PasswordField",
"NumberField",
"SearchBar",
"ContactForm"
],
"scripts": [
"fields",
"validate",
"contact_form"
]
},
"tests": {
"scripts": [
"tests/metadata.test.lua",
"tests/components.test.lua",
"tests/validate.test.lua",
"tests/contact_form.test.lua"
],
"parameterized": [
{
"parameters": "tests/metadata.cases.json"
},
{
"parameters": "tests/components.cases.json"
},
{
"parameters": "tests/validate.cases.json"
},
{
"parameters": "tests/contact_form.cases.json"
}
]
}
}

View File

@@ -0,0 +1,129 @@
{
"$schema": "https://metabuilder.dev/schemas/json-script.schema.json",
"schemaVersion": "2.2.0",
"package": "form_builder",
"description": "Form field handlers and validation functions",
"functions": [
{
"id": "fields_handle_change",
"name": "handleChange",
"exported": true,
"description": "Handle field value change",
"category": "handlers",
"luaScript": "fields.lua"
},
{
"id": "fields_handle_blur",
"name": "handleBlur",
"exported": true,
"description": "Handle field blur event",
"category": "handlers",
"luaScript": "fields.lua"
},
{
"id": "fields_handle_search",
"name": "handleSearch",
"exported": true,
"description": "Handle search input change",
"category": "handlers",
"luaScript": "fields.lua"
},
{
"id": "fields_clear_search",
"name": "clearSearch",
"exported": true,
"description": "Clear search input",
"category": "handlers",
"luaScript": "fields.lua"
},
{
"id": "fields_toggle_password",
"name": "togglePasswordVisibility",
"exported": true,
"description": "Toggle password visibility",
"category": "handlers",
"luaScript": "fields.lua"
},
{
"id": "validate_field",
"name": "validateField",
"exported": true,
"description": "Validate a single form field",
"category": "validation",
"luaScript": "validate.lua"
},
{
"id": "validate_email",
"name": "validateEmail",
"exported": true,
"description": "Validate email address format",
"category": "validation",
"luaScript": "validate.lua"
},
{
"id": "validate_password",
"name": "validatePassword",
"exported": true,
"description": "Validate password strength",
"category": "validation",
"luaScript": "validate.lua"
},
{
"id": "validate_required",
"name": "validateRequired",
"exported": true,
"description": "Check if required field has value",
"category": "validation",
"luaScript": "validate.lua"
},
{
"id": "validate_form",
"name": "validateForm",
"exported": true,
"description": "Validate entire form",
"category": "validation",
"luaScript": "validate.lua"
},
{
"id": "contact_form_handle_submit",
"name": "handleSubmit",
"exported": true,
"description": "Handle contact form submission",
"category": "forms",
"luaScript": "contact_form.lua"
},
{
"id": "contact_form_validate",
"name": "validate",
"exported": true,
"description": "Validate contact form",
"category": "forms",
"luaScript": "contact_form.lua"
},
{
"id": "contact_form_create_state",
"name": "createInitialState",
"exported": true,
"description": "Create initial form state",
"category": "forms",
"luaScript": "contact_form.lua"
}
],
"exports": {
"functions": [
"handleChange",
"handleBlur",
"handleSearch",
"clearSearch",
"togglePasswordVisibility",
"validateField",
"validateEmail",
"validatePassword",
"validateRequired",
"validateForm",
"handleSubmit",
"validate",
"createInitialState"
]
}
}

View File

@@ -0,0 +1,61 @@
{
"$schema": "https://metabuilder.dev/schemas/package-storybook.schema.json",
"featured": false,
"title": "Form Builder",
"description": "Reusable form fields with built-in validation",
"stories": [
{
"name": "FormFields",
"render": "fields",
"description": "Various form field types with validation",
"type": "component"
},
{
"name": "ContactForm",
"render": "contact_form",
"description": "Complete contact form example",
"type": "component"
},
{
"name": "EmailField",
"render": "fields",
"description": "Email input with validation"
},
{
"name": "PasswordField",
"render": "fields",
"description": "Password field with show/hide toggle"
},
{
"name": "SearchBar",
"render": "fields",
"description": "Search input with clear button"
}
],
"renders": {
"fields": {
"description": "Form field components showcase"
},
"contact_form": {
"description": "Contact form with validation",
"featured": true
}
},
"defaultContext": {
"user": {
"id": "demo-user",
"username": "demo_user",
"level": 1
}
},
"scripts": {
"renderFunctions": ["fields", "validate", "contact_form"],
"ignoredScripts": ["tests"]
},
"parameters": {
"layout": "padded",
"backgrounds": {
"default": "light"
}
}
}

View File

@@ -0,0 +1,22 @@
{
"$schema": "https://metabuilder.dev/schemas/package-styles.schema.json",
"schemaVersion": "2.0.0",
"colors": {
"fieldBorder": "#d1d5db",
"fieldBorderFocus": "#3b82f6",
"fieldBorderError": "#ef4444",
"fieldBackground": "#ffffff",
"fieldText": "#1f2937",
"labelText": "#374151",
"helperText": "#6b7280",
"errorText": "#ef4444"
},
"spacing": {
"fieldPadding": "8px 12px",
"labelMargin": "0 0 4px 0",
"helperMargin": "4px 0 0 0"
},
"borderRadius": {
"field": "6px"
}
}

View File

@@ -0,0 +1,123 @@
{
"$schema": "https://metabuilder.dev/schemas/validation.schema.json",
"schemaVersion": "2.0.0",
"package": "form_builder",
"description": "Validation patterns and functions for form fields",
"patterns": {
"email": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"password": "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,}$",
"url": "^https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)$",
"phone": "^[\\+]?[(]?[0-9]{3}[)]?[-\\s\\.]?[0-9]{3}[-\\s\\.]?[0-9]{4,6}$",
"zipCode": "^[0-9]{5}(?:-[0-9]{4})?$",
"username": "^[a-zA-Z0-9_-]{3,16}$"
},
"functions": [
{
"id": "validate_email",
"name": "validateEmail",
"description": "Validate email address format",
"params": [
{
"name": "email",
"type": "string",
"required": true
}
],
"returnType": "boolean",
"async": false,
"pattern": "email",
"errorMessage": "Please enter a valid email address"
},
{
"id": "validate_password",
"name": "validatePassword",
"description": "Validate password strength (min 8 chars, uppercase, lowercase, number)",
"params": [
{
"name": "password",
"type": "string",
"required": true
}
],
"returnType": "boolean",
"async": false,
"pattern": "password",
"errorMessage": "Password must be at least 8 characters and contain uppercase, lowercase, and numbers"
},
{
"id": "validate_required",
"name": "validateRequired",
"description": "Check if field has a value",
"params": [
{
"name": "value",
"type": "any",
"required": true
}
],
"returnType": "boolean",
"async": false,
"errorMessage": "This field is required"
},
{
"id": "validate_min_length",
"name": "validateMinLength",
"description": "Check minimum string length",
"params": [
{
"name": "value",
"type": "string",
"required": true
},
{
"name": "minLength",
"type": "number",
"required": true
}
],
"returnType": "boolean",
"async": false,
"errorMessage": "Must be at least ${minLength} characters"
},
{
"id": "validate_max_length",
"name": "validateMaxLength",
"description": "Check maximum string length",
"params": [
{
"name": "value",
"type": "string",
"required": true
},
{
"name": "maxLength",
"type": "number",
"required": true
}
],
"returnType": "boolean",
"async": false,
"errorMessage": "Must be no more than ${maxLength} characters"
},
{
"id": "validate_url",
"name": "validateURL",
"description": "Validate URL format",
"params": [
{
"name": "url",
"type": "string",
"required": true
}
],
"returnType": "boolean",
"async": false,
"pattern": "url",
"errorMessage": "Please enter a valid URL"
}
],
"exports": {
"patterns": ["email", "password", "url", "phone", "zipCode", "username"],
"functions": ["validateEmail", "validatePassword", "validateRequired", "validateMinLength", "validateMaxLength", "validateURL"]
}
}

View File

@@ -0,0 +1,281 @@
{
"$schema": "https://metabuilder.dev/schemas/json-script-components.schema.json",
"schemaVersion": "2.0.0",
"package": "notification_center",
"description": "Notification components including toast, list, and summary",
"components": [
{
"id": "notification_summary",
"name": "NotificationSummary",
"description": "Summary card showing notification counts by severity level",
"props": [
{
"name": "title",
"type": "string",
"default": "Notification Summary"
},
{
"name": "subtitle",
"type": "string",
"required": false
},
{
"name": "totalLabel",
"type": "string",
"default": "Total"
}
],
"state": [
{
"name": "total",
"type": "number",
"default": 0
},
{
"name": "items",
"type": "array",
"default": []
}
],
"handlers": {
"init": "summary.prepareSummary"
},
"render": {
"type": "element",
"template": {
"type": "Card",
"className": "space-y-4 p-4",
"children": [
{
"type": "Box",
"className": "space-y-1",
"children": [
{
"type": "Typography",
"variant": "overline",
"className": "tracking-[0.3em] text-muted-foreground",
"children": "{{title}}"
},
{
"type": "Box",
"className": "flex items-baseline justify-between gap-3",
"children": [
{
"type": "Typography",
"variant": "h3",
"className": "font-bold",
"children": "{{total}}"
},
{
"type": "Badge",
"variant": "secondary",
"label": "{{totalLabel}}"
}
]
}
]
},
{
"type": "Separator"
},
{
"type": "List",
"dataSource": "items",
"className": "space-y-3",
"itemTemplate": {
"type": "Box",
"className": "flex items-center justify-between gap-3",
"children": [
{
"type": "Box",
"children": [
{
"type": "Typography",
"variant": "body2",
"fontWeight": "semibold",
"children": "{{item.label}}"
},
{
"type": "Typography",
"variant": "caption",
"color": "textSecondary",
"children": "{{item.hint}}"
}
]
},
{
"type": "Box",
"className": "flex items-center gap-2",
"children": [
{
"type": "Badge",
"variant": "outline",
"className": "{{item.classes}}",
"label": "{{item.count}}"
},
{
"type": "Typography",
"variant": "overline",
"className": "tracking-[0.4em]",
"children": "{{item.severity}}"
}
]
}
]
}
}
]
}
}
},
{
"id": "notification_toast",
"name": "NotificationToast",
"description": "Toast notification popup",
"props": [
{
"name": "type",
"type": "string",
"default": "info",
"enum": ["info", "success", "warning", "error"]
},
{
"name": "title",
"type": "string",
"required": true
},
{
"name": "message",
"type": "string",
"required": true
},
{
"name": "duration",
"type": "number",
"default": 5000
}
],
"handlers": {
"onDismiss": "toast.dismiss"
},
"render": {
"type": "element",
"template": {
"type": "Box",
"className": "toast toast-{{type}}",
"children": [
{
"type": "Icon",
"name": "{{type === 'success' ? 'CheckCircle' : type === 'error' ? 'XCircle' : type === 'warning' ? 'AlertTriangle' : 'Info'}}",
"size": 20
},
{
"type": "Box",
"children": [
{
"type": "Text",
"fontWeight": "semibold",
"children": "{{title}}"
},
{
"type": "Text",
"variant": "caption",
"children": "{{message}}"
}
]
},
{
"type": "Button",
"variant": "ghost",
"size": "sm",
"onClick": "onDismiss",
"children": [
{
"type": "Icon",
"name": "X",
"size": 16
}
]
}
]
}
}
},
{
"id": "notification_list",
"name": "NotificationList",
"description": "List of notifications with read/unread status",
"props": [
{
"name": "notifications",
"type": "array",
"default": []
},
{
"name": "showUnreadOnly",
"type": "boolean",
"default": false
}
],
"handlers": {
"markAsRead": "list.markAsRead",
"dismiss": "list.dismiss"
},
"render": {
"type": "element",
"template": {
"type": "List",
"dataSource": "notifications",
"className": "notification-list",
"itemTemplate": {
"type": "Box",
"className": "notification-item {{item.read ? 'read' : 'unread'}}",
"children": [
{
"type": "Icon",
"name": "{{item.icon || 'Bell'}}",
"size": 24,
"color": "{{item.type}}"
},
{
"type": "Box",
"className": "flex-1",
"children": [
{
"type": "Text",
"fontWeight": "{{item.read ? 'normal' : 'semibold'}}",
"children": "{{item.title}}"
},
{
"type": "Text",
"variant": "caption",
"color": "secondary",
"children": "{{item.message}}"
},
{
"type": "Text",
"variant": "caption",
"color": "secondary",
"children": "{{item.createdAt}}"
}
]
},
{
"type": "conditional",
"condition": "{{!item.read}}",
"then": {
"type": "Badge",
"variant": "dot",
"color": "primary"
}
}
]
}
}
}
}
],
"exports": {
"components": ["NotificationSummary", "NotificationToast", "NotificationList"]
}
}

View File

@@ -0,0 +1,115 @@
{
"$schema": "https://metabuilder.dev/schemas/entities.schema.json",
"schemaVersion": "2.0.0",
"entities": [
{
"name": "Notification",
"version": "1.0",
"description": "User notification for alerts, messages, and system events",
"primaryKey": "id",
"timestamps": false,
"softDelete": false,
"fields": {
"id": {
"type": "string",
"generated": true,
"description": "Unique identifier (CUID)"
},
"tenantId": {
"type": "string",
"required": true,
"index": true,
"description": "Tenant identifier"
},
"userId": {
"type": "string",
"required": true,
"index": true,
"description": "User who receives this notification"
},
"type": {
"type": "enum",
"required": true,
"enum": ["info", "warning", "success", "error", "mention", "reply", "follow", "like", "system"],
"description": "Notification type/severity"
},
"title": {
"type": "string",
"required": true,
"maxLength": 200,
"description": "Notification title"
},
"message": {
"type": "string",
"required": true,
"description": "Notification message body"
},
"icon": {
"type": "string",
"nullable": true,
"description": "Icon name for display"
},
"read": {
"type": "boolean",
"default": false,
"index": true,
"description": "Whether notification has been read"
},
"data": {
"type": "text",
"nullable": true,
"description": "JSON: action URLs, entity references, etc."
},
"createdAt": {
"type": "bigint",
"required": true,
"index": true,
"description": "Creation timestamp in milliseconds"
},
"expiresAt": {
"type": "bigint",
"nullable": true,
"index": true,
"description": "Expiration timestamp in milliseconds"
}
},
"indexes": [
{
"fields": ["tenantId"],
"name": "idx_notification_tenant"
},
{
"fields": ["userId", "read"],
"name": "idx_notification_user_read"
},
{
"fields": ["createdAt"],
"name": "idx_notification_created"
}
],
"relations": [
{
"name": "tenant",
"type": "belongsTo",
"entity": "Tenant",
"field": "tenantId",
"onDelete": "Cascade"
},
{
"name": "user",
"type": "belongsTo",
"entity": "User",
"field": "userId",
"onDelete": "Cascade"
}
],
"acl": {
"create": ["system", "admin"],
"read": ["self"],
"update": ["self"],
"delete": ["self"],
"rowLevel": "userId = currentUser.id"
}
}
]
}

View File

@@ -0,0 +1,48 @@
{
"$schema": "https://metabuilder.dev/schemas/events.schema.json",
"schemaVersion": "1.0.0",
"package": "notification_center",
"description": "Notification event definitions and handlers",
"events": [
{
"name": "notification.created",
"version": "1.0.0",
"description": "Fired when a new notification is created",
"payload": "Notification"
},
{
"name": "notification.read",
"version": "1.0.0",
"description": "Fired when a notification is marked as read",
"payload": {
"notificationId": "string",
"userId": "string"
}
},
{
"name": "notification.dismissed",
"version": "1.0.0",
"description": "Fired when a notification is dismissed",
"payload": {
"notificationId": "string",
"userId": "string"
}
}
],
"subscribers": [
{
"id": "show_toast_on_create",
"name": "Show Toast on Notification",
"events": ["notification.created"],
"handler": "toast.showToast",
"description": "Display toast when new notification arrives"
},
{
"id": "update_count_on_read",
"name": "Update Count on Read",
"events": ["notification.read"],
"handler": "summary.prepareSummary",
"description": "Update notification count when marked as read"
}
]
}

View File

@@ -0,0 +1,43 @@
{
"$schema": "https://metabuilder.dev/schemas/package-metadata.schema.json",
"packageId": "notification_center",
"name": "Notification Center",
"version": "1.0.0",
"description": "Notification center components and summary cards",
"author": "MetaBuilder",
"license": "MIT",
"category": "ui",
"minLevel": 1,
"primary": false,
"dependencies": {},
"devDependencies": {
"lua_test": "*"
},
"exports": {
"components": [
"NotificationSummary",
"NotificationList",
"NotificationToast"
],
"scripts": [
"init",
"toast",
"list",
"summary"
]
},
"tests": {
"scripts": [
"tests/metadata.test.lua",
"tests/components.test.lua"
],
"parameterized": [
{
"parameters": "tests/metadata.cases.json"
},
{
"parameters": "tests/components.cases.json"
}
]
}
}

View File

@@ -0,0 +1,83 @@
{
"$schema": "https://metabuilder.dev/schemas/json-script.schema.json",
"schemaVersion": "2.2.0",
"package": "notification_center",
"description": "Notification management and display functions",
"functions": [
{
"id": "init_load",
"name": "loadNotifications",
"exported": true,
"description": "Load user notifications",
"category": "lifecycle",
"luaScript": "init.lua"
},
{
"id": "toast_show",
"name": "showToast",
"exported": true,
"description": "Display toast notification",
"category": "ui",
"luaScript": "toast.lua"
},
{
"id": "toast_dismiss",
"name": "dismiss",
"exported": true,
"description": "Dismiss toast notification",
"category": "ui",
"luaScript": "toast.lua"
},
{
"id": "list_mark_read",
"name": "markAsRead",
"exported": true,
"description": "Mark notification as read",
"category": "actions",
"luaScript": "list.lua"
},
{
"id": "list_dismiss",
"name": "dismiss",
"exported": true,
"description": "Dismiss notification",
"category": "actions",
"luaScript": "list.lua"
},
{
"id": "list_mark_all_read",
"name": "markAllAsRead",
"exported": true,
"description": "Mark all notifications as read",
"category": "actions",
"luaScript": "list.lua"
},
{
"id": "summary_prepare",
"name": "prepareSummary",
"exported": true,
"description": "Prepare notification summary data",
"category": "analytics",
"luaScript": "summary.lua"
},
{
"id": "summary_count_by_type",
"name": "countByType",
"exported": true,
"description": "Count notifications by type",
"category": "analytics",
"luaScript": "summary.lua"
}
],
"exports": {
"functions": [
"loadNotifications",
"showToast",
"dismiss",
"markAsRead",
"markAllAsRead",
"prepareSummary",
"countByType"
]
}
}

View File

@@ -0,0 +1,57 @@
{
"$schema": "https://metabuilder.dev/schemas/package-storybook.schema.json",
"featured": false,
"title": "Notification Center",
"description": "Notification management and display components",
"stories": [
{
"name": "NotificationCenter",
"render": "init",
"description": "Complete notification center with list and summary"
},
{
"name": "NotificationToast",
"render": "toast",
"description": "Toast notification popup",
"args": {
"type": "success",
"title": "Success",
"message": "Your changes have been saved"
}
},
{
"name": "NotificationSummary",
"render": "summary",
"description": "Notification summary card"
}
],
"renders": {
"init": {
"description": "Full notification center",
"featured": true
},
"toast": {
"description": "Toast notifications"
},
"summary": {
"description": "Notification summary statistics"
},
"list": {
"description": "Notification list view"
}
},
"defaultContext": {
"user": {
"id": "demo-user",
"username": "demo_user",
"level": 1
}
},
"scripts": {
"renderFunctions": ["init", "toast", "list", "summary"],
"ignoredScripts": ["tests"]
},
"parameters": {
"layout": "padded"
}
}

View File

@@ -0,0 +1,19 @@
{
"$schema": "https://metabuilder.dev/schemas/package-styles.schema.json",
"schemaVersion": "2.0.0",
"colors": {
"notificationInfo": "#3b82f6",
"notificationSuccess": "#10b981",
"notificationWarning": "#f59e0b",
"notificationError": "#ef4444",
"notificationUnread": "#6366f1",
"notificationRead": "#9ca3af"
},
"spacing": {
"toastPadding": "12px 16px",
"notificationItem": "12px"
},
"shadows": {
"toast": "0 4px 12px rgba(0, 0, 0, 0.15)"
}
}