refactor: extract shared patterns from popup/settings components
- Create useColoris composable (shared Coloris init across 4 files) - Create useLinkedSpacing composable (linked margin/padding logic from TextSettings) - Create BasePopup component (shared popup shell, CSS editor, inheritance button) - Add watchProp helper in ElementPopup (12 watchers → 12 compact lines) - Use extractSpacing for @page margin parsing in PagePopup and PageSettings Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0c682c78c0
commit
69d5ebe7ed
7 changed files with 816 additions and 1187 deletions
|
|
@ -372,14 +372,14 @@
|
|||
|
||||
<script setup>
|
||||
import { ref, watch, onMounted } from 'vue';
|
||||
import Coloris from '@melloware/coloris';
|
||||
import { initColoris } from '../../composables/useColoris';
|
||||
import UnitToggle from '../ui/UnitToggle.vue';
|
||||
import InputWithUnit from '../ui/InputWithUnit.vue';
|
||||
import NumberInput from '../ui/NumberInput.vue';
|
||||
import { useCssUpdater } from '../../composables/useCssUpdater';
|
||||
import { useCssSync } from '../../composables/useCssSync';
|
||||
import { useDebounce } from '../../composables/useDebounce';
|
||||
import { convertUnit } from '../../utils/unit-conversion';
|
||||
import { useLinkedSpacing } from '../../composables/useLinkedSpacing';
|
||||
|
||||
const { updateStyle, setMargin, setDetailedMargins, setPadding, setDetailedPadding } = useCssUpdater();
|
||||
const { extractValue, extractNumericValue, extractSpacing } = useCssSync();
|
||||
|
|
@ -406,59 +406,39 @@ const background = ref('transparent');
|
|||
const colorInput = ref(null);
|
||||
const backgroundInput = ref(null);
|
||||
|
||||
const marginOuterDetailed = ref({
|
||||
top: { value: 0, unit: 'mm' },
|
||||
right: { value: 0, unit: 'mm' },
|
||||
bottom: { value: 24, unit: 'mm' },
|
||||
left: { value: 0, unit: 'mm' }
|
||||
});
|
||||
|
||||
const marginInnerDetailed = ref({
|
||||
top: { value: 0, unit: 'mm' },
|
||||
right: { value: 0, unit: 'mm' },
|
||||
bottom: { value: 0, unit: 'mm' },
|
||||
left: { value: 0, unit: 'mm' }
|
||||
});
|
||||
|
||||
const marginOuterLinked = ref(false);
|
||||
const marginInnerLinked = ref(false);
|
||||
|
||||
// Track previous values to detect which one changed
|
||||
const prevMarginOuter = ref({
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 24,
|
||||
left: 0
|
||||
});
|
||||
|
||||
const prevMarginInner = ref({
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0
|
||||
});
|
||||
|
||||
let isUpdatingFromStore = false;
|
||||
|
||||
// Update margin outer unit for all sides with conversion
|
||||
const updateMarginOuterUnit = (newUnit) => {
|
||||
const sides = ['top', 'right', 'bottom', 'left'];
|
||||
sides.forEach((side) => {
|
||||
const s = marginOuterDetailed.value[side];
|
||||
s.value = convertUnit(s.value, s.unit, newUnit);
|
||||
s.unit = newUnit;
|
||||
});
|
||||
};
|
||||
const {
|
||||
sides: marginOuterDetailed,
|
||||
linked: marginOuterLinked,
|
||||
updateUnit: updateMarginOuterUnit,
|
||||
setFromSpacing: setMarginOuterFromSpacing,
|
||||
} = useLinkedSpacing({
|
||||
initialValues: {
|
||||
top: { value: 0, unit: 'mm' },
|
||||
right: { value: 0, unit: 'mm' },
|
||||
bottom: { value: 24, unit: 'mm' },
|
||||
left: { value: 0, unit: 'mm' },
|
||||
},
|
||||
isUpdatingFromStore: () => isUpdatingFromStore,
|
||||
debouncedUpdate,
|
||||
onUpdate: (s) => {
|
||||
setDetailedMargins('p', s.top, s.right, s.bottom, s.left);
|
||||
},
|
||||
});
|
||||
|
||||
// Update margin inner unit for all sides with conversion
|
||||
const updateMarginInnerUnit = (newUnit) => {
|
||||
const sides = ['top', 'right', 'bottom', 'left'];
|
||||
sides.forEach((side) => {
|
||||
const s = marginInnerDetailed.value[side];
|
||||
s.value = convertUnit(s.value, s.unit, newUnit);
|
||||
s.unit = newUnit;
|
||||
});
|
||||
};
|
||||
const {
|
||||
sides: marginInnerDetailed,
|
||||
linked: marginInnerLinked,
|
||||
updateUnit: updateMarginInnerUnit,
|
||||
setFromSpacing: setMarginInnerFromSpacing,
|
||||
} = useLinkedSpacing({
|
||||
isUpdatingFromStore: () => isUpdatingFromStore,
|
||||
debouncedUpdate,
|
||||
onUpdate: (s) => {
|
||||
setDetailedPadding('p', s.top, s.right, s.bottom, s.left);
|
||||
},
|
||||
});
|
||||
|
||||
// Watchers for body styles
|
||||
watch(font, (val) => {
|
||||
|
|
@ -499,160 +479,6 @@ watch(fontSize, (val) => {
|
|||
});
|
||||
}, { deep: true });
|
||||
|
||||
// Watch when link is toggled
|
||||
watch(marginOuterLinked, (isLinked) => {
|
||||
if (isLinked) {
|
||||
// When linking, sync all to the first non-zero value or top value
|
||||
const current = marginOuterDetailed.value;
|
||||
const syncValue = current.top.value || current.bottom.value || current.left.value || current.right.value;
|
||||
|
||||
isUpdatingFromStore = true;
|
||||
marginOuterDetailed.value.top.value = syncValue;
|
||||
marginOuterDetailed.value.bottom.value = syncValue;
|
||||
marginOuterDetailed.value.left.value = syncValue;
|
||||
marginOuterDetailed.value.right.value = syncValue;
|
||||
|
||||
prevMarginOuter.value.top = syncValue;
|
||||
prevMarginOuter.value.bottom = syncValue;
|
||||
prevMarginOuter.value.left = syncValue;
|
||||
prevMarginOuter.value.right = syncValue;
|
||||
isUpdatingFromStore = false;
|
||||
}
|
||||
});
|
||||
|
||||
watch(marginInnerLinked, (isLinked) => {
|
||||
if (isLinked) {
|
||||
// When linking, sync all to the first non-zero value or top value
|
||||
const current = marginInnerDetailed.value;
|
||||
const syncValue = current.top.value || current.bottom.value || current.left.value || current.right.value;
|
||||
|
||||
isUpdatingFromStore = true;
|
||||
marginInnerDetailed.value.top.value = syncValue;
|
||||
marginInnerDetailed.value.bottom.value = syncValue;
|
||||
marginInnerDetailed.value.left.value = syncValue;
|
||||
marginInnerDetailed.value.right.value = syncValue;
|
||||
|
||||
prevMarginInner.value.top = syncValue;
|
||||
prevMarginInner.value.bottom = syncValue;
|
||||
prevMarginInner.value.left = syncValue;
|
||||
prevMarginInner.value.right = syncValue;
|
||||
isUpdatingFromStore = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Watch margin outer values
|
||||
watch(() => [
|
||||
marginOuterDetailed.value.top.value,
|
||||
marginOuterDetailed.value.bottom.value,
|
||||
marginOuterDetailed.value.left.value,
|
||||
marginOuterDetailed.value.right.value,
|
||||
], () => {
|
||||
if (isUpdatingFromStore) return;
|
||||
|
||||
// If linked, sync all values to the one that changed
|
||||
if (marginOuterLinked.value) {
|
||||
const current = {
|
||||
top: marginOuterDetailed.value.top.value,
|
||||
bottom: marginOuterDetailed.value.bottom.value,
|
||||
left: marginOuterDetailed.value.left.value,
|
||||
right: marginOuterDetailed.value.right.value,
|
||||
};
|
||||
|
||||
// Find which value actually changed by comparing with previous
|
||||
let changedValue = null;
|
||||
if (current.top !== prevMarginOuter.value.top) changedValue = current.top;
|
||||
else if (current.bottom !== prevMarginOuter.value.bottom) changedValue = current.bottom;
|
||||
else if (current.left !== prevMarginOuter.value.left) changedValue = current.left;
|
||||
else if (current.right !== prevMarginOuter.value.right) changedValue = current.right;
|
||||
|
||||
if (changedValue !== null) {
|
||||
isUpdatingFromStore = true;
|
||||
marginOuterDetailed.value.top.value = changedValue;
|
||||
marginOuterDetailed.value.bottom.value = changedValue;
|
||||
marginOuterDetailed.value.left.value = changedValue;
|
||||
marginOuterDetailed.value.right.value = changedValue;
|
||||
|
||||
// Update previous values
|
||||
prevMarginOuter.value.top = changedValue;
|
||||
prevMarginOuter.value.bottom = changedValue;
|
||||
prevMarginOuter.value.left = changedValue;
|
||||
prevMarginOuter.value.right = changedValue;
|
||||
isUpdatingFromStore = false;
|
||||
}
|
||||
} else {
|
||||
// Update previous values even when not linked
|
||||
prevMarginOuter.value.top = marginOuterDetailed.value.top.value;
|
||||
prevMarginOuter.value.bottom = marginOuterDetailed.value.bottom.value;
|
||||
prevMarginOuter.value.left = marginOuterDetailed.value.left.value;
|
||||
prevMarginOuter.value.right = marginOuterDetailed.value.right.value;
|
||||
}
|
||||
|
||||
debouncedUpdate(() => {
|
||||
setDetailedMargins('p',
|
||||
marginOuterDetailed.value.top,
|
||||
marginOuterDetailed.value.right,
|
||||
marginOuterDetailed.value.bottom,
|
||||
marginOuterDetailed.value.left
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// Watch margin inner values
|
||||
watch(() => [
|
||||
marginInnerDetailed.value.top.value,
|
||||
marginInnerDetailed.value.bottom.value,
|
||||
marginInnerDetailed.value.left.value,
|
||||
marginInnerDetailed.value.right.value,
|
||||
], () => {
|
||||
if (isUpdatingFromStore) return;
|
||||
|
||||
// If linked, sync all values to the one that changed
|
||||
if (marginInnerLinked.value) {
|
||||
const current = {
|
||||
top: marginInnerDetailed.value.top.value,
|
||||
bottom: marginInnerDetailed.value.bottom.value,
|
||||
left: marginInnerDetailed.value.left.value,
|
||||
right: marginInnerDetailed.value.right.value,
|
||||
};
|
||||
|
||||
// Find which value actually changed by comparing with previous
|
||||
let changedValue = null;
|
||||
if (current.top !== prevMarginInner.value.top) changedValue = current.top;
|
||||
else if (current.bottom !== prevMarginInner.value.bottom) changedValue = current.bottom;
|
||||
else if (current.left !== prevMarginInner.value.left) changedValue = current.left;
|
||||
else if (current.right !== prevMarginInner.value.right) changedValue = current.right;
|
||||
|
||||
if (changedValue !== null) {
|
||||
isUpdatingFromStore = true;
|
||||
marginInnerDetailed.value.top.value = changedValue;
|
||||
marginInnerDetailed.value.bottom.value = changedValue;
|
||||
marginInnerDetailed.value.left.value = changedValue;
|
||||
marginInnerDetailed.value.right.value = changedValue;
|
||||
|
||||
// Update previous values
|
||||
prevMarginInner.value.top = changedValue;
|
||||
prevMarginInner.value.bottom = changedValue;
|
||||
prevMarginInner.value.left = changedValue;
|
||||
prevMarginInner.value.right = changedValue;
|
||||
isUpdatingFromStore = false;
|
||||
}
|
||||
} else {
|
||||
// Update previous values even when not linked
|
||||
prevMarginInner.value.top = marginInnerDetailed.value.top.value;
|
||||
prevMarginInner.value.bottom = marginInnerDetailed.value.bottom.value;
|
||||
prevMarginInner.value.left = marginInnerDetailed.value.left.value;
|
||||
prevMarginInner.value.right = marginInnerDetailed.value.right.value;
|
||||
}
|
||||
|
||||
debouncedUpdate(() => {
|
||||
setDetailedPadding('p',
|
||||
marginInnerDetailed.value.top,
|
||||
marginInnerDetailed.value.right,
|
||||
marginInnerDetailed.value.bottom,
|
||||
marginInnerDetailed.value.left
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// Sync from store
|
||||
const syncFromStore = () => {
|
||||
|
|
@ -680,70 +506,11 @@ const syncFromStore = () => {
|
|||
|
||||
// Margins
|
||||
const margins = extractSpacing('p', 'margin');
|
||||
if (margins) {
|
||||
if (margins.simple) {
|
||||
// All margins are the same
|
||||
marginOuterDetailed.value = {
|
||||
top: { ...margins.simple },
|
||||
right: { ...margins.simple },
|
||||
bottom: { ...margins.simple },
|
||||
left: { ...margins.simple }
|
||||
};
|
||||
marginOuterLinked.value = true;
|
||||
} else if (margins.detailed) {
|
||||
marginOuterDetailed.value = margins.detailed;
|
||||
// Check if all values are the same
|
||||
const allSame =
|
||||
margins.detailed.top.value === margins.detailed.right.value &&
|
||||
margins.detailed.top.value === margins.detailed.bottom.value &&
|
||||
margins.detailed.top.value === margins.detailed.left.value &&
|
||||
margins.detailed.top.unit === margins.detailed.right.unit &&
|
||||
margins.detailed.top.unit === margins.detailed.bottom.unit &&
|
||||
margins.detailed.top.unit === margins.detailed.left.unit;
|
||||
marginOuterLinked.value = allSame;
|
||||
}
|
||||
}
|
||||
if (margins) setMarginOuterFromSpacing(margins);
|
||||
|
||||
// Padding
|
||||
const padding = extractSpacing('p', 'padding');
|
||||
if (padding) {
|
||||
if (padding.simple) {
|
||||
// All paddings are the same
|
||||
marginInnerDetailed.value = {
|
||||
top: { ...padding.simple },
|
||||
right: { ...padding.simple },
|
||||
bottom: { ...padding.simple },
|
||||
left: { ...padding.simple }
|
||||
};
|
||||
marginInnerLinked.value = true;
|
||||
} else if (padding.detailed) {
|
||||
marginInnerDetailed.value = padding.detailed;
|
||||
// Check if all values are the same
|
||||
const allSame =
|
||||
padding.detailed.top.value === padding.detailed.right.value &&
|
||||
padding.detailed.top.value === padding.detailed.bottom.value &&
|
||||
padding.detailed.top.value === padding.detailed.left.value &&
|
||||
padding.detailed.top.unit === padding.detailed.right.unit &&
|
||||
padding.detailed.top.unit === padding.detailed.bottom.unit &&
|
||||
padding.detailed.top.unit === padding.detailed.left.unit;
|
||||
marginInnerLinked.value = allSame;
|
||||
}
|
||||
}
|
||||
|
||||
// Update previous values to match current state
|
||||
prevMarginOuter.value = {
|
||||
top: marginOuterDetailed.value.top.value,
|
||||
right: marginOuterDetailed.value.right.value,
|
||||
bottom: marginOuterDetailed.value.bottom.value,
|
||||
left: marginOuterDetailed.value.left.value
|
||||
};
|
||||
|
||||
prevMarginInner.value = {
|
||||
top: marginInnerDetailed.value.top.value,
|
||||
right: marginInnerDetailed.value.right.value,
|
||||
bottom: marginInnerDetailed.value.bottom.value,
|
||||
left: marginInnerDetailed.value.left.value
|
||||
};
|
||||
if (padding) setMarginInnerFromSpacing(padding);
|
||||
|
||||
isUpdatingFromStore = false;
|
||||
};
|
||||
|
|
@ -757,13 +524,9 @@ const updateColorisButtons = () => {
|
|||
};
|
||||
|
||||
onMounted(() => {
|
||||
Coloris.init();
|
||||
Coloris({
|
||||
themeMode: 'dark',
|
||||
alpha: true,
|
||||
initColoris({
|
||||
format: 'auto',
|
||||
formatToggle: true,
|
||||
swatches: ['#000000', '#FFFFFF', '#FF0000', '#00FF00', '#0000FF', 'transparent']
|
||||
swatches: ['#000000', '#FFFFFF', '#FF0000', '#00FF00', '#0000FF', 'transparent'],
|
||||
});
|
||||
syncFromStore();
|
||||
setTimeout(updateColorisButtons, 100);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue