Redesign homepage: Explore dropdown nav + paginated post list with summaries
- Replace Tags nav item with an Explore dropdown containing Tags, Site Index, and all tool subpages (Status, Flights, Volleyball Score, Pixel Art, ASCII Art) - Limit homepage to 8 posts per page with pagination controls - Show frontmatter description as post excerpt (more useful than auto-summary for Morning Brief posts with similar titles) - Custom CSS for dropdown panel (hover + focus-within for keyboard/touch) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f466701509
commit
9b37504988
5 changed files with 244 additions and 0 deletions
50
hugo.toml
50
hugo.toml
|
|
@ -8,19 +8,69 @@ googleAnalytics = 'G-LMKPZJ98Y8'
|
||||||
|
|
||||||
contentDir = "content"
|
contentDir = "content"
|
||||||
|
|
||||||
|
[pagination]
|
||||||
|
pagerSize = 8
|
||||||
|
|
||||||
[Params]
|
[Params]
|
||||||
description = "Writer, thinker, technologist. Morning briefs, Stoic reflections, self-hosting, and systems thinking."
|
description = "Writer, thinker, technologist. Morning briefs, Stoic reflections, self-hosting, and systems thinking."
|
||||||
|
|
||||||
|
# Main nav: Posts as a direct link, then an Explore dropdown for everything else
|
||||||
[[menus.main]]
|
[[menus.main]]
|
||||||
|
identifier = "posts"
|
||||||
name = "Posts"
|
name = "Posts"
|
||||||
url = "/posts/"
|
url = "/posts/"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
|
||||||
|
[[menus.main]]
|
||||||
|
identifier = "explore"
|
||||||
|
name = "Explore"
|
||||||
|
url = "/explore/"
|
||||||
|
weight = 2
|
||||||
|
|
||||||
|
# Explore dropdown children — blog navigation
|
||||||
[[menus.main]]
|
[[menus.main]]
|
||||||
name = "Tags"
|
name = "Tags"
|
||||||
url = "/tags/"
|
url = "/tags/"
|
||||||
|
parent = "explore"
|
||||||
|
weight = 1
|
||||||
|
|
||||||
|
[[menus.main]]
|
||||||
|
name = "Site Index"
|
||||||
|
url = "/explore/"
|
||||||
|
parent = "explore"
|
||||||
weight = 2
|
weight = 2
|
||||||
|
|
||||||
|
# Explore dropdown children — tools
|
||||||
|
[[menus.main]]
|
||||||
|
name = "Status Dashboard"
|
||||||
|
url = "/status"
|
||||||
|
parent = "explore"
|
||||||
|
weight = 3
|
||||||
|
|
||||||
|
[[menus.main]]
|
||||||
|
name = "Flights"
|
||||||
|
url = "/flights"
|
||||||
|
parent = "explore"
|
||||||
|
weight = 4
|
||||||
|
|
||||||
|
[[menus.main]]
|
||||||
|
name = "Volleyball Score"
|
||||||
|
url = "/volleyball-score"
|
||||||
|
parent = "explore"
|
||||||
|
weight = 5
|
||||||
|
|
||||||
|
[[menus.main]]
|
||||||
|
name = "Pixel Art"
|
||||||
|
url = "/pixel-art"
|
||||||
|
parent = "explore"
|
||||||
|
weight = 6
|
||||||
|
|
||||||
|
[[menus.main]]
|
||||||
|
name = "ASCII Art"
|
||||||
|
url = "/ascii-art"
|
||||||
|
parent = "explore"
|
||||||
|
weight = 7
|
||||||
|
|
||||||
[[menus.footer]]
|
[[menus.footer]]
|
||||||
name = "RSS"
|
name = "RSS"
|
||||||
url = "/index.xml"
|
url = "/index.xml"
|
||||||
|
|
|
||||||
42
layouts/index.html
Normal file
42
layouts/index.html
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
{{ define "main" }}
|
||||||
|
{{- $pages := where .Site.RegularPages "Section" "posts" }}
|
||||||
|
{{- $paginator := .Paginate $pages }}
|
||||||
|
<ul class="post-list">
|
||||||
|
{{- range $paginator.Pages }}
|
||||||
|
<li class="post-list__entry">
|
||||||
|
<div class="post-list__meta">
|
||||||
|
<time class="post-list__date" datetime="{{ .Date.Format "2006-01-02" }}">{{ .Date.Format "Jan 2, 2006" }}</time>
|
||||||
|
{{- with .Params.categories }}
|
||||||
|
<span class="post-list__category">{{ index . 0 | lower }}</span>
|
||||||
|
{{- end }}
|
||||||
|
</div>
|
||||||
|
<div class="post-list__body">
|
||||||
|
<a href="{{ .Permalink }}" class="post-list__title">{{ .Title }}</a>
|
||||||
|
{{- /* Use frontmatter description first (richer for Morning Brief posts),
|
||||||
|
fall back to auto-generated summary */}}
|
||||||
|
{{- $excerpt := or .Description (.Summary | plainify) }}
|
||||||
|
{{- if $excerpt }}
|
||||||
|
<p class="post-list__excerpt">{{ $excerpt | truncate 220 }}</p>
|
||||||
|
{{- end }}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{- end }}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{- /* Pagination controls — only shown when there's more than one page */}}
|
||||||
|
{{- if gt $paginator.TotalPages 1 }}
|
||||||
|
<nav class="post-list-pagination" aria-label="Post navigation">
|
||||||
|
<span>
|
||||||
|
{{- if $paginator.HasPrev }}
|
||||||
|
<a href="{{ $paginator.Prev.URL | absURL }}">← Newer posts</a>
|
||||||
|
{{- end }}
|
||||||
|
</span>
|
||||||
|
<span>Page {{ $paginator.PageNumber }} of {{ $paginator.TotalPages }}</span>
|
||||||
|
<span>
|
||||||
|
{{- if $paginator.HasNext }}
|
||||||
|
<a href="{{ $paginator.Next.URL | absURL }}">Older posts →</a>
|
||||||
|
{{- end }}
|
||||||
|
</span>
|
||||||
|
</nav>
|
||||||
|
{{- end }}
|
||||||
|
{{ end }}
|
||||||
23
layouts/partials/head.html
Normal file
23
layouts/partials/head.html
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ .Title }} — {{ .Site.Title }}{{ end }}</title>
|
||||||
|
{{ with .Description }}<meta name="description" content="{{ . }}">{{ end }}
|
||||||
|
{{ with .Params.summary }}<meta name="description" content="{{ . }}">{{ end }}
|
||||||
|
<meta name="generator" content="Hugo {{ hugo.Version }}">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,500;0,600;0,700;1,400&family=IBM+Plex+Mono:wght@400&display=swap" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="{{ "css/main.css" | relURL }}">
|
||||||
|
<link rel="stylesheet" href="{{ "css/custom.css" | relURL }}">
|
||||||
|
{{ with .OutputFormats.Get "rss" -}}
|
||||||
|
<link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink }}" title="{{ $.Site.Title }}">
|
||||||
|
{{- end }}
|
||||||
|
{{ with .Site.Params.googleAnalytics -}}
|
||||||
|
<script async src="https://www.googletagmanager.com/gtag/js?id={{ . }}"></script>
|
||||||
|
<script>
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag(){dataLayer.push(arguments);}
|
||||||
|
gtag('js', new Date());
|
||||||
|
gtag('config', '{{ . }}');
|
||||||
|
</script>
|
||||||
|
{{- end }}
|
||||||
37
layouts/partials/header.html
Normal file
37
layouts/partials/header.html
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="site-wrapper">
|
||||||
|
<div class="site-header__inner">
|
||||||
|
<a href="{{ "/" | relURL }}" class="site-title">{{ .Site.Title }}</a>
|
||||||
|
{{- if .Site.Menus.main }}
|
||||||
|
<nav aria-label="Main navigation">
|
||||||
|
<ul class="site-nav">
|
||||||
|
{{- range .Site.Menus.main }}
|
||||||
|
{{- if not .Parent }}{{/* top-level items only */}}
|
||||||
|
{{- if .HasChildren }}
|
||||||
|
{{/* Explore dropdown — renders parent link + child list */}}
|
||||||
|
<li class="nav-has-dropdown">
|
||||||
|
<a href="{{ .URL }}"
|
||||||
|
{{- if $.IsMenuCurrent "main" . }} class="is-active"{{ end }}
|
||||||
|
aria-haspopup="true">{{ .Name }} <span class="nav-arrow" aria-hidden="true">▾</span></a>
|
||||||
|
<ul class="nav-dropdown" role="menu">
|
||||||
|
{{- range .Children }}
|
||||||
|
<li role="none">
|
||||||
|
<a href="{{ .URL }}" role="menuitem">{{ .Name }}</a>
|
||||||
|
</li>
|
||||||
|
{{- end }}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{{- else }}
|
||||||
|
{{/* Regular nav item */}}
|
||||||
|
<li>
|
||||||
|
<a href="{{ .URL }}"{{ if $.IsMenuCurrent "main" . }} class="is-active"{{ end }}>{{ .Name }}</a>
|
||||||
|
</li>
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{{- end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
92
static/css/custom.css
Normal file
92
static/css/custom.css
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
/* ── Explore dropdown nav ── */
|
||||||
|
|
||||||
|
/* Wrapper li needs relative positioning for the dropdown panel */
|
||||||
|
.nav-has-dropdown {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show the dropdown on hover (desktop) and when focus is inside (keyboard/touch) */
|
||||||
|
.nav-has-dropdown:hover .nav-dropdown,
|
||||||
|
.nav-has-dropdown:focus-within .nav-dropdown {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dropdown panel */
|
||||||
|
.nav-dropdown {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: calc(100% + 4px);
|
||||||
|
right: 0;
|
||||||
|
min-width: 180px;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 6px 0;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 4px 16px rgba(44, 36, 22, 0.10);
|
||||||
|
z-index: 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-dropdown li {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-dropdown a {
|
||||||
|
display: block;
|
||||||
|
padding: 7px 16px;
|
||||||
|
font-size: 15px;
|
||||||
|
color: var(--color-secondary);
|
||||||
|
white-space: nowrap;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background 100ms ease, color 100ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-dropdown a:hover {
|
||||||
|
background: var(--color-neutral);
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Subtle arrow nudge so it's clear it's a dropdown trigger */
|
||||||
|
.nav-arrow {
|
||||||
|
font-size: 11px;
|
||||||
|
opacity: 0.6;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Homepage post list improvements ── */
|
||||||
|
|
||||||
|
/* Slightly more breathing room between entries */
|
||||||
|
.post-list__entry {
|
||||||
|
padding-bottom: 1.4rem;
|
||||||
|
margin-bottom: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Description/excerpt text under each post title */
|
||||||
|
.post-list__excerpt {
|
||||||
|
margin-top: 0.3rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--color-secondary);
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pagination controls at bottom of homepage */
|
||||||
|
.post-list-pagination {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 1.5rem;
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: var(--color-tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-list-pagination a {
|
||||||
|
color: var(--color-accent);
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-list-pagination a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue