Changeset 0.22.7 (#149)

This commit is contained in:
2026-03-04 10:44:42 +00:00
parent d8e0664fa3
commit 389e47b0f9
62 changed files with 6820 additions and 1476 deletions

View File

@@ -4,7 +4,7 @@
//
// templates/base.html — outer shell (banner + surface block + scripts)
// templates/login.html — standalone login page
// templates/components/*.html — reusable partials (model-select, team-select, etc.)
// templates/components/*.html — reusable partials (model-select, team-select, chat-pane, etc.)
// templates/surfaces/*.html — one per surface (chat, editor, notes, admin, etc.)
// templates/admin/*.html — admin sub-pages (roles, routing, providers, etc.)
package pages
@@ -52,15 +52,25 @@ type BannerConfig struct {
// PageData is passed to every template render.
type PageData struct {
Banner BannerConfig
Surface string // active surface ID
Section string // sub-section (for admin pages)
CSPNonce string
Banner BannerConfig
Surface string // active surface ID
Section string // sub-section (for admin pages)
CSPNonce string
BasePath string
Version string
Environment string
User *UserContext
Data any // surface-specific data from loader
User *UserContext
Data any // surface-specific data from loader
// v0.22.7: Theme + settings injection
Theme string // "dark", "light", or "" (= use default)
SurfaceSettings any // JSON-serialized to window.__SETTINGS__
// v0.22.7: Login/splash page fields
InstanceName string // branding: instance display name
LogoURL string // branding: custom logo URL
Tagline string // branding: tagline under instance name
RegistrationOpen bool // whether self-registration is enabled
}
// UserContext is the authenticated user's info available to templates.
@@ -138,6 +148,11 @@ func (e *Engine) Render(c *gin.Context, name string, data PageData) {
data.CSPNonce = generateNonce()
data.Banner = e.loadBanner()
// v0.22.7: Default theme if not set
if data.Theme == "" {
data.Theme = "dark"
}
e.mu.RLock()
tmpl := e.templates
e.mu.RUnlock()
@@ -186,8 +201,16 @@ func (e *Engine) RenderSurface(surfaceID string) gin.HandlerFunc {
// RenderLogin serves the standalone login page.
func (e *Engine) RenderLogin() gin.HandlerFunc {
return func(c *gin.Context) {
// v0.22.7: Populate splash/login fields from global config
instanceName, logoURL, tagline := e.loadBranding()
regOpen := e.isRegistrationOpen()
e.Render(c, "login.html", PageData{
Surface: "login",
Surface: "login",
InstanceName: instanceName,
LogoURL: logoURL,
Tagline: tagline,
RegistrationOpen: regOpen,
})
}
}
@@ -229,6 +252,43 @@ func (e *Engine) loadBanner() BannerConfig {
return b
}
// loadBranding reads instance branding from global settings.
func (e *Engine) loadBranding() (name, logoURL, tagline string) {
name = "Chat Switchboard" // default
if e.stores.GlobalConfig == nil {
return
}
raw, err := e.stores.GlobalConfig.Get(context.Background(), "branding")
if err != nil || raw == nil {
return
}
if v, ok := raw["instance_name"].(string); ok && v != "" {
name = v
}
if v, ok := raw["logo_url"].(string); ok {
logoURL = v
}
if v, ok := raw["tagline"].(string); ok {
tagline = v
}
return
}
// isRegistrationOpen checks if self-registration is enabled.
func (e *Engine) isRegistrationOpen() bool {
if e.stores.GlobalConfig == nil {
return false
}
raw, err := e.stores.GlobalConfig.Get(context.Background(), "registration")
if err != nil || raw == nil {
return false
}
if v, ok := raw["enabled"].(bool); ok {
return v
}
return false
}
// Version is injected at build time via ldflags.
var Version = "dev"