Build-time minification, image optimization, htmx SPA navigation, and local htmx bundle
This commit is contained in:
parent
50a5ca2c71
commit
b95d5c2ee5
13 changed files with 186 additions and 115 deletions
17
css/base.css
17
css/base.css
|
|
@ -133,3 +133,20 @@ ul {
|
|||
img {
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
main {
|
||||
transition: opacity 0.15s ease;
|
||||
}
|
||||
|
||||
#about-us,
|
||||
#featured-delights,
|
||||
#kawiarnia,
|
||||
#kawiarnia-content,
|
||||
#portfolio-grid,
|
||||
#wyroby,
|
||||
#slodkie_stoly,
|
||||
#lody,
|
||||
#wyroby-torty > section {
|
||||
content-visibility: auto;
|
||||
contain-intrinsic-size: 600px;
|
||||
}
|
||||
|
|
|
|||
6
go.mod
6
go.mod
|
|
@ -10,14 +10,16 @@ require (
|
|||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cli/browser v1.3.0 // indirect
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/natefinch/atomic v1.0.1 // indirect
|
||||
github.com/tdewolff/minify/v2 v2.24.13 // indirect
|
||||
github.com/tdewolff/parse/v2 v2.8.12 // indirect
|
||||
golang.org/x/mod v0.26.0 // indirect
|
||||
golang.org/x/net v0.51.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
golang.org/x/tools v0.35.0 // indirect
|
||||
)
|
||||
|
||||
|
|
|
|||
9
go.sum
9
go.sum
|
|
@ -14,6 +14,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
|||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
|
|
@ -27,6 +29,11 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tdewolff/minify/v2 v2.24.13 h1:xrcF7gKDnUszseEY9WX9mUlZII2v2Go/QAcAwRASw58=
|
||||
github.com/tdewolff/minify/v2 v2.24.13/go.mod h1:emvwoYeIl8bfAKqRU5ww95LX9Gpggpqv/naal9a8Yq0=
|
||||
github.com/tdewolff/parse/v2 v2.8.12 h1:5BBjfaCv482v3nltlS0u6wH1xJaxjR6ofDrWttNvROg=
|
||||
github.com/tdewolff/parse/v2 v2.8.12/go.mod h1:Hwlni2tiVNKyzR1o6nUs4FOF07URA+JLBLd6dlIXYqo=
|
||||
github.com/tdewolff/test v1.0.11/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
|
||||
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
|
||||
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
|
||||
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
||||
|
|
@ -37,6 +44,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
|
||||
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
|
|
|||
|
|
@ -24,6 +24,13 @@ func processImage(fileName string) string {
|
|||
return dst[4:]
|
||||
}
|
||||
|
||||
templ AvifImage(srcPath, alt string) {
|
||||
<img src={ processImage(srcPath) } alt={ alt }/>
|
||||
templ AvifImage(srcPath, alt string, lazy bool, priority bool) {
|
||||
<img src={ processImage(srcPath) } alt={ alt }
|
||||
if lazy {
|
||||
loading="lazy"
|
||||
}
|
||||
if priority {
|
||||
fetchpriority="high"
|
||||
}
|
||||
/>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,17 +13,17 @@ templ Index() {
|
|||
<a href="wyroby.html" class="btn">Zobacz naszą ofertę</a>
|
||||
</div>
|
||||
<div>
|
||||
@AvifImage("001.avif", "tort")
|
||||
@AvifImage("001.avif", "tort", false, true)
|
||||
</div>
|
||||
</header>
|
||||
<section id="about-us">
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
@AvifImage("002.avif", "kawiarnia")
|
||||
@AvifImage("002.avif", "kawiarnia", true, false)
|
||||
</div>
|
||||
<div>
|
||||
@AvifImage("003.avif", "kawiarnia")
|
||||
@AvifImage("003.avif", "kawiarnia", true, false)
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -42,7 +42,7 @@ templ Index() {
|
|||
<h2>Nasze Wyroby</h2>
|
||||
<div class="card">
|
||||
<div>
|
||||
@AvifImage("004.avif", "tort")
|
||||
@AvifImage("004.avif", "tort", true, false)
|
||||
</div>
|
||||
<div>
|
||||
<h3>Torty Okazjonalne</h3>
|
||||
|
|
@ -69,7 +69,7 @@ templ Index() {
|
|||
</div>
|
||||
<div class="card">
|
||||
<div>
|
||||
@AvifImage("005.avif", "ciasto")
|
||||
@AvifImage("005.avif", "ciasto", true, false)
|
||||
</div>
|
||||
<div class="greener">
|
||||
<h3>Domowe Ciasta</h3>
|
||||
|
|
@ -96,7 +96,7 @@ templ Index() {
|
|||
</div>
|
||||
<div class="card">
|
||||
<div>
|
||||
@AvifImage("006.avif", "slodkosci")
|
||||
@AvifImage("006.avif", "slodkosci", true, false)
|
||||
</div>
|
||||
<div>
|
||||
<h3>Słodkie Stoły</h3>
|
||||
|
|
@ -174,10 +174,10 @@ templ Index() {
|
|||
</div>
|
||||
<div>
|
||||
<div>
|
||||
@AvifImage("007.avif", "kawiarnia")
|
||||
@AvifImage("007.avif", "kawiarnia", true, false)
|
||||
</div>
|
||||
<div>
|
||||
@AvifImage("008.avif", "ciasto i kawa")
|
||||
@AvifImage("008.avif", "ciasto i kawa", true, false)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ templ Kawiarnia() {
|
|||
</p>
|
||||
</div>
|
||||
<div>
|
||||
@AvifImage("009.avif", "kawiarnia")
|
||||
@AvifImage("009.avif", "kawiarnia", false, true)
|
||||
<div></div>
|
||||
</div>
|
||||
</header>
|
||||
|
|
|
|||
|
|
@ -13,9 +13,10 @@ templ layout(activePage string) {
|
|||
<meta name="description" content=""/>
|
||||
<link href="style.css" rel="stylesheet"/>
|
||||
<link rel="icon" href="images/favicon.avif"/>
|
||||
<script src="htmx.min.js"></script>
|
||||
<script defer src="portfolio.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<body hx-boost="true">
|
||||
<nav>
|
||||
<div>
|
||||
<a href="index.html">
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ templ Portfolio(images []string, activePage string, pages []string) {
|
|||
<div id="portfolio-grid">
|
||||
for _, img := range images {
|
||||
<div>
|
||||
@AvifImage("portfolio/"+img, "portfolio")
|
||||
@AvifImage("portfolio/"+img, "portfolio", true, false)
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import "piekarnikgosi/types"
|
|||
templ card(product types.Product) {
|
||||
<div class="card">
|
||||
<div>
|
||||
@AvifImage("wyroby/"+product.Image+".avif", product.Name)
|
||||
@AvifImage("wyroby/"+product.Image+".avif", product.Name, true, false)
|
||||
</div>
|
||||
<div>
|
||||
<h3>{ product.Name }</h3>
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ templ WyrobyTorty() {
|
|||
<header>
|
||||
<h2>Torty Musowe</h2>
|
||||
<div>
|
||||
@AvifImage("010.avif", "tort musowy")
|
||||
@AvifImage("010.avif", "tort musowy", true, false)
|
||||
</div>
|
||||
</header>
|
||||
<div>
|
||||
|
|
|
|||
1
js/htmx.min.js
vendored
Normal file
1
js/htmx.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
140
js/portfolio.js
140
js/portfolio.js
|
|
@ -1,104 +1,94 @@
|
|||
(function () {
|
||||
var grid = document.getElementById("portfolio-grid");
|
||||
if (!grid) return;
|
||||
window.initPortfolio = function () {
|
||||
var old = document.getElementById('lightbox')
|
||||
if (old) old.remove()
|
||||
|
||||
var items = Array.from(grid.children);
|
||||
if (!items.length) return;
|
||||
var grid = document.getElementById('portfolio-grid')
|
||||
if (!grid) return
|
||||
|
||||
var lb = document.createElement("div");
|
||||
lb.id = "lightbox";
|
||||
var items = Array.from(grid.children)
|
||||
if (!items.length) return
|
||||
|
||||
var lb = document.createElement('div')
|
||||
lb.id = 'lightbox'
|
||||
lb.innerHTML =
|
||||
'<button id="lb-close" aria-label="Zamknij"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg></button>' +
|
||||
'<button id="lb-prev" aria-label="Poprzednie"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg></button>' +
|
||||
'<img src="" alt="">' +
|
||||
'<button id="lb-next" aria-label="Następne"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg></button>';
|
||||
document.body.appendChild(lb);
|
||||
'<button id="lb-next" aria-label="Następne"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg></button>'
|
||||
document.body.appendChild(lb)
|
||||
|
||||
var lbImg = lb.querySelector("img");
|
||||
var current = -1;
|
||||
var lbImg = lb.querySelector('img')
|
||||
var current = -1
|
||||
|
||||
function open(idx) {
|
||||
current = idx;
|
||||
var img = items[current].querySelector("img");
|
||||
lbImg.removeAttribute("src");
|
||||
lbImg.alt = "";
|
||||
lb.classList.add("open");
|
||||
lbImg.src = img.src;
|
||||
lbImg.alt = img.alt;
|
||||
current = idx
|
||||
var img = items[current].querySelector('img')
|
||||
lbImg.removeAttribute('src')
|
||||
lbImg.alt = ''
|
||||
lb.classList.add('open')
|
||||
lbImg.src = img.src
|
||||
lbImg.alt = img.alt
|
||||
}
|
||||
|
||||
function close() {
|
||||
lb.classList.remove("open");
|
||||
current = -1;
|
||||
lb.classList.remove('open')
|
||||
current = -1
|
||||
}
|
||||
|
||||
function prev() {
|
||||
if (current < 0) return;
|
||||
open((current - 1 + items.length) % items.length);
|
||||
if (current < 0) return
|
||||
open((current - 1 + items.length) % items.length)
|
||||
}
|
||||
|
||||
function next() {
|
||||
if (current < 0) return;
|
||||
open((current + 1) % items.length);
|
||||
if (current < 0) return
|
||||
open((current + 1) % items.length)
|
||||
}
|
||||
|
||||
items.forEach(function (item, i) {
|
||||
item.addEventListener("click", function () {
|
||||
open(i);
|
||||
});
|
||||
});
|
||||
item.addEventListener('click', function () { open(i) })
|
||||
})
|
||||
|
||||
lb.querySelector("#lb-close").addEventListener("click", close);
|
||||
lb.querySelector("#lb-prev").addEventListener("click", function (e) {
|
||||
e.stopPropagation();
|
||||
prev();
|
||||
});
|
||||
lb.querySelector("#lb-next").addEventListener("click", function (e) {
|
||||
e.stopPropagation();
|
||||
next();
|
||||
});
|
||||
lb.querySelector('#lb-close').addEventListener('click', close)
|
||||
lb.querySelector('#lb-prev').addEventListener('click', function (e) {
|
||||
e.stopPropagation()
|
||||
prev()
|
||||
})
|
||||
lb.querySelector('#lb-next').addEventListener('click', function (e) {
|
||||
e.stopPropagation()
|
||||
next()
|
||||
})
|
||||
|
||||
document.addEventListener("keydown", function (e) {
|
||||
if (!lb.classList.contains("open")) return;
|
||||
if (e.key === "Escape") {
|
||||
close();
|
||||
e.preventDefault();
|
||||
}
|
||||
if (e.key === "ArrowLeft") {
|
||||
prev();
|
||||
e.preventDefault();
|
||||
}
|
||||
if (e.key === "ArrowRight") {
|
||||
next();
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (!lb.classList.contains('open')) return
|
||||
if (e.key === 'Escape') { close(); e.preventDefault() }
|
||||
if (e.key === 'ArrowLeft') { prev(); e.preventDefault() }
|
||||
if (e.key === 'ArrowRight') { next(); e.preventDefault() }
|
||||
})
|
||||
|
||||
lb.addEventListener("click", function (e) {
|
||||
if (e.target === lb) close();
|
||||
});
|
||||
lb.addEventListener('click', function (e) {
|
||||
if (e.target === lb) close()
|
||||
})
|
||||
|
||||
var touchStartX = 0;
|
||||
var touchStartY = 0;
|
||||
lb.addEventListener(
|
||||
"touchstart",
|
||||
function (e) {
|
||||
touchStartX = e.changedTouches[0].screenX;
|
||||
touchStartY = e.changedTouches[0].screenY;
|
||||
},
|
||||
{ passive: true },
|
||||
);
|
||||
var touchStartX = 0
|
||||
var touchStartY = 0
|
||||
lb.addEventListener('touchstart', function (e) {
|
||||
touchStartX = e.changedTouches[0].screenX
|
||||
touchStartY = e.changedTouches[0].screenY
|
||||
}, { passive: true })
|
||||
|
||||
lb.addEventListener(
|
||||
"touchend",
|
||||
function (e) {
|
||||
var dx = e.changedTouches[0].screenX - touchStartX;
|
||||
var dy = e.changedTouches[0].screenY - touchStartY;
|
||||
lb.addEventListener('touchend', function (e) {
|
||||
var dx = e.changedTouches[0].screenX - touchStartX
|
||||
var dy = e.changedTouches[0].screenY - touchStartY
|
||||
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 50) {
|
||||
if (dx < 0) next();
|
||||
else prev();
|
||||
if (dx < 0) next()
|
||||
else prev()
|
||||
}
|
||||
},
|
||||
{ passive: true },
|
||||
);
|
||||
})();
|
||||
}, { passive: true })
|
||||
}
|
||||
|
||||
window.initPortfolio()
|
||||
|
||||
document.addEventListener('htmx:afterSwap', window.initPortfolio)
|
||||
})()
|
||||
|
|
|
|||
60
main.go
60
main.go
|
|
@ -3,6 +3,7 @@ package main
|
|||
//go:generate go tool templ generate templates
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -15,20 +16,57 @@ import (
|
|||
"piekarnikgosi/utils"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/tdewolff/minify/v2"
|
||||
mcss "github.com/tdewolff/minify/v2/css"
|
||||
mhtml "github.com/tdewolff/minify/v2/html"
|
||||
mjs "github.com/tdewolff/minify/v2/js"
|
||||
)
|
||||
|
||||
type ComponentRenderer interface {
|
||||
Render(ctx context.Context, w io.Writer) error
|
||||
}
|
||||
|
||||
func saveFile(name string, comp ComponentRenderer) {
|
||||
file, err := os.Create("www/" + name + ".html")
|
||||
var minifier = sync.OnceValue(func() *minify.M {
|
||||
m := minify.New()
|
||||
m.Add("text/html", &mhtml.Minifier{
|
||||
KeepDocumentTags: true,
|
||||
KeepEndTags: true,
|
||||
})
|
||||
m.Add("text/css", &mcss.Minifier{})
|
||||
m.Add("application/javascript", &mjs.Minifier{})
|
||||
return m
|
||||
})
|
||||
|
||||
func minifyFile(path, mediatype string) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer file.Close()
|
||||
err = os.WriteFile(path, minifyData(mediatype, data), 0666)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
err = comp.Render(context.Background(), file)
|
||||
func minifyData(mediatype string, data []byte) []byte {
|
||||
b, err := minifier().Bytes(mediatype, data)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func saveFile(name string, comp ComponentRenderer) {
|
||||
var buf bytes.Buffer
|
||||
err := comp.Render(context.Background(), &buf)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
minified := minifyData("text/html", buf.Bytes())
|
||||
|
||||
err = os.WriteFile("www/"+name+".html", minified, 0666)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
@ -117,7 +155,8 @@ func mergeStyles() {
|
|||
bundledCSS = append(bundledCSS, '\n')
|
||||
}
|
||||
|
||||
err := os.WriteFile("www/style.css", bundledCSS, 0666)
|
||||
minified := minifyData("text/css", bundledCSS)
|
||||
err := os.WriteFile("www/style.css", minified, 0666)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
@ -125,9 +164,12 @@ func mergeStyles() {
|
|||
|
||||
func ensureDir() {
|
||||
log.Println("creating directories")
|
||||
err := os.MkdirAll("www/images", 0777)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
os.MkdirAll("www/images", 0777)
|
||||
entries, _ := os.ReadDir("www")
|
||||
for _, e := range entries {
|
||||
if !e.IsDir() && filepath.Ext(e.Name()) == ".html" {
|
||||
os.Remove("www/" + e.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -145,6 +187,8 @@ func main() {
|
|||
mustCopy("img/favicon.avif", "www/images/favicon.avif")
|
||||
mustCopy("img/logo.svg", "www/images/logo.svg")
|
||||
mustCopy("js/portfolio.js", "www/portfolio.js")
|
||||
minifyFile("www/portfolio.js", "application/javascript")
|
||||
mustCopy("js/htmx.min.js", "www/htmx.min.js")
|
||||
if len(os.Args) > 1 {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue