FEAT: Implement deceased/givenaway enclosure visibility rules, preserve external clan name, and hide receiver fields for deceased gerbils
This commit is contained in:
81
gerbil-manager-web/src/pages/FarbkatalogPage.tsx
Normal file
81
gerbil-manager-web/src/pages/FarbkatalogPage.tsx
Normal file
@@ -0,0 +1,81 @@
|
||||
import { useState } from 'react'
|
||||
import { de } from '../strings/de'
|
||||
import { CATALOG, farbschlagImageUrl } from '../genetics'
|
||||
import './farbkatalog.css'
|
||||
|
||||
export default function FarbkatalogPage() {
|
||||
const [search, setSearch] = useState('')
|
||||
|
||||
// Filter color catalog by query
|
||||
const filtered = CATALOG.filter((variety) => {
|
||||
const q = search.toLowerCase()
|
||||
return (
|
||||
variety.name.toLowerCase().includes(q) ||
|
||||
(variety.english && variety.english.toLowerCase().includes(q)) ||
|
||||
variety.canonicalGenotype.toLowerCase().includes(q)
|
||||
);
|
||||
})
|
||||
|
||||
return (
|
||||
<section className="page farbkatalog-page">
|
||||
<header className="page-head">
|
||||
<div>
|
||||
<h2>{de.pages.farbkatalog.title}</h2>
|
||||
<p className="muted">
|
||||
{de.pages.farbkatalog.subtitle.replace('{count}', String(CATALOG.length))}
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="farbkatalog-search-bar">
|
||||
<input
|
||||
type="search"
|
||||
className="input"
|
||||
placeholder={de.pages.farbkatalog.searchPlaceholder}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="farbkatalog-grid">
|
||||
{filtered.map((variety) => {
|
||||
const imgUrl = farbschlagImageUrl(variety.image)
|
||||
return (
|
||||
<div key={variety.name} className="farbkatalog-card">
|
||||
<div className="farbkatalog-card-media">
|
||||
{imgUrl ? (
|
||||
<img
|
||||
src={imgUrl}
|
||||
alt={variety.name}
|
||||
className="farbkatalog-card-img"
|
||||
loading="lazy"
|
||||
/>
|
||||
) : (
|
||||
<div className="farbkatalog-card-media-placeholder">
|
||||
<span>{variety.name.substring(0, 2).toUpperCase()}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="farbkatalog-card-body">
|
||||
<h4 className="farbkatalog-card-title">{variety.name}</h4>
|
||||
{variety.english && (
|
||||
<span className="farbkatalog-card-subtitle">{variety.english}</span>
|
||||
)}
|
||||
<div className="farbkatalog-card-genotype">
|
||||
<code>{variety.canonicalGenotype}</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
|
||||
{filtered.length === 0 && (
|
||||
<div className="farbkatalog-empty">
|
||||
<span className="farbkatalog-empty-icon">🔍</span>
|
||||
<p>{de.pages.farbkatalog.empty}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user