diff --git a/src/components/ElementPopup.vue b/src/components/ElementPopup.vue index 7baae2b..d25c755 100644 --- a/src/components/ElementPopup.vue +++ b/src/components/ElementPopup.vue @@ -1,277 +1,192 @@ diff --git a/src/composables/useColoris.js b/src/composables/useColoris.js new file mode 100644 index 0000000..c589d4d --- /dev/null +++ b/src/composables/useColoris.js @@ -0,0 +1,34 @@ +import Coloris from '@melloware/coloris'; +import '@melloware/coloris/dist/coloris.css'; + +const defaultConfig = { + el: '[data-coloris]', + theme: 'pill', + themeMode: 'dark', + formatToggle: true, + alpha: true, + closeButton: true, + closeLabel: 'Fermer', + clearButton: true, + clearLabel: 'Effacer', + swatchesOnly: false, + inline: false, + wrap: true, + swatches: [ + '#264653', + '#2a9d8f', + '#e9c46a', + '#f4a261', + '#e76f51', + '#d62828', + '#023e8a', + '#0077b6', + '#ffffff', + '#000000', + ], +}; + +export function initColoris(overrides = {}) { + Coloris.init(); + Coloris({ ...defaultConfig, ...overrides }); +} diff --git a/src/composables/useLinkedSpacing.js b/src/composables/useLinkedSpacing.js new file mode 100644 index 0000000..6affe41 --- /dev/null +++ b/src/composables/useLinkedSpacing.js @@ -0,0 +1,146 @@ +import { ref, watch } from 'vue'; +import { convertUnit } from '../utils/unit-conversion'; + +/** + * Composable for managing linked/unlinked spacing (margin/padding) with 4 sides. + * @param {Object} options + * @param {string} options.defaultUnit - Default unit for all sides (default: 'mm') + * @param {Object} options.initialValues - Initial values for sides { top, right, bottom, left } each { value, unit } + * @param {Function} options.onUpdate - Callback called with the detailed sides when values change + * @param {Function} options.isUpdatingFromStore - Function that returns whether we're syncing from store + * @param {Function} options.debouncedUpdate - Debounced update function + */ +export function useLinkedSpacing({ defaultUnit = 'mm', initialValues, onUpdate, isUpdatingFromStore, debouncedUpdate }) { + const sides = ref(initialValues || { + top: { value: 0, unit: defaultUnit }, + right: { value: 0, unit: defaultUnit }, + bottom: { value: 0, unit: defaultUnit }, + left: { value: 0, unit: defaultUnit }, + }); + + const linked = ref(false); + + const prevValues = ref({ + top: sides.value.top.value, + right: sides.value.right.value, + bottom: sides.value.bottom.value, + left: sides.value.left.value, + }); + + const updateUnit = (newUnit) => { + const sideNames = ['top', 'right', 'bottom', 'left']; + sideNames.forEach((side) => { + const s = sides.value[side]; + s.value = convertUnit(s.value, s.unit, newUnit); + s.unit = newUnit; + }); + }; + + // When link is toggled on, sync all sides to first non-zero value + watch(linked, (isLinked) => { + if (!isLinked) return; + + const current = sides.value; + const syncValue = current.top.value || current.bottom.value || current.left.value || current.right.value; + + sides.value.top.value = syncValue; + sides.value.bottom.value = syncValue; + sides.value.left.value = syncValue; + sides.value.right.value = syncValue; + + prevValues.value.top = syncValue; + prevValues.value.bottom = syncValue; + prevValues.value.left = syncValue; + prevValues.value.right = syncValue; + }); + + // Watch side values for linked sync + update callback + watch(() => [ + sides.value.top.value, + sides.value.bottom.value, + sides.value.left.value, + sides.value.right.value, + ], () => { + if (isUpdatingFromStore()) return; + + if (linked.value) { + const current = { + top: sides.value.top.value, + bottom: sides.value.bottom.value, + left: sides.value.left.value, + right: sides.value.right.value, + }; + + let changedValue = null; + if (current.top !== prevValues.value.top) changedValue = current.top; + else if (current.bottom !== prevValues.value.bottom) changedValue = current.bottom; + else if (current.left !== prevValues.value.left) changedValue = current.left; + else if (current.right !== prevValues.value.right) changedValue = current.right; + + if (changedValue !== null) { + sides.value.top.value = changedValue; + sides.value.bottom.value = changedValue; + sides.value.left.value = changedValue; + sides.value.right.value = changedValue; + + prevValues.value.top = changedValue; + prevValues.value.bottom = changedValue; + prevValues.value.left = changedValue; + prevValues.value.right = changedValue; + } + } else { + prevValues.value.top = sides.value.top.value; + prevValues.value.bottom = sides.value.bottom.value; + prevValues.value.left = sides.value.left.value; + prevValues.value.right = sides.value.right.value; + } + + if (onUpdate) { + debouncedUpdate(() => { + onUpdate(sides.value); + }); + } + }); + + /** + * Set all sides from extracted spacing data (from syncFromStore). + * Also updates prevValues and optionally sets linked state. + */ + const setFromSpacing = (spacing) => { + if (spacing.simple) { + sides.value = { + top: { ...spacing.simple }, + right: { ...spacing.simple }, + bottom: { ...spacing.simple }, + left: { ...spacing.simple }, + }; + linked.value = true; + } else if (spacing.detailed) { + sides.value = spacing.detailed; + const d = spacing.detailed; + const allSame = + d.top.value === d.right.value && + d.top.value === d.bottom.value && + d.top.value === d.left.value && + d.top.unit === d.right.unit && + d.top.unit === d.bottom.unit && + d.top.unit === d.left.unit; + linked.value = allSame; + } + + prevValues.value = { + top: sides.value.top.value, + right: sides.value.right.value, + bottom: sides.value.bottom.value, + left: sides.value.left.value, + }; + }; + + return { + sides, + linked, + updateUnit, + prevValues, + setFromSpacing, + }; +}