saasitone/templ/layouts/main.templ

169 lines
4.5 KiB
Plaintext

package layouts
import (
"strings"
"git.grosinger.net/tgrosinger/saasitone/pkg/page"
"git.grosinger.net/tgrosinger/saasitone/pkg/funcmap"
"git.grosinger.net/tgrosinger/saasitone/templ/components"
)
templ Main(p page.Page, content templ.Component) {
<!DOCTYPE html>
<html lang="en" style="height:100%;">
<head>
@metatags(p)
@css()
@js()
</head>
<body class="has-background-light" style="min-height:100%;">
<nav class="navbar is-dark">
<div class="container">
<div class="navbar-brand" hx-boost="true">
<a href={ templ.URL(p.ToURL("home")) } class="navbar-item">{ p.AppName }</a>
</div>
<div id="navbarMenu" class="navbar-menu">
<div class="navbar-end">
@search(p)
</div>
</div>
</div>
</nav>
<div class="container mt-5">
<div class="columns">
<div class="column is-2">
<aside class="menu" hx-boost="true">
<p class="menu-label">General</p>
<ul class="menu-list">
<li>
@link(p, p.ToURL("home"), "Dashboard", "")
</li>
<li>
@link(p, p.ToURL("about"), "About", "")
</li>
<li>
@link(p, p.ToURL("contact"), "Contact", "")
</li>
<li>
@link(p, p.ToURL("cache"), "Cache", "")
</li>
<li>
@link(p, p.ToURL("task"), "Task", "")
</li>
</ul>
<p class="menu-label">Account</p>
<ul class="menu-list">
if p.IsAuth {
<li>
@link(p, p.ToURL("logout"), "Logout", "")
</li>
} else {
<li>
@link(p, p.ToURL("login"), "Login", "")
</li>
<li>
@link(p, p.ToURL("register"), "Register", "")
</li>
<li>
@link(p, p.ToURL("forgot_password"), "Forgot password", "")
</li>
}
</ul>
</aside>
</div>
<div class="column is-10">
<div class="box">
if p.Title != "" {
<h1 class="title">{ p.Title }</h1>
}
@components.Messages(p)
@content
</div>
</div>
</div>
</div>
@footer(p)
</body>
</html>
}
templ link(p page.Page, url, text, classes string) {
<a class={ classes, templ.KV("is-active", p.Path == url) } href={ templ.URL(url) }>{ text }</a>
}
templ search(p page.Page) {
<div class="search mr-2 mt-1" x-data="{modal:false}">
<input class="input" type="search" placeholder="Search..." @click="modal = true; $nextTick(() => $refs.input.focus());"/>
<div class="modal" :class="modal ? 'is-active' : ''" x-show="modal == true">
<div class="modal-background"></div>
<div class="modal-content" @click.away="modal = false;">
<div class="box">
<h2 class="subtitle">Search</h2>
<p class="control">
<input
hx-get={ p.ToURL("search") }
hx-trigger="keyup changed delay:500ms"
hx-target="#results"
name="query"
class="input"
type="search"
placeholder="Search..."
x-ref="input"
/>
</p>
<div class="block"></div>
<div id="results"></div>
</div>
</div>
<button class="modal-close is-large" aria-label="close"></button>
</div>
</div>
}
templ metatags(p page.Page) {
if p.Title != "" {
<title>{ p.AppName } | { p.Title }</title>
} else {
<title>{ p.AppName }</title>
}
<link rel="icon" href={ funcmap.File("favicon.png") }/>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
if p.Metatags.Description != "" {
<meta name="description" content="{{.Metatags.Description}}"/>
}
if len(p.Metatags.Keywords) > 0 {
<meta name="keywords" content={ strings.Join(p.Metatags.Keywords, ",") }/>
}
}
templ css() {
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css"/>
}
templ js() {
<script src="https://unpkg.com/htmx.org@2.0.0/dist/htmx.min.js"></script>
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
}
templ footer(p page.Page) {
if p.CSRF != "" {
<script>
document.body.addEventListener('htmx:configRequest', function(evt) {
if (evt.detail.verb !== "get") {
evt.detail.parameters['csrf'] = {p.CSRF};
}
})
</script>
}
<script>
document.body.addEventListener('htmx:beforeSwap', function(evt) {
if (evt.detail.xhr.status >= 400){
evt.detail.shouldSwap = true;
evt.detail.target = htmx.find("body");
}
});
</script>
}