feat: настроить визуальный стиль лестниц (#683)

Issue: #683
User-Visible: yes
This commit is contained in:
Sergey Matyunin
2026-09-27 23:04:28 +03:00
parent cf01489fa9
commit 5b5b808184
31 changed files with 554 additions and 93 deletions
+8 -1
View File
@@ -311,7 +311,14 @@ ordinary saves. Saves strip the legacy root `space.segments`.
Separate Plan entity, not decor (`STAIRS.md`). Eager `StairViewRuntime`:
symbols, tooltip, guarded navigation; lazy `StairEditorRuntime`: drawing,
transforms, magnets, properties (a plan never loads the editor graph). The root
card keeps lifecycle, shared history/persistence and stage pointer terminals.
card keeps lifecycle, shared history/persistence and stage pointer terminals;
pure model, tread/trapezoid geometry and style resolution stay in `stairs.ts`.
The optional `color`/`opacity` and `fill_color`/`fill_opacity` fields are a
snapshot owned by the stair. Missing legacy fields resolve at render/dialog
time from the current decor default but are not written until the user saves
that stair. Screen renderers consume the colour fields; PDF deliberately uses
the same geometry with its existing monochrome ink palette.
## Editor chrome and contextual controls
+10
View File
@@ -2,6 +2,16 @@
## Unreleased
- Stairs now have two independent line and fill colours with opacity controls. A
new stair snapshots the current main decor colour and starts with a fully
transparent fill. Straight flights show an internal 100%/80% trapezoid:
**Up/Down** flips the taper while the ascent arrow keeps its canonical
direction, so rotating the whole stair is the way to point the arrow. Both
straight and spiral stairs now divide their full run into equal intervals
whose physical size is as close as possible to 30 cm, without a short last
tread or sector. Valid floor links also consistently use the hand cursor
([#683](https://github.com/Matysh/houseplan-card/issues/683)).
## v1.78.0-beta.6 — 2026-09-27
- Manual virtual-light state and the latest vacuum-trail points are now flushed
+10
View File
@@ -8,6 +8,16 @@
## Не выпущено
- У лестниц появились два собственных цвета: для линий и для заливки, а также
отдельная прозрачность каждого. Новая лестница копирует текущий основной цвет декора и
создаётся с полностью прозрачной заливкой. В прямом марше рисуется внутренняя
трапеция шириной 100%/80%: варианты **«Вверх/Вниз»** разворачивают только её,
а стрелка сохраняет каноническое направление — чтобы направить стрелку,
нужно повернуть всю лестницу. Прямые и винтовые лестницы теперь делятся на
равные интервалы, максимально близкие к 30 см, без короткой последней ступени
или сектора. Корректная ссылка на этаж также всегда показывает курсор-руку
([#683](https://github.com/Matysh/houseplan-card/issues/683)).
## v1.78.0-beta.6 — 2026-09-27
- Состояние виртуальных источников света и последние точки маршрута пылесоса
+6 -1
View File
@@ -141,7 +141,12 @@ discriminated collection. `kind: "straight"` stores positive `length` and
`width` plus `direction: "forward" | "backward"`; `kind: "spiral"` stores a
positive `radius` plus `direction: "clockwise" | "counterclockwise"`. Both
variants carry stable `id`, continuous normalized centre `x/y`, scalar
`angle`, and an optional nullable `target_space_id`.
`angle`, and an optional nullable `target_space_id`. Optional `color`,
`opacity`, `fill_color` and `fill_opacity` store the stair-owned screen style.
Their absence is the legacy form: renderers/dialogs resolve the current decor
default without rewriting the config, and the first successful Properties save
materialises all four fields. Changing the global decor default later does not
recolour a stair that already owns the fields.
Stair transforms follow furniture's continuous contract. Config writes apply
only the nine-decimal scalar cleanup to position, size and angle; they do not
+29 -10
View File
@@ -39,7 +39,14 @@ Double click opens properties. A straight stair stores positive length and
width; a spiral stair stores a positive radius. The fields accept 30–10000 cm
(inches when Home Assistant is imperial); a field left untouched keeps the
stored number bit for bit, and saving without changes writes nothing. The
dialog also selects the rise direction, rotation and an optional target space.
dialog also selects the rise direction, rotation, two colour/opacity pairs
(all linework; full-footprint fill) and an optional target space. A new stair
snapshots the current main decor colour for its outline, treads, trapezoid and
arrow; its full rectangle/circle fill starts completely transparent. The
colours then belong to that stair and do not follow later default-decor changes.
For a straight stair the choices are **Up** and **Down**. They flip only the
100%/80% trapezoid; the arrow always points along the canonical local axis, so
turn the whole stair to point the arrow elsewhere.
A target cannot be the current space. A missing, self or deleted target leaves
the stair visible and editable but shows a repair warning and makes View
activation a no-op.
@@ -70,10 +77,14 @@ straddling a thin wall never snaps to the face hidden inside the masonry. Any
straight/circular pair of stairs can snap footprint-to-footprint. The other
stair is never modified or linked by the magnet.
Straight tread lines are perpendicular to the rise axis and start at the lower
edge every 30 cm. A remainder shorter than 30 cm stays at the upper edge.
Spiral stairs make one full turn; radial treads use the same 30 cm physical step
measured on the travel line at two thirds of the radius. Their direction is
The straight symbol contains a centred full-length trapezoid. Its wide base is
100% of the stair width and its narrow base is 80%, with symmetric 10% side
insets. **Up** widens toward the arrow tip; **Down** narrows toward it. Treads
end on the trapezoid sides and never enter the side strips. The full physical
length is divided into an integer number of equal intervals whose size is
closest to 30 cm (a tie chooses the larger count), so there is no remainder.
Spiral stairs similarly divide the complete travel-line circumference at two
thirds of the radius into equal sectors closest to 30 cm. Their direction is
clockwise or counter-clockwise when viewed from above. The arrow always means
physical ascent, not the direction of navigation between named tabs.
@@ -97,17 +108,25 @@ Each space may contain `stairs: []`, bounded to 250 valid records:
"length": 0.24,
"width": 0.10,
"direction": "forward",
"target_space_id": "floor-2"
"target_space_id": "floor-2",
"color": "#607d8b",
"opacity": 1,
"fill_color": "#607d8b",
"fill_opacity": 0
}
```
`kind:"spiral"` replaces `length`/`width` with `radius` and uses direction
`clockwise` or `counterclockwise`. Coordinates and sizes use the normalized
plan coordinate system; physical labels are derived through `cell_cm`.
`target_space_id` is nullable. Unknown sibling fields survive validation and
round trips for forward compatibility. Full backup/import/export, one-space
transfer, plan-only transfer, diagnostics and support packages preserve the
same records. When a complete backup removes a target space its incoming stair
`target_space_id` is nullable. The four visual fields are optional for backward
compatibility. A legacy record resolves missing fields from the current main
decor colour without being rewritten; its first successful Properties save
materialises the complete visual quartet. Unknown sibling fields survive
validation and round trips for forward compatibility. Full backup/import/export,
one-space transfer, plan-only transfer, diagnostics and support packages
preserve the same records. When a complete backup removes a target space its
incoming stair
links are cleared; a one-space transfer cannot invent an external target.
## Implementation boundary
+5 -1
View File
@@ -717,7 +717,11 @@ the stair and snaps the dragged side flush to a parallel wall; dragging the
body snaps the nearest side to a wall (turning the stair by at most 5°) or
flush to another stair; `Shift` snaps rotation to 45°. **Optimize plans**
preserves the exact continuous transform. Double click opens size (30 cm to
100 m, saved exactly as shown), direction, angle and target-floor properties.
100 m, saved exactly as shown), direction, angle, line/fill colour and opacity,
and target-floor properties. A new stair copies the main decor colour and has
no visible fill. Straight **Up/Down** changes the 100%/80% taper but not the
arrow direction; rotate the whole stair to turn the arrow. Treads and spiral
sectors divide the full run evenly at the closest possible step to 30 cm.
In View, hovering a stair with a valid target shows "Go to floor …", and a
clean activation switches to that target and restores its saved view; gesture
tails, broken links and fixed-floor cards do nothing. The target floor is
+6 -1
View File
@@ -803,7 +803,12 @@ Undo оптимизации.
больше чем на 5°) или вплотную к другой лестнице; `Shift` привязывает поворот
к 45°. **Оптимизировать планы** сохраняет этот continuous-transform без
привязки к сетке. Двойной клик открывает размеры (от 30 см до 100 м, хранятся
ровно такими, как показаны), направление подъёма, угол и целевой этаж. В
ровно такими, как показаны), направление подъёма, угол, цвет/прозрачность линий
и заливки и целевой этаж. Новая лестница копирует основной цвет декора и не
имеет видимой заливки. У прямого марша «Вверх/Вниз» разворачивает трапецию
100%/80%, но не стрелку — стрелка поворачивается вместе со всей лестницей.
Ступени и сектора винтовой лестницы равномерно делят весь путь с шагом,
максимально близким к 30 см. В
Просмотре наведение на лестницу с корректной целью показывает подсказку
«Переход на этаж …», а чистый клик переходит на эту цель и восстанавливает
сохранённый вид этажа; хвост жеста, битая ссылка и карточка с закреплённым