feat: redesign landing page with brand system and section blocks
Build & Push Docker Image / build (push) Has been cancelled
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>
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import type { Transition, Variants } from "motion/react";
|
||||
|
||||
/** Standard scroll-reveal ease (ui-ux-pro-max: power2.out-equivalent). */
|
||||
export const blockEase = [0.22, 1, 0.36, 1] as const;
|
||||
|
||||
/** ~400–500ms section entrance — transform + opacity only. */
|
||||
export const blockRevealTransition: Transition = {
|
||||
duration: 0.5,
|
||||
ease: blockEase,
|
||||
};
|
||||
|
||||
/**
|
||||
* Trigger when the block approaches ~85% from the top of the viewport.
|
||||
* `once` keeps motion purposeful and avoids reverse jitter on scroll-up.
|
||||
*/
|
||||
export const blockViewport = {
|
||||
once: true,
|
||||
amount: 0.2,
|
||||
margin: "0px 0px -10% 0px",
|
||||
} as const;
|
||||
|
||||
export const blockRevealContainer: Variants = {
|
||||
hidden: {},
|
||||
visible: {
|
||||
transition: {
|
||||
staggerChildren: 0.08,
|
||||
delayChildren: 0.04,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const blockRevealItem: Variants = {
|
||||
hidden: { opacity: 0, y: 24 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: blockRevealTransition,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
/**
|
||||
* Global layout tokens for Amin Rayan.
|
||||
* All page sections must use these — do not invent ad-hoc max-widths or gutters.
|
||||
*
|
||||
* Base was max-w-5xl (64rem); +20% → 76.8rem for a wider content column.
|
||||
*/
|
||||
export const layout = {
|
||||
/** Outer horizontal gutter (full-bleed backgrounds stay outside this). */
|
||||
gutter: "px-6",
|
||||
/** Main content max width (64rem × 1.2). */
|
||||
maxWidth: "max-w-[76.8rem]",
|
||||
/** Shared content shell: centered, capped, padded. */
|
||||
container: "mx-auto w-full max-w-[76.8rem] px-6",
|
||||
/**
|
||||
* Vertical rhythm for major sections.
|
||||
* Adjacent sections always meet as `pb + pt` from this token
|
||||
* (`py-16` → 8rem gap, `md:py-20` → 10rem) — including hero → خدمات ما.
|
||||
*/
|
||||
sectionY: "py-16 md:py-20",
|
||||
/** Top offset under fixed header for first section (incl. homepage hero). */
|
||||
sectionTopWithHeader: "pt-28 pb-16 md:pt-32 md:pb-20",
|
||||
/** Anchor scroll offset under fixed header. */
|
||||
scrollMargin: "scroll-mt-28",
|
||||
/** Soft visual cue between bands — no hard template break. */
|
||||
sectionBandDivider: "border-t border-border/30",
|
||||
} as const;
|
||||
|
||||
export function containerClassName(className?: string) {
|
||||
return cn(layout.container, className);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
const LATIN_TO_PERSIAN: Record<string, string> = {
|
||||
"0": "۰",
|
||||
"1": "۱",
|
||||
"2": "۲",
|
||||
"3": "۳",
|
||||
"4": "۴",
|
||||
"5": "۵",
|
||||
"6": "۶",
|
||||
"7": "۷",
|
||||
"8": "۸",
|
||||
"9": "۹",
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert Latin digits in a string to Persian digits.
|
||||
* Leaves non-digit characters unchanged. Use for UI labels, stats,
|
||||
* dates, and counters — not for technical IDs or code.
|
||||
*/
|
||||
export function toPersianDigits(value: string | number): string {
|
||||
return String(value).replace(/[0-9]/g, (digit) => LATIN_TO_PERSIAN[digit] ?? digit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a number for Persian UI (locale grouping + Persian digits).
|
||||
*/
|
||||
export function formatPersianNumber(
|
||||
value: number,
|
||||
options?: Intl.NumberFormatOptions
|
||||
): string {
|
||||
return toPersianDigits(
|
||||
new Intl.NumberFormat("fa-IR", options).format(value)
|
||||
);
|
||||
}
|
||||
+105
-52
@@ -4,62 +4,92 @@ 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 */
|
||||
/** Large marketing hero titles — may be centered via className */
|
||||
display:
|
||||
"text-3xl font-semibold leading-relaxed text-balance sm:text-4xl lg:text-5xl",
|
||||
"text-start text-3xl font-bold leading-[1.55] 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",
|
||||
h1: "text-start text-3xl font-extrabold leading-[1.45] 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",
|
||||
h2: "text-start text-2xl font-bold leading-[1.45] text-balance md:text-3xl lg:text-4xl",
|
||||
/** Subsection / feature block headings */
|
||||
h3: "text-lg font-semibold leading-snug md:text-xl",
|
||||
h3: "text-start text-lg font-bold leading-[1.5] 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",
|
||||
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-base leading-relaxed",
|
||||
body: "text-start text-base leading-[1.8]",
|
||||
/** Secondary / denser copy */
|
||||
"body-sm": "text-sm leading-relaxed",
|
||||
/** Metadata, timestamps, footnotes */
|
||||
caption: "text-xs leading-normal text-muted-foreground",
|
||||
"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-sm font-medium leading-normal text-muted-foreground",
|
||||
eyebrow:
|
||||
"text-start text-sm font-medium leading-normal text-muted-foreground",
|
||||
/** Form labels, settings labels */
|
||||
label: "text-sm font-medium leading-none",
|
||||
label: "text-start text-sm font-medium leading-none",
|
||||
/** Header / menu items (desktop) */
|
||||
nav: "text-sm font-medium",
|
||||
nav: "text-start text-sm font-medium leading-none",
|
||||
/** Mobile navigation items */
|
||||
"nav-mobile": "text-base font-medium",
|
||||
"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-base font-semibold leading-snug",
|
||||
"card-title": "text-start text-base font-bold leading-snug",
|
||||
/** Supporting copy inside cards */
|
||||
"card-desc": "text-sm leading-relaxed text-muted-foreground",
|
||||
"card-desc":
|
||||
"text-start text-sm leading-[1.75] text-muted-foreground",
|
||||
/** Chat message bubbles */
|
||||
chat: "text-sm leading-relaxed",
|
||||
chat: "text-start text-sm leading-[1.75]",
|
||||
/** Log panels, JSON, technical output */
|
||||
code: "font-mono text-xs leading-relaxed",
|
||||
code: "text-start font-mono text-xs leading-relaxed",
|
||||
/** Large stat numbers */
|
||||
stat: "text-4xl font-bold leading-none text-primary md:text-5xl",
|
||||
stat: "text-start 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",
|
||||
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-base font-medium leading-relaxed text-foreground",
|
||||
emphasis:
|
||||
"text-start text-base font-medium leading-[1.8] text-foreground",
|
||||
/** Accordion / list item titles */
|
||||
"list-title": "text-base font-medium leading-snug",
|
||||
"list-title": "text-start 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",
|
||||
"text-start text-2xl font-bold leading-[1.45] 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]",
|
||||
"text-start text-[5rem] font-black leading-none sm:text-[6rem] md:text-[8rem]",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
@@ -74,34 +104,57 @@ export type TypographyVariant = NonNullable<
|
||||
/** 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",
|
||||
"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-semibold leading-snug tracking-normal text-balance md:text-3xl lg:text-4xl",
|
||||
"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 sm:text-[6rem] md:text-[8rem]",
|
||||
"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 */
|
||||
|
||||
Reference in New Issue
Block a user