Build & Push Docker Image / build (push) Has been cancelled
Refresh the homepage around new hero/services/roadmap sections, shared design tokens, and updated brand assets. Co-authored-by: Cursor <cursoragent@cursor.com>
184 lines
7.9 KiB
TypeScript
184 lines
7.9 KiB
TypeScript
import { cva, type VariantProps } from "class-variance-authority";
|
|
|
|
import { cn } from "@/lib/utils";
|
|
|
|
/**
|
|
* Site-wide typography scale optimized for Persian (RTL) readability.
|
|
*
|
|
* Hierarchy (requested → variant):
|
|
* - Heading 1 → `h1` / `display`
|
|
* - Heading 2 → `h2`
|
|
* - Heading 3 → `h3`
|
|
* - Body Large → `body-lg`
|
|
* - Body → `body`
|
|
* - Small Text → `body-sm`
|
|
* - Caption → `caption`
|
|
* - Button Text → `button` / `button-lg`
|
|
* - Navigation → `nav` / `nav-mobile`
|
|
*
|
|
* Alignment: prefer `text-start` (right in RTL).
|
|
* Section captions (`section-intro`) use justify + last-line start for 2+ lines.
|
|
* Reading measure: keep paragraphs within `typeMeasure.*` max-widths.
|
|
*
|
|
* Use via `typography({ variant })`, `type.*` shorthand, or `<Typography>`.
|
|
*/
|
|
export const typographyVariants = cva("tracking-normal", {
|
|
variants: {
|
|
variant: {
|
|
/** Large marketing hero titles — may be centered via className */
|
|
display:
|
|
"text-start text-3xl font-bold leading-[1.55] text-balance sm:text-4xl lg:text-5xl",
|
|
/** Main page titles */
|
|
h1: "text-start text-3xl font-extrabold leading-[1.45] text-balance md:text-4xl lg:text-5xl",
|
|
/** Major section headings */
|
|
h2: "text-start text-2xl font-bold leading-[1.45] text-balance md:text-3xl lg:text-4xl",
|
|
/** Subsection / feature block headings */
|
|
h3: "text-start text-lg font-bold leading-[1.5] md:text-xl",
|
|
/** Compact block headings, mini sections */
|
|
h4: "text-start text-base font-bold leading-[1.5] md:text-lg",
|
|
/** Prominent intro paragraphs — same size as section captions */
|
|
"body-lg": "text-start text-lg leading-[1.8]",
|
|
/** Standard paragraphs */
|
|
body: "text-start text-base leading-[1.8]",
|
|
/** Secondary / denser copy */
|
|
"body-sm": "text-start text-sm leading-[1.75]",
|
|
/** Metadata, timestamps, footnotes — fixed size site-wide */
|
|
caption: "text-start text-xs leading-[1.6] text-muted-foreground",
|
|
/** Dense UI chrome (mockups, compact badges, timeline steps) — prefer caption when possible */
|
|
micro: "text-start text-[0.6875rem] leading-[1.5]",
|
|
/** Section eyebrow / badge labels */
|
|
eyebrow:
|
|
"text-start text-sm font-medium leading-normal text-muted-foreground",
|
|
/** Form labels, settings labels */
|
|
label: "text-start text-sm font-medium leading-none",
|
|
/** Header / menu items (desktop) */
|
|
nav: "text-start text-sm font-medium leading-none",
|
|
/** Mobile navigation items */
|
|
"nav-mobile": "text-start text-base font-medium leading-snug",
|
|
/** Default / sm button labels — optically centered in the control */
|
|
button: "text-sm font-medium leading-none",
|
|
/** Large button labels (hero / marketing CTAs) */
|
|
"button-lg": "text-base font-medium leading-none",
|
|
/** Titles inside cards and panels */
|
|
"card-title": "text-start text-base font-bold leading-snug",
|
|
/** Supporting copy inside cards */
|
|
"card-desc":
|
|
"text-start text-sm leading-[1.75] text-muted-foreground",
|
|
/** Chat message bubbles */
|
|
chat: "text-start text-sm leading-[1.75]",
|
|
/** Log panels, JSON, technical output */
|
|
code: "text-start font-mono text-xs leading-relaxed",
|
|
/** Large stat numbers */
|
|
stat: "text-start text-4xl font-bold leading-none text-primary md:text-5xl",
|
|
/** Inline nav / footer links */
|
|
link: "text-start text-sm leading-normal text-muted-foreground",
|
|
/**
|
|
* Section captions under headings (muted).
|
|
* Multi-line: justify; last line stays start (right in RTL).
|
|
* Single-line: justify has no visual stretch — stays start-aligned.
|
|
*/
|
|
"section-intro":
|
|
"text-justify text-lg leading-[1.8] text-muted-foreground [text-align-last:start]",
|
|
/** Pull quotes / emphasis blocks */
|
|
emphasis:
|
|
"text-start text-base font-medium leading-[1.8] text-foreground",
|
|
/** Accordion / list item titles */
|
|
"list-title": "text-start text-base font-medium leading-snug",
|
|
/** CTA section headings (slightly larger than h2) */
|
|
"cta-title":
|
|
"text-start text-2xl font-bold leading-[1.45] text-balance md:text-3xl lg:text-4xl",
|
|
/** Decorative error page numbers */
|
|
"display-mono":
|
|
"text-start text-[5rem] font-black leading-none sm:text-[6rem] md:text-[8rem]",
|
|
},
|
|
},
|
|
defaultVariants: {
|
|
variant: "body",
|
|
},
|
|
});
|
|
|
|
export type TypographyVariant = NonNullable<
|
|
VariantProps<typeof typographyVariants>["variant"]
|
|
>;
|
|
|
|
/** Shorthand class strings for inline use: `className={type.h2}` */
|
|
export const type: Record<TypographyVariant, string> = {
|
|
display:
|
|
"text-3xl font-bold leading-[1.55] tracking-normal text-balance text-start sm:text-4xl lg:text-5xl",
|
|
h1: "text-3xl font-extrabold leading-[1.45] tracking-normal text-balance text-start md:text-4xl lg:text-5xl",
|
|
h2: "text-2xl font-bold leading-[1.45] tracking-normal text-balance text-start md:text-3xl lg:text-4xl",
|
|
h3: "text-lg font-bold leading-[1.5] tracking-normal text-start md:text-xl",
|
|
h4: "text-base font-bold leading-[1.5] tracking-normal text-start md:text-lg",
|
|
"body-lg": "text-lg leading-[1.8] tracking-normal text-start",
|
|
body: "text-base leading-[1.8] tracking-normal text-start",
|
|
"body-sm": "text-sm leading-[1.75] tracking-normal text-start",
|
|
caption:
|
|
"text-xs leading-[1.6] tracking-normal text-start text-muted-foreground",
|
|
micro: "text-[0.6875rem] leading-[1.5] tracking-normal text-start",
|
|
eyebrow:
|
|
"text-sm font-medium leading-normal tracking-normal text-start text-muted-foreground",
|
|
label: "text-sm font-medium leading-none tracking-normal text-start",
|
|
nav: "text-sm font-medium leading-none tracking-normal text-start",
|
|
"nav-mobile": "text-base font-medium leading-snug tracking-normal text-start",
|
|
button: "text-sm font-medium leading-none tracking-normal",
|
|
"button-lg": "text-base font-medium leading-none tracking-normal",
|
|
"card-title":
|
|
"text-base font-bold leading-snug tracking-normal text-start",
|
|
"card-desc":
|
|
"text-sm leading-[1.75] tracking-normal text-start text-muted-foreground",
|
|
chat: "text-sm leading-[1.75] tracking-normal text-start",
|
|
code: "font-mono text-xs leading-relaxed tracking-normal text-start",
|
|
stat: "text-4xl font-bold leading-none tracking-normal text-start text-primary md:text-5xl",
|
|
link: "text-sm leading-normal tracking-normal text-start text-muted-foreground",
|
|
"section-intro":
|
|
"text-lg leading-[1.8] tracking-normal text-justify text-muted-foreground [text-align-last:start]",
|
|
emphasis:
|
|
"text-base font-medium leading-[1.8] tracking-normal text-start text-foreground",
|
|
"list-title":
|
|
"text-base font-medium leading-snug tracking-normal text-start",
|
|
"cta-title":
|
|
"text-2xl font-bold leading-[1.45] tracking-normal text-balance text-start md:text-3xl lg:text-4xl",
|
|
"display-mono":
|
|
"text-[5rem] font-black leading-none tracking-tighter text-start sm:text-[6rem] md:text-[8rem]",
|
|
};
|
|
|
|
/**
|
|
* Comfortable reading widths for Persian body copy.
|
|
* Prefer these over stretching lines across the full container.
|
|
*/
|
|
export const typeMeasure = {
|
|
/** Short support line under a heading */
|
|
narrow: "max-w-md",
|
|
/** Standard paragraph / section intro */
|
|
prose: "max-w-2xl",
|
|
/** Longer multi-paragraph blocks */
|
|
wide: "max-w-3xl",
|
|
} as const;
|
|
|
|
/** Text-related spacing tied to typography hierarchy */
|
|
export const typeSpacing = {
|
|
/** Eyebrow → heading */
|
|
eyebrowToHeading: "mt-2",
|
|
/** Heading → supporting paragraph */
|
|
headingToBody: "mt-3",
|
|
/** Section title block */
|
|
sectionStack: "space-y-4",
|
|
/** Page hero block */
|
|
heroStack: "space-y-6",
|
|
/** Card title → description */
|
|
cardStack: "gap-1.5",
|
|
/** Stacked paragraphs */
|
|
paragraphStack: "space-y-4",
|
|
/** Label → input */
|
|
labelToControl: "gap-1.5",
|
|
/** Message → timestamp in chat */
|
|
chatMeta: "space-y-1",
|
|
} as const;
|
|
|
|
export function typography(
|
|
variant: TypographyVariant,
|
|
className?: string
|
|
): string {
|
|
return cn(typographyVariants({ variant }), className);
|
|
}
|