Build image / build-and-push (push) Successful in 17s
Co-authored-by: Steve Dudenhoeffer <[email protected]>
70 lines
2.4 KiB
TypeScript
70 lines
2.4 KiB
TypeScript
import { cn } from '@/lib/cn'
|
|
|
|
/**
|
|
* Which season the canvas is showing.
|
|
*
|
|
* "Now" is the live, editable garden — what is in the ground today. A year is a
|
|
* read-only view of everything whose time in the ground overlapped that calendar
|
|
* year, plops since removed included. They are genuinely different questions:
|
|
* "what's growing" versus "what did I grow", and only the first one is editable.
|
|
*
|
|
* Only years the garden holds data for are offered. A free numeric field invites
|
|
* a typo, and a typo'd year produces a confidently empty garden that reads as
|
|
* data loss rather than a mistake.
|
|
*/
|
|
export function SeasonPicker({
|
|
years,
|
|
value,
|
|
onChange,
|
|
}: {
|
|
years: number[]
|
|
value: number | null
|
|
onChange: (year: number | null) => void
|
|
}) {
|
|
if (years.length === 0) return null
|
|
return (
|
|
<label className="flex items-center gap-1.5 text-xs text-muted">
|
|
<span>Season</span>
|
|
<select
|
|
value={value ?? ''}
|
|
onChange={(e) => onChange(e.target.value === '' ? null : Number(e.target.value))}
|
|
className={cn(
|
|
'rounded-md border border-border bg-surface px-1.5 py-1 text-xs text-fg outline-none',
|
|
'focus-visible:ring-2 focus-visible:ring-accent/40',
|
|
)}
|
|
>
|
|
<option value="">Now</option>
|
|
{years.map((y) => (
|
|
<option key={y} value={y}>
|
|
{y}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
)
|
|
}
|
|
|
|
/**
|
|
* The banner that stops you thinking you're looking at now. Editing the past by
|
|
* accident is the failure mode this whole feature introduces, so the state is
|
|
* stated rather than implied by a dropdown you set a while ago — with the way
|
|
* back to the live garden right next to it.
|
|
*/
|
|
export function SeasonBanner({ year, onExit }: { year: number; onExit: () => void }) {
|
|
return (
|
|
<div className="flex flex-wrap items-center gap-2 rounded-lg border border-amber-500/40 bg-amber-500/10 px-2 py-1.5 text-sm">
|
|
<span className="font-medium text-amber-800 dark:text-amber-300">Viewing {year}</span>
|
|
<span className="text-xs text-amber-800/80 dark:text-amber-300/80">
|
|
read-only, including plantings since removed
|
|
</span>
|
|
<button
|
|
type="button"
|
|
onClick={onExit}
|
|
className="ml-auto rounded px-1.5 py-0.5 text-xs font-medium text-amber-900 underline outline-none hover:no-underline focus-visible:ring-2 focus-visible:ring-accent/40 dark:text-amber-200"
|
|
>
|
|
Back to now
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|