initial implementation of the dialog manager, with just enough smarts to render the login dialog
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Amsterdam Web Communities System
|
||||
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
// Package main contains the high-level Amsterdam logic.
|
||||
package main
|
||||
|
||||
import "git.erbosoft.com/amy/amsterdam/ui"
|
||||
|
||||
/* LoginForm renders the Amsterdam login form.
|
||||
* Parameters:
|
||||
* ctxt - The AmContext for the request.
|
||||
* Returns:
|
||||
* Command string dictating what to be rendered.
|
||||
* Data as a parameter for the command string.
|
||||
* Standard Go error status.
|
||||
*/
|
||||
func LoginForm(ctxt ui.AmContext) (string, any, error) {
|
||||
dlg, err := ui.AmLoadDialog("login")
|
||||
if err == nil {
|
||||
ctxt.VarMap().Set("amsterdam_pageTitle", "Log In")
|
||||
return dlg.Render(ctxt)
|
||||
}
|
||||
return ui.ErrorPage(ctxt, err)
|
||||
}
|
||||
@@ -35,10 +35,14 @@ func setupEcho() *echo.Echo {
|
||||
e.Use(LogrusMiddleware)
|
||||
e.Use(session.Middleware(ui.SessionStore))
|
||||
|
||||
e.GET("/TODO/*", ui.AmWrap(NotImplPage))
|
||||
fn := ui.AmWrap(NotImplPage)
|
||||
e.GET("/TODO/*", fn)
|
||||
e.POST("/TODO/*", fn)
|
||||
e.GET("/img/*", ui.AmWrap(ui.AmServeImage))
|
||||
e.GET("/about", ui.AmWrap(AboutPage))
|
||||
|
||||
e.GET("/", ui.AmWrap(TopPage))
|
||||
e.GET("/about", ui.AmWrap(AboutPage))
|
||||
e.GET("/login", ui.AmWrap(LoginForm))
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Amsterdam Web Communities System
|
||||
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// Package ui holds the support for the Amsterdam user interface, wrapping Echo and Jet templates.
|
||||
package ui
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// DialogItem holds the dialog item definition.
|
||||
type DialogItem struct {
|
||||
Type string `yaml:"type"`
|
||||
Name string `yaml:"name"`
|
||||
Caption string `yaml:"caption,omitempty"`
|
||||
Size int `yaml:"size,omitempty"`
|
||||
MaxLength int `yaml:"maxlength,omitempty"`
|
||||
Value string `yaml:"value,omitempty"`
|
||||
Tone string `yaml:"tone,omitempty"`
|
||||
}
|
||||
|
||||
// Dialog holds the dialog definition.
|
||||
type Dialog struct {
|
||||
Name string `yaml:"name"`
|
||||
FormName string `yaml:"formName"`
|
||||
MenuSelector string `yaml:"menuSelector,omitempty"`
|
||||
Title string `yaml:"title"`
|
||||
Action string `yaml:"action"`
|
||||
Instructions string `yaml:"instructions,omitempty"`
|
||||
Fields []DialogItem `yaml:"fields"`
|
||||
}
|
||||
|
||||
//go:embed dialogs/*
|
||||
var dialogs embed.FS
|
||||
|
||||
/* AmLoadDialog loads a dialog definition.
|
||||
* Parameters:
|
||||
* name - The name of the dialog to load
|
||||
*/
|
||||
func AmLoadDialog(name string) (*Dialog, error) {
|
||||
b, err := dialogs.ReadFile(fmt.Sprintf("dialogs/%s.yaml", name))
|
||||
if err == nil {
|
||||
var d Dialog
|
||||
err = yaml.Unmarshal(b, &d)
|
||||
if err == nil {
|
||||
if d.MenuSelector == "" {
|
||||
d.MenuSelector = "nochange"
|
||||
}
|
||||
return &d, nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/* Render sets up the rendering parameters to send this dialog to the output.
|
||||
* Parameters:
|
||||
* ctxt - The AmContext for this request.
|
||||
* Returns:
|
||||
* Command string dictating what to be rendered.
|
||||
* Data as a parameter for the command string.
|
||||
* Standard Go error status.
|
||||
*/
|
||||
func (d *Dialog) Render(ctxt AmContext) (string, any, error) {
|
||||
ctxt.VarMap().Set("amsterdam_dialog", d)
|
||||
return "framed_template", "dialog.jet", nil
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#
|
||||
# Amsterdam Web Communities System
|
||||
# Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
name: "login"
|
||||
formName: "loginform"
|
||||
menuSelector: "top"
|
||||
title: "Log In"
|
||||
action: "/TODO/login"
|
||||
instructions: >
|
||||
Forgot your password? Enter your user name and click the <b>Reminder</b> button to receive
|
||||
a password reminder via E-mail.
|
||||
fields:
|
||||
- type: "hidden"
|
||||
name: "tgt"
|
||||
value: ""
|
||||
- type: "veniceid"
|
||||
name: "user"
|
||||
caption: "User Name"
|
||||
size: 32
|
||||
maxlength: 64
|
||||
- type: "password"
|
||||
name: "pass"
|
||||
caption: "Password"
|
||||
size: 32
|
||||
maxlength: 128
|
||||
- type: "checkbox"
|
||||
name: "saveme"
|
||||
caption: "Remember me for next time so I can log in automatically"
|
||||
- type: "button"
|
||||
name: "login"
|
||||
caption: "Log In"
|
||||
tone: "blue"
|
||||
- type: "button"
|
||||
name: "remind"
|
||||
caption: "Password Reminder"
|
||||
tone: "gray"
|
||||
- type: "button"
|
||||
name: "cancel"
|
||||
caption: "Cancel"
|
||||
tone: "red"
|
||||
@@ -0,0 +1,68 @@
|
||||
{*
|
||||
* Amsterdam Web Communities System
|
||||
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*}
|
||||
<div class="p-4">
|
||||
<div class="mb-6">
|
||||
<h1 class="text-blue-800 text-4xl font-bold mb-2">{{ amsterdam_dialog.Title }}</h1>
|
||||
<hr class="border-2 border-gray-400 w-4/5 mb-4">
|
||||
</div>
|
||||
<form name="{{ amsterdam_dialog.FormName }}" method="POST" action="{{ amsterdam_dialog.Action }}" class="max-w-2xl">
|
||||
{{ range amsterdam_dialog.Fields }}
|
||||
{{ if .Type == "hidden" }}
|
||||
<input type="hidden" name="{{ .Name }}" value="{{ .Value }}" />
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if amsterdam_dialog.Instructions != "" }}
|
||||
<p class="text-black text-sm mb-6">{{ amsterdam_dialog.Instructions | raw }}</p>
|
||||
{{ end }}
|
||||
|
||||
<div class="bg-gray-50 p-6 rounded-lg">
|
||||
<div class="space-y-4">
|
||||
{{ range amsterdam_dialog.Fields }}
|
||||
{{ if .Type == "veniceid" }}
|
||||
<div class="flex items-center">
|
||||
<label for="{{ .Name }}" class="w-24 text-right pr-4 text-black text-sm">{{ .Caption }}:</label>
|
||||
<input type="text" id="{{ .Name }}" name="{{ .Name }}"
|
||||
{{ if .Size > 0 }}size="{{ .Size }}"{{ end }}
|
||||
{{ if .MaxLength > 0 }}maxlength="{{ .MaxLength }}"{{ end }}
|
||||
value="{{ .Value }}"
|
||||
class="flex-1 px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
|
||||
</div>
|
||||
{{ else if .Type == "password" }}
|
||||
<div class="flex items-center">
|
||||
<label for="{{ .Name }}" class="w-24 text-right pr-4 text-black text-sm">{{ .Caption }}:</label>
|
||||
<input type="password" id="{{ .Name }}" name="{{ .Name }}"
|
||||
{{ if .Size > 0 }}size="{{ .Size }}"{{ end }}
|
||||
{{ if .MaxLength > 0 }}maxlength="{{ .MaxLength }}"{{ end }}
|
||||
value="{{ .Value }}"
|
||||
class="flex-1 px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
|
||||
</div>
|
||||
{{ else if .Type == "checkbox" }}
|
||||
<div class="flex items-center">
|
||||
<div class="w-24 text-right pr-4">
|
||||
<input type="checkbox" id="{{ .Name }}" name="{{ .Name }}"
|
||||
value="Y" class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" />
|
||||
</div>
|
||||
<label for="{{ .Name }}" class="flex-1 text-black text-sm">{{ .Caption }}</label>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="flex justify-center gap-4 mt-6">
|
||||
{{ range amsterdam_dialog.Fields }}
|
||||
{{ if .Type == "button" }}
|
||||
{{ clstmp := "bg-" + .Tone + "-600 hover:bg-" + .Tone + "-700" }}
|
||||
<button type="submit" name="{{ .Name }}"
|
||||
class="{{ clstmp }} text-white px-6 py-2 rounded font-medium transition-colors">{{ .Caption }}</button>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
+1
-1
@@ -59,7 +59,7 @@
|
||||
{{ if .CurrentUser().IsAnon }}
|
||||
You are not logged in
|
||||
<span class="mx-2">-</span>
|
||||
<a href="/TODO/login" class="text-yellow-300 hover:text-yellow-400">Log In</a>
|
||||
<a href="/login" class="text-yellow-300 hover:text-yellow-400">Log In</a>
|
||||
<span class="mx-2">|</span>
|
||||
<a href="/TODO/newaccount" class="text-yellow-300 hover:text-yellow-400">Create Account</a>
|
||||
{{ else }}
|
||||
|
||||
Reference in New Issue
Block a user