Browse Source

feat(fonts): add multi-language fonts matching Flutter Najm typography (Arabic, Persian, Urdu, SegoeUI)

master
mortezaei 2 weeks ago
parent
commit
d718c4f42a
  1. BIN
      public/fonts/segoeui/SegoeUIBold.ttf
  2. BIN
      public/fonts/segoeui/segoeui.ttf
  3. BIN
      public/fonts/urdu/NotoNastaliqUrdu.ttf
  4. BIN
      public/fonts/yekanx-arabic/ArabicYekanXRegular.ttf
  5. BIN
      public/fonts/yekanx/YekanXFaNum-R.ttf
  6. 58
      src/app/globals.css
  7. 45
      src/app/layout.tsx
  8. 4
      src/app/marriage-advisors/page.tsx
  9. 5
      src/app/new-match/profile/page.tsx
  10. 10
      src/translations/provider.tsx

BIN
public/fonts/segoeui/SegoeUIBold.ttf

BIN
public/fonts/segoeui/segoeui.ttf

BIN
public/fonts/urdu/NotoNastaliqUrdu.ttf

BIN
public/fonts/yekanx-arabic/ArabicYekanXRegular.ttf

BIN
public/fonts/yekanx/YekanXFaNum-R.ttf

58
src/app/globals.css

