mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-05 14:19:04 +00:00
File diff suppressed because one or more lines are too long
@@ -50,7 +50,12 @@ const res = await page.evaluate(async () => {
|
||||
// 3) повторный клик по активной вкладке — ничего
|
||||
tabs()[0].click(); await c.updateComplete;
|
||||
out.reclickNoop = c._mode === 'plan';
|
||||
const enteringTabCross = tabs()[0].querySelector('.closex');
|
||||
out.tabCrossCloseStartsDuringEnter = c._modeTransitionBusy;
|
||||
enteringTabCross.click();
|
||||
await settleMode();
|
||||
out.tabCrossCloseDuringEnterWorks = c._mode === 'view';
|
||||
tabs()[0].click(); await settleMode();
|
||||
// HP-UX-11: transient tool controls live in a stage overlay. Opening the
|
||||
// thickness controls must not resize/refit the stage or move pinned Close.
|
||||
const stageBeforeContext = sr().querySelector('.stage').getBoundingClientRect();
|
||||
@@ -171,10 +176,73 @@ const res = await page.evaluate(async () => {
|
||||
out.barCloseWorks = c._mode === 'view'
|
||||
&& getComputedStyle(chrome).visibility === 'hidden'
|
||||
&& chrome.getBoundingClientRect().height < 1;
|
||||
// 7) крестик в самой вкладке → Просмотр (и не переключает режим)
|
||||
tabs()[1].click(); await settleMode();
|
||||
tabs()[1].querySelector('.closex').click(); await settleMode();
|
||||
out.tabCrossWorks = c._mode === 'view';
|
||||
// 7) X in every active tab keeps its 13 px glyph/layout footprint, but its
|
||||
// real hit target is at least 24 px. Exercise the newly covered edge rather
|
||||
// than calling the element's centre programmatically.
|
||||
const tabCrossChecks = [];
|
||||
for (let index = 0; index < tabs().length; index++) {
|
||||
tabs()[index].click(); await settleMode();
|
||||
const cross = tabs()[index].querySelector('.closex');
|
||||
const rect = cross.getBoundingClientRect();
|
||||
const style = getComputedStyle(cross);
|
||||
const hit = sr().elementFromPoint(rect.left + 1, rect.top + rect.height / 2);
|
||||
const horizontalFootprint = rect.width
|
||||
+ parseFloat(style.marginLeft) + parseFloat(style.marginRight);
|
||||
const verticalFootprint = rect.height
|
||||
+ parseFloat(style.marginTop) + parseFloat(style.marginBottom);
|
||||
hit?.dispatchEvent(new MouseEvent('click', {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
clientX: rect.left + 1,
|
||||
clientY: rect.top + rect.height / 2,
|
||||
}));
|
||||
await settleMode();
|
||||
tabCrossChecks.push({
|
||||
target: rect.width >= 24 && rect.height >= 24,
|
||||
glyph: style.getPropertyValue('--mdc-icon-size').trim() === '13px',
|
||||
footprint: Math.abs(horizontalFootprint - 15) <= 0.1
|
||||
&& Math.abs(verticalFootprint - 13) <= 0.1,
|
||||
edgeHit: hit === cross,
|
||||
closed: c._mode === 'view',
|
||||
});
|
||||
}
|
||||
out.tabCrossTargetsAtLeast24 = tabCrossChecks.every((check) => check.target);
|
||||
out.tabCrossGlyphStays13 = tabCrossChecks.every((check) => check.glyph);
|
||||
out.tabCrossKeepsLayoutFootprint = tabCrossChecks.every((check) => check.footprint);
|
||||
out.tabCrossExpandedEdgeWorks = tabCrossChecks.every((check) => check.edgeHit && check.closed);
|
||||
out.tabCrossWorks = tabCrossChecks.every((check) => check.closed);
|
||||
|
||||
// Existing navigation contracts are not rewritten by the CSS fix: an open
|
||||
// Walls chain finishes on the same click, while the hard geometry limit
|
||||
// keeps the draft and gives explicit feedback.
|
||||
tabs()[0].click(); await settleMode();
|
||||
const chainSpace = c._curSpaceCfg;
|
||||
const savedPartitions = chainSpace.partitions ? [...chainSpace.partitions] : undefined;
|
||||
const savedSaveConfig = c._saveConfig;
|
||||
c._saveConfig = () => {};
|
||||
const partitionCount = (chainSpace.partitions || []).length;
|
||||
c._tool = 'draw';
|
||||
c._path = [[100, 100], [200, 100], [250, 150]];
|
||||
c._draftSegmentCms = [15, 15];
|
||||
tabs()[0].querySelector('.closex').click(); await settleMode();
|
||||
out.tabCrossFinishesWallChain = c._mode === 'view'
|
||||
&& (chainSpace.partitions || []).length === partitionCount + 2
|
||||
&& c._path.length === 0;
|
||||
chainSpace.partitions = savedPartitions;
|
||||
tabs()[0].click(); await settleMode();
|
||||
c._tool = 'draw';
|
||||
c._path = [[100, 100], [200, 100]];
|
||||
c._draftSegmentCms = [15];
|
||||
chainSpace.partitions = new Array(2000);
|
||||
tabs()[0].querySelector('.closex').click();
|
||||
out.tabCrossLimitKeepsDraftWithFeedback = c._mode === 'plan'
|
||||
&& c._path.length === 2
|
||||
&& c._toast === c._t('toast.physical_limit');
|
||||
chainSpace.partitions = savedPartitions;
|
||||
c._path = [];
|
||||
c._draftSegmentCms = [];
|
||||
c._saveConfig = savedSaveConfig;
|
||||
c._setMode('view', false); await c.updateComplete;
|
||||
|
||||
// Layout-independent editor history: physical KeyZ works when `key` is the
|
||||
// Russian «я», while an input keeps its native browser history.
|
||||
|
||||
File diff suppressed because one or more lines are too long
Vendored
+52
-43
File diff suppressed because one or more lines are too long
@@ -7,6 +7,10 @@
|
||||
rebind and length edits share the same limit and explain a rejected edit,
|
||||
while existing near-end openings and full backups remain unchanged
|
||||
([#186](https://github.com/Matysh/houseplan-card/issues/186)).
|
||||
- The close icon in an active editor tab now has a forgiving 24 × 24 px click
|
||||
target while keeping the same compact glyph and header layout. Near-misses no
|
||||
longer fall through to the active tab's intentional no-op
|
||||
([#195](https://github.com/Matysh/houseplan-card/issues/195)).
|
||||
- Room hover tooltips now show average humidity next to temperature. The value
|
||||
follows the room's configured humidity source or its Home Assistant area
|
||||
average, and is omitted when no valid reading is available
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
границу и объясняют отказ, а существующие проёмы у торца и полные резервные
|
||||
копии остаются без изменений
|
||||
([#186](https://github.com/Matysh/houseplan-card/issues/186)).
|
||||
- У крестика в активной вкладке редактора теперь удобная зона нажатия
|
||||
24 × 24 px при прежнем компактном значке и неизменной компоновке шапки.
|
||||
Близкий промах больше не попадает в намеренно неактивную команду самой вкладки
|
||||
([#195](https://github.com/Matysh/houseplan-card/issues/195)).
|
||||
- В подсказке комнаты при наведении теперь рядом с температурой показывается
|
||||
средняя влажность. Значение берётся из настроенного источника влажности или
|
||||
среднего по зоне Home Assistant и скрывается, если корректных данных нет
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ metadata). Only an explicit owner-approved emergency hotfix may skip this gate.
|
||||
| Item | State |
|
||||
|---|---|
|
||||
| Version | **v1.65.0-beta.4** everywhere (manifest, const.py, package.json, CARD_VERSION) — prerelease candidate for the current `S8-merged` queue |
|
||||
| Current local cycle | v1.65.0-beta.4 candidate carries #180, #192, #193, #196 and #197: every remaining colour/opacity setting uses the unified picker with a real hue spectrum, open passages preview their exact future wall cut, room hover exposes humidity, and degenerate optional junction patches can no longer erase the canonical masonry, floor or light barriers. #176 additionally removes the unreachable pre-#173 Partition tool-state while retaining legacy warm-token normalization and the persisted independent-wall model. Publication waits for a green exact-SHA Validate and fail-closed prerelease preflight; v1.65.0-beta.3 is published and stable v1.64.0 remains unchanged. |
|
||||
| Current local cycle | v1.65.0-beta.4 candidate carries #180, #192, #193, #196 and #197: every remaining colour/opacity setting uses the unified picker with a real hue spectrum, open passages preview their exact future wall cut, room hover exposes humidity, and degenerate optional junction patches can no longer erase the canonical masonry, floor or light barriers. #176 additionally removes the unreachable pre-#173 Partition tool-state while retaining legacy warm-token normalization and the persisted independent-wall model; #195 enlarges the active editor tab's close hit target without moving its compact header layout. Publication waits for a green exact-SHA Validate and fail-closed prerelease preflight; v1.65.0-beta.3 is published and stable v1.64.0 remains unchanged. |
|
||||
| Hidden Labs Stage | #89 Stage 1 ships in v1.63.0-beta.1. #122 Stage 2 ships in v1.64.0 and evolves the same hidden, expiring `iso` experiment with matte walls, a low exterior floor edge, restrained shared shadows and live vertical door/window/gate panels. Flat remains default; editors and `houseplan-space-card` remain flat; live floor effects and HA actions remain unchanged. Public activation remains a separate task. |
|
||||
| Workflow | Superseded 2026-08-12: the pre-1.62 rule of "local edits without tests or commits" is **dead** — since release 1.62 every product change follows `PROCESS.md` (issue in `S5-ready`+, branch `issue/<NN>-slug`, trailers on every commit, review pipeline; `AGENTS.md` is the summary). Release mechanics below remain current. A requested pre-release gets a production build plus the smallest targeted unit/smoke set covering the changed surfaces, one tested `dev` commit/tag and a GitHub Release with `prerelease=true`; `main` stays untouched. The complete local frontend/backend/smoke gate runs only before a stable release, after which `main` is fast-forwarded to the exact tested `dev` SHA and the GitHub Release uses `prerelease=false`. Release bodies are short and bilingual (Russian first): only significant user changes get individual bullets, while minor/code-only work is grouped as `Мелкие исправления и улучшения` / `Small fixes and improvements`; every body ends with separate links to the Russian and English changelogs. Detailed RU/EN changelog bullets may link the corresponding closed GitHub Issues; open or partially delivered issues are never presented as shipped. Telegram announcements are sent only for stable releases; beta and RC publication is silent. `docs/RELEASE-NOTES.md` is the current canonical body instance; `npm run release:prerelease -- <tag> --issues=… --yes` is the primary local publication path and the manual `Publish prerelease` workflow is its GitHub-only equivalent once present on `main`. Nothing is copied to the home instance by hand |
|
||||
| GitHub | https://github.com/Matysh/houseplan-card — [Issues](https://github.com/Matysh/houseplan-card/issues) are the canonical task records; their labels carry priority and workflow status (`PROCESS.md` §9). GitHub Projects is no longer used. `main` carries stable releases; pre-release tags may point directly at `dev`. Work lands on `dev` and is merged into `main` for a stable release, so `dev` is normally equal to or ahead of `main`, never behind. Push via SSH key `ha_jb` (remote git@github.com:…); API releases via the fine-grained PAT in `~/.git-credentials` (Contents R/W, issued 2026-07-23) |
|
||||
|
||||
+5
-1
@@ -1186,7 +1186,11 @@ separately promised workflows:
|
||||
"Background editor" (no View button; View is the default state); clicking a tab opens its
|
||||
bottom toolbar (Devices got its own bar with add/show-all/reset/rules);
|
||||
the bar and the active tab both show an X that returns to View; re-click
|
||||
on the active tab does nothing; Plan↔Devices switches directly [auto: smoke_editor_tabs]
|
||||
on the active tab does nothing; the header X keeps a 13 px glyph inside a
|
||||
≥24 × 24 px hit target and closes from its expanded edge, during an active
|
||||
transition and after finishing a Walls chain; a geometry-limit blocker
|
||||
keeps the draft with an explicit toast; Plan↔Devices switches directly
|
||||
[auto: smoke_editor_tabs]
|
||||
- [ ] Stable editor chrome (HP-UX-11): selection, tool parameters, operation
|
||||
hints and furniture palette use the single stage-owned context tray;
|
||||
opening/closing it leaves stage top/height, `_hdrH`, zoom/pan and the
|
||||
|
||||
+3
-1
@@ -32,7 +32,9 @@ inert everywhere outside its editor).
|
||||
background and editor-specific layers move on one short timeline, so opening
|
||||
an editor never flashes a default scale or a mixed dark/white frame. A rapid
|
||||
second choice retargets from the visible intermediate frame. Reduced-motion
|
||||
preferences apply the same final state immediately.
|
||||
preferences apply the same final state immediately. The header X keeps its
|
||||
compact 13 px glyph but owns a hit target of at least 24 × 24 px without
|
||||
changing the tab's layout footprint.
|
||||
- An editor's primary toolbar contains only persistent tools. Close is pinned
|
||||
in its own end cap. Selection actions, active-tool parameters, operation
|
||||
hints and palettes appear in one translucent context tray over the top of the
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"fixture": "synthetic-only",
|
||||
"sourceFingerprint": "edb4278c0d33b75e417cc0b2d83ac8a46f2be4cf0d2c46aed801c566d82b70bc",
|
||||
"sourceFingerprint": "b0a03dc3f4016afc7cf8cbb77c78925e8e61d441b5972e0a0c6c22e68131ed6b",
|
||||
"captureScriptSha256": "34f2219790d46efd8250e7a1bd829cb8fc0b0547e1260635fefa52407551b41b",
|
||||
"command": "npm run build && node demo/docs/capture.mjs",
|
||||
"scenarios": {
|
||||
@@ -13,7 +13,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "edb4278c0d33b75e417cc0b2d83ac8a46f2be4cf0d2c46aed801c566d82b70bc",
|
||||
"sourceSha256": "b0a03dc3f4016afc7cf8cbb77c78925e8e61d441b5972e0a0c6c22e68131ed6b",
|
||||
"imageSha256": "d36b6f9f8139f31ef73a780c6511a640a26055efd9d7a24c24fd48b1d8379bf0"
|
||||
},
|
||||
"view-touch": {
|
||||
@@ -24,7 +24,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "edb4278c0d33b75e417cc0b2d83ac8a46f2be4cf0d2c46aed801c566d82b70bc",
|
||||
"sourceSha256": "b0a03dc3f4016afc7cf8cbb77c78925e8e61d441b5972e0a0c6c22e68131ed6b",
|
||||
"imageSha256": "358e25ff9984d0fb0c03cfbb848df40c425fdfe64cd5f4f613b1e754ca9d4249"
|
||||
},
|
||||
"space-create": {
|
||||
@@ -35,7 +35,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "edb4278c0d33b75e417cc0b2d83ac8a46f2be4cf0d2c46aed801c566d82b70bc",
|
||||
"sourceSha256": "b0a03dc3f4016afc7cf8cbb77c78925e8e61d441b5972e0a0c6c22e68131ed6b",
|
||||
"imageSha256": "c53db2e5c642a5549c13f3c93a5b359fed69bdb2621bf71a243a877ffcb95e6b"
|
||||
},
|
||||
"room-contour-close": {
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "edb4278c0d33b75e417cc0b2d83ac8a46f2be4cf0d2c46aed801c566d82b70bc",
|
||||
"sourceSha256": "b0a03dc3f4016afc7cf8cbb77c78925e8e61d441b5972e0a0c6c22e68131ed6b",
|
||||
"imageSha256": "5ca7f24642926072ccbc5bf48341c5310329918631b147c116f9c29e20e4927e"
|
||||
},
|
||||
"plan-context-tray": {
|
||||
@@ -57,7 +57,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "edb4278c0d33b75e417cc0b2d83ac8a46f2be4cf0d2c46aed801c566d82b70bc",
|
||||
"sourceSha256": "b0a03dc3f4016afc7cf8cbb77c78925e8e61d441b5972e0a0c6c22e68131ed6b",
|
||||
"imageSha256": "164b79fd9075a1425cffe3c85c88b689dfda90b79856bb4ed6655507b166b3e0"
|
||||
},
|
||||
"device-editor": {
|
||||
@@ -68,7 +68,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "edb4278c0d33b75e417cc0b2d83ac8a46f2be4cf0d2c46aed801c566d82b70bc",
|
||||
"sourceSha256": "b0a03dc3f4016afc7cf8cbb77c78925e8e61d441b5972e0a0c6c22e68131ed6b",
|
||||
"imageSha256": "7c3e25534fc819c45431907616c3d523961505859ee68af27cce2daec9f04fb0"
|
||||
},
|
||||
"device-display-preview": {
|
||||
@@ -79,7 +79,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "edb4278c0d33b75e417cc0b2d83ac8a46f2be4cf0d2c46aed801c566d82b70bc",
|
||||
"sourceSha256": "b0a03dc3f4016afc7cf8cbb77c78925e8e61d441b5972e0a0c6c22e68131ed6b",
|
||||
"imageSha256": "f6014caed7b7d28790b8548996ba09d806a4e4d51fbb7e8d3fb3c582ebe49167"
|
||||
},
|
||||
"background-editor": {
|
||||
@@ -90,7 +90,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "edb4278c0d33b75e417cc0b2d83ac8a46f2be4cf0d2c46aed801c566d82b70bc",
|
||||
"sourceSha256": "b0a03dc3f4016afc7cf8cbb77c78925e8e61d441b5972e0a0c6c22e68131ed6b",
|
||||
"imageSha256": "d7cfe70551d9260169df8efd832e32ed7df99c7f60b55d1fd4a8322bd4c47175"
|
||||
},
|
||||
"room-card": {
|
||||
@@ -101,7 +101,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "edb4278c0d33b75e417cc0b2d83ac8a46f2be4cf0d2c46aed801c566d82b70bc",
|
||||
"sourceSha256": "b0a03dc3f4016afc7cf8cbb77c78925e8e61d441b5972e0a0c6c22e68131ed6b",
|
||||
"imageSha256": "176abba71d41cfb045a33f82a794d9fbb2a5d3c48e6df66e6ec3a8e448311b11"
|
||||
},
|
||||
"device-info": {
|
||||
@@ -112,7 +112,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "edb4278c0d33b75e417cc0b2d83ac8a46f2be4cf0d2c46aed801c566d82b70bc",
|
||||
"sourceSha256": "b0a03dc3f4016afc7cf8cbb77c78925e8e61d441b5972e0a0c6c22e68131ed6b",
|
||||
"imageSha256": "2199ed88b215bf2bff63bf665028f78b2aa6a92c3032b803931790f2ef071893"
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -1613,9 +1613,18 @@ export const cardStyles = css`
|
||||
.modetab ha-icon { --mdc-icon-size: 15px; }
|
||||
.modetab .closex {
|
||||
--mdc-icon-size: 13px;
|
||||
box-sizing: border-box;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-left: 2px;
|
||||
justify-content: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
/* Keep the old 13 × 13 flex footprint (+2 px left margin) while the
|
||||
pointer target grows around it. Header width, height and wrapping do
|
||||
not move; only near-misses that used to hit the active tab reach X. */
|
||||
margin: -5.5px -5.5px -5.5px -3.5px;
|
||||
opacity: 0.75;
|
||||
cursor: pointer;
|
||||
border-radius: var(--rad-s);
|
||||
|
||||
Reference in New Issue
Block a user