The house meter is GradeMeter
(js/src/components/commonComponent/seoTools/GradeMeter.jsx). It draws six
bands: F, D, C, B, A, A+, with the current band highlighted.
Six, not five, and that is the whole point of it existing. The scale gained an F, and the meter that preceded it did not. A meter that disagrees with the grade chip beside it is the bug this replaces.
Use it for anything on the 0-100 score scale. It is already in the dashboard, the channel audit, the title workshop, the SEO workshop, and the extension.
ProgressIconic (js/src/components/svgcomponents/ProgressIconic.jsx) is the
one being retired. It draws five frames on 20-point bands (0-20, 20-40 and
so on), with a sparkle at 71 and a particle burst at 86.
Because the two disagree about how many bands the scale has, any screen showing both is showing the same score on two scales. That is not a subtle mismatch: a score can sit in the fourth of five frames and the fourth of six bands and mean different things.
Still on it, and not yet reviewed: the video report top section. That is TS-5173.
SeoBlock takes a meter prop. It is opt-in rather than a straight swap so
that consumers get converted deliberately rather than silently restyled.
<SeoBlock meter progressScore={score} />A score we do not have is not a score of zero. GradeMeter renders null as
no band current, not as an F, because stamping an F on something we simply
have not measured is a different claim entirely.
Two consequences worth knowing:
score || default defeats this. A genuine score of 0 is falsy, so it falls
through to the placeholder and the distinction is lost. This pattern is still
present in the SEO workshop sidebar and is worth fixing wherever it appears.
Whether an empty meter belongs is a judgement call. The channel audit
passes progressScore={null} with meter, so an unmeasured category shows
an empty meter and says so, because there absence is a result. The SEO
workshop’s Title Keyword and Learning Skills cards pass null without
meter, because they are list cards showing keywords with their own score
tags, not categories left unmeasured. Same prop, opposite intent. Ask whether
absence is itself information before deciding.
getScoreGrade(score, context) takes "title" or "channel". This is easy to
get wrong in both directions, so:
getScoreGrade defaults to "title".GradeMeter defaults to "channel".SeoBlock forwards no context at all.None of that affects the band. Context swaps only the blurb wording, so the copy reads correctly for a title or for a channel. The thresholds are shared. A block and the sidebar beside it will always agree on the letter even if they disagree on the context.
Bands take the --ts-score-* tokens. Do not reach for the colours
getScoreGrade returns: that scale is the older generation (#96DC46,
#5AB43C, #FAC833) and does not carry on a white page, let alone on glass.
The helper owns the boundaries, the design tokens own the palette.