feat: 添加企业官网首页及关于页面

This commit is contained in:
asgerzhou
2026-07-28 11:36:52 +08:00
parent 6a3db4e620
commit c4e2ed6cc3
44 changed files with 824 additions and 66 deletions
+2 -1
View File
@@ -42,5 +42,6 @@
"tailwindcss": "^4",
"tsx": "^4.23.0",
"typescript": "^5"
}
},
"packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 MiB

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="42.5005" height="33.1625" viewBox="0 0 42.5005 33.1625" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="&#229;&#133;&#168;&#229;&#165;&#151;&#230;&#150;&#185;&#230;&#161;&#136;icon" d="M42.2794 11.1L36.2194 0.92C35.9594 0.39 35.3994 0 34.7394 0H7.76937V0.02C7.20937 0.02 6.66937 0.29 6.36937 0.82L0.309366 10.96C-0.150634 11.61 -0.100634 12.51 0.479366 13.07L20.0594 32.67L20.1094 32.69C20.7494 33.32 21.7694 33.32 22.4094 32.69L42.0194 13.06H42.0094C42.5294 12.54 42.6694 11.72 42.2694 11.08L42.2794 11.1ZM32.5994 3.27L28.6794 9.7C28.6194 9.7 28.5594 9.7 28.5094 9.7C28.3794 9.7 28.2594 9.71 28.1394 9.73L23.6094 3.27H32.6094H32.5994ZM26.5594 10.9C26.5594 10.9 26.5494 10.92 26.5394 10.94H16.1894C16.1494 10.87 16.1194 10.79 16.0694 10.73L21.2594 3.35L26.5494 10.91L26.5594 10.9ZM18.9094 3.27L14.4094 9.7C14.3494 9.7 14.2894 9.7 14.2294 9.7C14.0994 9.7 13.9794 9.71 13.8594 9.73L9.89937 3.27H18.9094ZM8.17937 4.16L12.2894 10.9C12.2894 10.9 12.2794 10.92 12.2694 10.94H4.11937L8.17937 4.16ZM4.90937 12.91H12.3194C12.6194 13.46 13.1494 13.86 13.7694 14L18.2594 26.25L4.90937 12.91ZM21.2694 28.71L15.6694 13.49C15.8594 13.32 16.0194 13.12 16.1394 12.9H26.5894C26.6794 13.06 26.7794 13.2 26.8994 13.34L21.2594 28.71H21.2694ZM24.2394 26.25L28.7194 14.04C29.4494 13.97 30.0794 13.53 30.4094 12.91H37.5594L24.2294 26.25H24.2394ZM30.4694 10.94C30.4294 10.86 30.3894 10.79 30.3494 10.71L34.3594 4.16L38.3894 10.94H30.4694Z" fill="var(--fill-0, white)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+16
View File
@@ -0,0 +1,16 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="34.88" height="33.86" viewBox="0 0 34.88 33.86" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="&#228;&#184;&#128;&#228;&#189;&#147;&#229;&#140;&#150;icon" clip-path="url(#clip0_4_375)">
<path id="Vector" d="M34.33 4.64L33.54 2.78L30.37 5.97L29.49 5.99L29.51 5.2L32.71 1.96L30.85 1.16C29.47 0.56 27.91 0.44 26.45 0.84C22.88 1.82 20.78 5.5 21.74 9.09L18.15 12.7L17.05 13.81L15.1 15.76L13.93 16.94L10.4 20.49C8.93 20.09 7.39 20.2 6 20.8C2.61 22.3 1.06 26.25 2.51 29.65L3.3 31.54L6.55 28.3L7.33 28.28L7.31 29.17L4.14 32.36L6 33.16C7.38 33.76 8.93 33.88 10.38 33.47C13.95 32.48 16.05 28.8 15.09 25.22L18.12 22.17L19.78 20.5L21.73 18.54L24.45 15.79L26.44 13.78C27.91 14.18 29.45 14.07 30.84 13.47C34.22 12 35.77 8.05 34.3 4.64H34.33Z" fill="var(--fill-0, white)"/>
<g id="Group">
<path id="Vector_2" d="M7.27714 1.33537L1.35209 7.14775C0.88687 7.60413 0.879698 8.35123 1.33607 8.81645L6.75629 14.3417C7.21266 14.807 7.95976 14.8141 8.42499 14.3578L14.35 8.54538C14.8153 8.089 14.8224 7.3419 14.3661 6.87668L8.94584 1.35139C8.48947 0.886172 7.74236 0.879001 7.27714 1.33537Z" stroke="var(--stroke-0, white)" stroke-width="2" stroke-miterlimit="10"/>
<path id="Vector_3" d="M21.0911 27.408L27.1518 21.4625L31.2485 25.6386C32.8871 27.3091 32.8683 30.0031 31.1908 31.6488C29.5203 33.2874 26.8263 33.2686 25.1806 31.5911L21.084 27.415L21.0911 27.408Z" stroke="var(--stroke-0, white)" stroke-width="2" stroke-miterlimit="10"/>
<path id="Vector_4" d="M12.868 9.99451L9.8983 12.9077L21.1099 24.3366L24.0796 21.4234L12.868 9.99451Z" stroke="var(--stroke-0, white)" stroke-width="2" stroke-miterlimit="10"/>
<path id="Vector_5" d="M25.8784 18.4154L18.0617 26.0835C17.5491 26.5863 17.5412 27.4094 18.044 27.9219L18.9404 28.8357C19.4432 29.3482 20.2662 29.3561 20.7788 28.8533L28.5955 21.1852C29.1081 20.6824 29.116 19.8593 28.6132 19.3468L27.7168 18.4331C27.214 17.9205 26.391 17.9126 25.8784 18.4154Z" fill="var(--fill-0, white)"/>
</g>
</g>
<defs>
<clipPath id="clip0_4_375">
<rect width="34.88" height="33.86" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+13
View File
@@ -0,0 +1,13 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="48.51" height="40.38" viewBox="0 0 48.51 40.38" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="&#233;&#135;&#143;&#228;&#186;&#167;&#228;&#186;&#164;&#228;&#187;&#152;icon" clip-path="url(#clip0_4_385)">
<path id="Vector" d="M28.68 19.55C32.19 19.55 35.03 16.71 35.03 13.2C35.03 9.69 32.19 6.85 28.68 6.85C25.17 6.85 22.33 9.69 22.33 13.2C22.33 16.71 25.17 19.55 28.68 19.55ZM24.73 11.56C25.51 9.67 27.52 8.6 29.52 9C31.52 9.4 32.96 11.16 32.96 13.2C32.96 14.34 32.51 15.42 31.71 16.23C30.27 17.67 28 17.9 26.31 16.76C24.61 15.63 23.95 13.45 24.73 11.56Z" fill="var(--fill-0, white)"/>
<path id="Vector_2" d="M15.63 16.51C15.95 17.76 16.45 18.96 17.11 20.07L17.43 20.61L20.43 20.46C20.74 20.81 21.07 21.14 21.42 21.45L21.27 24.45L21.81 24.77C22.92 25.43 24.12 25.93 25.37 26.25L25.98 26.4L27.99 24.17C28.45 24.2 28.92 24.2 29.39 24.17L31.4 26.4L32.01 26.25C33.26 25.93 34.46 25.43 35.57 24.77L36.11 24.45L35.96 21.45C36.31 21.14 36.64 20.81 36.95 20.46L39.95 20.61L40.27 20.07C40.93 18.96 41.43 17.76 41.75 16.51L41.9 15.9L39.67 13.89C39.68 13.65 39.69 13.42 39.69 13.19C39.69 12.96 39.69 12.73 39.67 12.49L41.9 10.48L41.75 9.87C41.43 8.62 40.93 7.42 40.27 6.31L39.95 5.77L36.95 5.92C36.64 5.57 36.31 5.24 35.96 4.93L36.11 1.93L35.57 1.61C34.46 0.95 33.26 0.45 32.01 0.13L31.4 -0.02L29.39 2.21C28.93 2.18 28.46 2.18 27.99 2.21L25.98 -0.02L25.37 0.13C24.12 0.45 22.92 0.95 21.81 1.61L21.27 1.93L21.42 4.93C21.07 5.24 20.74 5.57 20.43 5.92L17.43 5.77L17.11 6.31C16.45 7.42 15.95 8.62 15.63 9.87L15.48 10.48L17.71 12.49C17.7 12.72 17.69 12.96 17.69 13.19C17.69 13.42 17.69 13.65 17.71 13.89L15.48 15.9L15.63 16.51ZM18.59 7.92L21.37 8.06L21.7 7.64C22.12 7.11 22.6 6.64 23.12 6.22L23.54 5.89L23.4 3.11C24 2.79 24.63 2.53 25.28 2.33L27.15 4.4L27.68 4.34C28.35 4.26 29.02 4.26 29.69 4.34L30.22 4.4L32.09 2.34C32.74 2.54 33.37 2.8 33.97 3.12L33.83 5.9L34.25 6.23C34.78 6.65 35.25 7.13 35.67 7.65L36 8.07L38.78 7.93C39.1 8.53 39.36 9.16 39.56 9.81L37.49 11.68L37.55 12.21C37.63 12.88 37.63 13.55 37.55 14.22L37.49 14.75L39.56 16.62C39.36 17.27 39.1 17.9 38.78 18.5L36 18.36L35.67 18.78C35.25 19.31 34.77 19.78 34.25 20.2L33.83 20.53L33.97 23.31C33.37 23.63 32.74 23.89 32.09 24.09L30.22 22.02L29.69 22.08C29.02 22.16 28.35 22.16 27.68 22.08L27.15 22.02L25.28 24.08C24.63 23.88 24 23.62 23.4 23.3L23.54 20.52L23.12 20.19C22.59 19.77 22.12 19.29 21.7 18.77L21.37 18.35L18.59 18.49C18.27 17.89 18.01 17.26 17.81 16.61L19.88 14.74L19.82 14.21C19.74 13.54 19.74 12.87 19.82 12.2L19.88 11.67L17.81 9.8C18.01 9.15 18.27 8.52 18.59 7.92Z" fill="var(--fill-0, white)"/>
<path id="Vector_3" d="M48.51 25.83C48.51 26.52 48.18 27.16 47.62 27.57L29.75 40.38H5.87V24.36H10.88C12.11 24.36 13.31 24.71 14.36 25.35L18.92 28.15H25.46C26.66 28.15 27.63 29.13 27.63 30.33C27.63 31.53 26.66 32.51 25.46 32.51H20.08C19.33 32.51 18.62 32.81 18.1 33.33L17.49 33.94C17.27 34.16 17.02 34.34 16.76 34.49V34.51L19.25 33.86C19.73 33.74 20.22 33.67 20.71 33.67H25.24C26.47 33.67 27.62 33.1 28.36 32.11C28.57 31.83 28.9 31.67 29.26 31.67H29.75L45.42 23.91C46.84 23.2 48.51 24.24 48.51 25.83Z" fill="var(--fill-0, white)"/>
<path id="Vector_4" d="M1.32 24.37H3.17C3.9 24.37 4.49 24.96 4.49 25.69V39.07C4.49 39.8 3.9 40.39 3.17 40.39H1.32C0.59 40.39 0 39.8 0 39.07V25.69C0 24.96 0.59 24.37 1.32 24.37Z" fill="var(--fill-0, white)"/>
</g>
<defs>
<clipPath id="clip0_4_385">
<rect width="48.51" height="40.38" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

