font-size, line-height, color → defaults values

This commit is contained in:
Julie Blanc 2026-03-05 15:59:38 +01:00
parent fa56118e75
commit 8b99326de2
3 changed files with 127 additions and 89 deletions

View file

@ -307,13 +307,7 @@ const color = ref('rgb(0, 0, 0)');
const background = ref('transparent');
const fontSize = reactive({ value: 23, unit: 'px' });
const fontSizeModel = computed({
get: () => {
if (!settingEnabled.fontSize) {
// When disabled, display TextSettings' current value reactively
return { ...textDefaults.fontSize };
}
return { value: fontSize.value, unit: fontSize.unit };
},
get: () => ({ value: fontSize.value, unit: fontSize.unit }),
set: (v) => { fontSize.value = v.value; fontSize.unit = v.unit; },
});
const lineHeight = reactive({ value: 28, unit: 'px' });
@ -345,18 +339,18 @@ const padding = reactive({
const settingCache = reactive({
font: null, // { fontFamily, italic, bold }
fontSize: null, // { value, unit }
lineHeight: null, // { value, unit }
color: null, // string
});
// Per-subsection toggle state
// Special groups (font, fontSize, color): checked by default
// Other groups: unchecked by default
// Per-subsection toggle state all unchecked by default
// Special groups (font, fontSize, lineHeight, color) appear in popup-css with "valeur par défaut" comment
const settingEnabled = reactive({
font: true,
fontSize: true,
font: false,
fontSize: false,
lineHeight: false,
textAlign: false,
color: true,
color: false,
background: false,
border: false,
margin: false,
@ -552,7 +546,45 @@ const generatePreviewCss = () => {
const displayedCss = computed(() => {
if (!selector.value) return '';
return elementCss.value || generatePreviewCss();
let base = elementCss.value || generatePreviewCss();
if (!base) base = `${selector.value} {\n}`;
// Special groups config for displayedCss annotation
const specialDisplayProps = [
{ group: 'fontSize', css: 'font-size', getValue: () => `${(settingEnabled.fontSize ? fontSize : textDefaults.fontSize).value}${(settingEnabled.fontSize ? fontSize : textDefaults.fontSize).unit}` },
{ group: 'lineHeight', css: 'line-height', getValue: () => `${(settingEnabled.lineHeight ? lineHeight : textDefaults.lineHeight).value}${(settingEnabled.lineHeight ? lineHeight : textDefaults.lineHeight).unit}` },
{ group: 'color', css: 'color', getValue: () => settingEnabled.color ? color.value : textDefaults.color },
{ group: 'font', css: 'font-family', getValue: () => `"${settingEnabled.font ? fontFamily.value : textDefaults.fontFamily}"` },
];
// For disabled special groups: annotate existing lines with comment
// For enabled special groups: remove stale comments
for (const sp of specialDisplayProps) {
if (!settingEnabled[sp.group] && base.includes(sp.css + ':')) {
const escaped = sp.css.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
base = base.replace(new RegExp(`(${escaped}:\\s*[^;]+;)(?!\\s*\\/\\*)`), '$1 /* valeur par défaut */');
}
if (settingEnabled[sp.group]) {
const escaped = sp.css.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
base = base.replace(new RegExp(`(${escaped}:\\s*[^;]+;)\\s*\\/\\* valeur par défaut \\*\\/`), '$1');
}
}
// Inject missing special properties (if not yet in block at all)
const toInject = [];
for (const sp of specialDisplayProps) {
if (!base.includes(sp.css + ':')) {
const comment = !settingEnabled[sp.group] ? ' /* valeur par défaut */' : '';
toInject.push(` ${sp.css}: ${sp.getValue()};${comment}`);
}
}
if (toInject.length > 0) {
base = base.replace(/\}\s*$/, toInject.join('\n') + '\n}');
}
return base;
});
// Apply all properties for a given group to the stylesheet
@ -587,22 +619,15 @@ const applyAllEnabledGroups = () => {
};
// When unchecking a special group: save element value, load TextSettings fallback for display
const saveToCacheAndLoadFallback = (group) => {
const saveToCache = (group) => {
if (group === 'fontSize') {
settingCache.fontSize = { value: fontSize.value, unit: fontSize.unit };
// Display is handled reactively by fontSizeModel computed
} else if (group === 'lineHeight') {
settingCache.lineHeight = { value: lineHeight.value, unit: lineHeight.unit };
} else if (group === 'font') {
settingCache.font = { fontFamily: fontFamily.value, italic: italic.value, bold: bold.value };
const ff = cssExtractValue('body', 'font-family');
if (ff) fontFamily.value = ff.replace(/['"]/g, '');
const fs = cssExtractValue('p', 'font-style');
if (fs) italic.value = fs === 'italic';
const fw = cssExtractValue('p', 'font-weight');
if (fw) bold.value = fw === 'bold' || parseInt(fw) >= 700;
} else if (group === 'color') {
settingCache.color = color.value;
const c = cssExtractValue('body', 'color');
if (c) color.value = c;
}
};
@ -612,6 +637,10 @@ const restoreFromCache = (group) => {
fontSize.value = settingCache.fontSize.value;
fontSize.unit = settingCache.fontSize.unit;
settingCache.fontSize = null;
} else if (group === 'lineHeight' && settingCache.lineHeight) {
lineHeight.value = settingCache.lineHeight.value;
lineHeight.unit = settingCache.lineHeight.unit;
settingCache.lineHeight = null;
} else if (group === 'font' && settingCache.font) {
fontFamily.value = settingCache.font.fontFamily;
italic.value = settingCache.font.italic;
@ -623,18 +652,38 @@ const restoreFromCache = (group) => {
}
};
// Replace a special group's CSS values with TextSettings defaults
const applyDefaultsForGroup = (group) => {
if (!selector.value) return;
if (group === 'fontSize') {
updateProp('font-size', textDefaults.fontSize.value, textDefaults.fontSize.unit);
} else if (group === 'lineHeight') {
updateProp('line-height', textDefaults.lineHeight.value, textDefaults.lineHeight.unit);
} else if (group === 'color') {
updateProp('color', textDefaults.color);
} else if (group === 'font') {
updateProp('font-family', `"${textDefaults.fontFamily}"`);
removeProps(['font-style', 'font-weight']);
}
};
// Toggle a setting group on/off
const onToggleSetting = (group, enabled) => {
settingEnabled[group] = enabled;
if (enabled) {
isUpdatingFromStore = true;
if (enabled) {
restoreFromCache(group);
isUpdatingFromStore = false;
applyAllEnabledGroups();
} else {
saveToCacheAndLoadFallback(group);
saveToCache(group);
const specialGroups = ['font', 'fontSize', 'lineHeight', 'color'];
if (specialGroups.includes(group)) {
applyDefaultsForGroup(group);
} else {
removeProps(settingGroups[group]);
}
}
nextTick(() => { isUpdatingFromStore = false; });
};
// Watchers simple props (with group guard)
@ -744,19 +793,6 @@ watch(
const loadValuesFromStylesheet = (isInitialLoad = false) => {
if (!selector.value) return;
if (isInitialLoad) {
// Reset settingEnabled to defaults only on initial open
settingEnabled.font = true;
settingEnabled.fontSize = true;
settingEnabled.lineHeight = false;
settingEnabled.textAlign = false;
settingEnabled.color = true;
settingEnabled.background = false;
settingEnabled.border = false;
settingEnabled.margin = false;
settingEnabled.padding = false;
}
const groupsFound = new Set();
// Only detect settingEnabled from the custom CSS block (not baseCss fallback)
@ -841,19 +877,9 @@ const loadValuesFromStylesheet = (isInitialLoad = false) => {
}
if (anyPaddingFound) groupsFound.add('padding');
// Update settingEnabled based on what was found in the element's CSS
if (isInitialLoad) {
for (const group of ['lineHeight', 'textAlign', 'background', 'border', 'margin', 'padding']) {
settingEnabled[group] = groupsFound.has(group);
}
} else {
// During live sync: only enable groups newly found in CSS, never override user's manual toggles
for (const group of Object.keys(settingEnabled)) {
if (groupsFound.has(group)) settingEnabled[group] = true;
}
}
// settingEnabled is NEVER modified automatically only by user toggle clicks
// Special groups: font, fontSize, color always enabled
// Special groups: font, fontSize, color
// If not found in element CSS, load fallback values from TextSettings selectors
// Only on initial open during live sync, ElementPopup is independent from TextSettings
if (isInitialLoad) {
@ -874,6 +900,14 @@ const loadValuesFromStylesheet = (isInitialLoad = false) => {
}
}
if (!groupsFound.has('lineHeight')) {
const data = stylesheetStore.extractValue('p', 'line-height');
if (data && data.value !== undefined) {
lineHeight.value = data.value;
lineHeight.unit = data.unit;
}
}
if (!groupsFound.has('color')) {
const c = stylesheetStore.extractValue('body', 'color');
if (c) color.value = typeof c === 'string' ? c : c.value;
@ -886,9 +920,15 @@ const loadValuesFromStylesheet = (isInitialLoad = false) => {
};
const open = (element, event, count = null) => {
// Reset all toggles to unchecked for each new element
for (const group of Object.keys(settingEnabled)) {
settingEnabled[group] = false;
}
// Clear cache from any previous element
settingCache.font = null;
settingCache.fontSize = null;
settingCache.lineHeight = null;
settingCache.color = null;
isUpdatingFromStore = true;

View file

@ -16,14 +16,6 @@
<select id="text-font" v-model="font" disabled class="field--view-only" title="Fonctionnalité à venir">
<option v-for="f in fonts" :key="f" :value="f">{{ f }}</option>
</select>
<div class="field-checkbox">
<input id="text-italic" type="checkbox" v-model="italic" />
<label for="text-italic" class="label-with-tooltip" data-css="font-style">Italique</label>
</div>
<div class="field-checkbox">
<input id="text-bold" type="checkbox" v-model="bold" />
<label for="text-bold" class="label-with-tooltip" data-css="font-weight">Gras</label>
</div>
</div>
</div>
</div>
@ -42,6 +34,20 @@
</div>
</div>
<!-- Interlignage -->
<div class="settings-subsection">
<div class="field field-text-size">
<label for="text-lineheight-range" class="label-with-tooltip" data-css="line-height">Interlignage</label>
<InputWithUnit
v-model="lineHeight"
:units="['px']"
:min="0"
:max="72"
showRange
/>
</div>
</div>
<!-- Couleurs -->
<div class="settings-subsection">
<div class="field field-simple">
@ -83,9 +89,8 @@ const fonts = ['Alegreya Sans', 'Arial', 'Georgia', 'Helvetica', 'Times New Roma
// State
const font = ref('Alegreya Sans');
const italic = ref(false);
const bold = ref(false);
const fontSize = ref({ value: 16, unit: 'px' });
const lineHeight = ref({ value: 20, unit: 'px' });
const color = ref('rgb(0, 0, 0)');
const colorInput = ref(null);
@ -93,25 +98,16 @@ let isUpdatingFromStore = false;
// Watchers for body styles
watch(font, (val) => {
textDefaults.fontFamily = val;
if (isUpdatingFromStore) return;
updateStyle('body', 'font-family', `"${val}"`);
});
watch(italic, (val) => {
if (isUpdatingFromStore) return;
updateStyle('p', 'font-style', val ? 'italic' : 'normal');
});
}, { immediate: true });
watch(color, (val) => {
textDefaults.color = val;
if (isUpdatingFromStore) return;
updateStyle('body', 'color', val);
});
// Watchers for paragraph styles
watch(bold, (val) => {
if (isUpdatingFromStore) return;
updateStyle('p', 'font-weight', val ? 'bold' : 'normal');
});
}, { immediate: true });
watch(fontSize, (val) => {
textDefaults.fontSize = { value: val.value, unit: val.unit };
@ -121,25 +117,28 @@ watch(fontSize, (val) => {
});
}, { deep: true, immediate: true });
watch(lineHeight, (val) => {
textDefaults.lineHeight = { value: val.value, unit: val.unit };
if (isUpdatingFromStore) return;
debouncedUpdate(() => {
updateStyle('p', 'line-height', `${val.value}${val.unit}`);
});
}, { deep: true, immediate: true });
// Sync from store
const syncFromStore = () => {
isUpdatingFromStore = true;
// Body styles
const fontStyle = extractValue('p', 'font-style');
if (fontStyle) italic.value = fontStyle === 'italic';
const colorVal = extractValue('body', 'color');
if (colorVal) color.value = colorVal;
// Paragraph styles
const fontWeight = extractValue('p', 'font-weight');
if (fontWeight) bold.value = fontWeight === 'bold' || parseInt(fontWeight) >= 700;
const fontSizeVal = extractNumericValue('p', 'font-size', ['px']); // ['px', 'em', 'rem']
if (fontSizeVal) fontSize.value = fontSizeVal;
const lineHeightVal = extractNumericValue('p', 'line-height', ['px']);
if (lineHeightVal) lineHeight.value = lineHeightVal;
isUpdatingFromStore = false;
};

View file

@ -3,9 +3,8 @@ import { reactive } from 'vue';
// Singleton reactive — TextSettings writes here, ElementPopup reads when disabled
const defaults = reactive({
fontSize: { value: 16, unit: 'px' },
lineHeight: { value: 20, unit: 'px' },
fontFamily: 'Alegreya Sans',
italic: false,
bold: false,
color: 'rgb(0, 0, 0)',
});