Skip to main content

max / makenotwork

Give the progress and chart bars one vocabulary and one fill property The nine remaining inline styles set a CSS property in the template because the percentage is per-render data. Only the value has to be inline, so they now pass --fill and the property that reads it lives in the stylesheet. Doing that surfaced four class families for one concept. .storage-track and .storage-fill were .progress-bar-container and .progress-bar under different names, identical but for a redundant width:100% and a transition of 0.3s against 0.2s; deleted. .synckit-gauge-fill had no base rule at all, only --warn and --danger modifiers riding on .progress-bar, so they become .progress-bar--warn and --danger. .chart-bar and .analytics-revenue-bar are genuinely different shapes and stay. The creator tab restated gauge_tier's 90% danger cutoff in its own template condition. It now reads gauge_tier, so the thresholds have one home. The item, project and user analytics tabs held three byte-identical copies of the bar chart. One partial now, included by all three, which is also why nine inline styles became seven. 1910 lib tests pass, clippy clean.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-02 20:36 UTC
Signed with PGP, not checked
Commit: c87492d3290bc1e65a16c30e386f67186b6c9605
Parent: 82fd934
12 files changed, +38 insertions, -51 deletions
@@ -4764,6 +4764,7 @@
4764 4764
4765 4765 .chart-bar {
4766 4766 width: 100%;
4767 + height: var(--fill, 0%);
4767 4768 background: var(--primary-dark);
4768 4769 min-height: 2px;
4769 4770 transition: opacity 0.15s;
@@ -5491,13 +5492,17 @@
5491 5492 .progress-bar-container--slim { height: 6px; }
5492 5493 .progress-bar-container--rounded { border-radius: 3px; }
5493 5494
5495 + /* Fill proportion comes from the template as --fill, because it is
5496 + per-render data. The property that reads it lives here. */
5494 5497 .progress-bar {
5495 - width: 0%;
5498 + width: var(--fill, 0%);
5496 5499 height: 100%;
5497 5500 background: var(--success);
5498 5501 transition: width 0.2s ease;
5499 5502 }
5500 5503 .progress-bar--highlight { background: var(--action); }
5504 + .progress-bar--warn { background: var(--warning); }
5505 + .progress-bar--danger { background: var(--danger); }
5501 5506
5502 5507 /* Upload status block (filename + percent label + progress bar). One of these
5503 5508 in the codebase. Used by wizard upload flows and standalone audio/video upload partials. */
@@ -8302,18 +8307,6 @@
8302 8307 margin-bottom: var(--gap-peer);
8303 8308 font-size: 0.9rem;
8304 8309 }
8305 - .storage-track {
8306 - background: var(--border);
8307 - height: 8px;
8308 - width: 100%;
8309 - overflow: hidden;
8310 - }
8311 - .storage-fill {
8312 - background: var(--action);
8313 - height: 100%;
8314 - transition: width 0.3s;
8315 - }
8316 - .storage-fill--full { background: var(--danger); }
8317 8310 .storage-breakdown {
8318 8311 display: grid;
8319 8312 grid-template-columns: 1fr 1fr;
@@ -10053,6 +10046,7 @@
10053 10046 gap: var(--gap-peer);
10054 10047 }
10055 10048 .analytics-revenue-bar {
10049 + width: var(--fill, 0%);
10056 10050 height: 10px;
10057 10051 min-width: 2px;
10058 10052 max-width: 80px;
@@ -11249,8 +11243,6 @@
11249 11243 font-size: 0.8125rem;
11250 11244 }
11251 11245 .synckit-gauge-value { color: var(--content-muted); }
11252 - .synckit-gauge-fill--warn { background: var(--warning); }
11253 - .synckit-gauge-fill--danger { background: var(--danger); }
11254 11246
11255 11247 /* ============================================================================
11256 11248 Carousel: composable click-through widget (partials/carousel.html).
@@ -353,6 +353,10 @@
353 353 pub storage_max: String,
354 354 /// Storage usage percentage (0-100) for the progress bar.
355 355 pub storage_pct: u8,
356 + /// Gauge severity for that bar, from `gauge_tier`: "warn", "danger" or "".
357 + /// Read from the same function the SyncKit gauges use so the thresholds
358 + /// live in one place.
359 + pub storage_tier: &'static str,
356 360 /// Whether the founder pricing window is currently open. Used to badge
357 361 /// in-progress founders ("Founder pricing, locked in when the window
358 362 /// closes") before the close sweep stamps `founder_locked_at`.
@@ -596,7 +596,7 @@
596 596 /// Map a gauge percentage to its color tier, matching the warning thresholds
597 597 /// the scheduler uses to send usage emails. Tiers are then emitted as CSS
598 598 /// classes on the gauge fill div.
599 - fn gauge_tier(pct: i32) -> &'static str {
599 + pub fn gauge_tier(pct: i32) -> &'static str {
600 600 if pct >= 90 {
601 601 "danger"
602 602 } else if pct >= 75 {
@@ -19,7 +19,7 @@
19 19 pub use blog::*;
20 20 pub use content::*;
21 21 pub use conversions::{
22 - apply_top_keys, build_top_keys_map, discover_items_view, discover_projects_view,
22 + apply_top_keys, build_top_keys_map, discover_items_view, discover_projects_view, gauge_tier,
23 23 };
24 24 pub use dashboard::*;
25 25 pub use discover::*;
@@ -36,13 +36,6 @@
36 36 {% if bars.is_empty() %}
37 37 {% call ui::empty_state_chart("No revenue data yet. Sales will appear here once fans purchase this item.") %}{% endcall %}
38 38 {% else %}
39 - <div class="chart-bars">
40 - {% for bar in bars %}
41 - <div class="chart-bar-col" data-tooltip="{{ bar.value }} / {{ bar.count }} sale{% if bar.count != 1 %}s{% endif %}">
42 - <div class="chart-bar" style="height: {{ bar.height_pct }}%;"></div>
43 - <div class="chart-bar-label">{{ bar.label }}</div>
44 - </div>
45 - {% endfor %}
46 - </div>
39 + {% include "partials/chart_bars.html" %}
47 40 {% endif %}
48 41 </div>
@@ -9,7 +9,7 @@
9 9 class="btn-tiny">Hide for now</button>
10 10 </div>
11 11 <div class="progress-bar-container progress-bar-container--slim mb-section">
12 - <div class="progress-bar progress-bar--highlight" style="width: {{ checklist.progress_pct }}%;"></div>
12 + <div class="progress-bar progress-bar--highlight" style="--fill: {{ checklist.progress_pct }}%;"></div>
13 13 </div>
14 14 {% for step in checklist.steps %}
15 15 <div class="checklist-row">
@@ -117,8 +117,8 @@
117 117 <span class="synckit-gauge-value">{{ b.storage_display }}</span>
118 118 </div>
119 119 <div class="progress-bar-container progress-bar-container--slim progress-bar-container--rounded">
120 - <div class="progress-bar synckit-gauge-fill{% if !b.storage_tier.is_empty() %} synckit-gauge-fill--{{ b.storage_tier }}{% endif %}"
121 - style="width: {{ b.storage_pct }}%"></div>
120 + <div class="progress-bar progress-bar--highlight{% if !b.storage_tier.is_empty() %} progress-bar--{{ b.storage_tier }}{% endif %}"
121 + style="--fill: {{ b.storage_pct }}%"></div>
122 122 </div>
123 123 </div>
124 124
@@ -134,8 +134,8 @@
134 134 <span class="synckit-gauge-value">{{ b.keys_claimed }}{% if let Some(c) = b.key_cap %} / {{ c }}{% endif %}</span>
135 135 </div>
136 136 <div class="progress-bar-container progress-bar-container--slim progress-bar-container--rounded">
137 - <div class="progress-bar synckit-gauge-fill{% if !b.keys_tier.is_empty() %} synckit-gauge-fill--{{ b.keys_tier }}{% endif %}"
138 - style="width: {{ b.keys_pct }}%"></div>
137 + <div class="progress-bar progress-bar--highlight{% if !b.keys_tier.is_empty() %} progress-bar--{{ b.keys_tier }}{% endif %}"
138 + style="--fill: {{ b.keys_pct }}%"></div>
139 139 </div>
140 140 </div>
141 141
@@ -152,8 +152,8 @@
152 152 <span class="synckit-gauge-value">{{ k.display }}</span>
153 153 </div>
154 154 <div class="progress-bar-container progress-bar-container--slim progress-bar-container--rounded">
155 - <div class="progress-bar synckit-gauge-fill{% if !k.tier.is_empty() %} synckit-gauge-fill--{{ k.tier }}{% endif %}"
156 - style="width: {{ k.pct }}%"></div>
155 + <div class="progress-bar progress-bar--highlight{% if !k.tier.is_empty() %} progress-bar--{{ k.tier }}{% endif %}"
156 + style="--fill: {{ k.pct }}%"></div>
157 157 </div>
158 158 </div>
159 159 {% endfor %}
@@ -42,14 +42,7 @@
42 42 {% if bars.is_empty() %}
43 43 {% call ui::empty_state_chart("No revenue data yet. Revenue will appear here after your first sale. Publish an item and share it to get started.") %}{% endcall %}
44 44 {% else %}
45 - <div class="chart-bars">
46 - {% for bar in bars %}
47 - <div class="chart-bar-col" data-tooltip="{{ bar.value }} / {{ bar.count }} sale{% if bar.count != 1 %}s{% endif %}">
48 - <div class="chart-bar" style="height: {{ bar.height_pct }}%;"></div>
49 - <div class="chart-bar-label">{{ bar.label }}</div>
50 - </div>
51 - {% endfor %}
52 - </div>
45 + {% include "partials/chart_bars.html" %}
53 46 {% endif %}
54 47 </div>
55 48
@@ -42,14 +42,7 @@
42 42 {% if bars.is_empty() %}
43 43 {% call ui::empty_state_chart("Once you publish items and make sales, revenue data will appear here.") %}{% endcall %}
44 44 {% else %}
45 - <div class="chart-bars">
46 - {% for bar in bars %}
47 - <div class="chart-bar-col" data-tooltip="{{ bar.value }} / {{ bar.count }} sale{% if bar.count != 1 %}s{% endif %}">
48 - <div class="chart-bar" style="height: {{ bar.height_pct }}%;"></div>
49 - <div class="chart-bar-label">{{ bar.label }}</div>
50 - </div>
51 - {% endfor %}
52 - </div>
45 + {% include "partials/chart_bars.html" %}
53 46 {% endif %}
54 47 </div>
55 48
@@ -73,7 +66,7 @@
73 66 <td>{{ p.title }}</td>
74 67 <td>
75 68 <div class="analytics-revenue-cell">
76 - <div class="analytics-revenue-bar" style="width: {{ p.revenue_pct }}%;"></div>
69 + <div class="analytics-revenue-bar" style="--fill: {{ p.revenue_pct }}%;"></div>
77 70 {{ p.revenue }}
78 71 </div>
79 72 </td>