From de3bb2a27425f47a124ad68fb4ddccdf02806e3a Mon Sep 17 00:00:00 2001 From: isUnknown Date: Tue, 24 Feb 2026 14:08:30 +0100 Subject: [PATCH] fix: convert values when switching CSS units to preserve visual size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, changing unit (e.g. mm → px) kept the numeric value unchanged, causing visual changes. Now values are converted through a px pivot unit so the rendered size stays the same. Co-Authored-By: Claude Opus 4.6 --- src/components/ElementPopup.vue | 30 +++++++++++++++++++------ src/components/editor/PageSettings.vue | 31 ++++++++++++++++---------- src/components/editor/TextSettings.vue | 29 ++++++++++++++---------- src/components/ui/InputWithUnit.vue | 6 +++-- src/utils/unit-conversion.js | 29 ++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 33 deletions(-) create mode 100644 src/utils/unit-conversion.js diff --git a/src/components/ElementPopup.vue b/src/components/ElementPopup.vue index 72b17f8..cd3eee9 100644 --- a/src/components/ElementPopup.vue +++ b/src/components/ElementPopup.vue @@ -56,7 +56,7 @@ type="button" :class="{ active: fontSize.unit === 'px' }" :disabled="inheritanceLocked" - @click="fontSize.unit = 'px'" + @click="updateFontSizeUnit('px')" > px @@ -64,7 +64,7 @@ type="button" :class="{ active: fontSize.unit === 'em' }" :disabled="inheritanceLocked" - @click="fontSize.unit = 'em'" + @click="updateFontSizeUnit('em')" > em @@ -72,7 +72,7 @@ type="button" :class="{ active: fontSize.unit === 'rem' }" :disabled="inheritanceLocked" - @click="fontSize.unit = 'rem'" + @click="updateFontSizeUnit('rem')" > rem @@ -142,7 +142,7 @@ type="button" :class="{ active: marginOuter.unit === 'mm' }" :disabled="inheritanceLocked" - @click="marginOuter.unit = 'mm'" + @click="updateMarginOuterUnit('mm')" > mm @@ -150,7 +150,7 @@ type="button" :class="{ active: marginOuter.unit === 'px' }" :disabled="inheritanceLocked" - @click="marginOuter.unit = 'px'" + @click="updateMarginOuterUnit('px')" > px @@ -175,7 +175,7 @@ type="button" :class="{ active: paddingInner.unit === 'mm' }" :disabled="inheritanceLocked" - @click="paddingInner.unit = 'mm'" + @click="updatePaddingInnerUnit('mm')" > mm @@ -183,7 +183,7 @@ type="button" :class="{ active: paddingInner.unit === 'px' }" :disabled="inheritanceLocked" - @click="paddingInner.unit = 'px'" + @click="updatePaddingInnerUnit('px')" > px @@ -264,6 +264,7 @@ import { usePopupPosition } from '../composables/usePopupPosition'; import { useDebounce } from '../composables/useDebounce'; import NumberInput from './ui/NumberInput.vue'; import UnitToggle from './ui/UnitToggle.vue'; +import { convertUnit } from '../utils/unit-conversion'; import Coloris from '@melloware/coloris'; import '@melloware/coloris/dist/coloris.css'; import hljs from 'highlight.js/lib/core'; @@ -325,6 +326,21 @@ const immediateUpdate = (callback) => { callback(); }; +const updateFontSizeUnit = (newUnit) => { + fontSize.value.value = convertUnit(fontSize.value.value, fontSize.value.unit, newUnit); + fontSize.value.unit = newUnit; +}; + +const updateMarginOuterUnit = (newUnit) => { + marginOuter.value.value = convertUnit(marginOuter.value.value, marginOuter.value.unit, newUnit); + marginOuter.value.unit = newUnit; +}; + +const updatePaddingInnerUnit = (newUnit) => { + paddingInner.value.value = convertUnit(paddingInner.value.value, paddingInner.value.unit, newUnit); + paddingInner.value.unit = newUnit; +}; + const getSelectorFromElement = (element) => { // Try to build a meaningful selector if (element.id) { diff --git a/src/components/editor/PageSettings.vue b/src/components/editor/PageSettings.vue index 3517ddb..caefbc8 100644 --- a/src/components/editor/PageSettings.vue +++ b/src/components/editor/PageSettings.vue @@ -66,21 +66,21 @@ @@ -107,21 +107,21 @@ @@ -148,21 +148,21 @@ @@ -189,21 +189,21 @@ @@ -295,6 +295,7 @@ import { useStylesheetStore } from '../../stores/stylesheet'; import { useDebounce } from '../../composables/useDebounce'; import Coloris from '@melloware/coloris'; import NumberInput from '../ui/NumberInput.vue'; +import { convertUnit } from '../../utils/unit-conversion'; import '@melloware/coloris/dist/coloris.css'; const stylesheetStore = useStylesheetStore(); @@ -324,6 +325,12 @@ const margins = ref({ right: { value: 20, unit: 'mm' }, }); +const updateMarginUnit = (side, newUnit) => { + const m = margins.value[side]; + m.value = convertUnit(m.value, m.unit, newUnit); + m.unit = newUnit; +}; + const background = ref({ value: '', format: 'hex', diff --git a/src/components/editor/TextSettings.vue b/src/components/editor/TextSettings.vue index 567c146..92d4775 100644 --- a/src/components/editor/TextSettings.vue +++ b/src/components/editor/TextSettings.vue @@ -379,6 +379,7 @@ import NumberInput from '../ui/NumberInput.vue'; import { useCssUpdater } from '../../composables/useCssUpdater'; import { useCssSync } from '../../composables/useCssSync'; import { useDebounce } from '../../composables/useDebounce'; +import { convertUnit } from '../../utils/unit-conversion'; const { updateStyle, setMargin, setDetailedMargins, setPadding, setDetailedPadding } = useCssUpdater(); const { extractValue, extractNumericValue, extractSpacing } = useCssSync(); @@ -439,20 +440,24 @@ const prevMarginInner = ref({ let isUpdatingFromStore = false; -// Update margin outer unit for all sides -const updateMarginOuterUnit = (unit) => { - marginOuterDetailed.value.top.unit = unit; - marginOuterDetailed.value.right.unit = unit; - marginOuterDetailed.value.bottom.unit = unit; - marginOuterDetailed.value.left.unit = unit; +// Update margin outer unit for all sides with conversion +const updateMarginOuterUnit = (newUnit) => { + const sides = ['top', 'right', 'bottom', 'left']; + sides.forEach((side) => { + const s = marginOuterDetailed.value[side]; + s.value = convertUnit(s.value, s.unit, newUnit); + s.unit = newUnit; + }); }; -// Update margin inner unit for all sides -const updateMarginInnerUnit = (unit) => { - marginInnerDetailed.value.top.unit = unit; - marginInnerDetailed.value.right.unit = unit; - marginInnerDetailed.value.bottom.unit = unit; - marginInnerDetailed.value.left.unit = unit; +// Update margin inner unit for all sides with conversion +const updateMarginInnerUnit = (newUnit) => { + const sides = ['top', 'right', 'bottom', 'left']; + sides.forEach((side) => { + const s = marginInnerDetailed.value[side]; + s.value = convertUnit(s.value, s.unit, newUnit); + s.unit = newUnit; + }); }; // Watchers for body styles diff --git a/src/components/ui/InputWithUnit.vue b/src/components/ui/InputWithUnit.vue index a87ae90..25b4a9f 100644 --- a/src/components/ui/InputWithUnit.vue +++ b/src/components/ui/InputWithUnit.vue @@ -29,6 +29,7 @@ diff --git a/src/utils/unit-conversion.js b/src/utils/unit-conversion.js new file mode 100644 index 0000000..a9a6cd4 --- /dev/null +++ b/src/utils/unit-conversion.js @@ -0,0 +1,29 @@ +const PX_PER_MM = 3.7795275591; +const PX_PER_REM = 16; +const PX_PER_EM = 16; + +const toPx = { + px: (v) => v, + mm: (v) => v * PX_PER_MM, + rem: (v) => v * PX_PER_REM, + em: (v) => v * PX_PER_EM, +}; + +const fromPx = { + px: (v) => v, + mm: (v) => v / PX_PER_MM, + rem: (v) => v / PX_PER_REM, + em: (v) => v / PX_PER_EM, +}; + +export function convertUnit(value, fromUnit, toUnit) { + if (fromUnit === toUnit) return value; + + const converterTo = toPx[fromUnit]; + const converterFrom = fromPx[toUnit]; + + if (!converterTo || !converterFrom) return value; + + const px = converterTo(value); + return Math.round(converterFrom(px) * 100) / 100; +}