+23
View File
@@ -0,0 +1,23 @@
import { AboutIntro } from "@/components/about-intro";
import { CompetitiveAdvantage } from "@/components/competitive-advantage";
import { CorporateCulture } from "@/components/corporate-culture";
import { CustomerLogos } from "@/components/customer-logos";
import { DevelopmentHistory } from "@/components/development-history";
import { Hero } from "@/components/hero";
import { HonorsQualifications } from "@/components/honors-qualifications";
import { PatentAchievements } from "@/components/patent-achievements";
export default function AboutPage() {
return (
<div className="flex flex-col">
<Hero />
<AboutIntro />
<CorporateCulture />
<DevelopmentHistory />
<CompetitiveAdvantage />
<HonorsQualifications />
<PatentAchievements />
<CustomerLogos />
</div>
);
}
+16
View File
@@ -0,0 +1,16 @@
import { SiteFooter } from "@/components/site-footer";
import { SiteNav } from "@/components/site-nav";
export default function SiteLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex min-h-svh flex-col">
<SiteNav />
<main className="flex-1">{children}</main>
<SiteFooter />
</div>
);
}
+10
View File
@@ -0,0 +1,10 @@
export default function Home() {
return (
<div className="flex min-h-svh flex-col items-center justify-center bg-muted/50 p-4">
<div className="text-center">
<h1 className="text-3xl font-semibold tracking-tight"></h1>
<p className="mt-2 text-muted-foreground"></p>
</div>
</div>
);
}
-65
View File
@@ -1,65 +0,0 @@
import Image from "next/image";
export default function Home() {
return (
<div className="flex flex-col flex-1 items-center justify-center bg-zinc-50 font-sans dark:bg-black">
<main className="flex flex-1 w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={100}
height={20}
priority
/>
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
To get started, edit the page.tsx file.
</h1>
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Looking for a starting point or more instructions? Head over to{" "}
<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Templates
</a>{" "}
or the{" "}
<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Learning
</a>{" "}
center.
</p>
</div>
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
<a
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={16}
height={16}
/>
Deploy Now
</a>
<a
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Documentation
</a>
</div>
</main>
</div>
);
}
+46
View File
@@ -0,0 +1,46 @@
import Image from "next/image";
export function AboutIntro() {
return (
<section className="bg-white py-16 lg:py-0 lg:h-[572px]">
<div className="mx-auto flex h-full max-w-[1440px] flex-col items-center justify-center gap-12 px-6 lg:flex-row lg:gap-[120px] lg:px-[120px]">
{/* Text content */}
<div className="max-w-[421px] flex-1">
<p className="text-[12px] text-black"></p>
<h2 className="mt-2 text-[26px] font-bold text-[#04388b]">
</h2>
<div className="mt-6 space-y-4 text-[12px] leading-[21px] text-[#7f7f7f]">
<p>
</p>
<p>
</p>
</div>
<button
type="button"
className="mt-8 flex h-[30px] w-[100px] items-center justify-center bg-[#04388b] text-[12px] text-white transition-colors hover:bg-[#032a66]"
>
</button>
</div>
{/* Factory image */}
<div className="relative w-full max-w-[400px] flex-shrink-0 lg:w-[400px]">
<div className="relative aspect-[400/261] w-full overflow-hidden">
<Image
src="/about-factory.png"
alt="鼎兴电子厂房"
fill
className="object-cover"
sizes="(max-width: 1024px) 100vw, 400px"
/>
</div>
</div>
</div>
</section>
);
}
+75
View File
@@ -0,0 +1,75 @@
import Image from "next/image";
type Certificate = {
title: string;
image: string;
};
type CertificateSectionProps = {
title: string;
subtitle: string;
countLabel: string;
count: string;
certificates: Certificate[];
};
export function CertificateSection({
title,
subtitle,
countLabel,
count,
certificates,
}: CertificateSectionProps) {
return (
<section className="bg-white py-16 lg:py-24">
<div className="mx-auto max-w-[1440px] px-6 lg:px-[120px]">
{/* Header */}
<div className="flex flex-col justify-between gap-6 lg:flex-row lg:items-end">
<div>
<h2 className="text-[26px] font-bold text-[#04388b]">{title}</h2>
<p className="mt-4 text-[36px] font-medium leading-normal text-[#7f7f7f]">
{subtitle}
</p>
</div>
<div className="flex items-end gap-2">
<span className="text-[26px] font-medium text-[#7f7f7f]">
{countLabel}
</span>
<span className="text-[64px] font-bold leading-none text-[#7f7f7f]">
{count}
</span>
<span className="text-[26px] font-medium text-[#04388b]"></span>
</div>
</div>
{/* Certificates */}
<div className="mt-12 bg-[#eaebf0] p-8 lg:p-[40px]">
<div className="grid grid-cols-2 gap-6 lg:grid-cols-4">
{certificates.map((cert) => (
<div key={cert.title} className="flex flex-col items-center">
<div className="relative h-[184px] w-[130px] overflow-hidden">
<Image
src={cert.image}
alt={cert.title}
fill
className="object-cover"
sizes="130px"
/>
</div>
<p className="mt-4 text-center text-[12px] text-[#7f7f7f]">
{cert.title}
</p>
</div>
))}
</div>
</div>
{/* Pagination dots */}
<div className="mt-6 flex justify-center gap-2">
<div className="h-[8px] w-[42px] bg-[#04388b]" />
<div className="h-[8px] w-[42px] bg-[#d9d9d9]" />
</div>
</div>
</section>
);
}
+48
View File
@@ -0,0 +1,48 @@
import Image from "next/image";
const advantages = [
{
title: "一体化智造技术",
icon: "/icon-integration.svg",
},
{
title: "量产交付能力",
icon: "/icon-mass-production.svg",
},
{
title: "全套方案定制",
icon: "/icon-custom-solution.svg",
},
];
export function CompetitiveAdvantage() {
return (
<section className="bg-[#eaebf0] py-20 lg:h-[593px] lg:py-0">
<div className="mx-auto flex h-full max-w-[1440px] flex-col items-center justify-center px-6">
<h2 className="text-[26px] font-bold text-[#04388b]"></h2>
<div className="mt-12 flex w-full flex-wrap justify-center gap-6 lg:gap-[50px]">
{advantages.map((item) => (
<div
key={item.title}
className="relative flex h-[246px] w-full flex-col items-center justify-center bg-[#04388b] lg:w-[280px]"
>
<div className="absolute bottom-0 left-0 h-[10px] w-full bg-[#00d6f9]" />
<Image
src={item.icon}
alt=""
width={48}
height={40}
className="h-10 w-12 object-contain"
aria-hidden
/>
<p className="mt-4 text-[16px] font-bold text-white">
{item.title}
</p>
</div>
))}
</div>
</div>
</section>
);
}
+73
View File
@@ -0,0 +1,73 @@
import Image from "next/image";
const cultureItems = [
{
title: "品牌理念",
description: "建一流企业,造一流产品,创一流品牌!",
image: "/culture-card-1.png",
},
{
title: "企业使命",
description: "追求卓越品质,满足顾客需求,坚持诚实守信,铸造鼎兴品牌!",
image: "/culture-card-2.png",
},
{
title: "价值观",
description: "服务创造价值,品质改变世界",
image: "/culture-card-3.png",
},
{
title: "行为准则",
description: "精益求精造精品,至诚至善待客户",
image: "/culture-card-4.png",
},
];
export function CorporateCulture() {
return (
<section className="relative isolate overflow-hidden bg-[#04388b] py-20 lg:py-24">
{/* Background texture */}
<div className="absolute inset-0 opacity-10">
<Image
src="/culture-bg.png"
alt=""
fill
className="object-cover"
sizes="100vw"
aria-hidden
/>
</div>
<div className="relative z-10 mx-auto flex h-full max-w-[1440px] flex-col items-center justify-center px-6 lg:px-[120px]">
<h2 className="text-[26px] font-bold text-white"></h2>
<div className="mt-12 grid w-full grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4">
{cultureItems.map((item) => (
<div
key={item.title}
className="relative isolate h-[355px] overflow-hidden rounded-[16px] bg-black/20"
>
<Image
src={item.image}
alt={item.title}
fill
className="object-cover opacity-50"
sizes="(max-width: 1024px) 50vw, 300px"
/>
<div className="absolute inset-0 bg-black/20" />
<div className="relative z-10 flex h-full flex-col justify-end p-6">
<h3 className="text-[16px] font-bold text-white">
{item.title}
</h3>
<p className="mt-2 text-[12px] font-medium leading-normal text-white">
{item.description}
</p>
</div>
</div>
))}
</div>
</div>
</section>
);
}
+46
View File
@@ -0,0 +1,46 @@
import Image from "next/image";
const customers = [
{ name: "山河智能", logo: "/logo-sunward.png" },
{ name: "山河智能", logo: "/logo-sunward.png" },
{ name: "三一重工", logo: "/logo-sany.png" },
{ name: "山重建机", logo: "/logo-shanzhong.png" },
{ name: "上海振华重工", logo: "/logo-zpmc.png" },
{ name: "上海振华重工", logo: "/logo-zpmc.png" },
];
export function CustomerLogos() {
return (
<section className="relative isolate overflow-hidden bg-[#1d1d1d]">
{/* Background */}
<Image
src="/customers-bg.png"
alt=""
fill
className="object-cover"
sizes="100vw"
aria-hidden
/>
<div className="absolute inset-0 bg-black/20" />
<div className="relative z-10 mx-auto flex min-h-[400px] max-w-[1440px] items-center justify-center px-6 py-20 lg:px-[120px]">
<div className="flex flex-wrap items-center justify-center gap-6 lg:gap-10">
{customers.map((customer, index) => (
<div
key={`${customer.name}-${index}`}
className="flex h-[120px] w-[120px] items-center justify-center bg-white p-4 [clip-path:polygon(50%_0%,100%_25%,100%_75%,50%_100%,0%_75%,0%_25%)]"
>
<Image
src={customer.logo}
alt={customer.name}
width={80}
height={80}
className="max-h-full max-w-full object-contain"
/>
</div>
))}
</div>
</div>
</section>
);
}
+185
View File
@@ -0,0 +1,185 @@
"use client";
import { ChevronLeft, ChevronRight } from "lucide-react";
import Image from "next/image";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
const historyItems = [
{
year: "2004",
description: "鼎兴电子的生产总部落成,坐落于天安工业村B座6F",
image: "/history-2004.png",
},
{
year: "2007",
description:
"开始与三一重工开始合作,进入三一重工的战略合作供应商名单,并于当年被评为三一优秀供应商。",
image: "/history-2007.png",
},
{
year: "2008",
description: "于当年完成管理生产升级,通过9001等质量体系认证",
image: "/history-2008.png",
},
{
year: "2010",
description:
"鼎兴与国内港口机械龙头企业振华重工达成合作,并成为其重要的战略合作伙伴。",
image: "/history-2010.png",
},
{
year: "2015",
description:
"自研挖掘机模拟实验板完成交付,产品性能获三一多方认可,双方技术合作稳步深化",
image: "/history-2015.png",
},
{
year: "2019",
description:
"项目晋级东南大学创新创业大赛复赛,并达成多项院校专业合作,为企业开拓新领域研发筑牢根基。",
image: "/history-2019.png",
},
];
const ITEM_WIDTH = 176;
const ITEM_GAP = 53;
const STEP = ITEM_WIDTH + ITEM_GAP;
const VISIBLE_COUNT = 5;
function TimelineItem({
item,
isTop,
}: {
item: (typeof historyItems)[number];
isTop: boolean;
}) {
return (
<div
className="relative flex h-full shrink-0 flex-col items-center"
style={{ width: ITEM_WIDTH }}
>
{/* Top half */}
<div className="flex flex-1 flex-col items-center justify-end pb-6">
{isTop && (
<>
<div className="relative h-[117px] w-[176px] overflow-hidden rounded-md">
<Image
src={item.image}
alt={`${item.year} 历史照片`}
fill
className="object-cover"
sizes="176px"
/>
</div>
<p className="mt-4 text-[26px] font-bold text-white">{item.year}</p>
<p className="mt-2 max-w-[176px] text-center text-[12px] leading-normal text-white/90">
{item.description}
</p>
</>
)}
</div>
{/* Timeline dot */}
<div className="size-3 shrink-0 rounded-full bg-white" />
{/* Bottom half */}
<div className="flex flex-1 flex-col items-center justify-start pt-6">
{!isTop && (
<>
<div className="relative h-[117px] w-[176px] overflow-hidden rounded-md">
<Image
src={item.image}
alt={`${item.year} 历史照片`}
fill
className="object-cover"
sizes="176px"
/>
</div>
<p className="mt-4 text-[26px] font-bold text-white">{item.year}</p>
<p className="mt-2 max-w-[176px] text-center text-[12px] leading-normal text-white/90">
{item.description}
</p>
</>
)}
</div>
</div>
);
}
export function DevelopmentHistory() {
const [index, setIndex] = useState(0);
const maxIndex = Math.max(0, historyItems.length - VISIBLE_COUNT);
const canPrev = index > 0;
const canNext = index < maxIndex;
return (
<section className="relative isolate h-[828px] overflow-hidden bg-[#1d1d1d]">
{/* Background */}
<Image
src="/history-bg.png"
alt=""
fill
className="object-cover opacity-50"
sizes="100vw"
aria-hidden
/>
<div className="absolute inset-0 bg-black/50" />
<div className="relative z-10 mx-auto flex h-full max-w-[1443px] flex-col items-center justify-center px-6">
<h2 className="text-[26px] font-bold text-white"></h2>
<div className="relative mt-16 w-full max-w-[1046px]">
{/* Timeline line */}
<div className="absolute left-0 right-0 top-1/2 h-px -translate-y-1/2 bg-white/30" />
{/* Items */}
<div className="overflow-hidden">
<div
className="flex transition-transform duration-500 ease-in-out"
style={{
transform: `translateX(-${index * STEP}px)`,
gap: ITEM_GAP,
}}
>
{historyItems.map((item, i) => (
<TimelineItem key={item.year} item={item} isTop={i % 2 === 0} />
))}
</div>
</div>
{/* Navigation */}
<Button
variant="outline"
size="icon"
onClick={() => setIndex((v) => Math.max(0, v - 1))}
disabled={!canPrev}
className={cn(
"absolute left-0 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full border-white/30 bg-transparent text-white hover:bg-white/10",
!canPrev && "opacity-30",
)}
>
<ChevronLeft className="size-5" />
<span className="sr-only"></span>
</Button>
<Button
variant="outline"
size="icon"
onClick={() => setIndex((v) => Math.min(maxIndex, v + 1))}
disabled={!canNext}
className={cn(
"absolute right-0 top-1/2 -translate-y-1/2 translate-x-1/2 rounded-full border-white/30 bg-transparent text-white hover:bg-white/10",
!canNext && "opacity-30",
)}
>
<ChevronRight className="size-5" />
<span className="sr-only"></span>
</Button>
</div>
</div>
</section>
);
}
+40
View File
@@ -0,0 +1,40 @@
import Image from "next/image";
export function Hero() {
return (
<section className="relative isolate h-[817px] w-full overflow-hidden bg-[#1e1e1e]">
{/* Background image */}
<Image
src="/hero-cover.png"
alt="重工机械零件背景"
fill
priority
className="object-cover"
sizes="100vw"
/>
{/* Dark overlay at 20% opacity */}
<div className="absolute inset-0 bg-[#1e1e1e]/20" />
{/* Bottom gradient mask */}
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/30 to-transparent" />
{/* Content */}
<div className="relative z-10 mx-auto flex h-full max-w-[1442px] flex-col justify-center px-6 sm:px-12 lg:px-[124px]">
<div className="max-w-4xl">
<h1 className="text-3xl font-bold leading-tight text-white sm:text-4xl lg:text-[52px] lg:leading-[1.2]">
··
</h1>
<p className="mt-4 text-sm text-white/90 sm:text-base lg:text-[16px]">
Steady · Precise · Efficient Dingxing Intelligent Manufacturing
Expert in Heavy Machinery Supporting Parts
</p>
{/* Decorative cyan line */}
<div className="mt-6 h-[8px] w-[55px] bg-[#00d6f9]" />
</div>
</div>
</section>
);
}
+20
View File
@@ -0,0 +1,20 @@
import { CertificateSection } from "@/components/certificate-section";
const certificates = [
{ title: "质量管理体系认证证书", image: "/cert-quality.png" },
{ title: "国际质量管理体系认证证书", image: "/cert-international.png" },
{ title: "RoHS 有害物质限制认证", image: "/cert-rohs.png" },
{ title: "CE-EMC 电磁兼容认证", image: "/cert-ce-emc.png" },
];
export function HonorsQualifications() {
return (
<CertificateSection
title="荣誉资质"
subtitle="每一项权威认证,都是我们持续前行的动力"
countLabel="认证证书"
count="20"
certificates={certificates}
/>
);
}
+20
View File
@@ -0,0 +1,20 @@
import { CertificateSection } from "@/components/certificate-section";
const certificates = [
{ title: "质量管理体系认证证书", image: "/cert-quality.png" },
{ title: "国际质量管理体系认证证书", image: "/cert-international.png" },
{ title: "RoHS 有害物质限制认证", image: "/cert-rohs.png" },
{ title: "CE-EMC 电磁兼容认证", image: "/cert-ce-emc.png" },
];
export function PatentAchievements() {
return (
<CertificateSection
title="专利成果"
subtitle="每一份专利授权,都是技术深耕的见证"
countLabel="认证专利"
count="20"
certificates={certificates}
/>
);
}
+100
View File
@@ -0,0 +1,100 @@
import { MapPin, Phone } from "lucide-react";
import Image from "next/image";
import Link from "next/link";
const footerLinks = [
{
title: "关于鼎兴",
links: [
{ label: "公司简介", href: "/about" },
{ label: "企业文化", href: "/about" },
{ label: "公司历程", href: "/about" },
{ label: "企业实力", href: "/about" },
{ label: "企业荣誉", href: "/about" },
],
},
{
title: "解决方案",
links: [
{ label: "工程机械类", href: "/products" },
{ label: "港口机械类", href: "/products" },
],
},
{
title: "品牌故事",
links: [
{ label: "公司新闻", href: "/news" },
{ label: "行业新闻", href: "/news" },
],
},
];
export function SiteFooter() {
return (
<footer className="bg-white">
{/* Mountain background at top */}
<div className="relative h-[200px] w-full overflow-hidden">
<Image
src="/customers-bg.png"
alt=""
fill
className="object-cover object-bottom"
sizes="100vw"
aria-hidden
/>
</div>
{/* Footer content */}
<div className="mx-auto flex max-w-[1440px] flex-col justify-between gap-10 px-6 py-12 lg:flex-row lg:px-[120px]">
{/* Logo */}
<div className="flex-shrink-0">
<Image
src="/footer-logo.png"
alt="鼎兴电子 DINGXING ELECTRONICS"
width={285}
height={64}
className="h-[64px] w-[285px] object-contain"
/>
</div>
{/* Links */}
<div className="flex flex-1 flex-wrap gap-10 lg:justify-end lg:gap-16">
{footerLinks.map((group) => (
<div key={group.title}>
<h3 className="text-[26px] font-medium text-[#3e3e3e]">
{group.title}
</h3>
<ul className="mt-6 space-y-2">
{group.links.map((link) => (
<li key={link.label}>
<Link
href={link.href}
className="text-[12px] leading-[25px] text-[#3e3e3e] transition-colors hover:text-[#04388b]"
>
{link.label}
</Link>
</li>
))}
</ul>
</div>
))}
{/* Contact */}
<div>
<h3 className="text-[26px] font-medium text-[#3e3e3e]"></h3>
<ul className="mt-6 space-y-2 text-[12px] leading-[25px] text-[#3e3e3e]">
<li className="flex items-center gap-2">
<Phone className="size-3" />
86-0519-85155958
</li>
<li className="flex items-center gap-2">
<MapPin className="size-3" />
B座6层
</li>
</ul>
</div>
</div>
</div>
</footer>
);
}
+88
View File
@@ -0,0 +1,88 @@
"use client";
import Image from "next/image";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { cn } from "@/lib/utils";
const navItems = [
{ label: "首页", href: "/", left: 422 },
{ label: "关于鼎兴", href: "/about", left: 603 },
{ label: "产品", href: "/products", left: 820 },
{ label: "联系我们", href: "/contact", left: 1000 },
];
function isActive(pathname: string, href: string) {
if (href === "/") return pathname === "/";
return pathname === href || pathname.startsWith(`${href}/`);
}
export function SiteNav() {
const pathname = usePathname();
return (
<header className="sticky top-0 z-50 h-20 w-full bg-white shadow-[0_4px_4px_0_rgba(0,0,0,0.25)]">
<div className="relative mx-auto h-full max-w-[1442px]">
{/* Logo: 201x46 at left=117, top=24 */}
<Link
href="/"
className="absolute left-[117px] top-[24px] h-[46px] w-[201px]"
>
<Image
src="/logo.png"
alt="鼎兴电子 DINGXING ELECTRONICS"
width={201}
height={46}
className="h-[46px] w-[201px] object-contain"
priority
/>
</Link>
{/* Nav items */}
<nav className="absolute inset-y-0">
{navItems.map((item) => {
const active = isActive(pathname, item.href);
return (
<Link
key={item.href}
href={item.href}
className={cn(
"absolute top-[29px] whitespace-nowrap text-[18px] font-normal leading-normal transition-colors",
active
? "text-[#00d6f9]"
: "text-[#02398b] hover:text-[#00d6f9]"
)}
style={{ left: item.left }}
>
{item.label}
</Link>
);
})}
</nav>
{/* Language switcher: icon at left=1273, text at left=1298 */}
<button
type="button"
className="absolute left-[1273px] top-[31px] flex items-center gap-1.5 text-[18px] font-normal text-[#02398b] transition-colors hover:text-[#00d6f9]"
>
<svg
className="size-[20.48px]"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
>
<circle cx="12" cy="12" r="10" />
<path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" />
<path d="M2 12h20" />
</svg>
<span className="absolute left-[25px] top-[-2px] whitespace-nowrap">
En
</span>
</button>
</div>
</header>
);
}