24 Commits

Author SHA1 Message Date
vercel[bot]
6c9b8f072e Merge pull request #8 from handsomezhuzhu/v0/kdaugh14-4907-4423338f
Redesign navigation and update AI API proxy server list
2026-03-25 07:46:56 +00:00
v0
b7fc2671dc remove outdated sites from site list
Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-03-25 07:45:31 +00:00
vercel[bot]
b1c0c0da82 Merge pull request #7 from handsomezhuzhu/v0/kdaugh14-4907-053206dd
Redesign navigation and update AI API proxy server list
2026-03-20 10:51:16 +00:00
v0
a46f351021 feat: update AI API proxy servers and add label for Oracle
Change server list and style label for Oracle server.

Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-03-20 10:50:57 +00:00
v0
39562f0b84 fix: update API proxy server list
Remove incorrect servers and update to correct list.

Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-03-20 10:48:27 +00:00
vercel[bot]
b8d4eaa4df Merge pull request #6 from handsomezhuzhu/v0/kdaugh14-4907-7424b84c
Redesign navigation with centered layout and cyberpunk animations
2026-03-07 15:05:52 +00:00
v0
6d617a240f chore: remove redundant animation packages from package.json
Fix package.json syntax and ensure compatibility with Tailwind CSS v4.

Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-03-07 15:03:49 +00:00
v0
424542c56d feat: animate text-shadow for gradient glow effect
Text shadow color transitions with cycle: green → blue → purple → dark blue.

Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-03-07 15:00:48 +00:00
v0
8131a79752 fix: resolve CSS animation conflicts with Tailwind v4
Remove conflicting 'tailwindcss-animate' and downgrade 'tw-animate-css' to compatible version. Manually add necessary animation utilities to globals.css.

Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-03-07 14:55:34 +00:00
v0
766942e189 feat: replace glitch flicker with smooth color gradient animation
Update title with decryption effect and continuous color cycle animation.

Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-03-07 14:50:53 +00:00
v0
4dada4a6f8 feat: add cyberpunk navigation effects
Update site navigation title and remove top icon, add random glitch effects.

Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-03-07 14:48:57 +00:00
vercel[bot]
6ae5b6a30a Merge pull request #5 from handsomezhuzhu/v0/kdaugh14-4907-61999896
Redesign navigation with a modern centered layout
2026-03-07 14:43:03 +00:00
v0
9f8188a969 feat: redesign navigation with modern centered layout
Centered title, optimized search box, improved category headers,
enhanced card interactions, and realigned footer.

Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-03-07 14:17:00 +00:00
vercel[bot]
d810c06460 Merge pull request #4 from handsomezhuzhu/v0/kdaugh14-4907-03e8edbc
Update server configurations and improve site navigation
2026-02-20 11:41:57 +00:00
v0
d5d7b45459 update server list and add color styles for new servers
Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-02-20 11:39:08 +00:00
vercel[bot]
5355b6e04e Merge pull request #3 from handsomezhuzhu/v0/kdaugh14-4907-1734256a
Enhance site navigation and update API server configurations
2026-02-13 12:29:26 +00:00
v0
800a61a837 fix: update api.zhuzihan.com server and name
Change server to "狐蒂云-日本" and name to "NEW-API"

Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-02-13 12:28:38 +00:00
vercel[bot]
e9184dfca3 Merge pull request #2 from handsomezhuzhu/v0/kdaugh14-4907-a5e6b11d
feat: Enhance site navigation and server infrastructure
2026-02-02 08:57:39 +00:00
v0
e8932dc080 fix: update site names and remove non-existent site
Correct site name and delete non-existent entry based on updated list.

Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-02-02 08:56:19 +00:00
v0
7db48b99aa fix: revert site name to "青竹云管理后台"
Restore site name to match new data comparison.

Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-02-02 08:54:38 +00:00
Simon
723aa11344 Merge pull request #1 from handsomezhuzhu/v0/kdaugh14-4907-5f74c627
feat: Enhance site navigation and server infrastructure
2026-01-28 22:26:29 +08:00
v0
867a850f43 feat: update color distinctions for CDN and server components
Assign distinct colors to EdgeOne Pages, EdgeOne, ESA API, ESA, and rename "青竹云" to "青瑞云".

Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-01-28 14:24:46 +00:00
v0
9503eb4c5c style: differentiate server tag colors for Google regions
Distinguish server tags for Google regions with unique colors.

Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-01-28 14:22:07 +00:00
v0
7898615906 feat: add Google-Taiwan backend and update server list
Add new Google-Taiwan backend and update server counts and styles

Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
2026-01-28 14:20:26 +00:00
8 changed files with 946 additions and 903 deletions

