Styled the categories on the site

This commit is contained in:
Leon Mika 2026-03-22 10:28:33 +11:00
parent f45bdcd83c
commit d9aec4af2c
16 changed files with 176 additions and 59 deletions

View file

@ -1,9 +0,0 @@
<h2>Categories</h2>
<ul>
{{ range .Categories }}
<li>
<a href="{{ url_abs .Path }}">{{ .Name }}</a> ({{ .PostCount }})
{{ if .DescriptionBrief }}<br><small>{{ .DescriptionBrief }}</small>{{ end }}
</li>
{{ end }}
</ul>

View file

@ -1,16 +0,0 @@
<h2>{{ .Category.Name }}</h2>
{{ if .DescriptionHTML }}
<div>{{ .DescriptionHTML }}</div>
{{ end }}
{{ range .Posts }}
{{ if .Post.Title }}<h3>{{ .Post.Title }}</h3>{{ end }}
{{ .HTML }}
<a href="{{ url_abs .Path }}">{{ format_date .Post.PublishedAt }}</a>
{{ if .Categories }}
<p>
{{ range .Categories }}
<a href="{{ url_abs (printf "/categories/%s" .Slug) }}">{{ .Name }}</a>
{{ end }}
</p>
{{ end }}
{{ end }}

View file

@ -2,5 +2,6 @@ package simplecss
import "embed"
//go:embed *.html
//go:embed templates/*.html
//go:embed static/*
var FS embed.FS

View file

@ -1,12 +0,0 @@
{{ range .Posts }}
{{ if .Post.Title }}<h3>{{ .Post.Title }}</h3>{{ end }}
{{ .HTML }}
<a href="{{ url_abs .Path }}">{{ format_date .Post.PublishedAt }}</a>
{{ if .Categories }}
<p>
{{ range .Categories }}
<a href="{{ url_abs (printf "/categories/%s" .Slug) }}">{{ .Name }}</a>
{{ end }}
</p>
{{ end }}
{{ end }}

View file

@ -1,10 +0,0 @@
{{ if .Post.Title }}<h3>{{ .Post.Title }}</h3>{{ end }}
{{ .HTML }}
<a href="{{ url_abs .Path }}">{{ format_date .Post.PublishedAt }}</a>
{{ if .Categories }}
<p>
{{ range .Categories }}
<a href="{{ url_abs (printf "/categories/%s" .Slug) }}">{{ .Name }}</a>
{{ end }}
</p>
{{ end }}

View file

@ -0,0 +1,55 @@
.h-entry {
margin-block-start: 1.5rem;
margin-block-end: 2.5rem;
}
.post-meta {
display: flex;
flex-direction: row;
justify-content: space-between;
font-size: 0.95rem;
}
.post-meta a {
color: var(--text-light);
text-decoration: none;
}
.post-meta a:hover {
text-decoration: underline;
}
.post-categories {
display: inline-flex;
gap: 0.5rem;
}
.post-categories a:before {
content: "#";
}
/* Category list */
ul.category-list {
list-style: none;
padding-inline-start: 0;
}
ul.category-list li {
display: flex;
flex-direction: row;
justify-content: start;
gap: 4rem;
}
ul.category-list span.category-list-name {
min-width: 15vw;
}
/* Category single */
.category-description {
margin-block-start: 1.5rem;
margin-block-end: 2.5rem;
}

View file

@ -0,0 +1,10 @@
<div class="post-meta">
<a href="{{ url_abs .Path }}">{{ format_date .Post.PublishedAt }}</a>
{{ if .Categories }}
<div class="post-categories">
{{ range .Categories }}
<a href="{{ url_abs (printf "/categories/%s" .Slug) }}">{{ .Name }}</a>
{{ end }}
</div>
{{ end }}
</div>

View file

@ -0,0 +1,9 @@
<h2>Categories</h2>
<ul class="category-list">
{{ range .Categories }}
<li>
<span class="category-list-name"><a href="{{ url_abs .Path }}">{{ .Name }}</a> ({{ .PostCount }})</span>
{{ if .DescriptionBrief }}<small>{{ .DescriptionBrief }}</small>{{ end }}
</li>
{{ end }}
</ul>

View file

@ -0,0 +1,11 @@
<h2>{{ .Category.Name }}</h2>
{{ if .DescriptionHTML }}
<div class="notice category-description">{{ .DescriptionHTML }}</div>
{{ end }}
{{ range .Posts }}
<div class="h-entry">
{{ if .Post.Title }}<h3>{{ .Post.Title }}</h3>{{ end }}
{{ .HTML }}
{{ template "_post_meta.html" . }}
</div>
{{ end }}

View file

@ -7,6 +7,7 @@
<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="{{ url_abs "/feed.xml" }}"/>
<link rel="alternate" type="application/json" title="JSON feed" href="{{ url_abs "/feed.json" }}"/>
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
<link rel="stylesheet" href="{{ url_abs "/static/style.css" }}">
</head>
<body>
<header>

View file

