From fc6391a53dcda5cabcc9f61947da4ab0aea4aadf Mon Sep 17 00:00:00 2001 From: Julie Blanc Date: Thu, 5 Mar 2026 10:45:55 +0100 Subject: [PATCH] =?UTF-8?q?margins=20+=E2=80=AFpaddings=20in=20pop=20vue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ElementPopup.vue | 319 ++++++++++++++++++++++++++++---- 1 file changed, 279 insertions(+), 40 deletions(-) diff --git a/src/components/ElementPopup.vue b/src/components/ElementPopup.vue index 96209ed..d08d610 100644 --- a/src/components/ElementPopup.vue +++ b/src/components/ElementPopup.vue @@ -139,32 +139,54 @@
-
- +
+ Marges extérieures + +
+
+
+ @click="updateMarginUnit(side.key, 'mm')" + >mm + @click="updateMarginUnit(side.key, 'px')" + >px
@@ -172,32 +194,54 @@
-
- +
+ Marges intérieures + +
+
+
+ @click="updatePaddingUnit(side.key, 'mm')" + >mm + @click="updatePaddingUnit(side.key, 'px')" + >px
@@ -246,8 +290,22 @@ const color = ref('rgb(0, 0, 0)'); const background = ref('transparent'); const fontSize = reactive({ value: 23, unit: 'px' }); const lineHeight = reactive({ value: 28, unit: 'px' }); -const marginOuter = reactive({ value: 0, unit: 'mm' }); -const paddingInner = reactive({ value: 0, unit: 'mm' }); + +const marginLocked = ref(true); +const margin = reactive({ + top: { value: 0, unit: 'mm' }, + right: { value: 0, unit: 'mm' }, + bottom: { value: 0, unit: 'mm' }, + left: { value: 0, unit: 'mm' }, +}); + +const paddingLocked = ref(true); +const padding = reactive({ + top: { value: 0, unit: 'mm' }, + right: { value: 0, unit: 'mm' }, + bottom: { value: 0, unit: 'mm' }, + left: { value: 0, unit: 'mm' }, +}); // Constants const fonts = ['Alegreya Sans', 'Alegreya', 'Arial', 'Georgia', 'Times New Roman']; @@ -271,10 +329,55 @@ const styleProps = [ const unitProps = [ { css: 'font-size', ref: fontSize, debounce: true }, { css: 'line-height', ref: lineHeight, debounce: true }, - { css: 'margin', ref: marginOuter, debounce: true }, - { css: 'padding', ref: paddingInner, debounce: true }, ]; +const sides = [ + { key: 'top', label: 'Haut' }, + { key: 'bottom', label: 'Bas' }, + { key: 'left', label: 'Gauche' }, + { key: 'right', label: 'Droite' }, +]; + +const updateMarginValue = (side, value) => { + if (marginLocked.value) { + for (const s of ['top', 'right', 'bottom', 'left']) margin[s].value = value; + } else { + margin[side].value = value; + } +}; + +const updateMarginUnit = (side, unit) => { + if (marginLocked.value) { + for (const s of ['top', 'right', 'bottom', 'left']) { + margin[s].value = convertUnit(margin[s].value, margin[s].unit, unit); + margin[s].unit = unit; + } + } else { + margin[side].value = convertUnit(margin[side].value, margin[side].unit, unit); + margin[side].unit = unit; + } +}; + +const updatePaddingValue = (side, value) => { + if (paddingLocked.value) { + for (const s of ['top', 'right', 'bottom', 'left']) padding[s].value = value; + } else { + padding[side].value = value; + } +}; + +const updatePaddingUnit = (side, unit) => { + if (paddingLocked.value) { + for (const s of ['top', 'right', 'bottom', 'left']) { + padding[s].value = convertUnit(padding[s].value, padding[s].unit, unit); + padding[s].unit = unit; + } + } else { + padding[side].value = convertUnit(padding[side].value, padding[side].unit, unit); + padding[side].unit = unit; + } +}; + // Generic update: push a single property to the stylesheet store const updateProp = (cssProp, value, unit) => { if (!selector.value) return; @@ -336,6 +439,17 @@ const generatePreviewCss = () => { } } + for (const side of ['top', 'right', 'bottom', 'left']) { + if (margin[side].value !== undefined && margin[side].value !== null) { + properties.push(` margin-${side}: ${margin[side].value}${margin[side].unit};`); + } + } + for (const side of ['top', 'right', 'bottom', 'left']) { + if (padding[side].value !== undefined && padding[side].value !== null) { + properties.push(` padding-${side}: ${padding[side].value}${padding[side].unit};`); + } + } + if (properties.length === 0) return ''; return `${selector.value} {\n${properties.join('\n')}\n}`; @@ -364,6 +478,10 @@ const applyAllStyles = () => { for (const prop of unitProps) { updateProp(prop.css, prop.ref.value, prop.ref.unit); } + for (const side of ['top', 'right', 'bottom', 'left']) { + updateProp(`margin-${side}`, margin[side].value, margin[side].unit); + updateProp(`padding-${side}`, padding[side].value, padding[side].unit); + } }; // Watchers — simple props @@ -388,6 +506,50 @@ for (const prop of unitProps) { }); } +// Watchers — margin sides +watch( + () => [margin.top.value, margin.right.value, margin.bottom.value, margin.left.value], + () => { + if (isUpdatingFromStore) return; + debouncedUpdate(() => { + for (const side of ['top', 'right', 'bottom', 'left']) { + updateProp(`margin-${side}`, margin[side].value, margin[side].unit); + } + }); + } +); +watch( + () => [margin.top.unit, margin.right.unit, margin.bottom.unit, margin.left.unit], + () => { + if (isUpdatingFromStore) return; + for (const side of ['top', 'right', 'bottom', 'left']) { + updateProp(`margin-${side}`, margin[side].value, margin[side].unit); + } + } +); + +// Watchers — padding sides +watch( + () => [padding.top.value, padding.right.value, padding.bottom.value, padding.left.value], + () => { + if (isUpdatingFromStore) return; + debouncedUpdate(() => { + for (const side of ['top', 'right', 'bottom', 'left']) { + updateProp(`padding-${side}`, padding[side].value, padding[side].unit); + } + }); + } +); +watch( + () => [padding.top.unit, padding.right.unit, padding.bottom.unit, padding.left.unit], + () => { + if (isUpdatingFromStore) return; + for (const side of ['top', 'right', 'bottom', 'left']) { + updateProp(`padding-${side}`, padding[side].value, padding[side].unit); + } + } +); + const handleCssInput = (newCss) => { const oldBlock = elementCss.value; if (oldBlock) { @@ -440,6 +602,47 @@ const loadValuesFromStylesheet = () => { prop.ref.unit = data.unit; } } + + // Margin sides — try individual first, fallback to shorthand + const spacingSides = ['top', 'right', 'bottom', 'left']; + let anyMarginFound = false; + for (const side of spacingSides) { + const data = stylesheetStore.extractValue(selector.value, `margin-${side}`); + if (data && data.value !== undefined) { + margin[side].value = data.value; + margin[side].unit = data.unit; + anyMarginFound = true; + } + } + if (!anyMarginFound) { + const data = stylesheetStore.extractValue(selector.value, 'margin'); + if (data && data.value !== undefined) { + for (const side of spacingSides) { + margin[side].value = data.value; + margin[side].unit = data.unit; + } + } + } + + // Padding sides — try individual first, fallback to shorthand + let anyPaddingFound = false; + for (const side of spacingSides) { + const data = stylesheetStore.extractValue(selector.value, `padding-${side}`); + if (data && data.value !== undefined) { + padding[side].value = data.value; + padding[side].unit = data.unit; + anyPaddingFound = true; + } + } + if (!anyPaddingFound) { + const data = stylesheetStore.extractValue(selector.value, 'padding'); + if (data && data.value !== undefined) { + for (const side of spacingSides) { + padding[side].value = data.value; + padding[side].unit = data.unit; + } + } + } } catch (error) { console.error('Error loading values from stylesheet:', error); } @@ -517,16 +720,18 @@ const toggleInheritance = () => { color.value = cs.color; background.value = cs.backgroundColor; - const marginMatch = cs.marginTop.match(/([\d.]+)(px|mm|pt)/); - if (marginMatch) { - marginOuter.value = parseFloat(marginMatch[1]); - marginOuter.unit = marginMatch[2]; - } - - const paddingMatch = cs.paddingTop.match(/([\d.]+)(px|mm|pt)/); - if (paddingMatch) { - paddingInner.value = parseFloat(paddingMatch[1]); - paddingInner.unit = paddingMatch[2]; + for (const side of ['top', 'right', 'bottom', 'left']) { + const cssSide = side.charAt(0).toUpperCase() + side.slice(1); + const marginMatch = cs[`margin${cssSide}`].match(/([\d.]+)(px|mm|pt)/); + if (marginMatch) { + margin[side].value = parseFloat(marginMatch[1]); + margin[side].unit = marginMatch[2]; + } + const paddingMatch = cs[`padding${cssSide}`].match(/([\d.]+)(px|mm|pt)/); + if (paddingMatch) { + padding[side].value = parseFloat(paddingMatch[1]); + padding[side].unit = paddingMatch[2]; + } } isUpdatingFromStore = false; @@ -558,4 +763,38 @@ defineExpose({ handleIframeClick, close, visible }); color: var(--color-purple); font-size: 0.875rem; } + +.settings-subsection-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 0.25rem; +} + +.lock-toggle { + display: flex; + align-items: center; + justify-content: center; + background: none; + border: 1px solid transparent; + border-radius: 3px; + cursor: pointer; + padding: 2px 4px; + color: var(--color-text-muted, #999); + transition: color 0.15s, border-color 0.15s; +} + +.lock-toggle:hover:not(:disabled) { + color: var(--color-text, #333); + border-color: var(--color-border, #ccc); +} + +.lock-toggle.locked { + color: var(--color-purple, #7c3aed); +} + +.lock-toggle:disabled { + opacity: 0.4; + cursor: not-allowed; +}