general mechanism for default css
This commit is contained in:
parent
ec1b23d67a
commit
fc227bf519
4 changed files with 126 additions and 40 deletions
|
|
@ -31,13 +31,18 @@ figure, img{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
h1{
|
/* h1{
|
||||||
font-size: 38px;
|
font-size: 38px;
|
||||||
background: rgba(255, 255, 255, 0.521);
|
background: rgba(255, 255, 255, 0.521);
|
||||||
padding: 10px 20px;
|
padding-top: 10px;
|
||||||
margin: 0;
|
padding-left: 20px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
padding-right: 20px;
|
||||||
|
margin-left: 0px;
|
||||||
|
margin-right: 0px;
|
||||||
|
margin-bottom: 0px;
|
||||||
margin-top: 60px;
|
margin-top: 60px;
|
||||||
}
|
} */
|
||||||
|
|
||||||
p.author{
|
p.author{
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
|
|
|
||||||
|
|
@ -267,71 +267,96 @@ export function useElementSettings({ margin, padding, basePopup }) {
|
||||||
|
|
||||||
const displayedCssOrder = [
|
const displayedCssOrder = [
|
||||||
{ css: 'font-family', group: 'font', special: true,
|
{ css: 'font-family', group: 'font', special: true,
|
||||||
getValue: () => { const val = settingEnabled.font ? fontFamily.value : textDefaults.fontFamily; return val === 'sans-serif' ? 'sans-serif' : `"${val}"`; } },
|
getValue: () => { const val = fontFamily.value; return val === 'sans-serif' ? 'sans-serif' : `"${val}"`; } },
|
||||||
{ css: 'font-style', group: 'font',
|
{ css: 'font-style', group: 'font',
|
||||||
getValue: () => italic.value ? 'italic' : (INLINE_DEFAULTS[currentTag.value]?.fontStyle || null),
|
getValue: () => italic.value ? 'italic' : (INLINE_DEFAULTS[currentTag.value]?.fontStyle || null),
|
||||||
skip: () => !italic.value && !INLINE_DEFAULTS[currentTag.value]?.fontStyle },
|
skip: () => !italic.value && !INLINE_DEFAULTS[currentTag.value]?.fontStyle && !hasInCss('font-style') },
|
||||||
{ css: 'font-weight', group: 'font',
|
{ css: 'font-weight', group: 'font',
|
||||||
getValue: () => bold.value ? 'bold' : (INLINE_DEFAULTS[currentTag.value]?.fontWeight || null),
|
getValue: () => bold.value ? 'bold' : (INLINE_DEFAULTS[currentTag.value]?.fontWeight || null),
|
||||||
skip: () => !bold.value && !INLINE_DEFAULTS[currentTag.value]?.fontWeight },
|
skip: () => !bold.value && !INLINE_DEFAULTS[currentTag.value]?.fontWeight && !hasInCss('font-weight') },
|
||||||
{ css: 'font-size', group: 'fontSize', special: true,
|
{ css: 'font-size', group: 'fontSize', special: true,
|
||||||
getValue: () => `${(settingEnabled.fontSize ? fontSize : textDefaults.fontSize).value}${(settingEnabled.fontSize ? fontSize : textDefaults.fontSize).unit}` },
|
getValue: () => `${fontSize.value}${fontSize.unit}` },
|
||||||
{ css: 'line-height', group: 'lineHeight', special: true,
|
{ css: 'line-height', group: 'lineHeight', special: true,
|
||||||
getValue: () => `${(settingEnabled.lineHeight ? lineHeight : textDefaults.lineHeight).value}${(settingEnabled.lineHeight ? lineHeight : textDefaults.lineHeight).unit}` },
|
getValue: () => `${lineHeight.value}${lineHeight.unit}` },
|
||||||
{ css: 'text-align', group: 'textAlign',
|
{ css: 'text-align', group: 'textAlign',
|
||||||
getValue: () => textAlign.value,
|
getValue: () => textAlign.value,
|
||||||
skip: () => !settingEnabled.textAlign },
|
skip: () => !settingEnabled.textAlign && !hasInCss('text-align') },
|
||||||
{ css: 'color', group: 'color', special: true,
|
{ css: 'color', group: 'color', special: true,
|
||||||
getValue: () => settingEnabled.color ? color.value : textDefaults.color },
|
getValue: () => color.value },
|
||||||
{ css: 'background', group: 'background',
|
{ css: 'background', group: 'background',
|
||||||
getValue: () => background.value,
|
getValue: () => background.value,
|
||||||
skip: () => !settingEnabled.background },
|
skip: () => !settingEnabled.background && !hasInCss('background') },
|
||||||
{ css: 'border-width', group: 'border',
|
{ css: 'border-width', group: 'border',
|
||||||
getValue: () => `${borderWidth.value}${borderWidth.unit}`,
|
getValue: () => `${borderWidth.value}${borderWidth.unit}`,
|
||||||
skip: () => !settingEnabled.border },
|
skip: () => !settingEnabled.border && !hasInCss('border-width') },
|
||||||
{ css: 'border-style', group: 'border',
|
{ css: 'border-style', group: 'border',
|
||||||
getValue: () => borderStyle.value,
|
getValue: () => borderStyle.value,
|
||||||
skip: () => !settingEnabled.border || borderWidth.value === 0 },
|
skip: () => (!settingEnabled.border && !hasInCss('border-style')) || borderWidth.value === 0 },
|
||||||
{ css: 'border-color', group: 'border',
|
{ css: 'border-color', group: 'border',
|
||||||
getValue: () => borderColor.value,
|
getValue: () => borderColor.value,
|
||||||
skip: () => !settingEnabled.border || borderWidth.value === 0 },
|
skip: () => (!settingEnabled.border && !hasInCss('border-color')) || borderWidth.value === 0 },
|
||||||
{ css: 'text-decoration-line', group: 'textDecoration',
|
{ css: 'text-decoration-line', group: 'textDecoration',
|
||||||
getValue: () => textDecorationLine.value,
|
getValue: () => textDecorationLine.value || (INLINE_DEFAULTS[currentTag.value]?.textDecorationLine || null),
|
||||||
skip: () => !settingEnabled.textDecoration },
|
skip: () => !settingEnabled.textDecoration && !INLINE_DEFAULTS[currentTag.value]?.textDecorationLine && !hasInCss('text-decoration-line') },
|
||||||
{ css: 'text-decoration-style', group: 'textDecoration',
|
{ css: 'text-decoration-style', group: 'textDecoration',
|
||||||
getValue: () => textDecorationStyle.value,
|
getValue: () => textDecorationStyle.value,
|
||||||
skip: () => !settingEnabled.textDecoration },
|
skip: () => !settingEnabled.textDecoration && !hasInCss('text-decoration-style') },
|
||||||
{ css: 'text-decoration-thickness', group: 'textDecoration',
|
{ css: 'text-decoration-thickness', group: 'textDecoration',
|
||||||
getValue: () => `${textDecorationThickness.value}${textDecorationThickness.unit}`,
|
getValue: () => `${textDecorationThickness.value}${textDecorationThickness.unit}`,
|
||||||
skip: () => !settingEnabled.textDecoration },
|
skip: () => !settingEnabled.textDecoration && !hasInCss('text-decoration-thickness') },
|
||||||
{ css: 'text-decoration-color', group: 'textDecoration',
|
{ css: 'text-decoration-color', group: 'textDecoration',
|
||||||
getValue: () => textDecorationColor.value,
|
getValue: () => textDecorationColor.value,
|
||||||
skip: () => !settingEnabled.textDecoration },
|
skip: () => !settingEnabled.textDecoration && !hasInCss('text-decoration-color') },
|
||||||
{ css: 'text-underline-offset', group: 'textDecoration',
|
{ css: 'text-underline-offset', group: 'textDecoration',
|
||||||
getValue: () => `${textUnderlineOffset.value}${textUnderlineOffset.unit}`,
|
getValue: () => `${textUnderlineOffset.value}${textUnderlineOffset.unit}`,
|
||||||
skip: () => !settingEnabled.textDecoration },
|
skip: () => !settingEnabled.textDecoration && !hasInCss('text-underline-offset') },
|
||||||
];
|
];
|
||||||
|
|
||||||
const isInlineElement = computed(() => !!INLINE_DEFAULTS[currentTag.value]);
|
const isInlineElement = computed(() => !!INLINE_DEFAULTS[currentTag.value]);
|
||||||
|
|
||||||
|
// Check if the current selector has a CSS property in the store
|
||||||
|
const hasInCss = (cssProp) => {
|
||||||
|
if (!selector.value) return false;
|
||||||
|
return !!stylesheetStore.extractValue(selector.value, cssProp);
|
||||||
|
};
|
||||||
|
|
||||||
const displayedCss = computed(() => {
|
const displayedCss = computed(() => {
|
||||||
if (!selector.value) return '';
|
if (!selector.value) return '';
|
||||||
const lines = [];
|
const lines = [];
|
||||||
for (const entry of displayedCssOrder) {
|
for (const entry of displayedCssOrder) {
|
||||||
if (entry.skip && entry.skip()) continue;
|
if (entry.skip && entry.skip()) continue;
|
||||||
// For inline elements, skip special groups (TextSettings defaults) when toggle is OFF
|
// For inline elements, skip special groups (TextSettings defaults) when toggle is OFF
|
||||||
if (entry.special && isInlineElement.value && !settingEnabled[entry.group]) continue;
|
// Exception: keep if the current tag has an inline default for this CSS property
|
||||||
|
if (entry.special && isInlineElement.value && !settingEnabled[entry.group]) {
|
||||||
|
const tagDefaults = INLINE_DEFAULTS[currentTag.value];
|
||||||
|
const cssToDefaultKey = { 'color': 'color', 'font-family': 'fontFamily' };
|
||||||
|
const defaultKey = cssToDefaultKey[entry.css];
|
||||||
|
if (!defaultKey || !tagDefaults?.[defaultKey]) continue;
|
||||||
|
}
|
||||||
const val = entry.getValue();
|
const val = entry.getValue();
|
||||||
if (val === null || val === undefined) continue;
|
if (val === null || val === undefined) continue;
|
||||||
const comment = (entry.special && !settingEnabled[entry.group]) ? ' /* valeur par défaut */' : '';
|
// Show "valeur par défaut" only if the value actually matches the TextSettings default
|
||||||
|
let isTextDefault = false;
|
||||||
|
if (entry.special && !settingEnabled[entry.group]) {
|
||||||
|
const textDefaultValues = {
|
||||||
|
'font-family': textDefaults.fontFamily === 'sans-serif' ? 'sans-serif' : `"${textDefaults.fontFamily}"`,
|
||||||
|
'font-size': `${textDefaults.fontSize.value}${textDefaults.fontSize.unit}`,
|
||||||
|
'line-height': `${textDefaults.lineHeight.value}${textDefaults.lineHeight.unit}`,
|
||||||
|
'color': textDefaults.color,
|
||||||
|
};
|
||||||
|
isTextDefault = val === textDefaultValues[entry.css];
|
||||||
|
}
|
||||||
|
const comment = isTextDefault ? ' /* valeur par défaut */' : '';
|
||||||
lines.push(` ${entry.css}: ${val};${comment}`);
|
lines.push(` ${entry.css}: ${val};${comment}`);
|
||||||
}
|
}
|
||||||
if (settingEnabled.margin) {
|
const showMargin = settingEnabled.margin || ['top', 'right', 'bottom', 'left'].some(s => hasInCss(`margin-${s}`));
|
||||||
|
if (showMargin) {
|
||||||
for (const side of ['top', 'right', 'bottom', 'left']) {
|
for (const side of ['top', 'right', 'bottom', 'left']) {
|
||||||
lines.push(` margin-${side}: ${margin[side].value}${margin[side].unit};`);
|
lines.push(` margin-${side}: ${margin[side].value}${margin[side].unit};`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (settingEnabled.padding) {
|
const showPadding = settingEnabled.padding || ['top', 'right', 'bottom', 'left'].some(s => hasInCss(`padding-${s}`));
|
||||||
|
if (showPadding) {
|
||||||
for (const side of ['top', 'right', 'bottom', 'left']) {
|
for (const side of ['top', 'right', 'bottom', 'left']) {
|
||||||
lines.push(` padding-${side}: ${padding[side].value}${padding[side].unit};`);
|
lines.push(` padding-${side}: ${padding[side].value}${padding[side].unit};`);
|
||||||
}
|
}
|
||||||
|
|
@ -588,26 +613,39 @@ export function useElementSettings({ margin, padding, basePopup }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback to TextSettings defaults only if the selector doesn't already have the value
|
||||||
if (!settingEnabled.font && !settingCache.font) {
|
if (!settingEnabled.font && !settingCache.font) {
|
||||||
|
if (!stylesheetStore.extractValue(selector.value, 'font-family')) {
|
||||||
const ff = stylesheetStore.extractValue('body', 'font-family');
|
const ff = stylesheetStore.extractValue('body', 'font-family');
|
||||||
if (ff) fontFamily.value = (typeof ff === 'string' ? ff : ff.value).replace(/['"]/g, '');
|
if (ff) fontFamily.value = (typeof ff === 'string' ? ff : ff.value).replace(/['"]/g, '');
|
||||||
|
}
|
||||||
|
if (!stylesheetStore.extractValue(selector.value, 'font-style')) {
|
||||||
const fs = stylesheetStore.extractValue('p', 'font-style');
|
const fs = stylesheetStore.extractValue('p', 'font-style');
|
||||||
if (fs) italic.value = (typeof fs === 'string' ? fs : fs.value) === 'italic';
|
if (fs) italic.value = (typeof fs === 'string' ? fs : fs.value) === 'italic';
|
||||||
|
}
|
||||||
|
if (!stylesheetStore.extractValue(selector.value, 'font-weight')) {
|
||||||
const fw = stylesheetStore.extractValue('p', 'font-weight');
|
const fw = stylesheetStore.extractValue('p', 'font-weight');
|
||||||
if (fw) { const v = typeof fw === 'string' ? fw : fw.value; bold.value = v === 'bold' || parseInt(v) >= 700; }
|
if (fw) { const v = typeof fw === 'string' ? fw : fw.value; bold.value = v === 'bold' || parseInt(v) >= 700; }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!settingEnabled.fontSize && !settingCache.fontSize) {
|
if (!settingEnabled.fontSize && !settingCache.fontSize) {
|
||||||
|
if (!stylesheetStore.extractValue(selector.value, 'font-size')) {
|
||||||
const data = stylesheetStore.extractValue('p', 'font-size');
|
const data = stylesheetStore.extractValue('p', 'font-size');
|
||||||
if (data && data.value !== undefined) { fontSize.value = data.value; fontSize.unit = data.unit; }
|
if (data && data.value !== undefined) { fontSize.value = data.value; fontSize.unit = data.unit; }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!settingEnabled.lineHeight && !settingCache.lineHeight) {
|
if (!settingEnabled.lineHeight && !settingCache.lineHeight) {
|
||||||
|
if (!stylesheetStore.extractValue(selector.value, 'line-height')) {
|
||||||
const data = stylesheetStore.extractValue('p', 'line-height');
|
const data = stylesheetStore.extractValue('p', 'line-height');
|
||||||
if (data && data.value !== undefined) { lineHeight.value = data.value; lineHeight.unit = data.unit; }
|
if (data && data.value !== undefined) { lineHeight.value = data.value; lineHeight.unit = data.unit; }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!settingEnabled.color && settingCache.color === null) {
|
if (!settingEnabled.color && settingCache.color === null) {
|
||||||
|
if (!stylesheetStore.extractValue(selector.value, '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;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading values from stylesheet:', error);
|
console.error('Error loading values from stylesheet:', error);
|
||||||
}
|
}
|
||||||
|
|
@ -639,12 +677,19 @@ export function useElementSettings({ margin, padding, basePopup }) {
|
||||||
settingCache.color = null;
|
settingCache.color = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply tag-based defaults (em/i → italic, strong/b → bold)
|
// Reset inline-specific values, then apply tag-based defaults
|
||||||
|
italic.value = ELEMENT_DEFAULTS.italic;
|
||||||
|
bold.value = ELEMENT_DEFAULTS.bold;
|
||||||
|
color.value = ELEMENT_DEFAULTS.color;
|
||||||
|
textDecorationLine.value = ELEMENT_DEFAULTS.textDecorationLine;
|
||||||
|
|
||||||
const tag = element.tagName.toLowerCase();
|
const tag = element.tagName.toLowerCase();
|
||||||
const inlineDefaults = INLINE_DEFAULTS[tag];
|
const inlineDefaults = INLINE_DEFAULTS[tag];
|
||||||
if (inlineDefaults) {
|
if (inlineDefaults) {
|
||||||
if (inlineDefaults.fontStyle === 'italic') italic.value = true;
|
if (inlineDefaults.fontStyle === 'italic') italic.value = true;
|
||||||
if (inlineDefaults.fontWeight === 'bold') bold.value = true;
|
if (inlineDefaults.fontWeight === 'bold') bold.value = true;
|
||||||
|
if (inlineDefaults.color) color.value = inlineDefaults.color;
|
||||||
|
if (inlineDefaults.textDecorationLine) textDecorationLine.value = inlineDefaults.textDecorationLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadValuesFromStylesheet(true);
|
loadValuesFromStylesheet(true);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import * as cssComments from '../utils/css-comments';
|
||||||
import prettier from 'prettier/standalone';
|
import prettier from 'prettier/standalone';
|
||||||
import parserPostcss from 'prettier/plugins/postcss';
|
import parserPostcss from 'prettier/plugins/postcss';
|
||||||
import { getCsrfToken } from '../utils/kirby-auth';
|
import { getCsrfToken } from '../utils/kirby-auth';
|
||||||
import { PAGE_DEFAULTS, TEXT_DEFAULTS, INLINE_DEFAULTS } from '../utils/defaults';
|
import { PAGE_DEFAULTS, TEXT_DEFAULTS, HEADING_DEFAULTS, INLINE_DEFAULTS } from '../utils/defaults';
|
||||||
|
|
||||||
export const useStylesheetStore = defineStore('stylesheet', () => {
|
export const useStylesheetStore = defineStore('stylesheet', () => {
|
||||||
// Base state
|
// Base state
|
||||||
|
|
@ -195,10 +195,28 @@ export const useStylesheetStore = defineStore('stylesheet', () => {
|
||||||
set('p', 'font-size', TEXT_DEFAULTS.fontSize.value, TEXT_DEFAULTS.fontSize.unit);
|
set('p', 'font-size', TEXT_DEFAULTS.fontSize.value, TEXT_DEFAULTS.fontSize.unit);
|
||||||
set('p', 'line-height', TEXT_DEFAULTS.lineHeight.value, TEXT_DEFAULTS.lineHeight.unit);
|
set('p', 'line-height', TEXT_DEFAULTS.lineHeight.value, TEXT_DEFAULTS.lineHeight.unit);
|
||||||
|
|
||||||
// Inline element defaults (em, i, strong, b)
|
// Heading defaults (h1, h2, ...)
|
||||||
|
for (const [tag, props] of Object.entries(HEADING_DEFAULTS)) {
|
||||||
|
if (props.fontSize) set(tag, 'font-size', props.fontSize.value, props.fontSize.unit);
|
||||||
|
if (props.background) set(tag, 'background', props.background);
|
||||||
|
if (props.padding) {
|
||||||
|
for (const side of ['top', 'right', 'bottom', 'left']) {
|
||||||
|
if (props.padding[side]) set(tag, `padding-${side}`, props.padding[side].value, props.padding[side].unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (props.margin) {
|
||||||
|
for (const side of ['top', 'right', 'bottom', 'left']) {
|
||||||
|
if (props.margin[side]) set(tag, `margin-${side}`, props.margin[side].value, props.margin[side].unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inline element defaults (em, i, strong, b, a)
|
||||||
for (const [tag, props] of Object.entries(INLINE_DEFAULTS)) {
|
for (const [tag, props] of Object.entries(INLINE_DEFAULTS)) {
|
||||||
if (props.fontStyle) set(tag, 'font-style', props.fontStyle);
|
if (props.fontStyle) set(tag, 'font-style', props.fontStyle);
|
||||||
if (props.fontWeight) set(tag, 'font-weight', props.fontWeight);
|
if (props.fontWeight) set(tag, 'font-weight', props.fontWeight);
|
||||||
|
if (props.color) set(tag, 'color', props.color);
|
||||||
|
if (props.textDecorationLine) set(tag, 'text-decoration-line', props.textDecorationLine);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,27 @@ export const ELEMENT_DEFAULTS = Object.freeze({
|
||||||
textUnderlineOffset: Object.freeze({ value: 1, unit: 'px' }),
|
textUnderlineOffset: Object.freeze({ value: 1, unit: 'px' }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const HEADING_DEFAULTS = Object.freeze({
|
||||||
|
h1: Object.freeze({
|
||||||
|
fontSize: Object.freeze({ value: 38, unit: 'px' }),
|
||||||
|
lineHeight: Object.freeze({ value: 38, unit: 'px' }),
|
||||||
|
background: 'rgba(255, 255, 255, 0.521)',
|
||||||
|
padding: Object.freeze({
|
||||||
|
top: Object.freeze({ value: 10, unit: 'px' }),
|
||||||
|
right: Object.freeze({ value: 20, unit: 'px' }),
|
||||||
|
bottom: Object.freeze({ value: 10, unit: 'px' }),
|
||||||
|
left: Object.freeze({ value: 20, unit: 'px' }),
|
||||||
|
}),
|
||||||
|
margin: Object.freeze({
|
||||||
|
top: Object.freeze({ value: 60, unit: 'px' }),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
export const INLINE_DEFAULTS = Object.freeze({
|
export const INLINE_DEFAULTS = Object.freeze({
|
||||||
em: Object.freeze({ fontStyle: 'italic' }),
|
em: Object.freeze({ fontStyle: 'italic' }),
|
||||||
i: Object.freeze({ fontStyle: 'italic' }),
|
i: Object.freeze({ fontStyle: 'italic' }),
|
||||||
strong: Object.freeze({ fontWeight: 'bold' }),
|
strong: Object.freeze({ fontWeight: 'bold' }),
|
||||||
b: Object.freeze({ fontWeight: 'bold' }),
|
b: Object.freeze({ fontWeight: 'bold' }),
|
||||||
|
a: Object.freeze({ color: '#0000EE', textDecorationLine: 'underline' }),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue