added htmx swapping and url history features

This commit is contained in:
Nickiel12 2024-01-13 18:33:26 -08:00
parent 7b9a760e67
commit f97b31093c
7 changed files with 184 additions and 36 deletions

12
web/dashboard.templ Normal file
View file

@ -0,0 +1,12 @@
package web
templ dashboard() {
<title>Home</title>
<h1>Hello World!</h1>
<button hx-get="/hello" hx-trigger="click" hx-target="#hello" hx-swap="outerHtml">Hello you!</button>
<div id="hello">
</div>
}

View file

@ -1,6 +1,7 @@
package web
templ hello(name string) {
<title>Hello</title>
<div>Hello { name } </div>
<h1>SUPRISE!!!</h1>
}

View file

@ -1,22 +1,25 @@
package web
import (
"html/template"
"net/http"
"html/template"
"context"
"bytes"
"context"
"github.com/a-h/templ"
"github.com/go-chi/chi/v5"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
const TemplateDir = "./web/templates/"
type IndexData struct {
Title string
type TemplateState struct {
InnerHtml template.HTML
ActivePage string
}
const TemplateDir = "./web/templates/"
func SetLogLevel(level zerolog.Level) {
zerolog.SetGlobalLevel(level)
}
@ -29,7 +32,23 @@ func WebRouter() http.Handler {
return r
}
func getIndex(w http.ResponseWriter, req *http.Request) {
//for name, values := range req.Header {
// Loop over all values for the name.
// for _, value := range values {
// log.Debug().Msg(name + " " + value);
// }
// }
func renderFullPage(w http.ResponseWriter, c templ.Component, pageName string) {
var buf bytes.Buffer
// Render the provided templ component
err := c.Render(context.Background(), &buf)
if err != nil {
log.Fatal().Err(err).Msg("Fatal error reading hello template");
}
// get the index template
index, err := template.ParseFiles(TemplateDir + "index.html")
if err != nil {
log.Fatal().
@ -37,11 +56,40 @@ func getIndex(w http.ResponseWriter, req *http.Request) {
Msg("Fatal error reading index template")
}
err = index.Execute(w, IndexData{Title: "thetitle"})
// Inject the templ component html into the index template
err = index.Execute(w,
TemplateState{
InnerHtml: template.HTML(buf.String()),
ActivePage: pageName,
});
if err != nil {
log.Fatal().Err(err).Msg("Fatal error reading hello template");
}
}
func getIndex(w http.ResponseWriter, req *http.Request) {
component := dashboard();
_, ok := req.Header["Hx-Request"]
if ok {
err := component.Render(context.Background(), w);
if err != nil {
log.Fatal().Err(err).Msg("Couldn't render dashboard templ template");
}
} else {
renderFullPage(w, component, "index");
}
}
func getHello(w http.ResponseWriter, req *http.Request) {
log.Debug().Msg("Got index")
component := hello("Nick")
component.Render(context.Background(), w)
_, ok := req.Header["Hx-Request"]
if ok {
err := component.Render(context.Background(), w);
if err != nil {
log.Fatal().Err(err).Msg("Couldn't render dashboard templ template");
}
}else {
renderFullPage(w, component, "hello");
}
}

View file

@ -1,30 +1,42 @@
header {
background-color: $nav-bg;
height: 30px;
width: 100%;
margin-top: 10px;
margin-bottom: 10px;
}
nav {
background-color: $nav-bg;
display: flex;
flex-direction: column;
ul {
margin: 0;
padding: 0;
list-style: none;
padding-left: 0;
}
li { display: inline-block; }
button.title {
color: $green;
li {
margin-top: 10px;
margin-bottom: 10px;
}
button.active {
a.active {
pointer-events: none;
background-color: $nav-active-bg;
color: $nav-active-color;
}
button {
a {
transition: background-color $hl-trn-spd ease-in, color $hl-trn-spd ease-in;
border-radius: 5px;
text-align: center;
padding: 12px 0px;
display: inline-block;
cursor: pointer;
color: $nav-color;
display: block;
padding: 12px 24px;
width: 100%;
text-decoration: none;
@include button_link;
}
button:hover {
a:hover {
background-color: $nav-hover;
}
}

View file

@ -1,5 +1,8 @@
@import 'catpuccin';
// highlight transition speed
$hl-trn-spd: 0.2s;
$bg: $latte-base;
$nav-bg: $latte-crust;
$nav-color: $latte-text;
@ -21,3 +24,31 @@ body.dark-mode {
$nav-bg: $macchiato-crust;
$green: $macchiato-green;
}
div#below-header {
display:flex;
}
div#left-col {
width: 15vw;
padding: 10px;
}
div#main-body-content {
width: 70vw;
padding: 10px;
opacity: 1;
transition: opacity 0.2s ease-out;
}
div#main-body-content.htmx-swapping {
opacity: 0;
transition: opacity 0.2s ease-out;
}
div#main-body-content.htmx-added {
opacity: 0;
}
div#right-col {
width: 15vw;
padding: 10px;
}

View file

@ -3,4 +3,20 @@ function say_hello() {
console.log("Hello World");
}
export {say_hello};
function register_nav_links() {
var navAnchors = document.querySelectorAll("nav a");
navAnchors.forEach(function (a_el) {
a_el.addEventListener("click", nav_a_click);
});
}
function nav_a_click(event) {
var active_anchor = document.querySelector("nav a.active");
active_anchor.classList.remove("active");
var clicked = event.target;
clicked.classList.add("active");
}
export {say_hello, register_nav_links};

View file

@ -5,30 +5,58 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/static/site.css">
<script src="/static/htmx.min.js"></script>
<title>{{.Title}}</title>
</head>
<body>
<header>
<nav>
<button class="title" href="/">Recount!</button>
<ul>
<li><button hx-boost="true" class="active" href="/home">Home!</button></li>
<li><button href="/nohome">Not home!</button></li>
</ul>
</nav>
</header>
<div id="main-body-content">
<h1>Hello World!</h1>
<button hx-get="/hello" hx-trigger="click" hx-target="#hello" hx-swap="outerHtml">Hello you!</button>
<div id="below-header">
<div id="hello">
<div id="left-col">
<nav>
<button class="title" href="/">Recount!</button>
<ul>
<li>
<a
hx-get="/"
hx-swap="innerHtml swap:0.2s settle:0.2s"
hx-push-url="true"
hx-boost="true"
hx-target="#main-body-content"
{{ if (eq .ActivePage "index") }}
class="active"
{{ end }}
>
Home!
</a>
</div>
</li>
<li>
<a
hx-get="/hello"
hx-swap="innerHtml swap:0.2s settle:0.2s"
hx-push-url="true"
hx-boost="true"
hx-target="#main-body-content"
{{ if (eq .ActivePage "hello") }}
class="active"
{{ end }}
>
Not home!
</a>
</li>
</ul>
</nav>
</div>
<div id="main-body-content">
{{.InnerHtml}}
</div>
</div>
<script type="module" src="/static/index.js"></script>
<script type="module">
import {say_hello} from "/static/index.js";
import {say_hello, register_nav_links} from "/static/index.js";
say_hello();
register_nav_links();
</script>
</body>
</html>