From 73685823987f1b7b5b1a747a8516aa5f45f54be7 Mon Sep 17 00:00:00 2001 From: kuekhaoyang Date: Sun, 25 Jan 2026 15:02:46 +0800 Subject: [PATCH] . --- app/page.tsx | 25 ++++++++-------- lib/hooks/useHomePage.ts | 8 +---- lib/hooks/useSourceBadges.ts | 55 +++------------------------------- lib/hooks/useTypeBadges.ts | 57 ++++-------------------------------- package-lock.json | 4 +-- package.json | 2 +- 6 files changed, 25 insertions(+), 126 deletions(-) diff --git a/app/page.tsx b/app/page.tsx index 42cadc8..a330121 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -29,20 +29,19 @@ function HomePage() { {/* Search Form - Separate from navbar */} -
-
- -
+
{/* Main Content */} diff --git a/lib/hooks/useHomePage.ts b/lib/hooks/useHomePage.ts index 7e64ffa..7a639a3 100644 --- a/lib/hooks/useHomePage.ts +++ b/lib/hooks/useHomePage.ts @@ -18,13 +18,7 @@ export function useHomePage() { const [currentSortBy, setCurrentSortBy] = useState('default'); const onUrlUpdate = useCallback((q: string) => { - const params = new URLSearchParams(window.location.search); - if (q) { - params.set('q', q); - } else { - params.delete('q'); - } - router.replace(`/?${params.toString()}`, { scroll: false }); + router.replace(`/?q=${encodeURIComponent(q)}`, { scroll: false }); }, [router]); // Search stream hook diff --git a/lib/hooks/useSourceBadges.ts b/lib/hooks/useSourceBadges.ts index 3e4cd86..cc83d48 100644 --- a/lib/hooks/useSourceBadges.ts +++ b/lib/hooks/useSourceBadges.ts @@ -1,5 +1,6 @@ -import { useState, useEffect, useMemo, useCallback, useRef } from 'react'; -import { useSearchParams, useRouter, usePathname } from 'next/navigation'; +'use client'; + +import { useState, useEffect, useMemo, useCallback } from 'react'; import type { SourceBadge } from '@/lib/types'; /** @@ -9,59 +10,12 @@ import type { SourceBadge } from '@/lib/types'; * - Tracks available video sources * - Supports filtering by selected sources * - Auto-cleanup when sources no longer exist - * - Persists state in URL */ export function useSourceBadges( videos: T[], availableSources: SourceBadge[] ) { - const router = useRouter(); - const pathname = usePathname(); - const searchParams = useSearchParams(); - const isInitialMount = useRef(true); - - // Initialize from URL - const [selectedSources, setSelectedSources] = useState>(() => { - const sourcesParam = searchParams.get('sources'); - if (sourcesParam) { - return new Set(sourcesParam.split(',').filter(Boolean)); - } - return new Set(); - }); - - // Sync state to URL - useEffect(() => { - if (isInitialMount.current) { - isInitialMount.current = false; - return; - } - - const currentParams = new URLSearchParams(searchParams.toString()); - const sourcesParam = Array.from(selectedSources).join(','); - - if (sourcesParam) { - currentParams.set('sources', sourcesParam); - } else { - currentParams.delete('sources'); - } - - const newUrl = `${pathname}?${currentParams.toString()}`; - router.replace(newUrl, { scroll: false }); - }, [selectedSources, pathname, router, searchParams]); - - // Handle URL changes (e.g., when clicking browser back/forward) - useEffect(() => { - const sourcesParam = searchParams.get('sources'); - const urlSources = new Set(sourcesParam ? sourcesParam.split(',').filter(Boolean) : []); - - const currentSourcesArr = Array.from(selectedSources); - const urlSourcesArr = Array.from(urlSources); - - if (currentSourcesArr.length !== urlSourcesArr.length || - !currentSourcesArr.every(s => urlSources.has(s))) { - setSelectedSources(urlSources); - } - }, [searchParams]); + const [selectedSources, setSelectedSources] = useState>(new Set()); // Filter videos by selected sources const filteredVideos = useMemo(() => { @@ -89,7 +43,6 @@ export function useSourceBadges { - if (availableSources.length === 0) return; const availableSourceIds = new Set(availableSources.map(s => s.id)); setSelectedSources(prev => { diff --git a/lib/hooks/useTypeBadges.ts b/lib/hooks/useTypeBadges.ts index ed36d5c..7b14dcf 100644 --- a/lib/hooks/useTypeBadges.ts +++ b/lib/hooks/useTypeBadges.ts @@ -1,5 +1,6 @@ -import { useState, useEffect, useMemo, useCallback, useRef } from 'react'; -import { useSearchParams, useRouter, usePathname } from 'next/navigation'; +'use client'; + +import { useState, useEffect, useMemo, useCallback } from 'react'; import type { TypeBadge } from '@/lib/types'; /** @@ -11,56 +12,9 @@ import type { TypeBadge } from '@/lib/types'; * - Updates dynamically as videos are added/removed * - Removes badges when count reaches 0 * - Supports filtering by selected types - * - Persists state in URL */ export function useTypeBadges(videos: T[]) { - const router = useRouter(); - const pathname = usePathname(); - const searchParams = useSearchParams(); - const isInitialMount = useRef(true); - - // Initialize from URL - const [selectedTypes, setSelectedTypes] = useState>(() => { - const typesParam = searchParams.get('types'); - if (typesParam) { - return new Set(typesParam.split(',').filter(Boolean)); - } - return new Set(); - }); - - // Sync state to URL - useEffect(() => { - if (isInitialMount.current) { - isInitialMount.current = false; - return; - } - - const currentParams = new URLSearchParams(searchParams.toString()); - const typesParam = Array.from(selectedTypes).join(','); - - if (typesParam) { - currentParams.set('types', typesParam); - } else { - currentParams.delete('types'); - } - - const newUrl = `${pathname}?${currentParams.toString()}`; - router.replace(newUrl, { scroll: false }); - }, [selectedTypes, pathname, router, searchParams]); - - // Handle URL changes (e.g., when clicking browser back/forward) - useEffect(() => { - const typesParam = searchParams.get('types'); - const urlTypes = new Set(typesParam ? typesParam.split(',').filter(Boolean) : []); - - const currentTypesArr = Array.from(selectedTypes); - const urlTypesArr = Array.from(urlTypes); - - if (currentTypesArr.length !== urlTypesArr.length || - !currentTypesArr.every(t => urlTypes.has(t))) { - setSelectedTypes(urlTypes); - } - }, [searchParams]); + const [selectedTypes, setSelectedTypes] = useState>(new Set()); // Collect and count type badges from videos const typeBadges = useMemo(() => { @@ -92,7 +46,7 @@ export function useTypeBadges(videos: T[]) { // Toggle type selection - useCallback to prevent re-creation const toggleType = useCallback((type: string) => { - // Update selected types immediately + // Update selected types immediately (high priority) setSelectedTypes(prev => { const newSet = new Set(prev); if (newSet.has(type)) { @@ -106,7 +60,6 @@ export function useTypeBadges(videos: T[]) { // Auto-cleanup: remove selected types that no longer exist in badges useEffect(() => { - if (typeBadges.length === 0) return; const availableTypes = new Set(typeBadges.map(b => b.type)); setSelectedTypes(prev => { diff --git a/package-lock.json b/package-lock.json index b77d712..6dfe967 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "kvideo", - "version": "4.0.5", + "version": "4.0.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "kvideo", - "version": "4.0.5", + "version": "4.0.4", "dependencies": { "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", diff --git a/package.json b/package.json index fd6cfa8..9bc3693 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kvideo", - "version": "4.0.5", + "version": "4.0.4", "private": true, "scripts": { "dev": "next dev",