first commit

This commit is contained in:
sofio
2026-02-03 15:47:03 +08:00
parent 94b39b2099
commit e87c9006a8
52 changed files with 5762 additions and 119 deletions

View File

@@ -0,0 +1,83 @@
import { getTranslations } from "next-intl/server";
export default async function AICapabilitiesSection() {
const t = await getTranslations("aiCap");
const aiCards = [
{
num: t("card1Num"),
title: t("card1Title"),
desc: t("card1Desc"),
metrics: [
{ label: t("card1Metric1Label"), value: t("card1Metric1Value") },
{ label: t("card1Metric2Label"), value: t("card1Metric2Value") },
],
},
{
num: t("card2Num"),
title: t("card2Title"),
desc: t("card2Desc"),
metrics: [
{ label: t("card2Metric1Label"), value: t("card2Metric1Value") },
{ label: t("card2Metric2Label"), value: t("card2Metric2Value") },
],
},
{
num: t("card3Num"),
title: t("card3Title"),
desc: t("card3Desc"),
metrics: [
{ label: t("card3Metric1Label"), value: t("card3Metric1Value") },
{ label: t("card3Metric2Label"), value: t("card3Metric2Value") },
],
},
{
num: t("card4Num"),
title: t("card4Title"),
desc: t("card4Desc"),
metrics: [
{ label: t("card4Metric1Label"), value: t("card4Metric1Value") },
{ label: t("card4Metric2Label"), value: t("card4Metric2Value") },
],
},
];
return (
<section className="section section--light">
<div className="cap-header">
<div className="cap-header-left">
<div className="cap-divider">
<span className="cap-divider-line" />
<span className="cap-divider-label">{t("label")}</span>
</div>
<h2 className="cap-title">{t("title")}</h2>
<p className="cap-subtitle">{t("subtitle")}</p>
</div>
<div className="cap-header-right">
<span className="cap-big-number">{t("moduleCount")}</span>
<span className="cap-metric-label">{t("moduleLabel")}</span>
</div>
</div>
<div className="cap-grid">
{aiCards.map((card) => (
<div key={card.num} className="cap-card cap-card--light">
<div className="cap-card-header">
<span className="cap-card-num">{card.num}</span>
<h3 className="cap-card-title">{card.title}</h3>
</div>
<p className="cap-card-desc">{card.desc}</p>
<div className="cap-card-metrics">
{card.metrics.map((m) => (
<div key={m.label} className="cap-card-metric">
<span className="cap-card-metric-label">{m.label}</span>
<span className="cap-card-metric-value">{m.value}</span>
</div>
))}
</div>
</div>
))}
</div>
</section>
);
}

View File

