Make profile identity, bio and fonts configurable
The profile header, photo page byline and copyright footer previously
hardcoded the author name, handle, bio, and font choices. Move all of
these to CLI flags on the binary and matching options on the NixOS
module so the same build can serve any single-user gallery.
New surface, all with defaults matching the previous hardcoded values:
--author / services.photogallery.author
--handle / services.photogallery.handle
--bio / services.photogallery.bio
--bio-alt / services.photogallery.bioAlt ("" to omit)
--fonts-url / services.photogallery.fontsURL
--serif-family / services.photogallery.serifFamily
--ml-family / services.photogallery.mlFamily
Templates read the two font families from a small inline <style> that
overrides the :root variables, so the stylesheet stays fully static and
the font URL is loaded via the configured stylesheet link.
README updated to describe the new options, the medium/full-size photo
detail flow, and the EXIF-based date prefill on the upload page.
This commit is contained in:
+55
-20
@@ -3,8 +3,8 @@ package main
|
||||
import (
|
||||
"encoding/xml"
|
||||
"html/template"
|
||||
imagedraw "image/draw"
|
||||
"image"
|
||||
imagedraw "image/draw"
|
||||
"image/jpeg"
|
||||
_ "image/png"
|
||||
"io"
|
||||
@@ -42,23 +42,44 @@ type Photo struct {
|
||||
}
|
||||
|
||||
type Generator struct {
|
||||
contentDir string
|
||||
outputDir string
|
||||
baseURL string
|
||||
mu sync.Mutex
|
||||
tmpl *template.Template
|
||||
contentDir string
|
||||
outputDir string
|
||||
baseURL string
|
||||
author string
|
||||
handle string
|
||||
bio string
|
||||
bioAlt string
|
||||
fontsURL string
|
||||
serifFamily string
|
||||
mlFamily string
|
||||
mu sync.Mutex
|
||||
tmpl *template.Template
|
||||
}
|
||||
|
||||
func NewGenerator(contentDir, outputDir, baseURL string) *Generator {
|
||||
func NewGenerator(contentDir, outputDir, baseURL, author, handle, bio, bioAlt, fontsURL, serifFamily, mlFamily string) *Generator {
|
||||
tmpl := template.Must(template.ParseFS(assets, "templates/*.html"))
|
||||
return &Generator{
|
||||
contentDir: contentDir,
|
||||
outputDir: outputDir,
|
||||
baseURL: baseURL,
|
||||
tmpl: tmpl,
|
||||
contentDir: contentDir,
|
||||
outputDir: outputDir,
|
||||
baseURL: baseURL,
|
||||
author: author,
|
||||
handle: handle,
|
||||
bio: bio,
|
||||
bioAlt: bioAlt,
|
||||
fontsURL: fontsURL,
|
||||
serifFamily: serifFamily,
|
||||
mlFamily: mlFamily,
|
||||
tmpl: tmpl,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Generator) initial() string {
|
||||
for _, r := range g.author {
|
||||
return strings.ToUpper(string(r))
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Build performs a full rebuild of the site. It is safe to call concurrently;
|
||||
// concurrent calls are serialised by a mutex.
|
||||
func (g *Generator) Build() error {
|
||||
@@ -157,9 +178,9 @@ func (g *Generator) loadPhotos() ([]Photo, error) {
|
||||
// thumbnail to public/thumbs/ plus an aspect-preserved medium image to
|
||||
// public/medium/. Outputs are skipped when already newer than the source.
|
||||
func (g *Generator) processImage(p *Photo) error {
|
||||
src := filepath.Join(g.contentDir, filepath.Base(p.File))
|
||||
dstImg := filepath.Join(g.outputDir, p.File)
|
||||
dstThumb := filepath.Join(g.outputDir, p.Thumb)
|
||||
src := filepath.Join(g.contentDir, filepath.Base(p.File))
|
||||
dstImg := filepath.Join(g.outputDir, p.File)
|
||||
dstThumb := filepath.Join(g.outputDir, p.Thumb)
|
||||
dstMedium := filepath.Join(g.outputDir, p.Medium)
|
||||
|
||||
if !upToDate(src, dstImg) {
|
||||
@@ -272,9 +293,17 @@ func generateMedium(src, dst string, maxDim int) error {
|
||||
// renderIndex writes public/index.html.
|
||||
func (g *Generator) renderIndex(photos []Photo) error {
|
||||
return g.render("index.html", filepath.Join(g.outputDir, "index.html"), map[string]any{
|
||||
"Photos": photos,
|
||||
"BaseURL": g.baseURL,
|
||||
"Year": time.Now().Year(),
|
||||
"Photos": photos,
|
||||
"BaseURL": g.baseURL,
|
||||
"Year": time.Now().Year(),
|
||||
"Author": g.author,
|
||||
"Handle": g.handle,
|
||||
"Bio": g.bio,
|
||||
"BioAlt": g.bioAlt,
|
||||
"Initial": g.initial(),
|
||||
"FontsURL": g.fontsURL,
|
||||
"SerifFamily": g.serifFamily,
|
||||
"MlFamily": g.mlFamily,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -285,9 +314,15 @@ func (g *Generator) renderPhotoPage(p Photo) error {
|
||||
return err
|
||||
}
|
||||
return g.render("photo.html", filepath.Join(dir, "index.html"), map[string]any{
|
||||
"Photo": p,
|
||||
"BaseURL": g.baseURL,
|
||||
"Year": time.Now().Year(),
|
||||
"Photo": p,
|
||||
"BaseURL": g.baseURL,
|
||||
"Year": time.Now().Year(),
|
||||
"Author": g.author,
|
||||
"Handle": g.handle,
|
||||
"Initial": g.initial(),
|
||||
"FontsURL": g.fontsURL,
|
||||
"SerifFamily": g.serifFamily,
|
||||
"MlFamily": g.mlFamily,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user