From 19c2bbd35fbc5322b3671f4cd7dd98f4ae020d3b Mon Sep 17 00:00:00 2001 From: Void Date: Mon, 9 Nov 2026 14:52:56 +0000 Subject: [PATCH] Room list wash and name line: undo the solid slabs and the boxed pill Room list: rows and section labels carried 62% of the surface colour and hid the terrain. They are a faint wash again (labels 12%, rows 16%); hover, selected and pressed stay three distinct steps (26, 36, 48%). The Commons room icon stays. Chat (phone, pose bubbles): the name and time chip was a boxed pill straddling the bubble edge, growing upward when the name wrapped. It is now one plain line in flow above the bubble, on the side opposite the portrait, with no box. Only a name longer than the room beside the portrait wraps, and the time then drops under it on the same edge. Full names are kept. Co-Authored-By: Claude Sonnet 5.5 --- .../components/message/layout/layout.css.ts | 51 +++++++++---------- src/app/components/nav/styles.css.ts | 26 ++++++---- 2 files changed, 40 insertions(+), 37 deletions(-) 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, -- 2.47.3