From 06aef5beb34c800e85aca070f8fae6538e968afd Mon Sep 17 00:00:00 2001 From: isUnknown Date: Wed, 10 Dec 2025 13:47:49 +0100 Subject: [PATCH] refactor: replace MarginEditor with linked margin fields in TextSettings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace MarginEditor component with individual fields (top/bottom/left/right) - Add link/unlink button with SVG icons to sync margin values - When linked, all fields share the same value - Auto-detect linked state when loading from stylesheet - Match PageSettings UI pattern for consistency 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/components/editor/TextSettings.vue | 477 +++++++++++++++++++++---- 1 file changed, 400 insertions(+), 77 deletions(-) diff --git a/src/components/editor/TextSettings.vue b/src/components/editor/TextSettings.vue index 95973bd..9dd4a13 100644 --- a/src/components/editor/TextSettings.vue +++ b/src/components/editor/TextSettings.vue @@ -91,31 +91,269 @@ -
- +
+
+

Marges extérieures

+ +
+ +
+ +
+ +
+ + + +
+
+
+ +
+ +
+ +
+ + + +
+
+
+ +
+ +
+ +
+ + + +
+
+
+ +
+ +
+ +
+ + + +
+
+
-
- +
+
+

Marges intérieures

+ +
+ +
+ +
+ +
+ + + +
+
+
+ +
+ +
+ +
+ + + +
+
+
+ +
+ +
+ +
+ + + +
+
+
+ +
+ +
+ +
+ + + +
+
+
@@ -127,7 +365,7 @@ import { ref, watch, onMounted } from 'vue'; import Coloris from '@melloware/coloris'; import UnitToggle from '../ui/UnitToggle.vue'; import InputWithUnit from '../ui/InputWithUnit.vue'; -import MarginEditor from '../ui/MarginEditor.vue'; +import NumberInput from '../ui/NumberInput.vue'; import { useCssUpdater } from '../../composables/useCssUpdater'; import { useCssSync } from '../../composables/useCssSync'; import { useDebounce } from '../../composables/useDebounce'; @@ -155,7 +393,6 @@ const alignment = ref('left'); const color = ref('rgb(0, 0, 0)'); const background = ref('transparent'); -const marginOuter = ref({ value: 0, unit: 'mm' }); const marginOuterDetailed = ref({ top: { value: 0, unit: 'mm' }, right: { value: 0, unit: 'mm' }, @@ -163,7 +400,6 @@ const marginOuterDetailed = ref({ left: { value: 0, unit: 'mm' } }); -const marginInner = ref({ value: 0, unit: 'mm' }); const marginInnerDetailed = ref({ top: { value: 0, unit: 'mm' }, right: { value: 0, unit: 'mm' }, @@ -171,11 +407,27 @@ const marginInnerDetailed = ref({ left: { value: 0, unit: 'mm' } }); -const marginOuterEditor = ref(null); -const marginInnerEditor = ref(null); +const marginOuterLinked = ref(false); +const marginInnerLinked = ref(false); 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 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; +}; + // Watchers for body styles watch(italic, (val) => { if (isUpdatingFromStore) return; @@ -210,28 +462,77 @@ watch(fontSize, (val) => { }); }, { deep: true }); -// Margin/Padding handlers -const handleMarginOuterChange = ({ type, simple, detailed }) => { +// Watch margin outer values +watch(() => [ + marginOuterDetailed.value.top.value, + marginOuterDetailed.value.bottom.value, + marginOuterDetailed.value.left.value, + marginOuterDetailed.value.right.value, +], () => { if (isUpdatingFromStore) return; - debouncedUpdate(() => { - if (type === 'simple') { - setMargin('p', simple.value, simple.unit); - } else { - setDetailedMargins('p', detailed.top, detailed.right, detailed.bottom, detailed.left); - } - }); -}; -const handleMarginInnerChange = ({ type, simple, detailed }) => { - if (isUpdatingFromStore) return; + // If linked, sync all values to the one that changed + if (marginOuterLinked.value) { + // Find which value changed and sync others to it + const top = marginOuterDetailed.value.top.value; + const bottom = marginOuterDetailed.value.bottom.value; + const left = marginOuterDetailed.value.left.value; + const right = marginOuterDetailed.value.right.value; + + // Use the max value to determine which one changed (simple heuristic) + const maxValue = Math.max(top, bottom, left, right); + isUpdatingFromStore = true; + marginOuterDetailed.value.top.value = maxValue; + marginOuterDetailed.value.bottom.value = maxValue; + marginOuterDetailed.value.left.value = maxValue; + marginOuterDetailed.value.right.value = maxValue; + isUpdatingFromStore = false; + } + debouncedUpdate(() => { - if (type === 'simple') { - setPadding('p', simple.value, simple.unit); - } else { - setDetailedPadding('p', detailed.top, detailed.right, detailed.bottom, detailed.left); - } + setDetailedMargins('p', + marginOuterDetailed.value.top, + marginOuterDetailed.value.right, + marginOuterDetailed.value.bottom, + marginOuterDetailed.value.left + ); }); -}; +}); + +// Watch margin inner values +watch(() => [ + marginInnerDetailed.value.top.value, + marginInnerDetailed.value.bottom.value, + marginInnerDetailed.value.left.value, + marginInnerDetailed.value.right.value, +], () => { + if (isUpdatingFromStore) return; + + // If linked, sync all values to the one that changed + if (marginInnerLinked.value) { + const top = marginInnerDetailed.value.top.value; + const bottom = marginInnerDetailed.value.bottom.value; + const left = marginInnerDetailed.value.left.value; + const right = marginInnerDetailed.value.right.value; + + const maxValue = Math.max(top, bottom, left, right); + isUpdatingFromStore = true; + marginInnerDetailed.value.top.value = maxValue; + marginInnerDetailed.value.bottom.value = maxValue; + marginInnerDetailed.value.left.value = maxValue; + marginInnerDetailed.value.right.value = maxValue; + isUpdatingFromStore = false; + } + + debouncedUpdate(() => { + setDetailedPadding('p', + marginInnerDetailed.value.top, + marginInnerDetailed.value.right, + marginInnerDetailed.value.bottom, + marginInnerDetailed.value.left + ); + }); +}); // Sync from store const syncFromStore = () => { @@ -261,17 +562,17 @@ const syncFromStore = () => { const margins = extractSpacing('p', 'margin'); if (margins) { if (margins.simple) { - marginOuter.value = margins.simple; - // Sync detailed from simple + // All margins are the same marginOuterDetailed.value = { top: { ...margins.simple }, right: { ...margins.simple }, bottom: { ...margins.simple }, left: { ...margins.simple } }; + marginOuterLinked.value = true; } else if (margins.detailed) { marginOuterDetailed.value = margins.detailed; - // Check if all values are the same to set simple value + // Check if all values are the same const allSame = margins.detailed.top.value === margins.detailed.right.value && margins.detailed.top.value === margins.detailed.bottom.value && @@ -279,19 +580,7 @@ const syncFromStore = () => { margins.detailed.top.unit === margins.detailed.right.unit && margins.detailed.top.unit === margins.detailed.bottom.unit && margins.detailed.top.unit === margins.detailed.left.unit; - - if (allSame) { - marginOuter.value = margins.detailed.top; - } else { - // Values are different, open the detailed editor and use first value for simple - marginOuter.value = margins.detailed.top; - // Open detailed view after mount - setTimeout(() => { - if (marginOuterEditor.value) { - marginOuterEditor.value.expanded = true; - } - }, 0); - } + marginOuterLinked.value = allSame; } } @@ -299,17 +588,17 @@ const syncFromStore = () => { const padding = extractSpacing('p', 'padding'); if (padding) { if (padding.simple) { - marginInner.value = padding.simple; - // Sync detailed from simple + // All paddings are the same marginInnerDetailed.value = { top: { ...padding.simple }, right: { ...padding.simple }, bottom: { ...padding.simple }, left: { ...padding.simple } }; + marginInnerLinked.value = true; } else if (padding.detailed) { marginInnerDetailed.value = padding.detailed; - // Check if all values are the same to set simple value + // Check if all values are the same const allSame = padding.detailed.top.value === padding.detailed.right.value && padding.detailed.top.value === padding.detailed.bottom.value && @@ -317,19 +606,7 @@ const syncFromStore = () => { padding.detailed.top.unit === padding.detailed.right.unit && padding.detailed.top.unit === padding.detailed.bottom.unit && padding.detailed.top.unit === padding.detailed.left.unit; - - if (allSame) { - marginInner.value = padding.detailed.top; - } else { - // Values are different, open the detailed editor and use first value for simple - marginInner.value = padding.detailed.top; - // Open detailed view after mount - setTimeout(() => { - if (marginInnerEditor.value) { - marginInnerEditor.value.expanded = true; - } - }, 0); - } + marginInnerLinked.value = allSame; } } @@ -348,3 +625,49 @@ onMounted(() => { syncFromStore(); }); + +