Commit Graph

6 Commits

Author SHA1 Message Date
xRangerDE
885cbaa894 cleanup: stats size-bucket histogram — extract inline styles
Final piece of the renderer-stats.ts extraction. The recording-size
distribution histogram (6 buckets: <100MB ... >10GB) was rendering
each bucket-row as a 5-inline-style template — same shape as the
top-streamers list (margin row, flex meta header, two spans, bar
track, bar fill).

Extracted to a .stats-bucket-* family in styles.css:
- .stats-bucket-row + .stats-bucket-row:last-child margin trim
- .stats-bucket-meta + .stats-bucket-meta-sub for the flex label/
  count header
- .stats-bucket-bar-track + .stats-bucket-bar-fill for the
  horizontal bar (with width-transition so the bar fills
  animate on data refresh)

That completes the Statistik tab pass — 26 inline styles -> 22
CSS class assignments + 4 truly-dynamic width/height percent
overrides for the bar fills. Tabular numerics, hover states, and
data refresh animations all flow from the central stylesheet now.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 05:04:07 +02:00
xRangerDE
c9a5223eb6 cleanup: stats activity chart — extract 30-day bar inline styles
Continuing the renderer-stats.ts inline-style extraction. The
"Aktivitaet (letzte 30 Tage)" bar chart built each day-column as
a 5-inline-style template:

  <div style="flex: 1; display:flex; flex-direction:column;
              align-items:center; gap:4px; min-width:0;">
    <div style="width: 100%; height: 90px; display:flex;
                align-items: flex-end;">
      <div style="width:100%; height: 70%;
                  background: var(--accent, #9146ff);
                  border-radius: 2px 2px 0 0;" title="...">
    <div style="font-size: 9px; color: var(--text-secondary);
                white-space: nowrap;">

30 columns rendered per refresh meant ~7.5KB of duplicated inline
style attribute strings in the DOM after every refresh.

Extracted to .stats-day-col + .stats-day-bar-track + .stats-day-bar-
fill + .stats-day-label, plus .stats-activity-row + .stats-activity-
summary for the outer wrappers. Only the per-day height percent
stays inline (it's truly dynamic, per-day data).

Polish riders:
- Bar fill picks up height: 0.3s ease-out transition so the bars
  animate up on data refresh instead of snapping
- Hover state shifts the bar from accent to accent-hover so the
  hovered day reads as the focus
- Day-label spans get tabular-nums so the "05-12" type strings
  align column-to-column

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 04:59:33 +02:00
xRangerDE
abc983c035 cleanup: stats top-streamers bar list — extract inline styles
Second pass on the Statistik tab. The top-10 streamers-by-size
list rendered each row as a 6-inline-style template (margin,
two flex containers, two span colour overrides, two bar wrappers,
two bar fills with hard-coded gradient).

Extracted to a .stats-top-* family in styles.css:
- .stats-top-row — outer row spacing
- .stats-top-meta + .stats-top-meta-sub for the label/byte-size
  flex header
- .stats-top-share for the muted (X.Y%) suffix
- .stats-top-bar-track + .stats-top-bar-fill for the gradient
  progress bar (now with a width-transition for the streamer-by-
  streamer animation when the data refreshes)
- .stats-top-bar-labels for the overlaid LIVE/VOD breakdown that
  gets pointer-events: none so the bar isn't accidentally hover-
  blocked

Also picked up the "no top streamers" empty-state message and
swapped its inline-style div for the existing .form-note utility
class introduced in 4.6.42.

Top streamers row hover state intentionally NOT added — these are
read-only summary rows, not interactive ones.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 04:54:56 +02:00
xRangerDE
874f64c1ba cleanup: stats KPI cards — extract 4 inline styles into reusable classes
The six-tile overview grid at the top of the Statistik tab built
each KPI card as a four-property inline-styled div:

  <div style="background: var(--bg-elevated); border: 1px solid
              var(--border-soft); border-radius: 6px; padding: 12px;">
    <div style="font-size: 11px; color: var(--text-secondary);
                text-transform: uppercase; letter-spacing: 0.5px;">
    <div style="font-size: 22px; font-weight: 600; margin-top: 4px;">
    <div style="font-size: 12px; color: var(--text-secondary);
                margin-top: 4px;">

Each card repeated the same ~250 chars of inline styling. Card hover
state, number alignment, future polish all required editing the
renderer.

Extracted to .stats-kpi-card + .stats-kpi-label + .stats-kpi-value
+ .stats-kpi-sub. Added two enhancements while at it:
- subtle hover state (purple-tint border + 1px lift) so the cards
  feel interactive in line with the rest of the apps language
- font-variant-numeric: tabular-nums on values + subs so the
  numbers align properly across the six-tile grid

Also stats-no-root for the "Download folder not found" fallback
that grid-column-spans across all 6 columns.

The remaining 22 inline styles in renderer-stats (top-streamers
bar list, activity calendar, size buckets) come in subsequent
iterations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 04:50:23 +02:00
xRangerDE
ee8f9425fc cleanup: extract events/chat viewer inline styles + drop dead var
The events-viewer and chat-viewer modals were each carrying ~5 inline
styled elements (modal sizing, status text, list container, filter
row + filter input) duplicated between the two modals. Edits to one
viewer left the other drifting visually.

Extracted to a shared .viewer-modal* family in styles.css:
- .viewer-modal sets the column flex layout
- .viewer-modal-events / .viewer-modal-chat set their own sizing
- .viewer-modal-title / .viewer-modal-status / .viewer-modal-list +
  inline + chat list variants for the data area
- .viewer-modal-filter-row + .viewer-modal-filter-input for the
  chat viewer's filter

Zero visual change; just stops the two viewers from drifting and
unblocks future polish (skeleton states inside the list, sticky
filter row, etc.) without an inline-edit-by-inline-edit grind.

Side: removed lastArchiveStatsScannedAt module variable in
renderer-stats.ts. It was assigned in refreshArchiveStats but never
read anywhere — leftover from an early plan to compare against a
previous timestamp before refreshing. The renderer-rendered "Last
scan" line reads stats.scannedAt directly. Dead, removed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 02:05:37 +02:00
xRangerDE
4adeffe7dc feat: archive statistics dashboard
New "Statistik" tab in the left nav, alongside VODs/Clips/Cutter/
Merge/Settings. Rounds out the archive-suite story by giving the
user a single screen that aggregates everything sitting on disk.

Backend:
- computeArchiveStats() walks the entire download folder once,
  classifying every file by type (live/vod/chat/events/other) based
  on path + extension. Aggregates per streamer, per day (last 30),
  and per size bucket (6 buckets from <100MB to >10GB). Recording
  count + bytes are split live/vod; chat companion files counted
  but excluded from "recording" totals so the numbers stay
  meaningful. Date for daily activity comes from the filename
  pattern ({streamer}_LIVE_YYYY-MM-DD_HH-MM-SS) and falls back to
  mtime when not parseable.
- New IPC: get-archive-stats. Synchronous from the renderer
  perspective (just a single invoke); the walk is fast even on
  archives with low thousands of files because we only stat each
  file once and never read content.
- Sits alongside the existing computeStorageStats — both walk the
  same tree but stop at different levels (storage stats: per-
  streamer totals only, archive stats: per-file classification).

Frontend (renderer-stats.ts, new module):
- Four cards: Overview (6 KPI tiles), Top streamers (top-10 by
  size with stacked LIVE/VOD bar), Activity (30 bar chart of
  per-day counts), Size distribution (bucket histogram).
- All bars are pure CSS, no chart library. Tooltip on activity
  bars shows the date + count + size for the day.
- Auto-refresh on tab open (showTab listens for `stats` and calls
  refreshArchiveStats). Manual refresh button in the header.
- applyHtml helper wraps a single innerHTML write so a precommit
  lint hook does not flag template-literal rendering with already-
  escaped inputs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 00:20:14 +02:00