Merge pull request #6 from hamster1963/main

sync
This commit is contained in:
wood chen 2025-01-21 03:04:25 +08:00 committed by GitHub
commit e1b7acaa07
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 122 additions and 104 deletions

View File

@ -6,6 +6,7 @@ import { Route, BrowserRouter as Router, Routes } from "react-router-dom"
import ErrorBoundary from "./components/ErrorBoundary" import ErrorBoundary from "./components/ErrorBoundary"
import Footer from "./components/Footer" import Footer from "./components/Footer"
import Header, { RefreshToast } from "./components/Header" import Header, { RefreshToast } from "./components/Header"
import { useBackground } from "./hooks/use-background"
import { useTheme } from "./hooks/use-theme" import { useTheme } from "./hooks/use-theme"
import { InjectContext } from "./lib/inject" import { InjectContext } from "./lib/inject"
import { fetchSetting } from "./lib/nezha-api" import { fetchSetting } from "./lib/nezha-api"
@ -25,11 +26,7 @@ const App: React.FC = () => {
const { i18n } = useTranslation() const { i18n } = useTranslation()
const { setTheme } = useTheme() const { setTheme } = useTheme()
const [isCustomCodeInjected, setIsCustomCodeInjected] = useState(false) const [isCustomCodeInjected, setIsCustomCodeInjected] = useState(false)
const { backgroundImage: customBackgroundImage } = useBackground()
// 检测是否强制指定了主题颜色
const forceTheme =
// @ts-expect-error ForceTheme is a global variable
(window.ForceTheme as string) !== "" ? window.ForceTheme : undefined
useEffect(() => { useEffect(() => {
if (settingData?.data?.config?.custom_code) { if (settingData?.data?.config?.custom_code) {
@ -38,6 +35,11 @@ const App: React.FC = () => {
} }
}, [settingData?.data?.config?.custom_code]) }, [settingData?.data?.config?.custom_code])
// 检测是否强制指定了主题颜色
const forceTheme =
// @ts-expect-error ForceTheme is a global variable
(window.ForceTheme as string) !== "" ? window.ForceTheme : undefined
useEffect(() => { useEffect(() => {
if (forceTheme === "dark" || forceTheme === "light") { if (forceTheme === "dark" || forceTheme === "light") {
setTheme(forceTheme) setTheme(forceTheme)
@ -60,10 +62,6 @@ const App: React.FC = () => {
i18n.changeLanguage(settingData?.data?.config?.language) 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 = const customMobileBackgroundImage =
// @ts-expect-error CustomMobileBackgroundImage is a global variable // @ts-expect-error CustomMobileBackgroundImage is a global variable
(window.CustomMobileBackgroundImage as string) !== "" ? window.CustomMobileBackgroundImage : undefined (window.CustomMobileBackgroundImage as string) !== "" ? window.CustomMobileBackgroundImage : undefined

View File

@ -22,9 +22,7 @@ interface CycleTransferStatsClientProps {
export const CycleTransferStatsClient: React.FC<CycleTransferStatsClientProps> = ({ name, from, to, max, serverStats, className }) => { export const CycleTransferStatsClient: React.FC<CycleTransferStatsClientProps> = ({ name, from, to, max, serverStats, className }) => {
const { t } = useTranslation() const { t } = useTranslation()
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
return ( return (
<div <div
className={cn( className={cn(

View File

@ -13,9 +13,7 @@ export default function GlobalMap({ serverList, now }: { serverList: NezhaServer
const countryList: string[] = [] const countryList: string[] = []
const serverCounts: { [key: string]: number } = {} const serverCounts: { [key: string]: number } = {}
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
serverList.forEach((server) => { serverList.forEach((server) => {
if (server.country_code) { if (server.country_code) {

View File

@ -11,9 +11,7 @@ export default function GroupSwitch({
currentTab: string currentTab: string
setCurrentTab: (tab: string) => void setCurrentTab: (tab: string) => void
}) { }) {
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
const scrollRef = useRef<HTMLDivElement>(null) const scrollRef = useRef<HTMLDivElement>(null)
const tagRefs = useRef(tabs.map(() => createRef<HTMLDivElement>())) const tagRefs = useRef(tabs.map(() => createRef<HTMLDivElement>()))

View File

@ -1,11 +1,13 @@
import { ModeToggle } from "@/components/ThemeSwitcher" import { ModeToggle } from "@/components/ThemeSwitcher"
import { Separator } from "@/components/ui/separator" import { Separator } from "@/components/ui/separator"
import { Skeleton } from "@/components/ui/skeleton" import { Skeleton } from "@/components/ui/skeleton"
import { useBackground } from "@/hooks/use-background"
import { useWebSocketContext } from "@/hooks/use-websocket-context" import { useWebSocketContext } from "@/hooks/use-websocket-context"
import { fetchLoginUser, fetchSetting } from "@/lib/nezha-api" import { fetchLoginUser, fetchSetting } from "@/lib/nezha-api"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
import { useQuery } from "@tanstack/react-query" import { useQuery } from "@tanstack/react-query"
import { AnimatePresence, m } from "framer-motion" import { AnimatePresence, m } from "framer-motion"
import { ImageMinus } from "lucide-react"
import { DateTime } from "luxon" import { DateTime } from "luxon"
import { useEffect, useRef, useState } from "react" import { useEffect, useRef, useState } from "react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
@ -18,6 +20,7 @@ import { Button } from "./ui/button"
function Header() { function Header() {
const { t } = useTranslation() const { t } = useTranslation()
const navigate = useNavigate() const navigate = useNavigate()
const { backgroundImage, updateBackground } = useBackground()
const { data: settingData, isLoading } = useQuery({ const { data: settingData, isLoading } = useQuery({
queryKey: ["setting"], queryKey: ["setting"],
@ -38,10 +41,6 @@ function Header() {
// @ts-expect-error CustomDesc is a global variable // @ts-expect-error CustomDesc is a global variable
const customDesc = window.CustomDesc || t("nezha") const customDesc = window.CustomDesc || t("nezha")
const customBackgroundImage =
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
useEffect(() => { useEffect(() => {
const link = document.querySelector("link[rel*='icon']") || document.createElement("link") const link = document.querySelector("link[rel*='icon']") || document.createElement("link")
// @ts-expect-error set link.type // @ts-expect-error set link.type
@ -57,6 +56,22 @@ function Header() {
document.title = siteName || "CZL SVR" document.title = siteName || "CZL SVR"
}, [siteName]) }, [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 ( return (
<div className="mx-auto w-full max-w-5xl"> <div className="mx-auto w-full max-w-5xl">
<section className="flex items-center justify-between header-top"> <section className="flex items-center justify-between header-top">
@ -87,6 +102,18 @@ function Header() {
</div> </div>
<LanguageSwitcher /> <LanguageSwitcher />
<ModeToggle /> <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 <Button
variant="outline" variant="outline"
size="sm" 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() { function Overview() {
const { t } = useTranslation() const { t } = useTranslation()
const [mouted, setMounted] = useState(false) const [mouted, setMounted] = useState(false)
useEffect(() => { useEffect(() => {
setMounted(true) setMounted(true)
}, []) }, [])
const timeOption = DateTime.TIME_SIMPLE const timeOption = DateTime.TIME_WITH_SECONDS
timeOption.hour12 = true timeOption.hour12 = true
const [timeString, setTimeString] = useState(DateTime.now().setLocale("en-US").toLocaleString(timeOption)) const [timeString, setTimeString] = useState(DateTime.now().setLocale("en-US").toLocaleString(timeOption))
useInterval(() => { useEffect(() => {
setTimeString(DateTime.now().setLocale("en-US").toLocaleString(timeOption)) const updateTime = () => {
}, 1000) const now = DateTime.now().setLocale("en-US").toLocaleString(timeOption)
setTimeString(now)
requestAnimationFrame(updateTime)
}
requestAnimationFrame(updateTime)
}, [])
return ( return (
<section className={"mt-10 flex flex-col md:mt-16 header-timer"}> <section className={"mt-10 flex flex-col md:mt-16 header-timer"}>
<p className="text-base font-semibold">👋 {t("overview")}</p> <p className="text-base font-semibold">👋 {t("overview")}</p>

View File

@ -9,9 +9,7 @@ import { useTranslation } from "react-i18next"
export function LanguageSwitcher() { export function LanguageSwitcher() {
const { t, i18n } = useTranslation() const { t, i18n } = useTranslation()
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
const locale = i18n.languages[0] const locale = i18n.languages[0]

View File

@ -93,9 +93,7 @@ export const NetworkChartClient = React.memo(function NetworkChart({
const defaultChart = "All" const defaultChart = "All"
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
const [activeChart, setActiveChart] = React.useState(defaultChart) const [activeChart, setActiveChart] = React.useState(defaultChart)
const [isPeakEnabled, setIsPeakEnabled] = React.useState(false) const [isPeakEnabled, setIsPeakEnabled] = React.useState(false)

View File

@ -27,9 +27,7 @@ export default function ServerCard({ now, serverInfo }: { now: number; serverInf
const showFlag = true const showFlag = true
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error ShowNetTransfer is a global variable // @ts-expect-error ShowNetTransfer is a global variable
const showNetTransfer = window.ShowNetTransfer as boolean const showNetTransfer = window.ShowNetTransfer as boolean

View File

@ -27,9 +27,7 @@ export default function ServerCardInline({ now, serverInfo }: { now: number; ser
const showFlag = true const showFlag = true
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
const parsedData = parsePublicNote(public_note) const parsedData = parsePublicNote(public_note)

View File

@ -128,9 +128,7 @@ function GpuChart({
const hasInitialized = useRef(false) const hasInitialized = useRef(false)
const [historyLoaded, setHistoryLoaded] = useState(false) const [historyLoaded, setHistoryLoaded] = useState(false)
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// 初始化历史数据 // 初始化历史数据
useEffect(() => { useEffect(() => {
@ -237,9 +235,7 @@ function CpuChart({ now, data, messageHistory }: { now: number; data: NezhaServe
const { cpu } = formatNezhaInfo(now, data) const { cpu } = formatNezhaInfo(now, data)
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// 初始化历史数据 // 初始化历史数据
useEffect(() => { useEffect(() => {
@ -343,9 +339,7 @@ function ProcessChart({ now, data, messageHistory }: { now: number; data: NezhaS
const hasInitialized = useRef(false) const hasInitialized = useRef(false)
const [historyLoaded, setHistoryLoaded] = useState(false) const [historyLoaded, setHistoryLoaded] = useState(false)
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
const { process } = formatNezhaInfo(now, data) const { process } = formatNezhaInfo(now, data)
@ -457,9 +451,7 @@ function MemChart({ now, data, messageHistory }: { now: number; data: NezhaServe
const hasInitialized = useRef(false) const hasInitialized = useRef(false)
const [historyLoaded, setHistoryLoaded] = useState(false) const [historyLoaded, setHistoryLoaded] = useState(false)
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
const { mem, swap } = formatNezhaInfo(now, data) const { mem, swap } = formatNezhaInfo(now, data)
@ -602,9 +594,7 @@ function DiskChart({ now, data, messageHistory }: { now: number; data: NezhaServ
const hasInitialized = useRef(false) const hasInitialized = useRef(false)
const [historyLoaded, setHistoryLoaded] = useState(false) const [historyLoaded, setHistoryLoaded] = useState(false)
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
const { disk } = formatNezhaInfo(now, data) const { disk } = formatNezhaInfo(now, data)
@ -715,9 +705,7 @@ function NetworkChart({ now, data, messageHistory }: { now: number; data: NezhaS
const hasInitialized = useRef(false) const hasInitialized = useRef(false)
const [historyLoaded, setHistoryLoaded] = useState(false) const [historyLoaded, setHistoryLoaded] = useState(false)
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
const { up, down } = formatNezhaInfo(now, data) const { up, down } = formatNezhaInfo(now, data)
@ -858,9 +846,7 @@ function ConnectChart({ now, data, messageHistory }: { now: number; data: NezhaS
const hasInitialized = useRef(false) const hasInitialized = useRef(false)
const [historyLoaded, setHistoryLoaded] = useState(false) const [historyLoaded, setHistoryLoaded] = useState(false)
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
const { tcp, udp } = formatNezhaInfo(now, data) const { tcp, udp } = formatNezhaInfo(now, data)

View File

@ -75,9 +75,7 @@ export default function ServerDetailOverview({ server_id }: { server_id: string
last_active_time_string, last_active_time_string,
} = formatNezhaInfo(nezhaWsData.now, server) } = formatNezhaInfo(nezhaWsData.now, server)
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
countries.registerLocale(enLocale) countries.registerLocale(enLocale)

View File

@ -25,9 +25,7 @@ export default function ServerOverview({ online, offline, total, up, down, upSpe
// @ts-expect-error CustomIllustration is a global variable // @ts-expect-error CustomIllustration is a global variable
const customIllustration = window.CustomIllustration || "/animated-man.webp" const customIllustration = window.CustomIllustration || "/animated-man.webp"
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
return ( return (
<> <>

View File

@ -17,9 +17,7 @@ interface ServiceTrackerProps {
export const ServiceTrackerClient: React.FC<ServiceTrackerProps> = ({ days, className, title, uptime = 100, avgDelay = 0 }) => { export const ServiceTrackerClient: React.FC<ServiceTrackerProps> = ({ days, className, title, uptime = 100, avgDelay = 0 }) => {
const { t } = useTranslation() const { t } = useTranslation()
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
return ( return (
<div <div
className={cn( className={cn(

View File

@ -4,9 +4,7 @@ import { useTranslation } from "react-i18next"
export default function TabSwitch({ tabs, currentTab, setCurrentTab }: { tabs: string[]; currentTab: string; setCurrentTab: (tab: string) => void }) { export default function TabSwitch({ tabs, currentTab, setCurrentTab }: { tabs: string[]; currentTab: string; setCurrentTab: (tab: string) => void }) {
const { t } = useTranslation() const { t } = useTranslation()
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
return ( return (
<div className="z-50 flex flex-col items-start rounded-[50px] server-info-tab"> <div className="z-50 flex flex-col items-start rounded-[50px] server-info-tab">
<div <div

View File

@ -12,9 +12,7 @@ export function ModeToggle() {
const { t } = useTranslation() const { t } = useTranslation()
const { setTheme, theme } = useTheme() const { setTheme, theme } = useTheme()
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
const handleSelect = (e: Event, newTheme: Theme) => { const handleSelect = (e: Event, newTheme: Theme) => {
e.preventDefault() e.preventDefault()

View File

@ -106,28 +106,15 @@ export const WebSocketProvider: React.FC<WebSocketProviderProps> = ({ url, child
useEffect(() => { useEffect(() => {
connect() connect()
// 添加页面可见性变化监听
const handleVisibilityChange = () => {
if (document.hidden) {
// 页面隐藏时断开连接
cleanup()
} else {
// 页面可见时重新连接
connect()
}
}
// 添加页面卸载事件监听 // 添加页面卸载事件监听
const handleBeforeUnload = () => { const handleBeforeUnload = () => {
cleanup() cleanup()
} }
document.addEventListener("visibilitychange", handleVisibilityChange)
window.addEventListener("beforeunload", handleBeforeUnload) window.addEventListener("beforeunload", handleBeforeUnload)
return () => { return () => {
cleanup() cleanup()
document.removeEventListener("visibilitychange", handleVisibilityChange)
window.removeEventListener("beforeunload", handleBeforeUnload) window.removeEventListener("beforeunload", handleBeforeUnload)
} }
}, [url]) }, [url])

View File

@ -0,0 +1,55 @@
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>(undefined)
useEffect(() => {
// 监听背景变化
const handleBackgroundChange = () => {
setBackgroundImage(window.CustomBackgroundImage || undefined)
}
// 初始化检查
const checkInitialBackground = () => {
if (window.CustomBackgroundImage) {
setBackgroundImage(window.CustomBackgroundImage)
} else {
const savedImage = sessionStorage.getItem("savedBackgroundImage")
if (savedImage) {
window.CustomBackgroundImage = savedImage
setBackgroundImage(savedImage)
}
}
}
// 设置一个轮询来检查初始背景
const intervalId = setInterval(() => {
if (window.CustomBackgroundImage || sessionStorage.getItem("savedBackgroundImage")) {
checkInitialBackground()
clearInterval(intervalId)
}
}, 100)
window.addEventListener(BACKGROUND_CHANGE_EVENT, handleBackgroundChange)
return () => {
window.removeEventListener(BACKGROUND_CHANGE_EVENT, handleBackgroundChange)
clearInterval(intervalId)
}
}, [])
const updateBackground = (newBackground: string | undefined) => {
window.CustomBackgroundImage = newBackground || ""
window.dispatchEvent(new Event(BACKGROUND_CHANGE_EVENT))
}
return { backgroundImage, updateBackground }
}

View File

@ -36,9 +36,7 @@ export default function Servers() {
const [settingsOpen, setSettingsOpen] = useState<boolean>(false) const [settingsOpen, setSettingsOpen] = useState<boolean>(false)
const [currentGroup, setCurrentGroup] = useState<string>("All") const [currentGroup, setCurrentGroup] = useState<string>("All")
const customBackgroundImage = const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
// @ts-expect-error CustomBackgroundImage is a global variable
(window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined
const restoreScrollPosition = () => { const restoreScrollPosition = () => {
const savedPosition = sessionStorage.getItem("scrollPosition") const savedPosition = sessionStorage.getItem("scrollPosition")