139 lines
5.2 KiB
TypeScript
139 lines
5.2 KiB
TypeScript
import { style } from '@vanilla-extract/css';
|
|
import { color, toRem } from 'folds';
|
|
import { VOJO_HORSESHOE_GAP_PX, VOJO_HORSESHOE_RADIUS_PX } from '../../../styles/horseshoe';
|
|
|
|
// Re-exported so the TSX can pick up the constants without crossing the
|
|
// vanilla-extract / runtime boundary twice. Mirror of the canonical
|
|
// MobileSettingsHorseshoe css module.
|
|
export const HORSESHOE_RADIUS_PX = VOJO_HORSESHOE_RADIUS_PX;
|
|
export const HORSESHOE_GAP_PX = VOJO_HORSESHOE_GAP_PX;
|
|
|
|
// Outer container — anchor for the two absolutely-positioned panes
|
|
// (`appBody` and `silhouette`). `flex: 1` fills PageNav's inner column
|
|
// slot. `overflow: hidden` clips the rounded carves against the
|
|
// container's bg, which is painted inline with the void colour when
|
|
// the sheet is active. See MobileSettingsHorseshoe.css.ts for the full
|
|
// rationale on every property here — kept verbatim except for the file
|
|
// header.
|
|
//
|
|
// `marginTop: -var(--vojo-safe-top)` extends the container UP over the
|
|
// status-bar safe-top zone, and the compensating
|
|
// `paddingTop: var(--vojo-safe-top)` on `appBody` keeps the wrapped
|
|
// channels list anchored at the same visual Y. Mirror of the same
|
|
// pair in `MobileSettingsHorseshoe.css.ts::container` — purpose is
|
|
// (1) the workspace-sheet clip-path mask on `appBody` carves into an
|
|
// opaque surface that already paints through the status-bar strip,
|
|
// and (2) `appBody`'s bg paints the safe-top strip in the same
|
|
// `SurfaceVariant.Container` tone as the pager's static header so the
|
|
// system-tray backdrop stays consistent across surfaces.
|
|
//
|
|
// The curtain itself never paints into the safe-top zone — pin
|
|
// gesture clamps it at `top: 0` of the stage, see
|
|
// `components/stream-header/geometry.ts::PIN_TRAVEL_PX`.
|
|
export const container = style({
|
|
position: 'relative',
|
|
display: 'flex',
|
|
flex: 1,
|
|
flexDirection: 'column',
|
|
minWidth: 0,
|
|
minHeight: 0,
|
|
overflow: 'hidden',
|
|
marginTop: 'calc(-1 * var(--vojo-safe-top, 0px))',
|
|
});
|
|
|
|
// Wrapped children (StreamHeader → ChannelsList → WorkspaceFooter).
|
|
// Stays put — the bottom is carved away by an animated
|
|
// `clip-path: inset(...)` with rounded BL/BR. `backgroundColor` is
|
|
// load-bearing: the container is painted with the void colour when the
|
|
// sheet is active, so without an opaque bg the void would bleed through
|
|
// every transparent gap between list rows. See canonical for the full
|
|
// reasoning on clip-path vs translate vs flex-shrink.
|
|
//
|
|
// `paddingTop: var(--vojo-safe-top)` reserves status-bar space INSIDE
|
|
// appBody — compensates the `container.marginTop: -safe-top` shift so
|
|
// the wrapped flex children (StreamHeader.stage) stay anchored at the
|
|
// same visual Y as before. `backgroundColor` is `SurfaceVariant.Container`
|
|
// (not `Background.Container`) so the now-visible safe-top zone of
|
|
// appBody matches the tone `PageNav-inner` shows in Bots / Channels-root
|
|
// (which use `surface="surfaceVariant"`), giving the curtain's darker
|
|
// `Background.Container` tone a visible strip to over-paint on drag-up.
|
|
export const appBody = style({
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
right: 0,
|
|
bottom: 0,
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
minWidth: 0,
|
|
minHeight: 0,
|
|
backgroundColor: color.SurfaceVariant.Container,
|
|
paddingTop: 'var(--vojo-safe-top, 0px)',
|
|
willChange: 'clip-path',
|
|
});
|
|
|
|
// Workspace switcher sheet surface. Anchored at the bottom of the
|
|
// container; height animates 0 → railHeight as the user drags / clicks.
|
|
// `SurfaceVariant.Container` matches the chat-pane tone and keeps the
|
|
// safe-area / handle gaps from reading as dark stripes on edge-to-edge
|
|
// Android — same rationale as the canonical settings horseshoe.
|
|
export const silhouette = style({
|
|
position: 'absolute',
|
|
bottom: 0,
|
|
left: 0,
|
|
right: 0,
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
overflow: 'hidden',
|
|
backgroundColor: color.SurfaceVariant.Container,
|
|
willChange: 'height, border-top-left-radius, border-top-right-radius',
|
|
});
|
|
|
|
// Top-anchored panel content. Padding-bottom reserves Android nav-bar
|
|
// inset so the create-space row never tucks under the gesture pill.
|
|
export const panelContent = style({
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
right: 0,
|
|
boxSizing: 'border-box',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
paddingBottom: 'env(safe-area-inset-bottom, 0px)',
|
|
});
|
|
|
|
// 20px drag-to-close band at the top of the silhouette. The ONLY
|
|
// drag-down origin once the sheet is open — touches on the spaces list
|
|
// below this strip are not drag-sensitive, so internal scroll keeps
|
|
// working without a gesture conflict.
|
|
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' },
|
|
},
|
|
});
|
|
|
|
export const panelHandleBar = style({
|
|
width: toRem(36),
|
|
height: toRem(4),
|
|
borderRadius: toRem(4),
|
|
backgroundColor: color.Background.Container,
|
|
});
|
|
|
|
// Holds the workspace switcher list. `flex: 1` so it grows below the
|
|
// 20px handle to fill the remaining panel height; internal Scroll inside
|
|
// the switcher handles overflow when the user has many orphan spaces.
|
|
export const panelBody = style({
|
|
flex: 1,
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
minHeight: 0,
|
|
minWidth: 0,
|
|
});
|