main
tag: launch-2026-06-01
tag: magicmirror-v0.1.1
tag: magicmirror-v0.3.0
tag: mnw-cli-v0.1.2
tag: mnw-cli-v0.1.3
tag: mnw-cli-v0.1.4
tag: pom-v0.4.1
tag: pom-v0.4.2
tag: pom-v0.4.3
tag: pom-v0.4.4
tag: pom-v0.4.5
tag: wam-v0.3.0
tag: wam-v0.3.1
Files
Commits
Tags
Notes
Issues
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>
12 files changed,
+38 insertions,
-51 deletions
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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>