import React from 'react' import { Head, usePage } from '@inertiajs/react' import CollectionCard from '../../components/profile/collections/CollectionCard' const SEARCH_SELECT_OPTIONS = { type: [ { value: 'personal', label: 'Personal' }, { value: 'community', label: 'Community' }, { value: 'editorial', label: 'Editorial' }, ], mode: [ { value: 'manual', label: 'Manual' }, { value: 'smart', label: 'Smart' }, ], lifecycle_state: [ { value: 'published', label: 'Published' }, { value: 'featured', label: 'Featured' }, { value: 'archived', label: 'Archived' }, ], health_state: [ { value: 'healthy', label: 'Healthy' }, { value: 'needs_metadata', label: 'Needs metadata' }, { value: 'stale', label: 'Stale' }, { value: 'low_content', label: 'Low content' }, { value: 'broken_items', label: 'Broken items' }, { value: 'weak_cover', label: 'Weak cover' }, { value: 'low_engagement', label: 'Low engagement' }, { value: 'duplicate_risk', label: 'Duplicate risk' }, { value: 'merge_candidate', label: 'Merge candidate' }, ], sort: [ { value: 'trending', label: 'Trending' }, { value: 'recent', label: 'Recent' }, { value: 'quality', label: 'Quality' }, { value: 'evergreen', label: 'Evergreen' }, ], } function humanizeToken(value) { return String(value || '') .replaceAll('_', ' ') .replaceAll('-', ' ') .replace(/\b\w/g, (match) => match.toUpperCase()) } function searchChipLabel(key, value) { if (!value) return null const option = SEARCH_SELECT_OPTIONS[key]?.find((item) => item.value === value) const displayValue = option?.label || humanizeToken(value) return key === 'q' ? `Query: ${value}` : key === 'campaign_key' ? `Campaign: ${displayValue}` : key === 'program_key' ? `Program: ${displayValue}` : key === 'quality_tier' ? `Quality Tier: ${displayValue}` : key === 'sort' ? `Sort: ${displayValue}` : `${humanizeToken(key)}: ${displayValue}` } function buildSearchHref(filters, omitKey = null) { const params = new URLSearchParams() Object.entries(filters || {}).forEach(([key, value]) => { if (key === omitKey) return if (value === null || value === undefined || value === '') return params.set(key, value) }) const query = params.toString() return query ? `/collections/search?${query}` : '/collections/search' } function activeSearchChips(filters) { return Object.entries(filters || {}) .filter(([, value]) => value !== null && value !== undefined && value !== '') .map(([key, value]) => ({ key, label: searchChipLabel(key, value), href: buildSearchHref(filters, key), })) .filter((chip) => chip.label) } function primarySaveContext({ search, campaign, program, title, eyebrow }) { if (search) { return { context: 'collection_search', meta: { query: search?.filters?.q || null, surface_label: 'collection search', }, } } if (campaign) { return { context: 'campaign_landing', meta: { campaign_key: campaign.key, campaign_label: campaign.label, surface_label: campaign.label || 'campaign landing', }, } } if (program) { return { context: 'program_landing', meta: { program_key: program.key, program_label: program.label, surface_label: program.label || 'program landing', }, } } if (eyebrow === 'Trending') return { context: 'trending_landing', meta: { surface_label: 'trending collections' } } if (eyebrow === 'Editorial') return { context: 'editorial_landing', meta: { surface_label: 'editorial collections' } } if (eyebrow === 'Community') return { context: 'community_landing', meta: { surface_label: 'community collections' } } if (eyebrow === 'Seasonal') return { context: 'seasonal_landing', meta: { surface_label: 'seasonal collections' } } if (title === 'Recommended collections' || title === 'Collections worth exploring') return { context: 'recommended_landing', meta: { surface_label: 'recommended collections' } } return { context: 'featured_landing', meta: { surface_label: 'featured collections' }, } } function HeroStat({ icon, label, value }) { return (
{label}
{value}
) } function EmptyState() { return (

No featured collections yet

Featured placement is reserved for public collections with a strong visual point of view. Check back once creators start pinning their best showcases.

Back to home
) } function SearchPanel({ search }) { if (!search) return null const filters = search.filters || {} const options = search.options || {} const chips = activeSearchChips(filters) return (

Filters

Search collections

{search?.meta?.total ?? 0} results
Reset
{chips.length ? (
{chips.map((chip) => ( {chip.label} ))}
) : null} {(search?.links?.prev || search?.links?.next) ? (
{search.links.prev ? Previous : null} {search.links.next ? Next : null}
) : null}
) } export default function CollectionFeaturedIndex() { const { props } = usePage() const seo = props.seo || {} const eyebrow = props.eyebrow || 'Discovery' const title = props.title || 'Featured collections' const description = props.description || 'A rotating set of standout galleries from across Skinbase Nova. Some are meticulously hand-sequenced. Others are smart collections that stay fresh as the creator publishes new work.' const collections = Array.isArray(props.collections) ? props.collections : [] const communityCollections = Array.isArray(props.communityCollections) ? props.communityCollections : [] const editorialCollections = Array.isArray(props.editorialCollections) ? props.editorialCollections : [] const recentCollections = Array.isArray(props.recentCollections) ? props.recentCollections : [] const trendingCollections = Array.isArray(props.trendingCollections) ? props.trendingCollections : [] const seasonalCollections = Array.isArray(props.seasonalCollections) ? props.seasonalCollections : [] const campaign = props.campaign || null const program = props.program || null const search = props.search || null const smartCount = collections.filter((collection) => collection?.mode === 'smart').length const totalArtworks = collections.reduce((sum, collection) => sum + (collection?.artworks_count || 0), 0) const mainSave = primarySaveContext({ search, campaign, program, title, eyebrow }) const listSchema = seo?.canonical ? { '@context': 'https://schema.org', '@type': 'CollectionPage', name: title, description, url: seo.canonical, mainEntity: { '@type': 'ItemList', numberOfItems: collections.length, itemListElement: collections.slice(0, 18).map((collection, index) => ({ '@type': 'ListItem', position: index + 1, url: collection.url, name: collection.title, })), }, } : null return ( <> {seo?.title || `${title} — Skinbase Nova`} {seo?.canonical ? : null} {seo?.canonical ? : null} {listSchema ? : null}