Smoke-sweep fixes: exact saves, local dates, safer remove, readable markers
- Garden and plant dialogs keep centimeters as the source of truth (LengthField in lib/units.ts): a no-change Save no longer rewrites 900 cm as 899.922 or a 45 cm spacing as 44.958, bumping versions and writing bogus history entries on the way. - The UI stamps every date with the browser's local day (lib/dates.ts). Journal notes already did; plop placement, fill and removal now do too, so a 9 pm placement isn't "planted tomorrow". The fill endpoint gained an optional plantedAt; API and agent callers still default to UTC today. - Removing an object that holds plants asks first and says how many go with it. An empty one still goes straight away (one Undo restores it). - The expanded plant card's action row wraps instead of clipping "Delete". - Monogram lettering switches to a dark ink on pale marker colors (garlic, cabbage, marigold) instead of near-white on near-white. - Copy-as-plan proposes the next free year and warns when the typed name already exists, so two gardens can't both read as "the 2027 plan". - Plan cards show the base name with a "2027 plan" tag, so the year — the point of the name — survives truncation. - A rejected model spec now says which model and why: a wrapped ErrInvalidInput's reason reaches the client as the 400's message, and the Settings field shows it inline instead of toasting "invalid input". Also defuses a clock bomb in TestRemainingReturnsWhenAPlantingIsRemoved, which only passed while the real date was before 2026-08-01. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
type PointerEvent as ReactPointerEvent,
|
||||
} from 'react'
|
||||
import { clampScale, type Point } from '@/lib/geometry'
|
||||
import { monogramInk } from '@/lib/monogram'
|
||||
import { useCreateObject, useCreatePlanting, useUpdateObject, useUpdatePlanting } from '@/lib/objects'
|
||||
import type { Plant } from '@/lib/plants'
|
||||
import type { EditorPlanting } from '@/lib/plantings'
|
||||
@@ -34,6 +35,10 @@ import {
|
||||
import { useEditorStore, type Viewport } from './store'
|
||||
import type { EditorGarden, EditorObject } from './types'
|
||||
|
||||
// A plop whose plant is missing from the catalog (a shared garden's private
|
||||
// plant) still needs a color to be drawn in.
|
||||
const FALLBACK_PLANT_COLOR = '#97a97c'
|
||||
|
||||
const WHEEL_SENSITIVITY = 0.0016
|
||||
const ANIM_MS = 520
|
||||
const REFIT_THRESHOLD_PX = 60
|
||||
@@ -589,7 +594,7 @@ export const Canvas = forwardRef<
|
||||
>
|
||||
{/* A fingertip-sized hit area so a tiny plop at low zoom is still grabbable. */}
|
||||
<circle r={Math.max(p.radiusCm, 10 / s)} fill="transparent" />
|
||||
<circle r={p.radiusCm} fill={plant?.color ?? '#97a97c'} stroke={isSel ? 'var(--color-paper)' : 'none'} strokeWidth={2.5 / s} />
|
||||
<circle r={p.radiusCm} fill={plant?.color ?? FALLBACK_PLANT_COLOR} stroke={isSel ? 'var(--color-paper)' : 'none'} strokeWidth={2.5 / s} />
|
||||
</g>
|
||||
)
|
||||
})}
|
||||
@@ -642,7 +647,7 @@ export const Canvas = forwardRef<
|
||||
textAnchor="middle"
|
||||
dominantBaseline="central"
|
||||
fontSize={r * 1.05}
|
||||
fill="var(--color-paper)"
|
||||
fill={monogramInk(plant?.color ?? FALLBACK_PLANT_COLOR)}
|
||||
style={{ fontFamily: 'var(--font-heading)' }}
|
||||
>
|
||||
{letters.get(p.plantId) ?? '?'}
|
||||
|
||||
Reference in New Issue
Block a user