vojo/src/app/features/room/RoomViewMembersPanel.css.ts

128 lines
3.6 KiB
TypeScript

// Mobile members horseshoe — exact mirror of the 1:1 profile
// horseshoe in `RoomViewProfilePanel.css.ts`. Same silhouette
// wrapper geometry, same handle, same chatBody gap + radius
// constants — both ends of the chat read with identical visual
// language. Kept as a separate file (rather than reusing the profile
// CSS) because the two horseshoes can diverge in the future without
// rippling regressions through the other surface.
import { style } from '@vanilla-extract/css';
import { color, toRem } from 'folds';
// Re-export the two horseshoe constants from the profile panel so any
// future tweak (e.g. radius=28 trial) lives in one place.
export { HORSESHOE_GAP_PX, HORSESHOE_RADIUS_PX } from './RoomViewProfilePanel.css';
// Re-export the avatar-full-view styles from the profile panel — both
// the embedded user-profile branch (tap on member row → tap on avatar)
// and the group-hero branch (tap on group avatar) use the same
// silhouette-filling overlay treatment. Keeping the styles in one
// place ensures the two surfaces stay visually identical.
export { avatarFullView, avatarFullImage, avatarFullFallback } from './RoomViewProfilePanel.css';
export const container = style({
position: 'relative',
display: 'flex',
flex: 1,
flexDirection: 'column',
minWidth: 0,
minHeight: 0,
overflow: 'hidden',
});
export const silhouette = style({
display: 'flex',
flexDirection: 'column',
flexShrink: 0,
overflow: 'hidden',
backgroundColor: color.Background.Container,
willChange: 'border-bottom-left-radius, border-bottom-right-radius',
});
export const panelViewport = style({
position: 'relative',
width: '100%',
overflow: 'hidden',
willChange: 'height',
touchAction: 'pan-y',
userSelect: 'none',
});
// Anchor at the top so the list slides downward as the viewport grows
// — title strip + first group label become visible first. Mirrors the
// profile panel's emerge direction. `padding-top: var(--vojo-safe-top)`
// keeps the list clear of the Android status-bar icons in the open
// state.
export const panelContent = style({
position: 'absolute',
top: 0,
left: 0,
right: 0,
boxSizing: 'border-box',
paddingTop: 'var(--vojo-safe-top, 0px)',
});
export const panelInner = style({
display: 'flex',
flexDirection: 'column',
height: '100%',
});
// Wrapper around the `MembersList` so the host can switch overflow on
// when content exceeds the safety cap. Same idiom as `panelScroll` in
// the profile panel — the list owns its own scroll, but at the rail
// boundary the host still hides chrome and toggles overflow.
export const panelScroll = style({
flex: 1,
minHeight: 0,
scrollbarWidth: 'none',
selectors: {
'&::-webkit-scrollbar': {
display: 'none',
},
},
});
export const panelHandle = style({
flexShrink: 0,
height: toRem(20),
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
cursor: 'grab',
touchAction: 'none',
selectors: {
'&:active': { cursor: 'grabbing' },
},
});
export const panelHandleBar = style({
width: toRem(36),
height: toRem(4),
borderRadius: toRem(4),
backgroundColor: color.Surface.ContainerLine,
});
export const headerViewport = style({
flexShrink: 0,
overflow: 'hidden',
willChange: 'height',
userSelect: 'none',
});
export const headerViewportInner = style({
boxSizing: 'border-box',
minHeight: 0,
overflow: 'hidden',
paddingTop: 'var(--vojo-safe-top, 0px)',
backgroundColor: color.SurfaceVariant.Container,
});
export const chatBody = style({
display: 'flex',
flex: 1,
flexDirection: 'column',
minWidth: 0,
minHeight: 0,
willChange: 'margin-top, border-top-left-radius, border-top-right-radius',
});