Fix Coming soon
This commit is contained in:
parent
2b5e91377c
commit
0bb964f07e
@ -1,5 +1,5 @@
|
||||
import type { Metadata } from "next";
|
||||
import { getDictionary, isLocale, type Locale } from "@/lib/i18n";
|
||||
import { getActiveLocale, getDictionary, isLocale, type Locale } from "@/lib/i18n";
|
||||
import { buildPageMetadata } from "@/lib/metadata";
|
||||
import { isComingSoonMode } from "@/lib/site";
|
||||
import { notFound, redirect } from "next/navigation";
|
||||
@ -9,7 +9,7 @@ export function generateMetadata({ params }: { params: { locale: string } }): Me
|
||||
return {};
|
||||
}
|
||||
|
||||
return buildPageMetadata(params.locale, "about");
|
||||
return buildPageMetadata(getActiveLocale(params.locale), "about");
|
||||
}
|
||||
|
||||
export default function AboutPage({ params }: { params: { locale: string } }) {
|
||||
@ -18,10 +18,10 @@ export default function AboutPage({ params }: { params: { locale: string } }) {
|
||||
}
|
||||
|
||||
if (isComingSoonMode()) {
|
||||
redirect(`/${params.locale}`);
|
||||
redirect("/");
|
||||
}
|
||||
|
||||
const locale = params.locale as Locale;
|
||||
const locale = getActiveLocale(params.locale as Locale);
|
||||
const dictionary = getDictionary(locale);
|
||||
|
||||
return (
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { Metadata } from "next";
|
||||
import { getDictionary, isLocale, type Locale } from "@/lib/i18n";
|
||||
import { getActiveLocale, getDictionary, isLocale, type Locale } from "@/lib/i18n";
|
||||
import { buildPageMetadata } from "@/lib/metadata";
|
||||
import { getContactChannels, isComingSoonMode } from "@/lib/site";
|
||||
import { notFound, redirect } from "next/navigation";
|
||||
@ -9,7 +9,7 @@ export function generateMetadata({ params }: { params: { locale: string } }): Me
|
||||
return {};
|
||||
}
|
||||
|
||||
return buildPageMetadata(params.locale, "contact");
|
||||
return buildPageMetadata(getActiveLocale(params.locale), "contact");
|
||||
}
|
||||
|
||||
export default function ContactPage({ params }: { params: { locale: string } }) {
|
||||
@ -18,10 +18,10 @@ export default function ContactPage({ params }: { params: { locale: string } })
|
||||
}
|
||||
|
||||
if (isComingSoonMode()) {
|
||||
redirect(`/${params.locale}`);
|
||||
redirect("/");
|
||||
}
|
||||
|
||||
const locale = params.locale as Locale;
|
||||
const locale = getActiveLocale(params.locale as Locale);
|
||||
const dictionary = getDictionary(locale);
|
||||
const channels = getContactChannels(dictionary.contact);
|
||||
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { notFound } from "next/navigation";
|
||||
import { notFound, redirect } from "next/navigation";
|
||||
import BottomNav from "@/components/BottomNav";
|
||||
import SiteFooter from "@/components/SiteFooter";
|
||||
import SiteHeader from "@/components/SiteHeader";
|
||||
import { getDictionary, getDirection, isLocale, locales, type Locale } from "@/lib/i18n";
|
||||
import { getActiveLocale, getDictionary, getDirection, getEnabledLocales, isLocale, type Locale } from "@/lib/i18n";
|
||||
import { isComingSoonMode } from "@/lib/site";
|
||||
|
||||
export const dynamicParams = false;
|
||||
|
||||
export function generateStaticParams() {
|
||||
return locales.map((locale) => ({ locale }));
|
||||
return getEnabledLocales().map((locale) => ({ locale }));
|
||||
}
|
||||
|
||||
export default function LocaleLayout({
|
||||
@ -22,7 +23,11 @@ export default function LocaleLayout({
|
||||
notFound();
|
||||
}
|
||||
|
||||
const locale = params.locale as Locale;
|
||||
if (isComingSoonMode()) {
|
||||
redirect("/");
|
||||
}
|
||||
|
||||
const locale = getActiveLocale(params.locale as Locale);
|
||||
const dictionary = getDictionary(locale);
|
||||
|
||||
return (
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { Metadata } from "next";
|
||||
import HeroSection from "@/components/HeroSection";
|
||||
import { getDictionary, isLocale, type Locale } from "@/lib/i18n";
|
||||
import { getActiveLocale, getDictionary, isLocale, type Locale } from "@/lib/i18n";
|
||||
import { buildPageMetadata } from "@/lib/metadata";
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
@ -9,7 +9,7 @@ export function generateMetadata({ params }: { params: { locale: string } }): Me
|
||||
return {};
|
||||
}
|
||||
|
||||
return buildPageMetadata(params.locale, "home");
|
||||
return buildPageMetadata(getActiveLocale(params.locale), "home");
|
||||
}
|
||||
|
||||
export default function HomePage({ params }: { params: { locale: string } }) {
|
||||
@ -17,7 +17,7 @@ export default function HomePage({ params }: { params: { locale: string } }) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const locale = params.locale as Locale;
|
||||
const locale = getActiveLocale(params.locale as Locale);
|
||||
const dictionary = getDictionary(locale);
|
||||
|
||||
return <HeroSection locale={locale} home={dictionary.home} />;
|
||||
|
||||
100
app/globals.css
100
app/globals.css
@ -200,6 +200,22 @@ a {
|
||||
animation: fade-up 460ms ease both;
|
||||
}
|
||||
|
||||
.coming-soon-page {
|
||||
min-height: 100vh;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.coming-soon-title {
|
||||
margin: 0;
|
||||
font-size: clamp(2.5rem, 10vw, 5.5rem);
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
letter-spacing: -0.05em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.panel {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--line-strong);
|
||||
@ -305,6 +321,72 @@ a {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.coming-soon {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.4fr) minmax(280px, 0.8fr);
|
||||
gap: 1.4rem;
|
||||
align-items: stretch;
|
||||
min-height: min(72vh, 760px);
|
||||
padding: clamp(1.5rem, 3vw, 2.4rem);
|
||||
}
|
||||
|
||||
.coming-soon::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background:
|
||||
radial-gradient(circle at 18% 20%, color-mix(in srgb, var(--brand) 18%, transparent), transparent 28%),
|
||||
radial-gradient(circle at 86% 18%, color-mix(in srgb, var(--brand-2) 18%, transparent), transparent 24%),
|
||||
linear-gradient(135deg, color-mix(in srgb, var(--surface-2) 42%, transparent), transparent 66%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.coming-soon-copy,
|
||||
.coming-soon-meta {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.coming-soon-copy {
|
||||
display: grid;
|
||||
align-content: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.coming-soon-copy .cta-row {
|
||||
margin-top: 1.65rem;
|
||||
}
|
||||
|
||||
.coming-soon-meta {
|
||||
display: grid;
|
||||
gap: 0.9rem;
|
||||
align-content: end;
|
||||
}
|
||||
|
||||
.coming-soon-card {
|
||||
border-radius: 20px;
|
||||
border: 1px solid color-mix(in srgb, var(--line-strong) 92%, transparent);
|
||||
background: color-mix(in srgb, var(--card-bg) 88%, transparent);
|
||||
backdrop-filter: blur(16px);
|
||||
padding: 1.1rem 1rem;
|
||||
}
|
||||
|
||||
.coming-soon-value {
|
||||
display: block;
|
||||
font-size: 1rem;
|
||||
font-weight: 800;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.coming-soon-label {
|
||||
display: block;
|
||||
margin-top: 0.28rem;
|
||||
color: var(--muted);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.split-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
@ -531,6 +613,24 @@ a {
|
||||
}
|
||||
|
||||
.split-grid,
|
||||
.stat-grid,
|
||||
.coming-soon {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.coming-soon {
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.coming-soon-meta,
|
||||
.coming-soon-copy {
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
.coming-soon-meta {
|
||||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
.stat-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
@ -1,31 +1,46 @@
|
||||
import type { Metadata } from "next";
|
||||
import type { ReactNode } from "react";
|
||||
import { siteConfig } from "@/lib/site";
|
||||
import { isComingSoonMode } from "@/lib/site";
|
||||
import "./globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(siteConfig.siteUrl),
|
||||
title: {
|
||||
default: "Diyaa",
|
||||
template: "%s | Diyaa",
|
||||
},
|
||||
description: "Bilingual professional website built for private-server deployment.",
|
||||
applicationName: "Diyaa",
|
||||
authors: [{ name: "Diyaa" }],
|
||||
creator: "Diyaa",
|
||||
publisher: "Diyaa",
|
||||
alternates: {
|
||||
languages: {
|
||||
ar: "/ar",
|
||||
en: "/en",
|
||||
"x-default": "/ar",
|
||||
},
|
||||
},
|
||||
};
|
||||
export function generateMetadata(): Metadata {
|
||||
const comingSoon = isComingSoonMode();
|
||||
|
||||
const themeScript = `
|
||||
return {
|
||||
metadataBase: new URL(siteConfig.siteUrl),
|
||||
title: {
|
||||
default: "Diyaa",
|
||||
template: "%s | Diyaa",
|
||||
},
|
||||
description: comingSoon
|
||||
? "Minimal coming soon page for the upcoming launch."
|
||||
: "Bilingual professional website built for private-server deployment.",
|
||||
applicationName: "Diyaa",
|
||||
authors: [{ name: "Diyaa" }],
|
||||
creator: "Diyaa",
|
||||
publisher: "Diyaa",
|
||||
alternates: {
|
||||
languages: comingSoon
|
||||
? {
|
||||
en: "/",
|
||||
"x-default": "/",
|
||||
}
|
||||
: {
|
||||
ar: "/ar",
|
||||
en: "/en",
|
||||
"x-default": "/ar",
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function getThemeScript() {
|
||||
const comingSoon = isComingSoonMode();
|
||||
|
||||
return `
|
||||
(() => {
|
||||
const locale = window.location.pathname.split("/").filter(Boolean)[0] === "en" ? "en" : "ar";
|
||||
const locale = ${comingSoon ? '"en"' : 'window.location.pathname.split("/").filter(Boolean)[0] === "en" ? "en" : "ar"'};
|
||||
const direction = locale === "ar" ? "rtl" : "ltr";
|
||||
document.documentElement.lang = locale;
|
||||
document.documentElement.dir = direction;
|
||||
@ -38,12 +53,15 @@ const themeScript = `
|
||||
}
|
||||
})();
|
||||
`;
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }: { children: ReactNode }) {
|
||||
const comingSoon = isComingSoonMode();
|
||||
|
||||
return (
|
||||
<html lang="ar" dir="rtl" data-theme="dark" suppressHydrationWarning>
|
||||
<html lang={comingSoon ? "en" : "ar"} dir={comingSoon ? "ltr" : "rtl"} data-theme="dark" suppressHydrationWarning>
|
||||
<head>
|
||||
<script dangerouslySetInnerHTML={{ __html: themeScript }} />
|
||||
<script dangerouslySetInnerHTML={{ __html: getThemeScript() }} />
|
||||
</head>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
import Link from "next/link";
|
||||
import { isComingSoonMode } from "@/lib/site";
|
||||
|
||||
export default function NotFound() {
|
||||
const comingSoon = isComingSoonMode();
|
||||
|
||||
return (
|
||||
<main className="page-content">
|
||||
<section className="panel section-stack">
|
||||
@ -8,17 +11,27 @@ export default function NotFound() {
|
||||
<p className="eyebrow">404</p>
|
||||
<h1>الصفحة غير موجودة</h1>
|
||||
<p className="lead">
|
||||
الصفحة المطلوبة غير متاحة حاليًا. يمكنك العودة إلى النسخة العربية أو الإنجليزية من الصفحة الرئيسية.
|
||||
{comingSoon
|
||||
? "الصفحة المطلوبة غير متاحة حاليًا. يمكنك العودة إلى الصفحة الرئيسية."
|
||||
: "الصفحة المطلوبة غير متاحة حاليًا. يمكنك العودة إلى النسخة العربية أو الإنجليزية من الصفحة الرئيسية."}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="cta-row">
|
||||
<Link href="/ar" className="cta-btn">
|
||||
العودة إلى العربية
|
||||
</Link>
|
||||
<Link href="/en" className="ghost-btn">
|
||||
Go to English
|
||||
</Link>
|
||||
{comingSoon ? (
|
||||
<Link href="/" className="cta-btn">
|
||||
العودة إلى الرئيسية
|
||||
</Link>
|
||||
) : (
|
||||
<>
|
||||
<Link href="/ar" className="cta-btn">
|
||||
العودة إلى العربية
|
||||
</Link>
|
||||
<Link href="/en" className="ghost-btn">
|
||||
Go to English
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
@ -1,5 +1,14 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { isComingSoonMode } from "@/lib/site";
|
||||
|
||||
export default function RootPage() {
|
||||
if (isComingSoonMode()) {
|
||||
return (
|
||||
<main className="coming-soon-page">
|
||||
<h1 className="coming-soon-title">Coming Soon</h1>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
redirect("/ar");
|
||||
}
|
||||
|
||||
@ -1,11 +1,16 @@
|
||||
import type { MetadataRoute } from "next";
|
||||
import { getLocalizedPath, siteConfig } from "@/lib/site";
|
||||
import { isComingSoonMode } from "@/lib/site";
|
||||
import type { Locale } from "@/lib/i18n";
|
||||
|
||||
const pages = ["", "/about", "/contact"] as const;
|
||||
const locales = ["ar", "en"] as const;
|
||||
const allPages = ["", "/about", "/contact"] as const;
|
||||
const allLocales = ["ar", "en"] as const;
|
||||
|
||||
export default function sitemap(): MetadataRoute.Sitemap {
|
||||
const lastModified = new Date();
|
||||
const comingSoon = isComingSoonMode();
|
||||
const pages: readonly (typeof allPages)[number][] = comingSoon ? [] : allPages;
|
||||
const locales: readonly Locale[] = comingSoon ? [] : allLocales;
|
||||
|
||||
return [
|
||||
{
|
||||
|
||||
42
components/ComingSoonPanel.tsx
Normal file
42
components/ComingSoonPanel.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import type { HomeVariantContent } from "@/content/types";
|
||||
import { getEmailHref } from "@/lib/site";
|
||||
|
||||
type ComingSoonPanelProps = {
|
||||
content: HomeVariantContent;
|
||||
};
|
||||
|
||||
export default function ComingSoonPanel({ content }: ComingSoonPanelProps) {
|
||||
const emailHref = getEmailHref();
|
||||
|
||||
return (
|
||||
<section className="coming-soon panel">
|
||||
<div className="coming-soon-copy">
|
||||
<p className="availability-badge">{content.badge}</p>
|
||||
<p className="eyebrow">{content.kicker}</p>
|
||||
<h1>{content.title}</h1>
|
||||
<p className="lead">{content.description}</p>
|
||||
|
||||
<div className="cta-row">
|
||||
{emailHref ? (
|
||||
<a href={emailHref} className="cta-btn">
|
||||
{content.primaryCta}
|
||||
</a>
|
||||
) : (
|
||||
<span className="cta-btn is-disabled" aria-disabled="true">
|
||||
{content.primaryCta}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="coming-soon-meta" aria-label="Launch status">
|
||||
{content.highlights.map((item) => (
|
||||
<article key={item.label} className="coming-soon-card">
|
||||
<span className="coming-soon-value">{item.value}</span>
|
||||
<span className="coming-soon-label">{item.label}</span>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
import Link from "next/link";
|
||||
import ComingSoonPanel from "@/components/ComingSoonPanel";
|
||||
import type { HomeContent, HomeVariantContent } from "@/content/types";
|
||||
import type { Locale } from "@/lib/i18n";
|
||||
import { getEmailHref, getModeValue, isComingSoonMode } from "@/lib/site";
|
||||
@ -10,8 +11,13 @@ type HeroSectionProps = {
|
||||
|
||||
export default function HeroSection({ locale, home }: HeroSectionProps) {
|
||||
const activeHome: HomeVariantContent = getModeValue(home);
|
||||
const comingSoon = isComingSoonMode();
|
||||
const emailHref = getEmailHref();
|
||||
|
||||
if (comingSoon) {
|
||||
return <ComingSoonPanel content={activeHome} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="hero panel">
|
||||
<p className="availability-badge">{activeHome.badge}</p>
|
||||
@ -29,7 +35,7 @@ export default function HeroSection({ locale, home }: HeroSectionProps) {
|
||||
{activeHome.primaryCta}
|
||||
</span>
|
||||
)}
|
||||
<Link href={isComingSoonMode() ? `/${locale}` : `/${locale}/about`} className="ghost-btn">
|
||||
<Link href={`/${locale}/about`} className="ghost-btn">
|
||||
{activeHome.secondaryCta}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { Locale } from "@/lib/i18n";
|
||||
import type { CommonContent } from "@/content/types";
|
||||
import { getModeValue } from "@/lib/site";
|
||||
import { getModeValue, isComingSoonMode } from "@/lib/site";
|
||||
|
||||
type SiteFooterProps = {
|
||||
locale: Locale;
|
||||
@ -10,6 +10,7 @@ type SiteFooterProps = {
|
||||
export default function SiteFooter({ locale, common }: SiteFooterProps) {
|
||||
const year = new Date().getFullYear();
|
||||
const commonVariant = getModeValue(common.variants);
|
||||
const isComingSoon = isComingSoonMode();
|
||||
|
||||
return (
|
||||
<footer className="site-footer">
|
||||
@ -18,7 +19,7 @@ export default function SiteFooter({ locale, common }: SiteFooterProps) {
|
||||
<p>{common.footerRights.replace("{year}", String(year))}</p>
|
||||
<p>{commonVariant.footerBuiltWith}</p>
|
||||
</div>
|
||||
<p className="locale-badge">{locale.toUpperCase()}</p>
|
||||
{!isComingSoon ? <p className="locale-badge">{locale.toUpperCase()}</p> : null}
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
|
||||
@ -33,7 +33,7 @@ export default function SiteHeader({ locale, common }: SiteHeaderProps) {
|
||||
) : null}
|
||||
|
||||
<div className="header-actions">
|
||||
<LanguageSwitcher locale={locale} label={common.languageSwitcherLabel} />
|
||||
{!isComingSoon ? <LanguageSwitcher locale={locale} label={common.languageSwitcherLabel} /> : null}
|
||||
<ThemeToggle
|
||||
label={common.themeToggleLabel}
|
||||
lightLabel={common.themeLight}
|
||||
|
||||
@ -28,16 +28,16 @@ const en: Dictionary = {
|
||||
home: {
|
||||
comingSoon: {
|
||||
badge: "Coming Soon",
|
||||
kicker: "Coming soon",
|
||||
title: "A fresh version of this site is being prepared",
|
||||
kicker: "Temporary notice",
|
||||
title: "This website is temporarily closed while a new version is prepared",
|
||||
description:
|
||||
"The full website is currently being refined with a stronger visual identity, sharper content, and a cleaner launch-ready experience. It will be live soon.",
|
||||
primaryCta: "Reach out when it launches",
|
||||
"A cleaner and more complete version of the site is currently in progress. The full experience will return soon with updated content and a refined presentation.",
|
||||
primaryCta: "Contact by email",
|
||||
secondaryCta: "Stay tuned",
|
||||
highlights: [
|
||||
{ value: "New release", label: "Updated look and content" },
|
||||
{ value: "Bilingual", label: "Arabic and English ready" },
|
||||
{ value: "Soon", label: "Official launch" },
|
||||
{ value: "Temporarily offline", label: "Public pages are paused for now" },
|
||||
{ value: "New version", label: "Refined content and visual identity" },
|
||||
{ value: "Soon", label: "Full launch will return shortly" },
|
||||
],
|
||||
},
|
||||
full: {
|
||||
@ -98,24 +98,7 @@ const en: Dictionary = {
|
||||
{ key: "github", name: "GitHub", hint: "For repositories, code samples, and project history" },
|
||||
],
|
||||
},
|
||||
metadata: {
|
||||
home: {
|
||||
comingSoon: {
|
||||
title: "Coming Soon",
|
||||
description: "A temporary landing page announcing the upcoming launch of the new personal website.",
|
||||
},
|
||||
full: {
|
||||
title: "Home",
|
||||
description: "A bilingual professional site presenting technical expertise, project readiness, and server-friendly deployment.",
|
||||
},
|
||||
},
|
||||
aboutTitle: "About",
|
||||
aboutDescription: "Learn about experience, skills, and the working approach behind modern web builds.",
|
||||
contactTitle: "Contact",
|
||||
contactDescription: "Contact page wired for email and professional profile links through environment settings.",
|
||||
notFoundTitle: "Page not found",
|
||||
notFoundDescription: "The requested page could not be found. Return home or switch to the other language.",
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
export default en;
|
||||
|
||||
15
lib/i18n.ts
15
lib/i18n.ts
@ -1,6 +1,7 @@
|
||||
import ar from "@/content/ar";
|
||||
import en from "@/content/en";
|
||||
import type { Dictionary } from "@/content/types";
|
||||
import { isComingSoonMode } from "@/lib/site";
|
||||
|
||||
export const locales = ["ar", "en"] as const;
|
||||
|
||||
@ -11,18 +12,26 @@ const dictionaries: Record<Locale, Dictionary> = {
|
||||
en,
|
||||
};
|
||||
|
||||
export function getActiveLocale(locale: Locale): Locale {
|
||||
return isComingSoonMode() ? "en" : locale;
|
||||
}
|
||||
|
||||
export function getEnabledLocales(): Locale[] {
|
||||
return isComingSoonMode() ? ["en"] : [...locales];
|
||||
}
|
||||
|
||||
export function isLocale(value: string): value is Locale {
|
||||
return locales.includes(value as Locale);
|
||||
}
|
||||
|
||||
export function getDictionary(locale: Locale): Dictionary {
|
||||
return dictionaries[locale];
|
||||
return dictionaries[getActiveLocale(locale)];
|
||||
}
|
||||
|
||||
export function getDirection(locale: Locale): "rtl" | "ltr" {
|
||||
return locale === "ar" ? "rtl" : "ltr";
|
||||
return getActiveLocale(locale) === "ar" ? "rtl" : "ltr";
|
||||
}
|
||||
|
||||
export function getLocaleName(locale: Locale): string {
|
||||
return locale === "ar" ? "العربية" : "English";
|
||||
return getActiveLocale(locale) === "ar" ? "العربية" : "English";
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { Metadata } from "next";
|
||||
import { getDictionary, type Locale } from "@/lib/i18n";
|
||||
import { getLocalizedPath, getLocalizedUrl, getModeValue } from "@/lib/site";
|
||||
import { getActiveLocale, getDictionary, type Locale } from "@/lib/i18n";
|
||||
import { getLocalizedPath, getLocalizedUrl, getModeValue, isComingSoonMode } from "@/lib/site";
|
||||
|
||||
type PageKey = "home" | "about" | "contact";
|
||||
|
||||
@ -11,7 +11,8 @@ const pagePathMap: Record<PageKey, string> = {
|
||||
};
|
||||
|
||||
export function buildPageMetadata(locale: Locale, page: PageKey): Metadata {
|
||||
const dictionary = getDictionary(locale);
|
||||
const activeLocale = getActiveLocale(locale);
|
||||
const dictionary = getDictionary(activeLocale);
|
||||
const pathname = pagePathMap[page];
|
||||
const homeMetadata = getModeValue(dictionary.metadata.home);
|
||||
const metadataByPage = {
|
||||
@ -30,25 +31,34 @@ export function buildPageMetadata(locale: Locale, page: PageKey): Metadata {
|
||||
} as const;
|
||||
|
||||
const pageMetadata = metadataByPage[page];
|
||||
const canonicalPath = getLocalizedPath(pathname, locale);
|
||||
const canonicalPath = isComingSoonMode() && page === "home" ? "/" : getLocalizedPath(pathname, activeLocale);
|
||||
const alternates = isComingSoonMode()
|
||||
? {
|
||||
canonical: canonicalPath,
|
||||
languages: {
|
||||
en: "/",
|
||||
"x-default": "/",
|
||||
},
|
||||
}
|
||||
: {
|
||||
canonical: canonicalPath,
|
||||
languages: {
|
||||
ar: getLocalizedPath(pathname, "ar"),
|
||||
en: getLocalizedPath(pathname, "en"),
|
||||
"x-default": getLocalizedPath(pathname, "ar"),
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
title: pageMetadata.title,
|
||||
description: pageMetadata.description,
|
||||
alternates: {
|
||||
canonical: canonicalPath,
|
||||
languages: {
|
||||
ar: getLocalizedPath(pathname, "ar"),
|
||||
en: getLocalizedPath(pathname, "en"),
|
||||
"x-default": getLocalizedPath(pathname, "ar"),
|
||||
},
|
||||
},
|
||||
alternates,
|
||||
openGraph: {
|
||||
title: pageMetadata.title,
|
||||
description: pageMetadata.description,
|
||||
url: getLocalizedUrl(pathname, locale),
|
||||
url: isComingSoonMode() && page === "home" ? getLocalizedUrl("/", "en") : getLocalizedUrl(pathname, activeLocale),
|
||||
siteName: dictionary.common.siteTitle,
|
||||
locale: locale === "ar" ? "ar_SA" : "en_US",
|
||||
locale: activeLocale === "ar" ? "ar_SA" : "en_US",
|
||||
type: "website",
|
||||
},
|
||||
twitter: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user