Files
TREK/client/src/components/Collections/CollectionList.tsx
T
Maurice 4e478722c3 feat(collections): redesign the page on the dashboard glass language (#1081)
Rebuilds the /collections page from the functional placeholder into the
dashboard's glass visual language (light + dark):

- A colour-washed hero per list: eyebrow + member avatars, big title, and
  stat chips (All / Idea / Want / Visited) that double as the status filter.
- A sticky glass list rail (owned + shared + invites) with a mobile drawer.
- Gradient/photo cover place cards modelled on the trip cards, via a new
  rectangular PlaceCover (photoService-backed, gradient fallback) + a shared
  gradients util. List and map views restyled to match.
- Status pill rendered as a role=button span so it survives the .trek-dash
  button reset and can nest inside the card; the share member-count badge is
  now owner-only.
- New hero eyebrow strings across all locales.
2026-07-01 18:02:44 +02:00

62 lines
2.5 KiB
TypeScript

import React from 'react'
import { Check, MapPin } from 'lucide-react'
import type { CollectionPlace, CollectionStatus } from '@trek/shared'
import type { TranslationFn } from '../../types'
import PlaceAvatar from '../shared/PlaceAvatar'
import StatusBadge from './StatusBadge'
interface CollectionListProps {
places: CollectionPlace[]
selectedPlaceId: number | null
selectMode: boolean
selectedIds: number[]
onOpenPlace: (id: number) => void
onStatusChange: (placeId: number, status: CollectionStatus) => void
onToggleSelect: (id: number) => void
t: TranslationFn
}
/**
* List view — one glass row per saved place with a photo avatar, name +
* category/address, and a one-tap status cycle on the badge. Click the row to
* open the place (or toggle it in select mode).
*/
export default function CollectionList({
places, selectedPlaceId, selectMode, selectedIds, onOpenPlace, onStatusChange, onToggleSelect, t,
}: CollectionListProps): React.ReactElement {
return (
<div className="col-listview">
{places.map(place => {
const selected = selectedIds.includes(place.id)
const active = selectedPlaceId === place.id
return (
<div
key={place.id}
role="button"
tabIndex={0}
onClick={() => (selectMode ? onToggleSelect(place.id) : onOpenPlace(place.id))}
onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); if (selectMode) onToggleSelect(place.id); else onOpenPlace(place.id) } }}
className={`col-lrow${active || selected ? ' sel' : ''}`}
>
{selectMode ? (
<span className={`col-lcheck${selected ? ' on' : ''}`}>{selected && <Check size={14} strokeWidth={3} />}</span>
) : (
<PlaceAvatar place={place} size={40} category={place.category ? { color: place.category.color ?? undefined, icon: place.category.icon ?? undefined } : null} />
)}
<div className="li">
<div className="t">{place.name}</div>
{(place.category?.name || place.address) && (
<div className="s">
{!place.category?.name && <MapPin size={11} />}
<span>{place.category?.name || place.address}</span>
</div>
)}
</div>
<StatusBadge status={place.status} onChange={selectMode ? undefined : next => onStatusChange(place.id, next)} t={t} />
</div>
)
})}
</div>
)
}