Files
wehub-resource-sync d25d482dc2
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:20:55 +08:00

120 lines
5.4 KiB
TypeScript
Raw Permalink 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 {
LANDING_GUTTER,
LANDING_HERO_TOP_PADDING,
LANDING_SECTION_RHYTHM,
} from '@/app/(landing)/components/landing-layout'
/**
* Solutions-layout spacing - the single source of truth for every gutter, gap,
* inset, and reserved dimension used across the solutions-page components.
*
* The padding fortress lives here. No solutions component accepts a `className`
* or `style`, and none hard-codes a spacing value inline. Every measurement a
* reviewer might want to audit - the horizontal gutter, the inter-section rhythm,
* the card-grid gaps, the card stack, and the fixed visual-slot dimensions - is
* named in this one file. To change spacing you edit a constant here; consumer
* pages only choose from controlled component variants.
*
* All values are Tailwind class fragments (not raw numbers) so they compose
* directly into `className` strings inside the components and stay legible.
*/
export const SOLUTIONS_SPACING = {
/**
* The one horizontal gutter, owned solely by `SolutionsPage`. Matches the
* navbar and landing hero exactly (`px-20 max-lg:px-8 max-sm:px-5`) so
* solutions content starts on the wordmark's vertical line at every
* breakpoint. Sections and cards never set their own gutter.
*/
gutter: LANDING_GUTTER,
/**
* Inter-section vertical rhythm - the gap of the `<main>` flex column that
* `SolutionsPage` owns. Sections carry no vertical margin/padding of their own,
* so this is the only knob for the space between the hero, logos, and every
* card row. Tightens on smaller screens in lockstep with the landing `<main>`
* (`gap-[120px] max-lg:gap-[88px] max-sm:gap-16`).
*/
sectionRhythm: LANDING_SECTION_RHYTHM,
/** Hero text top padding, matching the landing hero at every breakpoint. */
heroTopPadding: LANDING_HERO_TOP_PADDING,
/** Vertical stack gap inside the hero header column (headline → description → CTA). */
heroStack: 'gap-[22px]',
/** Gap between the hero header column and the full-width hero visual beneath it. */
heroToVisual: 'gap-12',
/** Gap between a card row's header block and the card grid beneath it. */
cardRowHeaderToGrid: 'gap-12',
/** Vertical stack gap inside a card row's header (title → subtitle → CTA). */
cardRowHeaderStack: 'gap-5',
/**
* Extra top separation for the header CTA over the stack gap. Title and
* subtitle are one copy group and stay tight; the CTA is a separate action
* group, so its subtitle→CTA gap lands at 2× the title→subtitle gap
* (standard: 20px + 20px = 40px; feature: 12px + 12px = 24px).
*/
cardRowHeaderCtaGap: 'mt-5',
cardRowHeaderCtaGapFeature: 'mt-3',
/** Gap between cards within a card-row grid (both axes). */
cardGridGap: 'gap-8',
/** Minimum gap between a card's text block and its visual panel. */
cardTextToVisual: 'gap-5',
/** Vertical stack gap inside a card's text block (title → description). */
cardTextStack: 'gap-2',
/** Inner padding for feature tiles where copy and the visual slot share one frame. */
cardFeatureTilePadding: 'p-8 max-lg:p-6',
} as const
/**
* Readable text measures for the recurring solutions-page copy surfaces.
* Paragraph width is expressed in characters so line length tracks type size
* instead of the viewport. `min-w-0` keeps flex items wrapping cleanly on narrow
* screens, and `w-full` gives centered copy a stable measure.
*/
export const SOLUTIONS_TEXT_MEASURE = {
/** Hero support copy: broad enough for the primary value prop, still under long-form prose width. */
heroDescription: 'w-full min-w-0 max-w-[58ch]',
/** Section subtitles: slightly tighter than hero copy so centered headers feel intentional. */
rowSubtitle: 'w-full min-w-0 max-w-[52ch]',
/** Card descriptions: short scan lines inside three-up card grids. */
cardDescription: 'min-w-0 max-w-[38ch]',
} as const
/**
* Reserved fixed dimensions for the component-owned visual frames. A dropped-in
* `ReactNode` renders into a frame of exactly these dimensions, so it can never
* shift surrounding layout (CLS = 0) nor change its own frame padding. The node
* fills `h-full w-full` inside; it owns nothing about the frame.
*/
export const SOLUTIONS_VISUAL = {
/** Full-width hero visual aspect ratio - reserves height before paint. */
heroAspect: 'aspect-[16/9]',
/** Fixed height of a card's visual panel - uniform across every card. */
cardHeight: 'h-[240px]',
/**
* Minimum height for framed feature tiles with copy and future UI in one
* surface. One value at every breakpoint: the tallest tile vignettes (audit
* ledger, staging panel) need ~300px of visual slot below the copy block, so
* shrinking the tile on small screens crops their tops against the slot's
* `overflow-hidden`.
*/
featureTileMinHeight: 'min-h-[440px]',
} as const
/**
* Feature-tile surface + copy colors. Pages pick a tone per card via
* {@link SolutionsCardConfig.featureTileTone}; the component maps it here so
* each tile can diverge without shared hard-coded classes.
*/
export const SOLUTIONS_FEATURE_TILE_TONE = {
light: {
surface: 'bg-[var(--surface-3)]',
title: 'text-[var(--text-primary)]',
description: 'text-[var(--text-muted)]',
},
dark: {
surface: 'bg-[var(--text-secondary)]',
title: 'text-[var(--text-inverse)]',
description: 'text-[var(--surface-3)]',
/** Softer body copy on dark tiles — `#E6E6E6` via `--surface-6` (`#E5E5E5`). */
descriptionSoft: 'text-[var(--surface-6)]',
},
} as const