add module setting text-decoration

This commit is contained in:
Julie Blanc 2026-03-08 09:54:36 +01:00
parent 8a896277bf
commit ec1b23d67a
7 changed files with 124 additions and 42 deletions

View file

@ -1,35 +0,0 @@
// .settings__container {
// margin: var(--space-m) 0;
// h2 {
// margin-bottom: var(--space);
// font-weight: 600;
// font-size: 1.4rem;
// border-bottom: 1px solid var(--color-200);
// color: var(--color-800);
// }
// .infos {
// font-size: 0.8rem;
// color: var(--color-interface-400);
// }
// }
// .setting__section:not(:last-child) {
// border-bottom: 1px solid var(--color-interface-100);
// }
// .setting__section {
// padding: var(--space-s) 0;
// h3 {
// margin-top: calc(var(--space-xs) * 1.5);
// margin-bottom: calc(var(--space-xs) * 2);
// // color: var(--color-600);
// font-size: 1rem;
// font-weight: 600;
// color: red;
// }
// }

View file

@ -54,8 +54,12 @@
}
.setting__section[data-setting="textDecoration"],
.setting__section[data-setting="border"] {
.field-border__option{
.setting__body{
padding-top: 4px;
}
.field__option{
display: grid;
width: 100%;
grid-template-columns: 9ch minmax(0, 1fr);

View file

@ -780,7 +780,12 @@ input[type=number] {
margin-bottom: var(--space-xs);
}
.setting__section[data-setting=border] .field-border__option {
.setting__section[data-setting=textDecoration] .setting__body,
.setting__section[data-setting=border] .setting__body {
padding-top: 4px;
}
.setting__section[data-setting=textDecoration] .field__option,
.setting__section[data-setting=border] .field__option {
display: grid;
width: 100%;
grid-template-columns: 9ch minmax(0, 1fr);

File diff suppressed because one or more lines are too long

View file

@ -144,8 +144,8 @@
<label class="label-with-tooltip" data-css="border">Bordure</label>
</div>
<div class="setting__body">
<div class="field-border__options">
<div class="field-border__option">
<div class="field__options">
<div class="field__option">
<label class="label-with-tooltip" data-css="border-width">Épaisseur</label>
<div class="input-with-unit">
<NumberInput
@ -158,7 +158,7 @@
</div>
</div>
</div>
<div class="field-border__option">
<div class="field__option">
<label class="label-with-tooltip" data-css="border-style">Style</label>
<select v-model="borderStyle">
<option value="solid">Plein</option>
@ -167,7 +167,7 @@
<option value="double">Double</option>
</select>
</div>
<div class="field-border__option">
<div class="field__option">
<label class="label-with-tooltip" data-css="border-color">Couleur</label>
<div class="input-with-color">
<input
@ -182,6 +182,75 @@
</div>
</div>
<!-- Text Decoration -->
<div class="setting__section" data-setting="textDecoration" :class="{ 'setting-disabled': !settingEnabled.textDecoration }" @click="onSubsectionClick('textDecoration')">
<div class="setting__header">
<input type="checkbox" id="toggle-textDecoration" class="toggle-setting" :checked="settingEnabled.textDecoration" @change="onToggleSetting('textDecoration', $event.target.checked)" /><label for="toggle-textDecoration" aria-label="Activer le réglage de surlignement" @click.stop></label>
<label class="label-with-tooltip" data-css="text-decoration">Surlignement</label>
</div>
<div class="setting__body">
<div class="field__options">
<div class="field__option">
<label class="label-with-tooltip" data-css="text-decoration-line">Type</label>
<div class="radio-group">
<label><input type="radio" value="underline" v-model="textDecorationLine" /> Souligné</label>
<label><input type="radio" value="line-through" v-model="textDecorationLine" /> Barré</label>
</div>
</div>
<div class="field__option">
<label class="label-with-tooltip" data-css="text-decoration-style">Style</label>
<select v-model="textDecorationStyle">
<option value="solid">Plein</option>
<option value="double">Double</option>
<option value="dotted">Pointillés</option>
<option value="dashed">Tirets</option>
<option value="wavy">Ondulé</option>
</select>
</div>
<div class="field__option">
<label class="label-with-tooltip" data-css="text-decoration-thickness">Épaisseur</label>
<div class="input-with-unit">
<NumberInput
v-model="textDecorationThickness.value"
:min="1"
:max="100"
:step="1"
/>
<div class="unit-toggle">
<button type="button" class="active">px</button>
</div>
</div>
</div>
<div class="field__option">
<label class="label-with-tooltip" data-css="text-decoration-color">Couleur</label>
<div class="input-with-color">
<input
ref="textDecorationColorInput"
type="text"
v-model="textDecorationColor"
data-coloris
/>
</div>
</div>
<div class="field__option">
<label class="label-with-tooltip" data-css="text-underline-offset">Décalage</label>
<div class="input-with-unit">
<NumberInput
v-model="textUnderlineOffset.value"
:min="1"
:max="100"
:step="1"
/>
<div class="unit-toggle">
<button type="button" class="active">px</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Outer Margins -->
<div class="setting__section" data-setting="margin" :class="{ 'setting-disabled': !settingEnabled.margin }" @click="onSubsectionClick('margin')">
@ -314,6 +383,7 @@ const elementInstanceCount = ref(0);
const colorInput = ref(null);
const backgroundInput = ref(null);
const borderColorInput = ref(null);
const textDecorationColorInput = ref(null);
// Spacing editor (margin/padding)
const {
@ -330,6 +400,7 @@ const {
fontFamily, italic, bold, textAlign, color, background,
fontSize, fontSizeModel, lineHeight, lineHeightModel,
borderWidth, borderStyle, borderColor,
textDecorationLine, textDecorationStyle, textDecorationThickness, textDecorationColor, textUnderlineOffset,
settingEnabled,
textDefaults, projectFonts, loadAllFontPreviews,
displayedCss, editableFullCss,

View file

@ -37,6 +37,11 @@ export function useElementSettings({ margin, padding, basePopup }) {
const borderWidth = reactive({ ...ELEMENT_DEFAULTS.borderWidth });
const borderStyle = ref(ELEMENT_DEFAULTS.borderStyle);
const borderColor = ref(ELEMENT_DEFAULTS.borderColor);
const textDecorationLine = ref(ELEMENT_DEFAULTS.textDecorationLine);
const textDecorationStyle = ref(ELEMENT_DEFAULTS.textDecorationStyle);
const textDecorationThickness = reactive({ ...ELEMENT_DEFAULTS.textDecorationThickness });
const textDecorationColor = ref(ELEMENT_DEFAULTS.textDecorationColor);
const textUnderlineOffset = reactive({ ...ELEMENT_DEFAULTS.textUnderlineOffset });
// --- Toggle state ---
const settingEnabled = reactive({
@ -47,6 +52,7 @@ export function useElementSettings({ margin, padding, basePopup }) {
color: false,
background: false,
border: false,
textDecoration: false,
margin: false,
padding: false,
});
@ -93,12 +99,17 @@ export function useElementSettings({ margin, padding, basePopup }) {
{ css: 'background', group: 'background', get: () => background.value, set: v => background.value = v, debounce: true },
{ css: 'border-style', group: 'border', get: () => borderStyle.value, set: v => borderStyle.value = v || 'solid', debounce: false },
{ css: 'border-color', group: 'border', get: () => borderColor.value, set: v => borderColor.value = v, debounce: true },
{ css: 'text-decoration-line', group: 'textDecoration', get: () => textDecorationLine.value, set: v => textDecorationLine.value = v || 'underline', debounce: false },
{ css: 'text-decoration-style', group: 'textDecoration', get: () => textDecorationStyle.value, set: v => textDecorationStyle.value = v || 'solid', debounce: false },
{ css: 'text-decoration-color', group: 'textDecoration', get: () => textDecorationColor.value, set: v => textDecorationColor.value = v, debounce: true },
];
const unitProps = [
{ css: 'font-size', group: 'fontSize', ref: fontSize, debounce: true },
{ css: 'line-height', group: 'lineHeight', ref: lineHeight, debounce: true },
{ css: 'border-width', group: 'border', ref: borderWidth, debounce: true },
{ css: 'text-decoration-thickness', group: 'textDecoration', ref: textDecorationThickness, debounce: true },
{ css: 'text-underline-offset', group: 'textDecoration', ref: textUnderlineOffset, debounce: true },
];
const settingGroups = {
@ -109,6 +120,7 @@ export function useElementSettings({ margin, padding, basePopup }) {
color: ['color'],
background: ['background'],
border: ['border-width', 'border-style', 'border-color'],
textDecoration: ['text-decoration-line', 'text-decoration-style', 'text-decoration-thickness', 'text-decoration-color', 'text-underline-offset'],
margin: ['margin-top', 'margin-right', 'margin-bottom', 'margin-left'],
padding: ['padding-top', 'padding-right', 'padding-bottom', 'padding-left'],
};
@ -283,6 +295,21 @@ export function useElementSettings({ margin, padding, basePopup }) {
{ css: 'border-color', group: 'border',
getValue: () => borderColor.value,
skip: () => !settingEnabled.border || borderWidth.value === 0 },
{ css: 'text-decoration-line', group: 'textDecoration',
getValue: () => textDecorationLine.value,
skip: () => !settingEnabled.textDecoration },
{ css: 'text-decoration-style', group: 'textDecoration',
getValue: () => textDecorationStyle.value,
skip: () => !settingEnabled.textDecoration },
{ css: 'text-decoration-thickness', group: 'textDecoration',
getValue: () => `${textDecorationThickness.value}${textDecorationThickness.unit}`,
skip: () => !settingEnabled.textDecoration },
{ css: 'text-decoration-color', group: 'textDecoration',
getValue: () => textDecorationColor.value,
skip: () => !settingEnabled.textDecoration },
{ css: 'text-underline-offset', group: 'textDecoration',
getValue: () => `${textUnderlineOffset.value}${textUnderlineOffset.unit}`,
skip: () => !settingEnabled.textDecoration },
];
const isInlineElement = computed(() => !!INLINE_DEFAULTS[currentTag.value]);
@ -812,6 +839,11 @@ export function useElementSettings({ margin, padding, basePopup }) {
borderWidth,
borderStyle,
borderColor,
textDecorationLine,
textDecorationStyle,
textDecorationThickness,
textDecorationColor,
textUnderlineOffset,
settingEnabled,
settingCache,
textDefaults,

View file

@ -36,6 +36,11 @@ export const ELEMENT_DEFAULTS = Object.freeze({
borderWidth: Object.freeze({ value: 1, unit: 'px' }),
borderStyle: 'solid',
borderColor: '#000000',
textDecorationLine: 'underline',
textDecorationStyle: 'solid',
textDecorationThickness: Object.freeze({ value: 1, unit: 'px' }),
textDecorationColor: '#000000',
textUnderlineOffset: Object.freeze({ value: 1, unit: 'px' }),
});
export const INLINE_DEFAULTS = Object.freeze({