Initialized repository for chat Personal navigation site
Co-authored-by: Simon <85533298+handsomezhuzhu@users.noreply.github.com>
30
README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# Personal navigation site
|
||||
|
||||
*Automatically synced with your [v0.app](https://v0.app) deployments*
|
||||
|
||||
[](https://vercel.com/kdaugh14-4907s-projects/v0-personal-navigation-site)
|
||||
[](https://v0.app/chat/n78rOW1VhXq)
|
||||
|
||||
## Overview
|
||||
|
||||
This repository will stay in sync with your deployed chats on [v0.app](https://v0.app).
|
||||
Any changes you make to your deployed app will be automatically pushed to this repository from [v0.app](https://v0.app).
|
||||
|
||||
## Deployment
|
||||
|
||||
Your project is live at:
|
||||
|
||||
**[https://vercel.com/kdaugh14-4907s-projects/v0-personal-navigation-site](https://vercel.com/kdaugh14-4907s-projects/v0-personal-navigation-site)**
|
||||
|
||||
## Build your app
|
||||
|
||||
Continue building your app on:
|
||||
|
||||
**[https://v0.app/chat/n78rOW1VhXq](https://v0.app/chat/n78rOW1VhXq)**
|
||||
|
||||
## How It Works
|
||||
|
||||
1. Create and modify your project using [v0.app](https://v0.app)
|
||||
2. Deploy your chats from the v0 interface
|
||||
3. Changes are automatically pushed to this repository
|
||||
4. Vercel deploys the latest version from this repository
|
||||
126
app/globals.css
Normal file
@@ -0,0 +1,126 @@
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
/* 深色主题设计,适合个人导航站 */
|
||||
:root {
|
||||
--background: oklch(0.13 0.01 260);
|
||||
--foreground: oklch(0.95 0 0);
|
||||
--card: oklch(0.18 0.01 260);
|
||||
--card-foreground: oklch(0.95 0 0);
|
||||
--popover: oklch(0.18 0.01 260);
|
||||
--popover-foreground: oklch(0.95 0 0);
|
||||
--primary: oklch(0.7 0.15 200);
|
||||
--primary-foreground: oklch(0.1 0 0);
|
||||
--secondary: oklch(0.25 0.01 260);
|
||||
--secondary-foreground: oklch(0.9 0 0);
|
||||
--muted: oklch(0.25 0.01 260);
|
||||
--muted-foreground: oklch(0.65 0 0);
|
||||
--accent: oklch(0.7 0.15 200);
|
||||
--accent-foreground: oklch(0.1 0 0);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--destructive-foreground: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.28 0.01 260);
|
||||
--input: oklch(0.28 0.01 260);
|
||||
--ring: oklch(0.7 0.15 200);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--radius: 0.625rem;
|
||||
--sidebar: oklch(0.15 0.01 260);
|
||||
--sidebar-foreground: oklch(0.95 0 0);
|
||||
--sidebar-primary: oklch(0.7 0.15 200);
|
||||
--sidebar-primary-foreground: oklch(0.1 0 0);
|
||||
--sidebar-accent: oklch(0.25 0.01 260);
|
||||
--sidebar-accent-foreground: oklch(0.9 0 0);
|
||||
--sidebar-border: oklch(0.28 0.01 260);
|
||||
--sidebar-ring: oklch(0.7 0.15 200);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.13 0.01 260);
|
||||
--foreground: oklch(0.95 0 0);
|
||||
--card: oklch(0.18 0.01 260);
|
||||
--card-foreground: oklch(0.95 0 0);
|
||||
--popover: oklch(0.18 0.01 260);
|
||||
--popover-foreground: oklch(0.95 0 0);
|
||||
--primary: oklch(0.7 0.15 200);
|
||||
--primary-foreground: oklch(0.1 0 0);
|
||||
--secondary: oklch(0.25 0.01 260);
|
||||
--secondary-foreground: oklch(0.9 0 0);
|
||||
--muted: oklch(0.25 0.01 260);
|
||||
--muted-foreground: oklch(0.65 0 0);
|
||||
--accent: oklch(0.7 0.15 200);
|
||||
--accent-foreground: oklch(0.1 0 0);
|
||||
--destructive: oklch(0.396 0.141 25.723);
|
||||
--destructive-foreground: oklch(0.637 0.237 25.331);
|
||||
--border: oklch(0.28 0.01 260);
|
||||
--input: oklch(0.28 0.01 260);
|
||||
--ring: oklch(0.7 0.15 200);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(0.15 0.01 260);
|
||||
--sidebar-foreground: oklch(0.95 0 0);
|
||||
--sidebar-primary: oklch(0.7 0.15 200);
|
||||
--sidebar-primary-foreground: oklch(0.1 0 0);
|
||||
--sidebar-accent: oklch(0.25 0.01 260);
|
||||
--sidebar-accent-foreground: oklch(0.9 0 0);
|
||||
--sidebar-border: oklch(0.28 0.01 260);
|
||||
--sidebar-ring: oklch(0.7 0.15 200);
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--font-sans: "Geist", "Geist Fallback";
|
||||
--font-mono: "Geist Mono", "Geist Mono Fallback";
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
46
app/layout.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import type React from "react"
|
||||
import type { Metadata } from "next"
|
||||
import { Geist, Geist_Mono } from "next/font/google"
|
||||
import { Analytics } from "@vercel/analytics/next"
|
||||
import "./globals.css"
|
||||
|
||||
const _geist = Geist({ subsets: ["latin"] })
|
||||
const _geistMono = Geist_Mono({ subsets: ["latin"] })
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "站点导航 | zhuzihan.com",
|
||||
description: "个人站点导航与管理中心",
|
||||
generator: "v0.app",
|
||||
icons: {
|
||||
icon: [
|
||||
{
|
||||
url: "/icon-light-32x32.png",
|
||||
media: "(prefers-color-scheme: light)",
|
||||
},
|
||||
{
|
||||
url: "/icon-dark-32x32.png",
|
||||
media: "(prefers-color-scheme: dark)",
|
||||
},
|
||||
{
|
||||
url: "/icon.svg",
|
||||
type: "image/svg+xml",
|
||||
},
|
||||
],
|
||||
apple: "/apple-icon.png",
|
||||
},
|
||||
}
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode
|
||||
}>) {
|
||||
return (
|
||||
<html lang="zh-CN">
|
||||
<body className={`font-sans antialiased`}>
|
||||
{children}
|
||||
<Analytics />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
9
app/page.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import { SiteNavigation } from "@/components/site-navigation"
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="min-h-screen bg-background">
|
||||
<SiteNavigation />
|
||||
</main>
|
||||
)
|
||||
}
|
||||
21
components.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": true,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "",
|
||||
"css": "app/globals.css",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"iconLibrary": "lucide"
|
||||
}
|
||||
351
components/site-navigation.tsx
Normal file
@@ -0,0 +1,351 @@
|
||||
"use client"
|
||||
|
||||
import type React from "react"
|
||||
|
||||
import { useState } from "react"
|
||||
import { ExternalLink, Globe, Server, Mail, Zap, Shield, Code, FileText, Search } from "lucide-react"
|
||||
|
||||
interface Site {
|
||||
domain: string
|
||||
name: string
|
||||
server: string
|
||||
cdn: string
|
||||
url: string
|
||||
}
|
||||
|
||||
interface Category {
|
||||
title: string
|
||||
icon: React.ReactNode
|
||||
sites: Site[]
|
||||
}
|
||||
|
||||
const categories: Category[] = [
|
||||
{
|
||||
title: "博客与主页",
|
||||
icon: <FileText className="size-5" />,
|
||||
sites: [
|
||||
{
|
||||
domain: "zhuzihan.com",
|
||||
name: "个人博客",
|
||||
server: "EdgeOne Pages",
|
||||
cdn: "EdgeOne Pages并加速",
|
||||
url: "https://zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "blog.zhuzihan.com",
|
||||
name: "个人博客备份",
|
||||
server: "阿里云Pages",
|
||||
cdn: "ESA加速",
|
||||
url: "https://blog.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "www.zhuzihan.com",
|
||||
name: "个人主页",
|
||||
server: "阿里云",
|
||||
cdn: "无加速",
|
||||
url: "https://www.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "home.zhuzihan.com",
|
||||
name: "导航页",
|
||||
server: "GitHub Pages",
|
||||
cdn: "无加速",
|
||||
url: "https://home.zhuzihan.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "AI 与 API 服务",
|
||||
icon: <Zap className="size-5" />,
|
||||
sites: [
|
||||
{
|
||||
domain: "ai.zhuzihan.com",
|
||||
name: "OpenWebUI",
|
||||
server: "DigitalOcean",
|
||||
cdn: "EdgeOne加速",
|
||||
url: "https://ai.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "api.zhuzihan.com",
|
||||
name: "New-API",
|
||||
server: "DigitalOcean",
|
||||
cdn: "EdgeOne加速",
|
||||
url: "https://api.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "load.zhuzihan.com",
|
||||
name: "GPT-Load",
|
||||
server: "华为云",
|
||||
cdn: "EdgeOne加速",
|
||||
url: "https://load.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "crs.zhuzihan.com",
|
||||
name: "Claude轮训",
|
||||
server: "Azure",
|
||||
cdn: "无加速",
|
||||
url: "https://crs.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "api-test.zhuzihan.com",
|
||||
name: "API批量测试",
|
||||
server: "GitHub Pages",
|
||||
cdn: "EdgeOne加速",
|
||||
url: "https://api-test.zhuzihan.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "云服务管理后台",
|
||||
icon: <Server className="size-5" />,
|
||||
sites: [
|
||||
{
|
||||
domain: "admin.zhuzihan.com",
|
||||
name: "DigitalOcean管理后台",
|
||||
server: "DigitalOcean",
|
||||
cdn: "无加速",
|
||||
url: "https://admin.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "azure.zhuzihan.com",
|
||||
name: "Azure管理后台",
|
||||
server: "Azure",
|
||||
cdn: "无加速",
|
||||
url: "https://azure.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "huawei.zhuzihan.com",
|
||||
name: "华为云管理后台",
|
||||
server: "华为云",
|
||||
cdn: "无加速",
|
||||
url: "https://huawei.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "ali.zhuzihan.com",
|
||||
name: "阿里云管理后台",
|
||||
server: "阿里云",
|
||||
cdn: "无加速",
|
||||
url: "https://ali.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "qzy.zhuzihan.com",
|
||||
name: "青竹云管理后台",
|
||||
server: "青竹云",
|
||||
cdn: "无加速",
|
||||
url: "https://qzy.zhuzihan.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "项目与工具",
|
||||
icon: <Code className="size-5" />,
|
||||
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: "Vercel",
|
||||
cdn: "EdgeOne加速",
|
||||
url: "https://code.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "state.zhuzihan.com",
|
||||
name: "探针服务器状态检测",
|
||||
server: "华为云",
|
||||
cdn: "EdgeOne加速",
|
||||
url: "https://state.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "yummy.zhuzihan.com",
|
||||
name: "倒计时",
|
||||
server: "GitHub Pages",
|
||||
cdn: "无加速",
|
||||
url: "https://yummy.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "file.zhuzihan.com",
|
||||
name: "文件快递柜",
|
||||
server: "华为云",
|
||||
cdn: "无加速",
|
||||
url: "https://file.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "2fa.zhuzihan.com",
|
||||
name: "纯前端2FA",
|
||||
server: "EdgeOne Pages",
|
||||
cdn: "EdgeOne Pages并加速",
|
||||
url: "https://2fa.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "ieee.zhuzihan.com",
|
||||
name: "IEEE 754二进制计算演示",
|
||||
server: "v0 Pages",
|
||||
cdn: "Vercel自带加速",
|
||||
url: "https://ieee.zhuzihan.com",
|
||||
},
|
||||
{
|
||||
domain: "bcj.zhuzihan.com",
|
||||
name: "并查集算法演示",
|
||||
server: "v0 Pages",
|
||||
cdn: "Vercel自带加速",
|
||||
url: "https://bcj.zhuzihan.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "邮箱服务",
|
||||
icon: <Mail className="size-5" />,
|
||||
sites: [
|
||||
{ domain: "@zhuzihan.com", name: "个人顶级邮箱", server: "网易企业邮箱", cdn: "-", url: "https://qiye.163.com" },
|
||||
{
|
||||
domain: "@mail.zhuzihan.com",
|
||||
name: "个人邮箱",
|
||||
server: "阿里企业邮箱",
|
||||
cdn: "-",
|
||||
url: "https://qiye.aliyun.com",
|
||||
},
|
||||
{
|
||||
domain: "@webmail.zhuzihan.com",
|
||||
name: "个人备用邮箱",
|
||||
server: "阿里企业邮箱",
|
||||
cdn: "-",
|
||||
url: "https://qiye.aliyun.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
function getCdnBadgeStyle(cdn: string) {
|
||||
if (cdn.includes("EdgeOne")) return "bg-emerald-500/20 text-emerald-400"
|
||||
if (cdn.includes("ESA")) return "bg-sky-500/20 text-sky-400"
|
||||
if (cdn.includes("Vercel")) return "bg-foreground/10 text-foreground"
|
||||
return "bg-muted text-muted-foreground"
|
||||
}
|
||||
|
||||
function getServerBadgeStyle(server: string) {
|
||||
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("华为")) return "bg-red-500/20 text-red-400"
|
||||
if (server.includes("阿里")) return "bg-orange-500/20 text-orange-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("GitHub")) return "bg-foreground/10 text-foreground"
|
||||
if (server.includes("EdgeOne")) return "bg-emerald-500/20 text-emerald-400"
|
||||
if (server.includes("网易") || server.includes("企业邮箱")) return "bg-red-500/20 text-red-400"
|
||||
return "bg-muted text-muted-foreground"
|
||||
}
|
||||
|
||||
export function SiteNavigation() {
|
||||
const [searchQuery, setSearchQuery] = useState("")
|
||||
|
||||
const filteredCategories = categories
|
||||
.map((category) => ({
|
||||
...category,
|
||||
sites: category.sites.filter(
|
||||
(site) =>
|
||||
site.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
site.domain.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
site.server.toLowerCase().includes(searchQuery.toLowerCase()),
|
||||
),
|
||||
}))
|
||||
.filter((category) => category.sites.length > 0)
|
||||
|
||||
return (
|
||||
<div className="min-h-screen px-4 py-12 md:px-8 lg:px-16">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
{/* Header */}
|
||||
<header className="mb-12">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<Globe className="size-8 text-primary" />
|
||||
<h1 className="text-3xl font-bold tracking-tight text-foreground">站点导航</h1>
|
||||
</div>
|
||||
<p className="text-muted-foreground text-lg">zhuzihan.com 全部站点与服务管理</p>
|
||||
</header>
|
||||
|
||||
{/* Search */}
|
||||
<div className="relative mb-10">
|
||||
<Search className="absolute left-4 top-1/2 -translate-y-1/2 size-5 text-muted-foreground" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="搜索站点、域名或服务器..."
|
||||
value={searchQuery}
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Categories */}
|
||||
<div className="space-y-10">
|
||||
{filteredCategories.map((category) => (
|
||||
<section key={category.title}>
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<span className="text-primary">{category.icon}</span>
|
||||
<h2 className="text-xl font-semibold text-foreground">{category.title}</h2>
|
||||
<span className="text-sm text-muted-foreground ml-2">({category.sites.length})</span>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 md:grid-cols-2 lg:grid-cols-3">
|
||||
{category.sites.map((site) => (
|
||||
<a
|
||||
key={site.domain}
|
||||
href={site.url}
|
||||
target="_blank"
|
||||
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"
|
||||
>
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="font-medium text-foreground group-hover:text-primary transition-colors truncate">
|
||||
{site.name}
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground font-mono truncate mt-1">{site.domain}</p>
|
||||
</div>
|
||||
<ExternalLink className="size-4 text-muted-foreground group-hover:text-primary transition-colors flex-shrink-0 ml-2" />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<span
|
||||
className={`inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-medium ${getServerBadgeStyle(site.server)}`}
|
||||
>
|
||||
<Server className="size-3" />
|
||||
{site.server}
|
||||
</span>
|
||||
{site.cdn !== "-" && (
|
||||
<span
|
||||
className={`inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-medium ${getCdnBadgeStyle(site.cdn)}`}
|
||||
>
|
||||
<Shield className="size-3" />
|
||||
{site.cdn}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="mt-16 pt-8 border-t border-border">
|
||||
<p className="text-center text-sm text-muted-foreground">
|
||||
共 {categories.reduce((acc, cat) => acc + cat.sites.length, 0)} 个站点 · 个人使用
|
||||
</p>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
11
components/theme-provider.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
'use client'
|
||||
|
||||
import * as React from 'react'
|
||||
import {
|
||||
ThemeProvider as NextThemesProvider,
|
||||
type ThemeProviderProps,
|
||||
} from 'next-themes'
|
||||
|
||||
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
|
||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
|
||||
}
|
||||
6
lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
12
next.config.mjs
Normal file
@@ -0,0 +1,12 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
typescript: {
|
||||
ignoreBuildErrors: true,
|
||||
},
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
export default nextConfig
|
||||
73
package.json
Normal file
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"name": "my-v0-project",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "next build",
|
||||
"dev": "next dev",
|
||||
"lint": "eslint .",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^3.10.0",
|
||||
"@radix-ui/react-accordion": "1.2.2",
|
||||
"@radix-ui/react-alert-dialog": "1.1.4",
|
||||
"@radix-ui/react-aspect-ratio": "1.1.1",
|
||||
"@radix-ui/react-avatar": "1.1.2",
|
||||
"@radix-ui/react-checkbox": "1.1.3",
|
||||
"@radix-ui/react-collapsible": "1.1.2",
|
||||
"@radix-ui/react-context-menu": "2.2.4",
|
||||
"@radix-ui/react-dialog": "1.1.4",
|
||||
"@radix-ui/react-dropdown-menu": "2.1.4",
|
||||
"@radix-ui/react-hover-card": "1.1.4",
|
||||
"@radix-ui/react-label": "2.1.1",
|
||||
"@radix-ui/react-menubar": "1.1.4",
|
||||
"@radix-ui/react-navigation-menu": "1.2.3",
|
||||
"@radix-ui/react-popover": "1.1.4",
|
||||
"@radix-ui/react-progress": "1.1.1",
|
||||
"@radix-ui/react-radio-group": "1.2.2",
|
||||
"@radix-ui/react-scroll-area": "1.2.2",
|
||||
"@radix-ui/react-select": "2.1.4",
|
||||
"@radix-ui/react-separator": "1.1.1",
|
||||
"@radix-ui/react-slider": "1.2.2",
|
||||
"@radix-ui/react-slot": "1.1.1",
|
||||
"@radix-ui/react-switch": "1.1.2",
|
||||
"@radix-ui/react-tabs": "1.1.2",
|
||||
"@radix-ui/react-toast": "1.2.4",
|
||||
"@radix-ui/react-toggle": "1.1.1",
|
||||
"@radix-ui/react-toggle-group": "1.1.1",
|
||||
"@radix-ui/react-tooltip": "1.1.6",
|
||||
"@vercel/analytics": "1.3.1",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "1.0.4",
|
||||
"date-fns": "4.1.0",
|
||||
"embla-carousel-react": "8.5.1",
|
||||
"input-otp": "1.4.1",
|
||||
"lucide-react": "^0.454.0",
|
||||
"next": "16.0.10",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "19.2.0",
|
||||
"react-day-picker": "9.8.0",
|
||||
"react-dom": "19.2.0",
|
||||
"react-hook-form": "^7.60.0",
|
||||
"react-resizable-panels": "^2.1.7",
|
||||
"recharts": "2.15.4",
|
||||
"sonner": "^1.7.4",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"vaul": "^1.1.2",
|
||||
"zod": "3.25.76"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.9",
|
||||
"@types/node": "^22",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"postcss": "^8.5",
|
||||
"tailwindcss": "^4.1.9",
|
||||
"tw-animate-css": "1.3.3",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
3225
pnpm-lock.yaml
generated
Normal file
8
postcss.config.mjs
Normal file
@@ -0,0 +1,8 @@
|
||||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
||||
BIN
public/apple-icon.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
public/icon-dark-32x32.png
Normal file
|
After Width: | Height: | Size: 585 B |
BIN
public/icon-light-32x32.png
Normal file
|
After Width: | Height: | Size: 566 B |
26
public/icon.svg
Normal file
@@ -0,0 +1,26 @@
|
||||
<svg width="180" height="180" viewBox="0 0 180 180" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<style>
|
||||
@media (prefers-color-scheme: light) {
|
||||
.background { fill: black; }
|
||||
.foreground { fill: white; }
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.background { fill: white; }
|
||||
.foreground { fill: black; }
|
||||
}
|
||||
</style>
|
||||
<g clip-path="url(#clip0_7960_43945)">
|
||||
<rect class="background" width="180" height="180" rx="37" />
|
||||
<g style="transform: scale(95%); transform-origin: center">
|
||||
<path class="foreground"
|
||||
d="M101.141 53H136.632C151.023 53 162.689 64.6662 162.689 79.0573V112.904H148.112V79.0573C148.112 78.7105 148.098 78.3662 148.072 78.0251L112.581 112.898C112.701 112.902 112.821 112.904 112.941 112.904H148.112V126.672H112.941C98.5504 126.672 86.5638 114.891 86.5638 100.5V66.7434H101.141V100.5C101.141 101.15 101.191 101.792 101.289 102.422L137.56 66.7816C137.255 66.7563 136.945 66.7434 136.632 66.7434H101.141V53Z" />
|
||||
<path class="foreground"
|
||||
d="M65.2926 124.136L14 66.7372H34.6355L64.7495 100.436V66.7372H80.1365V118.47C80.1365 126.278 70.4953 129.958 65.2926 124.136Z" />
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_7960_43945">
|
||||
<rect width="180" height="180" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
BIN
public/placeholder-logo.png
Normal file
|
After Width: | Height: | Size: 568 B |
1
public/placeholder-logo.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="215" height="48" fill="none"><path fill="#000" d="M57.588 9.6h6L73.828 38h-5.2l-2.36-6.88h-11.36L52.548 38h-5.2l10.24-28.4Zm7.16 17.16-4.16-12.16-4.16 12.16h8.32Zm23.694-2.24c-.186-1.307-.706-2.32-1.56-3.04-.853-.72-1.866-1.08-3.04-1.08-1.68 0-2.986.613-3.92 1.84-.906 1.227-1.36 2.947-1.36 5.16s.454 3.933 1.36 5.16c.934 1.227 2.24 1.84 3.92 1.84 1.254 0 2.307-.373 3.16-1.12.854-.773 1.387-1.867 1.6-3.28l5.12.24c-.186 1.68-.733 3.147-1.64 4.4-.906 1.227-2.08 2.173-3.52 2.84-1.413.667-2.986 1-4.72 1-2.08 0-3.906-.453-5.48-1.36-1.546-.907-2.76-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84 0-2.24.427-4.187 1.28-5.84.88-1.68 2.094-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.68 0 3.227.32 4.64.96 1.414.64 2.56 1.56 3.44 2.76.907 1.2 1.454 2.6 1.64 4.2l-5.12.28Zm11.486-7.72.12 3.4c.534-1.227 1.307-2.173 2.32-2.84 1.04-.693 2.267-1.04 3.68-1.04 1.494 0 2.76.387 3.8 1.16 1.067.747 1.827 1.813 2.28 3.2.507-1.44 1.294-2.52 2.36-3.24 1.094-.747 2.414-1.12 3.96-1.12 1.414 0 2.64.307 3.68.92s1.84 1.52 2.4 2.72c.56 1.2.84 2.667.84 4.4V38h-4.96V25.92c0-1.813-.293-3.187-.88-4.12-.56-.96-1.413-1.44-2.56-1.44-.906 0-1.68.213-2.32.64-.64.427-1.133 1.053-1.48 1.88-.32.827-.48 1.84-.48 3.04V38h-4.56V25.92c0-1.2-.133-2.213-.4-3.04-.24-.827-.626-1.453-1.16-1.88-.506-.427-1.133-.64-1.88-.64-.906 0-1.68.227-2.32.68-.64.427-1.133 1.053-1.48 1.88-.32.827-.48 1.827-.48 3V38h-4.96V16.8h4.48Zm26.723 10.6c0-2.24.427-4.187 1.28-5.84.854-1.68 2.067-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.84 0 3.494.413 4.96 1.24 1.467.827 2.64 2.08 3.52 3.76.88 1.653 1.347 3.693 1.4 6.12v1.32h-15.08c.107 1.813.614 3.227 1.52 4.24.907.987 2.134 1.48 3.68 1.48.987 0 1.88-.253 2.68-.76a4.803 4.803 0 0 0 1.84-2.2l5.08.36c-.64 2.027-1.84 3.64-3.6 4.84-1.733 1.173-3.733 1.76-6 1.76-2.08 0-3.906-.453-5.48-1.36-1.573-.907-2.786-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84Zm15.16-2.04c-.213-1.733-.76-3.013-1.64-3.84-.853-.827-1.893-1.24-3.12-1.24-1.44 0-2.6.453-3.48 1.36-.88.88-1.44 2.12-1.68 3.72h9.92ZM163.139 9.6V38h-5.04V9.6h5.04Zm8.322 7.2.24 5.88-.64-.36c.32-2.053 1.094-3.56 2.32-4.52 1.254-.987 2.787-1.48 4.6-1.48 2.32 0 4.107.733 5.36 2.2 1.254 1.44 1.88 3.387 1.88 5.84V38h-4.96V25.92c0-1.253-.12-2.28-.36-3.08-.24-.8-.64-1.413-1.2-1.84-.533-.427-1.253-.64-2.16-.64-1.44 0-2.573.48-3.4 1.44-.8.933-1.2 2.307-1.2 4.12V38h-4.96V16.8h4.48Zm30.003 7.72c-.186-1.307-.706-2.32-1.56-3.04-.853-.72-1.866-1.08-3.04-1.08-1.68 0-2.986.613-3.92 1.84-.906 1.227-1.36 2.947-1.36 5.16s.454 3.933 1.36 5.16c.934 1.227 2.24 1.84 3.92 1.84 1.254 0 2.307-.373 3.16-1.12.854-.773 1.387-1.867 1.6-3.28l5.12.24c-.186 1.68-.733 3.147-1.64 4.4-.906 1.227-2.08 2.173-3.52 2.84-1.413.667-2.986 1-4.72 1-2.08 0-3.906-.453-5.48-1.36-1.546-.907-2.76-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84 0-2.24.427-4.187 1.28-5.84.88-1.68 2.094-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.68 0 3.227.32 4.64.96 1.414.64 2.56 1.56 3.44 2.76.907 1.2 1.454 2.6 1.64 4.2l-5.12.28Zm11.443 8.16V38h-5.6v-5.32h5.6Z"/><path fill="#171717" fill-rule="evenodd" d="m7.839 40.783 16.03-28.054L20 6 0 40.783h7.839Zm8.214 0H40L27.99 19.894l-4.02 7.032 3.976 6.914H20.02l-3.967 6.943Z" clip-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
BIN
public/placeholder-user.jpg
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
public/placeholder.jpg
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
1
public/placeholder.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200" fill="none"><rect width="1200" height="1200" fill="#EAEAEA" rx="3"/><g opacity=".5"><g opacity=".5"><path fill="#FAFAFA" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/></g><path stroke="url(#a)" stroke-width="2.418" d="M0-1.209h553.581" transform="scale(1 -1) rotate(45 1163.11 91.165)"/><path stroke="url(#b)" stroke-width="2.418" d="M404.846 598.671h391.726"/><path stroke="url(#c)" stroke-width="2.418" d="M599.5 795.742V404.017"/><path stroke="url(#d)" stroke-width="2.418" d="m795.717 796.597-391.441-391.44"/><path fill="#fff" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/><g clip-path="url(#e)"><path fill="#666" fill-rule="evenodd" d="M616.426 586.58h-31.434v16.176l3.553-3.554.531-.531h9.068l.074-.074 8.463-8.463h2.565l7.18 7.181V586.58Zm-15.715 14.654 3.698 3.699 1.283 1.282-2.565 2.565-1.282-1.283-5.2-5.199h-6.066l-5.514 5.514-.073.073v2.876a2.418 2.418 0 0 0 2.418 2.418h26.598a2.418 2.418 0 0 0 2.418-2.418v-8.317l-8.463-8.463-7.181 7.181-.071.072Zm-19.347 5.442v4.085a6.045 6.045 0 0 0 6.046 6.045h26.598a6.044 6.044 0 0 0 6.045-6.045v-7.108l1.356-1.355-1.282-1.283-.074-.073v-17.989h-38.689v23.43l-.146.146.146.147Z" clip-rule="evenodd"/></g><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/></g><defs><linearGradient id="a" x1="554.061" x2="-.48" y1=".083" y2=".087" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="b" x1="796.912" x2="404.507" y1="599.963" y2="599.965" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="c" x1="600.792" x2="600.794" y1="403.677" y2="796.082" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="d" x1="404.85" x2="796.972" y1="403.903" y2="796.02" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><clipPath id="e"><path fill="#fff" d="M581.364 580.535h38.689v38.689h-38.689z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
125
styles/globals.css
Normal file
@@ -0,0 +1,125 @@
|
||||
@import 'tailwindcss';
|
||||
@import 'tw-animate-css';
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
:root {
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-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: oklch(0.97 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);
|
||||
--destructive-foreground: 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);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--radius: 0.625rem;
|
||||
--sidebar: oklch(0.985 0 0);
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.205 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.97 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||
--sidebar-border: oklch(0.922 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.145 0 0);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--card: oklch(0.145 0 0);
|
||||
--card-foreground: oklch(0.985 0 0);
|
||||
--popover: oklch(0.145 0 0);
|
||||
--popover-foreground: oklch(0.985 0 0);
|
||||
--primary: oklch(0.985 0 0);
|
||||
--primary-foreground: oklch(0.205 0 0);
|
||||
--secondary: oklch(0.269 0 0);
|
||||
--secondary-foreground: oklch(0.985 0 0);
|
||||
--muted: oklch(0.269 0 0);
|
||||
--muted-foreground: oklch(0.708 0 0);
|
||||
--accent: oklch(0.269 0 0);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
--destructive: oklch(0.396 0.141 25.723);
|
||||
--destructive-foreground: oklch(0.637 0.237 25.331);
|
||||
--border: oklch(0.269 0 0);
|
||||
--input: oklch(0.269 0 0);
|
||||
--ring: oklch(0.439 0 0);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(0.205 0 0);
|
||||
--sidebar-foreground: oklch(0.985 0 0);
|
||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.269 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||
--sidebar-border: oklch(0.269 0 0);
|
||||
--sidebar-ring: oklch(0.439 0 0);
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--font-sans: 'Geist', 'Geist Fallback';
|
||||
--font-mono: 'Geist Mono', 'Geist Mono Fallback';
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
27
tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"target": "ES6",
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||