2
.gitignore vendored
View File

@@ -24,4 +24,4 @@ yarn-error.log*
# typescript # typescript
*.tsbuildinfo *.tsbuildinfo
next-env.d.ts next-env.d.ts

View File

@@ -27,4 +27,4 @@ Continue building your app on:
1. Create and modify your project using [v0.app](https://v0.app) 1. Create and modify your project using [v0.app](https://v0.app)
2. Deploy your chats from the v0 interface 2. Deploy your chats from the v0 interface
3. Changes are automatically pushed to this repository 3. Changes are automatically pushed to this repository
4. Vercel deploys the latest version from this repository 4. Vercel deploys the latest version from this repository

View File

@@ -1,29 +1,28 @@
@import "tailwindcss"; @import "tailwindcss";
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
/* 深色主题设计,适合个人导航站 */ /* 深色主题设计,个人导航站 - 深蓝色调 */
:root { :root {
--background: oklch(0.13 0.01 260); --background: oklch(0.12 0.015 240);
--foreground: oklch(0.95 0 0); --foreground: oklch(0.98 0 0);
--card: oklch(0.18 0.01 260); --card: oklch(0.16 0.015 240);
--card-foreground: oklch(0.95 0 0); --card-foreground: oklch(0.98 0 0);
--popover: oklch(0.18 0.01 260); --popover: oklch(0.16 0.015 240);
--popover-foreground: oklch(0.95 0 0); --popover-foreground: oklch(0.98 0 0);
--primary: oklch(0.7 0.15 200); --primary: oklch(0.75 0.12 180);
--primary-foreground: oklch(0.1 0 0); --primary-foreground: oklch(0.1 0 0);
--secondary: oklch(0.25 0.01 260); --secondary: oklch(0.22 0.015 240);
--secondary-foreground: oklch(0.9 0 0); --secondary-foreground: oklch(0.95 0 0);
--muted: oklch(0.25 0.01 260); --muted: oklch(0.22 0.015 240);
--muted-foreground: oklch(0.65 0 0); --muted-foreground: oklch(0.6 0.01 240);
--accent: oklch(0.7 0.15 200); --accent: oklch(0.75 0.12 180);
--accent-foreground: oklch(0.1 0 0); --accent-foreground: oklch(0.1 0 0);
--destructive: oklch(0.577 0.245 27.325); --destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.577 0.245 27.325); --destructive-foreground: oklch(0.577 0.245 27.325);
--border: oklch(0.28 0.01 260); --border: oklch(0.24 0.02 240);
--input: oklch(0.28 0.01 260); --input: oklch(0.20 0.015 240);
--ring: oklch(0.7 0.15 200); --ring: oklch(0.75 0.12 180);
--chart-1: oklch(0.646 0.222 41.116); --chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704); --chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392); --chart-3: oklch(0.398 0.07 227.392);
@@ -124,3 +123,79 @@
@apply bg-background text-foreground; @apply bg-background text-foreground;
} }
} }
/* Cyber glow animation - 文字白色,光晕颜色流动 */
@keyframes glow-flow {
0% { text-shadow: 0 0 12px oklch(0.75 0.18 180 / 0.9), 0 0 30px oklch(0.75 0.18 180 / 0.5), 0 0 60px oklch(0.75 0.18 180 / 0.2); }
25% { text-shadow: 0 0 12px oklch(0.70 0.20 220 / 0.9), 0 0 30px oklch(0.70 0.20 220 / 0.5), 0 0 60px oklch(0.70 0.20 220 / 0.2); }
50% { text-shadow: 0 0 12px oklch(0.65 0.22 280 / 0.9), 0 0 30px oklch(0.65 0.22 280 / 0.5), 0 0 60px oklch(0.65 0.22 280 / 0.2); }
75% { text-shadow: 0 0 12px oklch(0.72 0.20 240 / 0.9), 0 0 30px oklch(0.72 0.20 240 / 0.5), 0 0 60px oklch(0.72 0.20 240 / 0.2); }
100% { text-shadow: 0 0 12px oklch(0.75 0.18 180 / 0.9), 0 0 30px oklch(0.75 0.18 180 / 0.5), 0 0 60px oklch(0.75 0.18 180 / 0.2); }
}
.cyber-title {
color: oklch(0.98 0 0);
animation: glow-flow 6s ease infinite;
}
/* Animation utilities */
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes fade-out {
from { opacity: 1; }
to { opacity: 0; }
}
@keyframes zoom-in-95 {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
@keyframes zoom-out-95 {
from { opacity: 1; transform: scale(1); }
to { opacity: 0; transform: scale(0.95); }
}
@keyframes slide-in-from-top-2 {
from { transform: translateY(-0.5rem); }
to { transform: translateY(0); }
}
@keyframes slide-in-from-bottom-2 {
from { transform: translateY(0.5rem); }
to { transform: translateY(0); }
}
@keyframes slide-in-from-left-2 {
from { transform: translateX(-0.5rem); }
to { transform: translateX(0); }
}
@keyframes slide-in-from-right-2 {
from { transform: translateX(0.5rem); }
to { transform: translateX(0); }
}
.animate-in {
animation-duration: 150ms;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
animation-fill-mode: both;
}
.animate-out {
animation-duration: 150ms;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
animation-fill-mode: both;
}
.fade-in-0 { animation-name: fade-in; }
.fade-out-0 { animation-name: fade-out; }
.zoom-in-95 { animation-name: zoom-in-95; }
.zoom-out-95 { animation-name: zoom-out-95; }
.slide-in-from-top-2 { animation-name: slide-in-from-top-2; }
.slide-in-from-bottom-2 { animation-name: slide-in-from-bottom-2; }
.slide-in-from-left-2 { animation-name: slide-in-from-left-2; }
.slide-in-from-right-2 { animation-name: slide-in-from-right-2; }

View File

@@ -2,8 +2,8 @@
import type React from "react" import type React from "react"
import { useState } from "react" import { useState, useEffect } from "react"
import { ExternalLink, Globe, Server, Mail, Zap, Shield, Code, FileText, Search } from "lucide-react" import { ExternalLink, Server, Mail, Zap, Shield, Code, FileText, Search } from "lucide-react"
interface Site { interface Site {
domain: string domain: string
@@ -58,17 +58,10 @@ const categories: Category[] = [
title: "AI 与 API 服务", title: "AI 与 API 服务",
icon: <Zap className="size-5" />, icon: <Zap className="size-5" />,
sites: [ sites: [
{
domain: "ai.zhuzihan.com",
name: "OpenWebUI",
server: "狐蒂云-日本",
cdn: "EdgeOne加速",
url: "https://ai.zhuzihan.com",
},
{ {
domain: "api.zhuzihan.com", domain: "api.zhuzihan.com",
name: "New-API", name: "New-API",
server: "DigitalOcean", server: "狐蒂云-日本",
cdn: "无加速", cdn: "无加速",
url: "https://api.zhuzihan.com", url: "https://api.zhuzihan.com",
}, },
@@ -82,17 +75,52 @@ const categories: Category[] = [
{ {
domain: "api-proxy.zhuzihan.com", domain: "api-proxy.zhuzihan.com",
name: "AI API转发", name: "AI API转发",
server: ["狐蒂云-美国", "Google-Iowa", "Google-Oregon"], server: ["Oracle", "Google-Iowa", "Google-Oregon"],
cdn: "ESA API加速", cdn: "ESA API加速",
url: "https://api-proxy.zhuzihan.com", url: "https://api-proxy.zhuzihan.com",
}, },
{ {
domain: "ai-proxy.zhuzihan.com", domain: "ai-proxy.zhuzihan.com",
name: "AI API转发", name: "AI API转发",
server: ["狐蒂云-美国", "Google-Iowa", "Google-Oregon"], server: ["Oracle", "Google-Iowa", "Google-Oregon"],
cdn: "ESA API加速", cdn: "ESA API加速",
url: "https://ai-proxy.zhuzihan.com", url: "https://ai-proxy.zhuzihan.com",
}, },
{
domain: "grok.zhuzihan.com",
name: "Grok2API",
server: "狐蒂云-美国",
cdn: "无加速",
url: "https://grok.zhuzihan.com",
},
{
domain: "git.zhuzihan.com",
name: "Gitea自托管Git",
server: "狐蒂云-美国-2",
cdn: "无加速",
url: "https://git.zhuzihan.com",
},
{
domain: "codex.zhuzihan.com",
name: "公益New-API",
server: "青瑞云",
cdn: "EdgeOne加速",
url: "https://codex.zhuzihan.com",
},
{
domain: "ai.zzhdsgsss.xyz",
name: "LINUXDO公益New-API",
server: "青瑞云",
cdn: "CloudFlare加速",
url: "https://ai.zzhdsgsss.xyz",
},
{
domain: "apitool.zzhdsgsss.xyz",
name: "LINUXDO公益New-API监控",
server: "青瑞云",
cdn: "CloudFlare加速",
url: "https://apitool.zzhdsgsss.xyz",
},
{ {
domain: "cpa.zhuzihan.com/management.html", domain: "cpa.zhuzihan.com/management.html",
name: "CliProxyAPI", name: "CliProxyAPI",
@@ -100,13 +128,6 @@ const categories: Category[] = [
cdn: "无加速", cdn: "无加速",
url: "https://cpa.zhuzihan.com/management.html", url: "https://cpa.zhuzihan.com/management.html",
}, },
{
domain: "crs.zhuzihan.com",
name: "Claude轮训",
server: "Azure",
cdn: "无加速",
url: "https://crs.zhuzihan.com",
},
{ {
domain: "api-test.zhuzihan.com", domain: "api-test.zhuzihan.com",
name: "API批量测试", name: "API批量测试",
@@ -114,26 +135,12 @@ const categories: Category[] = [
cdn: "EdgeOne加速", cdn: "EdgeOne加速",
url: "https://api-test.zhuzihan.com", url: "https://api-test.zhuzihan.com",
}, },
{
domain: "health.zhuzihan.com/status/ai",
name: "AI服务状态查询",
server: "青竹云",
cdn: "ESA加速",
url: "https://health.zhuzihan.com/status/ai",
},
], ],
}, },
{ {
title: "云服务管理后台", title: "云服务管理后台",
icon: <Server className="size-5" />, icon: <Server className="size-5" />,
sites: [ sites: [
{
domain: "admin.zhuzihan.com",
name: "DigitalOcean管理后台",
server: "DigitalOcean",
cdn: "无加速",
url: "https://admin.zhuzihan.com",
},
{ {
domain: "azure.zhuzihan.com", domain: "azure.zhuzihan.com",
name: "Azure管理后台", name: "Azure管理后台",
@@ -157,8 +164,8 @@ const categories: Category[] = [
}, },
{ {
domain: "qzy.zhuzihan.com", domain: "qzy.zhuzihan.com",
name: "青云管理后台", name: "青云管理后台",
server: "青云", server: "青云",
cdn: "无加速", cdn: "无加速",
url: "https://qzy.zhuzihan.com", url: "https://qzy.zhuzihan.com",
}, },
@@ -176,13 +183,6 @@ const categories: Category[] = [
cdn: "无加速", cdn: "无加速",
url: "https://google2.zhuzihan.com", url: "https://google2.zhuzihan.com",
}, },
{
domain: "hdy.zhuzihan.com",
name: "狐蒂云-日本管理后台",
server: "狐蒂云-日本",
cdn: "无加速",
url: "https://hdy.zhuzihan.com",
},
{ {
domain: "hdy2.zhuzihan.com", domain: "hdy2.zhuzihan.com",
name: "狐蒂云-美国管理后台", name: "狐蒂云-美国管理后台",
@@ -190,33 +190,19 @@ const categories: Category[] = [
cdn: "无加速", cdn: "无加速",
url: "https://hdy2.zhuzihan.com", url: "https://hdy2.zhuzihan.com",
}, },
{
domain: "hdy3.zhuzihan.com",
name: "狐蒂云-美国-2管理后台",
server: "狐蒂云-美国-2",
cdn: "无加速",
url: "https://hdy3.zhuzihan.com",
},
], ],
}, },
{ {
title: "项目与工具", title: "项目与工具",
icon: <Code className="size-5" />, icon: <Code className="size-5" />,
sites: [ sites: [
{
domain: "qquiz.zhuzihan.com",
name: "QQuiz项目",
server: "华为云",
cdn: "ESA加速",
url: "https://qquiz.zhuzihan.com",
},
{
domain: "wwords.zhuzihan.com",
name: "WWords项目",
server: "华为云",
cdn: "ESA加速",
url: "https://wwords.zhuzihan.com",
},
{
domain: "code.zhuzihan.com",
name: "代码小项目",
server: "EdgeOne Pages",
cdn: "EdgeOne Pages并加速",
url: "https://code.zhuzihan.com",
},
{ {
domain: "state.zhuzihan.com", domain: "state.zhuzihan.com",
name: "探针服务器状态检测", name: "探针服务器状态检测",
@@ -224,13 +210,6 @@ const categories: Category[] = [
cdn: "EdgeOne加速", cdn: "EdgeOne加速",
url: "https://state.zhuzihan.com", url: "https://state.zhuzihan.com",
}, },
{
domain: "yummy.zhuzihan.com",
name: "倒计时",
server: "EdgeOne Pages",
cdn: "EdgeOne Pages并加速",
url: "https://yummy.zhuzihan.com",
},
{ {
domain: "file.zhuzihan.com", domain: "file.zhuzihan.com",
name: "文件快递柜", name: "文件快递柜",
@@ -245,20 +224,6 @@ const categories: Category[] = [
cdn: "ESA加速", cdn: "ESA加速",
url: "https://2fa.zhuzihan.com", url: "https://2fa.zhuzihan.com",
}, },
{
domain: "ieee.zhuzihan.com",
name: "IEEE 754二进制计算演示",
server: "EdgeOne Pages",
cdn: "EdgeOne Pages并加速",
url: "https://ieee.zhuzihan.com",
},
{
domain: "bcj.zhuzihan.com",
name: "并查集算法演示",
server: "EdgeOne Pages",
cdn: "EdgeOne Pages并加速",
url: "https://bcj.zhuzihan.com",
},
{ {
domain: "page.zhuzihan.com", domain: "page.zhuzihan.com",
name: "搜索页/起始页", name: "搜索页/起始页",
@@ -292,13 +257,17 @@ const categories: Category[] = [
] ]
function getCdnBadgeStyle(cdn: string) { function getCdnBadgeStyle(cdn: string) {
if (cdn.includes("EdgeOne")) return "bg-emerald-500/20 text-emerald-400" if (cdn.includes("EdgeOne Pages")) return "bg-emerald-500/20 text-emerald-400"
if (cdn.includes("EdgeOne")) return "bg-green-500/20 text-green-400"
if (cdn.includes("ESA API")) return "bg-indigo-500/20 text-indigo-400"
if (cdn.includes("ESA")) return "bg-sky-500/20 text-sky-400" if (cdn.includes("ESA")) return "bg-sky-500/20 text-sky-400"
if (cdn.includes("CloudFlare")) return "bg-orange-500/20 text-orange-400"
if (cdn.includes("Vercel")) return "bg-foreground/10 text-foreground" if (cdn.includes("Vercel")) return "bg-foreground/10 text-foreground"
return "bg-muted text-muted-foreground" return "bg-muted text-muted-foreground"
} }
function getServerBadgeStyle(server: string) { function getServerBadgeStyle(server: string) {
if (server.includes("Oracle")) return "bg-red-600/20 text-red-400"
if (server.includes("DigitalOcean")) return "bg-blue-500/20 text-blue-400" if (server.includes("DigitalOcean")) return "bg-blue-500/20 text-blue-400"
if (server.includes("Azure")) return "bg-sky-500/20 text-sky-400" if (server.includes("Azure")) return "bg-sky-500/20 text-sky-400"
if (server.includes("华为")) return "bg-red-500/20 text-red-400" if (server.includes("华为")) return "bg-red-500/20 text-red-400"
@@ -306,16 +275,52 @@ function getServerBadgeStyle(server: string) {
if (server.includes("火山")) return "bg-amber-500/20 text-amber-400" if (server.includes("火山")) return "bg-amber-500/20 text-amber-400"
if (server.includes("Vercel") || server.includes("v0")) return "bg-foreground/10 text-foreground" if (server.includes("Vercel") || server.includes("v0")) return "bg-foreground/10 text-foreground"
if (server.includes("GitHub")) return "bg-foreground/10 text-foreground" if (server.includes("GitHub")) return "bg-foreground/10 text-foreground"
if (server.includes("EdgeOne")) return "bg-emerald-500/20 text-emerald-400" if (server.includes("EdgeOne Pages")) return "bg-emerald-500/20 text-emerald-400"
if (server.includes("EdgeOne")) return "bg-green-500/20 text-green-400"
if (server.includes("网易") || server.includes("企业邮箱")) return "bg-red-500/20 text-red-400" if (server.includes("网易") || server.includes("企业邮箱")) return "bg-red-500/20 text-red-400"
if (server.includes("狐蒂云-日本")) return "bg-pink-500/20 text-pink-400" if (server.includes("狐蒂云-日本")) return "bg-pink-500/20 text-pink-400"
if (server.includes("狐蒂云-美国-2")) return "bg-purple-500/20 text-purple-400"
if (server.includes("狐蒂云-美国")) return "bg-violet-500/20 text-violet-400" if (server.includes("狐蒂云-美国")) return "bg-violet-500/20 text-violet-400"
if (server.includes("Google-Iowa") || server.includes("Google-Oregon")) return "bg-green-500/20 text-green-400" if (server.includes("青瑞云")) return "bg-lime-500/20 text-lime-400"
if (server.includes("Google-Iowa")) return "bg-green-500/20 text-green-400"
if (server.includes("Google-Oregon")) return "bg-teal-500/20 text-teal-400"
if (server.includes("Google-Taiwan")) return "bg-cyan-500/20 text-cyan-400"
return "bg-muted text-muted-foreground" return "bg-muted text-muted-foreground"
} }
export function SiteNavigation() { export function SiteNavigation() {
const [searchQuery, setSearchQuery] = useState("") const [searchQuery, setSearchQuery] = useState("")
const [displayText, setDisplayText] = useState("")
const [isAnimationDone, setIsAnimationDone] = useState(false)
const fullText = "SIMON站点导航"
useEffect(() => {
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*_-+=<>?/\\|~"
let frame = 0
const totalFrames = fullText.length * 5
const interval = setInterval(() => {
let output = ""
for (let i = 0; i < fullText.length; i++) {
if (i < Math.floor(frame / 5)) {
output += fullText[i]
} else {
output += chars[Math.floor(Math.random() * chars.length)]
}
}
setDisplayText(output)
frame++
if (frame > totalFrames) {
clearInterval(interval)
setDisplayText(fullText)
setIsAnimationDone(true)
}
}, 40)
return () => {
clearInterval(interval)
}
}, [])
const filteredCategories = categories const filteredCategories = categories
.map((category) => ({ .map((category) => ({
@@ -332,64 +337,77 @@ export function SiteNavigation() {
.filter((category) => category.sites.length > 0) .filter((category) => category.sites.length > 0)
return ( return (
<div className="min-h-screen px-4 py-12 md:px-8 lg:px-16"> <div className="min-h-screen px-4 py-16 md:px-8 lg:px-16">
<div className="mx-auto max-w-6xl"> <div className="mx-auto max-w-6xl">
{/* Header */} {/* Header - 居中设计 */}
<header className="mb-12"> <header className="mb-16 text-center">
<div className="flex items-center gap-3 mb-4"> <h1
<Globe className="size-8 text-primary" /> className={`text-4xl md:text-6xl font-bold tracking-widest mb-4 font-mono transition-all duration-500 ${
<h1 className="text-3xl font-bold tracking-tight text-foreground"></h1> isAnimationDone ? "cyber-title" : "text-foreground"
}`}
>
{displayText || "SIMON站点导航"}
</h1>
<div className="flex items-center justify-center gap-2 mb-2">
<span className="block h-px w-16 bg-primary/30" />
<p className="text-muted-foreground text-sm md:text-base tracking-widest uppercase font-mono">
<span className="text-primary/80">zhuzihan.com</span>
<span className="mx-2 text-border">|</span>
</p>
<span className="block h-px w-16 bg-primary/30" />
</div> </div>
<p className="text-muted-foreground text-lg">zhuzihan.com </p>
</header> </header>
{/* Search */} {/* Search - 居中设计 */}
<div className="relative mb-10"> <div className="relative mb-12 max-w-2xl mx-auto">
<Search className="absolute left-4 top-1/2 -translate-y-1/2 size-5 text-muted-foreground" /> <Search className="absolute left-4 top-1/2 -translate-y-1/2 size-5 text-muted-foreground" />
<input <input
type="text" type="text"
placeholder="搜索站点、域名或服务器..." placeholder="搜索站点、域名或服务器..."
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
className="w-full bg-card border border-border rounded-lg py-3 pl-12 pr-4 text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/50 transition-all" className="w-full bg-input border border-border rounded-xl py-4 pl-12 pr-4 text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary/50 transition-all shadow-lg shadow-black/10"
/> />
</div> </div>
{/* Categories */} {/* Categories */}
<div className="space-y-10"> <div className="space-y-12">
{filteredCategories.map((category) => ( {filteredCategories.map((category) => (
<section key={category.title}> <section key={category.title}>
<div className="flex items-center gap-2 mb-4"> <div className="flex items-center gap-3 mb-6 pb-3 border-b border-border/50">
<span className="text-primary">{category.icon}</span> <span className="p-2 bg-primary/10 rounded-lg text-primary">{category.icon}</span>
<h2 className="text-xl font-semibold text-foreground">{category.title}</h2> <h2 className="text-xl font-semibold text-foreground">{category.title}</h2>
<span className="text-sm text-muted-foreground ml-2">({category.sites.length})</span> <span className="text-sm text-muted-foreground px-2 py-1 bg-muted/50 rounded-full">
{category.sites.length}
</span>
</div> </div>
<div className="grid gap-3 md:grid-cols-2 lg:grid-cols-3"> <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{category.sites.map((site) => ( {category.sites.map((site) => (
<a <a
key={site.domain} key={site.domain}
href={site.url} href={site.url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="group flex flex-col gap-3 p-4 bg-card border border-border rounded-lg hover:border-primary/50 hover:bg-card/80 transition-all" className="group flex flex-col gap-3 p-5 bg-card border border-border/50 rounded-xl hover:border-primary/50 hover:shadow-lg hover:shadow-primary/5 transition-all duration-300"
> >
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<h3 className="font-medium text-foreground group-hover:text-primary transition-colors truncate"> <h3 className="font-semibold text-foreground group-hover:text-primary transition-colors truncate">
{site.name} {site.name}
</h3> </h3>
<p className="text-sm text-muted-foreground font-mono truncate mt-1">{site.domain}</p> <p className="text-sm text-muted-foreground font-mono truncate mt-1.5">{site.domain}</p>
</div> </div>
<ExternalLink className="size-4 text-muted-foreground group-hover:text-primary transition-colors flex-shrink-0 ml-2" /> <ExternalLink className="size-4 text-muted-foreground group-hover:text-primary group-hover:translate-x-0.5 group-hover:-translate-y-0.5 transition-all flex-shrink-0 ml-2 mt-1" />
</div> </div>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2 pt-1">
{Array.isArray(site.server) ? ( {Array.isArray(site.server) ? (
site.server.map((s) => ( site.server.map((s) => (
<span <span
key={s} key={s}
className={`inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-medium ${getServerBadgeStyle(s)}`} className={`inline-flex items-center gap-1 px-2.5 py-1 rounded-lg text-xs font-medium ${getServerBadgeStyle(s)}`}
> >
<Server className="size-3" /> <Server className="size-3" />
{s} {s}
@@ -397,7 +415,7 @@ export function SiteNavigation() {
)) ))
) : ( ) : (
<span <span
className={`inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-medium ${getServerBadgeStyle(site.server)}`} className={`inline-flex items-center gap-1 px-2.5 py-1 rounded-lg text-xs font-medium ${getServerBadgeStyle(site.server)}`}
> >
<Server className="size-3" /> <Server className="size-3" />
{site.server} {site.server}
@@ -405,7 +423,7 @@ export function SiteNavigation() {
)} )}
{site.cdn !== "-" && ( {site.cdn !== "-" && (
<span <span
className={`inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-medium ${getCdnBadgeStyle(site.cdn)}`} className={`inline-flex items-center gap-1 px-2.5 py-1 rounded-lg text-xs font-medium ${getCdnBadgeStyle(site.cdn)}`}
> >
<Shield className="size-3" /> <Shield className="size-3" />
{site.cdn} {site.cdn}
@@ -420,14 +438,21 @@ export function SiteNavigation() {
</div> </div>
{/* Footer */} {/* Footer */}
<footer className="mt-16 pt-8 border-t border-border"> <footer className="mt-20 pt-10 border-t border-border/50">
<div className="flex flex-wrap items-center justify-center gap-x-4 gap-y-2 text-sm text-muted-foreground"> <div className="text-center mb-6">
<p className="text-muted-foreground">
<span className="text-primary font-semibold">{categories.reduce((acc, cat) => acc + cat.sites.length, 0)}</span>
<span className="mx-2 text-border">·</span>
使
</p>
</div>
<div className="flex flex-wrap items-center justify-center gap-x-6 gap-y-2 text-sm text-muted-foreground">
<span>Copyright © 2019 - 2025</span> <span>Copyright © 2019 - 2025</span>
<a <a
href="https://beian.miit.gov.cn/" href="https://beian.miit.gov.cn/"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="hover:text-foreground transition-colors" className="hover:text-primary transition-colors"
> >
ICP备2025074424号 ICP备2025074424号
</a> </a>
@@ -435,15 +460,12 @@ export function SiteNavigation() {
href="https://beian.mps.gov.cn" href="https://beian.mps.gov.cn"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="inline-flex items-center gap-1 hover:text-foreground transition-colors" className="inline-flex items-center gap-1.5 hover:text-primary transition-colors"
> >
<img src="/images/beian.png" alt="备案图标" className="size-4" /> <img src="/images/beian.png" alt="备案图标" className="size-4" />
53250402000233 53250402000233
</a> </a>
</div> </div>
<p className="text-center text-sm text-muted-foreground mt-4">
{categories.reduce((acc, cat) => acc + cat.sites.length, 0)} · 使
</p>
</footer> </footer>
</div> </div>
</div> </div>

View File

@@ -9,4 +9,4 @@ const nextConfig = {
} }
export default nextConfig export default nextConfig

View File

@@ -56,7 +56,7 @@
"recharts": "2.15.4", "recharts": "2.15.4",
"sonner": "^1.7.4", "sonner": "^1.7.4",
"tailwind-merge": "^3.3.1", "tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "1.0.7",
"vaul": "^1.1.2", "vaul": "^1.1.2",
"zod": "3.25.76" "zod": "3.25.76"
}, },
@@ -67,7 +67,6 @@
"@types/react-dom": "^19", "@types/react-dom": "^19",
"postcss": "^8.5", "postcss": "^8.5",
"tailwindcss": "^4.1.9", "tailwindcss": "^4.1.9",
"tw-animate-css": "1.3.3",
"typescript": "^5" "typescript": "^5"
} }
} }

1474
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,4 @@
@import 'tailwindcss'; @import 'tailwindcss';
@import 'tw-animate-css';
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));