From de9982c9eb333a36da8d07dda1bd2a682ee9ceab Mon Sep 17 00:00:00 2001 From: MisakaAkio Date: Sat, 22 Aug 2026 22:23:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=BB=BA=E8=AE=BE=E4=B8=BB?= =?UTF-8?q?=E9=A1=B5=E5=92=8C=E6=96=B0=E9=97=BB=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 24 +- components.json | 9 - package.json | 12 +- pnpm-lock.yaml | 389 ++-------------------- postcss.config.mjs | 2 - public/brand/.gitkeep | 1 + public/icon/icon.svg | 5 + public/icon/kivotosrailway.svg | 13 + src/app/globals.css | 160 ++++++++- src/app/layout.tsx | 7 +- src/app/news/[slug]/page.tsx | 45 +++ src/app/news/page.tsx | 25 ++ src/app/page.tsx | 15 +- src/components/home/home-page-content.tsx | 85 +++++ src/components/layout/page-breadcrumb.tsx | 14 + src/components/layout/site-footer.tsx | 113 +++++++ src/components/layout/site-header.tsx | 91 +++++ src/components/news/news-list.tsx | 57 ++++ src/components/news/news-share.tsx | 40 +++ src/components/ui/button.tsx | 17 - src/data/news/index.ts | 204 ++++++++++++ src/data/news/posts/20240713-mcnews.md | 15 + src/data/news/posts/20240714-mcnews.md | 22 ++ src/data/news/posts/20240728-mcnews.md | 15 + src/data/news/posts/20240729-mcnews.md | 24 ++ src/data/news/posts/20240731-mcnews.md | 21 ++ src/data/news/posts/20240801-mcnews.md | 24 ++ src/data/news/posts/20240802-mcnews.md | 17 + src/data/news/posts/20240807-mcnews.md | 24 ++ src/data/news/posts/20240808-mcnews.md | 18 + src/data/news/posts/20240811-mcnews.md | 25 ++ src/data/news/posts/20240821-mcnews.md | 35 ++ src/data/news/posts/20240823-mcnews.md | 22 ++ src/data/news/posts/20240901-mcnews.md | 38 +++ src/data/news/posts/20240903-mcnews.md | 58 ++++ src/data/news/posts/20240906-mcnews.md | 39 +++ src/data/news/posts/20240917-mcnews.md | 21 ++ src/data/news/posts/20241004-mcnews.md | 17 + src/data/news/posts/20241005-mcnews.md | 59 ++++ src/data/news/posts/20241010-mcnews.md | 30 ++ src/data/news/posts/20241213-mcnews.md | 54 +++ src/data/news/posts/20241231-mcnews.md | 47 +++ src/data/news/posts/20250131-mcnews.md | 68 ++++ src/data/news/posts/20250228-mcnews.md | 26 ++ src/data/news/posts/20250331-mcnews.md | 25 ++ src/data/news/posts/20250430-mcnews.md | 72 ++++ src/data/news/posts/20250531-mcnews.md | 41 +++ src/data/news/posts/20250630-mcnews.md | 40 +++ src/data/news/posts/20250731-mcnews.md | 65 ++++ src/data/news/posts/20250831-mcnews.md | 59 ++++ src/data/news/posts/20250930-mcnews.md | 33 ++ src/data/news/posts/20251031-mcnews.md | 37 ++ src/data/news/posts/20251130-mcnews.md | 49 +++ src/data/news/posts/20251231-mcnews.md | 74 ++++ src/data/news/posts/20260131-mcnews.md | 124 +++++++ src/data/news/posts/Line-HM.md | 77 +++++ src/data/news/posts/Line-KS.md | 40 +++ src/data/news/posts/Line-UW.md | 29 ++ src/data/news/posts/Plan-1.md | 53 +++ src/data/news/posts/Plan-2.md | 31 ++ src/data/news/posts/Plan-City1.md | 20 ++ src/data/news/posts/Plan-IC1.md | 20 ++ src/data/news/posts/Plan-West.md | 28 ++ src/data/news/posts/mc-chiho.md | 19 ++ src/data/news/posts/mc-intro.md | 57 ++++ src/data/news/posts/mc-kuro.md | 20 ++ src/data/news/posts/mc-lumi.md | 9 + src/data/news/posts/mc-yuiko.md | 19 ++ src/lib/hexo.ts | 82 +++++ src/lib/i18n.ts | 56 ++++ src/lib/utils.ts | 6 - src/locales/en.json | 27 ++ src/locales/ja.json | 27 ++ src/locales/zh-CN.json | 27 ++ src/locales/zh-TW.json | 27 ++ 75 files changed, 2913 insertions(+), 427 deletions(-) delete mode 100644 components.json delete mode 100644 postcss.config.mjs create mode 100644 public/brand/.gitkeep create mode 100644 public/icon/icon.svg create mode 100644 public/icon/kivotosrailway.svg create mode 100644 src/app/news/[slug]/page.tsx create mode 100644 src/app/news/page.tsx create mode 100644 src/components/home/home-page-content.tsx create mode 100644 src/components/layout/page-breadcrumb.tsx create mode 100644 src/components/layout/site-footer.tsx create mode 100644 src/components/layout/site-header.tsx create mode 100644 src/components/news/news-list.tsx create mode 100644 src/components/news/news-share.tsx delete mode 100644 src/components/ui/button.tsx create mode 100644 src/data/news/index.ts create mode 100644 src/data/news/posts/20240713-mcnews.md create mode 100644 src/data/news/posts/20240714-mcnews.md create mode 100644 src/data/news/posts/20240728-mcnews.md create mode 100644 src/data/news/posts/20240729-mcnews.md create mode 100644 src/data/news/posts/20240731-mcnews.md create mode 100644 src/data/news/posts/20240801-mcnews.md create mode 100644 src/data/news/posts/20240802-mcnews.md create mode 100644 src/data/news/posts/20240807-mcnews.md create mode 100644 src/data/news/posts/20240808-mcnews.md create mode 100644 src/data/news/posts/20240811-mcnews.md create mode 100644 src/data/news/posts/20240821-mcnews.md create mode 100644 src/data/news/posts/20240823-mcnews.md create mode 100644 src/data/news/posts/20240901-mcnews.md create mode 100644 src/data/news/posts/20240903-mcnews.md create mode 100644 src/data/news/posts/20240906-mcnews.md create mode 100644 src/data/news/posts/20240917-mcnews.md create mode 100644 src/data/news/posts/20241004-mcnews.md create mode 100644 src/data/news/posts/20241005-mcnews.md create mode 100644 src/data/news/posts/20241010-mcnews.md create mode 100644 src/data/news/posts/20241213-mcnews.md create mode 100644 src/data/news/posts/20241231-mcnews.md create mode 100644 src/data/news/posts/20250131-mcnews.md create mode 100644 src/data/news/posts/20250228-mcnews.md create mode 100644 src/data/news/posts/20250331-mcnews.md create mode 100644 src/data/news/posts/20250430-mcnews.md create mode 100644 src/data/news/posts/20250531-mcnews.md create mode 100644 src/data/news/posts/20250630-mcnews.md create mode 100644 src/data/news/posts/20250731-mcnews.md create mode 100644 src/data/news/posts/20250831-mcnews.md create mode 100644 src/data/news/posts/20250930-mcnews.md create mode 100644 src/data/news/posts/20251031-mcnews.md create mode 100644 src/data/news/posts/20251130-mcnews.md create mode 100644 src/data/news/posts/20251231-mcnews.md create mode 100644 src/data/news/posts/20260131-mcnews.md create mode 100644 src/data/news/posts/Line-HM.md create mode 100644 src/data/news/posts/Line-KS.md create mode 100644 src/data/news/posts/Line-UW.md create mode 100644 src/data/news/posts/Plan-1.md create mode 100644 src/data/news/posts/Plan-2.md create mode 100644 src/data/news/posts/Plan-City1.md create mode 100644 src/data/news/posts/Plan-IC1.md create mode 100644 src/data/news/posts/Plan-West.md create mode 100644 src/data/news/posts/mc-chiho.md create mode 100644 src/data/news/posts/mc-intro.md create mode 100644 src/data/news/posts/mc-kuro.md create mode 100644 src/data/news/posts/mc-lumi.md create mode 100644 src/data/news/posts/mc-yuiko.md create mode 100644 src/lib/hexo.ts create mode 100644 src/lib/i18n.ts delete mode 100644 src/lib/utils.ts create mode 100644 src/locales/en.json create mode 100644 src/locales/ja.json create mode 100644 src/locales/zh-CN.json create mode 100644 src/locales/zh-TW.json diff --git a/README.md b/README.md index a4b53b3..fee1314 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,25 @@ # KivotosRailway 第二代官网 -正在~~用AI~~创作 \ No newline at end of file +正在~~用AI~~创作 + +## 本地最新资讯说明 + +首页已改为纯本地数据展示,当前显示最近 3 条资讯,内容直接维护在前端页面中,便于快速迭代与本地调试。 + +### 1. 数据位置 + +首页资讯内容位于: + +- `src/app/page.tsx` + +### 2. 展示规则 + +当前首页只展示最新 3 条: + +- 标题区 +- 3 个资讯卡片 +- 图片 + 标题 + 日期 + +### 3. 后续扩展 + +如果后续需要从其他来源更新内容,可以直接在该数组中补充数据,或替换成新的数据源实现,但当前版本不再依赖 Hexo。 \ No newline at end of file diff --git a/components.json b/components.json deleted file mode 100644 index 893a183..0000000 --- a/components.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "new-york", - "rsc": true, - "tsx": true, - "tailwind": { "config": "", "css": "src/app/globals.css", "baseColor": "neutral", "cssVariables": true }, - "aliases": { "components": "@/components", "utils": "@/lib/utils", "ui": "@/components/ui", "lib": "@/lib", "hooks": "@/hooks" }, - "iconLibrary": "lucide" -} diff --git a/package.json b/package.json index f0c6322..d107230 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kivotosrailway-website-v2", - "version": "2.0.0", + "version": "0.1.0", "private": true, "packageManager": "pnpm@11.22.0", "scripts": { @@ -10,15 +10,11 @@ "lint": "eslint" }, "dependencies": { - "@tailwindcss/postcss": "^4.3.3", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "lucide-react": "^1.31.0", + "@fontsource-variable/noto-sans": "^5.3.0", + "@fontsource-variable/noto-sans-sc": "^5.3.0", "next": "latest", "react": "latest", - "react-dom": "latest", - "tailwind-merge": "^3.6.0", - "tailwindcss": "^4.3.3" + "react-dom": "latest" }, "devDependencies": { "@types/node": "latest", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2495819..429a5c6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,18 +8,12 @@ importers: .: dependencies: - '@tailwindcss/postcss': - specifier: ^4.3.3 - version: 4.3.3 - class-variance-authority: - specifier: ^0.7.1 - version: 0.7.1 - clsx: - specifier: ^2.1.1 - version: 2.1.1 - lucide-react: - specifier: ^1.31.0 - version: 1.31.0(react@19.2.8) + '@fontsource-variable/noto-sans': + specifier: ^5.3.0 + version: 5.3.0 + '@fontsource-variable/noto-sans-sc': + specifier: ^5.3.0 + version: 5.3.0 next: specifier: latest version: 16.3.1(@babel/core@7.29.7)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -29,12 +23,6 @@ importers: react-dom: specifier: latest version: 19.2.8(react@19.2.8) - tailwind-merge: - specifier: ^3.6.0 - version: 3.6.0 - tailwindcss: - specifier: ^4.3.3 - version: 4.3.3 devDependencies: '@types/node': specifier: latest @@ -57,10 +45,6 @@ importers: packages: - '@alloc/quick-lru@5.2.0': - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} - engines: {node: '>=10'} - '@babel/code-frame@7.29.7': resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} @@ -176,6 +160,12 @@ packages: resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@fontsource-variable/noto-sans-sc@5.3.0': + resolution: {integrity: sha512-lNar1dF7Ik/lHNPo/7JWG0TolXY29LtsqYgMvEysooZ5bsO9uH4shJmRrwyJ3PjyTPljhpMJEK0jDuLSU4vJ1w==} + + '@fontsource-variable/noto-sans@5.3.0': + resolution: {integrity: sha512-e3ZuxzY9AL2psXPZlhwhnYrHUHv6PMoyK9MQ7croF0CUgURLqu9EMjW7q2FgVLwij1tjLsIHQrnwQ8aUcg4BiA==} + '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} @@ -461,98 +451,6 @@ packages: '@swc/helpers@0.5.23': resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==} - '@tailwindcss/node@4.3.3': - resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==} - - '@tailwindcss/oxide-android-arm64@4.3.3': - resolution: {integrity: sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [android] - - '@tailwindcss/oxide-darwin-arm64@4.3.3': - resolution: {integrity: sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [darwin] - - '@tailwindcss/oxide-darwin-x64@4.3.3': - resolution: {integrity: sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==} - engines: {node: '>= 20'} - cpu: [x64] - os: [darwin] - - '@tailwindcss/oxide-freebsd-x64@4.3.3': - resolution: {integrity: sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==} - engines: {node: '>= 20'} - cpu: [x64] - os: [freebsd] - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': - resolution: {integrity: sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==} - engines: {node: '>= 20'} - cpu: [arm] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': - resolution: {integrity: sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@tailwindcss/oxide-linux-arm64-musl@4.3.3': - resolution: {integrity: sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@tailwindcss/oxide-linux-x64-gnu@4.3.3': - resolution: {integrity: sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@tailwindcss/oxide-linux-x64-musl@4.3.3': - resolution: {integrity: sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@tailwindcss/oxide-wasm32-wasi@4.3.3': - resolution: {integrity: sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib - - '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': - resolution: {integrity: sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [win32] - - '@tailwindcss/oxide-win32-x64-msvc@4.3.3': - resolution: {integrity: sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==} - engines: {node: '>= 20'} - cpu: [x64] - os: [win32] - - '@tailwindcss/oxide@4.3.3': - resolution: {integrity: sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==} - engines: {node: '>= 20'} - - '@tailwindcss/postcss@4.3.3': - resolution: {integrity: sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==} - '@tybys/wasm-util@0.10.3': resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} @@ -989,16 +887,9 @@ packages: caniuse-lite@1.0.30001809: resolution: {integrity: sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==} - class-variance-authority@0.7.1: - resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} - client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - clsx@2.1.1: - resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} - engines: {node: '>=6'} - concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -1073,10 +964,6 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - enhanced-resolve@5.24.5: - resolution: {integrity: sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==} - engines: {node: '>=10.13.0'} - es-abstract-get@1.0.0: resolution: {integrity: sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==} engines: {node: '>= 0.4'} @@ -1338,9 +1225,6 @@ packages: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -1551,80 +1435,6 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lightningcss-android-arm64@1.32.0: - resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] - - lightningcss-darwin-arm64@1.32.0: - resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.32.0: - resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.32.0: - resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.32.0: - resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.32.0: - resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - lightningcss-linux-arm64-musl@1.32.0: - resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [musl] - - lightningcss-linux-x64-gnu@1.32.0: - resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [glibc] - - lightningcss-linux-x64-musl@1.32.0: - resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [musl] - - lightningcss-win32-arm64-msvc@1.32.0: - resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.32.0: - resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.32.0: - resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} - engines: {node: '>= 12.0.0'} - locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1636,14 +1446,6 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lucide-react@1.31.0: - resolution: {integrity: sha512-G8u2eEtoHUnUa9f8lbvqDhCiORMnYLdUEo06EEG9MQvHQrInKcX3Pa2TH39MM5qyzRcWETxB0+aOwAPI1g1kEg==} - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -1962,16 +1764,6 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - tailwind-merge@3.6.0: - resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} - - tailwindcss@4.3.3: - resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==} - - tapable@2.3.3: - resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} - engines: {node: '>=6'} - tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} @@ -2086,8 +1878,6 @@ packages: snapshots: - '@alloc/quick-lru@5.2.0': {} - '@babel/code-frame@7.29.7': dependencies: '@babel/helper-validator-identifier': 7.29.7 @@ -2244,6 +2034,10 @@ snapshots: '@eslint/core': 1.2.1 levn: 0.4.1 + '@fontsource-variable/noto-sans-sc@5.3.0': {} + + '@fontsource-variable/noto-sans@5.3.0': {} + '@humanfs/core@0.19.2': dependencies: '@humanfs/types': 0.15.0 @@ -2446,75 +2240,6 @@ snapshots: dependencies: tslib: 2.8.1 - '@tailwindcss/node@4.3.3': - dependencies: - '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.24.5 - jiti: 2.7.0 - lightningcss: 1.32.0 - magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.3.3 - - '@tailwindcss/oxide-android-arm64@4.3.3': - optional: true - - '@tailwindcss/oxide-darwin-arm64@4.3.3': - optional: true - - '@tailwindcss/oxide-darwin-x64@4.3.3': - optional: true - - '@tailwindcss/oxide-freebsd-x64@4.3.3': - optional: true - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': - optional: true - - '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': - optional: true - - '@tailwindcss/oxide-linux-arm64-musl@4.3.3': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.3.3': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.3.3': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.3.3': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.3.3': - optional: true - - '@tailwindcss/oxide@4.3.3': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.3.3 - '@tailwindcss/oxide-darwin-arm64': 4.3.3 - '@tailwindcss/oxide-darwin-x64': 4.3.3 - '@tailwindcss/oxide-freebsd-x64': 4.3.3 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.3 - '@tailwindcss/oxide-linux-arm64-gnu': 4.3.3 - '@tailwindcss/oxide-linux-arm64-musl': 4.3.3 - '@tailwindcss/oxide-linux-x64-gnu': 4.3.3 - '@tailwindcss/oxide-linux-x64-musl': 4.3.3 - '@tailwindcss/oxide-wasm32-wasi': 4.3.3 - '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 - '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 - - '@tailwindcss/postcss@4.3.3': - dependencies: - '@alloc/quick-lru': 5.2.0 - '@tailwindcss/node': 4.3.3 - '@tailwindcss/oxide': 4.3.3 - postcss: 8.5.23 - tailwindcss: 4.3.3 - '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 @@ -2901,14 +2626,8 @@ snapshots: caniuse-lite@1.0.30001809: {} - class-variance-authority@0.7.1: - dependencies: - clsx: 2.1.1 - client-only@0.0.1: {} - clsx@2.1.1: {} - concat-map@0.0.1: {} convert-source-map@2.0.0: {} @@ -2963,7 +2682,8 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - detect-libc@2.1.2: {} + detect-libc@2.1.2: + optional: true doctrine@2.1.0: dependencies: @@ -2979,11 +2699,6 @@ snapshots: emoji-regex@9.2.2: {} - enhanced-resolve@5.24.5: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.3 - es-abstract-get@1.0.0: dependencies: es-errors: 1.3.0 @@ -3411,8 +3126,6 @@ snapshots: gopd@1.2.0: {} - graceful-fs@4.2.11: {} - has-bigints@1.1.0: {} has-property-descriptors@1.0.2: @@ -3580,7 +3293,8 @@ snapshots: has-symbols: 1.1.0 set-function-name: 2.0.2 - jiti@2.7.0: {} + jiti@2.7.0: + optional: true js-tokens@4.0.0: {} @@ -3620,55 +3334,6 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lightningcss-android-arm64@1.32.0: - optional: true - - lightningcss-darwin-arm64@1.32.0: - optional: true - - lightningcss-darwin-x64@1.32.0: - optional: true - - lightningcss-freebsd-x64@1.32.0: - optional: true - - lightningcss-linux-arm-gnueabihf@1.32.0: - optional: true - - lightningcss-linux-arm64-gnu@1.32.0: - optional: true - - lightningcss-linux-arm64-musl@1.32.0: - optional: true - - lightningcss-linux-x64-gnu@1.32.0: - optional: true - - lightningcss-linux-x64-musl@1.32.0: - optional: true - - lightningcss-win32-arm64-msvc@1.32.0: - optional: true - - lightningcss-win32-x64-msvc@1.32.0: - optional: true - - lightningcss@1.32.0: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.32.0 - lightningcss-darwin-arm64: 1.32.0 - lightningcss-darwin-x64: 1.32.0 - lightningcss-freebsd-x64: 1.32.0 - lightningcss-linux-arm-gnueabihf: 1.32.0 - lightningcss-linux-arm64-gnu: 1.32.0 - lightningcss-linux-arm64-musl: 1.32.0 - lightningcss-linux-x64-gnu: 1.32.0 - lightningcss-linux-x64-musl: 1.32.0 - lightningcss-win32-arm64-msvc: 1.32.0 - lightningcss-win32-x64-msvc: 1.32.0 - locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -3681,14 +3346,6 @@ snapshots: dependencies: yallist: 3.1.1 - lucide-react@1.31.0(react@19.2.8): - dependencies: - react: 19.2.8 - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - math-intrinsics@1.1.0: {} merge2@1.4.1: {} @@ -4080,12 +3737,6 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - tailwind-merge@3.6.0: {} - - tailwindcss@4.3.3: {} - - tapable@2.3.3: {} - tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.5) diff --git a/postcss.config.mjs b/postcss.config.mjs deleted file mode 100644 index d062fcd..0000000 --- a/postcss.config.mjs +++ /dev/null @@ -1,2 +0,0 @@ -const config = { plugins: { "@tailwindcss/postcss": {} } }; -export default config; diff --git a/public/brand/.gitkeep b/public/brand/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/public/brand/.gitkeep @@ -0,0 +1 @@ + diff --git a/public/icon/icon.svg b/public/icon/icon.svg new file mode 100644 index 0000000..e2291cf --- /dev/null +++ b/public/icon/icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/icon/kivotosrailway.svg b/public/icon/kivotosrailway.svg new file mode 100644 index 0000000..bc17f59 --- /dev/null +++ b/public/icon/kivotosrailway.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/app/globals.css b/src/app/globals.css index ecbdc72..12517d3 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,6 +1,156 @@ -@import "tailwindcss"; +@import "@fontsource-variable/noto-sans/wght.css"; +@import "@fontsource-variable/noto-sans-sc/wght.css"; -:root { --background: oklch(1 0 0); --foreground: oklch(0.145 0 0); --primary: oklch(0.205 0 0); --primary-foreground: oklch(0.985 0 0); --secondary: oklch(0.97 0 0); --secondary-foreground: oklch(0.205 0 0); --muted-foreground: oklch(0.556 0 0); --accent: oklch(0.97 0 0); --accent-foreground: oklch(0.205 0 0); --destructive: oklch(0.577 0.245 27.325); --border: oklch(0.922 0 0); --input: oklch(0.922 0 0); --ring: oklch(0.708 0 0); } -@theme inline { --color-background: var(--background); --color-foreground: var(--foreground); --color-primary: var(--primary); --color-primary-foreground: var(--primary-foreground); --color-secondary: var(--secondary); --color-secondary-foreground: var(--secondary-foreground); --color-accent: var(--accent); --color-accent-foreground: var(--accent-foreground); --color-destructive: var(--destructive); --color-border: var(--border); --color-input: var(--input); --color-ring: var(--ring); } -* { box-sizing: border-box; border-color: var(--border); } -body { margin: 0; min-height: 100%; background: var(--background); color: var(--foreground); font-family: Arial, Helvetica, sans-serif; } +:root { --ink: #0b1622; --blue: #1267d8; --paper: #ffffff; --soft: #f5f7f9; --muted: #75828d; --panel: #f6f7f8; } +* { box-sizing: border-box; } +html, body { min-height: 100%; margin: 0; } +body { color: var(--ink); background: var(--paper); font-family: "Noto Sans SC", "Noto Sans", Arial, "Microsoft YaHei", sans-serif; } +a { color: inherit; text-decoration: none; } +.site-header { display: flex; align-items: center; height: 128px; gap: 32px; padding: 0 clamp(24px, 4vw, 76px); background: #fff; } +.site-logo { display: inline-flex; align-items: center; min-width: 248px; } +.site-logo-image { display: block; width: min(240px, 18vw); height: auto; } +.site-navigation { display: flex; align-items: center; justify-content: flex-end; flex: 1; gap: clamp(28px, 3vw, 64px); } +.site-navigation a { position: relative; padding: 8px 0; font-size: 15px; font-weight: 700; white-space: nowrap; } +.site-navigation a::after { position: absolute; right: 0; bottom: 0; left: 0; height: 2px; content: ""; background: var(--blue); transform: scaleX(0); transition: transform .2s ease; } +.site-navigation a:hover { color: var(--blue); }.site-navigation a:hover::after { transform: scaleX(1); } +.site-header-actions { display: flex; align-items: center; gap: 24px; min-width: 180px; justify-content: flex-end; } +.site-locale { display: inline-flex; align-items: center; gap: 0; padding: 3px 4px; border-radius: 16px; background: #f1f3f5; border: 1px solid rgba(17, 24, 39, 0.06); box-shadow: inset 0 1px 0 rgba(255,255,255,0.8); } +.site-locale button { appearance: none; border: 0; background: transparent; border-radius: 12px; padding: 10px 14px; min-width: 48px; color: #5d6773; font-size: 12px; font-weight: 700; letter-spacing: 0.05em; cursor: pointer; transition: all 0.2s ease; } +.site-locale button:hover { color: var(--ink); } +.site-locale button.active { background: #fff; color: var(--ink); box-shadow: 0 2px 8px rgba(15, 23, 42, 0.08); } +.site-menu-button { display: none; width: 38px; border: 0; background: transparent; cursor: pointer; } +.site-menu-button span { display: block; height: 2px; margin: 5px 0; background: var(--ink); } +.home-page { padding: 0 clamp(24px, 4vw, 76px) 48px; } +.home-hero { position: relative; min-height: min(780px, calc(100vh - 170px)); overflow: hidden; border-radius: 15px; isolation: isolate; color: #fff; background: #173c59; } +.hero-scene, .hero-shade { position: absolute; inset: 0; }.hero-sky { position: absolute; inset: 0; background: radial-gradient(circle at 82% 12%, rgba(255,246,203,.88), transparent 22%), linear-gradient(115deg, #19394f 0%, #6ea7c8 43%, #e5e8e1 100%); } +.hero-city { position: absolute; bottom: 0; width: 34%; height: 70%; opacity: .82; background: repeating-linear-gradient(90deg, #244052 0 17px, #98b1ba 18px 21px, #1b3347 22px 42px); }.hero-city-left { left: -7%; transform: skewY(8deg); }.hero-city-right { right: -6%; height: 61%; background: repeating-linear-gradient(90deg, #405d70 0 29px, #b3c1c4 30px 33px, #314c60 34px 58px); transform: skewY(-4deg); } +.hero-overpass { position: absolute; right: 14%; bottom: 21%; width: 65%; height: 15%; border-top: 10px solid #d9dedb; border-bottom: 12px solid #6e8284; transform: skewY(-7deg); box-shadow: 0 14px 0 rgba(25,48,57,.35); } +.hero-track { position: absolute; bottom: -18%; left: 17%; width: 70%; height: 55%; border-top: 10px solid #dee4e1; border-right: 10px solid #c5cecb; transform-origin: bottom left; }.hero-track-one { transform: skewX(-31deg) rotate(-5deg); }.hero-track-two { bottom: -25%; left: 36%; width: 62%; opacity: .75; transform: skewX(-31deg) rotate(-5deg); } +.hero-train { position: absolute; right: 24%; bottom: 27%; width: 39%; height: 11%; display: flex; gap: 4px; padding: 7px; background: linear-gradient(#e6ece7 0 44%, #0d5b77 45% 78%, #152c3e 79%); border-radius: 3px; box-shadow: 0 10px 10px rgba(11,26,33,.25); transform: skewY(-7deg); }.hero-train span { flex: 1; background: linear-gradient(#233d51 0 55%, #97c3d1 57%); } +.hero-shade { z-index: 1; background: linear-gradient(90deg, rgba(3,12,20,.75), rgba(3,12,20,.36) 43%, transparent 78%); }.hero-content { position: absolute; z-index: 2; left: clamp(32px, 6.5vw, 122px); bottom: clamp(50px, 10vw, 136px); max-width: 760px; } +.hero-kicker { margin: 0 0 20px; color: #c4e4ff; font-size: 11px; font-weight: 700; letter-spacing: .18em; }.hero-content h1 { margin: 0; font-size: clamp(48px, 5.4vw, 98px); font-weight: 800; letter-spacing: -.08em; line-height: 1.02; }.hero-content > p:not(.hero-kicker) { margin: 26px 0; font-size: clamp(15px, 1.3vw, 19px); line-height: 1.7; }.hero-link { display: inline-flex; align-items: center; gap: 17px; padding-bottom: 8px; border-bottom: 2px solid #fff; font-size: 16px; font-weight: 700; }.hero-link span { font-size: 25px; line-height: .5; transition: transform .2s ease; }.hero-link:hover span { transform: translateX(7px); } + +.home-news { margin-top: 46px; padding: 0 0 16px; } +.news-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 32px; } +.news-header h2 { margin: 0; font-size: clamp(32px, 3vw, 50px); line-height: 1.1; letter-spacing: -0.04em; } +.news-more-link { color: var(--blue); font-size: clamp(16px, 1.5vw, 24px); font-weight: 700; display: inline-flex; align-items: center; gap: 8px; } +.news-more-link span { font-size: 24px; line-height: 1; } +.news-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px; } +.news-card { min-width: 0; } +.news-card-link { display: block; } +.news-visual { height: 420px; border-radius: 18px; background-size: cover; background-position: center; box-shadow: inset 0 0 0 1px rgba(15, 23, 42, 0.06); } +.news-card h3 { margin: 18px 0 14px; font-size: clamp(20px, 1.7vw, 28px); line-height: 1.4; letter-spacing: -0.03em; } +.news-card time { color: var(--muted); font-size: 16px; } + +.news-page { padding: 30px 0 60px; } +.news-page-inner { max-width: 1200px; margin: 0 auto; padding: 0 24px; } +.news-page-header { display: flex; justify-content: center; align-items: center; margin: 0 0 30px; } +.news-page-header h1 { margin: 0; font-size: clamp(52px, 5vw, 88px); letter-spacing: -0.07em; line-height: 1; font-weight: 800; } +.news-toolbar { display: flex; align-items: center; justify-content: space-between; padding: 18px 0 24px; border-bottom: 1px solid rgba(15, 23, 42, 0.12); } +.news-toolbar-actions { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; } +.news-filter-button { border: 1px solid rgba(15, 23, 42, 0.16); background: transparent; border-radius: 999px; padding: 10px 24px; font-size: 15px; color: #1b2430; cursor: pointer; } +.news-filter-button.active { background: #0f73ff; border-color: #0f73ff; color: #fff; } +.news-toolbar-right { display: flex; align-items: center; gap: 8px; } +.news-view-toggle { width: 36px; height: 36px; border: 1px solid rgba(15, 23, 42, 0.16); border-radius: 50%; background: rgba(15, 23, 42, 0.03); color: #1b2430; cursor: pointer; } +.news-list-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 28px; padding-top: 28px; } +.news-list-card { min-width: 0; } +.news-list-link { display: block; } +.news-list-cover { height: 250px; border-radius: 18px; background-size: cover; background-position: center; } +.news-list-meta { padding-top: 14px; } +.news-list-tag { display: inline-block; margin-bottom: 10px; font-size: 12px; color: #0f73ff; background: rgba(15, 115, 255, 0.08); padding: 5px 8px; border-radius: 999px; } +.news-list-meta h3 { margin: 0 0 8px; font-size: clamp(20px, 1.5vw, 26px); line-height: 1.4; letter-spacing: -0.04em; } +.news-list-meta time { color: #697684; font-size: 14px; } + +.news-detail-page { padding: 40px 0 80px; } +.news-detail-inner { max-width: 960px; margin: 0 auto; padding: 0 24px; } +.back-link { display: inline-block; margin-bottom: 20px; color: #0f73ff; font-weight: 700; } +.news-detail-card { background: #fff; border-radius: 26px; padding: 28px; box-shadow: 0 10px 30px rgba(15, 23, 42, 0.04); } +.news-detail-tag { display: inline-block; margin: 0 0 12px; padding: 6px 10px; border-radius: 999px; background: rgba(15, 115, 255, 0.08); color: #0f73ff; font-size: 12px; } +.news-detail-card h1 { margin: 0 0 10px; font-size: clamp(34px, 4vw, 52px); letter-spacing: -0.06em; } +.news-detail-card time { display: inline-block; margin-bottom: 20px; color: #697684; } +.news-detail-cover { height: 360px; border-radius: 18px; background-size: cover; background-position: center; margin-bottom: 24px; } +.news-detail-body { color: #1d2732; line-height: 1.9; font-size: 17px; } +.news-detail-body h2, .news-detail-body h3 { margin-top: 28px; } +.news-detail-body p { margin: 0 0 18px; } +.news-detail-body img { display: block; width: auto; max-width: 100%; height: auto; margin: 18px 0; } +.news-detail-body ul { padding-left: 22px; } +.news-detail-body li { margin: 8px 0; } +.page-bottom-nav { width: min(1200px, calc(100% - 40px)); margin: 48px auto 0; padding: 32px 0; border-top: 0.8px solid #d9d9d9; border-bottom: 0.8px solid #d9d9d9; } +.page-bottom-nav-inner { width: 100%; margin: 0 auto; } +.page-breadcrumb { display: flex; align-items: center; gap: 16px; margin: 0; color: #3a3a3a; font-size: 16px; font-weight: 500; line-height: 24px; letter-spacing: -0.0625px; } +.page-breadcrumb-item { display: inline-flex; align-items: center; gap: 16px; white-space: nowrap; } +.page-breadcrumb-separator { color: #3a3a3a; } +.page-breadcrumb a { color: #000; } +.news-share { margin-top: 40px; padding-top: 28px; border-top: 1px solid rgba(15, 23, 42, 0.1); } +.news-share h2 { margin: 0 0 18px; font-size: 24px; line-height: 1.2; } +.news-share-actions { display: flex; flex-wrap: wrap; gap: 14px; } +.news-share-button { min-width: 86px; height: 42px; padding: 0 16px; border: 1px solid rgba(15, 23, 42, 0.16); border-radius: 999px; background: #fff; color: #172333; font: inherit; cursor: pointer; } +.news-share-button:hover { border-color: #0f73ff; color: #0f73ff; } +.news-share-x, .news-share-qq { min-width: 52px; font-weight: 700; } + +.site-footer { height: 500px; color: #5e686d; background: #fbfbfb; } +.site-footer-inner { width: min(1200px, calc(100% - 40px)); height: 480px; margin: 0 auto; } +.site-footer-top { height: 89px; border-bottom: 1px solid rgba(15, 23, 42, 0.06); padding-top: 33px; } +.site-footer-socials { display: flex; align-items: center; justify-content: flex-start; gap: 33px; height: 28px; } +.site-footer-title { width: 80px; font-family: "Noto Sans SC", sans-serif; font-size: 20px; font-weight: 400; line-height: 21px; letter-spacing: 0; color: #5f6464; } +.site-footer-icons { display: flex; align-items: center; gap: 28px; } +.site-footer-icon { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 4px; background: transparent; color: #5e686d; font-size: 14px; font-weight: 700; transition: transform .2s ease, color .2s ease; } +.site-footer-icon:hover { color: #1f2b38; transform: translateY(-1px); } +.site-footer-main { position: relative; height: 234px; padding-top: 21px; } +.site-footer-columns { display: grid; grid-template-columns: 216px 216px 298px; gap: 0; width: 730px; height: 207px; } +.site-footer-column h3 { margin: 0; font-family: "Noto Sans SC", sans-serif; font-size: 20px; font-weight: 400; line-height: 21px; color: #5f6464; } +.site-footer-column ul { list-style: none; padding: 30px 0 18px; margin: 0; display: flex; flex-direction: column; gap: 18px; } +.site-footer-column li { flex: none; height: 21px; } +.site-footer-column a { display: block; height: 21px; color: #5f6464; font-family: "Noto Sans SC", sans-serif; font-size: 16px; font-weight: 400; line-height: 21px; transition: color .2s ease; } +.site-footer-column a:hover { color: #122331; } +.site-footer-brand-wrap { position: absolute; top: 76px; left: 830px; display: flex; align-items: center; justify-content: center; width: 370px; height: 158px; } +.site-footer-brand { display: inline-flex; align-items: center; justify-content: center; width: 100%; } +.site-footer-brand-logo { display: block; width: 270px; height: auto; opacity: 0.96; filter: drop-shadow(0 2px 6px rgba(17, 34, 52, 0.06)); } +.site-footer-meta { height: 130.8px; padding-top: 26px; border-top: 1px solid rgba(15, 23, 42, 0.06); margin-top: 0; } +.site-footer-legal-row { display: flex; flex-wrap: wrap; gap: 0 18px; align-items: center; font-family: "Noto Sans SC", sans-serif; font-size: 14px; font-weight: 400; line-height: 17px; color: #5f6b75; } +.site-footer-legal-row a { color: inherit; } +.site-footer-copyright-row { display: flex; flex-wrap: wrap; gap: 0 18px; align-items: center; margin-top: 18px; font-family: "Noto Sans SC", sans-serif; font-size: 14px; font-weight: 400; line-height: 17px; color: #66737e; } +.site-footer-meta p { margin: 18px 0 0; font-family: "Noto Sans SC", sans-serif; font-size: 14px; font-weight: 400; line-height: 17px; color: #66737e; } +.site-footer-meta .site-footer-description { width: 1200px; max-width: 100%; margin-top: 18px; } + +@media (max-width: 900px) { + .site-header { height: 84px; padding: 0 16px; } + .site-logo { min-width: 0; flex: 1; justify-content: center; } + .site-logo-image { width: min(180px, 44vw); } + .site-navigation { display: none; } + .site-navigation.is-open { position: absolute; top: 84px; right: 16px; left: 16px; z-index: 10; display: flex; flex-direction: column; align-items: stretch; gap: 0; padding: 10px 18px; border: 1px solid rgba(15, 23, 42, 0.08); background: #fff; box-shadow: 0 14px 28px rgba(15, 23, 42, 0.12); } + .site-navigation.is-open a { padding: 13px 0; border-bottom: 1px solid rgba(15, 23, 42, 0.08); } + .site-navigation.is-open a:last-child { border-bottom: 0; } + .site-navigation.is-open a::after { display: none; } + .site-locale { display: none; } + .site-header-actions { min-width: auto; margin-left: auto; } + .site-menu-button { display: block; } + .home-page { padding: 0 16px 32px; } + .home-hero { min-height: calc(100svh - 115px); border-radius: 11px; } + .hero-city-left { width: 52%; } + .hero-city-right { width: 47%; } + .hero-train { right: 6%; width: 68%; } + .hero-content { right: 28px; left: 28px; bottom: 62px; } + .hero-content h1 { font-size: clamp(43px, 12vw, 66px); } + .hero-shade { background: linear-gradient(0deg, rgba(3,12,20,.88), rgba(3,12,20,.13) 70%); } + .hero-content > p:not(.hero-kicker) { max-width: 370px; } + .news-header { margin-bottom: 22px; } + .news-grid { grid-template-columns: 1fr; gap: 24px; } + .news-visual { height: 260px; } + .news-page-inner { padding: 0 16px; } + .news-toolbar { padding-top: 12px; } + .news-list-grid { grid-template-columns: 1fr; gap: 22px; } + .news-detail-card { padding: 20px; } + .news-detail-cover { height: 240px; } + .page-bottom-nav { width: calc(100% - 40px); margin-top: 30px; padding: 24px 0; overflow-x: auto; } + .page-bottom-nav-inner { width: 100%; padding: 0 20px; } + .news-share { margin-top: 30px; padding-top: 22px; } + .site-footer-inner { width: auto; height: auto; margin: 0; padding: 0 20px; } + .site-footer-main { height: auto; padding-top: 26px; } + .site-footer-columns { grid-template-columns: 1fr; gap: 22px; width: auto; height: auto; } + .site-footer-brand-wrap { display: none; } + .site-footer-socials { flex-direction: row; align-items: center; } + .site-footer-legal-row { gap: 8px 12px; } + .site-footer { height: auto; padding: 28px 0 22px; } + .site-footer-meta p { font-size: 12px; } +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 344c6be..79bbe1d 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,9 +1,14 @@ import type { Metadata } from "next"; import "./globals.css"; +import { SiteFooter } from "@/components/layout/site-footer"; +import { SiteHeader } from "@/components/layout/site-header"; export const metadata: Metadata = { title: "Kivotos Railway", description: "Kivotos Railway website", + icons: { + icon: "/icon.svg", + }, }; export default function RootLayout({ @@ -11,7 +16,7 @@ export default function RootLayout({ }: Readonly<{ children: React.ReactNode }>) { return ( - {children} + {children} ); } diff --git a/src/app/news/[slug]/page.tsx b/src/app/news/[slug]/page.tsx new file mode 100644 index 0000000..e1970cf --- /dev/null +++ b/src/app/news/[slug]/page.tsx @@ -0,0 +1,45 @@ +import Link from "next/link"; +import { getNewsBySlug, markdownToHtml } from "@/data/news"; +import { PageBreadcrumb } from "@/components/layout/page-breadcrumb"; +import { NewsShare } from "@/components/news/news-share"; + +export default async function NewsDetailPage({ + params, +}: { + params: Promise<{ slug: string }>; +}) { + const { slug } = await params; + const item = await getNewsBySlug(slug); + + if (!item) { + return ( +
+
+

