You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: render sparklines and status glyphs as shapes in marketing SVGs
The SVG exporter sent braille (tunnel sparklines, the snippet trend chart,
spinners) and the status / icon glyphs (● ○ ◉ ◐ ✖ ⇄ ␣) to the <text> path.
Neither Berkeley Mono nor JetBrains Mono ships those glyphs, so rsvg-convert
substituted a fallback face that advances wider than the cell grid and
ignores textLength. That bled the sparkline over the throughput readout, ran
the snippet trend line past the card border, and rendered status icons in an
off-brand fallback font.
glyph_shape now draws all of them as crisp in-cell SVG shapes (dots, circles
and stroked paths), the way box-drawing and block glyphs already are. The
imagery is font-independent for everything except real text (Berkeley Mono)
and the five symbols JetBrains Mono covers (✓ ⚠ ▲ ▸ ▾).
// Heavy multiplication X (ICON_ERROR): two diagonal strokes. Neither
685
+
// brand face ships this glyph, so draw it instead of leaking to a
686
+
// system fallback font in the rasterised imagery.
687
+
'\u{2716}' => {
688
+
let s = cw.min(ch)*0.72;
689
+
let(xl, xr) = (cx - s / 2.0, cx + s / 2.0);
690
+
let(yt, yb) = (cy - s / 2.0, cy + s / 2.0);
691
+
Some(format!(
692
+
"<path d=\"M {},{} L {},{} M {},{} L {},{}\" fill=\"none\" stroke=\"{fill}\" stroke-width=\"{}\" stroke-linecap=\"round\"{sop}/>",
693
+
coord(xl),
694
+
coord(yt),
695
+
coord(xr),
696
+
coord(yb),
697
+
coord(xr),
698
+
coord(yt),
699
+
coord(xl),
700
+
coord(yb),
701
+
coord(t *1.5),
702
+
))
703
+
}
704
+
// Left-right arrows (tunnel indicator U+21C4): top line points right,
705
+
// bottom line points left. Also absent from both brand faces.
706
+
'\u{21C4}' => {
707
+
let xl = coord(x0 + cw *0.12);
708
+
let xr = coord(x0 + cw *0.88);
709
+
let yt = coord(cy - ch *0.10);
710
+
let yb = coord(cy + ch *0.10);
711
+
let head_r = coord(x0 + cw *0.88 - cw *0.24);
712
+
let head_l = coord(x0 + cw *0.12 + cw *0.24);
713
+
let yt_up = coord(cy - ch *0.10 - ch *0.06);
714
+
let yt_dn = coord(cy - ch *0.10 + ch *0.06);
715
+
let yb_up = coord(cy + ch *0.10 - ch *0.06);
716
+
let yb_dn = coord(cy + ch *0.10 + ch *0.06);
717
+
let sw = coord(t);
718
+
Some(format!(
719
+
"<path d=\"M {xl},{yt} H {xr} M {head_r},{yt_up} L {xr},{yt} L {head_r},{yt_dn} M {xr},{yb} H {xl} M {head_l},{yb_up} L {xl},{yb} L {head_l},{yb_dn}\" fill=\"none\" stroke=\"{fill}\" stroke-width=\"{sw}\" stroke-linecap=\"round\" stroke-linejoin=\"round\"{sop}/>",
720
+
))
721
+
}
722
+
// Status circles: crisp shapes so every status dot renders identically
723
+
// and never depends on a fallback face. ● filled, ○ outline, ◉ ring +
724
+
// centre (target/fisheye), ◐ outline + filled left half (paused).
// Open box (toggle / space-key hint): a squared U on the baseline.
739
+
'\u{2423}' => {
740
+
let l = coord(x0 + cw *0.18);
741
+
let r2 = coord(x0 + cw *0.82);
742
+
let top = coord(cy - ch *0.10);
743
+
let bot = coord(cy + ch *0.16);
744
+
let sw = coord(t);
745
+
Some(format!(
746
+
"<path d=\"M {l},{top} V {bot} H {r2} V {top}\" fill=\"none\" stroke=\"{fill}\" stroke-width=\"{sw}\" stroke-linecap=\"round\" stroke-linejoin=\"round\"{sop}/>",
747
+
))
748
+
}
637
749
_ => None,
638
750
}
639
751
}
@@ -936,11 +1048,11 @@ mod tests {
936
1048
}
937
1049
938
1050
#[test]
939
-
fnstatus_glyph_stays_text(){
940
-
let svg = glyph_svg(crate::ui::design::ICON_ONLINE);// ● has no shape, renders as text
1051
+
fnsymbol_without_a_shape_stays_text(){
1052
+
let svg = glyph_svg(crate::ui::design::ICON_WARNING);// ⚠ has no shape, renders as text
941
1053
assert!(
942
-
svg.contains(">\u{25CF}</text>"),
943
-
"dot renders as text: {svg}"
1054
+
svg.contains(">\u{26A0}</text>"),
1055
+
"warning sign renders as text: {svg}"
944
1056
);
945
1057
}
946
1058
@@ -959,6 +1071,125 @@ mod tests {
959
1071
);
960
1072
}
961
1073
1074
+
#[test]
1075
+
fnbraille_renders_as_in_cell_dots_not_text(){
1076
+
let svg = glyph_svg("\u{28FF}");// ⣿ all eight dots raised
1077
+
assert_eq!(
1078
+
svg.matches("<text").count(),
1079
+
0,
1080
+
"braille renders as dot shapes, not a fallback-font glyph: {svg}"
0 commit comments