From 5fac00b5ce8f79f3f0a802361642bc6e9cafeee3 Mon Sep 17 00:00:00 2001 From: jonny Date: Mon, 9 Mar 2026 20:00:42 +0800 Subject: [PATCH] =?UTF-8?q?-=20feat:=E8=AE=B0=E5=BF=86=E6=8B=96=E6=8B=BD?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E5=A4=A7=E5=B0=8F=E5=92=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=8A=A8=E7=94=BB=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add persistent, robust scaling for the proportional editor and remove CSS transitions that interfered with instant restores. Introduces a storageKey, parseScale, applyScaleInstant and logic to restore scale synchronously from localStorage (for immediate UX) and asynchronously from chrome.storage.sync (best-effort), keeping localStorage in sync. Ensures pending RAF updates are flushed before persisting and guards against missing APIs or invalid values. Also removes transition properties in main.css so scale restores remain immediate and predictable. --- css/main.css | 3 --- js/oper.js | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/css/main.css b/css/main.css index 6a9b183..b551a32 100644 --- a/css/main.css +++ b/css/main.css @@ -44,9 +44,6 @@ a{color: #555;} background-color: rgb(255,255,255); margin-top:0.8rem; padding: 0.6rem; - transition-property: all; - transition-timing-function: cubic-bezier(.4,0,.2,1); - transition-duration: .15s; } .memo-editor{ position: relative; diff --git a/js/oper.js b/js/oper.js index 0e3b270..fadcf01 100644 --- a/js/oper.js +++ b/js/oper.js @@ -39,6 +39,8 @@ function initProportionalEditorResize() { editor.style.minWidth = `${baseW}px` editor.style.minHeight = `${baseH}px` + const storageKey = 'popupEditorScale' + let maxScale = 1 const computeMaxScale = () => { // In popup mode, allow scaling up to Chrome's max popup size. @@ -69,6 +71,15 @@ function initProportionalEditorResize() { let rafId = 0 let pendingScale = null + const parseScale = (raw) => { + const s = typeof raw === 'number' && Number.isFinite(raw) + ? raw + : typeof raw === 'string' && raw.trim() !== '' && !Number.isNaN(Number(raw)) + ? Number(raw) + : 1 + return s > 0 ? s : 1 + } + const readCurrentScale = () => { const w = parseFloat(editor.style.width || '') const h = parseFloat(editor.style.height || '') @@ -83,6 +94,47 @@ function initProportionalEditorResize() { editor.style.height = `${Math.round(baseH * s)}px` } + const applyScaleInstant = (scale) => { + // In case CSS transitions exist (or get reintroduced), keep restores immediate. + const prevTransition = editor.style.transition + editor.style.transition = 'none' + applyScale(scale) + window.requestAnimationFrame(function () { + editor.style.transition = prevTransition + }) + } + + // Restore previously saved scale synchronously (localStorage) first. + // This makes the popup *feel* synchronous because it can apply before async chrome.storage returns. + let restoredFromLocal = false + let localScale = 1 + try { + const raw = window.localStorage ? window.localStorage.getItem(storageKey) : null + const s = parseScale(raw) + if (s && s !== 1) { + localScale = s + restoredFromLocal = true + applyScaleInstant(s) + } + } catch (_) { + // ignore + } + + // Restore from chrome.storage.sync (best-effort) and keep localStorage in sync. + try { + chrome.storage.sync.get({ [storageKey]: 1 }, function (items) { + const raw = items ? items[storageKey] : 1 + const s = parseScale(raw) + const shouldApply = !restoredFromLocal || Math.abs(s - localScale) > 1e-6 + if (shouldApply) applyScaleInstant(s) + try { + if (window.localStorage) window.localStorage.setItem(storageKey, String(s)) + } catch (_) {} + }) + } catch (_) { + // ignore + } + const scheduleApply = () => { if (rafId) return rafId = window.requestAnimationFrame(() => { @@ -122,6 +174,25 @@ function initProportionalEditorResize() { const endDrag = () => { dragging = false + + // Flush any pending RAF update before persisting. + if (pendingScale != null) { + applyScale(pendingScale) + pendingScale = null + } + + // Persist current scale (best-effort). + try { + const s = readCurrentScale() + if (typeof s === 'number' && Number.isFinite(s)) { + try { + if (window.localStorage) window.localStorage.setItem(storageKey, String(s)) + } catch (_) {} + chrome.storage.sync.set({ [storageKey]: s }) + } + } catch (_) { + // ignore + } } handle.addEventListener('pointerup', endDrag)