Copy over the white label page template
This commit is contained in:
@@ -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),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user