improve the page, sections, components
This commit is contained in:
9
.idea/copilotDiffState.xml
generated
9
.idea/copilotDiffState.xml
generated
File diff suppressed because one or more lines are too long
@ -2,13 +2,13 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"masonry/lang"
|
"masonry/lang"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Read the example.masonry file
|
// Read the example.masonry file
|
||||||
content, err := ioutil.ReadFile("example.masonry")
|
content, err := os.ReadFile("example.masonry")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error reading example.masonry: %v\n", err)
|
fmt.Printf("Error reading example.masonry: %v\n", err)
|
||||||
return
|
return
|
||||||
@ -20,7 +20,7 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error: %v\n", err)
|
fmt.Printf("Error: %v\n", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("🎉 Successfully parsed complete DSL with pages!\n\n")
|
fmt.Printf("🎉 Successfully parsed enhanced DSL with containers and detailed fields!\n\n")
|
||||||
|
|
||||||
for _, def := range ast.Definitions {
|
for _, def := range ast.Definitions {
|
||||||
if def.Server != nil {
|
if def.Server != nil {
|
||||||
@ -55,6 +55,27 @@ func main() {
|
|||||||
if field.Default != nil {
|
if field.Default != nil {
|
||||||
fmt.Printf(" default=%s", *field.Default)
|
fmt.Printf(" default=%s", *field.Default)
|
||||||
}
|
}
|
||||||
|
if field.Relationship != nil {
|
||||||
|
fmt.Printf(" relates to %s as %s", field.Relationship.Type, field.Relationship.Cardinality)
|
||||||
|
if field.Relationship.ForeignKey != nil {
|
||||||
|
fmt.Printf(" via %s", *field.Relationship.ForeignKey)
|
||||||
|
}
|
||||||
|
if field.Relationship.Through != nil {
|
||||||
|
fmt.Printf(" through %s", *field.Relationship.Through)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(field.Validations) > 0 {
|
||||||
|
fmt.Printf(" validates: ")
|
||||||
|
for i, val := range field.Validations {
|
||||||
|
if i > 0 {
|
||||||
|
fmt.Printf(", ")
|
||||||
|
}
|
||||||
|
fmt.Printf("%s", val.Type)
|
||||||
|
if val.Value != nil {
|
||||||
|
fmt.Printf("(%s)", *val.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
@ -72,7 +93,31 @@ func main() {
|
|||||||
if endpoint.Auth {
|
if endpoint.Auth {
|
||||||
fmt.Printf(" [AUTH]")
|
fmt.Printf(" [AUTH]")
|
||||||
}
|
}
|
||||||
fmt.Printf("\n\n")
|
fmt.Printf("\n")
|
||||||
|
|
||||||
|
for _, param := range endpoint.Params {
|
||||||
|
fmt.Printf(" param %s: %s from %s", param.Name, param.Type, param.Source)
|
||||||
|
if param.Required {
|
||||||
|
fmt.Printf(" (required)")
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if endpoint.Response != nil {
|
||||||
|
fmt.Printf(" returns %s", endpoint.Response.Type)
|
||||||
|
if endpoint.Response.Format != nil {
|
||||||
|
fmt.Printf(" as %s", *endpoint.Response.Format)
|
||||||
|
}
|
||||||
|
if len(endpoint.Response.Fields) > 0 {
|
||||||
|
fmt.Printf(" fields: %v", endpoint.Response.Fields)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if endpoint.CustomLogic != nil {
|
||||||
|
fmt.Printf(" custom logic: %s\n", *endpoint.CustomLogic)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
if def.Page != nil {
|
if def.Page != nil {
|
||||||
@ -87,23 +132,139 @@ func main() {
|
|||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
fmt.Printf(" Layout: %s\n", page.Layout)
|
fmt.Printf(" Layout: %s\n", page.Layout)
|
||||||
|
|
||||||
|
if page.LayoutType != nil {
|
||||||
|
fmt.Printf(" Layout Type: %s\n", *page.LayoutType)
|
||||||
|
}
|
||||||
|
|
||||||
for _, meta := range page.Meta {
|
for _, meta := range page.Meta {
|
||||||
fmt.Printf(" Meta %s: %s\n", meta.Name, meta.Content)
|
fmt.Printf(" Meta %s: %s\n", meta.Name, meta.Content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Display containers
|
||||||
|
for _, container := range page.Containers {
|
||||||
|
fmt.Printf(" 📦 Container: %s", container.Type)
|
||||||
|
if container.Class != nil {
|
||||||
|
fmt.Printf(" class=\"%s\"", *container.Class)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
|
||||||
|
for _, section := range container.Sections {
|
||||||
|
fmt.Printf(" 📂 Section: %s", section.Name)
|
||||||
|
if section.Class != nil {
|
||||||
|
fmt.Printf(" class=\"%s\"", *section.Class)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
|
||||||
|
for _, comp := range section.Components {
|
||||||
|
displayComponent(comp, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, panel := range section.Panels {
|
||||||
|
fmt.Printf(" 🗂️ Panel: %s trigger=\"%s\"", panel.Name, panel.Trigger)
|
||||||
|
if panel.Position != nil {
|
||||||
|
fmt.Printf(" position=\"%s\"", *panel.Position)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
for _, comp := range panel.Components {
|
||||||
|
displayComponent(comp, " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tab := range container.Tabs {
|
||||||
|
fmt.Printf(" 📋 Tab: %s label=\"%s\"", tab.Name, tab.Label)
|
||||||
|
if tab.Active {
|
||||||
|
fmt.Printf(" (active)")
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
for _, comp := range tab.Components {
|
||||||
|
displayComponent(comp, " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, comp := range container.Components {
|
||||||
|
displayComponent(comp, " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display direct components
|
||||||
for _, comp := range page.Components {
|
for _, comp := range page.Components {
|
||||||
fmt.Printf(" 📦 Component: %s", comp.Type)
|
displayComponent(comp, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display modals
|
||||||
|
for _, modal := range page.Modals {
|
||||||
|
fmt.Printf(" 🪟 Modal: %s trigger=\"%s\"\n", modal.Name, modal.Trigger)
|
||||||
|
for _, comp := range modal.Components {
|
||||||
|
displayComponent(comp, " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display master-detail layout
|
||||||
|
if page.MasterDetail != nil {
|
||||||
|
fmt.Printf(" 🔄 Master-Detail Layout\n")
|
||||||
|
if page.MasterDetail.Master != nil {
|
||||||
|
fmt.Printf(" 📋 Master: %s\n", page.MasterDetail.Master.Name)
|
||||||
|
for _, comp := range page.MasterDetail.Master.Components {
|
||||||
|
displayComponent(comp, " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if page.MasterDetail.Detail != nil {
|
||||||
|
fmt.Printf(" 📄 Detail: %s", page.MasterDetail.Detail.Name)
|
||||||
|
if page.MasterDetail.Detail.Trigger != nil {
|
||||||
|
fmt.Printf(" trigger=\"%s\"", *page.MasterDetail.Detail.Trigger)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
for _, comp := range page.MasterDetail.Detail.Components {
|
||||||
|
displayComponent(comp, " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func displayComponent(comp lang.Component, indent string) {
|
||||||
|
fmt.Printf("%s🧩 Component: %s", indent, comp.Type)
|
||||||
if comp.Entity != nil {
|
if comp.Entity != nil {
|
||||||
fmt.Printf(" for %s", *comp.Entity)
|
fmt.Printf(" for %s", *comp.Entity)
|
||||||
}
|
}
|
||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
|
|
||||||
for _, attr := range comp.Config {
|
// Process elements to extract fields, config, conditions, sections, and actions
|
||||||
|
var fields []lang.ComponentField
|
||||||
|
var config []lang.ComponentAttr
|
||||||
|
var conditions []lang.WhenCondition
|
||||||
|
var sections []lang.ComponentSection
|
||||||
|
var actions []lang.ComponentButtonAttr
|
||||||
|
|
||||||
|
for _, element := range comp.Elements {
|
||||||
|
if element.Field != nil {
|
||||||
|
fields = append(fields, *element.Field)
|
||||||
|
}
|
||||||
|
if element.Config != nil {
|
||||||
|
config = append(config, *element.Config)
|
||||||
|
}
|
||||||
|
if element.Condition != nil {
|
||||||
|
conditions = append(conditions, *element.Condition)
|
||||||
|
}
|
||||||
|
if element.Section != nil {
|
||||||
|
sections = append(sections, *element.Section)
|
||||||
|
}
|
||||||
|
if element.Action != nil {
|
||||||
|
actions = append(actions, *element.Action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display config attributes
|
||||||
|
for _, attr := range config {
|
||||||
if attr.Fields != nil {
|
if attr.Fields != nil {
|
||||||
fmt.Printf(" fields: %v\n", attr.Fields.Fields)
|
fmt.Printf("%s fields: %v\n", indent, attr.Fields.Fields)
|
||||||
}
|
}
|
||||||
if attr.Actions != nil {
|
if attr.Actions != nil {
|
||||||
fmt.Printf(" actions: ")
|
fmt.Printf("%s actions: ", indent)
|
||||||
for i, action := range attr.Actions.Actions {
|
for i, action := range attr.Actions.Actions {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
fmt.Printf(", ")
|
fmt.Printf(", ")
|
||||||
@ -116,24 +277,24 @@ func main() {
|
|||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
if attr.DataSource != nil {
|
if attr.DataSource != nil {
|
||||||
fmt.Printf(" data from: %s\n", attr.DataSource.Endpoint)
|
fmt.Printf("%s data from: %s\n", indent, attr.DataSource.Endpoint)
|
||||||
}
|
}
|
||||||
if attr.Style != nil {
|
if attr.Style != nil {
|
||||||
fmt.Printf(" style: %s", *attr.Style.Theme)
|
fmt.Printf("%s style: %s", indent, *attr.Style.Theme)
|
||||||
if len(attr.Style.Classes) > 0 {
|
if len(attr.Style.Classes) > 0 {
|
||||||
fmt.Printf(" classes: %v", attr.Style.Classes)
|
fmt.Printf(" classes: %v", attr.Style.Classes)
|
||||||
}
|
}
|
||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
if attr.Pagination != nil {
|
if attr.Pagination != nil {
|
||||||
fmt.Printf(" pagination: enabled")
|
fmt.Printf("%s pagination: enabled", indent)
|
||||||
if attr.Pagination.PageSize != nil {
|
if attr.Pagination.PageSize != nil {
|
||||||
fmt.Printf(" size %d", *attr.Pagination.PageSize)
|
fmt.Printf(" size %d", *attr.Pagination.PageSize)
|
||||||
}
|
}
|
||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
if attr.Filters != nil {
|
if attr.Filters != nil {
|
||||||
fmt.Printf(" filters: ")
|
fmt.Printf("%s filters: ", indent)
|
||||||
for i, filter := range attr.Filters.Filters {
|
for i, filter := range attr.Filters.Filters {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
fmt.Printf(", ")
|
fmt.Printf(", ")
|
||||||
@ -146,12 +307,165 @@ func main() {
|
|||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
if attr.Validation {
|
if attr.Validation {
|
||||||
fmt.Printf(" validation: enabled\n")
|
fmt.Printf("%s validation: enabled\n", indent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display enhanced fields
|
||||||
|
for _, field := range fields {
|
||||||
|
fmt.Printf("%s 📝 Field: %s type %s", indent, field.Name, field.Type)
|
||||||
|
|
||||||
|
// Process attributes
|
||||||
|
for _, attr := range field.Attributes {
|
||||||
|
if attr.Label != nil {
|
||||||
|
fmt.Printf(" label=\"%s\"", *attr.Label)
|
||||||
|
}
|
||||||
|
if attr.Placeholder != nil {
|
||||||
|
fmt.Printf(" placeholder=\"%s\"", *attr.Placeholder)
|
||||||
|
}
|
||||||
|
if attr.Required {
|
||||||
|
fmt.Printf(" (required)")
|
||||||
|
}
|
||||||
|
if attr.Sortable {
|
||||||
|
fmt.Printf(" (sortable)")
|
||||||
|
}
|
||||||
|
if attr.Searchable {
|
||||||
|
fmt.Printf(" (searchable)")
|
||||||
|
}
|
||||||
|
if attr.Thumbnail {
|
||||||
|
fmt.Printf(" (thumbnail)")
|
||||||
|
}
|
||||||
|
if attr.Default != nil {
|
||||||
|
fmt.Printf(" default=\"%s\"", *attr.Default)
|
||||||
|
}
|
||||||
|
if len(attr.Options) > 0 {
|
||||||
|
fmt.Printf(" options=%v", attr.Options)
|
||||||
|
}
|
||||||
|
if attr.Accept != nil {
|
||||||
|
fmt.Printf(" accept=\"%s\"", *attr.Accept)
|
||||||
|
}
|
||||||
|
if attr.Rows != nil {
|
||||||
|
fmt.Printf(" rows=%d", *attr.Rows)
|
||||||
|
}
|
||||||
|
if attr.Format != nil {
|
||||||
|
fmt.Printf(" format=\"%s\"", *attr.Format)
|
||||||
|
}
|
||||||
|
if attr.Size != nil {
|
||||||
|
fmt.Printf(" size=\"%s\"", *attr.Size)
|
||||||
|
}
|
||||||
|
if attr.Source != nil {
|
||||||
|
fmt.Printf(" source=\"%s\"", *attr.Source)
|
||||||
|
}
|
||||||
|
if attr.Display != nil {
|
||||||
|
fmt.Printf(" display=\"%s\"", *attr.Display)
|
||||||
|
}
|
||||||
|
if attr.Value != nil {
|
||||||
|
fmt.Printf(" value=\"%s\"", *attr.Value)
|
||||||
|
}
|
||||||
|
if attr.Relates != nil {
|
||||||
|
fmt.Printf(" relates to %s", attr.Relates.Type)
|
||||||
|
}
|
||||||
|
if attr.Validation != nil {
|
||||||
|
fmt.Printf(" validates: %s", attr.Validation.Type)
|
||||||
|
if attr.Validation.Value != nil {
|
||||||
|
fmt.Printf("(%s)", *attr.Validation.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Display conditions
|
||||||
|
for _, condition := range conditions {
|
||||||
|
fmt.Printf("%s 🔀 When %s %s \"%s\":\n", indent, condition.Field, condition.Operator, condition.Value)
|
||||||
|
for _, field := range condition.Fields {
|
||||||
|
fmt.Printf("%s 📝 Field: %s type %s", indent, field.Name, field.Type)
|
||||||
|
// Process attributes for conditional fields
|
||||||
|
for _, attr := range field.Attributes {
|
||||||
|
if attr.Label != nil {
|
||||||
|
fmt.Printf(" label=\"%s\"", *attr.Label)
|
||||||
|
}
|
||||||
|
if len(attr.Options) > 0 {
|
||||||
|
fmt.Printf(" options=%v", attr.Options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
for _, section := range condition.Sections {
|
||||||
|
fmt.Printf("%s 📂 Section: %s\n", indent, section.Name)
|
||||||
|
}
|
||||||
|
for _, button := range condition.Buttons {
|
||||||
|
fmt.Printf("%s 🔘 Button: %s label=\"%s\"", indent, button.Name, button.Label)
|
||||||
|
if button.Style != nil {
|
||||||
|
fmt.Printf(" style=\"%s\"", *button.Style)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display sections
|
||||||
|
for _, section := range sections {
|
||||||
|
fmt.Printf("%s 📂 Section: %s", indent, section.Name)
|
||||||
|
if section.Class != nil {
|
||||||
|
fmt.Printf(" class=\"%s\"", *section.Class)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
for _, field := range section.Fields {
|
||||||
|
fmt.Printf("%s 📝 Field: %s type %s", indent, field.Name, field.Type)
|
||||||
|
// Process attributes for section fields
|
||||||
|
for _, attr := range field.Attributes {
|
||||||
|
if attr.Label != nil {
|
||||||
|
fmt.Printf(" label=\"%s\"", *attr.Label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
for _, button := range section.Buttons {
|
||||||
|
fmt.Printf("%s 🔘 Button: %s label=\"%s\"", indent, button.Name, button.Label)
|
||||||
|
if button.Style != nil {
|
||||||
|
fmt.Printf(" style=\"%s\"", *button.Style)
|
||||||
|
}
|
||||||
|
if button.Via != nil {
|
||||||
|
fmt.Printf(" via=\"%s\"", *button.Via)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
for _, action := range section.Actions {
|
||||||
|
fmt.Printf("%s ⚡ Action: %s label=\"%s\"", indent, action.Name, action.Label)
|
||||||
|
if action.Style != nil {
|
||||||
|
fmt.Printf(" style=\"%s\"", *action.Style)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display direct actions/buttons
|
||||||
|
for _, action := range actions {
|
||||||
|
fmt.Printf("%s 🔘 Button: %s label=\"%s\"", indent, action.Name, action.Label)
|
||||||
|
if action.Style != nil {
|
||||||
|
fmt.Printf(" style=\"%s\"", *action.Style)
|
||||||
|
}
|
||||||
|
if action.Icon != nil {
|
||||||
|
fmt.Printf(" icon=\"%s\"", *action.Icon)
|
||||||
|
}
|
||||||
|
if action.Loading != nil {
|
||||||
|
fmt.Printf(" loading=\"%s\"", *action.Loading)
|
||||||
|
}
|
||||||
|
if action.Disabled != nil {
|
||||||
|
fmt.Printf(" disabled when %s", *action.Disabled)
|
||||||
|
}
|
||||||
|
if action.Confirm != nil {
|
||||||
|
fmt.Printf(" confirm=\"%s\"", *action.Confirm)
|
||||||
|
}
|
||||||
|
if action.Target != nil {
|
||||||
|
fmt.Printf(" target=\"%s\"", *action.Target)
|
||||||
|
}
|
||||||
|
if action.Position != nil {
|
||||||
|
fmt.Printf(" position=\"%s\"", *action.Position)
|
||||||
|
}
|
||||||
|
if action.Via != nil {
|
||||||
|
fmt.Printf(" via=\"%s\"", *action.Via)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Example Masonry DSL definition
|
// Enhanced Masonry DSL example demonstrating new features
|
||||||
// This demonstrates the comprehensive language structure
|
// This shows the comprehensive language structure with containers, detailed fields, and layouts
|
||||||
|
|
||||||
// Server configuration
|
// Server configuration
|
||||||
server MyApp host "localhost" port 8080
|
server MyApp host "localhost" port 8080
|
||||||
@ -65,61 +65,122 @@ endpoint POST "/posts" for Post desc "Create post" auth
|
|||||||
param post_data: object required from body
|
param post_data: object required from body
|
||||||
returns object fields [id, title, content, author_id]
|
returns object fields [id, title, content, author_id]
|
||||||
|
|
||||||
// Frontend pages with components
|
// Enhanced User Management page with container layout
|
||||||
page UserManagement at "/admin/users" layout AdminLayout title "User Management" auth
|
page UserManagement at "/admin/users" layout AdminLayout title "User Management" auth
|
||||||
meta description "Manage system users"
|
meta description "Manage system users"
|
||||||
meta keywords "users, admin, management"
|
meta keywords "users, admin, management"
|
||||||
|
|
||||||
component Table for User
|
container main class "grid grid-cols-3 gap-4"
|
||||||
fields [email, name, id]
|
section sidebar class "col-span-1"
|
||||||
actions [edit via "/users/{id}", delete via "/users/{id}", create via "/users"]
|
component UserStats for User
|
||||||
data from "/users"
|
data from "/users/stats"
|
||||||
style modern classes ["table-striped", "table-hover"]
|
|
||||||
pagination size 20
|
|
||||||
filters [email as text label "Search email", name as text label "Search name"]
|
|
||||||
validate
|
|
||||||
|
|
||||||
|
section content class "col-span-2"
|
||||||
|
component UserTable for User
|
||||||
|
fields [email, name, role, created_at]
|
||||||
|
actions [edit, delete, view]
|
||||||
|
data from "/users"
|
||||||
|
|
||||||
|
panel UserEditPanel for User trigger "edit" position "slide-right"
|
||||||
|
component UserForm for User
|
||||||
|
field email type text label "Email" required
|
||||||
|
field name type text label "Name" required
|
||||||
|
field role type select options ["admin", "user"]
|
||||||
|
button save label "Save User" style "primary" via "/users/{id}"
|
||||||
|
button cancel label "Cancel" style "secondary"
|
||||||
|
|
||||||
|
// Enhanced Form component with detailed field configurations
|
||||||
|
page UserFormPage at "/admin/users/new" layout AdminLayout title "Create User" auth
|
||||||
component Form for User
|
component Form for User
|
||||||
fields [email, name]
|
field email type text label "Email Address" placeholder "Enter your email" required validate email
|
||||||
actions [save via "/users", cancel]
|
field name type text label "Full Name" placeholder "Enter your full name" required
|
||||||
style clean
|
field role type select label "User Role" options ["admin", "user", "moderator"] default "user"
|
||||||
validate
|
field avatar type file label "Profile Picture" accept "image/*"
|
||||||
|
field bio type textarea label "Biography" placeholder "Tell us about yourself" rows 4
|
||||||
|
|
||||||
page UserList at "/users" layout MainLayout title "Users"
|
when role equals "admin"
|
||||||
meta description "Browse all users"
|
field permissions type multiselect label "Permissions"
|
||||||
|
options ["users.manage", "posts.manage", "system.config"]
|
||||||
|
|
||||||
component Table for User
|
section actions
|
||||||
fields [email, name]
|
button save label "Save User" style "primary" loading "Saving..." via "/users"
|
||||||
|
button cancel label "Cancel" style "secondary"
|
||||||
|
|
||||||
|
// Dashboard with tabbed interface
|
||||||
|
page Dashboard at "/dashboard" layout MainLayout title "Dashboard"
|
||||||
|
container tabs
|
||||||
|
tab overview label "Overview" active
|
||||||
|
component StatsCards
|
||||||
|
component RecentActivity
|
||||||
|
|
||||||
|
tab users label "Users"
|
||||||
|
component UserTable for User
|
||||||
data from "/users"
|
data from "/users"
|
||||||
pagination size 10
|
|
||||||
filters [name as text label "Search by name"]
|
|
||||||
|
|
||||||
|
tab posts label "Posts"
|
||||||
|
component PostTable for Post
|
||||||
|
data from "/posts"
|
||||||
|
|
||||||
|
modal CreateUserModal trigger "create-user"
|
||||||
|
component UserForm for User
|
||||||
|
field email type text label "Email" required
|
||||||
|
field name type text label "Name" required
|
||||||
|
button save label "Create" via "/users"
|
||||||
|
button cancel label "Cancel"
|
||||||
|
|
||||||
|
// Post Management with master-detail layout
|
||||||
page PostManagement at "/admin/posts" layout AdminLayout title "Post Management" auth
|
page PostManagement at "/admin/posts" layout AdminLayout title "Post Management" auth
|
||||||
meta description "Manage blog posts"
|
layout "master-detail"
|
||||||
meta keywords "posts, blog, content"
|
|
||||||
|
|
||||||
|
master PostList
|
||||||
component Table for Post
|
component Table for Post
|
||||||
fields [title, author_id, published, created_at]
|
field title type text label "Title" sortable
|
||||||
actions [edit via "/posts/{id}", delete via "/posts/{id}", create via "/posts"]
|
field author type relation label "Author" display "name" relates to User
|
||||||
data from "/posts"
|
field status type badge label "Status"
|
||||||
style modern
|
|
||||||
pagination size 15
|
|
||||||
filters [title as text label "Search title", published as select label "Published status"]
|
|
||||||
validate
|
|
||||||
|
|
||||||
page CreatePost at "/posts/new" layout MainLayout title "Create Post" auth
|
detail PostEditor trigger "edit"
|
||||||
component Form for Post
|
component Form for Post
|
||||||
fields [title, content]
|
section basic class "mb-4"
|
||||||
actions [save via "/posts", cancel]
|
field title type text label "Post Title" required
|
||||||
style clean
|
field content type richtext label "Content" required
|
||||||
validate
|
|
||||||
|
|
||||||
page BlogList at "/blog" layout PublicLayout title "Blog Posts"
|
section metadata class "grid grid-cols-2 gap-4"
|
||||||
meta description "Read our latest blog posts"
|
field author_id type autocomplete label "Author"
|
||||||
meta keywords "blog, articles, content"
|
source "/users" display "name" value "id"
|
||||||
|
field published type toggle label "Published" default "false"
|
||||||
|
field tags type multiselect label "Tags"
|
||||||
|
source "/tags" display "name" value "id"
|
||||||
|
|
||||||
component Table for Post
|
// Simple table component with smart defaults
|
||||||
fields [title, created_at]
|
page SimpleUserList at "/users" layout MainLayout title "Users"
|
||||||
data from "/posts"
|
component SimpleTable for User
|
||||||
pagination size 5
|
fields [email, name, created_at]
|
||||||
filters [title as text label "Search posts"]
|
actions [edit, delete]
|
||||||
|
data from "/users"
|
||||||
|
|
||||||
|
// Detailed table when more control is needed
|
||||||
|
page DetailedUserList at "/admin/users/detailed" layout AdminLayout title "Detailed User Management" auth
|
||||||
|
component DetailedTable for User
|
||||||
|
field email type text label "Email Address"
|
||||||
|
field name type text label "Full Name"
|
||||||
|
|
||||||
|
data from "/users"
|
||||||
|
pagination size 20
|
||||||
|
|
||||||
|
// Conditional rendering example
|
||||||
|
page ConditionalForm at "/conditional" layout MainLayout title "Conditional Form"
|
||||||
|
component UserForm for User
|
||||||
|
field email type text label "Email" required
|
||||||
|
field role type select options ["admin", "user", "moderator"]
|
||||||
|
|
||||||
|
when role equals "admin"
|
||||||
|
field permissions type multiselect label "Admin Permissions"
|
||||||
|
options ["users.manage", "posts.manage", "system.config"]
|
||||||
|
|
||||||
|
when role equals "moderator"
|
||||||
|
field moderation_level type select label "Moderation Level"
|
||||||
|
options ["basic", "advanced", "full"]
|
||||||
|
|
||||||
|
section actions
|
||||||
|
button save label "Save User" style "primary" loading "Saving..."
|
||||||
|
button cancel label "Cancel" style "secondary"
|
||||||
|
161
lang/lang.go
161
lang/lang.go
@ -88,7 +88,7 @@ type ResponseSpec struct {
|
|||||||
Fields []string `parser:"('fields' '[' @Ident (',' @Ident)* ']')?"`
|
Fields []string `parser:"('fields' '[' @Ident (',' @Ident)* ']')?"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Page definitions for frontend with clean syntax
|
// Enhanced Page definitions with layout containers and composition
|
||||||
type Page struct {
|
type Page struct {
|
||||||
Name string `parser:"'page' @Ident"`
|
Name string `parser:"'page' @Ident"`
|
||||||
Path string `parser:"'at' @String"`
|
Path string `parser:"'at' @String"`
|
||||||
@ -96,8 +96,12 @@ type Page struct {
|
|||||||
Title *string `parser:"('title' @String)?"`
|
Title *string `parser:"('title' @String)?"`
|
||||||
Description *string `parser:"('desc' @String)?"`
|
Description *string `parser:"('desc' @String)?"`
|
||||||
Auth bool `parser:"@'auth'?"`
|
Auth bool `parser:"@'auth'?"`
|
||||||
|
LayoutType *string `parser:"('layout' @String)?"`
|
||||||
Meta []MetaTag `parser:"@@*"`
|
Meta []MetaTag `parser:"@@*"`
|
||||||
|
MasterDetail *MasterDetail `parser:"@@?"`
|
||||||
|
Containers []Container `parser:"@@*"`
|
||||||
Components []Component `parser:"@@*"`
|
Components []Component `parser:"@@*"`
|
||||||
|
Modals []Modal `parser:"@@*"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Meta tags for SEO
|
// Meta tags for SEO
|
||||||
@ -106,14 +110,153 @@ type MetaTag struct {
|
|||||||
Content string `parser:"@String"`
|
Content string `parser:"@String"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Component definitions with endpoint references
|
// Container types for layout organization
|
||||||
|
type Container struct {
|
||||||
|
Type string `parser:"'container' @Ident"`
|
||||||
|
Class *string `parser:"('class' @String)?"`
|
||||||
|
Sections []Section `parser:"@@*"`
|
||||||
|
Tabs []Tab `parser:"@@*"`
|
||||||
|
Components []Component `parser:"@@*"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sections within containers
|
||||||
|
type Section struct {
|
||||||
|
Name string `parser:"'section' @Ident"`
|
||||||
|
Class *string `parser:"('class' @String)?"`
|
||||||
|
Components []Component `parser:"@@*"`
|
||||||
|
Panels []Panel `parser:"@@*"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tab definitions for tabbed interfaces
|
||||||
|
type Tab struct {
|
||||||
|
Name string `parser:"'tab' @Ident"`
|
||||||
|
Label string `parser:"'label' @String"`
|
||||||
|
Active bool `parser:"@'active'?"`
|
||||||
|
Components []Component `parser:"@@*"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panel definitions for slide-out or overlay interfaces
|
||||||
|
type Panel struct {
|
||||||
|
Name string `parser:"'panel' @Ident"`
|
||||||
|
Entity *string `parser:"('for' @Ident)?"`
|
||||||
|
Trigger string `parser:"'trigger' @String"`
|
||||||
|
Position *string `parser:"('position' @String)?"`
|
||||||
|
Components []Component `parser:"@@*"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modal definitions
|
||||||
|
type Modal struct {
|
||||||
|
Name string `parser:"'modal' @Ident"`
|
||||||
|
Trigger string `parser:"'trigger' @String"`
|
||||||
|
Components []Component `parser:"@@*"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Master-detail layout components - simplified parsing
|
||||||
|
type MasterDetail struct {
|
||||||
|
Master *MasterSection `parser:"'master' @@"`
|
||||||
|
Detail *DetailSection `parser:"'detail' @@"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MasterSection struct {
|
||||||
|
Name string `parser:"@Ident"`
|
||||||
|
Components []Component `parser:"@@*"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DetailSection struct {
|
||||||
|
Name string `parser:"@Ident"`
|
||||||
|
Trigger *string `parser:"('trigger' @String)?"`
|
||||||
|
Components []Component `parser:"@@*"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enhanced Component definitions with detailed field configurations
|
||||||
type Component struct {
|
type Component struct {
|
||||||
Type string `parser:"'component' @Ident"`
|
Type string `parser:"'component' @Ident"`
|
||||||
Entity *string `parser:"('for' @Ident)?"`
|
Entity *string `parser:"('for' @Ident)?"`
|
||||||
Config []ComponentAttr `parser:"@@*"`
|
Elements []ComponentElement `parser:"@@*"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Component attributes and configurations
|
// Union type for component elements to allow flexible ordering
|
||||||
|
type ComponentElement struct {
|
||||||
|
Config *ComponentAttr `parser:"@@"`
|
||||||
|
Field *ComponentField `parser:"| @@"`
|
||||||
|
Condition *WhenCondition `parser:"| @@"`
|
||||||
|
Section *ComponentSection `parser:"| @@"`
|
||||||
|
Action *ComponentButtonAttr `parser:"| @@"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enhanced component field with detailed configuration using flexible attributes
|
||||||
|
type ComponentField struct {
|
||||||
|
Name string `parser:"'field' @Ident"`
|
||||||
|
Type string `parser:"'type' @Ident"`
|
||||||
|
Attributes []ComponentFieldAttribute `parser:"@@*"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flexible field attribute system
|
||||||
|
type ComponentFieldAttribute struct {
|
||||||
|
Label *string `parser:"('label' @String)"`
|
||||||
|
Placeholder *string `parser:"| ('placeholder' @String)"`
|
||||||
|
Required bool `parser:"| @'required'"`
|
||||||
|
Sortable bool `parser:"| @'sortable'"`
|
||||||
|
Searchable bool `parser:"| @'searchable'"`
|
||||||
|
Thumbnail bool `parser:"| @'thumbnail'"`
|
||||||
|
Default *string `parser:"| ('default' @String)"`
|
||||||
|
Options []string `parser:"| ('options' '[' @String (',' @String)* ']')"`
|
||||||
|
Accept *string `parser:"| ('accept' @String)"`
|
||||||
|
Rows *int `parser:"| ('rows' @Int)"`
|
||||||
|
Format *string `parser:"| ('format' @String)"`
|
||||||
|
Size *string `parser:"| ('size' @String)"`
|
||||||
|
Display *string `parser:"| ('display' @String)"`
|
||||||
|
Value *string `parser:"| ('value' @String)"`
|
||||||
|
Source *string `parser:"| ('source' @String)"`
|
||||||
|
Relates *FieldRelation `parser:"| @@"`
|
||||||
|
Validation *ComponentValidation `parser:"| @@"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field relationship for autocomplete and select fields
|
||||||
|
type FieldRelation struct {
|
||||||
|
Type string `parser:"'relates' 'to' @Ident"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Component validation
|
||||||
|
type ComponentValidation struct {
|
||||||
|
Type string `parser:"'validate' @Ident"`
|
||||||
|
Value *string `parser:"@String?"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conditional rendering
|
||||||
|
type WhenCondition struct {
|
||||||
|
Field string `parser:"'when' @Ident"`
|
||||||
|
Operator string `parser:"@('equals' | 'not_equals' | 'contains')"`
|
||||||
|
Value string `parser:"@String"`
|
||||||
|
Fields []ComponentField `parser:"@@*"`
|
||||||
|
Sections []ComponentSection `parser:"@@*"`
|
||||||
|
Buttons []ComponentButtonAttr `parser:"@@*"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Component sections for grouping
|
||||||
|
type ComponentSection struct {
|
||||||
|
Name string `parser:"'section' @Ident"`
|
||||||
|
Class *string `parser:"('class' @String)?"`
|
||||||
|
Fields []ComponentField `parser:"@@*"`
|
||||||
|
Buttons []ComponentButtonAttr `parser:"@@*"`
|
||||||
|
Actions []ComponentButtonAttr `parser:"@@*"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enhanced component buttons/actions with detailed configuration
|
||||||
|
type ComponentButtonAttr struct {
|
||||||
|
Name string `parser:"'button' @Ident"`
|
||||||
|
Label string `parser:"'label' @String"`
|
||||||
|
Style *string `parser:"('style' @String)?"`
|
||||||
|
Icon *string `parser:"('icon' @String)?"`
|
||||||
|
Loading *string `parser:"('loading' @String)?"`
|
||||||
|
Disabled *string `parser:"('disabled' 'when' @Ident)?"`
|
||||||
|
Confirm *string `parser:"('confirm' @String)?"`
|
||||||
|
Target *string `parser:"('target' @Ident)?"`
|
||||||
|
Position *string `parser:"('position' @String)?"`
|
||||||
|
Via *string `parser:"('via' @String)?"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Component attributes and configurations (keeping existing for backward compatibility)
|
||||||
type ComponentAttr struct {
|
type ComponentAttr struct {
|
||||||
Fields *ComponentFields `parser:"@@"`
|
Fields *ComponentFields `parser:"@@"`
|
||||||
Actions *ComponentActions `parser:"| @@"`
|
Actions *ComponentActions `parser:"| @@"`
|
||||||
@ -124,19 +267,25 @@ type ComponentAttr struct {
|
|||||||
Validation bool `parser:"| @'validate'"`
|
Validation bool `parser:"| @'validate'"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Component field specification
|
// Component field specification (simple version for backward compatibility)
|
||||||
type ComponentFields struct {
|
type ComponentFields struct {
|
||||||
Fields []string `parser:"'fields' '[' @Ident (',' @Ident)* ']'"`
|
Fields []string `parser:"'fields' '[' @Ident (',' @Ident)* ']'"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Component actions (can reference endpoints)
|
// Enhanced component actions
|
||||||
type ComponentActions struct {
|
type ComponentActions struct {
|
||||||
Actions []ComponentAction `parser:"'actions' '[' @@ (',' @@)* ']'"`
|
Actions []ComponentAction `parser:"'actions' '[' @@ (',' @@)* ']'"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ComponentAction struct {
|
type ComponentAction struct {
|
||||||
Name string `parser:"@Ident"`
|
Name string `parser:"@Ident"`
|
||||||
|
Label *string `parser:"('label' @String)?"`
|
||||||
|
Icon *string `parser:"('icon' @String)?"`
|
||||||
|
Style *string `parser:"('style' @String)?"`
|
||||||
Endpoint *string `parser:"('via' @String)?"`
|
Endpoint *string `parser:"('via' @String)?"`
|
||||||
|
Target *string `parser:"('target' @Ident)?"`
|
||||||
|
Position *string `parser:"('position' @String)?"`
|
||||||
|
Confirm *string `parser:"('confirm' @String)?"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data source configuration (can reference endpoints)
|
// Data source configuration (can reference endpoints)
|
||||||
|
1396
lang/lang_test.go
1396
lang/lang_test.go
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user