Fix Coming soon
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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");
|
||||
}
|
||||
|
||||
+7
-2
@@ -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 [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user