diff --git a/src/components/ElementPopup.vue b/src/components/ElementPopup.vue index bfc2cf5..d79aedf 100644 --- a/src/components/ElementPopup.vue +++ b/src/components/ElementPopup.vue @@ -3,7 +3,7 @@ ref="basePopup" id="element-popup" :display-css="displayedCss" - :editable-css="elementCss" + :editable-css="editableFullCss" :popup-width="800" :popup-height="600" :show-inheritance="false" @@ -596,6 +596,12 @@ const displayedCss = computed(() => { return `${selector.value} {\n${lines.join('\n')}\n}`; }); +// Editable CSS: same as displayedCss but without "valeur par défaut" comments +// Special group defaults are always visible in edit mode so the user can modify them +const editableFullCss = computed(() => { + return displayedCss.value.replace(/ \/\* valeur par défaut \*\//g, ''); +}); + // Apply all properties for a given group to the stylesheet const applyGroup = (group) => { if (!selector.value) return; @@ -822,8 +828,45 @@ const parseCssProperties = (cssText) => { return result; }; +// Check if a special group's parsed CSS value differs from its textDefaults value +const specialGroupDiffersFromDefault = (group, parsed) => { + switch (group) { + case 'font': { + if ('font-family' in parsed) { + const val = parsed['font-family'].split(',')[0].trim().replace(/['"]/g, ''); + if (val !== textDefaults.fontFamily) return true; + } + if ('font-style' in parsed && parsed['font-style'].trim() === 'italic') return true; + if ('font-weight' in parsed) { + const v = parsed['font-weight'].trim(); + if (v === 'bold' || parseInt(v) >= 700) return true; + } + return false; + } + case 'fontSize': { + if ('font-size' in parsed) { + const m = parsed['font-size'].match(/([\d.]+)(px|rem|em|mm|cm|in)?/); + if (m) return parseFloat(m[1]) !== textDefaults.fontSize.value || (m[2] || 'px') !== textDefaults.fontSize.unit; + } + return false; + } + case 'lineHeight': { + if ('line-height' in parsed) { + const m = parsed['line-height'].match(/([\d.]+)(px|rem|em|mm|cm|in)?/); + if (m) return parseFloat(m[1]) !== textDefaults.lineHeight.value || (m[2] || 'px') !== textDefaults.lineHeight.unit; + } + return false; + } + case 'color': { + if ('color' in parsed) return parsed['color'].trim() !== textDefaults.color; + return false; + } + } + return false; +}; + // Sync refs from edited CSS text (bidirectional: textarea → inputs) -// For special groups: if user adds/modifies a property, it becomes a "user value" (toggle ON) +// For special groups: only enable toggle if value differs from default const syncRefsFromCss = (cssText) => { const parsed = parseCssProperties(cssText); const specialGroupNames = ['font', 'fontSize', 'lineHeight', 'color']; @@ -836,7 +879,6 @@ const syncRefsFromCss = (cssText) => { for (const prop of styleProps) { if (prop.group !== group || !(prop.css in parsed)) continue; if (prop.css === 'font-family') { - // Take first font from the stack, strip quotes const firstFont = parsed[prop.css].split(',')[0].trim().replace(/['"]/g, ''); fontFamily.value = firstFont; } else { @@ -868,17 +910,22 @@ const syncRefsFromCss = (cssText) => { } } - // Auto-enable toggle if it was OFF (user explicitly wrote the property) + // Auto-enable toggle if it was OFF if (!settingEnabled[group]) { - settingEnabled[group] = true; if (specialGroupNames.includes(group)) { - settingCache[group] = null; + // Special groups: only enable if value differs from default + if (specialGroupDiffersFromDefault(group, parsed)) { + settingEnabled[group] = true; + settingCache[group] = null; + } + } else { + settingEnabled[group] = true; } } } else if (settingEnabled[group]) { // All properties from this group were removed → disable toggle settingEnabled[group] = false; - // For special groups, reset to defaults (user intentionally removed) + // For special groups, reset to defaults if (group === 'font') { fontFamily.value = textDefaults.fontFamily; italic.value = false; @@ -904,15 +951,48 @@ const syncRefsFromCss = (cssText) => { const handleCssInput = (newCss) => { isUpdatingFromStore = true; + + // Sync refs and toggles from the edited CSS + syncRefsFromCss(newCss); + + // Build store block: exclude disabled special group properties + // (they are shown in the textarea as defaults but should not be persisted) + const parsed = parseCssProperties(newCss); + const specialGroupPropsMap = { + font: ['font-family', 'font-style', 'font-weight'], + fontSize: ['font-size'], + lineHeight: ['line-height'], + color: ['color'], + }; + const excludedProps = new Set(); + for (const [group, props] of Object.entries(specialGroupPropsMap)) { + if (!settingEnabled[group]) { + props.forEach(p => excludedProps.add(p)); + } + } + + const storeParts = []; + for (const [prop, val] of Object.entries(parsed)) { + if (!excludedProps.has(prop)) { + storeParts.push(` ${prop}: ${val};`); + } + } + + const storeBlock = storeParts.length + ? `${selector.value} {\n${storeParts.join('\n')}\n}\n` + : ''; + const oldBlock = elementCss.value; - if (oldBlock) { - stylesheetStore.replaceInCustomCss(oldBlock, newCss); - } else if (newCss.trim()) { + if (oldBlock && storeBlock) { + stylesheetStore.replaceInCustomCss(oldBlock, storeBlock); + } else if (oldBlock && !storeBlock) { + stylesheetStore.replaceInCustomCss(oldBlock, ''); + } else if (!oldBlock && storeBlock) { stylesheetStore.setCustomCss( - (stylesheetStore.customCss ? stylesheetStore.customCss + '\n' : '') + newCss + (stylesheetStore.customCss ? stylesheetStore.customCss + '\n' : '') + storeBlock ); } - syncRefsFromCss(newCss); + nextTick(() => { isUpdatingFromStore = false; }); };