98 lines
3.1 KiB
TypeScript
98 lines
3.1 KiB
TypeScript
import { style } from '@vanilla-extract/css';
|
|
import { toRem } from 'folds';
|
|
import {
|
|
VOJO_HORSESHOE_VOID_COLOR,
|
|
VOJO_HORSESHOE_GAP_PX,
|
|
VOJO_HORSESHOE_RADIUS_PX,
|
|
} from '../styles/horseshoe';
|
|
|
|
// Color of the «void» between the app shell and the bottom call rail —
|
|
// shared across every horseshoe surface, see `styles/horseshoe.ts`.
|
|
// Painted only when the call rail is mounted, so the rest of the app
|
|
// keeps its normal page background.
|
|
const SURFACE_GAP_COLOR = VOJO_HORSESHOE_VOID_COLOR;
|
|
const HORSESHOE_RADIUS = toRem(VOJO_HORSESHOE_RADIUS_PX);
|
|
const HORSESHOE_GAP = toRem(VOJO_HORSESHOE_GAP_PX);
|
|
|
|
// Outer flex column hosting app shell + bottom call rail.
|
|
// `min-height: 0` is required for nested scroll containers inside
|
|
// ClientLayout to shrink correctly.
|
|
export const surface = style({
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
flex: 1,
|
|
minWidth: 0,
|
|
minHeight: 0,
|
|
});
|
|
|
|
export const surfaceActive = style({
|
|
backgroundColor: SURFACE_GAP_COLOR,
|
|
});
|
|
|
|
// === App shell ===
|
|
//
|
|
// Wraps the whole client UI. Gets rounded BOTTOM corners + 8px
|
|
// margin pushing the rest of the app up while a call surface is
|
|
// active.
|
|
export const appShell = style({
|
|
display: 'flex',
|
|
flex: 1,
|
|
minWidth: 0,
|
|
minHeight: 0,
|
|
});
|
|
|
|
export const appShellBottomRound = style({
|
|
borderBottomLeftRadius: HORSESHOE_RADIUS,
|
|
borderBottomRightRadius: HORSESHOE_RADIUS,
|
|
overflow: 'hidden',
|
|
marginBottom: HORSESHOE_GAP,
|
|
});
|
|
|
|
// === Bottom horseshoe (call rail) ===
|
|
//
|
|
// Rounded *top* corners only because it sits flush against the
|
|
// safe-area inset; the bottom is the screen edge. `position: relative`
|
|
// carries the absolute-positioned orbit border.
|
|
export const bottomRail = style({
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
flexShrink: 0,
|
|
});
|
|
|
|
export const bottomRailActive = style({
|
|
position: 'relative',
|
|
borderTopLeftRadius: HORSESHOE_RADIUS,
|
|
borderTopRightRadius: HORSESHOE_RADIUS,
|
|
overflow: 'hidden',
|
|
});
|
|
|
|
// Orbit border on the bottom rail — small green segment of a
|
|
// conic-gradient that runs around the rail's perimeter when a ring is
|
|
// incoming. The mask trick (content-box layer XOR full-box layer)
|
|
// cuts the inner area, so only the 2px rim shows the gradient. The
|
|
// angle is driven by `--vojo-orbit-angle`, registered via `@property`
|
|
// in `src/index.css`.
|
|
export const ringOrbit = style({
|
|
position: 'absolute',
|
|
inset: 0,
|
|
borderRadius: 'inherit',
|
|
padding: toRem(2),
|
|
pointerEvents: 'none',
|
|
background:
|
|
'conic-gradient(from var(--vojo-orbit-angle, 0deg), transparent 0deg 280deg, rgba(91, 227, 197, 0.15) 300deg, #5BE3C5 335deg, rgba(91, 227, 197, 0.15) 350deg, transparent 360deg)',
|
|
filter: 'drop-shadow(0 0 6px rgba(91, 227, 197, 0.55))',
|
|
WebkitMask:
|
|
'linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0)',
|
|
WebkitMaskComposite: 'xor',
|
|
mask: 'linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0)',
|
|
maskComposite: 'exclude',
|
|
animationName: 'vojo-orbit-sweep',
|
|
animationDuration: '1.8s',
|
|
animationTimingFunction: 'linear',
|
|
animationIterationCount: 'infinite',
|
|
'@media': {
|
|
'(prefers-reduced-motion: reduce)': {
|
|
animation: 'none',
|
|
},
|
|
},
|
|
});
|