feat(ui): force every user and room avatar to render as a circle via globalStyle override on the folds Avatar wrapper
This commit is contained in:
parent
ed1544dd5e
commit
8f49124043
6 changed files with 34 additions and 11 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import { style } from '@vanilla-extract/css';
|
import { globalStyle, style } from '@vanilla-extract/css';
|
||||||
import { color } from 'folds';
|
import { color } from 'folds';
|
||||||
|
|
||||||
export const RoomAvatar = style({
|
export const RoomAvatar = style({
|
||||||
|
|
@ -12,3 +12,10 @@ export const RoomAvatar = style({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// See `UserAvatar.css.ts` for the rationale — same one-liner override forces
|
||||||
|
// every RoomAvatar (rooms, spaces, DMs, bridged puppets) into a circle without
|
||||||
|
// touching callsites.
|
||||||
|
globalStyle(`*:has(> .${RoomAvatar})`, {
|
||||||
|
borderRadius: '50% !important',
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ type RoomAvatarProps = {
|
||||||
alt?: string;
|
alt?: string;
|
||||||
renderFallback: () => ReactNode;
|
renderFallback: () => ReactNode;
|
||||||
};
|
};
|
||||||
|
// Always renders as a circle: a globalStyle in `RoomAvatar.css.ts` forces the
|
||||||
|
// parent folds `<Avatar>` to `border-radius: 50%`, so the `radii` prop on the
|
||||||
|
// outer `<Avatar>` is intentionally inert at every callsite.
|
||||||
export function RoomAvatar({ roomId, src, alt, renderFallback }: RoomAvatarProps) {
|
export function RoomAvatar({ roomId, src, alt, renderFallback }: RoomAvatarProps) {
|
||||||
const [error, setError] = useState(false);
|
const [error, setError] = useState(false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { style } from '@vanilla-extract/css';
|
import { globalStyle, style } from '@vanilla-extract/css';
|
||||||
import { color } from 'folds';
|
import { color } from 'folds';
|
||||||
|
|
||||||
export const UserAvatar = style({
|
export const UserAvatar = style({
|
||||||
|
|
@ -12,3 +12,14 @@ export const UserAvatar = style({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Force every UserAvatar to render as a circle. Folds `<Avatar>` controls the
|
||||||
|
// outer shape via its `radii` variant; the inner `AvatarImage`/`AvatarFallback`
|
||||||
|
// inherit `border-radius` from it. By overriding the parent's radius we round
|
||||||
|
// every user avatar without touching the ~30 callsites or losing the radii
|
||||||
|
// system for non-avatar uses of folds `<Avatar>` (icon tabs, emoji-pack tiles).
|
||||||
|
// `!important` is necessary because folds' recipe rule has the same specificity
|
||||||
|
// and source-order would otherwise be a coin flip.
|
||||||
|
globalStyle(`*:has(> .${UserAvatar})`, {
|
||||||
|
borderRadius: '50% !important',
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ type UserAvatarProps = {
|
||||||
alt?: string;
|
alt?: string;
|
||||||
renderFallback: () => ReactNode;
|
renderFallback: () => ReactNode;
|
||||||
};
|
};
|
||||||
|
// Always renders as a circle: a globalStyle in `UserAvatar.css.ts` forces the
|
||||||
|
// parent folds `<Avatar>` to `border-radius: 50%`, so the `radii` prop on the
|
||||||
|
// outer `<Avatar>` is intentionally inert at every callsite.
|
||||||
export function UserAvatar({ className, userId, src, alt, renderFallback }: UserAvatarProps) {
|
export function UserAvatar({ className, userId, src, alt, renderFallback }: UserAvatarProps) {
|
||||||
const [error, setError] = useState(false);
|
const [error, setError] = useState(false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ export function BotCard({ preset, selected }: BotCardProps) {
|
||||||
padding: `${toRem(6)} 0`,
|
padding: `${toRem(6)} 0`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Avatar size="300" radii="400" style={{ background: AVATAR_BG, color: '#0c0c0e' }}>
|
<Avatar size="300" radii="Pill" style={{ background: AVATAR_BG, color: '#0c0c0e' }}>
|
||||||
{avatarUrl ? (
|
{avatarUrl ? (
|
||||||
<AvatarImage src={avatarUrl} alt={preset.name} />
|
<AvatarImage src={avatarUrl} alt={preset.name} />
|
||||||
) : (
|
) : (
|
||||||
|
|
|
||||||
|
|
@ -97,18 +97,18 @@ export const HeroBack = style([
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 56×56 square avatar with 14px radius, fleet violet (DAWN.fleet) bg.
|
// 56×56 circular avatar, fleet violet (DAWN.fleet) bg. Fleet color is
|
||||||
// Fleet color is hardcoded here because it's the canonical bot accent in
|
// hardcoded here because it's the canonical bot accent in the mockup and we
|
||||||
// the mockup and we don't want it varying with Folds palette swaps. The
|
// don't want it varying with Folds palette swaps. The violet disk shows when
|
||||||
// violet square shows when the bot's Matrix profile has no `avatar_url`
|
// the bot's Matrix profile has no `avatar_url` (fallback to the initial
|
||||||
// (fallback to the initial letter); when it does, the inner <img> covers
|
// letter); when it does, the inner <img> covers the violet — `overflow:
|
||||||
// the violet — `overflow: hidden` keeps it inside the rounded corners.
|
// hidden` keeps it inside the round mask.
|
||||||
export const HeroAvatar = style([
|
export const HeroAvatar = style([
|
||||||
DefaultReset,
|
DefaultReset,
|
||||||
{
|
{
|
||||||
width: toRem(56),
|
width: toRem(56),
|
||||||
height: toRem(56),
|
height: toRem(56),
|
||||||
borderRadius: toRem(14),
|
borderRadius: '50%',
|
||||||
backgroundColor: '#9580ff',
|
backgroundColor: '#9580ff',
|
||||||
color: '#0c0c0e',
|
color: '#0c0c0e',
|
||||||
fontSize: toRem(24),
|
fontSize: toRem(24),
|
||||||
|
|
@ -123,7 +123,6 @@ export const HeroAvatar = style([
|
||||||
'(max-width: 600px)': {
|
'(max-width: 600px)': {
|
||||||
width: toRem(36),
|
width: toRem(36),
|
||||||
height: toRem(36),
|
height: toRem(36),
|
||||||
borderRadius: toRem(8),
|
|
||||||
fontSize: toRem(16),
|
fontSize: toRem(16),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue