fix(systemviews): mute history title stats
- commit
- 4f7fc7c7855cc4863d751647c976c6b62dd247e1
- author
- brice · · 2026-04-26 07:14 UTC
- parent
- 4e23726
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
8 files · +204 -157
M assets/systemviews/systemviews.css +11 -0
| @@ -53,11 +53,22 @@ body { | |||
| 53 | 53 | } | |
| 54 | 54 | ||
| 55 | 55 | .sv-title { | |
| 56 | + | display: flex; | |
| 57 | + | flex-wrap: wrap; | |
| 58 | + | gap: 0.45rem; | |
| 59 | + | align-items: baseline; | |
| 56 | 60 | margin: 0; | |
| 57 | 61 | font-size: clamp(1.35rem, 2.4vw, 2rem); | |
| 58 | 62 | line-height: 1.15; | |
| 59 | 63 | } | |
| 60 | 64 | ||
| 65 | + | .sv-title-detail { | |
| 66 | + | color: var(--sv-muted); | |
| 67 | + | font-size: clamp(0.9rem, 1.25vw, 1.05rem); | |
| 68 | + | font-weight: 600; | |
| 69 | + | letter-spacing: 0; | |
| 70 | + | } | |
| 71 | + | ||
| 61 | 72 | .sv-content { | |
| 62 | 73 | display: grid; | |
| 63 | 74 | gap: 1rem; | |
| @@ -53,11 +53,22 @@ body { | |||||
| 53 | } | 53 | } | ||
| 54 | 54 | ||||
| 55 | .sv-title { | 55 | .sv-title { | ||
| 56 | + | display: flex; | |||
| 57 | + | flex-wrap: wrap; | |||
| 58 | + | gap: 0.45rem; | |||
| 59 | + | align-items: baseline; | |||
| 56 | margin: 0; | 60 | margin: 0; | ||
| 57 | font-size: clamp(1.35rem, 2.4vw, 2rem); | 61 | font-size: clamp(1.35rem, 2.4vw, 2rem); | ||
| 58 | line-height: 1.15; | 62 | line-height: 1.15; | ||
| 59 | } | 63 | } | ||
| 60 | 64 | ||||
| 65 | + | .sv-title-detail { | |||
| 66 | + | color: var(--sv-muted); | |||
| 67 | + | font-size: clamp(0.9rem, 1.25vw, 1.05rem); | |||
| 68 | + | font-weight: 600; | |||
| 69 | + | letter-spacing: 0; | |||
| 70 | + | } | |||
| 71 | + | ||||
| 61 | .sv-content { | 72 | .sv-content { | ||
| 62 | display: grid; | 73 | display: grid; | ||
| 63 | gap: 1rem; | 74 | gap: 1rem; | ||
M internal/ui/systemviews/app.go +10 -8
| @@ -515,10 +515,11 @@ func (a *App) loadHistoryLoadingRoute() { | |||
| 515 | 515 | } | |
| 516 | 516 | title := historyDocumentTitle(data) | |
| 517 | 517 | a.renderedHTML = renderAppFrame(renderedPage{ | |
| 518 | - | route: RouteHistory, | |
| 519 | - | title: title, | |
| 520 | - | subtitle: title, | |
| 521 | - | body: historyHTML(data), | |
| 518 | + | route: RouteHistory, | |
| 519 | + | title: title, | |
| 520 | + | subtitle: "History", | |
| 521 | + | subtitleDetail: historyTitleDetail(data), | |
| 522 | + | body: historyHTML(data), | |
| 522 | 523 | }, a.shellTheme) | |
| 523 | 524 | } | |
| 524 | 525 | ||
| @@ -633,10 +634,11 @@ func (a *App) renderHistoryRouteSnapshot(ctx context.Context, snapshot historyRo | |||
| 633 | 634 | } | |
| 634 | 635 | title := historyDocumentTitle(data) | |
| 635 | 636 | result.html = renderAppFrame(renderedPage{ | |
| 636 | - | route: RouteHistory, | |
| 637 | - | title: title, | |
| 638 | - | subtitle: title, | |
| 639 | - | body: historyHTML(data), | |
| 637 | + | route: RouteHistory, | |
| 638 | + | title: title, | |
| 639 | + | subtitle: "History", | |
| 640 | + | subtitleDetail: historyTitleDetail(data), | |
| 641 | + | body: historyHTML(data), | |
| 640 | 642 | }, snapshot.shellTheme) | |
| 641 | 643 | return result, nil | |
| 642 | 644 | } | |
| @@ -515,10 +515,11 @@ func (a *App) loadHistoryLoadingRoute() { | |||||
| 515 | } | 515 | } | ||
| 516 | title := historyDocumentTitle(data) | 516 | title := historyDocumentTitle(data) | ||
| 517 | a.renderedHTML = renderAppFrame(renderedPage{ | 517 | a.renderedHTML = renderAppFrame(renderedPage{ | ||
| 518 | - | route: RouteHistory, | 518 | + | route: RouteHistory, |
| 519 | - | title: title, | 519 | + | title: title, |
| 520 | - | subtitle: title, | 520 | + | subtitle: "History", |
| 521 | - | body: historyHTML(data), | 521 | + | subtitleDetail: historyTitleDetail(data), |
| 522 | + | body: historyHTML(data), | |||
| 522 | }, a.shellTheme) | 523 | }, a.shellTheme) | ||
| 523 | } | 524 | } | ||
| 524 | 525 | ||||
| @@ -633,10 +634,11 @@ func (a *App) renderHistoryRouteSnapshot(ctx context.Context, snapshot historyRo | |||||
| 633 | } | 634 | } | ||
| 634 | title := historyDocumentTitle(data) | 635 | title := historyDocumentTitle(data) | ||
| 635 | result.html = renderAppFrame(renderedPage{ | 636 | result.html = renderAppFrame(renderedPage{ | ||
| 636 | - | route: RouteHistory, | 637 | + | route: RouteHistory, |
| 637 | - | title: title, | 638 | + | title: title, |
| 638 | - | subtitle: title, | 639 | + | subtitle: "History", |
| 639 | - | body: historyHTML(data), | 640 | + | subtitleDetail: historyTitleDetail(data), |
| 641 | + | body: historyHTML(data), | |||
| 640 | }, snapshot.shellTheme) | 642 | }, snapshot.shellTheme) | ||
| 641 | return result, nil | 643 | return result, nil | ||
| 642 | } | 644 | } | ||
M internal/ui/systemviews/app_test.go +1 -1
| @@ -111,7 +111,7 @@ func TestAppLoadInitialHistoryRouteShowsTotalStatsWithWindowedTimeline(t *testin | |||
| 111 | 111 | assert.True(t, history.statsCalled) | |
| 112 | 112 | assert.Contains(t, app.renderedHTML, "Loaded 2 items") | |
| 113 | 113 | assert.Contains(t, app.renderedHTML, `data-page-title="History - 8904 entries, 40947 visits, 121 days"`) | |
| 114 | - | assert.Contains(t, app.renderedHTML, `<h1 class="sv-title">History - 8904 entries, 40947 visits, 121 days</h1>`) | |
| 114 | + | assert.Contains(t, app.renderedHTML, `<h1 class="sv-title">History <span class="sv-title-detail">- 8904 entries, 40947 visits, 121 days</span></h1>`) | |
| 115 | 115 | assert.NotContains(t, app.renderedHTML, `sv-history-summary`) | |
| 116 | 116 | assert.NotContains(t, app.renderedHTML, `sv-stat-value`) | |
| 117 | 117 | } | |
| @@ -111,7 +111,7 @@ func TestAppLoadInitialHistoryRouteShowsTotalStatsWithWindowedTimeline(t *testin | |||||
| 111 | assert.True(t, history.statsCalled) | 111 | assert.True(t, history.statsCalled) | ||
| 112 | assert.Contains(t, app.renderedHTML, "Loaded 2 items") | 112 | assert.Contains(t, app.renderedHTML, "Loaded 2 items") | ||
| 113 | assert.Contains(t, app.renderedHTML, `data-page-title="History - 8904 entries, 40947 visits, 121 days"`) | 113 | assert.Contains(t, app.renderedHTML, `data-page-title="History - 8904 entries, 40947 visits, 121 days"`) | ||
| 114 | - | assert.Contains(t, app.renderedHTML, `<h1 class="sv-title">History - 8904 entries, 40947 visits, 121 days</h1>`) | 114 | + | assert.Contains(t, app.renderedHTML, `<h1 class="sv-title">History <span class="sv-title-detail">- 8904 entries, 40947 visits, 121 days</span></h1>`) |
| 115 | assert.NotContains(t, app.renderedHTML, `sv-history-summary`) | 115 | assert.NotContains(t, app.renderedHTML, `sv-history-summary`) | ||
| 116 | assert.NotContains(t, app.renderedHTML, `sv-stat-value`) | 116 | assert.NotContains(t, app.renderedHTML, `sv-stat-value`) | ||
| 117 | } | 117 | } | ||
M internal/ui/systemviews/components.templ +6 -1
| @@ -8,7 +8,12 @@ templ appFrameComponent(page renderedPage, theme shellTheme, body templ.Componen | |||
| 8 | 8 | > | |
| 9 | 9 | <div class="sv-shell"> | |
| 10 | 10 | if page.subtitle != "" { | |
| 11 | - | <h1 class="sv-title">{ page.subtitle }</h1> | |
| 11 | + | <h1 class="sv-title"> | |
| 12 | + | { page.subtitle } | |
| 13 | + | if page.subtitleDetail != "" { | |
| 14 | + | <span class="sv-title-detail">{ page.subtitleDetail }</span> | |
| 15 | + | } | |
| 16 | + | </h1> | |
| 12 | 17 | } | |
| 13 | 18 | <div class="sv-content"> | |
| 14 | 19 | @body | |
| @@ -8,7 +8,12 @@ templ appFrameComponent(page renderedPage, theme shellTheme, body templ.Componen | |||||
| 8 | > | 8 | > | ||
| 9 | <div class="sv-shell"> | 9 | <div class="sv-shell"> | ||
| 10 | if page.subtitle != "" { | 10 | if page.subtitle != "" { | ||
| 11 | - | <h1 class="sv-title">{ page.subtitle }</h1> | 11 | + | <h1 class="sv-title"> |
| 12 | + | { page.subtitle } | |||
| 13 | + | if page.subtitleDetail != "" { | |||
| 14 | + | <span class="sv-title-detail">{ page.subtitleDetail }</span> | |||
| 15 | + | } | |||
| 16 | + | </h1> | |||
| 12 | } | 17 | } | ||
| 13 | <div class="sv-content"> | 18 | <div class="sv-content"> | ||
| 14 | @body | 19 | @body | ||
M internal/ui/systemviews/components_templ.go +160 -137 generated file: collapsed
M internal/ui/systemviews/history_actions.go +5 -4
| @@ -237,10 +237,11 @@ func (a *App) handleHistoryLoadMore(ctx context.Context, event DOMAction) error | |||
| 237 | 237 | fullData.Entries = a.historyEntries | |
| 238 | 238 | title := historyDocumentTitle(fullData) | |
| 239 | 239 | a.renderedHTML = renderAppFrame(renderedPage{ | |
| 240 | - | route: RouteHistory, | |
| 241 | - | title: title, | |
| 242 | - | subtitle: title, | |
| 243 | - | body: historyHTML(fullData), | |
| 240 | + | route: RouteHistory, | |
| 241 | + | title: title, | |
| 242 | + | subtitle: "History", | |
| 243 | + | subtitleDetail: historyTitleDetail(fullData), | |
| 244 | + | body: historyHTML(fullData), | |
| 244 | 245 | }, a.shellTheme) | |
| 245 | 246 | fallbackHTML = a.renderedHTML | |
| 246 | 247 | } | |
| @@ -237,10 +237,11 @@ func (a *App) handleHistoryLoadMore(ctx context.Context, event DOMAction) error | |||||
| 237 | fullData.Entries = a.historyEntries | 237 | fullData.Entries = a.historyEntries | ||
| 238 | title := historyDocumentTitle(fullData) | 238 | title := historyDocumentTitle(fullData) | ||
| 239 | a.renderedHTML = renderAppFrame(renderedPage{ | 239 | a.renderedHTML = renderAppFrame(renderedPage{ | ||
| 240 | - | route: RouteHistory, | 240 | + | route: RouteHistory, |
| 241 | - | title: title, | 241 | + | title: title, |
| 242 | - | subtitle: title, | 242 | + | subtitle: "History", |
| 243 | - | body: historyHTML(fullData), | 243 | + | subtitleDetail: historyTitleDetail(fullData), |
| 244 | + | body: historyHTML(fullData), | |||
| 244 | }, a.shellTheme) | 245 | }, a.shellTheme) | ||
| 245 | fallbackHTML = a.renderedHTML | 246 | fallbackHTML = a.renderedHTML | ||
| 246 | } | 247 | } | ||
M internal/ui/systemviews/history_view.go +6 -2
| @@ -52,12 +52,16 @@ func historyTimelineAppendHTML(data historyRenderData) string { | |||
| 52 | 52 | } | |
| 53 | 53 | ||
| 54 | 54 | func historyDocumentTitle(data historyRenderData) string { | |
| 55 | + | return "History " + historyTitleDetail(data) | |
| 56 | + | } | |
| 57 | + | ||
| 58 | + | func historyTitleDetail(data historyRenderData) string { | |
| 55 | 59 | if data.Loading { | |
| 56 | - | return "History - Loading" | |
| 60 | + | return "- Loading" | |
| 57 | 61 | } | |
| 58 | 62 | entries, visits, days := historySummaryValues(data) | |
| 59 | 63 | return fmt.Sprintf( | |
| 60 | - | "History - %s, %s, %s", | |
| 64 | + | "- %s, %s, %s", | |
| 61 | 65 | historyCountLabel(entries, "entry", "entries"), | |
| 62 | 66 | historyCountLabel(visits, "visit", "visits"), | |
| 63 | 67 | historyCountLabel(days, "day", "days"), | |
| @@ -52,12 +52,16 @@ func historyTimelineAppendHTML(data historyRenderData) string { | |||||
| 52 | } | 52 | } | ||
| 53 | 53 | ||||
| 54 | func historyDocumentTitle(data historyRenderData) string { | 54 | func historyDocumentTitle(data historyRenderData) string { | ||
| 55 | + | return "History " + historyTitleDetail(data) | |||
| 56 | + | } | |||
| 57 | + | ||||
| 58 | + | func historyTitleDetail(data historyRenderData) string { | |||
| 55 | if data.Loading { | 59 | if data.Loading { | ||
| 56 | - | return "History - Loading" | 60 | + | return "- Loading" |
| 57 | } | 61 | } | ||
| 58 | entries, visits, days := historySummaryValues(data) | 62 | entries, visits, days := historySummaryValues(data) | ||
| 59 | return fmt.Sprintf( | 63 | return fmt.Sprintf( | ||
| 60 | - | "History - %s, %s, %s", | 64 | + | "- %s, %s, %s", |
| 61 | historyCountLabel(entries, "entry", "entries"), | 65 | historyCountLabel(entries, "entry", "entries"), | ||
| 62 | historyCountLabel(visits, "visit", "visits"), | 66 | historyCountLabel(visits, "visit", "visits"), | ||
| 63 | historyCountLabel(days, "day", "days"), | 67 | historyCountLabel(days, "day", "days"), | ||
M internal/ui/systemviews/shell.go +5 -4
| @@ -16,10 +16,11 @@ type kvPair struct { | |||
| 16 | 16 | // renderedPage holds the data needed by renderAppFrame to produce the shell | |
| 17 | 17 | // fragment. Route views populate this; the app frame wraps it. | |
| 18 | 18 | type renderedPage struct { | |
| 19 | - | route Route | |
| 20 | - | title string | |
| 21 | - | subtitle string | |
| 22 | - | body string | |
| 19 | + | route Route | |
| 20 | + | title string | |
| 21 | + | subtitle string | |
| 22 | + | subtitleDetail string | |
| 23 | + | body string | |
| 23 | 24 | } | |
| 24 | 25 | ||
| 25 | 26 | // renderAppFrame produces a self-contained HTML fragment (no <html>, <head>, | |
| @@ -16,10 +16,11 @@ type kvPair struct { | |||||
| 16 | // renderedPage holds the data needed by renderAppFrame to produce the shell | 16 | // renderedPage holds the data needed by renderAppFrame to produce the shell | ||
| 17 | // fragment. Route views populate this; the app frame wraps it. | 17 | // fragment. Route views populate this; the app frame wraps it. | ||
| 18 | type renderedPage struct { | 18 | type renderedPage struct { | ||
| 19 | - | route Route | 19 | + | route Route |
| 20 | - | title string | 20 | + | title string |
| 21 | - | subtitle string | 21 | + | subtitle string |
| 22 | - | body string | 22 | + | subtitleDetail string |
| 23 | + | body string | |||
| 23 | } | 24 | } | ||
| 24 | 25 | ||||
| 25 | // renderAppFrame produces a self-contained HTML fragment (no <html>, <head>, | 26 | // renderAppFrame produces a self-contained HTML fragment (no <html>, <head>, | ||