Fix Coming soon

This commit is contained in:
diyaa
2026-03-13 09:26:40 +01:00
parent 2b5e91377c
commit 0bb964f07e
16 changed files with 294 additions and 93 deletions
+4 -4
View File
@@ -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 (
+4 -4
View File
@@ -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);
+9 -4
View File
@@ -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 (
+3 -3
View File
@@ -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
View File
@@ -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;
}
+41 -23
View File
@@ -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>
+20 -7
View File
@@ -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>
+9
View File
@@ -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");
}
+7 -2
View File
@@ -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 [
{