mirror of
https://github.com/hamster1963/nezha-dash.git
synced 2025-04-24 21:10:45 +08:00
feat: add tag switch
This commit is contained in:
parent
ba9ba92271
commit
bb519a07c9
@ -3,4 +3,5 @@ NezhaAuth=your-nezha-api-token
|
|||||||
DefaultLocale=zh
|
DefaultLocale=zh
|
||||||
NEXT_PUBLIC_NezhaFetchInterval=5000
|
NEXT_PUBLIC_NezhaFetchInterval=5000
|
||||||
NEXT_PUBLIC_ShowFlag=true
|
NEXT_PUBLIC_ShowFlag=true
|
||||||
NEXT_PUBLIC_DisableCartoon=true
|
NEXT_PUBLIC_DisableCartoon=true
|
||||||
|
NEXT_PUBLIC_ShowTag=true
|
@ -5,7 +5,14 @@ import ServerCard from "../../../../components/ServerCard";
|
|||||||
import { nezhaFetcher } from "../../../../lib/utils";
|
import { nezhaFetcher } from "../../../../lib/utils";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import getEnv from "../../../../lib/env-entry";
|
import getEnv from "../../../../lib/env-entry";
|
||||||
|
import Switch from "@/components/Switch";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
const defaultTag = "All";
|
||||||
|
|
||||||
export default function ServerListClient() {
|
export default function ServerListClient() {
|
||||||
|
const [tag, setTag] = useState<string>(defaultTag);
|
||||||
|
|
||||||
const { data, error } = useSWR<ServerApi>("/api/server", nezhaFetcher, {
|
const { data, error } = useSWR<ServerApi>("/api/server", nezhaFetcher, {
|
||||||
refreshInterval: Number(getEnv("NEXT_PUBLIC_NezhaFetchInterval")) || 2000,
|
refreshInterval: Number(getEnv("NEXT_PUBLIC_NezhaFetchInterval")) || 2000,
|
||||||
});
|
});
|
||||||
@ -23,17 +30,31 @@ export default function ServerListClient() {
|
|||||||
|
|
||||||
const { result } = data;
|
const { result } = data;
|
||||||
|
|
||||||
|
const allTag = result.map((server) => server.tag).filter((tag) => tag);
|
||||||
|
const uniqueTags = [...new Set(allTag)];
|
||||||
|
uniqueTags.unshift(defaultTag);
|
||||||
|
|
||||||
const sortedServers = result.sort((a, b) => {
|
const sortedServers = result.sort((a, b) => {
|
||||||
const displayIndexDiff = (b.display_index || 0) - (a.display_index || 0);
|
const displayIndexDiff = (b.display_index || 0) - (a.display_index || 0);
|
||||||
if (displayIndexDiff !== 0) return displayIndexDiff;
|
if (displayIndexDiff !== 0) return displayIndexDiff;
|
||||||
return a.id - b.id;
|
return a.id - b.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const filteredServers =
|
||||||
|
tag === defaultTag
|
||||||
|
? sortedServers
|
||||||
|
: sortedServers.filter((server) => server.tag === tag);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="grid grid-cols-1 gap-2 md:grid-cols-2">
|
<>
|
||||||
{sortedServers.map((serverInfo) => (
|
{getEnv("NEXT_PUBLIC_ShowTag") === "true" && uniqueTags.length > 1 && (
|
||||||
<ServerCard key={serverInfo.id} serverInfo={serverInfo} />
|
<Switch allTag={uniqueTags} nowTag={tag} setTag={setTag} />
|
||||||
))}
|
)}
|
||||||
</section>
|
<section className="grid grid-cols-1 gap-2 md:grid-cols-2">
|
||||||
|
{filteredServers.map((serverInfo) => (
|
||||||
|
<ServerCard key={serverInfo.id} serverInfo={serverInfo} />
|
||||||
|
))}
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
48
components/Switch.tsx
Normal file
48
components/Switch.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
|
export default function Switch({
|
||||||
|
allTag,
|
||||||
|
nowTag,
|
||||||
|
setTag,
|
||||||
|
}: {
|
||||||
|
allTag: string[];
|
||||||
|
nowTag: string;
|
||||||
|
setTag: (tag: string) => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className="z-50 flex flex-col items-start">
|
||||||
|
<div className="flex items-center gap-1 rounded-[50px] bg-stone-100 p-[3px] dark:bg-stone-800">
|
||||||
|
{allTag.map((tag) => (
|
||||||
|
<div
|
||||||
|
key={tag}
|
||||||
|
onClick={() => setTag(tag)}
|
||||||
|
className={cn(
|
||||||
|
"relative cursor-pointer rounded-3xl px-2.5 py-[8px] text-[13px] font-[600] transition-all duration-500",
|
||||||
|
nowTag === tag
|
||||||
|
? "text-black dark:text-white"
|
||||||
|
: "text-stone-400 dark:text-stone-500",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{nowTag === tag && (
|
||||||
|
<motion.div
|
||||||
|
layoutId="nav-item"
|
||||||
|
className="absolute inset-0 z-10 h-full w-full content-center bg-white shadow-lg shadow-black/5 dark:bg-stone-700 dark:shadow-white/5"
|
||||||
|
style={{
|
||||||
|
originY: "0px",
|
||||||
|
borderRadius: 46,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<div className="relative z-20 flex items-center gap-1">
|
||||||
|
<p className="whitespace-nowrap">{tag}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -28,6 +28,7 @@
|
|||||||
"country-flag-icons": "^1.5.13",
|
"country-flag-icons": "^1.5.13",
|
||||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||||
"flag-icons": "^7.2.3",
|
"flag-icons": "^7.2.3",
|
||||||
|
"framer-motion": "^11.9.0",
|
||||||
"lucide-react": "^0.414.0",
|
"lucide-react": "^0.414.0",
|
||||||
"luxon": "^3.5.0",
|
"luxon": "^3.5.0",
|
||||||
"next": "^14.2.13",
|
"next": "^14.2.13",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"target": "ES6",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
Loading…
Reference in New Issue
Block a user