Compare commits

...

2 Commits

Author SHA1 Message Date
b8c8a08ddd seo优化 2025-12-18 19:33:22 +08:00
cd40c603a1 添加i18n 2025-12-18 18:32:35 +08:00
26 changed files with 735 additions and 150 deletions

115
app/[locale]/layout.tsx Normal file
View File

@ -0,0 +1,115 @@
import type { Metadata } from "next";
import { Playfair_Display, Noto_Serif_SC } from "next/font/google";
import "../globals.css";
import Navbar from "@/components/Navbar";
import Footer from "@/components/Footer";
import {NextIntlClientProvider} from 'next-intl';
import {getMessages, getTranslations} from 'next-intl/server';
import {notFound} from 'next/navigation';
import {routing} from '@/i18n/routing';
const playfairDisplay = Playfair_Display({
variable: "--font-serif",
subsets: ["latin"],
weight: ["400", "600", "700"],
style: ["normal", "italic"],
});
const notoSerifSC = Noto_Serif_SC({
variable: "--font-serif-sc",
subsets: ["latin"],
weight: ["300", "400", "500", "700"],
});
export async function generateMetadata({
params
}: {
params: Promise<{locale: string}>;
}): Promise<Metadata> {
const { locale } = await params;
const t = await getTranslations({locale, namespace: 'Metadata'});
const baseUrl = 'https://feietech.com'; // 请替换为您的实际域名
return {
title: t('title'),
description: t('description'),
alternates: {
canonical: `${baseUrl}/${locale}`,
languages: {
'en': `${baseUrl}/en`,
'zh': `${baseUrl}/zh`,
'ja': `${baseUrl}/ja`,
},
},
openGraph: {
title: t('title'),
description: t('description'),
url: `${baseUrl}/${locale}`,
siteName: 'Nanjing Feie Information Technology',
locale: locale,
type: 'website',
images: [
{
url: `${baseUrl}/icon.jpg`,
width: 1184,
height: 1184,
alt: 'Nanjing Feie Information Technology Logo',
},
],
},
icons: {
icon: '/icon.jpg',
shortcut: '/icon.jpg',
apple: '/icon.jpg',
},
};
}
export default async function LocaleLayout({
children,
params
}: {
children: React.ReactNode;
params: Promise<{locale: string}>;
}) {
const { locale } = await params;
if (!['en', 'zh', 'ja'].includes(locale)) {
notFound();
}
const messages = await getMessages();
const baseUrl = 'https://feietech.com'; // 请替换为您的实际域名
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Organization',
name: 'Nanjing Feie Information Technology Co., Ltd.',
url: baseUrl,
logo: `${baseUrl}/assets/logo.png`,
contactPoint: {
'@type': 'ContactPoint',
telephone: '+86-198-4456-1014',
contactType: 'customer service',
areaServed: ['CN', 'US', 'JP'],
availableLanguage: ['Chinese', 'English', 'Japanese']
}
};
return (
<html lang={locale}>
<body
className={`${playfairDisplay.variable} ${notoSerifSC.variable} antialiased selection:bg-feie-gold selection:text-white`}
>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{__html: JSON.stringify(jsonLd)}}
/>
<NextIntlClientProvider messages={messages}>
<Navbar />
{children}
<Footer />
</NextIntlClientProvider>
</body>
</html>
);
}

View File

@ -1,42 +0,0 @@
import type { Metadata } from "next";
import { Playfair_Display, Noto_Serif_SC } from "next/font/google";
import "./globals.css";
import Navbar from "@/components/Navbar";
import Footer from "@/components/Footer";
const playfairDisplay = Playfair_Display({
variable: "--font-serif",
subsets: ["latin"],
weight: ["400", "600", "700"],
style: ["normal", "italic"],
});
const notoSerifSC = Noto_Serif_SC({
variable: "--font-serif-sc",
subsets: ["latin"],
weight: ["300", "400", "500", "700"],
});
export const metadata: Metadata = {
title: "南京市肥鹅信息技术有限公司 | Nanjing Feie Information Technology",
description: "南京市肥鹅信息技术有限公司致力于为企业提供卓越的数字化解决方案,以创新技术驱动商业价值。",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="zh-CN">
<body
className={`${playfairDisplay.variable} ${notoSerifSC.variable} antialiased selection:bg-feie-gold selection:text-white`}
>
<Navbar />
{children}
<Footer />
</body>
</html>
);
}

13
app/robots.ts Normal file
View File

@ -0,0 +1,13 @@
import {MetadataRoute} from 'next';
export default function robots(): MetadataRoute.Robots {
const baseUrl = 'https://feietech.com';
return {
rules: {
userAgent: '*',
allow: '/',
disallow: '/private/',
},
sitemap: `${baseUrl}/sitemap.xml`,
};
}

20
app/sitemap.ts Normal file
View File

@ -0,0 +1,20 @@
import {MetadataRoute} from 'next';
import {routing} from '@/i18n/routing';
export default function sitemap(): MetadataRoute.Sitemap {
const baseUrl = 'https://feietech.com';
// 基础路由,这里只有首页
const routes = [''];
return routes.flatMap((route) => {
return routing.locales.map((locale) => {
return {
url: `${baseUrl}/${locale}${route}`,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: route === '' ? 1 : 0.8,
};
});
});
}

View File

