Files
aragrp/lib/typography.ts
T
alirez.brandCursor a47ec493c5 feat: add version history drawer with release notes
Introduce a footer-triggered Version History drawer with categorized release notes, hardcoded release data, and semver tracking at v0.3.0. Also ships blog blockquote/table styling, site-wide typography, home page image updates, header refinements, and related bug fixes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 02:46:20 +03:30

131 lines
5.6 KiB
TypeScript

import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
/**
* Site-wide typography scale optimized for Persian (RTL) readability.
* Use via `typography({ variant })`, `type.*` shorthand, or `<Typography>`.
*/
export const typographyVariants = cva("tracking-normal", {
variants: {
variant: {
/** Large marketing hero titles */
display:
"text-3xl font-semibold leading-relaxed text-balance sm:text-4xl lg:text-5xl",
/** Main page titles */
h1: "text-3xl font-bold leading-snug text-balance md:text-4xl lg:text-5xl",
/** Major section headings */
h2: "text-2xl font-semibold leading-snug text-balance md:text-3xl lg:text-4xl",
/** Subsection / feature block headings */
h3: "text-lg font-semibold leading-snug md:text-xl",
/** Compact block headings, mini sections */
h4: "text-base font-semibold leading-snug md:text-lg",
/** Prominent intro paragraphs */
"body-lg": "text-lg leading-relaxed md:text-xl",
/** Standard paragraphs */
body: "text-base leading-relaxed",
/** Secondary / denser copy */
"body-sm": "text-sm leading-relaxed",
/** Metadata, timestamps, footnotes */
caption: "text-xs leading-normal text-muted-foreground",
/** Section eyebrow / badge labels */
eyebrow: "text-sm font-medium leading-normal text-muted-foreground",
/** Form labels, settings labels */
label: "text-sm font-medium leading-none",
/** Header / menu items (desktop) */
nav: "text-sm font-medium",
/** Mobile navigation items */
"nav-mobile": "text-base font-medium",
/** Titles inside cards and panels */
"card-title": "text-base font-semibold leading-snug",
/** Supporting copy inside cards */
"card-desc": "text-sm leading-relaxed text-muted-foreground",
/** Chat message bubbles */
chat: "text-sm leading-relaxed",
/** Log panels, JSON, technical output */
code: "font-mono text-xs leading-relaxed",
/** Large stat numbers */
stat: "text-4xl font-bold leading-none text-primary md:text-5xl",
/** Inline nav / footer links */
link: "text-sm text-muted-foreground",
/** Section intro paragraphs (muted) */
"section-intro": "text-lg leading-relaxed text-muted-foreground",
/** Pull quotes / emphasis blocks */
emphasis: "text-base font-medium leading-relaxed text-foreground",
/** Accordion / list item titles */
"list-title": "text-base font-medium leading-snug",
/** CTA section headings (slightly larger than h2) */
"cta-title":
"text-2xl font-semibold leading-snug text-balance md:text-3xl lg:text-4xl",
/** Decorative error page numbers */
"display-mono":
"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-semibold leading-relaxed tracking-normal text-balance sm:text-4xl lg:text-5xl",
h1: "text-3xl font-bold leading-snug tracking-normal text-balance md:text-4xl lg:text-5xl",
h2: "text-2xl font-semibold leading-snug tracking-normal text-balance md:text-3xl lg:text-4xl",
h3: "text-lg font-semibold leading-snug tracking-normal md:text-xl",
h4: "text-base font-semibold leading-snug tracking-normal md:text-lg",
"body-lg": "text-lg leading-relaxed tracking-normal md:text-xl",
body: "text-base leading-relaxed tracking-normal",
"body-sm": "text-sm leading-relaxed tracking-normal",
caption: "text-xs leading-normal tracking-normal text-muted-foreground",
eyebrow: "text-sm font-medium leading-normal tracking-normal text-muted-foreground",
label: "text-sm font-medium leading-none tracking-normal",
nav: "text-sm font-medium tracking-normal",
"nav-mobile": "text-base font-medium tracking-normal",
"card-title": "text-base font-semibold leading-snug tracking-normal",
"card-desc": "text-sm leading-relaxed tracking-normal text-muted-foreground",
chat: "text-sm leading-relaxed tracking-normal",
code: "font-mono text-xs leading-relaxed tracking-normal",
stat: "text-4xl font-bold leading-none tracking-normal text-primary md:text-5xl",
link: "text-sm tracking-normal text-muted-foreground",
"section-intro": "text-lg leading-relaxed tracking-normal text-muted-foreground",
emphasis: "text-base font-medium leading-relaxed tracking-normal text-foreground",
"list-title": "text-base font-medium leading-snug tracking-normal",
"cta-title":
"text-2xl font-semibold leading-snug tracking-normal text-balance md:text-3xl lg:text-4xl",
"display-mono":
"text-[5rem] font-black leading-none tracking-tighter sm:text-[6rem] md:text-[8rem]",
};
/** 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);
}