diff --git a/src/app/components/message/layout/layout.css.ts b/src/app/components/message/layout/layout.css.ts index 731fa0f5..815c579f 100644 --- a/src/app/components/message/layout/layout.css.ts +++ b/src/app/components/message/layout/layout.css.ts @@ -198,25 +198,19 @@ export const BubbleHeaderOwn = style({ alignSelf: 'flex-end', }); -// Phone: the name is a pill straddling the bubble's top edge, on the side opposite the portrait. +// Phone: name and time are one plain line in flow above the bubble, on the side opposite the +// portrait. It is as wide as the full name needs, up to the room beside the portrait; only a name +// longer than that wraps (and then the time drops below it). It is capped by the viewport, not by +// the column: a short bubble's column is narrower than its own name, and a percentage cap there +// truncated names to one letter. export const BubbleHeaderPose = style({ '@media': { [PHONE]: { - position: 'absolute', - zIndex: 2, - // Anchored by its bottom edge, 13px inside the bubble: a name that wraps grows upward, out of - // the bubble, instead of down over the first line of text. - bottom: `calc(100% - ${toRem(13)})`, - right: toRem(14), - padding: `0 ${toRem(13)}`, - background: color.Secondary.Container, - border: `1px solid ${color.Secondary.ContainerLine}`, - // The pill is as wide as the full name needs, up to the room beside the portrait, then the - // name wraps. It is capped by the viewport, not by the column: a short bubble's column is - // narrower than its own name, and a percentage cap there truncated names to one letter. + alignSelf: 'flex-end', + margin: `0 ${toRem(14)} ${toRem(2)}`, width: 'max-content', maxWidth: `calc(100vw - ${PHONE_PORTRAIT} - ${toRem(64)})`, - borderRadius: toRem(14), + textAlign: 'right', }, }, }); @@ -224,8 +218,8 @@ export const BubbleHeaderPose = style({ export const BubbleHeaderPoseAlt = style({ '@media': { [PHONE]: { - right: 'auto', - left: toRem(14), + alignSelf: 'flex-start', + textAlign: 'left', }, }, }); @@ -398,9 +392,8 @@ globalStyle(`${BubbleContentPose} > div`, { }, }); -// The name inside the pill wraps instead of ellipsising: the pill already caps its own width, and -// Username's own nowrap + ellipsis, and the truncate on the Text inside it, clipped long names to -// "Heimdall o…" inside it. +// The name wraps instead of ellipsising: the header already caps its own width, and Username's own +// nowrap + ellipsis, and the truncate on the Text inside it, clipped long names to "Heimdall o…". globalStyle(`${BubbleHeaderPose} ${Username}, ${BubbleHeaderPose} ${Username} *`, { '@media': { [PHONE]: { @@ -413,11 +406,21 @@ globalStyle(`${BubbleHeaderPose} ${Username}, ${BubbleHeaderPose} ${Username} *` }); // A name too long for one line takes its own lines and the time drops below it, instead of the -// name shrinking to a sliver beside the time (the pill's one child is the flex row of both). +// name shrinking to a sliver beside the time (the header's one child is the flex row of both). The +// row hugs the side the header sits on, so a dropped time stays under the name's edge. globalStyle(`${BubbleHeaderPose} > div`, { '@media': { [PHONE]: { flexWrap: 'wrap', + justifyContent: 'flex-end', + }, + }, +}); + +globalStyle(`${BubbleHeaderPoseAlt} > div`, { + '@media': { + [PHONE]: { + justifyContent: 'flex-start', }, }, }); @@ -446,14 +449,6 @@ globalStyle(`${scene} ${BubbleContent}`, { globalStyle(`${scene} ${BubbleContentOwn}`, { backgroundColor: [color.Primary.Container, half(color.Primary.Container)], }); -globalStyle(`${scene} ${BubbleHeaderPose}`, { - '@media': { - [PHONE]: { - backgroundColor: [color.Secondary.Container, half(color.Secondary.Container)], - backdropFilter: 'blur(12px)', - }, - }, -}); globalStyle(`${scene} ${BubbleLeftArrow}`, { display: 'none', }); diff --git a/src/app/components/nav/styles.css.ts b/src/app/components/nav/styles.css.ts index 927fee0f..b123f9bc 100644 --- a/src/app/components/nav/styles.css.ts +++ b/src/app/components/nav/styles.css.ts @@ -3,6 +3,14 @@ import { RecipeVariants, recipe } from '@vanilla-extract/recipes'; import { ContainerColor, DefaultReset, Disabled, RadiiVariant, color, config, toRem } from 'folds'; import { surfaceInk } from '../../features/scene/sceneShell.css'; +// Wash strengths over the scene: rows and labels are faint, and hover, selected and pressed rows +// are three distinct steps above them. +const SCRIM_LABEL = '12%'; +const SCRIM_ROW = '16%'; +const SCRIM_HOVER = '26%'; +const SCRIM_SELECTED = '36%'; +const SCRIM_PRESSED = '48%'; + export const NavCategory = style([ DefaultReset, { @@ -13,9 +21,9 @@ export const NavCategory = style([ export const NavCategoryHeader = style({ gap: config.space.S100, selectors: { - // Category labels sit on the scene like the rows do, and need the same scrim to be read. + // Category labels sit on the scene like the rows do, and need a wash to be read. ':root[data-scene] &': { - backgroundColor: `color-mix(in srgb, ${surfaceInk} 62%, transparent)`, + backgroundColor: `color-mix(in srgb, ${surfaceInk} ${SCRIM_LABEL}, transparent)`, borderRadius: config.radii.R400, }, }, @@ -69,21 +77,21 @@ const NavItemBase = style({ '&[data-hover=true]': { backgroundColor: ContainerHover, }, - // While the background scene runs the shell is clear (sceneShell.css.ts); a row is a steady - // scrim of the theme's own surface, so ridges never show through its text. Hover, the selected row and a - // press each strengthen it a step. + // While the background scene runs the shell is clear (sceneShell.css.ts); a row is a faint + // wash of the theme's own surface: the terrain stays visible, the text stays readable. Hover, + // the selected row and a press each strengthen it a step. ':root[data-scene] &': { - backgroundColor: `color-mix(in srgb, ${surfaceInk} 62%, transparent)`, + backgroundColor: `color-mix(in srgb, ${surfaceInk} ${SCRIM_ROW}, transparent)`, }, ':root[data-scene] &:hover, :root[data-scene] &:focus-visible, :root[data-scene] &[data-hover=true]': { - backgroundColor: `color-mix(in srgb, ${surfaceInk} 74%, transparent)`, + backgroundColor: `color-mix(in srgb, ${surfaceInk} ${SCRIM_HOVER}, transparent)`, }, ':root[data-scene] &[aria-selected=true]': { - backgroundColor: `color-mix(in srgb, ${surfaceInk} 84%, transparent)`, + backgroundColor: `color-mix(in srgb, ${surfaceInk} ${SCRIM_SELECTED}, transparent)`, }, [`:root[data-scene] &:has(.${NavLink}:active)`]: { - backgroundColor: `color-mix(in srgb, ${surfaceInk} 92%, transparent)`, + backgroundColor: `color-mix(in srgb, ${surfaceInk} ${SCRIM_PRESSED}, transparent)`, }, [`&:has(.${NavLink}:active)`]: { backgroundColor: ContainerActive,