add line height value + gestion passage px/em

This commit is contained in:
Julie Blanc 2025-12-10 16:01:36 +01:00
parent 7f3aff948b
commit 68343a52f5
4 changed files with 159 additions and 15 deletions

View file

@ -31,7 +31,7 @@ h2 {
}
p {
font-size: 1rem;
font-size: 16px;
margin: 0mm 0mm 5mm 0mm;
}

View file

@ -2,7 +2,7 @@
<section class="settings-section" id="settings-section_elem" data-color-type="elem">
<h2>Réglage du texte</h2>
<div class="container">
<p class="infos">
Ces réglages s'appliquent à l'ensemble des éléments du document. Vous
pouvez modifier ensuite les éléments indépendamment.
@ -38,7 +38,7 @@
<label for="text-size-range" class="label-with-tooltip" data-css="font-size">Taille du texte</label>
<InputWithUnit
v-model="fontSize"
:units="['px', 'em', 'rem']"
:units="['px']"
:min="8"
:max="72"
showRange
@ -46,6 +46,20 @@
</div>
</div>
<!-- line height -->
<div class="settings-subsection">
<div class="field field-text-size">
<label for="line-height-range" class="label-with-tooltip" data-css="line-height">Interlignage</label>
<InputWithUnit
v-model="lineHeight"
:units="['px', 'em', 'rem']"
:min="0"
:max="72"
showRange
/>
</div>
</div>
<!-- Alignement -->
<div class="settings-subsection">
<div class="field field-simple">
@ -151,6 +165,7 @@ const font = ref('Alegreya Sans');
const italic = ref(false);
const weight = ref('400');
const fontSize = ref({ value: 16, unit: 'px' });
const lineHeight = ref({ value: 1.2, unit: 'em' });
const alignment = ref('left');
const color = ref('rgb(0, 0, 0)');
const background = ref('transparent');
@ -203,10 +218,92 @@ watch(weight, (val) => {
updateStyle('p', 'font-weight', val);
});
watch(fontSize, (val) => {
watch(fontSize, (newVal, oldVal) => {
if (isUpdatingFromStore) return;
// If unit changed, convert the value
if (oldVal && newVal.unit !== oldVal.unit) {
const baseFontSize = 16; // Default base font size for rem
let convertedValue = newVal.value;
// Convert from px to em/rem
if (oldVal.unit === 'px' && (newVal.unit === 'em' || newVal.unit === 'rem')) {
convertedValue = newVal.value / baseFontSize;
// Round to 1 decimal place
convertedValue = Math.round(convertedValue * 10) / 10;
}
// Convert from em/rem to px
else if ((oldVal.unit === 'em' || oldVal.unit === 'rem') && newVal.unit === 'px') {
convertedValue = newVal.value * baseFontSize;
// Round to whole number for px
convertedValue = Math.round(convertedValue);
}
// Clamp to valid range based on new unit
if (newVal.unit === 'em' || newVal.unit === 'rem') {
convertedValue = Math.max(0, Math.min(4, convertedValue));
} else {
convertedValue = Math.max(8, Math.min(72, convertedValue));
}
// Update with converted value - create new object to trigger reactivity
fontSize.value = { value: convertedValue, unit: newVal.unit };
return; // Exit early to avoid double update
}
debouncedUpdate(() => {
updateStyle('p', 'font-size', `${val.value}${val.unit}`);
updateStyle('p', 'font-size', `${newVal.value}${newVal.unit}`);
});
}, { deep: true });
watch(lineHeight, (newVal, oldVal) => {
if (isUpdatingFromStore) return;
// If unit changed, convert the value
if (oldVal && newVal.unit !== oldVal.unit) {
const baseFontSize = 16; // Default base font size for rem
let convertedValue = newVal.value;
// Convert from px to em/rem
if (oldVal.unit === 'px' && (newVal.unit === 'em' || newVal.unit === 'rem')) {
const divisor = newVal.unit === 'em' ? fontSize.value.value : baseFontSize;
convertedValue = newVal.value / divisor;
// Round to 1 decimal place
convertedValue = Math.round(convertedValue * 10) / 10;
}
// Convert from em/rem to px
else if ((oldVal.unit === 'em' || oldVal.unit === 'rem') && newVal.unit === 'px') {
const multiplier = oldVal.unit === 'em' ? fontSize.value.value : baseFontSize;
convertedValue = newVal.value * multiplier;
// Round to whole number for px
convertedValue = Math.round(convertedValue);
}
// Convert between em and rem
else if (oldVal.unit === 'em' && newVal.unit === 'rem') {
convertedValue = (newVal.value * fontSize.value.value) / baseFontSize;
// Round to 1 decimal place
convertedValue = Math.round(convertedValue * 10) / 10;
}
else if (oldVal.unit === 'rem' && newVal.unit === 'em') {
convertedValue = (newVal.value * baseFontSize) / fontSize.value.value;
// Round to 1 decimal place
convertedValue = Math.round(convertedValue * 10) / 10;
}
// Clamp to valid range based on new unit
if (newVal.unit === 'em' || newVal.unit === 'rem') {
convertedValue = Math.max(0, Math.min(4, convertedValue));
} else {
convertedValue = Math.max(0, Math.min(72, convertedValue));
}
// Update with converted value - create new object to trigger reactivity
lineHeight.value = { value: convertedValue, unit: newVal.unit };
return; // Exit early to avoid double update
}
debouncedUpdate(() => {
updateStyle('p', 'line-height', `${newVal.value}${newVal.unit}`);
});
}, { deep: true });
@ -257,6 +354,9 @@ const syncFromStore = () => {
const fontSizeVal = extractNumericValue('p', 'font-size', ['px', 'em', 'rem']);
if (fontSizeVal) fontSize.value = fontSizeVal;
const lineHeightVal = extractNumericValue('p', 'line-height', ['px', 'em', 'rem']);
if (lineHeightVal) lineHeight.value = lineHeightVal;
// Margins
const margins = extractSpacing('p', 'margin');
if (margins) {

View file

@ -4,16 +4,16 @@
v-if="showRange"
type="range"
:value="modelValue.value"
:min="min"
:max="max"
:step="step"
:min="computedMin"
:max="computedMax"
:step="computedStep"
@input="updateValue(Number($event.target.value))"
/>
<NumberInput
:modelValue="modelValue.value"
:min="min"
:max="max"
:step="step"
:min="computedMin"
:max="computedMax"
:step="computedStep"
inputClass="size-input"
@update:modelValue="updateValue"
/>
@ -27,6 +27,7 @@
</template>
<script setup>
import { computed } from 'vue';
import NumberInput from './NumberInput.vue';
import UnitToggle from './UnitToggle.vue';
@ -60,11 +61,36 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue']);
// Compute step based on unit
const computedStep = computed(() => {
if (props.modelValue.unit === 'em' || props.modelValue.unit === 'rem') {
return 0.1;
}
return props.step;
});
// Compute min based on unit
const computedMin = computed(() => {
if (props.modelValue.unit === 'em' || props.modelValue.unit === 'rem') {
return 0;
}
return props.min;
});
// Compute max based on unit
const computedMax = computed(() => {
if (props.modelValue.unit === 'em' || props.modelValue.unit === 'rem') {
return 4;
}
return props.max;
});
const updateValue = (value) => {
emit('update:modelValue', { ...props.modelValue, value });
};
const updateUnit = (unit) => {
// Just emit the unit change, let parent handle any conversion
emit('update:modelValue', { ...props.modelValue, unit });
};
</script>

View file

@ -2,7 +2,7 @@
<div class="number-input">
<input
type="number"
:value="modelValue"
:value="displayValue"
:min="min"
:max="max"
:step="step"
@ -39,6 +39,8 @@
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps({
modelValue: {
type: Number,
@ -72,20 +74,36 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue']);
// Round to 1 decimal place for display, but show whole numbers without decimals
const displayValue = computed(() => {
const rounded = Math.round(props.modelValue * 10) / 10;
// If it's a whole number, return it as is (no decimal)
if (Number.isInteger(rounded)) {
return rounded;
}
return rounded;
});
const handleInput = (event) => {
const value = Number(event.target.value);
let value = Number(event.target.value);
// Round to 1 decimal place
value = Math.round(value * 10) / 10;
emit('update:modelValue', value);
};
const increment = () => {
const newValue = props.modelValue + props.step;
let newValue = props.modelValue + props.step;
// Round to 1 decimal place
newValue = Math.round(newValue * 10) / 10;
if (props.max === undefined || newValue <= props.max) {
emit('update:modelValue', newValue);
}
};
const decrement = () => {
const newValue = props.modelValue - props.step;
let newValue = props.modelValue - props.step;
// Round to 1 decimal place
newValue = Math.round(newValue * 10) / 10;
if (props.min === undefined || newValue >= props.min) {
emit('update:modelValue', newValue);
}