mirror of
https://github.com/woodchen-ink/nezha-dash-v1.git
synced 2025-07-18 01:21:56 +08:00
更新 GroupSwitch 组件,增加暗黑模式支持和国家切换功能,同时优化状态管理逻辑以适应不同的切换需求。在 Server 页面中添加国家筛选功能,提升用户体验。
This commit is contained in:
parent
3c6e8c1730
commit
20ca646e9a
@ -1,21 +1,45 @@
|
||||
import { cn } from "@/lib/utils"
|
||||
import { m } from "framer-motion"
|
||||
import { createRef, useEffect, useRef } from "react"
|
||||
import { createRef, useEffect, useRef, useState } from "react"
|
||||
import ServerFlag from "@/components/ServerFlag"
|
||||
|
||||
export default function GroupSwitch({
|
||||
tabs,
|
||||
currentTab,
|
||||
setCurrentTab,
|
||||
isCountrySwitch = false
|
||||
}: {
|
||||
tabs: string[]
|
||||
currentTab: string
|
||||
setCurrentTab: (tab: string) => void
|
||||
isCountrySwitch?: boolean
|
||||
}) {
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const [isDarkMode, setIsDarkMode] = useState(false)
|
||||
|
||||
const scrollRef = useRef<HTMLDivElement>(null)
|
||||
const tagRefs = useRef(tabs.map(() => createRef<HTMLDivElement>()))
|
||||
|
||||
useEffect(() => {
|
||||
// 检测暗黑模式
|
||||
setIsDarkMode(document.documentElement.classList.contains('dark'))
|
||||
|
||||
// 监听主题变化
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.attributeName === 'class') {
|
||||
setIsDarkMode(document.documentElement.classList.contains('dark'))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
observer.observe(document.documentElement, { attributes: true })
|
||||
|
||||
return () => {
|
||||
observer.disconnect()
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const container = scrollRef.current
|
||||
if (!container) return
|
||||
@ -36,11 +60,12 @@ export default function GroupSwitch({
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const savedGroup = sessionStorage.getItem("selectedGroup")
|
||||
if (savedGroup && tabs.includes(savedGroup)) {
|
||||
setCurrentTab(savedGroup)
|
||||
const storageKey = isCountrySwitch ? "selectedCountry" : "selectedGroup"
|
||||
const savedValue = sessionStorage.getItem(storageKey)
|
||||
if (savedValue && tabs.includes(savedValue)) {
|
||||
setCurrentTab(savedValue)
|
||||
}
|
||||
}, [tabs, setCurrentTab])
|
||||
}, [tabs, setCurrentTab, isCountrySwitch])
|
||||
|
||||
useEffect(() => {
|
||||
const currentTagRef = tagRefs.current[tabs.indexOf(currentTab)]
|
||||
@ -52,7 +77,7 @@ export default function GroupSwitch({
|
||||
inline: "center",
|
||||
})
|
||||
}
|
||||
}, [currentTab])
|
||||
}, [currentTab, tabs])
|
||||
|
||||
return (
|
||||
<div ref={scrollRef} className="scrollbar-hidden z-50 flex flex-col items-start overflow-x-scroll rounded-[50px]">
|
||||
@ -73,15 +98,22 @@ export default function GroupSwitch({
|
||||
>
|
||||
{currentTab === tab && (
|
||||
<m.div
|
||||
layoutId="tab-switch"
|
||||
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"
|
||||
layoutId={isCountrySwitch ? "country-switch" : "tab-switch"}
|
||||
style={{
|
||||
position: "absolute",
|
||||
inset: 0,
|
||||
zIndex: 10,
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
backgroundColor: isDarkMode ? "rgb(68 64 60)" : "white", // bg-stone-700 : white
|
||||
boxShadow: isDarkMode ? "0 1px 3px 0 rgba(255, 255, 255, 0.05)" : "0 1px 3px 0 rgba(0, 0, 0, 0.05)",
|
||||
originY: "0px",
|
||||
borderRadius: 46,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div className="relative z-20 flex items-center gap-1">
|
||||
{isCountrySwitch && tab !== "All" && <ServerFlag country_code={tab.toLowerCase()} className="text-[10px]" />}
|
||||
<p className="whitespace-nowrap">{tab}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -34,6 +34,7 @@ export default function Servers() {
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const [settingsOpen, setSettingsOpen] = useState<boolean>(false)
|
||||
const [currentGroup, setCurrentGroup] = useState<string>("All")
|
||||
const [currentCountry, setCurrentCountry] = useState<string>("All")
|
||||
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
@ -46,7 +47,15 @@ export default function Servers() {
|
||||
|
||||
const handleTagChange = (newGroup: string) => {
|
||||
setCurrentGroup(newGroup)
|
||||
setCurrentCountry("All") // 切换组时重置国家筛选
|
||||
sessionStorage.setItem("selectedGroup", newGroup)
|
||||
sessionStorage.setItem("selectedCountry", "All")
|
||||
sessionStorage.setItem("scrollPosition", String(containerRef.current?.scrollTop || 0))
|
||||
}
|
||||
|
||||
const handleCountryChange = (newCountry: string) => {
|
||||
setCurrentCountry(newCountry)
|
||||
sessionStorage.setItem("selectedCountry", newCountry)
|
||||
sessionStorage.setItem("scrollPosition", String(containerRef.current?.scrollTop || 0))
|
||||
}
|
||||
|
||||
@ -73,13 +82,22 @@ export default function Servers() {
|
||||
|
||||
useEffect(() => {
|
||||
const savedGroup = sessionStorage.getItem("selectedGroup") || "All"
|
||||
const savedCountry = sessionStorage.getItem("selectedCountry") || "All"
|
||||
setCurrentGroup(savedGroup)
|
||||
setCurrentCountry(savedCountry)
|
||||
|
||||
restoreScrollPosition()
|
||||
}, [])
|
||||
|
||||
const nezhaWsData = lastMessage ? (JSON.parse(lastMessage.data) as NezhaWebsocketResponse) : null
|
||||
|
||||
// 获取所有可用的国家代码
|
||||
const availableCountries = nezhaWsData?.servers
|
||||
? [...new Set(nezhaWsData.servers.map(server => server.country_code))]
|
||||
.filter(Boolean)
|
||||
.sort()
|
||||
: []
|
||||
|
||||
const groupTabs = [
|
||||
"All",
|
||||
...(groupData?.data
|
||||
@ -89,6 +107,11 @@ export default function Servers() {
|
||||
?.map((item: ServerGroup) => item.group.name) || []),
|
||||
]
|
||||
|
||||
const countryTabs = [
|
||||
"All",
|
||||
...availableCountries.map(code => code.toUpperCase())
|
||||
]
|
||||
|
||||
// 获取cycle_transfer_stats数据
|
||||
const { data: serviceData } = useQuery({
|
||||
queryKey: ["service"],
|
||||
@ -122,11 +145,20 @@ export default function Servers() {
|
||||
|
||||
let filteredServers =
|
||||
nezhaWsData?.servers?.filter((server) => {
|
||||
if (currentGroup === "All") return true
|
||||
const group = groupData?.data?.find(
|
||||
(g: ServerGroup) => g.group.name === currentGroup && Array.isArray(g.servers) && g.servers.includes(server.id),
|
||||
)
|
||||
return !!group
|
||||
// 组筛选
|
||||
if (currentGroup !== "All") {
|
||||
const group = groupData?.data?.find(
|
||||
(g: ServerGroup) => g.group.name === currentGroup && Array.isArray(g.servers) && g.servers.includes(server.id),
|
||||
)
|
||||
if (!group) return false
|
||||
}
|
||||
|
||||
// 国家筛选
|
||||
if (currentCountry !== "All" && server.country_code?.toUpperCase() !== currentCountry) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}) || []
|
||||
|
||||
const totalServers = filteredServers.length || 0
|
||||
@ -272,6 +304,7 @@ export default function Servers() {
|
||||
/>
|
||||
</button>
|
||||
<GroupSwitch tabs={groupTabs} currentTab={currentGroup} setCurrentTab={handleTagChange} />
|
||||
<GroupSwitch tabs={countryTabs} currentTab={currentCountry} setCurrentTab={handleCountryChange} isCountrySwitch={true} />
|
||||
</section>
|
||||
<Popover onOpenChange={setSettingsOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
|
Loading…
x
Reference in New Issue
Block a user