未找到该文章。

+ 返回新闻列表 +
+
+ ); + } + + return ( +
+
+ ← 返回新闻 +
+

{item.category}

+

{item.title}

+ +
+
+ +
+
+
+
+ +
+
+
+ ); +} diff --git a/src/app/news/page.tsx b/src/app/news/page.tsx new file mode 100644 index 0000000..f2789c7 --- /dev/null +++ b/src/app/news/page.tsx @@ -0,0 +1,25 @@ +import Link from "next/link"; +import { getNewsList } from "@/data/news"; +import { PageBreadcrumb } from "@/components/layout/page-breadcrumb"; +import { NewsList } from "@/components/news/news-list"; + +export default async function NewsPage() { + const news = await getNewsList(); + + return ( +
+
+
+

新闻

+
+ + +
+
+
+ +
+
+
+ ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx index aa24bcb..3354e9a 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,11 +1,8 @@ -import { Button } from "@/components/ui/button"; +import { HomePageContent } from "@/components/home/home-page-content"; +import { getLatestNews } from "@/data/news"; -export default function Home() { - return ( -
-

Kivotos Railway

-

Welcome to kivotosrailway-website-v2.

- -
- ); +export default async function Home() { + const news = await getLatestNews(); + + return ; } diff --git a/src/components/home/home-page-content.tsx b/src/components/home/home-page-content.tsx new file mode 100644 index 0000000..9752afb --- /dev/null +++ b/src/components/home/home-page-content.tsx @@ -0,0 +1,85 @@ +"use client"; + +import Link from "next/link"; +import { useEffect, useState } from "react"; +import type { NewsItem } from "@/data/news"; +import { applyLocale, getInitialLocale, getLocaleMessages, type Locale } from "@/lib/i18n"; + +export function HomePageContent({ news }: { news: NewsItem[] }) { + const [locale, setLocale] = useState("zh-CN"); + + useEffect(() => { + const syncLocale = (nextLocale: Locale) => setLocale(nextLocale); + + const currentLocale = getInitialLocale(); + syncLocale(currentLocale); + applyLocale(currentLocale); + + const onLocaleChange = (event: Event) => { + const detail = (event as CustomEvent<{ locale?: Locale }>).detail; + if (detail?.locale) { + setLocale(detail.locale); + } + }; + + const handleStorage = () => { + const nextLocale = getInitialLocale(); + syncLocale(nextLocale); + applyLocale(nextLocale); + }; + + window.addEventListener("kr-locale-change", onLocaleChange); + window.addEventListener("storage", handleStorage); + + return () => { + window.removeEventListener("kr-locale-change", onLocaleChange); + window.removeEventListener("storage", handleStorage); + }; + }, []); + + const t = getLocaleMessages(locale); + + return ( +
+
+
+ +
+
+

{t.home.latest}

+ + {t.home.more} + +
+ +
+ {news.map((post) => ( +
+ +
+

{post.title}

+ + +
+ ))} +
+
+
+ ); +} diff --git a/src/components/layout/page-breadcrumb.tsx b/src/components/layout/page-breadcrumb.tsx new file mode 100644 index 0000000..fc2948b --- /dev/null +++ b/src/components/layout/page-breadcrumb.tsx @@ -0,0 +1,14 @@ +import Link from "next/link"; + +export function PageBreadcrumb({ items }: { items: Array<{ label: string; href?: string }> }) { + return ( + + ); +} diff --git a/src/components/layout/site-footer.tsx b/src/components/layout/site-footer.tsx new file mode 100644 index 0000000..497a504 --- /dev/null +++ b/src/components/layout/site-footer.tsx @@ -0,0 +1,113 @@ +"use client"; + +import Image from "next/image"; +import { useEffect, useState } from "react"; +import { applyLocale, getInitialLocale, getLocaleMessages, type Locale } from "@/lib/i18n"; + +const footerColumnHrefs = [ + ["/policy/user-agreement", "/policy/privacy-policy", "/policy/disclaimer", "/policy/resource-pack"], + ["/about", "/join-us"], + ["mailto:connect@kivotos.cc", "mailto:infringement@kivotos.cc"], +] as const; + +const footerLegalHrefs = ["https://wiki.kivotosrailway.com", "https://url.kivotos.cc/status", "/links"] as const; + +function isIcpVisibleHost(hostname: string) { + return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]" || hostname.endsWith(".kivotos.cc"); +} + +export function SiteFooter() { + const [locale, setLocale] = useState("zh-CN"); + const [showIcp, setShowIcp] = useState(false); + + useEffect(() => { + const syncLocale = (nextLocale: Locale) => setLocale(nextLocale); + const handleLocaleChange = (event: Event) => { + const nextLocale = (event as CustomEvent<{ locale?: Locale }>).detail?.locale ?? getInitialLocale(); + syncLocale(nextLocale); + }; + + const handleStorage = () => { + syncLocale(getInitialLocale()); + }; + + const currentLocale = getInitialLocale(); + syncLocale(currentLocale); + applyLocale(currentLocale); + setShowIcp(isIcpVisibleHost(window.location.hostname)); + window.addEventListener("kr-locale-change", handleLocaleChange); + window.addEventListener("storage", handleStorage); + + return () => { + window.removeEventListener("kr-locale-change", handleLocaleChange); + window.removeEventListener("storage", handleStorage); + }; + }, []); + + const messages = getLocaleMessages(locale); + + return ( +
+
+
+
+ {messages.footer.follow} +
+ {messages.footer.social.map((item, index) => ( + + {[ + "◌", + "◍", + "X", + "in", + "▶", + ][index] ?? "•"} + + ))} +
+
+
+ +
+
+ {messages.footer.columns.map((group, groupIndex) => ( +
+

{group.title}

+
    + {group.links.map((link, linkIndex) => ( +
  • {link}
  • + ))} +
+
+ ))} +
+ +
+
+ Kivotos Railway +
+
+
+ +
+
+ {messages.footer.legal.map((item, itemIndex) => ( + {item} + ))} +
+

{messages.footer.description}

+
+ {messages.footer.copyright} + {showIcp && {messages.footer.icp}} +
+
+
+
+ ); +} diff --git a/src/components/layout/site-header.tsx b/src/components/layout/site-header.tsx new file mode 100644 index 0000000..5b45316 --- /dev/null +++ b/src/components/layout/site-header.tsx @@ -0,0 +1,91 @@ +"use client"; + +import Link from "next/link"; +import Image from "next/image"; +import { useEffect, useState } from "react"; +import { applyLocale, getInitialLocale, getLocaleMessages, localeLabels, locales, localeShortLabels, type Locale } from "@/lib/i18n"; + +export function SiteHeader() { + const [locale, setLocale] = useState("zh-CN"); + const [menuOpen, setMenuOpen] = useState(false); + + useEffect(() => { + const syncLocale = (nextLocale: Locale) => setLocale(nextLocale); + + const handleLocaleChange = (event: Event) => { + const nextLocale = (event as CustomEvent<{ locale?: Locale }>).detail?.locale ?? getInitialLocale(); + syncLocale(nextLocale); + }; + + const handleStorage = () => { + syncLocale(getInitialLocale()); + }; + + const currentLocale = getInitialLocale(); + syncLocale(currentLocale); + applyLocale(currentLocale); + + window.addEventListener("kr-locale-change", handleLocaleChange); + window.addEventListener("storage", handleStorage); + + return () => { + window.removeEventListener("kr-locale-change", handleLocaleChange); + window.removeEventListener("storage", handleStorage); + }; + }, []); + + const messages = getLocaleMessages(locale); + + return ( +
+ + Kivotos Railway + + +
+
+ {locales.map((item) => ( + + ))} +
+ +
+
+ ); +} diff --git a/src/components/news/news-list.tsx b/src/components/news/news-list.tsx new file mode 100644 index 0000000..f03ac38 --- /dev/null +++ b/src/components/news/news-list.tsx @@ -0,0 +1,57 @@ +"use client"; + +import Link from "next/link"; +import { useState } from "react"; +import type { NewsItem } from "@/data/news"; + +export function NewsList({ news }: { news: NewsItem[] }) { + const [activeCategory, setActiveCategory] = useState(null); + const categories = Array.from(new Set(news.map((item) => item.category).filter(Boolean))); + const visibleNews = activeCategory + ? news.filter((item) => item.category === activeCategory) + : news; + + return ( + <> +
+
+ + {categories.map((category) => ( + + ))} +
+
+ +
+
+ +
+ {visibleNews.map((item) => ( +
+ +
+
+ {item.category} +

{item.title}

+ +
+ +
+ ))} +
+ + ); +} diff --git a/src/components/news/news-share.tsx b/src/components/news/news-share.tsx new file mode 100644 index 0000000..2da924e --- /dev/null +++ b/src/components/news/news-share.tsx @@ -0,0 +1,40 @@ +"use client"; + +import { useState } from "react"; + +export function NewsShare({ title }: { title: string }) { + const [copied, setCopied] = useState(false); + + const getPageUrl = () => window.location.href; + + const copyLink = async () => { + await navigator.clipboard.writeText(getPageUrl()); + setCopied(true); + window.setTimeout(() => setCopied(false), 1600); + }; + + const shareOnX = () => { + const url = encodeURIComponent(getPageUrl()); + const text = encodeURIComponent(title); + window.open(`https://twitter.com/intent/tweet?url=${url}&text=${text}`, "_blank", "noopener,noreferrer"); + }; + + const shareOnQq = () => { + const url = encodeURIComponent(getPageUrl()); + const text = encodeURIComponent(title); + window.open(`https://connect.qq.com/widget/shareqq/index.html?url=${url}&title=${text}`, "_blank", "noopener,noreferrer"); + }; + + return ( +
+

分享

+
+ + + +
+
+ ); +} diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx deleted file mode 100644 index ecbd24b..0000000 --- a/src/components/ui/button.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import * as React from "react"; -import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils"; - -const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50", - { variants: { variant: { default: "bg-primary text-primary-foreground hover:bg-primary/90", destructive: "bg-destructive text-white hover:bg-destructive/90", outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline" }, size: { default: "h-10 px-4 py-2", sm: "h-9 rounded-md px-3", lg: "h-11 rounded-md px-8", icon: "h-10 w-10" } }, defaultVariants: { variant: "default", size: "default" } }, -); - -export interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps {} - -const Button = React.forwardRef(({ className, variant, size, ...props }, ref) => ( -