Files
ersteller/starter/page/page.go
T
2025-09-12 23:26:10 +02:00

227 lines
5.1 KiB
Go

package page
import (
. "ersteller-lib"
"fmt"
"time"
. "maragu.dev/gomponents"
. "maragu.dev/gomponents/components"
. "maragu.dev/gomponents/html"
)
const DeIndexUrl = "/de/index"
const EnIndexUrl = "/en/index"
const DefaultLanguage = En
var _texts *Texts
func CreatePage(req HtmxContext, metadata PageWebsiteMetaData, content ...Node) {
metadata.Lang = req.GetLanguage()
var contentForFunction Node
if len(content) > 0 {
contentForFunction = Div(content...)
} else if len(content) == 0 {
contentForFunction = Div()
} else if len(content) == 1 {
contentForFunction = content[0]
}
styles := []string{
"/static/styles.css",
}
for _, src := range metadata.StyleSrcs {
styles = append(styles, src)
}
scripts := []string{
"/static/scripts/language-select.js",
"/static/htmx.js",
}
for _, src := range metadata.ScriptSrcs {
scripts = append(scripts, src)
}
page := HTML5(HTML5Props{
Title: "White Label App " + metadata.Title.From(req),
Language: string(metadata.Lang),
Description: metadata.Description.From(req),
Head: []Node{
Map(styles, func(s string) Node {
return Link(Rel("stylesheet"), Href(s))
}),
Map(scripts, func(s string) Node {
return Script(Type("text/javascript"), Src(s))
}),
addLanguageSelectScript(metadata),
},
Body: []Node{
Header(Class("header"),
Div(Class("header-content"),
Div(Class("logo"),
Span(Class("logo-icon"), Text("🚀")),
Span(Class("logo-text"), Text("White Label App")),
),
getNav(req, metadata),
getLanguageSwitcher(req, metadata),
),
),
Div(Class("container"),
contentForFunction,
),
Footer(Class("footer"),
Div(Class("footer-menu"), Aria("label", "Footer Menu"),
getFooterMenu(req, metadata),
),
P(Class("footer-disclaimer"), Text(getTexts().disclaimer.From(req))),
P(Text(getTexts().getCopyright(req.GetLanguage()))),
),
},
})
req.Render(page)
}
func addLanguageSelectScript(metadata PageWebsiteMetaData) Node {
script := InlineTemplate(`
(function() {
const langs = {
de: "$.DeUrl$",
en: "$.EnUrl$",
};
const currentLang = "$.CurrentLang$";
const defaultLang = "$.DefaultLang$";
selectWebsiteLanguage(currentLang, langs, defaultLang);
})();`, struct {
CurrentLang string
DeUrl string
EnUrl string
DefaultLang string
}{
CurrentLang: string(metadata.Lang),
DeUrl: DeIndexUrl,
EnUrl: EnIndexUrl,
DefaultLang: string(DefaultLanguage),
})
return Script(Type("text/javascript"), Raw(script))
}
func getNav(c HtmxContext, metadata PageWebsiteMetaData) Node {
return Nav(Class("nav"), Aria("label", "Main Menu"),
Map(metadata.NavItems, func(path ActivePath) Node {
return createNavItem(c, path)
}),
)
}
func createNavItem(c HtmxContext, activePath ActivePath) Node {
isActive := activePath.IsActive(c)
return A(
Href(activePath.GetPath(c.GetLanguage())),
Text(activePath.From(c)),
If(isActive, Attr("aria-current", "page")),
If(isActive, Class("selected")),
)
}
func getLanguageSwitcher(c HtmxContext, metadata PageWebsiteMetaData) Node {
currentLang := c.GetLanguage()
var currentRoute HtmxRoute
for _, route := range c.GetAllRoutes() {
if route.IsCurrentRoute(c) {
currentRoute = route
break
}
}
return Div(Class("language-switcher"),
createLanguageButton(En, currentLang, currentRoute, c),
createLanguageButton(De, currentLang, currentRoute, c),
)
}
func getFooterMenu(c HtmxContext, metadata PageWebsiteMetaData) Node {
lang := c.GetLanguage()
return Div(
Map(metadata.FooterNavItems, func(path ActivePath) Node {
return Span(
A(Href(path.GetPath(lang)), Class("footer-link"), Text(path.From(c))),
)
}),
)
}
func createLanguageButton(lang Language, currentLang Language, route HtmxRoute, c HtmxContext) Node {
isActive := lang == currentLang
var href string
if route != nil {
href = route.ToUrlFromContext(c, lang)
} else {
// Fallback to index page if no active path found
if lang == En {
href = EnIndexUrl
} else {
href = DeIndexUrl
}
}
var langText string
if lang == En {
langText = "EN"
} else {
langText = "DE"
}
// Combine classes properly
var classes string
if isActive {
classes = "language-button active"
} else {
classes = "language-button inactive"
}
return A(
Href(href),
Text(langText),
Class(classes),
)
}
type Texts struct {
disclaimer I18nText
copyright I18nText
}
func NewTexts() *Texts {
return &Texts{
disclaimer: NewI18nText(map[Language]string{
De: "Dies ist eine White-Label-Vorlage. Passen Sie den Inhalt an Ihre Bedürfnisse an.",
En: "This is a white label template. Customize the content to fit your needs.",
}),
copyright: NewI18nText(map[Language]string{
De: "© 2020 - $Year$ White Label App. Alle Rechte vorbehalten.",
En: "© 2020 - $Year$ White Label App. All rights reserved.",
}),
}
}
func (t *Texts) getCopyright(lang Language) string {
currentYear := fmt.Sprint(time.Now().Year())
text := t.copyright.FromLang(lang)
return InlineTemplate(text, struct {
Year string
}{
Year: currentYear,
})
}
func getTexts() *Texts {
if _texts != nil {
return _texts
}
_texts = NewTexts()
return _texts
}