@ -0,0 +1,8 @@
{{ range .Posts }}
<div class="h-entry">
{{ if .Post.Title }}<h3>{{ .Post.Title }}</h3>{{ end }}
{{ .HTML }}
{{ template "_post_meta.html" . }}
</div>
{{ end }}

View file

@ -0,0 +1,5 @@
<div class="h-entry">
{{ if .Post.Title }}<h3>{{ .Post.Title }}</h3>{{ end }}
{{ .HTML }}
{{ template "_post_meta.html" . }}
</div>

View file

@ -6,7 +6,9 @@ import (
"fmt"
"html/template"
"io"
"io/fs"
"iter"
"log"
"os"
"path/filepath"
"strings"
@ -31,11 +33,15 @@ type Builder struct {
func New(site pubmodel.Site, opts Options) (*Builder, error) {
tmpls, err := template.New("").
Funcs(templateFns(site, opts)).
ParseFS(opts.TemplatesFS, tmplNamePostSingle, tmplNamePostList, tmplNameLayoutMain, tmplNameCategoryList, tmplNameCategorySingle)
ParseFS(opts.TemplatesFS, "*.html")
if err != nil {
return nil, err
}
for _, t := range tmpls.Templates() {
log.Printf("Loaded template %s", t.Name())
}
return &Builder{
site: site,
opts: opts,
@ -109,6 +115,9 @@ func (b *Builder) BuildSite(outDir string) error {
return b.writeUploads(buildCtx, b.site.Uploads)
})
// Build static assets
eg.Go(func() error { return b.writeStaticAssets(buildCtx) })
return eg.Wait()
}
@ -432,7 +441,7 @@ func (b *Builder) renderTemplate(w io.Writer, name string, data interface{}) err
func (b *Builder) writeUploads(ctx buildContext, uploads []models.Upload) error {
for _, u := range uploads {
fullPath := filepath.Join(ctx.outDir, "uploads", u.Slug)
fullPath := filepath.Join(ctx.outDir, b.opts.BaseUploads, u.Slug)
if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
return err
}
@ -460,3 +469,37 @@ func (b *Builder) writeUploads(ctx buildContext, uploads []models.Upload) error
}
return nil
}
func (b *Builder) writeStaticAssets(ctx buildContext) error {
return fs.WalkDir(b.opts.StaticFS, ".", func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
} else if d.IsDir() {
return nil
}
fullPath := filepath.Join(ctx.outDir, b.opts.BaseStatic, path)
if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
return err
}
return func() error {
r, err := b.opts.StaticFS.Open(path)
if err != nil {
return err
}
defer r.Close()
w, err := os.Create(fullPath)
if err != nil {
return err
}
defer w.Close()
if _, err := io.Copy(w, r); err != nil {
return err
}
return nil
}()
})
}

View file

@ -29,12 +29,17 @@ const (
)
type Options struct {
// BasePosts is the base path for posts.
BasePosts string
BasePosts string // BasePosts is the base path for posts.
BaseUploads string // BaseUploads is the base path for uploads.
BaseStatic string // BaseStatic is the base path for static assets.
// TemplatesFS provides the raw templates for rendering the site.
TemplatesFS fs.FS
// StaticFS provides the raw assets for the site. This will be written as is
// from the BaseStatic dir.
StaticFS fs.FS
// FeedItems holds the number of posts to show in the feed.
FeedItems int

View file

@ -3,6 +3,7 @@ package publisher
import (
"context"
"io"
"io/fs"
"iter"
"log"
"os"
@ -102,9 +103,22 @@ func (p *Publisher) publishSite(ctx context.Context, pubSite pubmodel.Site, targ
renderTZ = time.UTC
}
templateFS, err := fs.Sub(simplecss.FS, "templates")
if err != nil {
return err
}
staticFS, err := fs.Sub(simplecss.FS, "static")
if err != nil {
return err
}
sb, err := sitebuilder.New(pubSite, sitebuilder.Options{
BasePosts: "/posts",
TemplatesFS: simplecss.FS,
BaseUploads: "/uploads",
BaseStatic: "/static",
TemplatesFS: templateFS,
StaticFS: staticFS,
FeedItems: 30,
RenderTZ: renderTZ,
})

View file

@ -5,7 +5,7 @@
</div>
</div>
{{ range .categories }}
{{ if .categories }}
<table class="table">
<thead>
<tr>
@ -15,11 +15,13 @@
</tr>
</thead>
<tbody>
<tr>
<td><a href="/sites/{{ $.site.ID }}/categories/{{ .ID }}">{{ .Name }}</a></td>
<td><code>{{ .Slug }}</code></td>
<td>{{ .PostCount }}</td>
</tr>
{{ range .categories }}
<tr>
<td><a href="/sites/{{ $.site.ID }}/categories/{{ .ID }}">{{ .Name }}</a></td>
<td><code>{{ .Slug }}</code></td>
<td>{{ .PostCount }}</td>
</tr>
{{ end }}
</tbody>
</table>
{{ else }}