web: give Avatar a named size scale
Avatar used to take a tailwind class for its size, and a separate `tiny` flag
that picked which image size to download. Nothing kept those two in agreement,
and they drifted apart: comment avatars draw at 32px but downloaded a 32px
image, so they looked blurry on retina screens, while the small 16px avatars in
settings downloaded a full-size one.
Now there's one prop. Pick mini, small, regular or large — the names the design
system already uses — and Avatar works out the image size itself, always asking
for twice what it draws so it stays sharp. `full` is for the cases where the
surrounding layout sets the size instead; it fills whatever box you put it in
and uses the original image.
The sizes go through tv() so you can still pass your own size class and have it
win. Two size classes in one string is a coin flip otherwise, because tailwind
decides by where the rules land in the stylesheet, not the order you wrote them.
A few avatars shift slightly to land on the scale: comments 32 to 26, settings
lists 16 to 17, access and last commit 20 to 21, repo header and commit rows 24
to 26.
Signed-off-by: eti <eti@eti.tf>
web: give Avatar a named size scale
Avatar used to take a tailwind class for its size, and a separate `tiny` flag
that picked which image size to download. Nothing kept those two in agreement,
and they drifted apart: comment avatars draw at 32px but downloaded a 32px
image, so they looked blurry on retina screens, while the small 16px avatars in
settings downloaded a full-size one.
Now there's one prop. Pick mini, small, regular or large — the names the design
system already uses — and Avatar works out the image size itself, always asking
for twice what it draws so it stays sharp. `full` is for the cases where the
surrounding layout sets the size instead; it fills whatever box you put it in
and uses the original image.
The sizes go through tv() so you can still pass your own size class and have it
win. Two size classes in one string is a coin flip otherwise, because tailwind
decides by where the rules land in the stylesheet, not the order you wrote them.
A few avatars shift slightly to land on the scale: comments 32 to 26, settings
lists 16 to 17, access and last commit 20 to 21, repo header and commit rows 24
to 26.
Signed-off-by: eti <eti@eti.tf>
web/components: make the button group match the figma segmented control
a joined group is a tab switcher, but the selected segment was the plain default
variant, which reads as the hovered state of an unselected one, and the group
itself drew nothing.
per figma (design system 605:3859): the group owns the outer border and a
recessed background-subtle surface, the selected segment is default + its inset
shadow so it reads as a raised card, and unselected segments are ghost with the
default foreground rather than ghost's muted one. each segment's own border is
pulled onto the group's (-m-px) so the selected segment's edge doubles as the
divider and unselected segments show no divider at all.
segmentProps() carries the recipe so the call sites stop repeating the variant
ternary. verified pixel for pixel against the figma render: 36px tall, #e5e7eb
border on all four edges, #ffffff on the selected segment against #f9fafb on the
unselected, a 1px divider at the selected segment's edge, and the inset shadow
two rows above the bottom border.
ghost's own foreground is still muted where it's used outside a group, which
figma disagrees with; that's a wider change, left alone here.
Signed-off-by: eti <eti@eti.tf>
web: move the type scale onto typography-* utilities
the scale lived in @theme as --text-heading-*, --text-paragraph-* and
--text-monospace-*, so it generated text-heading-3, text-paragraph-small and so
on. tailwind-merge classes anything shaped like that as a colour, so inside a
tv() whose variants set text colours it dropped the size as soon as a colour
followed — which, in those definitions, is always. $lib/tv.ts existed only to
re-register the twelve names as font sizes, and every tv() in the app had to
import from there rather than from tailwind-variants to pick that up.
naming them typography-* sidesteps the collision instead of patching it: the
classes match no tailwind-merge group at all, so nothing can read them as
colours and the shim is gone. they're @utility blocks rather than theme tokens
now, since --text-* is precisely the namespace that spells its utilities text-*.
font-size comes first in each block on purpose. tailwind sorts a custom utility
into the bucket of its first declared property, which keeps typography-* ahead
of every font-weight, leading-* and tracking-* utility in the sheet, so the call
sites pairing typography-heading-4 with leading-8 font-normal still resolve the
way they did.
this does give up size-against-size merging: two typography-* classes in one
string no longer collapse, so a size passed in through class= sits next to the
component's own and the stylesheet order picks the winner. nothing does that
today — Typography takes a variant prop for it — and one classGroups entry
brings the merging back if it ever comes up.
Signed-off-by: eti <eti@eti.tf>
web: move the type scale onto typography-* utilities
the scale lived in @theme as --text-heading-*, --text-paragraph-* and
--text-monospace-*, so it generated text-heading-3, text-paragraph-small and so
on. tailwind-merge classes anything shaped like that as a colour, so inside a
tv() whose variants set text colours it dropped the size as soon as a colour
followed — which, in those definitions, is always. $lib/tv.ts existed only to
re-register the twelve names as font sizes, and every tv() in the app had to
import from there rather than from tailwind-variants to pick that up.
naming them typography-* sidesteps the collision instead of patching it: the
classes match no tailwind-merge group at all, so nothing can read them as
colours and the shim is gone. they're @utility blocks rather than theme tokens
now, since --text-* is precisely the namespace that spells its utilities text-*.
font-size comes first in each block on purpose. tailwind sorts a custom utility
into the bucket of its first declared property, which keeps typography-* ahead
of every font-weight, leading-* and tracking-* utility in the sheet, so the call
sites pairing typography-heading-4 with leading-8 font-normal still resolve the
way they did.
this does give up size-against-size merging: two typography-* classes in one
string no longer collapse, so a size passed in through class= sits next to the
component's own and the stylesheet order picks the winner. nothing does that
today — Typography takes a variant prop for it — and one classGroups entry
brings the merging back if it ever comes up.
Signed-off-by: eti <eti@eti.tf>
web: move the type scale onto typography-* utilities
the scale lived in @theme as --text-heading-*, --text-paragraph-* and
--text-monospace-*, so it generated text-heading-3, text-paragraph-small and so
on. tailwind-merge classes anything shaped like that as a colour, so inside a
tv() whose variants set text colours it dropped the size as soon as a colour
followed — which, in those definitions, is always. $lib/tv.ts existed only to
re-register the twelve names as font sizes, and every tv() in the app had to
import from there rather than from tailwind-variants to pick that up.
naming them typography-* sidesteps the collision instead of patching it: the
classes match no tailwind-merge group at all, so nothing can read them as
colours and the shim is gone. they're @utility blocks rather than theme tokens
now, since --text-* is precisely the namespace that spells its utilities text-*.
font-size comes first in each block on purpose. tailwind sorts a custom utility
into the bucket of its first declared property, which keeps typography-* ahead
of every font-weight, leading-* and tracking-* utility in the sheet, so the call
sites pairing typography-heading-4 with leading-8 font-normal still resolve the
way they did.
this does give up size-against-size merging: two typography-* classes in one
string no longer collapse, so a size passed in through class= sits next to the
component's own and the stylesheet order picks the winner. nothing does that
today — Typography takes a variant prop for it — and one classGroups entry
brings the merging back if it ever comes up.
Signed-off-by: eti <eti@eti.tf>
web: give Avatar a named size scale
Avatar used to take a tailwind class for its size, and a separate `tiny` flag
that picked which image size to download. Nothing kept those two in agreement,
and they drifted apart: comment avatars draw at 32px but downloaded a 32px
image, so they looked blurry on retina screens, while the small 16px avatars in
settings downloaded a full-size one.
Now there's one prop. Pick mini, small, regular or large — the names the design
system already uses — and Avatar works out the image size itself, always asking
for twice what it draws so it stays sharp. `full` is for the cases where the
surrounding layout sets the size instead; it fills whatever box you put it in
and uses the original image.
The sizes go through tv() so you can still pass your own size class and have it
win. Two size classes in one string is a coin flip otherwise, because tailwind
decides by where the rules land in the stylesheet, not the order you wrote them.
A few avatars shift slightly to land on the scale: comments 32 to 26, settings
lists 16 to 17, access and last commit 20 to 21, repo header and commit rows 24
to 26.
Signed-off-by: eti <eti@eti.tf>