diff --git a/.env-dev b/.env-dev index 987fc85..50d28c3 100644 --- a/.env-dev +++ b/.env-dev @@ -5,7 +5,7 @@ APP_NAME=Tabler APP_ENV=local # local | testing | production APP_DEBUG_MODE=true App_HTTP_HOST=localhost -App_HTTP_PORT=8080 +App_HTTP_PORT=8081 App_USE_HTTPS=false App_USE_LETSENCRYPT=false App_USE_CORESERVICES=true @@ -60,7 +60,7 @@ CACHE_DRIVER=redis REDIS_HOST=localhost REDIS_PORT=6379 REDIS_PASSWORD= -REDIS_DB=1 +REDIS_DB=2 ####################################### ###### Emails ###### diff --git a/controllers/tablerbase.go b/controllers/tablerbase.go index bfbf06c..4a65292 100644 --- a/controllers/tablerbase.go +++ b/controllers/tablerbase.go @@ -310,3 +310,258 @@ func TablerHome(c *core.Context) *core.Response { } return c.Response.Template("tabler_homepage.html", data) } + +// DemoForm1 renders the sample contact form using the form generator. +func DemoForm1(c *core.Context) *core.Response { + type demoForm1Data struct { + TablerPageData + FormDefinition FormtablerFormDefinition + } + data := demoForm1Data{ + TablerPageData: TablerPageData{ + PageTitle: "Demo Form 1", + PageDescription: "Sample contact form generated from JSON definition", + ShowTopbar: true, + Sidebar: false, + PageHeader: "Contact Form", + PagePretitle: "Demo Form Generator", + UserName: "Jane Doe", + UserRole: "Administrator", + NavbarMenu: SampleNavbarMenu(), + }, + FormDefinition: FormtablerFormDefinition{ + ID: "contact-form", + Title: "Contact us", + SuccessMessage: "Thanks! We'll get back to you soon.", + Method: "POST", + Fields: []FormtablerFormField{ + { + Name: "name", + Label: "Name", + Type: "text", + Required: true, + Placeholder: "Jane Doe", + }, + { + Name: "email", + Label: "Email", + Type: "email", + Required: true, + Placeholder: "jane@example.com", + }, + { + Name: "phone", + Label: "Phone", + Type: "phone", + Required: false, + Placeholder: "+1 555 000 0000", + }, + { + Name: "message", + Label: "Message", + Type: "textarea", + Required: true, + Placeholder: "How can we help?", + MaxLength: 1000, + }, + }, + }, + } + return c.Response.Template("apptabler_demoform.html", data) +} + +// DemoForm2 renders an advanced form using all available field types. +func DemoForm2(c *core.Context) *core.Response { + type demoForm2Data struct { + TablerPageData + FormDefinition FormtablerFormDefinition + } + data := demoForm2Data{ + TablerPageData: TablerPageData{ + PageTitle: "Demo Form 2", + PageDescription: "Advanced form with all field types", + ShowTopbar: true, + Sidebar: false, + PageHeader: "Advanced Registration Form", + PagePretitle: "Demo Form Generator", + UserName: "Jane Doe", + UserRole: "Administrator", + NavbarMenu: SampleNavbarMenu(), + }, + FormDefinition: FormtablerFormDefinition{ + ID: "advanced-registration", + Title: "User Registration", + SuccessMessage: "Registration submitted successfully! We'll review your application.", + Method: "POST", + Columns: 3, + FieldsetTitle: "Personal Information", + FieldsetDescription: "Please fill in all required fields marked with an asterisk (*).", + Fields: []FormtablerFormField{ + { + Name: "first_name", + Label: "First Name", + Type: "text", + Required: true, + Placeholder: "John", + MinLength: 2, + MaxLength: 50, + Autofocus: true, + }, + { + Name: "last_name", + Label: "Last Name", + Type: "text", + Required: true, + Placeholder: "Doe", + MinLength: 2, + MaxLength: 50, + }, + { + Name: "email", + Label: "Email Address", + Type: "email", + Required: true, + Placeholder: "john.doe@example.com", + }, + { + Name: "phone", + Label: "Phone Number", + Type: "phone", + Required: true, + Placeholder: "+1 (555) 000-0000", + HelpText: "Include country code for international numbers.", + }, + { + Name: "account_type", + Label: "Account Type", + Type: "select", + Required: true, + Options: []FormtablerFormFieldOption{ + {Label: "Personal", Value: "personal", Selected: true}, + {Label: "Business", Value: "business"}, + {Label: "Enterprise", Value: "enterprise"}, + }, + }, + { + Name: "password", + Label: "Password", + Type: "password", + Required: true, + Placeholder: "••••••••", + MinLength: 8, + MaxLength: 128, + HelpText: "At least 8 characters with uppercase, lowercase and numbers.", + }, + { + Name: "company", + Label: "Company Name", + Type: "text", + Placeholder: "Acme Inc.", + HelpText: "Only required for Business and Enterprise accounts.", + }, + { + Name: "website", + Label: "Website", + Type: "url", + Placeholder: "https://example.com", + }, + { + Name: "bio", + Label: "Biography", + Type: "textarea", + Placeholder: "Tell us about yourself...", + MaxLength: 500, + HelpText: "Maximum 500 characters.", + }, + { + Name: "birth_date", + Label: "Date of Birth", + Type: "date", + }, + { + Name: "preferred_language", + Label: "Preferred Language", + Type: "select", + Options: []FormtablerFormFieldOption{ + {Label: "English", Value: "en", Selected: true}, + {Label: "Spanish", Value: "es"}, + {Label: "French", Value: "fr"}, + {Label: "German", Value: "de"}, + {Label: "Japanese", Value: "ja"}, + {Label: "Chinese", Value: "zh"}, + }, + }, + { + Name: "experience_level", + Label: "Experience Level", + Type: "radio", + Required: true, + Options: []FormtablerFormFieldOption{ + {Label: "Beginner", Value: "beginner", Checked: true}, + {Label: "Intermediate", Value: "intermediate"}, + {Label: "Advanced", Value: "advanced"}, + {Label: "Expert", Value: "expert"}, + }, + }, + { + Name: "skills", + Label: "Skills & Technologies", + Type: "checkbox", + HelpText: "Select all that apply.", + Options: []FormtablerFormFieldOption{ + {Label: "Go", Value: "go", Checked: true}, + {Label: "JavaScript", Value: "javascript", Checked: true}, + {Label: "Python", Value: "python"}, + {Label: "Rust", Value: "rust"}, + {Label: "Docker", Value: "docker"}, + {Label: "Kubernetes", Value: "kubernetes"}, + {Label: "PostgreSQL", Value: "postgresql"}, + {Label: "Redis", Value: "redis"}, + }, + }, + { + Name: "notifications", + Label: "Email Notifications", + Type: "toggle", + HelpText: "Receive updates about new features and security alerts.", + }, + { + Name: "website_color", + Label: "Preferred Accent Color", + Type: "color", + Value: "#206bc4", + }, + { + Name: "priority_level", + Label: "Priority Level", + Type: "range", + Min: 1, + Max: 10, + Step: 1, + Value: "5", + HelpText: "1 = Lowest priority, 10 = Highest priority", + }, + { + Name: "agree_terms", + Label: "I agree to the Terms of Service and Privacy Policy", + Type: "checkbox", + Required: true, + }, + { + Name: "marketing_consent", + Label: "I would like to receive marketing communications", + Type: "toggle", + }, + { + Name: "csrf_token", + Type: "hidden", + Value: "abc123xyz", + }, + }, + SubmitText: "Create Account", + ShowReset: true, + ResetText: "Clear All", + }, + } + return c.Response.Template("apptabler_demoform.html", data) +} diff --git a/controllers/tablerdemo.go b/controllers/tablerdemo.go index 14055dc..ad5b405 100644 --- a/controllers/tablerdemo.go +++ b/controllers/tablerdemo.go @@ -82,3 +82,60 @@ type AdminCustomersPage struct { type AuthLockPageData struct { PersonName string } + +// FormtablerFormFieldOption is an option for select, radio, or checkbox fields. +type FormtablerFormFieldOption struct { + Label string + Value string + Selected bool + Checked bool + Disabled bool +} + +// FormtablerFormField represents a single field in a JSON-defined form. +type FormtablerFormField struct { + Name string + Label string + Type string // "text", "email", "phone", "textarea", "password", "select", "checkbox", "radio", "toggle", "file", "number", "url", "date", "datetime-local", "color", "range", "hidden" + Required bool + Placeholder string + MaxLength int + MinLength int + Min float64 + Max float64 + Step float64 + Pattern string + Value string + Options []FormtablerFormFieldOption // for select, radio, checkbox + Autofocus bool + Readonly bool + Disabled bool + Multiple bool + Accept string // file accept attribute + Class string + HelpText string + ErrorText string + Success bool + Error bool + ColSpan int // for grid layout, 1-12 +} + +// FormtablerFormDefinition is the top-level structure for a JSON-defined form. +type FormtablerFormDefinition struct { + ID string + Title string + SuccessMessage string + Fields []FormtablerFormField + Method string // "GET" or "POST", default "POST" + Action string // form action URL + SubmitText string // button text, default "Submit" + ResetText string // button text for reset + ShowReset bool + Class string // form class + Layout string // "default", "inline", "horizontal", "card" + Columns int // number of columns (1, 2, 3), default 1 + Enctype string // form enctype + NoValidate bool + FieldsetTitle string // optional fieldset wrapper + FieldsetDescription string +} diff --git a/routes.go b/routes.go index 276709a..bbe51a8 100644 --- a/routes.go +++ b/routes.go @@ -92,6 +92,10 @@ func registerRoutes() { controller.Get("/admin/customers", controllers.AdminCustomers) controller.Post("/admin/customers", controllers.AdminCustomers) + // Form generator demo routes + controller.Get("/demoform1", controllers.DemoForm1) + controller.Get("/demoform2", controllers.DemoForm2) + } diff --git a/storage/templates/apptabler_demoform.html b/storage/templates/apptabler_demoform.html new file mode 100644 index 0000000..0681260 --- /dev/null +++ b/storage/templates/apptabler_demoform.html @@ -0,0 +1 @@ +{{template "default_layout" .}} \ No newline at end of file diff --git a/storage/templates/tabler/includes/forms/formtabler_generator.html b/storage/templates/tabler/includes/forms/formtabler_generator.html new file mode 100644 index 0000000..50a389c --- /dev/null +++ b/storage/templates/tabler/includes/forms/formtabler_generator.html @@ -0,0 +1,272 @@ + +{{define "formtabler_generator"}} +