diff --git a/api/submissionsApi.ts b/api/submissionsApi.ts index 73e3547..bbca168 100644 --- a/api/submissionsApi.ts +++ b/api/submissionsApi.ts @@ -9,5 +9,5 @@ export interface SubmitFormPayload { } export async function submitForm(payload: SubmitFormPayload): Promise { - await axiosInstance.post("/api/submissions", payload); + await axiosInstance.post("/ipv6/api/submissions", payload); } diff --git a/app/components/forms/FeedbackForm.tsx b/app/components/forms/FeedbackForm.tsx index d0c5b8b..f167e80 100644 --- a/app/components/forms/FeedbackForm.tsx +++ b/app/components/forms/FeedbackForm.tsx @@ -95,7 +95,7 @@ export default function FeedbackForm({ data }: { data: FeedbackJson }) { setSubmitState("sending"); try { - const res = await fetch("/api/submissions", { + const res = await fetch("/ipv6/api/submissions", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ diff --git a/app/components/forms/RegistrationForm.tsx b/app/components/forms/RegistrationForm.tsx index e4182bc..bf86c61 100644 --- a/app/components/forms/RegistrationForm.tsx +++ b/app/components/forms/RegistrationForm.tsx @@ -40,7 +40,7 @@ export default function RegistrationForm({ setSubmitState("sending"); const industryLabel = industries.find((o) => o.value === form.industry)?.label ?? ""; try { - const res = await fetch("/api/submissions", { + const res = await fetch("/ipv6/api/submissions", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ diff --git a/app/components/layout/Header/HeaderClient.tsx b/app/components/layout/Header/HeaderClient.tsx index 562d275..7598299 100644 --- a/app/components/layout/Header/HeaderClient.tsx +++ b/app/components/layout/Header/HeaderClient.tsx @@ -20,9 +20,14 @@ export default function HeaderClient({ const { lang, setLang } = useLanguage(); const { site } = useTranslation(); - const isHome = pathname === "/"; + const isHome = pathname === "/" || pathname === "/ipv6" || pathname === "/ipv6/"; const navItems = useMemo(() => site.nav.filter((x) => x.href !== "/"), [site.nav]); + const isActive = (href: string) => { + if (href === "/") return isHome; + return pathname === href || pathname === `/ipv6${href}` || pathname?.startsWith(`${href}/`) || pathname?.startsWith(`/ipv6${href}/`); + }; + const registerLabel = lang === "vi" ? "Đăng Ký" : "Register"; const registerNowLabel = lang === "vi" ? "Đăng Ký Ngay" : "Register Now"; const backLabel = lang === "vi" ? "Trang Chủ" : "Home"; @@ -56,7 +61,7 @@ export default function HeaderClient({ {backLabel} {navItems.map((item) => { - const active = pathname === item.href; + const active = isActive(item.href); return ( {navItems.map((item) => { - const active = pathname === item.href; + const active = isActive(item.href); return ( -
+
+
+
+ {/* Background Decor */} +
+
- {/* glass-panel gold-border — p-stack-lg lg:p-section-gap */} -
- {/* Glow */} -
+
+ {/* Left Content */} +
+
+

+ {data.title} +

+

+ {data.description} +

+
-
- {/* Left */} -
-

{data.title}

- -

- {data.description} -

- -
+
{/* Phone */} -
-
- call -
-
-

{data.phone.label}

-

{data.phone.value}

+
+
+
+ call +
+
+

+ {data.phone.label} +

+

+ {data.phone.value} +

+
{/* Email */} -
-
- mail -
-
-

{data.email.label}

-

{data.email.value}

+
+
+
+ mail +
+
+

+ {data.email.label} +

+

+ {data.email.value} +

+
- {/* Right: image */} -
-
+ {/* Right Image */} +
+
{/* eslint-disable-next-line @next/next/no-img-element */} {data.image.alt} -
+
+
+ + {/* Decorative Frame */} +
diff --git a/app/components/sponsor/SponsorHero.tsx b/app/components/sponsor/SponsorHero.tsx index a356040..85c43e7 100644 --- a/app/components/sponsor/SponsorHero.tsx +++ b/app/components/sponsor/SponsorHero.tsx @@ -11,36 +11,39 @@ type SponsorHeroData = { export default function SponsorHero({ data }: { data: SponsorHeroData }) { return ( -
-
- -
- +
+
+ {/* Eyebrow */} +

{data.eyebrow} - +

-

+ {/* Title */} +

{data.title}

-

+ {/* Subtitle */} +

{data.subtitle} -

+

-

+ {/* Description */} +

{data.description}

-
+ {/* CTAs */} +
{data.primaryCta.label} {data.secondaryCta.label} diff --git a/app/components/sponsor/SponsorItemBased.tsx b/app/components/sponsor/SponsorItemBased.tsx index a13c78e..767c24f 100644 --- a/app/components/sponsor/SponsorItemBased.tsx +++ b/app/components/sponsor/SponsorItemBased.tsx @@ -20,45 +20,60 @@ type SponsorItemBasedData = { export default function SponsorItemBased({ data }: { data: SponsorItemBasedData }) { return ( -
-
- - {/* Header — text-center mb-stack-lg */} -
-

{data.title}

-

{data.description}

+
+
+ {/* Header */} +
+

+ {data.title} +

+

+ {data.description} +

- {/* 4-col cards — gap-gutter = 24px, mb-stack-lg = 32px */} -
+ {/* 4-col cards */} +
{data.items.map((item) => (
-
- {item.icon} +
+ + {item.icon} +
-

{item.title}

-

{item.status}

+

+ {item.title} +

+

+ {item.status} +

))}
- {/* Highlights — gap-gutter = 24px */} -
+ {/* Highlights */} +
{data.highlights.map((h) => (
-
-

{h.eyebrow}

-

{h.title}

+
+

+ {h.eyebrow} +

+

+ {h.title} +

+
+
+ + {h.icon} +
- - {h.icon} -
))}
diff --git a/app/components/sponsor/SponsorPackages.tsx b/app/components/sponsor/SponsorPackages.tsx index ba48a9f..8d4d81a 100644 --- a/app/components/sponsor/SponsorPackages.tsx +++ b/app/components/sponsor/SponsorPackages.tsx @@ -17,60 +17,48 @@ type SponsorPackagesData = { export default function SponsorPackages({ data }: { data: SponsorPackagesData }) { return ( -
-
- - {/* Header — flex items-center justify-between mb-stack-lg */} -
-

{data.title}

-
+
+
+ {/* Header */} +
+

+ {data.title} +

+
- {/* Grid — gap-stack-lg = 32px */} -
+ {/* Grid */} +
{data.items.map((pkg) => (
-
+
{pkg.badge && ( - + {pkg.badge} )} -

+

{pkg.tier}

-
+
{pkg.price}
-
    +
    + +
      {pkg.benefits.map((benefit) => ( -
    • - - check_circle +
    • + + {pkg.featured ? "verified" : "check_circle"} - + {benefit}
    • @@ -79,11 +67,7 @@ export default function SponsorPackages({ data }: { data: SponsorPackagesData }) diff --git a/app/components/sponsor/SponsorPageClient.tsx b/app/components/sponsor/SponsorPageClient.tsx index a4334eb..ef1e41b 100644 --- a/app/components/sponsor/SponsorPageClient.tsx +++ b/app/components/sponsor/SponsorPageClient.tsx @@ -10,7 +10,7 @@ export default function SponsorPageClient() { const { sponsor } = useTranslation(); return ( -
      +
      diff --git a/app/globals.css b/app/globals.css index 4ed078e..4bb5a1c 100644 --- a/app/globals.css +++ b/app/globals.css @@ -23,6 +23,10 @@ "Courier New", monospace; --spacing-gutter: clamp(1.25rem, 5vw, 5rem); + --spacing-stack-sm: 1rem; + --spacing-stack-md: 1.5rem; + --spacing-stack-lg: 2rem; + --spacing-section-gap: clamp(2rem, 8vw, 6rem); --spacing-container-max: 1800px; } @@ -53,17 +57,25 @@ textarea::placeholder { .glass-panel { background: rgba(15, 15, 15, 0.7); - backdrop-filter: blur(8px); - border: 1px solid rgba(197, 160, 89, 0.2); + backdrop-filter: blur(12px); + border: 1px solid rgba(197, 160, 89, 0.15); + box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37); } @media (min-width: 1024px) { .glass-panel { - backdrop-filter: blur(12px); - border: 1px solid rgba(197, 160, 89, 0.3); + border: 1px solid rgba(197, 160, 89, 0.25); } } +.gold-border { + border: 1px solid var(--color-primary) !important; +} + +.gold-glow { + box-shadow: 0 0 20px rgba(197, 160, 89, 0.2); +} + .gold-gradient-bg { background: linear-gradient(135deg, #c5a059 0%, #8e6d3d 100%); } diff --git a/next.config.ts b/next.config.ts index 55e51cc..0988bc5 100644 --- a/next.config.ts +++ b/next.config.ts @@ -2,7 +2,18 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { /* config options here */ + basePath: "/ipv6", output: "standalone", + async redirects() { + return [ + { + source: "/", + destination: "/ipv6", + basePath: false, + permanent: false, + }, + ]; + }, images: { remotePatterns: [ { diff --git a/package.json b/package.json index 5b3557d..2239972 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "dotenv -- next dev --no-turbopack", + "dev": "dotenv -- next dev", + "clean": "rm -rf .next", "build": "next build", "start": "dotenv -- next start", "lint": "eslint", @@ -24,6 +25,7 @@ "@types/react": "^19", "@types/react-dom": "^19", "dotenv-cli": "11.0.0", + "dotenv": "^17.4.2", "eslint": "^9", "eslint-config-next": "16.1.6", "sass": "^1.98.0",