font-size, line-height, color → defaults values
This commit is contained in:
parent
fa56118e75
commit
8b99326de2
3 changed files with 127 additions and 89 deletions
|
|
@ -307,13 +307,7 @@ const color = ref('rgb(0, 0, 0)');
|
||||||
const background = ref('transparent');
|
const background = ref('transparent');
|
||||||
const fontSize = reactive({ value: 23, unit: 'px' });
|
const fontSize = reactive({ value: 23, unit: 'px' });
|
||||||
const fontSizeModel = computed({
|
const fontSizeModel = computed({
|
||||||
get: () => {
|
get: () => ({ value: fontSize.value, unit: fontSize.unit }),
|
||||||
if (!settingEnabled.fontSize) {
|
|
||||||
// When disabled, display TextSettings' current value reactively
|
|
||||||
return { ...textDefaults.fontSize };
|
|
||||||
}
|
|
||||||
return { value: fontSize.value, unit: fontSize.unit };
|
|
||||||
},
|
|
||||||
set: (v) => { fontSize.value = v.value; fontSize.unit = v.unit; },
|
set: (v) => { fontSize.value = v.value; fontSize.unit = v.unit; },
|
||||||
});
|
});
|
||||||
const lineHeight = reactive({ value: 28, unit: 'px' });
|
const lineHeight = reactive({ value: 28, unit: 'px' });
|
||||||
|
|
@ -343,20 +337,20 @@ const padding = reactive({
|
||||||
|
|
||||||
// Cache for special groups values when unchecked (to restore on re-check)
|
// Cache for special groups values when unchecked (to restore on re-check)
|
||||||
const settingCache = reactive({
|
const settingCache = reactive({
|
||||||
font: null, // { fontFamily, italic, bold }
|
font: null, // { fontFamily, italic, bold }
|
||||||
fontSize: null, // { value, unit }
|
fontSize: null, // { value, unit }
|
||||||
color: null, // string
|
lineHeight: null, // { value, unit }
|
||||||
|
color: null, // string
|
||||||
});
|
});
|
||||||
|
|
||||||
// Per-subsection toggle state
|
// Per-subsection toggle state — all unchecked by default
|
||||||
// Special groups (font, fontSize, color): checked by default
|
// Special groups (font, fontSize, lineHeight, color) appear in popup-css with "valeur par défaut" comment
|
||||||
// Other groups: unchecked by default
|
|
||||||
const settingEnabled = reactive({
|
const settingEnabled = reactive({
|
||||||
font: true,
|
font: false,
|
||||||
fontSize: true,
|
fontSize: false,
|
||||||
lineHeight: false,
|
lineHeight: false,
|
||||||
textAlign: false,
|
textAlign: false,
|
||||||
color: true,
|
color: false,
|
||||||
background: false,
|
background: false,
|
||||||
border: false,
|
border: false,
|
||||||
margin: false,
|
margin: false,
|
||||||
|
|
@ -552,7 +546,45 @@ const generatePreviewCss = () => {
|
||||||
|
|
||||||
const displayedCss = computed(() => {
|
const displayedCss = computed(() => {
|
||||||
if (!selector.value) return '';
|
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
|
// 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
|
// When unchecking a special group: save element value, load TextSettings fallback for display
|
||||||
const saveToCacheAndLoadFallback = (group) => {
|
const saveToCache = (group) => {
|
||||||
if (group === 'fontSize') {
|
if (group === 'fontSize') {
|
||||||
settingCache.fontSize = { value: fontSize.value, unit: fontSize.unit };
|
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') {
|
} else if (group === 'font') {
|
||||||
settingCache.font = { fontFamily: fontFamily.value, italic: italic.value, bold: bold.value };
|
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') {
|
} else if (group === 'color') {
|
||||||
settingCache.color = color.value;
|
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.value = settingCache.fontSize.value;
|
||||||
fontSize.unit = settingCache.fontSize.unit;
|
fontSize.unit = settingCache.fontSize.unit;
|
||||||
settingCache.fontSize = null;
|
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) {
|
} else if (group === 'font' && settingCache.font) {
|
||||||
fontFamily.value = settingCache.font.fontFamily;
|
fontFamily.value = settingCache.font.fontFamily;
|
||||||
italic.value = settingCache.font.italic;
|
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
|
// Toggle a setting group on/off
|
||||||
const onToggleSetting = (group, enabled) => {
|
const onToggleSetting = (group, enabled) => {
|
||||||
settingEnabled[group] = enabled;
|
settingEnabled[group] = enabled;
|
||||||
|
isUpdatingFromStore = true;
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
isUpdatingFromStore = true;
|
|
||||||
restoreFromCache(group);
|
restoreFromCache(group);
|
||||||
isUpdatingFromStore = false;
|
|
||||||
applyAllEnabledGroups();
|
applyAllEnabledGroups();
|
||||||
} else {
|
} else {
|
||||||
saveToCacheAndLoadFallback(group);
|
saveToCache(group);
|
||||||
removeProps(settingGroups[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)
|
// Watchers — simple props (with group guard)
|
||||||
|
|
@ -744,19 +793,6 @@ watch(
|
||||||
const loadValuesFromStylesheet = (isInitialLoad = false) => {
|
const loadValuesFromStylesheet = (isInitialLoad = false) => {
|
||||||
if (!selector.value) return;
|
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();
|
const groupsFound = new Set();
|
||||||
|
|
||||||
// Only detect settingEnabled from the custom CSS block (not baseCss fallback)
|
// Only detect settingEnabled from the custom CSS block (not baseCss fallback)
|
||||||
|
|
@ -841,19 +877,9 @@ const loadValuesFromStylesheet = (isInitialLoad = false) => {
|
||||||
}
|
}
|
||||||
if (anyPaddingFound) groupsFound.add('padding');
|
if (anyPaddingFound) groupsFound.add('padding');
|
||||||
|
|
||||||
// Update settingEnabled based on what was found in the element's CSS
|
// settingEnabled is NEVER modified automatically — only by user toggle clicks
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special groups: font, fontSize, color — always enabled
|
// Special groups: font, fontSize, color
|
||||||
// If not found in element CSS, load fallback values from TextSettings selectors
|
// If not found in element CSS, load fallback values from TextSettings selectors
|
||||||
// Only on initial open — during live sync, ElementPopup is independent from TextSettings
|
// Only on initial open — during live sync, ElementPopup is independent from TextSettings
|
||||||
if (isInitialLoad) {
|
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')) {
|
if (!groupsFound.has('color')) {
|
||||||
const c = stylesheetStore.extractValue('body', 'color');
|
const c = stylesheetStore.extractValue('body', 'color');
|
||||||
if (c) color.value = typeof c === 'string' ? c : c.value;
|
if (c) color.value = typeof c === 'string' ? c : c.value;
|
||||||
|
|
@ -886,9 +920,15 @@ const loadValuesFromStylesheet = (isInitialLoad = false) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const open = (element, event, count = null) => {
|
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
|
// Clear cache from any previous element
|
||||||
settingCache.font = null;
|
settingCache.font = null;
|
||||||
settingCache.fontSize = null;
|
settingCache.fontSize = null;
|
||||||
|
settingCache.lineHeight = null;
|
||||||
settingCache.color = null;
|
settingCache.color = null;
|
||||||
|
|
||||||
isUpdatingFromStore = true;
|
isUpdatingFromStore = true;
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,6 @@
|
||||||
<select id="text-font" v-model="font" disabled class="field--view-only" title="Fonctionnalité à venir">
|
<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>
|
<option v-for="f in fonts" :key="f" :value="f">{{ f }}</option>
|
||||||
</select>
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -42,6 +34,20 @@
|
||||||
</div>
|
</div>
|
||||||
</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 -->
|
<!-- Couleurs -->
|
||||||
<div class="settings-subsection">
|
<div class="settings-subsection">
|
||||||
<div class="field field-simple">
|
<div class="field field-simple">
|
||||||
|
|
@ -83,9 +89,8 @@ const fonts = ['Alegreya Sans', 'Arial', 'Georgia', 'Helvetica', 'Times New Roma
|
||||||
|
|
||||||
// State
|
// State
|
||||||
const font = ref('Alegreya Sans');
|
const font = ref('Alegreya Sans');
|
||||||
const italic = ref(false);
|
|
||||||
const bold = ref(false);
|
|
||||||
const fontSize = ref({ value: 16, unit: 'px' });
|
const fontSize = ref({ value: 16, unit: 'px' });
|
||||||
|
const lineHeight = ref({ value: 20, unit: 'px' });
|
||||||
const color = ref('rgb(0, 0, 0)');
|
const color = ref('rgb(0, 0, 0)');
|
||||||
const colorInput = ref(null);
|
const colorInput = ref(null);
|
||||||
|
|
||||||
|
|
@ -93,25 +98,16 @@ let isUpdatingFromStore = false;
|
||||||
|
|
||||||
// Watchers for body styles
|
// Watchers for body styles
|
||||||
watch(font, (val) => {
|
watch(font, (val) => {
|
||||||
|
textDefaults.fontFamily = val;
|
||||||
if (isUpdatingFromStore) return;
|
if (isUpdatingFromStore) return;
|
||||||
updateStyle('body', 'font-family', `"${val}"`);
|
updateStyle('body', 'font-family', `"${val}"`);
|
||||||
});
|
}, { immediate: true });
|
||||||
|
|
||||||
watch(italic, (val) => {
|
|
||||||
if (isUpdatingFromStore) return;
|
|
||||||
updateStyle('p', 'font-style', val ? 'italic' : 'normal');
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(color, (val) => {
|
watch(color, (val) => {
|
||||||
|
textDefaults.color = val;
|
||||||
if (isUpdatingFromStore) return;
|
if (isUpdatingFromStore) return;
|
||||||
updateStyle('body', 'color', val);
|
updateStyle('body', 'color', val);
|
||||||
});
|
}, { immediate: true });
|
||||||
|
|
||||||
// Watchers for paragraph styles
|
|
||||||
watch(bold, (val) => {
|
|
||||||
if (isUpdatingFromStore) return;
|
|
||||||
updateStyle('p', 'font-weight', val ? 'bold' : 'normal');
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(fontSize, (val) => {
|
watch(fontSize, (val) => {
|
||||||
textDefaults.fontSize = { value: val.value, unit: val.unit };
|
textDefaults.fontSize = { value: val.value, unit: val.unit };
|
||||||
|
|
@ -121,25 +117,28 @@ watch(fontSize, (val) => {
|
||||||
});
|
});
|
||||||
}, { deep: true, immediate: true });
|
}, { 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
|
// Sync from store
|
||||||
const syncFromStore = () => {
|
const syncFromStore = () => {
|
||||||
isUpdatingFromStore = true;
|
isUpdatingFromStore = true;
|
||||||
|
|
||||||
// Body styles
|
|
||||||
const fontStyle = extractValue('p', 'font-style');
|
|
||||||
if (fontStyle) italic.value = fontStyle === 'italic';
|
|
||||||
|
|
||||||
const colorVal = extractValue('body', 'color');
|
const colorVal = extractValue('body', 'color');
|
||||||
if (colorVal) color.value = colorVal;
|
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']
|
const fontSizeVal = extractNumericValue('p', 'font-size', ['px']); // ['px', 'em', 'rem']
|
||||||
if (fontSizeVal) fontSize.value = fontSizeVal;
|
if (fontSizeVal) fontSize.value = fontSizeVal;
|
||||||
|
|
||||||
|
const lineHeightVal = extractNumericValue('p', 'line-height', ['px']);
|
||||||
|
if (lineHeightVal) lineHeight.value = lineHeightVal;
|
||||||
|
|
||||||
isUpdatingFromStore = false;
|
isUpdatingFromStore = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,8 @@ import { reactive } from 'vue';
|
||||||
// Singleton reactive — TextSettings writes here, ElementPopup reads when disabled
|
// Singleton reactive — TextSettings writes here, ElementPopup reads when disabled
|
||||||
const defaults = reactive({
|
const defaults = reactive({
|
||||||
fontSize: { value: 16, unit: 'px' },
|
fontSize: { value: 16, unit: 'px' },
|
||||||
|
lineHeight: { value: 20, unit: 'px' },
|
||||||
fontFamily: 'Alegreya Sans',
|
fontFamily: 'Alegreya Sans',
|
||||||
italic: false,
|
|
||||||
bold: false,
|
|
||||||
color: 'rgb(0, 0, 0)',
|
color: 'rgb(0, 0, 0)',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue