vojo/src/app/components/page/style.css.ts

220 lines
6.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { style } from '@vanilla-extract/css';
import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
import { DefaultReset, color, config, toRem } from 'folds';
export const PageNavResizable = style({
position: 'relative',
flexShrink: 0,
flexGrow: 0,
});
export const PageNavResizeHandle = style({
position: 'absolute',
top: 0,
bottom: 0,
// Native default — sits across the (original) `<Line>` separator
// between page-nav and content. Web shifts the handle into the
// horseshoe void via an inline style override in `ResizablePageNav`.
right: -3,
width: 7,
cursor: 'col-resize',
zIndex: 1,
background: 'transparent',
touchAction: 'none',
outline: 'none',
selectors: {
'&::before': {
content: '""',
position: 'absolute',
top: '50%',
left: '50%',
width: 2,
height: toRem(36),
transform: 'translate(-50%, -50%)',
borderRadius: 1,
backgroundColor: color.Surface.OnContainer,
opacity: 0,
transition:
'opacity 140ms ease, height 140ms ease, width 140ms ease, background-color 140ms ease',
},
'&:hover::before, &:focus-visible::before': {
opacity: 0.25,
},
'&:focus-visible::before': {
backgroundColor: color.Primary.Main,
opacity: 0.45,
},
'&[data-dragging="true"]::before': {
opacity: 0.55,
height: toRem(48),
backgroundColor: color.Primary.Main,
},
// Limit feedback: when the user drags past a clamp the width stops
// moving and the indicator deforms to signal it. Min = spring crushed
// against a wall (slight squish, thicker). Max = rubber band stretched
// (taller, full opacity). Activates only during drag so the resting
// state stays calm.
'&[data-dragging="true"][data-at-min="true"]::before': {
height: toRem(28),
width: 3,
opacity: 0.85,
},
'&[data-dragging="true"][data-at-max="true"]::before': {
height: toRem(76),
width: 2,
opacity: 0.9,
},
},
});
export const PageNav = recipe({
variants: {
size: {
'500': {
width: toRem(320),
},
'400': {
width: toRem(256),
},
'300': {
width: toRem(222),
},
// Used by the Settings nav — ~1.43× the regular 300 (~317px =
// 1.3 × 1.1 over 222px). Settings labels are long
// ("Notifications", "Emojis & Stickers", "Developer Tools") and
// the 222px column truncated them; the wider column also gives
// the nested-horseshoe void gap on the right room to breathe.
'350': {
width: toRem(317),
},
},
},
defaultVariants: {
size: '400',
},
});
export type PageNavVariants = RecipeVariants<typeof PageNav>;
// Web-only horseshoe shell wrapping every page-nav's inner column.
// Previously carved rounded TR / BR corners against a void backdrop;
// the rounding was reverted while keeping the 12px void gap between
// page-nav and chat panel, so this class now just enforces an opaque
// Background bg + clips overflow. The bg keeps the page-nav header /
// footer painted even on routes (Bots, Channels) that don't paint
// anything of their own; `overflow:hidden` is defensive against any
// child that might bleed past the inner column. Applied conditionally
// in `PageNav` / `ResizablePageNav` below; native skips it entirely.
export const PageNavInnerWebHorseshoe = style({
overflow: 'hidden',
backgroundColor: color.Background.Container,
});
export const PageNavHeader = recipe({
base: {
padding: `0 ${config.space.S200} 0 ${config.space.S300}`,
flexShrink: 0,
selectors: {
'button&': {
cursor: 'pointer',
},
'button&[aria-pressed=true]': {
backgroundColor: color.Background.ContainerActive,
},
'button&:hover, button&:focus-visible': {
backgroundColor: color.Background.ContainerHover,
},
'button&:active': {
backgroundColor: color.Background.ContainerActive,
},
},
},
variants: {
outlined: {
true: {
borderBottomWidth: 1,
},
},
},
defaultVariants: {
outlined: true,
},
});
export type PageNavHeaderVariants = RecipeVariants<typeof PageNavHeader>;
export const PageNavContent = style({
// No `min-height: 100%`. It used to force this padded wrapper to at least
// the scroll viewport's height, but the div is transparent (the curtain on
// native / the PageNav inner column on web paints the background) so the
// fill was invisible — its only real effect was a ~1px scroll overflow:
// `100%` resolves against the fractional flex-parent height and rounds UP
// while the viewport's clientHeight rounds DOWN, leaving the list
// permanently scrollable by a hair even when it fits. That hair is the
// "useless" overscroll on native. Letting the wrapper size to its content
// means a short list has no scroll range at all (paired with the
// `overflow-y: auto` override on the Scroll in Page.tsx).
padding: config.space.S200,
paddingRight: 0,
paddingBottom: config.space.S700,
});
export const PageHeader = recipe({
base: {
paddingLeft: config.space.S400,
paddingRight: config.space.S200,
},
variants: {
balance: {
true: {
paddingLeft: config.space.S200,
},
},
outlined: {
true: {
borderBottomWidth: config.borderWidth.B300,
},
},
},
defaultVariants: {
outlined: true,
},
});
export type PageHeaderVariants = RecipeVariants<typeof PageHeader>;
export const PageContent = style([
DefaultReset,
{
paddingTop: config.space.S400,
paddingLeft: config.space.S400,
paddingRight: 0,
paddingBottom: toRem(100),
},
]);
export const PageHeroEmpty = style([
DefaultReset,
{
padding: config.space.S400,
borderRadius: config.radii.R400,
minHeight: toRem(450),
},
]);
export const PageHeroSection = style([
DefaultReset,
{
padding: '40px 0',
maxWidth: toRem(466),
width: '100%',
margin: 'auto',
},
]);
export const PageContentCenter = style([
DefaultReset,
{
maxWidth: toRem(964),
width: '100%',
margin: 'auto',
},
]);