The drag replicas cast the shadow the pickup lift already promised

DragReplicaStyle spells the pathfinder's constant ambient shadow once
(black 16%, radius 2.5, y 1.5) and all three replica faces — card,
lane, trashed lane — wear it via one modifier; the ghost fans compose
from the same faces so every copy inherits it, dimmed by its own
opacity. 03 § Motion's "pickup lift (scale + shadow)" supplies the
scale from the system session but no shadow on the preview image — the
replica is the only place it can come from. BoardMetrics.replicaPadding
was already written to keep exactly this shadow from clipping and was
simply unused until now.

Drag-perf card 24397310.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
This commit is contained in:
2026-08-03 13:33:52 -04:00
parent 1ffb64913b
commit 43e6ad229e
4 changed files with 23 additions and 0 deletions
+20
View File
@@ -78,3 +78,23 @@ struct DragCountBadge: View {
}
}
}
/// The pickup lift's shadow figures 03-board-ui.md § Motion's "the pickup lift (scale + shadow as
/// it detaches from the card)": the system drag session supplies the scale and the tracking, but
/// paints no shadow onto its preview image, so the shadow can only come from the replica view
/// itself. Values are the pathfinder's own constant ambient shadow, reused verbatim rather than
/// re-derived (`~/Documents/indie/Kanban` CardView.swift:623) its drags read subtly raised, and
/// that read is the point.
enum DragReplicaStyle {
static let shadowColor = Color.black.opacity(0.16)
static let shadowRadius: CGFloat = 2.5
static let shadowY: CGFloat = 1.5
}
extension View {
/// The pickup lift's shadow (`DragReplicaStyle`), for a drag replica's face shared by the
/// card, lane, and trashed-lane replicas so the figures are spelled once.
func dragReplicaShadow() -> some View {
shadow(color: DragReplicaStyle.shadowColor, radius: DragReplicaStyle.shadowRadius, y: DragReplicaStyle.shadowY)
}
}