Copy over the white label page template

This commit is contained in:
Achim Rohn
2025-09-14 01:07:00 +02:00
parent 35ee289765
commit 92488618a9
3 changed files with 147 additions and 116 deletions
+112
View File
@@ -3,8 +3,13 @@ package ersteller_lib
import ( import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
. "maragu.dev/gomponents" . "maragu.dev/gomponents"
. "maragu.dev/gomponents/html"
) )
const DeIndexUrl = "/de/index"
const EnIndexUrl = "/en/index"
const DefaultLanguage = En
type NavItem struct { type NavItem struct {
Label string Label string
Url string Url string
@@ -36,3 +41,110 @@ type PageWebsiteMetaData struct {
type CreatePageFunc func(c echo.Context, metadata PageWebsiteMetaData, content ...Node) error type CreatePageFunc func(c echo.Context, metadata PageWebsiteMetaData, content ...Node) error
type CreateHtmxPageFunc func(req HtmxContext, metadata PageWebsiteMetaData, content ...Node) type CreateHtmxPageFunc func(req HtmxContext, metadata PageWebsiteMetaData, content ...Node)
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),
)
}
+31 -1
View File
@@ -7,6 +7,7 @@ import (
"log" "log"
"os" "os"
"os/exec" "os/exec"
"path"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings" "strings"
@@ -99,6 +100,15 @@ func (s StarterCreator) Create() {
s.copyFile("../.gitignore", ".gitignore") s.copyFile("../.gitignore", ".gitignore")
s.createEnvironment() s.createEnvironment()
directories := []string{
"index",
"page",
"routes",
"static",
}
for _, dir := range directories {
s.copyDirectoryRecursive(path.Join(s.thisDir, "..", dir), path.Join(s.params.ProjectDir, dir))
}
} }
func (s StarterCreator) createEnvironment() { func (s StarterCreator) createEnvironment() {
@@ -144,6 +154,26 @@ func (s StarterCreator) copyFile(src string, dst string) {
must(os.WriteFile(filepath.Join(s.params.ProjectDir, dst), content, 0o644)) must(os.WriteFile(filepath.Join(s.params.ProjectDir, dst), content, 0o644))
} }
func (s StarterCreator) copyDirectoryRecursive(src string, dst string) {
must(os.MkdirAll(dst, 0o755))
entries, err := os.ReadDir(src)
Debug()
must(err)
for _, entry := range entries {
srcPath := filepath.Join(src, entry.Name())
dstPath := filepath.Join(dst, entry.Name())
Debug("copying srcPath: ", srcPath, " to dstPath: ", dstPath)
if entry.IsDir() {
s.copyDirectoryRecursive(srcPath, dstPath)
return
}
content, err := os.ReadFile(srcPath)
content = s.replaceImports(content)
must(err)
must(os.WriteFile(filepath.Join(dstPath), content, 0o644))
}
}
func (s StarterCreator) copySchema() { func (s StarterCreator) copySchema() {
content, err := os.ReadFile(filepath.Join(s.thisDir, "../../schema_template.prisma")) content, err := os.ReadFile(filepath.Join(s.thisDir, "../../schema_template.prisma"))
must(err) must(err)
@@ -200,7 +230,7 @@ func (s StarterCreator) executeGetPrismaClient() {
func (s StarterCreator) replaceImports(content []byte) []byte { func (s StarterCreator) replaceImports(content []byte) []byte {
contentString := string(content) contentString := string(content)
contentString = strings.ReplaceAll(contentString, "\"ersteller-lib/starter/env\"", fmt.Sprint("\"", s.params.ModuleName, "/env\"")) contentString = strings.ReplaceAll(contentString, "\"ersteller-lib/starter/", fmt.Sprint("\"", s.params.ModuleName, "/"))
return []byte(contentString) return []byte(contentString)
} }
+4 -115
View File
@@ -10,10 +10,6 @@ import (
. "maragu.dev/gomponents/html" . "maragu.dev/gomponents/html"
) )
const DeIndexUrl = "/de/index"
const EnIndexUrl = "/en/index"
const DefaultLanguage = En
var _texts *Texts var _texts *Texts
func CreatePage(req HtmxContext, metadata PageWebsiteMetaData, content ...Node) { func CreatePage(req HtmxContext, metadata PageWebsiteMetaData, content ...Node) {
@@ -54,7 +50,7 @@ func CreatePage(req HtmxContext, metadata PageWebsiteMetaData, content ...Node)
Map(scripts, func(s string) Node { Map(scripts, func(s string) Node {
return Script(Type("text/javascript"), Src(s)) return Script(Type("text/javascript"), Src(s))
}), }),
addLanguageSelectScript(metadata), AddLanguageSelectScript(metadata),
}, },
Body: []Node{ Body: []Node{
Header(Class("header"), Header(Class("header"),
@@ -63,8 +59,8 @@ func CreatePage(req HtmxContext, metadata PageWebsiteMetaData, content ...Node)
Span(Class("logo-icon"), Text("🚀")), Span(Class("logo-icon"), Text("🚀")),
Span(Class("logo-text"), Text("White Label App")), Span(Class("logo-text"), Text("White Label App")),
), ),
getNav(req, metadata), GetNav(req, metadata),
getLanguageSwitcher(req, metadata), GetLanguageSwitcher(req, metadata),
), ),
), ),
Div(Class("container"), Div(Class("container"),
@@ -72,7 +68,7 @@ func CreatePage(req HtmxContext, metadata PageWebsiteMetaData, content ...Node)
), ),
Footer(Class("footer"), Footer(Class("footer"),
Div(Class("footer-menu"), Aria("label", "Footer Menu"), Div(Class("footer-menu"), Aria("label", "Footer Menu"),
getFooterMenu(req, metadata), GetFooterMenu(req, metadata),
), ),
P(Class("footer-disclaimer"), Text(getTexts().disclaimer.From(req))), P(Class("footer-disclaimer"), Text(getTexts().disclaimer.From(req))),
P(Text(getTexts().getCopyright(req.GetLanguage()))), P(Text(getTexts().getCopyright(req.GetLanguage()))),
@@ -82,113 +78,6 @@ func CreatePage(req HtmxContext, metadata PageWebsiteMetaData, content ...Node)
req.Render(page) 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 { type Texts struct {
disclaimer I18nText disclaimer I18nText
copyright I18nText copyright I18nText