@ -9,6 +9,7 @@
"@react-three/fiber": "^9.4.2",
"lucide-react": "^0.559.0",
"next": "16.0.8",
"next-intl": "^4.6.1",
"prisma": "^6.0.0",
"react": "19.2.1",
"react-dom": "19.2.1",
@ -90,6 +91,16 @@
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="],
"@formatjs/ecma402-abstract": ["@formatjs/ecma402-abstract@2.3.6", "", { "dependencies": { "@formatjs/fast-memoize": "2.2.7", "@formatjs/intl-localematcher": "0.6.2", "decimal.js": "^10.4.3", "tslib": "^2.8.0" } }, "sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw=="],
"@formatjs/fast-memoize": ["@formatjs/fast-memoize@2.2.7", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ=="],
"@formatjs/icu-messageformat-parser": ["@formatjs/icu-messageformat-parser@2.11.4", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.6", "@formatjs/icu-skeleton-parser": "1.8.16", "tslib": "^2.8.0" } }, "sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw=="],
"@formatjs/icu-skeleton-parser": ["@formatjs/icu-skeleton-parser@1.8.16", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.6", "tslib": "^2.8.0" } }, "sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ=="],
"@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.5.10", "", { "dependencies": { "tslib": "2" } }, "sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
"@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="],
@ -192,6 +203,34 @@
"@nolyfill/is-core-module": ["@nolyfill/is-core-module@1.0.39", "", {}, "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA=="],
"@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="],
"@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.1", "", { "os": "android", "cpu": "arm64" }, "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA=="],
"@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.5.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw=="],
"@parcel/watcher-darwin-x64": ["@parcel/watcher-darwin-x64@2.5.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg=="],
"@parcel/watcher-freebsd-x64": ["@parcel/watcher-freebsd-x64@2.5.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ=="],
"@parcel/watcher-linux-arm-glibc": ["@parcel/watcher-linux-arm-glibc@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA=="],
"@parcel/watcher-linux-arm-musl": ["@parcel/watcher-linux-arm-musl@2.5.1", "", { "os": "linux", "cpu": "arm" }, "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q=="],
"@parcel/watcher-linux-arm64-glibc": ["@parcel/watcher-linux-arm64-glibc@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w=="],
"@parcel/watcher-linux-arm64-musl": ["@parcel/watcher-linux-arm64-musl@2.5.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg=="],
"@parcel/watcher-linux-x64-glibc": ["@parcel/watcher-linux-x64-glibc@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A=="],
"@parcel/watcher-linux-x64-musl": ["@parcel/watcher-linux-x64-musl@2.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg=="],
"@parcel/watcher-win32-arm64": ["@parcel/watcher-win32-arm64@2.5.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw=="],
"@parcel/watcher-win32-ia32": ["@parcel/watcher-win32-ia32@2.5.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ=="],
"@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="],
"@prisma/client": ["@prisma/client@6.19.1", "", { "peerDependencies": { "prisma": "*", "typescript": ">=5.1.0" }, "optionalPeers": ["prisma", "typescript"] }, "sha512-4SXj4Oo6HyQkLUWT8Ke5R0PTAfVOKip5Roo+6+b2EDTkFg5be0FnBWiuRJc0BC0sRQIWGMLKW1XguhVfW/z3/A=="],
"@prisma/config": ["@prisma/config@6.19.1", "", { "dependencies": { "c12": "3.1.0", "deepmerge-ts": "7.1.5", "effect": "3.18.4", "empathic": "2.0.0" } }, "sha512-bUL/aYkGXLwxVGhJmQMtslLT7KPEfUqmRa919fKI4wQFX4bIFUKiY8Jmio/2waAjjPYrtuDHa7EsNCnJTXxiOw=="],
@ -212,10 +251,38 @@
"@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="],
"@schummar/icu-type-parser": ["@schummar/icu-type-parser@1.21.5", "", {}, "sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw=="],
"@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
"@swc/core": ["@swc/core@1.15.6", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.25" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.15.6", "@swc/core-darwin-x64": "1.15.6", "@swc/core-linux-arm-gnueabihf": "1.15.6", "@swc/core-linux-arm64-gnu": "1.15.6", "@swc/core-linux-arm64-musl": "1.15.6", "@swc/core-linux-x64-gnu": "1.15.6", "@swc/core-linux-x64-musl": "1.15.6", "@swc/core-win32-arm64-msvc": "1.15.6", "@swc/core-win32-ia32-msvc": "1.15.6", "@swc/core-win32-x64-msvc": "1.15.6" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-BpSCKSwE5DG4N4Um+ZZwvJzJ/4iyMVlzvhJQoR0wJSgccca9ES3+P/7SbPxTM/jtV9vE1llfLPphw+Y+MFhnZg=="],
"@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.15.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-8pv6W49H70/yxNAC0k+W/Ko3nJW2Za706C1a8q6XhT4JtMLyaYqb+KeoBfIOR8F7qNhMdMa7wdOY5DLPk5cPSg=="],
"@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.15.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-v4mDTwA+UdYEHKvzefc3VX/4a7QrRnAFZzNwL33PcLNUJhWbBg6ptcQpBDz/xWOjU6m+pC0IQfzcs16rkAFCHg=="],
"@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.15.6", "", { "os": "linux", "cpu": "arm" }, "sha512-OT8rIl24/mu4bgDPJT6FVcW+WF3ep9VTau69FspjeycNIa0U0est1ooHxxJyTcO8Qdv0Jy11oXHwtxslZ6KXcw=="],
"@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.15.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-RKdeG9HBecClhtNJpGyZCYwvGrjzxDzQxGaVOQa44DbNSlVgupj6LnqNSt0RCTy8HEjra1WTD8dCJ9AR++dznQ=="],
"@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.15.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-+llo+x7fRyyYd5qGfeYyHgDoZy7M9jKQKmYjTKTJ1BMoydeBoujUWtw+L3tOHyrzKBWOdmVhwdyK+Rx8DeOaGQ=="],
"@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.15.6", "", { "os": "linux", "cpu": "x64" }, "sha512-1Ufezv5CtJOZaIzYUVMWPORNXgY1MuBrU6LPIeACkdpIaY2wiyfvTiMF57yZ3/c6RQQAY5ZmgV44wCe4dhUFew=="],
"@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.15.6", "", { "os": "linux", "cpu": "x64" }, "sha512-hKhR3mAvLvp1bmSrM68DyW+p8vKoFospxtffCTdC0fUR+Y6GEmSMTh+KcQ5vcGptnS2VB6QhZx3oLdzoBs0R6g=="],
"@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.15.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-s3AMvEOxS+H4l2+bEYwKkfDBf34u1/i+t7OgflFCaZ9wSDA3f693bptPO3m1/DrMTq1iEztEV2MPbjMmQqOmBw=="],
"@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.15.6", "", { "os": "win32", "cpu": "ia32" }, "sha512-oD9REGtkA/kU+d9xBa0jddrn4BEIfWA7Jx+O+KD1Dhvgd23aYVWwR98kote6DbC/5nAbt201JnW73SkYHBm4pQ=="],
"@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.15.6", "", { "os": "win32", "cpu": "x64" }, "sha512-oJ17Ouy1BkoUM5R8HJF8nX8IbiDror8tjW9x/PUoUVmtxxVb42vpXrS6xGDpH0mXx8K1wVVS6DOgH83uwKEBUQ=="],
"@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="],
"@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="],
"@swc/types": ["@swc/types@0.1.25", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g=="],
"@tailwindcss/node": ["@tailwindcss/node@4.1.17", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.17" } }, "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg=="],
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.17", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.17", "@tailwindcss/oxide-darwin-arm64": "4.1.17", "@tailwindcss/oxide-darwin-x64": "4.1.17", "@tailwindcss/oxide-freebsd-x64": "4.1.17", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17", "@tailwindcss/oxide-linux-arm64-musl": "4.1.17", "@tailwindcss/oxide-linux-x64-gnu": "4.1.17", "@tailwindcss/oxide-linux-x64-musl": "4.1.17", "@tailwindcss/oxide-wasm32-wasi": "4.1.17", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17", "@tailwindcss/oxide-win32-x64-msvc": "4.1.17" } }, "sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA=="],
@ -442,6 +509,8 @@
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
"decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="],
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
"deepmerge-ts": ["deepmerge-ts@7.1.5", "", {}, "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw=="],
@ -622,6 +691,8 @@
"internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="],
"intl-messageformat": ["intl-messageformat@10.7.18", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.6", "@formatjs/fast-memoize": "2.2.7", "@formatjs/icu-messageformat-parser": "2.11.4", "tslib": "^2.8.0" } }, "sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g=="],
"is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="],
"is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="],
@ -772,8 +843,16 @@
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
"next": ["next@16.0.8", "", { "dependencies": { "@next/env": "16.0.8", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.0.8", "@next/swc-darwin-x64": "16.0.8", "@next/swc-linux-arm64-gnu": "16.0.8", "@next/swc-linux-arm64-musl": "16.0.8", "@next/swc-linux-x64-gnu": "16.0.8", "@next/swc-linux-x64-musl": "16.0.8", "@next/swc-win32-arm64-msvc": "16.0.8", "@next/swc-win32-x64-msvc": "16.0.8", "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-LmcZzG04JuzNXi48s5P+TnJBsTGPJunViNKV/iE4uM6kstjTQsQhvsAv+xF6MJxU2Pr26tl15eVbp0jQnsv6/g=="],
"next-intl": ["next-intl@4.6.1", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.5.4", "@parcel/watcher": "^2.4.1", "@swc/core": "^1.15.2", "negotiator": "^1.0.0", "next-intl-swc-plugin-extractor": "^4.6.1", "po-parser": "^2.0.0", "use-intl": "^4.6.1" }, "peerDependencies": { "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0", "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-KlWgWtKLBPUsTPgxqwyjws1wCMD2QKxLlVjeeGj53DC1JWfKmBShKOrhIP0NznZrRQ0GleeoDUeHSETmyyIFeA=="],
"next-intl-swc-plugin-extractor": ["next-intl-swc-plugin-extractor@4.6.1", "", {}, "sha512-+HHNeVERfSvuPDF7LYVn3pxst5Rf7EYdUTw7C7WIrYhcLaKiZ1b9oSRkTQddAN3mifDMCfHqO4kAQ/pcKiBl3A=="],
"node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="],
"node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
"node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
@ -824,6 +903,8 @@
"pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="],
"po-parser": ["po-parser@2.0.0", "", {}, "sha512-SZvoKi3PoI/hHa2V9je9CW7Xgxl4dvO74cvaa6tWShIHT51FkPxje6pt0gTJznJrU67ix91nDaQp2hUxkOYhKA=="],
"possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
@ -992,6 +1073,8 @@
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
"use-intl": ["use-intl@4.6.1", "", { "dependencies": { "@formatjs/fast-memoize": "^2.2.0", "@schummar/icu-type-parser": "1.21.5", "intl-messageformat": "^10.5.14" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" } }, "sha512-mUIj6QvJZ7Rk33mLDxRziz1YiBBAnIji8YW4TXXMdYHtaPEbVucrXD3iKQGAqJhbVn0VnjrEtIKYO1B18mfSJw=="],
"use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
"utility-types": ["utility-types@3.11.0", "", {}, "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw=="],
@ -1028,6 +1111,10 @@
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
"@formatjs/ecma402-abstract/@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.6.2", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA=="],
"@parcel/watcher/detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.7.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="],

View File

@ -1,7 +1,10 @@
import React from 'react';
import Image from 'next/image';
import { useTranslations } from 'next-intl';
const About: React.FC = () => {
const t = useTranslations('About');
return (
<section id="about" className="py-24 bg-feie-cream relative">
<div className="container mx-auto px-6">
@ -23,32 +26,32 @@ const About: React.FC = () => {
{/* Text Content */}
<div className="w-full md:w-1/2 space-y-8">
<h2 className="text-sm font-bold tracking-widest text-feie-gold uppercase mb-2"> About Us</h2>
<h2 className="text-sm font-bold tracking-widest text-feie-gold uppercase mb-2">{t('title')} {t('subtitle')}</h2>
<h3 className="text-4xl md:text-5xl font-serif text-feie-dark leading-tight">
<br />
<span className="italic text-gray-500"></span>
{t('heading')} <br />
<span className="italic text-gray-500">{t('subheading')}</span>
</h3>
<div className="space-y-6 text-gray-600 font-light leading-relaxed">
<p>
沿
{t('p1')}
</p>
<p>
"技术驱动、服务至上"
{t('p2')}
</p>
<p>
IT解决方案
{t('p3')}
</p>
</div>
<div className="pt-4 grid grid-cols-2 gap-8">
<div>
<h4 className="text-3xl font-serif text-feie-gold">100+</h4>
<p className="text-sm text-gray-500 uppercase tracking-wider mt-1"></p>
<p className="text-sm text-gray-500 uppercase tracking-wider mt-1">{t('stats.cases')}</p>
</div>
<div>
<h4 className="text-3xl font-serif text-feie-gold">24/7</h4>
<p className="text-sm text-gray-500 uppercase tracking-wider mt-1"></p>
<p className="text-sm text-gray-500 uppercase tracking-wider mt-1">{t('stats.support')}</p>
</div>
</div>
</div>

View File

@ -2,6 +2,7 @@
import React, { useState } from 'react';
import { MapPin, Phone, Mail } from 'lucide-react';
import { useTranslations } from 'next-intl';
interface FormData {
name: string;
@ -18,6 +19,7 @@ interface FormErrors {
}
const Contact: React.FC = () => {
const t = useTranslations('Contact');
const [formData, setFormData] = useState<FormData>({
name: '',
phone: '',
@ -33,25 +35,25 @@ const Contact: React.FC = () => {
const newErrors: FormErrors = {};
if (!formData.name.trim()) {
newErrors.name = '请输入姓名';
newErrors.name = t('form.errors.nameRequired');
}
const phoneRegex = /^1[3-9]\d{9}$/;
if (!formData.phone.trim()) {
newErrors.phone = '请输入电话';
newErrors.phone = t('form.errors.phoneRequired');
} else if (!phoneRegex.test(formData.phone)) {
newErrors.phone = '请输入正确的手机号';
newErrors.phone = t('form.errors.phoneInvalid');
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!formData.email.trim()) {
newErrors.email = '请输入邮箱';
newErrors.email = t('form.errors.emailRequired');
} else if (!emailRegex.test(formData.email)) {
newErrors.email = '请输入正确的邮箱地址';
newErrors.email = t('form.errors.emailInvalid');
}
if (!formData.description.trim()) {
newErrors.description = '请描述您的需求';
newErrors.description = t('form.errors.descRequired');
}
setErrors(newErrors);
@ -91,7 +93,7 @@ const Contact: React.FC = () => {
if (response.ok) {
setSubmitStatus({
type: 'success',
message: data.message || '留言提交成功,我们会尽快与您联系!'
message: data.message || t('form.success')
});
// 清空表单
setFormData({
@ -129,9 +131,9 @@ const Contact: React.FC = () => {
<div className="space-y-8">
<div>
<h2 className="text-sm font-bold tracking-widest text-feie-gold uppercase mb-3"> Contact</h2>
<h2 className="text-sm font-bold tracking-widest text-feie-gold uppercase mb-3">{t('title')} {t('subtitle')}</h2>
<h3 className="text-4xl md:text-5xl font-serif leading-tight">
<br/>
{t('heading')} <br/>
<span className="text-feie-white/50"></span>
</h3>
</div>
@ -146,8 +148,8 @@ const Contact: React.FC = () => {
<MapPin className="w-6 h-6 text-feie-gold" />
</div>
<div>
<p className="text-sm text-gray-400 uppercase tracking-wider mb-1"></p>
<p className="text-xl font-serif">8181630</p>
<p className="text-sm text-gray-400 uppercase tracking-wider mb-1">{t('info.address')}</p>
<p className="text-xl font-serif">{t('info.addressValue')}</p>
</div>
</div>
@ -156,7 +158,7 @@ const Contact: React.FC = () => {
<Phone className="w-6 h-6 text-feie-gold" />
</div>
<div>
<p className="text-sm text-gray-400 uppercase tracking-wider mb-1"></p>
<p className="text-sm text-gray-400 uppercase tracking-wider mb-1">{t('info.phone')}</p>
<p className="text-xl font-serif">19844561014</p>
</div>
</div>
@ -166,7 +168,7 @@ const Contact: React.FC = () => {
<Mail className="w-6 h-6 text-feie-gold" />
</div>
<div>
<p className="text-sm text-gray-400 uppercase tracking-wider mb-1"></p>
<p className="text-sm text-gray-400 uppercase tracking-wider mb-1">{t('info.email')}</p>
<a href="mailto:feie9454@gmail.com" className="text-xl font-serif hover:text-feie-gold transition-colors">
feie9454@gmail.com
</a>
@ -192,7 +194,7 @@ const Contact: React.FC = () => {
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label className="block text-sm font-bold uppercase tracking-wider text-gray-500 mb-2">
<span className="text-red-500">*</span>
{t('form.name')} <span className="text-red-500">*</span>
</label>
<input
type="text"
@ -202,13 +204,13 @@ const Contact: React.FC = () => {
className={`w-full bg-white border-b-2 p-3 focus:border-feie-gold outline-none transition-colors ${
errors.name ? 'border-red-500' : 'border-gray-200'
}`}
placeholder="您的姓名"
placeholder={t('form.name')}
/>
{errors.name && <p className="text-red-500 text-sm mt-1">{errors.name}</p>}
</div>
<div>
<label className="block text-sm font-bold uppercase tracking-wider text-gray-500 mb-2">
<span className="text-red-500">*</span>
{t('form.phone')} <span className="text-red-500">*</span>
</label>
<input
type="tel"
@ -218,14 +220,14 @@ const Contact: React.FC = () => {
className={`w-full bg-white border-b-2 p-3 focus:border-feie-gold outline-none transition-colors ${
errors.phone ? 'border-red-500' : 'border-gray-200'
}`}
placeholder="联系电话"
placeholder={t('form.phone')}
/>
{errors.phone && <p className="text-red-500 text-sm mt-1">{errors.phone}</p>}
</div>
</div>
<div>
<label className="block text-sm font-bold uppercase tracking-wider text-gray-500 mb-2">
<span className="text-red-500">*</span>
{t('form.email')} <span className="text-red-500">*</span>
</label>
<input
type="email"
@ -241,7 +243,7 @@ const Contact: React.FC = () => {
</div>
<div>
<label className="block text-sm font-bold uppercase tracking-wider text-gray-500 mb-2">
<span className="text-red-500">*</span>
{t('form.description')} <span className="text-red-500">*</span>
</label>
<textarea
rows={4}
@ -251,7 +253,7 @@ const Contact: React.FC = () => {
className={`w-full bg-white border-b-2 p-3 focus:border-feie-gold outline-none transition-colors resize-none ${
errors.description ? 'border-red-500' : 'border-gray-200'
}`}
placeholder="请简要描述您的需求..."
placeholder={t('form.description')}
></textarea>
{errors.description && <p className="text-red-500 text-sm mt-1">{errors.description}</p>}
</div>
@ -264,7 +266,7 @@ const Contact: React.FC = () => {
: 'bg-feie-dark text-feie-white hover:bg-feie-gold'
}`}
>
{isSubmitting ? '发送中...' : '发送信息'}
{isSubmitting ? t('form.submitting') : t('form.submit')}
</button>
</form>
</div>

View File

@ -1,17 +1,20 @@
import React from 'react';
import { useTranslations } from 'next-intl';
const Footer: React.FC = () => {
const t = useTranslations('Footer');
return (
<footer className="bg-feie-dark text-feie-white border-t border-white/10 py-12">
<div className="container mx-auto px-6 flex flex-col md:flex-row justify-between items-center gap-6">
<div className="text-center md:text-left">
<h5 className="font-serif text-xl font-bold mb-2"></h5>
<p className="text-gray-500 text-sm">© {new Date().getFullYear()} Nanjing Feie Information Technology Co., Ltd. All rights reserved.</p>
<h5 className="font-serif text-xl font-bold mb-2">{t('company')}</h5>
<p className="text-gray-500 text-sm">{t('rights', {year: new Date().getFullYear()})}</p>
</div>
<div className="flex gap-6 text-sm text-gray-400">
<a href="#" className="hover:text-feie-gold transition-colors"></a>
<a href="#" className="hover:text-feie-gold transition-colors"></a>
<a href="#" className="hover:text-feie-gold transition-colors">{t('privacy')}</a>
<a href="#" className="hover:text-feie-gold transition-colors">{t('terms')}</a>
</div>
</div>
</footer>

View File

@ -4,6 +4,7 @@ import React, { useRef, useMemo } from 'react';
import { Canvas, useFrame } from '@react-three/fiber';
import { Float, Stars } from '@react-three/drei';
import * as THREE from 'three';
import { useTranslations } from 'next-intl';
// ------------------- Three.js Components -------------------
@ -103,6 +104,9 @@ const Scene = () => {
// ------------------- Main Component -------------------
const Hero: React.FC = () => {
const t = useTranslations('Hero');
const tNav = useTranslations('Navbar');
return (
<section id="hero" className="relative w-full h-screen bg-feie-dark overflow-hidden">
{/* 3D Canvas Layer */}
@ -122,24 +126,24 @@ const Hero: React.FC = () => {
</span>
</div>
<h1 className="text-5xl md:text-7xl font-serif text-feie-white leading-tight">
<br />
<span className="text-feie-gold italic"></span>
{t('title')} <br />
<span className="text-feie-gold italic">{t('subtitle')}</span>
</h1>
<p className="text-feie-white/70 text-lg md:text-xl font-light max-w-md leading-relaxed">
{t('description')}
</p>
<div className="pt-8 flex gap-4">
<a
href="#services"
className="px-8 py-3 bg-feie-gold text-feie-white font-serif hover:bg-yellow-600 transition-colors duration-300 rounded-sm"
>
{t('cta')}
</a>
<a
href="#contact"
className="px-8 py-3 border border-feie-white text-feie-white font-serif hover:bg-feie-white hover:text-feie-dark transition-colors duration-300 rounded-sm"
>
{tNav('contact')}
</a>
</div>
</div>

View File

@ -1,18 +1,34 @@
'use client';
import React, { useState, useEffect } from 'react';
import { Menu, X } from 'lucide-react';
const navItems = [
{ label: '首页', href: '#hero' },
{ label: '关于我们', href: '#about' },
{ label: '核心业务', href: '#services' },
{ label: '联系方式', href: '#contact' },
];
import React, { useState, useEffect, useTransition } from 'react';
import { Menu, X, Globe } from 'lucide-react';
import { useTranslations, useLocale } from 'next-intl';
import { usePathname, useRouter } from '@/i18n/routing';
const Navbar: React.FC = () => {
const t = useTranslations('Navbar');
const locale = useLocale();
const router = useRouter();
const pathname = usePathname();
const [isPending, startTransition] = useTransition();
const [isScrolled, setIsScrolled] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [isLangMenuOpen, setIsLangMenuOpen] = useState(false);
const navItems = [
{ label: t('home'), href: '#hero' },
{ label: t('about'), href: '#about' },
{ label: t('services'), href: '#services' },
{ label: t('contact'), href: '#contact' },
];
const onSelectChange = (nextLocale: string) => {
startTransition(() => {
router.replace(pathname, {locale: nextLocale});
});
setIsLangMenuOpen(false);
};
useEffect(() => {
const handleScroll = () => {
@ -63,21 +79,52 @@ const Navbar: React.FC = () => {
{item.label}
</a>
))}
<a
href="#contact"
className={`px-5 py-2 border font-serif text-sm transition-all duration-300 ${
isScrolled
? 'border-feie-dark text-feie-dark hover:bg-feie-dark hover:text-feie-white'
: 'border-feie-white text-feie-white hover:bg-feie-white hover:text-feie-dark'
{/* Language Switcher */}
<div className="relative">
<button
onClick={() => setIsLangMenuOpen(!isLangMenuOpen)}
className={`flex items-center gap-1 font-serif text-sm tracking-widest uppercase hover:text-feie-gold transition-colors duration-300 ${
isScrolled ? 'text-feie-dark' : 'text-feie-white/90'
}`}
>
</a>
<Globe size={16} />
<span>{locale.toUpperCase()}</span>
</button>
{isLangMenuOpen && (
<div className="absolute top-full right-0 mt-2 w-24 bg-white rounded-md shadow-lg py-1 z-50">
{['zh', 'en', 'ja'].map((l) => (
<button
key={l}
onClick={() => onSelectChange(l)}
className={`block w-full text-left px-4 py-2 text-sm hover:bg-gray-100 ${locale === l ? 'text-feie-gold font-bold' : 'text-gray-700'}`}
>
{l === 'zh' ? '中文' : l === 'en' ? 'English' : '日本語'}
</button>
))}
</div>
)}
</div>
</div>
{/* Mobile Toggle */}
<div className="md:hidden flex items-center gap-4">
{/* Mobile Language Switcher */}
<button
className="md:hidden focus:outline-none"
onClick={() => {
const nextLocale = locale === 'zh' ? 'en' : locale === 'en' ? 'ja' : 'zh';
onSelectChange(nextLocale);
}}
className={`flex items-center gap-1 font-serif text-sm tracking-widest uppercase ${
isScrolled || isMobileMenuOpen ? 'text-feie-dark' : 'text-feie-white'
}`}
>
{locale.toUpperCase()}
</button>
<button
className="focus:outline-none"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
>
{isMobileMenuOpen ? (
@ -87,6 +134,7 @@ const Navbar: React.FC = () => {
)}
</button>
</div>
</div>
{/* Mobile Menu */}
<div

View File

@ -1,48 +1,51 @@
import React from 'react';
import { Monitor, Server, Code, Database, Globe, Shield } from 'lucide-react';
import { ServiceItem } from '../types';
import { useTranslations } from 'next-intl';
const Services: React.FC = () => {
const t = useTranslations('Services');
const services: ServiceItem[] = [
{
title: '定制软件开发',
description: '根据企业独特需求打造专属的Web应用、移动端APP及桌面软件优化业务流程。',
title: t('items.customDev.title'),
description: t('items.customDev.desc'),
icon: Code,
},
{
title: '企业数字化转型',
description: '提供全方位的数字化咨询与落地实施方案,助力传统企业实现智能化升级。',
title: t('items.digitalTrans.title'),
description: t('items.digitalTrans.desc'),
icon: Monitor,
},
{
title: '系统集成服务',
description: '打破信息孤岛,实现异构系统间的数据互通与功能协同,提升整体运营效率。',
title: t('items.systemIntegration.title'),
description: t('items.systemIntegration.desc'),
icon: Server,
},
{
title: '大数据分析',
description: '挖掘数据价值,提供可视化报表与智能决策支持,让数据成为企业的核心资产。',
title: t('items.bigData.title'),
description: t('items.bigData.desc'),
icon: Database,
},
{
title: '云服务与部署',
description: '提供安全可靠的云端架构设计、迁移及运维服务,保障业务的高可用性。',
title: t('items.cloudService.title'),
description: t('items.cloudService.desc'),
icon: Globe,
},
{
title: '信息安全保障',
description: '构建多层次的安全防护体系,保护企业核心数据资产不受威胁。',
title: t('items.security.title'),
description: t('items.security.desc'),
icon: Shield,
},
];
const Services: React.FC = () => {
return (
<section id="services" className="py-24 bg-white">
<div className="container mx-auto px-6">
<div className="text-center max-w-3xl mx-auto mb-16">
<h2 className="text-sm font-bold tracking-widest text-feie-gold uppercase mb-3"> Services</h2>
<h2 className="text-sm font-bold tracking-widest text-feie-gold uppercase mb-3">{t('title')} {t('subtitle')}</h2>
<h3 className="text-3xl md:text-4xl font-serif text-feie-dark mb-6">
{t('heading')}
</h3>
<div className="w-16 h-1 bg-feie-dark mx-auto"></div>
</div>

16
i18n/request.ts Normal file
View File

@ -0,0 +1,16 @@
import {getRequestConfig} from 'next-intl/server';
export default getRequestConfig(async ({requestLocale}) => {
// This typically corresponds to the `[locale]` segment
let locale = await requestLocale;
// Ensure that a valid locale is used
if (!locale || !['en', 'zh', 'ja'].includes(locale)) {
locale = 'zh';
}
return {
locale,
messages: (await import(`../messages/${locale}.json`)).default
};
});

15
i18n/routing.ts Normal file
View File

@ -0,0 +1,15 @@
import {defineRouting} from 'next-intl/routing';
import {createNavigation} from 'next-intl/navigation';
export const routing = defineRouting({
// A list of all locales that are supported
locales: ['en', 'zh', 'ja'],
// Used when no locale matches
defaultLocale: 'en'
});
// Lightweight wrappers around Next.js' navigation APIs
// that will consider the routing configuration
export const {Link, redirect, usePathname, useRouter, getPathname} =
createNavigation(routing);

96
messages/en.json Normal file
View File

@ -0,0 +1,96 @@
{
"Metadata": {
"title": "Nanjing Feie Information Technology | Digital Transformation & Software Development",
"description": "Nanjing Feie Information Technology specializes in custom software development, digital transformation, system integration, and big data analysis. We drive business value with innovative technology."
},
"Navbar": {
"home": "Home",
"about": "About Us",
"services": "Services",
"contact": "Contact"
},
"Hero": {
"title": "Digital Future",
"subtitle": "Innovation Leads Change",
"description": "We are committed to providing excellent digital solutions for enterprises, driving business value with innovative technology.",
"cta": "Learn More"
},
"About": {
"title": "About Us",
"subtitle": "About Us",
"heading": "Focus on Technology",
"subheading": "Achieve Excellence",
"p1": "Nanjing Feie Information Technology Co., Ltd. is located in Nanjing, the ancient capital of the Six Dynasties. We are a high-tech enterprise focusing on the R&D and application of cutting-edge information technology.",
"p2": "Since our establishment, we have always adhered to the concept of \"Technology Driven, Service First\", deeply cultivating in the fields of software development, system integration, and digital transformation consulting. We have an experienced and creative technical team dedicated to changing the world through code and connecting the future with wisdom.",
"p3": "In the vibrant innovation hot land of Lishui District, we are providing customized IT solutions for customers in various industries with steady steps, helping enterprises ride the wind and waves in the digital economy.",
"stats": {
"cases": "Successful Cases",
"support": "Tech Support"
}
},
"Services": {
"title": "Core Services",
"subtitle": "Services",
"heading": "Comprehensive Tech Solutions",
"items": {
"customDev": {
"title": "Custom Software Development",
"desc": "Build exclusive Web applications, mobile APPs, and desktop software according to unique enterprise needs to optimize business processes."
},
"digitalTrans": {
"title": "Digital Transformation",
"desc": "Provide comprehensive digital consulting and implementation plans to help traditional enterprises achieve intelligent upgrades."
},
"systemIntegration": {
"title": "System Integration",
"desc": "Break information silos, achieve data interoperability and functional synergy between heterogeneous systems, and improve overall operational efficiency."
},
"bigData": {
"title": "Big Data Analysis",
"desc": "Mine data value, provide visual reports and intelligent decision support, making data a core asset of the enterprise."
},
"cloudService": {
"title": "Cloud Services & Deployment",
"desc": "Provide safe and reliable cloud architecture design, migration, and operation and maintenance services to ensure high availability of business."
},
"security": {
"title": "Information Security",
"desc": "Build a multi-level security protection system to protect enterprise core data assets from threats."
}
}
},
"Contact": {
"title": "Contact Us",
"subtitle": "Contact Us",
"heading": "Start Your Digital Journey",
"form": {
"name": "Name",
"phone": "Phone",
"email": "Email",
"description": "Description",
"submit": "Submit",
"submitting": "Submitting...",
"success": "Message submitted successfully, we will contact you soon!",
"errors": {
"nameRequired": "Please enter your name",
"phoneRequired": "Please enter your phone number",
"phoneInvalid": "Please enter a valid phone number",
"emailRequired": "Please enter your email",
"emailInvalid": "Please enter a valid email address",
"descRequired": "Please describe your needs"
}
},
"info": {
"address": "Registered Address",
"addressValue": "Room 1630, Building 8, No. 81 Zhongda Street, Yongyang Subdistrict, Lishui District, Nanjing, Jiangsu Province",
"phone": "Phone",
"email": "Email"
}
},
"Footer": {
"company": "Nanjing Feie Information Technology Co., Ltd.",
"rights": "© {year} Nanjing Feie Information Technology Co., Ltd. All rights reserved.",
"privacy": "Privacy Policy",
"terms": "Terms of Service"
}
}

96
messages/ja.json Normal file
View File

@ -0,0 +1,96 @@
{
"Metadata": {
"title": "南京市肥鹅信息技术有限公司 | DX推進・ソフトウェア開発",
"description": "南京市肥鹅信息技术有限公司は、カスタムソフトウェア開発、企業のデジタルトランスフォーメーションDX、システムインテグレーション、ビッグデータ分析を専門としています。革新的な技術でビジネス価値を創造します。"
},
"Navbar": {
"home": "ホーム",
"about": "私たちについて",
"services": "サービス",
"contact": "お問い合わせ"
},
"Hero": {
"title": "デジタルが未来を拓く",
"subtitle": "革新が変革を導く",
"description": "私たちは、革新的な技術でビジネス価値を創造し、企業に卓越したデジタルソリューションを提供することに尽力しています。",
"cta": "詳細を見る"
},
"About": {
"title": "私たちについて",
"subtitle": "About Us",
"heading": "技術へのこだわり",
"subheading": "卓越した品質の追求",
"p1": "南京市肥鹅信息技术有限公司は、歴史ある六朝の古都、南京に位置しています。最先端の情報技術の研究開発と応用に注力するハイテク企業です。",
"p2": "設立以来、「技術主導、サービス第一」の理念を掲げ、ソフトウェア開発、システムインテグレーション、デジタルトランスフォーメーションコンサルティングの分野で深く活動してきました。経験豊富で創造的な技術チームを擁し、コードで世界を変え、知恵で未来をつなぐことに尽力しています。",
"p3": "活気あふれる溧水区のイベーションの地で、私たちは着実な歩みで、各業界のお客様にカスタマイズされたITソリューションを提供し、デジタル経済の波に乗る企業を支援しています。",
"stats": {
"cases": "成功事例",
"support": "技術サポート"
}
},
"Services": {
"title": "コアサービス",
"subtitle": "Services",
"heading": "包括的な技術ソリューション",
"items": {
"customDev": {
"title": "カスタムソフトウェア開発",
"desc": "企業の独自のニーズに合わせて、専用のWebアプリケーション、モバイルアプリ、デスクトップソフトウェアを構築し、業務プロセスを最適化します。"
},
"digitalTrans": {
"title": "企業のデジタルトランスフォーメーション",
"desc": "包括的なデジタルコンサルティングと実装計画を提供し、伝統的な企業のインテリジェントなアップグレードを支援します。"
},
"systemIntegration": {
"title": "システムインテグレーション",
"desc": "情報の孤立を打破し、異種システム間のデータ相互運用性と機能的相乗効果を実現し、全体的な運用効率を向上させます。"
},
"bigData": {
"title": "ビッグデータ分析",
"desc": "データの価値を掘り起こし、視覚的なレポートとインテリジェントな意思決定サポートを提供し、データを企業のコア資産にします。"
},
"cloudService": {
"title": "クラウドサービスと展開",
"desc": "安全で信頼性の高いクラウドアーキテクチャの設計、移行、運用保守サービスを提供し、ビジネスの高可用性を保証します。"
},
"security": {
"title": "情報セキュリティ保証",
"desc": "多層的なセキュリティ保護システムを構築し、企業のコアデータ資産を脅威から保護します。"
}
}
},
"Contact": {
"title": "お問い合わせ",
"subtitle": "Contact Us",
"heading": "デジタルの旅を始めましょう",
"form": {
"name": "お名前",
"phone": "電話番号",
"email": "メールアドレス",
"description": "ご要望",
"submit": "送信",
"submitting": "送信中...",
"success": "メッセージが送信されました。すぐにご連絡いたします!",
"errors": {
"nameRequired": "お名前を入力してください",
"phoneRequired": "電話番号を入力してください",
"phoneInvalid": "有効な電話番号を入力してください",
"emailRequired": "メールアドレスを入力してください",
"emailInvalid": "有効なメールアドレスを入力してください",
"descRequired": "ご要望を入力してください"
}
},
"info": {
"address": "登録住所",
"addressValue": "江蘇省南京市溧水区永陽街道中大街81号8棟1630室",
"phone": "電話番号",
"email": "メールアドレス"
}
},
"Footer": {
"company": "南京市肥鹅信息技术有限公司",
"rights": "© {year} Nanjing Feie Information Technology Co., Ltd. All rights reserved.",
"privacy": "プライバシーポリシー",
"terms": "利用規約"
}
}

96
messages/zh.json Normal file
View File

@ -0,0 +1,96 @@
{
"Metadata": {
"title": "南京市肥鹅信息技术有限公司 | 数字化转型与软件开发专家",
"description": "南京市肥鹅信息技术有限公司专注于定制软件开发、企业数字化转型、系统集成及大数据分析。我们以创新技术驱动商业价值为您提供卓越的IT解决方案。"
},
"Navbar": {
"home": "首页",
"about": "关于我们",
"services": "核心业务",
"contact": "联系方式"
},
"Hero": {
"title": "数字驱动未来",
"subtitle": "创新引领变革",
"description": "我们致力于为企业提供卓越的数字化解决方案,以创新技术驱动商业价值。",
"cta": "了解更多"
},
"About": {
"title": "关于我们",
"subtitle": "About Us",
"heading": "专注技术沉淀",
"subheading": "成就卓越品质",
"p1": "南京市肥鹅信息技术有限公司坐落于历史悠久的六朝古都——南京。我们是一家专注于前沿信息技术研发与应用的高新技术企业。",
"p2": "自成立以来,我们始终秉承\"技术驱动、服务至上\"的理念,深耕软件开发、系统集成及数字化转型咨询领域。我们拥有一支经验丰富、富有创造力的技术团队,致力于通过代码改变世界,用智慧连接未来。",
"p3": "在溧水区这片充满活力的创新热土上我们正以稳健的步伐为各行各业的客户提供量身定制的IT解决方案助力企业在数字经济浪潮中乘风破浪。",
"stats": {
"cases": "成功案例",
"support": "技术支持"
}
},
"Services": {
"title": "核心业务",
"subtitle": "Services",
"heading": "全方位技术解决方案",
"items": {
"customDev": {
"title": "定制软件开发",
"desc": "根据企业独特需求打造专属的Web应用、移动端APP及桌面软件优化业务流程。"
},
"digitalTrans": {
"title": "企业数字化转型",
"desc": "提供全方位的数字化咨询与落地实施方案,助力传统企业实现智能化升级。"
},
"systemIntegration": {
"title": "系统集成服务",
"desc": "打破信息孤岛,实现异构系统间的数据互通与功能协同,提升整体运营效率。"
},
"bigData": {
"title": "大数据分析",
"desc": "挖掘数据价值,提供可视化报表与智能决策支持,让数据成为企业的核心资产。"
},
"cloudService": {
"title": "云服务与部署",
"desc": "提供安全可靠的云端架构设计、迁移及运维服务,保障业务的高可用性。"
},
"security": {
"title": "信息安全保障",
"desc": "构建多层次的安全防护体系,保护企业核心数据资产不受威胁。"
}
}
},
"Contact": {
"title": "联系我们",
"subtitle": "Contact Us",
"heading": "开启您的数字化之旅",
"form": {
"name": "姓名",
"phone": "电话",
"email": "邮箱",
"description": "需求描述",
"submit": "提交留言",
"submitting": "提交中...",
"success": "留言提交成功,我们会尽快与您联系!",
"errors": {
"nameRequired": "请输入姓名",
"phoneRequired": "请输入电话",
"phoneInvalid": "请输入正确的手机号",
"emailRequired": "请输入邮箱",
"emailInvalid": "请输入正确的邮箱地址",
"descRequired": "请描述您的需求"
}
},
"info": {
"address": "注册地址",
"addressValue": "江苏省南京市溧水区永阳街道中大街81号8幢1630室",
"phone": "联系电话",
"email": "电子邮箱"
}
},
"Footer": {
"company": "南京市肥鹅信息技术有限公司",
"rights": "© {year} Nanjing Feie Information Technology Co., Ltd. All rights reserved.",
"privacy": "隐私政策",
"terms": "服务条款"
}
}

11
middleware.ts Normal file
View File

@ -0,0 +1,11 @@
import createMiddleware from 'next-intl/middleware';
import {routing} from './i18n/routing';
export default createMiddleware(routing);
export const config = {
// Match all pathnames except for
// - … if they start with `/api`, `/_next` or `/_vercel`
// - … the ones containing a dot (e.g. `favicon.ico`)
matcher: ['/((?!api|_next|_vercel|.*\\..*).*)']
};

View File

@ -1,7 +1,10 @@
import type { NextConfig } from "next";
import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin('./i18n/request.ts');
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;
export default withNextIntl(nextConfig);

View File

@ -14,6 +14,7 @@
"@react-three/fiber": "^9.4.2",
"lucide-react": "^0.559.0",
"next": "16.0.8",
"next-intl": "^4.6.1",
"prisma": "^6.0.0",
"react": "19.2.1",
"react-dom": "19.2.1",

View File

@ -1 +0,0 @@
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>

Before

Width:  |  Height:  |  Size: 391 B

View File

@ -1 +0,0 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

BIN
public/icon.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1 +0,0 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 128 B

View File

@ -1 +0,0 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>

Before

Width:  |  Height:  |  Size: 385 B