diff --git a/app/[locale]/(main)/ClientComponents/ServerDetailClient.tsx b/app/[locale]/(main)/ClientComponents/ServerDetailClient.tsx index 7843953..74227c2 100644 --- a/app/[locale]/(main)/ClientComponents/ServerDetailClient.tsx +++ b/app/[locale]/(main)/ClientComponents/ServerDetailClient.tsx @@ -10,6 +10,7 @@ import getEnv from "@/lib/env-entry"; import { cn, formatBytes, nezhaFetcher } from "@/lib/utils"; import { useLocale, useTranslations } from "next-intl"; import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; import useSWR from "swr"; export default function ServerDetailClient({ @@ -20,6 +21,32 @@ export default function ServerDetailClient({ const t = useTranslations("ServerDetailClient"); const router = useRouter(); const locale = useLocale(); + + const [hasHistory, setHasHistory] = useState(false); + + useEffect(() => { + window.scrollTo(0, 0); + }, []); + + useEffect(() => { + const previousPath = sessionStorage.getItem("lastPath"); + const currentPath = window.location.pathname; + + if (previousPath && previousPath !== currentPath) { + setHasHistory(true); + } else { + sessionStorage.setItem("lastPath", currentPath); + } + }, []); + + const linkClick = () => { + if (hasHistory) { + router.back(); + } else { + router.push(`/${locale}/`); + } + }; + const { data, error } = useSWR( `/api/detail?server_id=${server_id}`, nezhaFetcher, @@ -46,9 +73,7 @@ export default function ServerDetailClient({ return (
{ - router.push(`/${locale}/`); - }} + onClick={linkClick} className="flex flex-none cursor-pointer font-semibold leading-none items-center break-all tracking-tight gap-0.5 text-xl" > diff --git a/app/[locale]/(main)/ClientComponents/ServerListClient.tsx b/app/[locale]/(main)/ClientComponents/ServerListClient.tsx index 2f163ba..85425cc 100644 --- a/app/[locale]/(main)/ClientComponents/ServerListClient.tsx +++ b/app/[locale]/(main)/ClientComponents/ServerListClient.tsx @@ -6,17 +6,53 @@ import Switch from "@/components/Switch"; import getEnv from "@/lib/env-entry"; import { nezhaFetcher } from "@/lib/utils"; import { useTranslations } from "next-intl"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import useSWR from "swr"; export default function ServerListClient() { const t = useTranslations("ServerListClient"); + const containerRef = useRef(null); - const [tag, setTag] = useState(t("defaultTag")); + const defaultTag = t("defaultTag"); + const [tag, setTag] = useState( + sessionStorage.getItem("selectedTag") || defaultTag, + ); + + const handleTagChange = (newTag: string) => { + setTag(newTag); + sessionStorage.setItem("selectedTag", newTag); + sessionStorage.setItem( + "scrollPosition", + String(containerRef.current?.scrollTop || 0), + ); + }; + + const restoreScrollPosition = () => { + const savedPosition = sessionStorage.getItem("scrollPosition"); + if (savedPosition && containerRef.current) { + containerRef.current.scrollTop = Number(savedPosition); + } + }; + + useEffect(() => { + restoreScrollPosition(); + }, [tag]); + + useEffect(() => { + const handleRouteChange = () => { + restoreScrollPosition(); + }; + + window.addEventListener("popstate", handleRouteChange); + return () => { + window.removeEventListener("popstate", handleRouteChange); + }; + }, []); const { data, error } = useSWR("/api/server", nezhaFetcher, { refreshInterval: Number(getEnv("NEXT_PUBLIC_NezhaFetchInterval")) || 2000, }); + if (error) return (
@@ -24,32 +60,38 @@ export default function ServerListClient() {

{t("error_message")}

); + if (!data?.result) return null; const { result } = data; - const sortedServers = result.sort((a, b) => { const displayIndexDiff = (b.display_index || 0) - (a.display_index || 0); if (displayIndexDiff !== 0) return displayIndexDiff; return a.id - b.id; }); - const allTag = sortedServers.map((server) => server.tag).filter((tag) => tag); + const allTag = sortedServers.map((server) => server.tag).filter(Boolean); const uniqueTags = [...new Set(allTag)]; - - uniqueTags.unshift(t("defaultTag")); + uniqueTags.unshift(defaultTag); const filteredServers = - tag === t("defaultTag") + tag === defaultTag ? sortedServers : sortedServers.filter((server) => server.tag === tag); return ( <> {getEnv("NEXT_PUBLIC_ShowTag") === "true" && uniqueTags.length > 1 && ( - + )} -
+
{filteredServers.map((serverInfo) => ( ))} diff --git a/components/Switch.tsx b/components/Switch.tsx index 43db879..8db919a 100644 --- a/components/Switch.tsx +++ b/components/Switch.tsx @@ -2,32 +2,35 @@ import { cn } from "@/lib/utils"; import { motion } from "framer-motion"; -import React, { useEffect, useRef } from "react"; +import React, { useEffect, useRef, useState } from "react"; export default function Switch({ allTag, nowTag, - setTag, + onTagChange, }: { allTag: string[]; nowTag: string; - setTag: (tag: string) => void; + onTagChange: (tag: string) => void; }) { const scrollRef = useRef(null); + useEffect(() => { + const savedTag = sessionStorage.getItem("selectedTag"); + if (savedTag && allTag.includes(savedTag)) { + onTagChange(savedTag); + } + }, [allTag]); + useEffect(() => { const container = scrollRef.current; if (!container) return; const isOverflowing = container.scrollWidth > container.clientWidth; - - if (!isOverflowing) { - return; - } + if (!isOverflowing) return; const onWheel = (e: WheelEvent) => { e.preventDefault(); - e.stopPropagation(); container.scrollLeft += e.deltaY; }; @@ -47,7 +50,7 @@ export default function Switch({ {allTag.map((tag) => (
setTag(tag)} + onClick={() => onTagChange(tag)} className={cn( "relative cursor-pointer rounded-3xl px-2.5 py-[8px] text-[13px] font-[600] transition-all duration-500", nowTag === tag diff --git a/package.json b/package.json index 50dfe09..76c090f 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev -p 3020 --turbo", + "dev": "next dev -p 3020", "start": "node .next/standalone/server.js", "lint": "next lint", "build": "next build && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/",