mirror of
https://github.com/woodchen-ink/nezha-dash-v1.git
synced 2025-07-18 09:31:55 +08:00
feat: disable custom background button
This commit is contained in:
parent
b1c5b6e0a8
commit
38be1e9a10
@ -6,6 +6,7 @@ import { Route, BrowserRouter as Router, Routes } from "react-router-dom"
|
||||
import ErrorBoundary from "./components/ErrorBoundary"
|
||||
import Footer from "./components/Footer"
|
||||
import Header, { RefreshToast } from "./components/Header"
|
||||
import { useBackground } from "./hooks/use-background"
|
||||
import { useTheme } from "./hooks/use-theme"
|
||||
import { InjectContext } from "./lib/inject"
|
||||
import { fetchSetting } from "./lib/nezha-api"
|
||||
@ -25,6 +26,7 @@ const App: React.FC = () => {
|
||||
const { i18n } = useTranslation()
|
||||
const { setTheme } = useTheme()
|
||||
const [isCustomCodeInjected, setIsCustomCodeInjected] = useState(false)
|
||||
const { backgroundImage: customBackgroundImage } = useBackground()
|
||||
|
||||
// 检测是否强制指定了主题颜色
|
||||
const forceTheme =
|
||||
@ -60,10 +62,6 @@ const App: React.FC = () => {
|
||||
i18n.changeLanguage(settingData?.data?.config?.language)
|
||||
}
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
const customMobileBackgroundImage =
|
||||
// @ts-expect-error CustomMobileBackgroundImage is a global variable
|
||||
(window.CustomMobileBackgroundImage as string) !== "" ? window.CustomMobileBackgroundImage : undefined
|
||||
|
@ -22,9 +22,7 @@ interface CycleTransferStatsClientProps {
|
||||
|
||||
export const CycleTransferStatsClient: React.FC<CycleTransferStatsClientProps> = ({ name, from, to, max, serverStats, className }) => {
|
||||
const { t } = useTranslation()
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
|
@ -13,9 +13,7 @@ export default function GlobalMap({ serverList, now }: { serverList: NezhaServer
|
||||
const countryList: string[] = []
|
||||
const serverCounts: { [key: string]: number } = {}
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
serverList.forEach((server) => {
|
||||
if (server.country_code) {
|
||||
|
@ -11,9 +11,7 @@ export default function GroupSwitch({
|
||||
currentTab: string
|
||||
setCurrentTab: (tab: string) => void
|
||||
}) {
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
const scrollRef = useRef<HTMLDivElement>(null)
|
||||
const tagRefs = useRef(tabs.map(() => createRef<HTMLDivElement>()))
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { ModeToggle } from "@/components/ThemeSwitcher"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import { Skeleton } from "@/components/ui/skeleton"
|
||||
import { useBackground } from "@/hooks/use-background"
|
||||
import { useWebSocketContext } from "@/hooks/use-websocket-context"
|
||||
import { fetchLoginUser, fetchSetting } from "@/lib/nezha-api"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
import { AnimatePresence, m } from "framer-motion"
|
||||
import { ImageMinus } from "lucide-react"
|
||||
import { DateTime } from "luxon"
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
@ -18,6 +20,7 @@ import { Button } from "./ui/button"
|
||||
function Header() {
|
||||
const { t } = useTranslation()
|
||||
const navigate = useNavigate()
|
||||
const { backgroundImage, updateBackground } = useBackground()
|
||||
|
||||
const { data: settingData, isLoading } = useQuery({
|
||||
queryKey: ["setting"],
|
||||
@ -38,10 +41,6 @@ function Header() {
|
||||
// @ts-expect-error CustomDesc is a global variable
|
||||
const customDesc = window.CustomDesc || t("nezha")
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
useEffect(() => {
|
||||
const link = document.querySelector("link[rel*='icon']") || document.createElement("link")
|
||||
// @ts-expect-error set link.type
|
||||
@ -57,6 +56,22 @@ function Header() {
|
||||
document.title = siteName || "哪吒监控 Nezha Monitoring"
|
||||
}, [siteName])
|
||||
|
||||
const handleBackgroundToggle = () => {
|
||||
if (window.CustomBackgroundImage) {
|
||||
// Store the current background image before removing it
|
||||
sessionStorage.setItem("savedBackgroundImage", window.CustomBackgroundImage)
|
||||
updateBackground(undefined)
|
||||
} else {
|
||||
// Restore the saved background image
|
||||
const savedImage = sessionStorage.getItem("savedBackgroundImage")
|
||||
if (savedImage) {
|
||||
updateBackground(savedImage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const customBackgroundImage = backgroundImage
|
||||
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-5xl">
|
||||
<section className="flex items-center justify-between header-top">
|
||||
@ -87,6 +102,18 @@ function Header() {
|
||||
</div>
|
||||
<LanguageSwitcher />
|
||||
<ModeToggle />
|
||||
{(customBackgroundImage || sessionStorage.getItem("savedBackgroundImage")) && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleBackgroundToggle}
|
||||
className={cn("rounded-full px-[9px] bg-white dark:bg-black", {
|
||||
"bg-white/70 dark:bg-black/70": customBackgroundImage,
|
||||
})}
|
||||
>
|
||||
<ImageMinus className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@ -234,32 +261,23 @@ function DashboardLink() {
|
||||
)
|
||||
}
|
||||
|
||||
// https://github.com/streamich/react-use/blob/master/src/useInterval.ts
|
||||
const useInterval = (callback: () => void, delay: number | null) => {
|
||||
const savedCallback = useRef<() => void>(() => {})
|
||||
useEffect(() => {
|
||||
savedCallback.current = callback
|
||||
})
|
||||
useEffect(() => {
|
||||
if (delay !== null) {
|
||||
const interval = setInterval(() => savedCallback.current(), delay || 0)
|
||||
return () => clearInterval(interval)
|
||||
}
|
||||
return undefined
|
||||
}, [delay])
|
||||
}
|
||||
function Overview() {
|
||||
const { t } = useTranslation()
|
||||
const [mouted, setMounted] = useState(false)
|
||||
useEffect(() => {
|
||||
setMounted(true)
|
||||
}, [])
|
||||
const timeOption = DateTime.TIME_SIMPLE
|
||||
const timeOption = DateTime.TIME_WITH_SECONDS
|
||||
timeOption.hour12 = true
|
||||
const [timeString, setTimeString] = useState(DateTime.now().setLocale("en-US").toLocaleString(timeOption))
|
||||
useInterval(() => {
|
||||
setTimeString(DateTime.now().setLocale("en-US").toLocaleString(timeOption))
|
||||
}, 1000)
|
||||
useEffect(() => {
|
||||
const updateTime = () => {
|
||||
const now = DateTime.now().setLocale("en-US").toLocaleString(timeOption)
|
||||
setTimeString(now)
|
||||
requestAnimationFrame(updateTime)
|
||||
}
|
||||
requestAnimationFrame(updateTime)
|
||||
}, [])
|
||||
return (
|
||||
<section className={"mt-10 flex flex-col md:mt-16 header-timer"}>
|
||||
<p className="text-base font-semibold">👋 {t("overview")}</p>
|
||||
|
@ -9,9 +9,7 @@ import { useTranslation } from "react-i18next"
|
||||
export function LanguageSwitcher() {
|
||||
const { t, i18n } = useTranslation()
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
const locale = i18n.languages[0]
|
||||
|
||||
|
@ -93,9 +93,7 @@ export const NetworkChartClient = React.memo(function NetworkChart({
|
||||
|
||||
const defaultChart = "All"
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
const [activeChart, setActiveChart] = React.useState(defaultChart)
|
||||
const [isPeakEnabled, setIsPeakEnabled] = React.useState(false)
|
||||
|
@ -27,9 +27,7 @@ export default function ServerCard({ now, serverInfo }: { now: number; serverInf
|
||||
|
||||
const showFlag = true
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
// @ts-expect-error ShowNetTransfer is a global variable
|
||||
const showNetTransfer = window.ShowNetTransfer as boolean
|
||||
|
@ -27,9 +27,7 @@ export default function ServerCardInline({ now, serverInfo }: { now: number; ser
|
||||
|
||||
const showFlag = true
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
const parsedData = parsePublicNote(public_note)
|
||||
|
||||
|
@ -128,9 +128,7 @@ function GpuChart({
|
||||
const hasInitialized = useRef(false)
|
||||
const [historyLoaded, setHistoryLoaded] = useState(false)
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
// 初始化历史数据
|
||||
useEffect(() => {
|
||||
@ -237,9 +235,7 @@ function CpuChart({ now, data, messageHistory }: { now: number; data: NezhaServe
|
||||
|
||||
const { cpu } = formatNezhaInfo(now, data)
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
// 初始化历史数据
|
||||
useEffect(() => {
|
||||
@ -343,9 +339,7 @@ function ProcessChart({ now, data, messageHistory }: { now: number; data: NezhaS
|
||||
const hasInitialized = useRef(false)
|
||||
const [historyLoaded, setHistoryLoaded] = useState(false)
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
const { process } = formatNezhaInfo(now, data)
|
||||
|
||||
@ -457,9 +451,7 @@ function MemChart({ now, data, messageHistory }: { now: number; data: NezhaServe
|
||||
const hasInitialized = useRef(false)
|
||||
const [historyLoaded, setHistoryLoaded] = useState(false)
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
const { mem, swap } = formatNezhaInfo(now, data)
|
||||
|
||||
@ -602,9 +594,7 @@ function DiskChart({ now, data, messageHistory }: { now: number; data: NezhaServ
|
||||
const hasInitialized = useRef(false)
|
||||
const [historyLoaded, setHistoryLoaded] = useState(false)
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
const { disk } = formatNezhaInfo(now, data)
|
||||
|
||||
@ -715,9 +705,7 @@ function NetworkChart({ now, data, messageHistory }: { now: number; data: NezhaS
|
||||
const hasInitialized = useRef(false)
|
||||
const [historyLoaded, setHistoryLoaded] = useState(false)
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
const { up, down } = formatNezhaInfo(now, data)
|
||||
|
||||
@ -858,9 +846,7 @@ function ConnectChart({ now, data, messageHistory }: { now: number; data: NezhaS
|
||||
const hasInitialized = useRef(false)
|
||||
const [historyLoaded, setHistoryLoaded] = useState(false)
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
const { tcp, udp } = formatNezhaInfo(now, data)
|
||||
|
||||
|
@ -75,9 +75,7 @@ export default function ServerDetailOverview({ server_id }: { server_id: string
|
||||
last_active_time_string,
|
||||
} = formatNezhaInfo(nezhaWsData.now, server)
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
countries.registerLocale(enLocale)
|
||||
|
||||
|
@ -25,9 +25,7 @@ export default function ServerOverview({ online, offline, total, up, down, upSpe
|
||||
// @ts-expect-error CustomIllustration is a global variable
|
||||
const customIllustration = window.CustomIllustration || "/animated-man.webp"
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -17,9 +17,7 @@ interface ServiceTrackerProps {
|
||||
|
||||
export const ServiceTrackerClient: React.FC<ServiceTrackerProps> = ({ days, className, title, uptime = 100, avgDelay = 0 }) => {
|
||||
const { t } = useTranslation()
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
|
@ -4,9 +4,7 @@ import { useTranslation } from "react-i18next"
|
||||
|
||||
export default function TabSwitch({ tabs, currentTab, setCurrentTab }: { tabs: string[]; currentTab: string; setCurrentTab: (tab: string) => void }) {
|
||||
const { t } = useTranslation()
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
return (
|
||||
<div className="z-50 flex flex-col items-start rounded-[50px] server-info-tab">
|
||||
<div
|
||||
|
@ -12,9 +12,7 @@ export function ModeToggle() {
|
||||
const { t } = useTranslation()
|
||||
const { setTheme, theme } = useTheme()
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
const handleSelect = (e: Event, newTheme: Theme) => {
|
||||
e.preventDefault()
|
||||
|
@ -106,28 +106,15 @@ export const WebSocketProvider: React.FC<WebSocketProviderProps> = ({ url, child
|
||||
useEffect(() => {
|
||||
connect()
|
||||
|
||||
// 添加页面可见性变化监听
|
||||
const handleVisibilityChange = () => {
|
||||
if (document.hidden) {
|
||||
// 页面隐藏时断开连接
|
||||
cleanup()
|
||||
} else {
|
||||
// 页面可见时重新连接
|
||||
connect()
|
||||
}
|
||||
}
|
||||
|
||||
// 添加页面卸载事件监听
|
||||
const handleBeforeUnload = () => {
|
||||
cleanup()
|
||||
}
|
||||
|
||||
document.addEventListener("visibilitychange", handleVisibilityChange)
|
||||
window.addEventListener("beforeunload", handleBeforeUnload)
|
||||
|
||||
return () => {
|
||||
cleanup()
|
||||
document.removeEventListener("visibilitychange", handleVisibilityChange)
|
||||
window.removeEventListener("beforeunload", handleBeforeUnload)
|
||||
}
|
||||
}, [url])
|
||||
|
37
src/hooks/use-background.ts
Normal file
37
src/hooks/use-background.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
CustomBackgroundImage: string
|
||||
}
|
||||
}
|
||||
|
||||
const BACKGROUND_CHANGE_EVENT = "backgroundChange"
|
||||
|
||||
export function useBackground() {
|
||||
const [backgroundImage, setBackgroundImage] = useState<string | undefined>(() => {
|
||||
// 首先检查 sessionStorage 中是否有保存的背景图
|
||||
const savedImage = sessionStorage.getItem("savedBackgroundImage")
|
||||
// 如果 window.CustomBackgroundImage 为空但有保存的背景图,则恢复它
|
||||
if (!window.CustomBackgroundImage && savedImage) {
|
||||
window.CustomBackgroundImage = savedImage
|
||||
}
|
||||
return window.CustomBackgroundImage || undefined
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const handleBackgroundChange = () => {
|
||||
setBackgroundImage(window.CustomBackgroundImage || undefined)
|
||||
}
|
||||
|
||||
window.addEventListener(BACKGROUND_CHANGE_EVENT, handleBackgroundChange)
|
||||
return () => window.removeEventListener(BACKGROUND_CHANGE_EVENT, handleBackgroundChange)
|
||||
}, [])
|
||||
|
||||
const updateBackground = (newBackground: string | undefined) => {
|
||||
window.CustomBackgroundImage = newBackground || ""
|
||||
window.dispatchEvent(new Event(BACKGROUND_CHANGE_EVENT))
|
||||
}
|
||||
|
||||
return { backgroundImage, updateBackground }
|
||||
}
|
@ -36,9 +36,7 @@ export default function Servers() {
|
||||
const [settingsOpen, setSettingsOpen] = useState<boolean>(false)
|
||||
const [currentGroup, setCurrentGroup] = useState<string>("All")
|
||||
|
||||
const customBackgroundImage =
|
||||
// @ts-expect-error CustomBackgroundImage is a global variable
|
||||
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
|
||||
|
||||
const restoreScrollPosition = () => {
|
||||
const savedPosition = sessionStorage.getItem("scrollPosition")
|
||||
|
Loading…
x
Reference in New Issue
Block a user