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

110 lines
3.4 KiB
TypeScript

import { style } from '@vanilla-extract/css';
import { color, toRem } from 'folds';
import { VOJO_HORSESHOE_RADIUS_PX } from '../../styles/horseshoe';
// Outer container — anchor for the two absolutely-positioned panes
// (`appBody` and `silhouette`). Same shape as the settings-sheet
// container, see that file for the full rationale.
export const container = style({
position: 'relative',
display: 'flex',
flex: 1,
flexDirection: 'column',
minWidth: 0,
minHeight: 0,
overflow: 'hidden',
});
// Holds the wrapped chat column. Stays put — clip-path carves the
// bottom edge so virtualized timeline rows aren't re-measured
// mid-gesture. `backgroundColor` opaque so the void colour painted
// on the container doesn't bleed through any transparent slivers
// in the wrapped tree (e.g. between bubble rows).
export const appBody = style({
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
display: 'flex',
flexDirection: 'column',
minWidth: 0,
minHeight: 0,
backgroundColor: color.Background.Container,
willChange: 'clip-path',
});
// The viewer sheet's surface. `Background.Container` (deepest Dawn
// tone) so the image floats on a near-black backdrop — closest to
// the legacy `<Overlay>` viewer's full-screen dark scrim. Rounded
// top corners (same radius as the tab curtains) with `overflow:
// hidden` clip the header / image to the curve; the carved corners
// expose the app's dark background behind, so the rounding reads
// without re-introducing a black void gap.
export const silhouette = style({
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
backgroundColor: color.Background.Container,
borderTopLeftRadius: toRem(VOJO_HORSESHOE_RADIUS_PX),
borderTopRightRadius: toRem(VOJO_HORSESHOE_RADIUS_PX),
willChange: 'height',
});
// Top-anchored — handle + viewer body reveal top-down as silhouette
// grows. Android nav-bar clearance is owned by `MainActivity.java`'s
// WindowInsets listener (the WebView is already sized above the nav
// bar), so no `padding-bottom: env(...)` here — that would stack on
// top of the native padding and lift the download / share row above
// its visible host.
export const panelContent = style({
position: 'absolute',
top: 0,
left: 0,
right: 0,
boxSizing: 'border-box',
display: 'flex',
flexDirection: 'column',
});
// 20px drag-to-close band. The ONLY drag-to-close origin — touches
// on the viewer body below this strip drive zoom / pan / swipe and
// MUST NOT initiate a close gesture. `touchAction: none` blocks
// browser-native scroll on this strip.
export const panelHandle = style({
flexShrink: 0,
height: toRem(20),
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
cursor: 'grab',
touchAction: 'none',
userSelect: 'none',
selectors: {
'&:active': { cursor: 'grabbing' },
},
});
// Darker than `Background.Container` would make the grabber
// disappear — use `SurfaceVariant.Container` so the bar reads
// against the dark viewer bg. Mirror of the settings handle's
// step-up against `SurfaceVariant.Container` (where it uses the
// deeper `Background.Container`).
export const panelHandleBar = style({
width: toRem(36),
height: toRem(4),
borderRadius: toRem(4),
backgroundColor: color.SurfaceVariant.Container,
});
export const panelBody = style({
flex: 1,
display: 'flex',
flexDirection: 'column',
minHeight: 0,
minWidth: 0,
});