/** * Explore page — browse shaders by tag, trending, new, top. */ import { useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { Link, useSearchParams } from 'react-router-dom'; import api from '@/lib/api'; import ShaderCanvas from '@/components/ShaderCanvas'; type SortOption = 'trending' | 'new' | 'top'; export default function Explore() { const [searchParams, setSearchParams] = useSearchParams(); const [sort, setSort] = useState((searchParams.get('sort') as SortOption) || 'trending'); const [query, setQuery] = useState(searchParams.get('q') || ''); const tagFilter = searchParams.get('tags')?.split(',').filter(Boolean) || []; const { data: shaders = [], isLoading } = useQuery({ queryKey: ['explore', sort, query, tagFilter.join(',')], queryFn: async () => { const params: any = { sort, limit: 30 }; if (query) params.q = query; if (tagFilter.length) params.tags = tagFilter; const { data } = await api.get('/shaders', { params }); return data; }, }); const handleSearch = (e: React.FormEvent) => { e.preventDefault(); setSearchParams({ sort, q: query }); }; return (

Explore

{/* Sort tabs */}
{(['trending', 'new', 'top'] as SortOption[]).map((s) => ( ))}
{/* Search */}
setQuery(e.target.value)} className="input max-w-md" placeholder="Search shaders..." />
{/* Tag filter pills */} {tagFilter.length > 0 && (
{tagFilter.map((tag) => ( #{tag} ))}
)} {/* Grid */} {isLoading ? (
{Array.from({ length: 8 }).map((_, i) => (
))}
) : shaders.length > 0 ? (
{shaders.map((shader: any) => (

{shader.title}

{shader.shader_type} · {shader.view_count} views
))}
) : (
No shaders found. Try a different search or sort.
)}
); }