diff --git a/.github/workflows/docs-screenshots.yml b/.github/workflows/docs-screenshots.yml
index 3a021777..0efef313 100644
--- a/.github/workflows/docs-screenshots.yml
+++ b/.github/workflows/docs-screenshots.yml
@@ -48,6 +48,29 @@ jobs:
run: npx playwright install chromium
- name: Build the bundle the screenshots must come from
run: npm run build
+ # oxipng без потерь снимает с набора ~19% (замер в #345 на pyoxipng 9.1.1;
+ # у 10.2.0 пресеты уровней перебалансированы, точная доля может отличаться,
+ # но кадры остаются пиксельно идентичными в любой версии — это перепаковка).
+ #
+ # Пин версии и контрольной суммы намеренно, а не `apt-get install oxipng`:
+ # пакет из образа раннера может пропасть или переехать, а падение шага
+ # съёмки стоит целого цикла приёмки. Тот же урок, что с azure-зеркалом
+ # Playwright (#175, #206).
+ - name: Установить oxipng
+ env:
+ OXIPNG_VERSION: 10.2.0
+ OXIPNG_SHA256: b33f84c73d42cb592bea5d84c431030b1e97784817693380dfcec7d9575f871e
+ run: |
+ set -euo pipefail
+ asset="oxipng-${OXIPNG_VERSION}-x86_64-unknown-linux-gnu.tar.gz"
+ curl -fsSL -o "$asset" \
+ "https://github.com/oxipng/oxipng/releases/download/v${OXIPNG_VERSION}/${asset}"
+ echo "${OXIPNG_SHA256} ${asset}" | sha256sum -c -
+ mkdir -p "$HOME/.local/bin"
+ tar -xzf "$asset" --strip-components=1 -C "$HOME/.local/bin" \
+ "oxipng-${OXIPNG_VERSION}-x86_64-unknown-linux-gnu/oxipng"
+ echo "$HOME/.local/bin" >> "$GITHUB_PATH"
+ "$HOME/.local/bin/oxipng" --version
- name: Capture
run: node demo/docs/capture.mjs
# Вердикт до всякой приёмки. Само число изменившихся файлов ничего не
@@ -58,16 +81,30 @@ jobs:
# разницу рендеринга.
- name: Вердикт
run: |
+ # Поле манифеста «до» — из закоммиченного состояния, «после» — из
+ # свежего. Читается одинаково для браузера и для упаковщика: оба
+ # переписывают все кадры сразу, и различить их причины обязан вердикт,
+ # а не человек по памяти (#345).
+ field() {
+ node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{try{console.log(JSON.parse(s).$1||'')}catch{console.log('')}})"
+ }
git status --porcelain docs/images
changed=$(git diff --name-only docs/images | grep -c png || true)
- before=$(git show HEAD:docs/images/screenshots.json | node -e \
- "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{try{console.log(JSON.parse(s).chromium||'')}catch{console.log('')}})")
+ before=$(git show HEAD:docs/images/screenshots.json | field chromium)
after=$(node -e "console.log(require('./docs/images/screenshots.json').chromium)")
+ packer_before=$(git show HEAD:docs/images/screenshots.json | field oxipng)
+ packer_after=$(node -e "console.log(require('./docs/images/screenshots.json').oxipng || '')")
echo "--- изменившихся PNG: $changed"
echo "--- Chromium: было «${before:-не записан}», стало «$after»"
- if [ "$before" = "$after" ] && [ "$changed" -gt 0 ]; then
- echo "ВЕРДИКТ: тот же браузер, а картинки изменились — изменился продукт."
- echo "Смотрите на кадры: если изменение ожидаемое, принимайте."
+ echo "--- oxipng: было «${packer_before:-не записан}», стало «${packer_after:-нет}»"
+ if [ "$packer_before" != "$packer_after" ] && [ "$changed" -gt 0 ]; then
+ echo "ВЕРДИКТ: изменился упаковщик, поэтому переписаны все кадры сразу."
+ echo "Это перепаковка без потерь: пиксели те же, размер меньше на ~19%."
+ echo "Ожидаемо один раз — при включении oxipng либо при смене его версии."
+ echo "Проверить можно сравнением декодированных кадров, а не байтов."
+ elif [ "$before" = "$after" ] && [ "$changed" -gt 0 ]; then
+ echo "ВЕРДИКТ: тот же браузер и тот же упаковщик, а картинки изменились —"
+ echo "изменился продукт. Смотрите на кадры: если изменение ожидаемое, принимайте."
elif [ "$before" != "$after" ]; then
echo "ВЕРДИКТ: браузер другой, поэтому переписаны все кадры сразу."
echo "Это ожидаемо один раз — при переходе на канонический прогон."
diff --git a/custom_components/houseplan/frontend/houseplan-assets.json b/custom_components/houseplan/frontend/houseplan-assets.json
index 2a1a55d0..ac88fd7a 100644
--- a/custom_components/houseplan/frontend/houseplan-assets.json
+++ b/custom_components/houseplan/frontend/houseplan-assets.json
@@ -1,96 +1,96 @@
{
"schema": 1,
- "fingerprint": "edcb61bd3c2c9a6056c747c366bbd7c73f1678dce2c656f631b56a4241a4b8dc",
+ "fingerprint": "e499c3cfebb07203abd2397b1303ed1a45286f24fcc9129f45917b8a99ba1479",
"entry": "houseplan-card.js",
"initialViewFiles": [
- "houseplan-assets/houseplan-card-CdKyxHZ7.js",
+ "houseplan-assets/houseplan-card-OQuczTJf.js",
"houseplan-card.js"
],
- "initialViewGzipBytes": 255910,
+ "initialViewGzipBytes": 255908,
"lazyFiles": [
- "houseplan-assets/editor-MqqOS4sP.js",
- "houseplan-assets/houseplan-editor-runtime-Bbmj7A6f.js",
- "houseplan-assets/houseplan-onboarding-runtime-C28J-NJP.js",
- "houseplan-assets/space-deletion-BxF_6aDU.js"
+ "houseplan-assets/editor-DMlizeQy.js",
+ "houseplan-assets/houseplan-editor-runtime-Bk__jFmU.js",
+ "houseplan-assets/houseplan-onboarding-runtime-Dor16U6K.js",
+ "houseplan-assets/space-deletion-7mvB_XVT.js"
],
- "lazyGzipBytes": 138425,
+ "lazyGzipBytes": 138428,
"lazyEditorFiles": [
- "houseplan-assets/editor-MqqOS4sP.js",
- "houseplan-assets/houseplan-editor-runtime-Bbmj7A6f.js",
- "houseplan-assets/space-deletion-BxF_6aDU.js"
+ "houseplan-assets/editor-DMlizeQy.js",
+ "houseplan-assets/houseplan-editor-runtime-Bk__jFmU.js",
+ "houseplan-assets/space-deletion-7mvB_XVT.js"
],
"lazyEditorGzipBytes": 131779,
"lazyOnboardingFiles": [
- "houseplan-assets/houseplan-onboarding-runtime-C28J-NJP.js",
- "houseplan-assets/space-deletion-BxF_6aDU.js"
+ "houseplan-assets/houseplan-onboarding-runtime-Dor16U6K.js",
+ "houseplan-assets/space-deletion-7mvB_XVT.js"
],
- "lazyOnboardingGzipBytes": 7199,
+ "lazyOnboardingGzipBytes": 7203,
"files": [
{
- "path": "houseplan-assets/editor-MqqOS4sP.js",
- "sha256": "140369d29021c71a88b788224fca477b97fc4fc1d5254bbad9e68f01fee403c9",
+ "path": "houseplan-assets/editor-DMlizeQy.js",
+ "sha256": "7aeb38573980efdf90749280c7be4150f41bec4939919c9d84ecdf028185fd6a",
"rawBytes": 3699,
- "gzipBytes": 1529,
+ "gzipBytes": 1530,
"isEntry": false,
"imports": [
- "houseplan-assets/houseplan-card-CdKyxHZ7.js"
+ "houseplan-assets/houseplan-card-OQuczTJf.js"
],
"dynamicImports": []
},
{
- "path": "houseplan-assets/houseplan-card-CdKyxHZ7.js",
- "sha256": "66c490a5ab13cff53463d315b0d18c8dfd26f1caf150836de5559ac3df2aa82e",
+ "path": "houseplan-assets/houseplan-card-OQuczTJf.js",
+ "sha256": "bbff295ebc0def9401caac0001245371490977fe612cc08c2402cfca5b827faf",
"rawBytes": 910654,
- "gzipBytes": 255727,
+ "gzipBytes": 255726,
"isEntry": false,
"imports": [],
"dynamicImports": [
- "houseplan-assets/editor-MqqOS4sP.js",
- "houseplan-assets/houseplan-editor-runtime-Bbmj7A6f.js",
- "houseplan-assets/houseplan-onboarding-runtime-C28J-NJP.js"
+ "houseplan-assets/editor-DMlizeQy.js",
+ "houseplan-assets/houseplan-editor-runtime-Bk__jFmU.js",
+ "houseplan-assets/houseplan-onboarding-runtime-Dor16U6K.js"
]
},
{
- "path": "houseplan-assets/houseplan-editor-runtime-Bbmj7A6f.js",
- "sha256": "0d2dd1b6cfc0c05a010e7b2345623f1063ed5e0fe0f9a95be9afb81e90c26e6b",
+ "path": "houseplan-assets/houseplan-editor-runtime-Bk__jFmU.js",
+ "sha256": "616d30f0d4a61a14f8c149c55e6a8d12647aa80bdd31c32b57d2803ba9c5653b",
"rawBytes": 504952,
- "gzipBytes": 129697,
+ "gzipBytes": 129695,
"isEntry": false,
"imports": [
- "houseplan-assets/houseplan-card-CdKyxHZ7.js",
- "houseplan-assets/space-deletion-BxF_6aDU.js"
+ "houseplan-assets/houseplan-card-OQuczTJf.js",
+ "houseplan-assets/space-deletion-7mvB_XVT.js"
],
"dynamicImports": []
},
{
- "path": "houseplan-assets/houseplan-onboarding-runtime-C28J-NJP.js",
- "sha256": "38044f0836917a8f91705b61b5d48fcf4c0ca72d41b919831d2b66a0a78e4ff9",
+ "path": "houseplan-assets/houseplan-onboarding-runtime-Dor16U6K.js",
+ "sha256": "218d3b7f139f12bb842f7f888ba2e2fa97ca2f11b8bbfd6c2b9e16eff0647eef",
"rawBytes": 26356,
- "gzipBytes": 6646,
+ "gzipBytes": 6649,
"isEntry": false,
"imports": [
- "houseplan-assets/houseplan-card-CdKyxHZ7.js",
- "houseplan-assets/space-deletion-BxF_6aDU.js"
+ "houseplan-assets/houseplan-card-OQuczTJf.js",
+ "houseplan-assets/space-deletion-7mvB_XVT.js"
],
"dynamicImports": []
},
{
- "path": "houseplan-assets/space-deletion-BxF_6aDU.js",
- "sha256": "137b0f78bc5e11c7b1e95c138c1fcf0f982f89013053a1cc648e6df52092401e",
+ "path": "houseplan-assets/space-deletion-7mvB_XVT.js",
+ "sha256": "ca7cdbe51f937d2cd53385204d3b7917ec18f50c51b5aef4eb3e273516b08747",
"rawBytes": 911,
- "gzipBytes": 553,
+ "gzipBytes": 554,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
- "sha256": "3a1818c954f8d4a8a8cb143d7b9c39196a8a340a43c578fd6ca5b6fc01ac8065",
+ "sha256": "45da1371d0ca2713a6a8f6108599c614bed0907f2c80556192375dbfdc741e2e",
"rawBytes": 190,
- "gzipBytes": 183,
+ "gzipBytes": 182,
"isEntry": true,
"imports": [
- "houseplan-assets/houseplan-card-CdKyxHZ7.js"
+ "houseplan-assets/houseplan-card-OQuczTJf.js"
],
"dynamicImports": []
}
diff --git a/custom_components/houseplan/frontend/houseplan-assets/editor-MqqOS4sP.js b/custom_components/houseplan/frontend/houseplan-assets/editor-MqqOS4sP.js
deleted file mode 100644
index f4d028c3..00000000
--- a/custom_components/houseplan/frontend/houseplan-assets/editor-MqqOS4sP.js
+++ /dev/null
@@ -1,14 +0,0 @@
-globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="edcb61bd3c2c9a6056c747c366bbd7c73f1678dce2c656f631b56a4241a4b8dc";import{c as e,l as o,t,d2 as s,A as a,b as l}from"./houseplan-card-CdKyxHZ7.js";class i extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],l=this._floorToken;l&&a.push({value:l,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const i="string"==typeof this._config?.floor?this._config.floor:"";i&&!e.some(e=>e.value===i)&&a.push({value:i,label:i}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;this._loadSpaces();const e=this._lang,o={title:t(e,"editor.title"),floor:t(e,"editor.floor"),default_floor:t(e,"editor.default_floor"),language:t(e,"editor.language"),icon_size:t(e,"editor.icon_size"),show_temperature:t(e,"editor.show_temperature"),live_states:t(e,"editor.live_states"),show_signal:t(e,"editor.show_signal"),kiosk:t(e,"editor.kiosk"),cycle:t(e,"editor.cycle")},s=this._schema,i=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),n=e=>l`
${this._t("fixed_floor.loading")}
-${this._t("fixed_floor.invalid_title")}
-${this._t("fixed_floor.invalid_body",{value:this._fixedFloorValue(r.value)})}
-${this._t("empty.no_spaces")}
- ${this._serverStorage?B`${this._t("empty.add_first")}
- `:B`${this._t("empty.install")}
`} -${this._t("vac.residual_message",{error:this._vacCalConfirm.error})}
-${this._tapConfirm.text}
`:this._tapConfirm.lines.map((e,t)=>B` -${e}
`)} -${this._t("opening.no_entities")}
`} -${this._reason(t.fallbackReason)}
`:a} - ${t.explanation.notices.map(t=>o`${this._reason(t)}
`)} - ${p<1?o`${this._t("marker.preview.scaled",{n:b})}
`:a} - ${e&&this._reducedMotion?o`${this._t("marker.preview.reduced_motion")}
`:a} -${t.eid}
- ${t.stateText||t.state}
- ${this._sourceProvider(t.eid)}
-