Move coming-soon storefront into website Next.js app.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-09-07 21:00:21 +03:30
co-authored by Cursor
parent e171222b16
commit 2f857f1a90
22 changed files with 7427 additions and 1 deletions
+187
View File
@@ -0,0 +1,187 @@
@import "tailwindcss";
:root {
--background: #fbfbfa;
--foreground: #0a0a0a;
--surface: #ffffff;
--muted: #6b6b6b;
--line: #e4e4e4;
--ink: #0a0a0a;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-surface: var(--surface);
--color-muted: var(--muted);
--color-line: var(--line);
--color-ink: var(--ink);
--font-sans: var(--font-doran);
--font-display: var(--font-cailyne);
}
body {
background: var(--background);
color: var(--foreground);
font-family: var(--font-doran), Tahoma, sans-serif;
}
.font-display {
font-family: var(--font-cailyne), Georgia, serif;
letter-spacing: 0.04em;
}
.font-montserrat {
font-family: var(--font-montserrat), system-ui, sans-serif;
}
@keyframes coming-soon-rise {
from {
opacity: 0;
transform: translateY(22px);
filter: blur(6px);
}
to {
opacity: 1;
transform: translateY(0);
filter: blur(0);
}
}
@keyframes coming-soon-panel {
from {
opacity: 0;
transform: translateX(24px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes coming-soon-drift {
0% {
transform: scale(1) translate3d(0, 0, 0);
}
100% {
transform: scale(1.06) translate3d(-0.8%, 0.5%, 0);
}
}
@keyframes coming-soon-line {
from {
transform: scaleX(0);
opacity: 0;
}
to {
transform: scaleX(1);
opacity: 1;
}
}
@keyframes coming-soon-glow {
0%,
100% {
box-shadow: 0 0 0 0 rgba(10, 10, 10, 0);
}
50% {
box-shadow: 0 0 0 4px rgba(10, 10, 10, 0.06);
}
}
.coming-soon-seq {
opacity: 0;
animation: coming-soon-rise 0.95s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.coming-soon-seq-1 {
animation-delay: 0.12s;
}
.coming-soon-seq-2 {
animation-delay: 0.38s;
}
.coming-soon-seq-3 {
animation-delay: 0.58s;
}
.coming-soon-seq-4 {
animation-delay: 0.78s;
}
.coming-soon-seq-5 {
animation-delay: 1s;
}
.coming-soon-seq-5 {
position: relative;
}
.coming-soon-seq-5::before {
content: "";
position: absolute;
top: 0;
inset-inline: 0;
height: 1px;
background: var(--line);
transform-origin: center;
animation: coming-soon-line 0.7s cubic-bezier(0.16, 1, 0.3, 1) 1.05s both;
}
.coming-soon-seq-image {
opacity: 0;
animation: coming-soon-panel 1.1s ease-out 0.05s forwards;
}
.coming-soon-image {
transform: scale(1);
animation: coming-soon-drift 20s ease-in-out 1.2s alternate infinite both;
will-change: transform;
}
.coming-soon-login {
animation: coming-soon-glow 2.4s ease-in-out 1.6s 2;
}
@media (prefers-reduced-motion: reduce) {
.coming-soon-seq,
.coming-soon-seq-image,
.coming-soon-image,
.coming-soon-seq-5::before,
.coming-soon-login {
animation: none !important;
opacity: 1 !important;
filter: none !important;
transform: none !important;
}
}
.mana-canvas {
background:
radial-gradient(ellipse 80% 60% at 20% 20%, rgba(0, 0, 0, 0.02), transparent 55%),
radial-gradient(ellipse 70% 50% at 90% 80%, rgba(0, 0, 0, 0.022), transparent 50%),
linear-gradient(160deg, #fcfcfb 0%, #f7f7f5 48%, #f3f3f0 100%);
}
.mana-canvas::before {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
opacity: 0.45;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220' viewBox='0 0 220 220'%3E%3Cg fill='%230a0a0a'%3E%3Ccircle cx='12' cy='18' r='1.1' opacity='.28'/%3E%3Ccircle cx='48' cy='9' r='0.7' opacity='.18'/%3E%3Ccircle cx='91' cy='27' r='1.4' opacity='.22'/%3E%3Ccircle cx='133' cy='14' r='0.8' opacity='.3'/%3E%3Ccircle cx='176' cy='31' r='1.2' opacity='.16'/%3E%3Ccircle cx='208' cy='8' r='0.9' opacity='.24'/%3E%3Ccircle cx='27' cy='56' r='0.75' opacity='.2'/%3E%3Ccircle cx='69' cy='71' r='1.3' opacity='.26'/%3E%3Ccircle cx='112' cy='49' r='0.65' opacity='.15'/%3E%3Ccircle cx='154' cy='63' r='1.05' opacity='.29'/%3E%3Ccircle cx='197' cy='78' r='0.85' opacity='.19'/%3E%3Ccircle cx='8' cy='99' r='1.15' opacity='.23'/%3E%3Ccircle cx='41' cy='118' r='0.7' opacity='.17'/%3E%3Ccircle cx='83' cy='104' r='1.45' opacity='.27'/%3E%3Ccircle cx='126' cy='129' r='0.9' opacity='.21'/%3E%3Ccircle cx='168' cy='111' r='0.6' opacity='.14'/%3E%3Ccircle cx='201' cy='136' r='1.2' opacity='.25'/%3E%3Ccircle cx='22' cy='158' r='0.95' opacity='.18'/%3E%3Ccircle cx='58' cy='179' r='1.25' opacity='.3'/%3E%3Ccircle cx='97' cy='163' r='0.7' opacity='.16'/%3E%3Ccircle cx='139' cy='188' r='1.1' opacity='.22'/%3E%3Ccircle cx='181' cy='171' r='0.8' opacity='.28'/%3E%3Ccircle cx='213' cy='194' r='1' opacity='.19'/%3E%3Ccircle cx='35' cy='208' r='0.65' opacity='.24'/%3E%3Ccircle cx='74' cy='201' r='1.35' opacity='.15'/%3E%3Ccircle cx='118' cy='214' r='0.85' opacity='.26'/%3E%3Ccircle cx='160' cy='203' r='0.75' opacity='.2'/%3E%3Ccircle cx='16' cy='78' r='0.55' opacity='.12'/%3E%3Ccircle cx='104' cy='86' r='0.5' opacity='.13'/%3E%3Ccircle cx='187' cy='52' r='0.6' opacity='.11'/%3E%3Ccircle cx='149' cy='149' r='0.55' opacity='.14'/%3E%3C/g%3E%3C/svg%3E");
background-size: 220px 220px;
background-repeat: repeat;
}
.mana-canvas::after {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
opacity: 0.16;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.45'/%3E%3C/svg%3E");
background-size: 180px 180px;
mix-blend-mode: multiply;
}
+71
View File
@@ -0,0 +1,71 @@
import type { Metadata } from "next";
import { Montserrat } from "next/font/google";
import localFont from "next/font/local";
import "./globals.css";
const doran = localFont({
src: [
{
path: "../fonts/doran/Doran-Thin.woff",
weight: "100",
style: "normal",
},
{
path: "../fonts/doran/Doran-Regular.woff",
weight: "400",
style: "normal",
},
{
path: "../fonts/doran/Doran-Medium.woff",
weight: "500",
style: "normal",
},
{
path: "../fonts/doran/Doran-Bold.woff",
weight: "700",
style: "normal",
},
],
variable: "--font-doran",
display: "swap",
});
const cailyne = localFont({
src: [
{
path: "../fonts/Cailyne.otf",
weight: "400",
style: "normal",
},
],
variable: "--font-cailyne",
display: "swap",
});
const montserrat = Montserrat({
subsets: ["latin"],
weight: ["400", "500", "600"],
variable: "--font-montserrat",
display: "swap",
});
export const metadata: Metadata = {
title: "به‌زودی | مانا کالکشن",
description: "فروشگاه آنلاین مانا کالکشن به‌زودی در دسترس خواهد بود.",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html
lang="fa"
dir="rtl"
className={`${doran.variable} ${cailyne.variable} ${montserrat.variable} h-full antialiased`}
>
<body className="min-h-full font-sans text-foreground">{children}</body>
</html>
);
}
+81
View File
@@ -0,0 +1,81 @@
import Image from "next/image";
import ManaLogo from "@/components/ui/ManaLogo";
const STORE_LOGIN =
process.env.NEXT_PUBLIC_STORE_URL?.replace(/\/$/, "") ||
"http://store.mana-collection.com:3001";
export default function HomePage() {
return (
<main className="coming-soon relative min-h-dvh overflow-hidden bg-[#f7f7f5] text-ink">
{/* dir=ltr keeps content on visual left, image on visual right */}
<div dir="ltr" className="grid min-h-dvh grid-cols-1 lg:grid-cols-2">
{/* Content — left */}
<section className="relative order-2 flex min-h-[52dvh] flex-col lg:order-1 lg:min-h-dvh">
<div className="mana-canvas absolute inset-0" aria-hidden />
<div
dir="rtl"
className="relative z-10 flex flex-1 flex-col px-7 py-8 sm:px-12 sm:py-10 lg:px-16 lg:py-14"
>
<header className="coming-soon-seq coming-soon-seq-1 flex shrink-0 justify-center">
<ManaLogo
href=""
width={400}
priority
showTagline
variant="white"
blackBg
className="w-[400px] max-w-[min(400px,100%)]"
/>
</header>
<div className="flex flex-1 flex-col items-center justify-center py-12 text-center sm:py-16">
<div className="max-w-md">
<p
dir="ltr"
className="coming-soon-seq coming-soon-seq-2 mb-4 font-display text-sm tracking-[0.2em] text-muted sm:text-base"
>
Coming soon
</p>
<h1 className="coming-soon-seq coming-soon-seq-3 mb-5 text-4xl leading-tight text-ink sm:text-5xl">
به‌زودی
</h1>
<p className="coming-soon-seq coming-soon-seq-4 text-sm leading-8 text-muted sm:text-base sm:leading-8">
در این آدرس میزبان شما خواهیم بود.
</p>
</div>
</div>
<footer className="coming-soon-seq coming-soon-seq-5 shrink-0 pt-6">
<div className="flex flex-wrap items-center justify-between gap-4">
<p className="text-xs leading-6 text-muted">
حساب دارید؟ وارد شوید.
</p>
<a
href={`${STORE_LOGIN}/login`}
className="coming-soon-login inline-flex items-center justify-center border border-ink bg-ink px-7 py-2.5 text-sm text-white transition-colors hover:bg-white hover:text-ink"
>
ورود
</a>
</div>
</footer>
</div>
</section>
{/* Image — right */}
<aside className="coming-soon-seq-image relative order-1 min-h-[42dvh] overflow-hidden lg:order-2 lg:min-h-dvh">
<Image
src="/images/image1.jpg"
alt="مانا کالکشن"
fill
priority
sizes="(max-width: 1024px) 100vw, 50vw"
className="coming-soon-image object-cover object-center"
/>
<div className="pointer-events-none absolute inset-0 bg-gradient-to-l from-transparent via-transparent to-black/10" />
</aside>
</div>
</main>
);
}