'use client'
import { Button } from '@thedaviddias/design-system/button'
import { ErrorBoundaryCustom } from '@thedaviddias/design-system/error-boundary'
import { ToggleGroup, ToggleGroupItem } from '@thedaviddias/design-system/toggle-group'
import { Clock, Grid, List, SortAsc } from 'lucide-react'
import { useEffect, useState } from 'react'
import { EmptyState } from '@/components/empty-state'
import { LLMGrid } from '@/components/llm/llm-grid'
import { useWebsiteFilters } from '@/hooks/use-website-filters'
import { categories } from '@/lib/categories'
import type { WebsiteMetadata } from '@/lib/content-loader'
import { getRoute } from '@/lib/routes'
interface ClientProjectsListProps {
initialWebsites: WebsiteMetadata[]
}
/**
* Type guard to validate WebsiteMetadata objects
*
* @param website - Object to validate
* @returns True if object is a valid WebsiteMetadata
*/
function isValidWebsite(website: any): website is WebsiteMetadata {
const isValid =
website &&
typeof website.slug === 'string' &&
typeof website.name === 'string' &&
typeof website.description === 'string' &&
typeof website.website === 'string' &&
typeof website.llmsUrl === 'string' &&
typeof website.category === 'string' &&
typeof website.publishedAt === 'string'
return isValid
}
/**
* Client-side component for displaying and filtering a list of websites
*
* @param props - Component props
* @param props.initialWebsites - Initial list of websites to display
*
* @returns React component with filtering, sorting, and view mode controls
*
* @example
* ```tsx
*
* ```
*/
export function ClientProjectsList({ initialWebsites }: ClientProjectsListProps) {
const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid')
const [websites, setWebsites] = useState(initialWebsites)
const { categoryFilter, sortBy, setCategoryFilter, setSortBy } = useWebsiteFilters()
// Get current category name for heading
const currentCategoryName =
categoryFilter === 'all'
? 'All LLMs Websites'
: `${categories.find(cat => cat.slug === categoryFilter)?.name || 'Unknown'} Websites`
// Update filtered and sorted websites when filters or initial websites change
useEffect(() => {
let filteredWebsites = [...initialWebsites]
// Filter by category if selected
if (categoryFilter !== 'all') {
filteredWebsites = filteredWebsites.filter(website => website.category === categoryFilter)
}
// Sort by selected criteria
if (sortBy === 'latest') {
filteredWebsites.sort(
(a, b) => new Date(b.publishedAt).getTime() - new Date(a.publishedAt).getTime()
)
} else if (sortBy === 'name') {
filteredWebsites.sort((a, b) => a.name.localeCompare(b.name))
}
// Validate websites after all filtering and sorting
const validWebsites = filteredWebsites.filter(isValidWebsite)
setWebsites(validWebsites)
}, [initialWebsites, categoryFilter, sortBy])
return (
{currentCategoryName}
{categories.map(category => (
))}
Sort by:
value && setSortBy(value)}
className="bg-background border rounded-md"
>
Latest
Name
{websites.length === 0 ? (
) : viewMode === 'grid' ? (
Websites list
) : (
Websites list
)}
)
}