@@ -0,0 +1,60 @@
import { getTranslations } from "next-intl/server";
export default async function AboutHeroSection() {
const t = await getTranslations("aboutHero");
const capabilities = [
{ icon: t("cap1Icon"), label: t("cap1Label") },
{ icon: t("cap2Icon"), label: t("cap2Label") },
{ icon: t("cap3Icon"), label: t("cap3Label") },
{ icon: t("cap4Icon"), label: t("cap4Label") },
];
const strategies = [
{ tag: t("strat1Tag"), title: t("strat1Title"), desc: t("strat1Desc") },
{ tag: t("strat2Tag"), title: t("strat2Title"), desc: t("strat2Desc") },
];
return (
<section className="about-hero-section">
<div className="about-hero-content">
<span className="about-hero-label">{t("label")}</span>
<h1 className="about-hero-title">{t("title")}</h1>
<p className="about-hero-subtitle">{t("subtitle")}</p>
<div className="about-hero-vision">
<span className="about-hero-vision-label">{t("visionLabel")}</span>
<span className="about-hero-vision-text">{t("visionText")}</span>
</div>
</div>
<div className="about-sub-block">
<div className="about-divider-label">
<span className="about-divider-label-text">{t("capLabel")}</span>
</div>
<div className="about-cap-grid">
{capabilities.map((cap) => (
<div key={cap.icon} className="about-cap-card">
<span className="about-cap-icon">{cap.icon}</span>
<span className="about-cap-text">{cap.label}</span>
</div>
))}
</div>
</div>
<div className="about-sub-block">
<div className="about-divider-label">
<span className="about-divider-label-text">{t("stratLabel")}</span>
</div>
<div className="about-strat-grid">
{strategies.map((s) => (
<div key={s.tag} className="about-strat-card">
<span className="about-strat-tag">{s.tag}</span>
<h3 className="about-strat-title">{s.title}</h3>
<span className="about-strat-desc">{s.desc}</span>
</div>
))}
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,50 @@
import { getTranslations } from "next-intl/server";
export default async function ArchitectureSection() {
const t = await getTranslations("architecture");
return (
<section className="section section--dark">
<div className="section-header">
<div className="decorated-tag">
<span className="decorated-tag-line decorated-tag-line--dark" />
<span className="decorated-tag-text">{t("tag")}</span>
<span className="decorated-tag-line decorated-tag-line--dark" />
</div>
<h2 className="heading-section">{t("title")}</h2>
</div>
<div className="arch-diagram">
<div className="arch-top">
<span className="arch-top-label">{t("topLabel")}</span>
<span className="arch-top-desc">{t("topDesc")}</span>
</div>
<div className="arch-connector">
<div className="arch-vert-line" />
<span className="arch-connector-icon"></span>
</div>
<div className="arch-engines">
<div className="arch-engine arch-engine--light">
<span className="arch-engine-label">{t("engine1Label")}</span>
<h3 className="arch-engine-title arch-engine-title--dark">{t("engine1Title")}</h3>
<span className="arch-engine-desc">{t("engine1Desc")}</span>
</div>
<div className="arch-middle">
<span className="arch-arrow"></span>
<span className="arch-middle-label">{t("middleLabel")}</span>
<span className="arch-arrow"></span>
</div>
<div className="arch-engine arch-engine--dark">
<span className="arch-engine-label arch-engine-label--dim">{t("engine2Label")}</span>
<h3 className="arch-engine-title">{t("engine2Title")}</h3>
<span className="arch-engine-desc arch-engine-desc--muted">{t("engine2Desc")}</span>
</div>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,22 @@
import { getTranslations } from "next-intl/server";
import { Link } from "@/i18n/navigation";
import { ArrowRight } from "lucide-react";
export default async function CTASection() {
const t = await getTranslations("cta");
return (
<section className="section section--light cta">
<h2 className="heading-cta heading-cta--light">{t("title")}</h2>
<div className="cta-buttons">
<Link href="/solutions" className="btn btn--dark">
<span>{t("services")}</span>
<ArrowRight size={16} />
</Link>
<Link href="/contact" className="btn btn--outline-dark">
{t("contact")}
</Link>
</div>
</section>
);
}

View File

@@ -0,0 +1,68 @@
import { getTranslations } from "next-intl/server";
export default async function FlywheelSection() {
const t = await getTranslations("flywheel");
const cards = [
{
tag: t("card1Tag"),
title: t("card1Title"),
subtitle: t("card1Subtitle"),
desc: t("card1Desc"),
features: [t("card1Feature1"), t("card1Feature2")],
},
{
tag: t("card2Tag"),
title: t("card2Title"),
subtitle: t("card2Subtitle"),
desc: t("card2Desc"),
features: [t("card2Feature1"), t("card2Feature2"), t("card2Feature3")],
},
{
tag: t("card3Tag"),
title: t("card3Title"),
subtitle: t("card3Subtitle"),
desc: t("card3Desc"),
features: [t("card3Feature1"), t("card3Feature2"), t("card3Feature3")],
},
];
const summarySteps = [t("summary1"), t("summary2"), t("summary3")];
return (
<section className="section section--dark">
<div className="section-header">
<span className="label-text">{t("label")}</span>
<h2 className="heading-section">{t("title")}</h2>
<p className="body-text">{t("subtitle")}</p>
</div>
<div className="flywheel-cards">
{cards.map((card) => (
<div key={card.title} className="flywheel-card">
<span className="label-text">{card.tag}</span>
<h3 className="flywheel-card-title">{card.title}</h3>
<span className="body-text">{card.subtitle}</span>
<p className="body-text body-text--muted">{card.desc}</p>
<ul className="flywheel-features">
{card.features.map((f) => (
<li key={f} className="body-text body-text--sm body-text--muted">
{f}
</li>
))}
</ul>
</div>
))}
</div>
<div className="flywheel-summary">
{summarySteps.map((step, i) => (
<span key={step} className="flywheel-summary-item">
{i > 0 && <span className="flywheel-arrow"></span>}
<span className="body-text body-text--muted">{step}</span>
</span>
))}
</div>
</section>
);
}

117
src/components/Footer.tsx Normal file
View File

@@ -0,0 +1,117 @@
import { Link } from "@/i18n/navigation";
import { getTranslations } from "next-intl/server";
function WeChatIcon({ size = 16 }: { size?: number }) {
return (
<svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
<path d="M8.691 2.188C3.891 2.188 0 5.476 0 9.53c0 2.212 1.17 4.203 3.002 5.55a.59.59 0 0 1 .213.665l-.39 1.48c-.019.07-.048.141-.048.213 0 .163.13.295.29.295a.326.326 0 0 0 .167-.054l1.903-1.114a.864.864 0 0 1 .717-.098 10.16 10.16 0 0 0 2.837.403c.276 0 .543-.027.811-.05a6.329 6.329 0 0 1-.235-1.69c0-3.542 3.276-6.426 7.315-6.426.348 0 .688.029 1.023.074C16.088 4.68 12.727 2.189 8.691 2.189zM5.785 5.991a1.09 1.09 0 0 1 1.083 1.09 1.09 1.09 0 0 1-1.083 1.09A1.09 1.09 0 0 1 4.7 7.08a1.09 1.09 0 0 1 1.085-1.09zm5.88 0a1.09 1.09 0 0 1 1.083 1.09 1.09 1.09 0 0 1-1.083 1.09 1.09 1.09 0 0 1-1.085-1.09 1.09 1.09 0 0 1 1.085-1.09zm2.927 3.525c-3.508 0-6.36 2.51-6.36 5.596 0 3.088 2.852 5.596 6.36 5.596a7.5 7.5 0 0 0 2.36-.382.636.636 0 0 1 .527.074l1.402.822a.244.244 0 0 0 .122.04.214.214 0 0 0 .213-.217c0-.053-.02-.105-.035-.156l-.286-1.09a.432.432 0 0 1 .156-.488c1.352-.998 2.22-2.465 2.22-4.1 0-3.087-2.853-5.596-6.36-5.596h-.319zm-1.834 2.89a.905.905 0 0 1 .9.907.905.905 0 0 1-.9.906.905.905 0 0 1-.902-.906.905.905 0 0 1 .902-.906zm3.99 0a.905.905 0 0 1 .9.907.905.905 0 0 1-.9.906.905.905 0 0 1-.902-.906.905.905 0 0 1 .901-.906z" />
</svg>
);
}
function LinkedInIcon({ size = 16 }: { size?: number }) {
return (
<svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
</svg>
);
}
function XIcon({ size = 16 }: { size?: number }) {
return (
<svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
<path d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z" />
</svg>
);
}
function MailIcon({ size = 16 }: { size?: number }) {
return (
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round">
<rect x="2" y="4" width="20" height="16" rx="2" />
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
</svg>
);
}
const socialIcons = [
{ icon: WeChatIcon, label: "WeChat" },
{ icon: LinkedInIcon, label: "LinkedIn" },
{ icon: XIcon, label: "X" },
{ icon: MailIcon, label: "Email" },
];
export default async function Footer() {
const t = await getTranslations("footer");
const th = await getTranslations("header");
const pageLinks = [
{ label: th("home"), href: "/" as const },
{ label: th("tech"), href: "/tech" as const },
{ label: th("solutions"), href: "/solutions" as const },
{ label: th("about"), href: "/about" as const },
];
const businessLinks = [
{ label: t("bizDeSpace"), href: "#" as const },
{ label: t("bizRWA"), href: "#" as const },
{ label: t("bizQuant"), href: "#" as const },
];
return (
<footer className="footer">
<div className="footer-main">
<div className="footer-brand">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src="/logo.png"
alt="DESUN SINGULARITY"
width={160}
height={46}
className="footer-logo-img"
/>
<p className="footer-tagline">{t("tagline")}</p>
<div className="footer-contact">
<span className="footer-contact-label">{t("contactLabel")}</span>
<div className="footer-social">
{socialIcons.map((item) => (
<a
key={item.label}
href="#"
className="footer-social-icon"
aria-label={item.label}
>
<item.icon size={16} />
</a>
))}
</div>
</div>
</div>
<div className="footer-links">
<div className="footer-col">
<span className="footer-col-title">{t("pagesTitle")}</span>
{pageLinks.map((link) => (
<Link key={link.href} href={link.href} className="footer-link">
{link.label}
</Link>
))}
</div>
<div className="footer-col">
<span className="footer-col-title">{t("businessTitle")}</span>
{businessLinks.map((link) => (
<a key={link.label} href={link.href} className="footer-link">
{link.label}
</a>
))}
</div>
</div>
</div>
<div className="footer-divider" />
<div className="footer-bottom">
<span className="footer-copyright">{t("copyright")}</span>
</div>
</footer>
);
}

91
src/components/Header.tsx Normal file
View File

@@ -0,0 +1,91 @@
"use client";
import Image from "next/image";
import { Link, usePathname } from "@/i18n/navigation";
import { useTranslations } from "next-intl";
import { useState } from "react";
import { Menu, X } from "lucide-react";
import LanguageSwitcher from "./LanguageSwitcher";
export default function Header() {
const pathname = usePathname();
const t = useTranslations("header");
const [mobileOpen, setMobileOpen] = useState(false);
const navItems = [
{ label: t("home"), href: "/" as const },
{ label: t("tech"), href: "/tech" as const },
{ label: t("solutions"), href: "/solutions" as const },
{ label: t("about"), href: "/about" as const },
];
return (
<header className="header">
<Link href="/" className="logo">
<Image
src="/logo.png"
alt="DESUN SINGULARITY"
width={140}
height={40}
priority
/>
</Link>
<nav className="nav">
{navItems.map((item) => (
<Link
key={item.href}
href={item.href}
className={`nav-item ${pathname === item.href ? "nav-item-active" : ""}`}
>
{item.label}
</Link>
))}
</nav>
<div className="header-right">
<LanguageSwitcher />
<Link href="/contact" className="contact-btn">
{t("contact")}
</Link>
</div>
{/* Mobile hamburger */}
<button
className="mobile-menu-btn"
onClick={() => setMobileOpen(!mobileOpen)}
aria-label="Toggle menu"
>
{mobileOpen ? <X size={22} /> : <Menu size={22} />}
</button>
{/* Mobile overlay */}
{mobileOpen && (
<div className="mobile-overlay" onClick={() => setMobileOpen(false)}>
<nav className="mobile-nav" onClick={(e) => e.stopPropagation()}>
{navItems.map((item) => (
<Link
key={item.href}
href={item.href}
className={`mobile-nav-item ${pathname === item.href ? "mobile-nav-item--active" : ""}`}
onClick={() => setMobileOpen(false)}
>
{item.label}
</Link>
))}
<div className="mobile-nav-footer">
<LanguageSwitcher />
<Link
href="/contact"
className="contact-btn"
onClick={() => setMobileOpen(false)}
>
{t("contact")}
</Link>
</div>
</nav>
</div>
)}
</header>
);
}

View File

@@ -0,0 +1,31 @@
import { getTranslations } from "next-intl/server";
export default async function HeroSection() {
const t = await getTranslations("hero");
const metrics = [
{ label: t("metric1Label"), value: t("metric1Value"), desc: t("metric1Desc") },
{ label: t("metric2Label"), value: t("metric2Value"), desc: t("metric2Desc") },
{ label: t("metric3Label"), value: t("metric3Value"), desc: t("metric3Desc") },
{ label: t("metric4Label"), value: t("metric4Value"), desc: t("metric4Desc") },
];
return (
<section className="section section--light hero">
<div className="hero-content">
<span className="label-text">{t("label")}</span>
<h1 className="heading-display">{t("title")}</h1>
<p className="body-text body-text--lg">{t("subtitle")}</p>
</div>
<div className="metric-grid">
{metrics.map((m) => (
<div key={m.label} className="metric-card">
<span className="label-text">{m.label}</span>
<span className="metric-value">{m.value}</span>
<span className="body-text body-text--sm">{m.desc}</span>
</div>
))}
</div>
</section>
);
}

View File

@@ -0,0 +1,57 @@
"use client";
import { usePathname, useRouter } from "@/i18n/navigation";
import { useLocale } from "next-intl";
import { locales, localeNames, type Locale } from "@/i18n/config";
import {
Dropdown,
DropdownTrigger,
DropdownMenu,
DropdownItem,
Button,
} from "@heroui/react";
import type { Selection } from "@heroui/react";
import { ChevronDown } from "lucide-react";
export default function LanguageSwitcher() {
const locale = useLocale() as Locale;
const router = useRouter();
const pathname = usePathname();
function handleSelectionChange(keys: Selection) {
const next = Array.from(keys)[0] as Locale;
if (next && next !== locale) {
document.cookie = `NEXT_LOCALE=${next};path=/;max-age=31536000`;
router.replace(pathname, { locale: next });
}
}
return (
<Dropdown>
<DropdownTrigger>
<Button
variant="bordered"
size="sm"
className="lang-switcher-trigger"
endContent={<ChevronDown size={12} />}
>
{localeNames[locale]}
</Button>
</DropdownTrigger>
<DropdownMenu
aria-label="Language"
selectionMode="single"
selectedKeys={new Set([locale])}
disallowEmptySelection
onSelectionChange={handleSelectionChange}
className="lang-switcher-menu"
>
{locales.map((l) => (
<DropdownItem key={l} className="lang-switcher-item">
{localeNames[l]}
</DropdownItem>
))}
</DropdownMenu>
</Dropdown>
);
}

View File

@@ -0,0 +1,30 @@
import { getTranslations } from "next-intl/server";
export default async function MarketSection() {
const t = await getTranslations("market");
const marketData = [
{ label: t("metric1Label"), value: t("metric1Value"), desc: t("metric1Desc") },
{ label: t("metric2Label"), value: t("metric2Value"), desc: t("metric2Desc") },
{ label: t("metric3Label"), value: t("metric3Value"), desc: t("metric3Desc") },
];
return (
<section className="section section--light">
<div className="section-header">
<span className="label-text">{t("label")}</span>
<h2 className="heading-section heading-section--dark">{t("title")}</h2>
<p className="body-text">{t("subtitle")}</p>
</div>
<div className="metric-grid metric-grid--3">
{marketData.map((m) => (
<div key={m.label} className="metric-card metric-card--tall">
<span className="label-text">{m.label}</span>
<span className="metric-value">{m.value}</span>
<span className="body-text body-text--sm">{m.desc}</span>
</div>
))}
</div>
</section>
);
}

View File

@@ -0,0 +1,49 @@
import { getTranslations } from "next-intl/server";
export default async function MilestonesSection() {
const t = await getTranslations("milestones");
const milestones = [
{ date: t("ms1Date"), title: t("ms1Title"), desc: t("ms1Desc") },
{ date: t("ms2Date"), title: t("ms2Title"), desc: t("ms2Desc") },
{ date: t("ms3Date"), title: t("ms3Title"), desc: t("ms3Desc") },
{ date: t("ms4Date"), title: t("ms4Title"), desc: t("ms4Desc") },
];
return (
<section className="about-section about-section--dark">
<div className="about-sub-block">
<div className="about-divider-label about-divider-label--dark">
<div className="about-divider-label-row">
<span className="about-divider-label-text about-divider-label-text--muted">
{t("label")}
</span>
<span className="about-mono-tag">{t("tag")}</span>
</div>
</div>
<h2 className="about-section-title about-section-title--light">
{t("title")}
</h2>
</div>
<div className="timeline">
{milestones.map((ms) => (
<div key={ms.title} className="timeline-item">
<span className="timeline-date">{ms.date}</span>
<div className="timeline-content">
<span className="timeline-title">{ms.title}</span>
<span className="timeline-desc">{ms.desc}</span>
</div>
</div>
))}
<div className="timeline-item timeline-item--last">
<span className="timeline-date timeline-date--dim">{t("continueDate")}</span>
<div className="timeline-content">
<span className="timeline-title timeline-title--dim">{t("continueTitle")}</span>
<span className="timeline-desc timeline-desc--dim">{t("continueDesc")}</span>
</div>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,64 @@
import { getTranslations } from "next-intl/server";
export default async function ParentCompanySection() {
const t = await getTranslations("parentCompany");
const metrics = [
{ value: t("metric1Value"), label: t("metric1Label") },
{ value: t("metric2Value"), label: t("metric2Label") },
{ value: t("metric3Value"), label: t("metric3Label") },
{ value: t("metric4Value"), label: t("metric4Label") },
{ value: t("metric5Value"), label: t("metric5Label") },
];
const bizTypes = [
{ title: t("biz1Title"), stats: t("biz1Stats") },
{ title: t("biz2Title"), stats: t("biz2Stats") },
{ title: t("biz3Title"), stats: t("biz3Stats") },
{ title: t("biz4Title"), stats: t("biz4Stats") },
];
return (
<section className="about-section about-section--dark">
<div className="about-sub-block">
<div className="about-divider-label about-divider-label--dark">
<div className="about-divider-label-row">
<span className="about-divider-label-text about-divider-label-text--muted">
{t("bgLabel")}
</span>
<span className="about-mono-tag">{t("stockCode")}</span>
</div>
</div>
<h2 className="about-section-title about-section-title--light">
{t("title")}
</h2>
<p className="about-body-lg">{t("subtitle")}</p>
</div>
<div className="parent-metric-grid">
{metrics.map((m) => (
<div key={m.label} className="parent-metric-card">
<span className="parent-metric-value">{m.value}</span>
<span className="parent-metric-label">{m.label}</span>
</div>
))}
</div>
<div className="about-sub-block">
<div className="about-divider-label about-divider-label--dark">
<span className="about-divider-label-text about-divider-label-text--dim">
{t("bizLabel")}
</span>
</div>
<div className="parent-biz-grid">
{bizTypes.map((b) => (
<div key={b.title} className="parent-biz-card">
<span className="parent-biz-title">{b.title}</span>
<span className="parent-biz-stats">{b.stats}</span>
</div>
))}
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,7 @@
"use client";
import { HeroUIProvider } from "@heroui/react";
export default function Providers({ children }: { children: React.ReactNode }) {
return <HeroUIProvider>{children}</HeroUIProvider>;
}

View File

@@ -0,0 +1,46 @@
import { getTranslations } from "next-intl/server";
export default async function RecruitSection() {
const t = await getTranslations("recruit");
const positions = [t("pos1"), t("pos2"), t("pos3"), t("pos4")];
return (
<section className="about-section about-section--light">
<div className="about-sub-block">
<div className="about-divider-label">
<div className="about-divider-label-row">
<span className="about-divider-label-text">{t("label")}</span>
<span className="about-mono-tag about-mono-tag--muted">{t("tag")}</span>
</div>
</div>
<h2 className="recruit-title">{t("title")}</h2>
</div>
<div className="recruit-content">
<div className="recruit-left">
<span className="recruit-col-label">{t("positionsLabel")}</span>
<div className="recruit-positions">
{positions.map((pos, i) => (
<div
key={pos}
className={`recruit-pos${i < positions.length - 1 ? " recruit-pos--border" : ""}`}
>
<span className="recruit-pos-title">{pos}</span>
<span className="recruit-pos-arrow">&rarr;</span>
</div>
))}
</div>
</div>
<div className="recruit-right">
<span className="recruit-col-label">{t("newsLabel")}</span>
<div className="recruit-news-placeholder">
<span style={{ fontSize: 32 }}>📰</span>
<span className="recruit-news-text">{t("newsPlaceholder")}</span>
<span className="recruit-news-desc">{t("newsDesc")}</span>
</div>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,121 @@
import { getTranslations } from "next-intl/server";
interface ScenarioData {
variant: "dark" | "light";
label: string;
tag: string;
titles: [string, string];
ai: {
desc: string;
benefit: string;
metrics?: { label: string; value: string }[];
};
web3: {
desc: string;
benefit: string;
};
steps: string[];
}
export default async function ScenarioSection({ data }: { data: ScenarioData }) {
const t = await getTranslations("scenario");
const isDark = data.variant === "dark";
return (
<section className={`section ${isDark ? "section--dark" : "section--light"}`}>
{/* Header */}
<div className="scenario-header">
<div className={`scenario-divider-row ${isDark ? "scenario-divider-row--dark" : ""}`}>
<span className={`scenario-label ${isDark ? "scenario-label--muted" : ""}`}>
{data.label}
</span>
<span className="scenario-tag">{data.tag}</span>
</div>
<h2 className={`scenario-title ${isDark ? "scenario-title--light" : ""}`}>
{data.titles[0]}
</h2>
<h2 className={`scenario-title ${isDark ? "scenario-title--light" : ""}`}>
{data.titles[1]}
</h2>
</div>
{/* Content */}
<div className="scenario-content">
{/* Left: AI + Web3 blocks */}
<div className="scenario-left">
{/* AI Block */}
<div className={`scenario-block ${isDark ? "scenario-block--dark" : ""}`}>
<div className="scenario-block-header">
<div className={`scenario-icon ${isDark ? "scenario-icon--light" : "scenario-icon--dark"}`}>
<span className={`scenario-icon-text ${isDark ? "scenario-icon-text--dark" : "scenario-icon-text--light"}`}>
AI
</span>
</div>
<span className={`scenario-block-label ${isDark ? "scenario-block-label--light" : ""}`}>
{t("aiLabel")}
</span>
</div>
<p className="scenario-block-desc">{data.ai.desc}</p>
{data.ai.metrics && (
<div className="scenario-metrics">
{data.ai.metrics.map((m) => (
<div key={m.label} className="scenario-metric">
<span className={`scenario-metric-value ${isDark ? "scenario-metric-value--light" : ""}`}>
{m.value}
</span>
<span className="scenario-metric-label">{m.label}</span>
</div>
))}
</div>
)}
{!data.ai.metrics && (
<span className={`scenario-benefit ${isDark ? "scenario-benefit--light" : ""}`}>
{data.ai.benefit}
</span>
)}
</div>
{/* Web3 Block */}
<div className={`scenario-block ${isDark ? "scenario-block--dark" : ""}`}>
<div className="scenario-block-header">
<div className={`scenario-icon scenario-icon--outline ${isDark ? "scenario-icon--outline-light" : "scenario-icon--outline-dark"}`}>
<span className={`scenario-icon-text ${isDark ? "scenario-icon-text--light" : ""}`}>
W3
</span>
</div>
<span className={`scenario-block-label ${isDark ? "scenario-block-label--light" : ""}`}>
{t("web3Label")}
</span>
</div>
<p className="scenario-block-desc">{data.web3.desc}</p>
<span className={`scenario-benefit ${isDark ? "scenario-benefit--light" : ""}`}>
{data.web3.benefit}
</span>
</div>
</div>
{/* Right: Process steps */}
<div className="scenario-right">
<span className={`scenario-process-label ${isDark ? "scenario-process-label--dim" : ""}`}>
{t("processLabel")}
</span>
<div className="scenario-steps">
{data.steps.map((step, i) => (
<div
key={step}
className={`scenario-step ${i < data.steps.length - 1 ? (isDark ? "scenario-step--border-dark" : "scenario-step--border") : ""}`}
>
<span className={`scenario-step-num ${isDark ? "scenario-step-num--dim" : ""}`}>
{String(i + 1).padStart(2, "0")}
</span>
<span className={`scenario-step-text ${isDark ? "scenario-step-text--light" : ""}`}>
{step}
</span>
</div>
))}
</div>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,18 @@
import { getTranslations } from "next-intl/server";
import { Link } from "@/i18n/navigation";
export default async function SolutionsCTASection() {
const t = await getTranslations("solCta");
return (
<section className="section section--light" style={{ gap: 32 }}>
<div className="sol-cta-divider" />
<h2 className="heading-section heading-section--dark">{t("title")}</h2>
<p className="body-text body-text--lg sol-cta-desc">{t("desc")}</p>
<Link href="/contact" className="btn btn--dark" style={{ gap: 8 }}>
<span>{t("contact")}</span>
<span></span>
</Link>
</section>
);
}

View File

@@ -0,0 +1,56 @@
import { getTranslations } from "next-intl/server";
export default async function SolutionsHeroSection() {
const t = await getTranslations("solHero");
const flowCards = [
{
num: t("flow1Num"),
title: t("flow1Title"),
sub: t("flow1Sub"),
ai: t("flow1AI"),
web3: t("flow1Web3"),
},
{
num: t("flow2Num"),
title: t("flow2Title"),
sub: t("flow2Sub"),
ai: t("flow2AI"),
web3: t("flow2Web3"),
},
{
num: t("flow3Num"),
title: t("flow3Title"),
sub: t("flow3Sub"),
ai: t("flow3AI"),
web3: t("flow3Web3"),
},
];
return (
<section className="section section--light">
<div className="section-header" style={{ gap: 24 }}>
<span className="label-text">{t("label")}</span>
<h1 className="sol-hero-title">{t("title")}</h1>
<h2 className="sol-hero-subtitle">{t("subtitle")}</h2>
<p className="body-text body-text--lg sol-hero-desc">{t("desc")}</p>
</div>
<div className="flow-diagram">
{flowCards.map((card, i) => (
<div key={card.num} className="flow-item">
{i > 0 && <span className="flow-arrow"></span>}
<div className="flow-card">
<span className="flow-card-num">{card.num}</span>
<h3 className="flow-card-title">{card.title}</h3>
<span className="flow-card-sub">{card.sub}</span>
<div className="flow-card-divider" />
<span className="flow-card-tag">{card.ai}</span>
<span className="flow-card-tag">{card.web3}</span>
</div>
</div>
))}
</div>
</section>
);
}

View File

@@ -0,0 +1,55 @@
import { getTranslations } from "next-intl/server";
function MemberCard({ role, name, bio }: { role: string; name: string; bio: string }) {
return (
<div className="team-card">
<span className="team-card-role">{role}</span>
<h3 className="team-card-name">{name}</h3>
<p className="team-card-bio">{bio}</p>
</div>
);
}
export default async function TeamSection() {
const t = await getTranslations("team");
const teamRow1 = [
{ role: t("ceo"), name: t("ceoName"), bio: t("ceoBio") },
{ role: t("coo"), name: t("cooName"), bio: t("cooBio") },
{ role: t("cmo"), name: t("cmoName"), bio: t("cmoBio") },
{ role: t("cto"), name: t("ctoName"), bio: t("ctoBio") },
];
const teamRow2 = [
{ role: t("cio"), name: t("cioName"), bio: t("cioBio") },
{ role: t("strategist"), name: t("strategistName"), bio: t("strategistBio") },
{ role: t("analyst"), name: t("analystName"), bio: t("analystBio") },
];
return (
<section className="about-section about-section--light">
<div className="about-sub-block">
<div className="about-divider-label">
<div className="about-divider-label-row">
<span className="about-divider-label-text">{t("label")}</span>
<span className="about-count-tag">{t("count")}</span>
</div>
</div>
<h2 className="team-title">{t("title")}</h2>
</div>
<div className="team-grid">
<div className="team-row team-row--4">
{teamRow1.map((m) => (
<MemberCard key={m.name} {...m} />
))}
</div>
<div className="team-row team-row--3">
{teamRow2.map((m) => (
<MemberCard key={m.name} {...m} />
))}
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,20 @@
import { getTranslations } from "next-intl/server";
import { Link } from "@/i18n/navigation";
export default async function TechCTASection() {
const t = await getTranslations("techCta");
return (
<section className="section section--light cta">
<h2 className="heading-section heading-section--dark">{t("title")}</h2>
<div className="cta-buttons">
<Link href="/solutions" className="btn btn--dark">
{t("solutions")}
</Link>
<Link href="/contact" className="btn btn--outline-dark">
{t("contact")}
</Link>
</div>
</section>
);
}

View File

@@ -0,0 +1,18 @@
import { getTranslations } from "next-intl/server";
export default async function TechHeroSection() {
const t = await getTranslations("techHero");
return (
<section className="section section--light tech-hero">
<div className="decorated-tag">
<span className="decorated-tag-line" />
<span className="decorated-tag-text">{t("tag")}</span>
<span className="decorated-tag-line" />
</div>
<h1 className="heading-display">{t("title1")}</h1>
<h1 className="heading-display">{t("title2")}</h1>
<p className="body-text body-text--lg tech-hero-subtitle">{t("subtitle")}</p>
</section>
);
}

View File

@@ -0,0 +1,44 @@
import { getTranslations } from "next-intl/server";
export default async function Web3CapabilitiesSection() {
const t = await getTranslations("web3Cap");
const web3Cards = [
{ num: t("card1Num"), title: t("card1Title"), desc: t("card1Desc"), value: t("card1Value") },
{ num: t("card2Num"), title: t("card2Title"), desc: t("card2Desc"), value: t("card2Value") },
{ num: t("card3Num"), title: t("card3Title"), desc: t("card3Desc"), value: t("card3Value") },
{ num: t("card4Num"), title: t("card4Title"), desc: t("card4Desc"), value: t("card4Value") },
];
return (
<section className="section section--dark">
<div className="cap-header">
<div className="cap-header-left">
<div className="cap-divider cap-divider--dark">
<span className="cap-divider-line cap-divider-line--dark" />
<span className="cap-divider-label">{t("label")}</span>
</div>
<h2 className="cap-title cap-title--light">{t("title")}</h2>
<p className="cap-subtitle cap-subtitle--muted">{t("subtitle")}</p>
</div>
<div className="cap-header-right">
<span className="cap-big-number cap-big-number--light">{t("moduleCount")}</span>
<span className="cap-metric-label">{t("moduleLabel")}</span>
</div>
</div>
<div className="cap-grid cap-grid--dark">
{web3Cards.map((card) => (
<div key={card.num} className="cap-card cap-card--dark">
<div className="cap-card-header">
<span className="cap-card-num cap-card-num--dim">{card.num}</span>
<h3 className="cap-card-title cap-card-title--light">{card.title}</h3>
</div>
<p className="cap-card-desc cap-card-desc--muted">{card.desc}</p>
<span className="cap-card-value">{card.value}</span>
</div>
))}
</div>
</section>
);
}