Add newer/older navigation to the photo detail page
Replace the standalone Back link with a three-cell nav row so each photo page links to its neighbours in the timeline. Prefetch the neighbouring pages and bind the arrow keys for keyboard navigation.
This commit is contained in:
+12
-3
@@ -108,8 +108,15 @@ func (g *Generator) Build() error {
|
||||
if err := g.renderIndexPages(photos); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, p := range photos {
|
||||
if err := g.renderPhotoPage(p); err != nil {
|
||||
for i := range photos {
|
||||
var newer, older *Photo
|
||||
if i > 0 {
|
||||
newer = &photos[i-1]
|
||||
}
|
||||
if i+1 < len(photos) {
|
||||
older = &photos[i+1]
|
||||
}
|
||||
if err := g.renderPhotoPage(photos[i], newer, older); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -358,13 +365,15 @@ func (g *Generator) renderIndexPages(photos []Photo) error {
|
||||
}
|
||||
|
||||
// renderPhotoPage writes public/photo/<slug>/index.html.
|
||||
func (g *Generator) renderPhotoPage(p Photo) error {
|
||||
func (g *Generator) renderPhotoPage(p Photo, newer, older *Photo) error {
|
||||
dir := filepath.Join(g.outputDir, "photo", p.Slug)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
return g.render("photo.html", filepath.Join(dir, "index.html"), map[string]any{
|
||||
"Photo": p,
|
||||
"Newer": newer,
|
||||
"Older": older,
|
||||
"BaseURL": g.baseURL,
|
||||
"Year": time.Now().Year(),
|
||||
"Author": g.author,
|
||||
|
||||
+24
-7
@@ -195,17 +195,34 @@ body {
|
||||
padding: 16px 20px;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
display: inline-block;
|
||||
font-size: 15px;
|
||||
color: var(--fg3);
|
||||
text-decoration: none;
|
||||
.photo-nav {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 0;
|
||||
margin-bottom: 16px;
|
||||
font-family: var(--serif);
|
||||
font-family: monospace;
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.back-btn:hover {
|
||||
.photo-nav a {
|
||||
color: var(--aqua);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.photo-nav a:hover {
|
||||
color: var(--fg2);
|
||||
}
|
||||
|
||||
.photo-nav .back-btn {
|
||||
font-family: var(--serif);
|
||||
font-size: 15px;
|
||||
color: var(--fg3);
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.photo-nav .back-btn:hover {
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,16 @@
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
<style>:root { --serif: '{{.SerifFamily}}', Georgia, serif; --mj: '{{.MlFamily}}', sans-serif; }</style>
|
||||
<link rel="alternate" type="application/atom+xml" href="/feed.xml" title="Photo Feed">
|
||||
{{if .Newer}}<link rel="prefetch" href="/photo/{{.Newer.Slug}}/">{{end}}
|
||||
{{if .Older}}<link rel="prefetch" href="/photo/{{.Older.Slug}}/">{{end}}
|
||||
</head>
|
||||
<body>
|
||||
<div class="photo-page">
|
||||
<nav class="photo-nav">
|
||||
{{if .Newer}}<a href="/photo/{{.Newer.Slug}}/" data-nav="newer">← Newer</a>{{else}}<span></span>{{end}}
|
||||
<a href="/" class="back-btn">← Back</a>
|
||||
{{if .Older}}<a href="/photo/{{.Older.Slug}}/" data-nav="older">Older →</a>{{else}}<span></span>{{end}}
|
||||
</nav>
|
||||
<div class="dlayout">
|
||||
<div class="dimg-wrap">
|
||||
<a href="/{{.Photo.File}}" target="_blank" rel="noopener">
|
||||
@@ -33,5 +39,17 @@
|
||||
<footer class="site-footer">
|
||||
© 2000–{{.Year}} {{.Author}}. All rights reserved.
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
const newer = document.querySelector('[data-nav="newer"]');
|
||||
const older = document.querySelector('[data-nav="older"]');
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.target.matches('input, textarea')) return;
|
||||
if (e.key === 'ArrowLeft' && newer) location.href = newer.href;
|
||||
if (e.key === 'ArrowRight' && older) location.href = older.href;
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user