@ -75,11 +75,13 @@
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
--font-sans: var(--font-segoeui), "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
--font-mono: var(--font-geist-mono);
--font-arabic: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
--font-ryling: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
--font-faminela: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
--font-arabic: var(--font-yekanx-arabic), var(--font-segoeui), "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
--font-persian: var(--font-yekanx), var(--font-yekanx-arabic), var(--font-segoeui), "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
--font-urdu: var(--font-nastaliq-urdu), var(--font-yekanx-arabic), var(--font-segoeui), "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
--font-ryling: var(--font-segoeui), "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
--font-faminela: var(--font-faminela-local), "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
--color-semantic-neutral-bg: var(--semantic-neutral-bg);
--color-semantic-neutral-text: var(--semantic-neutral-text);
@ -196,29 +198,49 @@ body {
justify-content: center;
overflow: hidden;
color: var(--foreground);
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
font-family: var(--font-segoeui), "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
overscroll-behavior: none;
}
/* ─── Multi-Language Typography matching Flutter Najm AppTheme ─── */
/* 1. Arabic (ar) -> Flutter yekanxArabic (ArabicYekanXRegular.ttf) */
html:lang(ar) body,
:lang(ar) {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
html[lang="ar"] body,
body[data-lang="ar"],
:lang(ar),
.font-arabic {
font-family: var(--font-yekanx-arabic), var(--font-segoeui), "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}
.font-arabic,
.font-ryling {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
/* 2. Persian (fa) -> Flutter yekanx (YekanXFaNum-R.ttf) */
html:lang(fa) body,
html[lang="fa"] body,
body[data-lang="fa"],
:lang(fa),
.font-persian {
font-family: var(--font-yekanx), var(--font-yekanx-arabic), var(--font-segoeui), "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}
/* 3. Urdu (ur) & Kashmiri (ks) -> Flutter NastaliqUrdu (NotoNastaliqUrdu.ttf) */
html:lang(ur) body,
html[lang="ur"] body,
body[data-lang="ur"],
:lang(ur),
html:lang(ks) body,
html[lang="ks"] body,
body[data-lang="ks"],
:lang(ks),
.font-urdu {
font-family: var(--font-nastaliq-urdu), var(--font-yekanx-arabic), var(--font-segoeui), "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}
/* 4. Global / Latin / Cyrillic / Asian languages -> Flutter Segoeui */
html:not([lang="ar"]):not([lang="fa"]):not([lang="ur"]):not([lang="ks"]) body {
font-family: var(--font-segoeui), "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}
.font-faminela:lang(ar),
.font-ryling:lang(ar),
[dir="rtl"] .font-faminela,
[dir="rtl"] .font-ryling,
[dir="rtl"].font-faminela,
[dir="rtl"].font-ryling,
.font-faminela {
font-family:
var(--font-faminela-local), "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
font-family: var(--font-faminela-local), var(--font-segoeui), "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}
.app-shell {

45
src/app/layout.tsx

@ -13,6 +13,49 @@ import {
import { getInitialMarriageProfile } from "@/hooks/marriage/use-profile-main";
import type { MarriageProfileResponse } from "@/hooks/marriage/types";
const yekanxArabic = localFont({
src: "../../public/fonts/yekanx-arabic/ArabicYekanXRegular.ttf",
variable: "--font-yekanx-arabic",
display: "swap",
preload: false,
fallback: ["Segoe UI", "Tahoma", "Geneva", "Verdana", "sans-serif"],
});
const yekanx = localFont({
src: "../../public/fonts/yekanx/YekanXFaNum-R.ttf",
variable: "--font-yekanx",
display: "swap",
preload: false,
fallback: ["Segoe UI", "Tahoma", "Geneva", "Verdana", "sans-serif"],
});
const notoNastaliqUrdu = localFont({
src: "../../public/fonts/urdu/NotoNastaliqUrdu.ttf",
variable: "--font-nastaliq-urdu",
display: "swap",
preload: false,
fallback: ["Segoe UI", "Tahoma", "Geneva", "Verdana", "sans-serif"],
});
const segoeui = localFont({
src: [
{
path: "../../public/fonts/segoeui/segoeui.ttf",
weight: "400",
style: "normal",
},
{
path: "../../public/fonts/segoeui/SegoeUIBold.ttf",
weight: "700",
style: "normal",
},
],
variable: "--font-segoeui",
display: "swap",
preload: false,
fallback: ["Segoe UI", "Tahoma", "Geneva", "Verdana", "sans-serif"],
});
const faminela = localFont({
src: "../../public/fonts/Faminela/Faminela.otf",
variable: "--font-faminela-local",
@ -407,7 +450,7 @@ export default async function RootLayout({
/>
</head>
<body
className={`${faminela.variable} ${amiri.variable}`}
className={`${segoeui.variable} ${yekanxArabic.variable} ${yekanx.variable} ${notoNastaliqUrdu.variable} ${faminela.variable} ${amiri.variable}`}
suppressHydrationWarning
>
<Providers initialProfile={initialProfile}>

4
src/app/marriage-advisors/page.tsx

@ -60,7 +60,6 @@ export default function MarriageAdvisorsPage({
/>
<h1
className="min-w-0 flex-1 text-center font-semibold text-[14px] leading-[16px] text-white"
style={{ fontFamily: "'Segoe UI', sans-serif" }}
>
{t["Marriage advisors"]}
</h1>
@ -75,7 +74,6 @@ export default function MarriageAdvisorsPage({
<div className="flex w-[343px] flex-col items-center gap-3 rounded-[15px] border border-[#EBEBEB] bg-white px-4 py-8 text-center shadow-[0px_4px_12px_rgba(0,0,0,0.05)]">
<p
className="text-[14px] leading-[20px] text-[#747474]"
style={{ fontFamily: "'Segoe UI', sans-serif" }}
>
{t["Failed to load advisors."]}
</p>
@ -83,7 +81,6 @@ export default function MarriageAdvisorsPage({
type="button"
onClick={() => refetch()}
className="cursor-pointer rounded-[20px] border-none bg-[rgba(14,177,60,0.1)] px-4 py-1.5 text-[12px] font-semibold text-[#0EB13C] transition-transform active:scale-95"
style={{ fontFamily: "'Segoe UI', sans-serif" }}
>
{t["Try again"]}
</button>
@ -94,7 +91,6 @@ export default function MarriageAdvisorsPage({
<div className="flex w-[343px] flex-col items-center rounded-[15px] border border-[#EBEBEB] bg-white px-4 py-8 text-center shadow-[0px_4px_12px_rgba(0,0,0,0.05)]">
<p
className="text-[14px] leading-[20px] text-[#747474]"
style={{ fontFamily: "'Segoe UI', sans-serif" }}
>
{t["No advisors are currently available."]}
</p>

5
src/app/new-match/profile/page.tsx

@ -78,13 +78,11 @@ function MatchField({
<div className="flex flex-col items-start w-full border-b border-black/10 pb-[14px] mt-[14px]">
<p
className="text-[12px] font-semibold leading-[17px] text-[#978787]"
style={{ fontFamily: "'Segoe UI', sans-serif" }}
>
{label}
</p>
<p
className="text-[16px] font-bold leading-[20px] text-[#111111] mt-[7px] text-left"
style={{ fontFamily: "'Segoe UI', sans-serif" }}
>
{value}
</p>
@ -195,7 +193,6 @@ function NewMatchProfileSkeleton({
)}
<h1
className="min-w-0 flex-1 text-center font-semibold text-[14px] leading-[16px] text-white"
style={{ fontFamily: "'Segoe UI', sans-serif" }}
>
{t["More detail"]}
</h1>
@ -629,7 +626,6 @@ export default function NewMatchProfilePage({
/>
<h1
className="min-w-0 flex-1 text-center font-semibold text-[14px] leading-[16px] text-white"
style={{ fontFamily: "'Segoe UI', sans-serif" }}
>
{t["More detail"]}
</h1>
@ -675,7 +671,6 @@ export default function NewMatchProfilePage({
<span
className="font-bold text-[22px] leading-[26px] text-[#F0445B] text-center"
style={{
fontFamily: "'Segoe UI', sans-serif",
WebkitTextStroke: "2px rgba(255, 255, 255, 0.5)",
paintOrder: "stroke fill",
}}

10
src/translations/provider.tsx

@ -1,7 +1,7 @@
"use client";
import { createContext, type ReactNode, useContext, useEffect, useMemo } from "react";
import { defaultLocale, type Locale } from "@/translations/config";
import { defaultLocale, type Locale, localeDirections } from "@/translations/config";
import { type Dictionary, getDictionary } from "@/translations/dictionaries";
import { getUserGeoRegion } from "@/lib/geo-region";
@ -25,6 +25,14 @@ export function I18nProvider({ children, locale }: I18nProviderProps) {
void getUserGeoRegion(true);
}, []);
useEffect(() => {
if (typeof document !== "undefined") {
document.documentElement.lang = locale;
document.documentElement.dir = localeDirections[locale] ?? "ltr";
document.body.setAttribute("data-lang", locale);
}
}, [locale]);
const value = useMemo(
() => ({
locale,

Loading…
Cancel
Save