Fix chapter reader nav bar: use hamburger icon for back-to-book, show chapter date below title
- Replace bare ← back-to-book link with ☰ (hamburger) icon to eliminate the visual double-arrow confusion with the ← Prev chapter button - Export SplitChapterTitle in writer package and call it in handleChapter to split the raw heading into (title, date) — fixes concatenated title+date bug - Display ChapterDate as a smaller muted line below the chapter title in the center nav button - Bump nav bar height from h-12 to h-14 to accommodate two-line center button
This commit is contained in:
@@ -1379,19 +1379,19 @@ const chapterTmpl = `
|
||||
<!-- aria-hidden keeps it out of accessibility trees / Reader Mode heuristics -->
|
||||
<nav id="reader-header" aria-hidden="true"
|
||||
style="position:sticky;top:0;z-index:50;background:#09090b;border-bottom:1px solid #27272a;">
|
||||
<div class="max-w-2xl mx-auto px-4 flex items-center gap-2 h-12">
|
||||
<div class="max-w-2xl mx-auto px-4 flex items-center gap-2 h-14">
|
||||
|
||||
<!-- Back to book -->
|
||||
<!-- Back to book (book/list icon, visually distinct from ← Prev) -->
|
||||
<a href="/books/{{.Slug}}"
|
||||
hx-get="/books/{{.Slug}}"
|
||||
hx-target="#main-content"
|
||||
hx-push-url="true"
|
||||
hx-swap="innerHTML"
|
||||
title="Chapter list"
|
||||
title="Back to chapter list"
|
||||
aria-label="Back to chapter list"
|
||||
style="flex-shrink:0;padding:0.375rem 0.5rem;border-radius:0.5rem;color:#a1a1aa;font-size:0.875rem;text-decoration:none;transition:color 0.15s;"
|
||||
style="flex-shrink:0;padding:0.375rem 0.5rem;border-radius:0.5rem;color:#a1a1aa;font-size:1rem;text-decoration:none;transition:color 0.15s;line-height:1;"
|
||||
onmouseover="this.style.color='#fbbf24'" onmouseout="this.style.color='#a1a1aa'">
|
||||
←
|
||||
☰
|
||||
</a>
|
||||
|
||||
<!-- Prev chapter -->
|
||||
@@ -1416,8 +1416,11 @@ const chapterTmpl = `
|
||||
onclick="toggleChapterList()"
|
||||
title="Jump to chapter"
|
||||
aria-label="Jump to chapter"
|
||||
style="flex:1;min-width:0;display:flex;align-items:center;justify-content:center;gap:0.375rem;overflow:hidden;background:transparent;border:none;cursor:pointer;padding:0.375rem 0.25rem;">
|
||||
<span style="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:0.8125rem;color:#a1a1aa;">{{.Title}}</span>
|
||||
style="flex:1;min-width:0;display:flex;align-items:center;justify-content:center;gap:0.375rem;overflow:hidden;background:transparent;border:none;cursor:pointer;padding:0.25rem 0.25rem;">
|
||||
<span style="min-width:0;display:flex;flex-direction:column;align-items:center;overflow:hidden;">
|
||||
<span style="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:0.8125rem;color:#a1a1aa;max-width:100%;">{{.Title}}</span>
|
||||
{{if .ChapterDate}}<span style="font-size:0.6875rem;color:#52525b;white-space:nowrap;">{{.ChapterDate}}</span>{{end}}
|
||||
</span>
|
||||
<span style="flex-shrink:0;font-size:0.625rem;color:#52525b;" aria-hidden="true">▼</span>
|
||||
</button>
|
||||
|
||||
@@ -2166,6 +2169,7 @@ func (s *Server) handleChapter(w http.ResponseWriter, r *http.Request) {
|
||||
prevN, nextN := adjacentChapters(chapters, n)
|
||||
|
||||
title := firstHeading(raw, fmt.Sprintf("Chapter %d", n))
|
||||
chapterTitle, chapterDate := writer.SplitChapterTitle(title)
|
||||
|
||||
t := template.Must(template.New("chapter").Parse(chapterTmpl))
|
||||
var buf bytes.Buffer
|
||||
@@ -2176,6 +2180,7 @@ func (s *Server) handleChapter(w http.ResponseWriter, r *http.Request) {
|
||||
NextN int
|
||||
ChapterN int
|
||||
Title string
|
||||
ChapterDate string
|
||||
AllChapters interface{}
|
||||
Voices []string
|
||||
DefaultVoice string
|
||||
@@ -2185,13 +2190,14 @@ func (s *Server) handleChapter(w http.ResponseWriter, r *http.Request) {
|
||||
PrevN: prevN,
|
||||
NextN: nextN,
|
||||
ChapterN: n,
|
||||
Title: title,
|
||||
Title: chapterTitle,
|
||||
ChapterDate: chapterDate,
|
||||
AllChapters: chapters,
|
||||
Voices: kokoroVoices,
|
||||
DefaultVoice: s.kokoroVoice,
|
||||
})
|
||||
|
||||
s.respond(w, r, title, buf.String())
|
||||
s.respond(w, r, chapterTitle, buf.String())
|
||||
}
|
||||
|
||||
// ─── helpers ──────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -219,12 +219,12 @@ func chapterTitle(path string, n int) (title, date string) {
|
||||
continue
|
||||
}
|
||||
line = strings.TrimPrefix(line, "# ")
|
||||
return splitChapterTitle(line)
|
||||
return SplitChapterTitle(line)
|
||||
}
|
||||
return fmt.Sprintf("Chapter %d", n), ""
|
||||
}
|
||||
|
||||
// splitChapterTitle separates the human-readable chapter name from the
|
||||
// SplitChapterTitle separates the human-readable chapter name from the
|
||||
// trailing relative-date string that novelfire.net appends to the heading.
|
||||
// Examples of raw heading text (after stripping "# "):
|
||||
//
|
||||
@@ -233,7 +233,7 @@ func chapterTitle(path string, n int) (title, date string) {
|
||||
//
|
||||
// The pattern is: optional leading number+whitespace, then the real title,
|
||||
// then a date that matches /\d+\s+(second|minute|hour|day|week|month|year)s?\s+ago$/
|
||||
func splitChapterTitle(raw string) (title, date string) {
|
||||
func SplitChapterTitle(raw string) (title, date string) {
|
||||
// Strip a leading chapter-number index that novelfire sometimes prepends.
|
||||
// It looks like "1 " or "12 " at the very start.
|
||||
raw = strings.TrimSpace(raw)
|
||||
|
||||
Reference in New Issue
Block a user