Compare commits
No commits in common. "b584a539fe7c4c8eab71a7693ea561b1947e3c69" and "628f666d6aba9eb48e15df59c9405b318acf10a0" have entirely different histories.
b584a539fe
...
628f666d6a
10 changed files with 1012 additions and 797 deletions
16
package-lock.json
generated
16
package-lock.json
generated
|
|
@ -12,7 +12,6 @@
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"pagedjs": "^0.4.3",
|
"pagedjs": "^0.4.3",
|
||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"prettier": "^3.7.4",
|
|
||||||
"vue": "^3.5.24"
|
"vue": "^3.5.24"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
@ -1889,21 +1888,6 @@
|
||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
|
||||||
"version": "3.7.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz",
|
|
||||||
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
|
||||||
"prettier": "bin/prettier.cjs"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/readdirp": {
|
"node_modules/readdirp": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"pagedjs": "^0.4.3",
|
"pagedjs": "^0.4.3",
|
||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"prettier": "^3.7.4",
|
|
||||||
"vue": "^3.5.24"
|
"vue": "^3.5.24"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
|
|
@ -66,13 +66,6 @@
|
||||||
>
|
>
|
||||||
px
|
px
|
||||||
</button>
|
</button>
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
:class="{ active: margins.top.unit === 'rem' }"
|
|
||||||
@click="margins.top.unit = 'rem'"
|
|
||||||
>
|
|
||||||
rem
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -101,13 +94,6 @@
|
||||||
>
|
>
|
||||||
px
|
px
|
||||||
</button>
|
</button>
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
:class="{ active: margins.bottom.unit === 'rem' }"
|
|
||||||
@click="margins.bottom.unit = 'rem'"
|
|
||||||
>
|
|
||||||
rem
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -136,13 +122,6 @@
|
||||||
>
|
>
|
||||||
px
|
px
|
||||||
</button>
|
</button>
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
:class="{ active: margins.left.unit === 'rem' }"
|
|
||||||
@click="margins.left.unit = 'rem'"
|
|
||||||
>
|
|
||||||
rem
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -171,13 +150,6 @@
|
||||||
>
|
>
|
||||||
px
|
px
|
||||||
</button>
|
</button>
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
:class="{ active: margins.right.unit === 'rem' }"
|
|
||||||
@click="margins.right.unit = 'rem'"
|
|
||||||
>
|
|
||||||
rem
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,70 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="input-with-unit">
|
|
||||||
<input
|
|
||||||
v-if="showRange"
|
|
||||||
type="range"
|
|
||||||
:value="modelValue.value"
|
|
||||||
:min="min"
|
|
||||||
:max="max"
|
|
||||||
:step="step"
|
|
||||||
@input="updateValue(Number($event.target.value))"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
:value="modelValue.value"
|
|
||||||
:min="min"
|
|
||||||
:max="max"
|
|
||||||
:step="step"
|
|
||||||
class="size-input"
|
|
||||||
@input="updateValue(Number($event.target.value))"
|
|
||||||
/>
|
|
||||||
<UnitToggle
|
|
||||||
:modelValue="modelValue.unit"
|
|
||||||
:units="units"
|
|
||||||
@update:modelValue="updateUnit"
|
|
||||||
/>
|
|
||||||
<slot name="after" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import UnitToggle from './UnitToggle.vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
validator: (v) => 'value' in v && 'unit' in v
|
|
||||||
},
|
|
||||||
units: {
|
|
||||||
type: Array,
|
|
||||||
default: () => ['mm', 'px']
|
|
||||||
},
|
|
||||||
min: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
max: {
|
|
||||||
type: Number,
|
|
||||||
default: 100
|
|
||||||
},
|
|
||||||
step: {
|
|
||||||
type: Number,
|
|
||||||
default: 1
|
|
||||||
},
|
|
||||||
showRange: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue']);
|
|
||||||
|
|
||||||
const updateValue = (value) => {
|
|
||||||
emit('update:modelValue', { ...props.modelValue, value });
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateUnit = (unit) => {
|
|
||||||
emit('update:modelValue', { ...props.modelValue, unit });
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,162 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="margin-editor">
|
|
||||||
<div class="field">
|
|
||||||
<label :for="id">{{ label }}</label>
|
|
||||||
<div class="input-with-unit">
|
|
||||||
<input
|
|
||||||
:id="id"
|
|
||||||
type="number"
|
|
||||||
:value="simple.value"
|
|
||||||
min="0"
|
|
||||||
@input="updateSimpleValue(Number($event.target.value))"
|
|
||||||
/>
|
|
||||||
<UnitToggle
|
|
||||||
:modelValue="simple.unit"
|
|
||||||
:units="units"
|
|
||||||
@update:modelValue="updateSimpleUnit"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="collapse-toggle"
|
|
||||||
:class="{ expanded }"
|
|
||||||
@click="toggleExpanded"
|
|
||||||
title="Réglages détaillés"
|
|
||||||
>
|
|
||||||
▶
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="expanded" class="subsection collapsed-section">
|
|
||||||
<div v-for="side in sides" :key="side.key" class="field">
|
|
||||||
<label :for="`${id}-${side.key}`">{{ side.label }}</label>
|
|
||||||
<div class="input-with-unit">
|
|
||||||
<input
|
|
||||||
:id="`${id}-${side.key}`"
|
|
||||||
type="number"
|
|
||||||
:value="detailed[side.key].value"
|
|
||||||
min="0"
|
|
||||||
@input="updateDetailedValue(side.key, Number($event.target.value))"
|
|
||||||
/>
|
|
||||||
<UnitToggle
|
|
||||||
:modelValue="detailed[side.key].unit"
|
|
||||||
:units="units"
|
|
||||||
@update:modelValue="(unit) => updateDetailedUnit(side.key, unit)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, watch } from 'vue';
|
|
||||||
import UnitToggle from './UnitToggle.vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
simple: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
validator: (v) => 'value' in v && 'unit' in v
|
|
||||||
},
|
|
||||||
detailed: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
validator: (v) => ['top', 'right', 'bottom', 'left'].every(k => k in v)
|
|
||||||
},
|
|
||||||
units: {
|
|
||||||
type: Array,
|
|
||||||
default: () => ['mm', 'px']
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:simple', 'update:detailed', 'change']);
|
|
||||||
|
|
||||||
const expanded = ref(false);
|
|
||||||
let isSyncing = false;
|
|
||||||
|
|
||||||
const sides = [
|
|
||||||
{ key: 'top', label: 'Haut' },
|
|
||||||
{ key: 'bottom', label: 'Bas' },
|
|
||||||
{ key: 'left', label: 'Gauche' },
|
|
||||||
{ key: 'right', label: 'Droite' }
|
|
||||||
];
|
|
||||||
|
|
||||||
const toggleExpanded = () => {
|
|
||||||
expanded.value = !expanded.value;
|
|
||||||
if (expanded.value) {
|
|
||||||
// Sync detailed values from simple when expanding
|
|
||||||
syncDetailedFromSimple();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const syncDetailedFromSimple = () => {
|
|
||||||
isSyncing = true;
|
|
||||||
const newDetailed = {};
|
|
||||||
for (const side of sides) {
|
|
||||||
newDetailed[side.key] = { value: props.simple.value, unit: props.simple.unit };
|
|
||||||
}
|
|
||||||
emit('update:detailed', newDetailed);
|
|
||||||
isSyncing = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateSimpleValue = (value) => {
|
|
||||||
const newSimple = { ...props.simple, value };
|
|
||||||
emit('update:simple', newSimple);
|
|
||||||
|
|
||||||
// Sync all detailed values
|
|
||||||
isSyncing = true;
|
|
||||||
const newDetailed = {};
|
|
||||||
for (const side of sides) {
|
|
||||||
newDetailed[side.key] = { value, unit: props.simple.unit };
|
|
||||||
}
|
|
||||||
emit('update:detailed', newDetailed);
|
|
||||||
isSyncing = false;
|
|
||||||
|
|
||||||
emit('change', { type: 'simple', simple: newSimple });
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateSimpleUnit = (unit) => {
|
|
||||||
const newSimple = { ...props.simple, unit };
|
|
||||||
emit('update:simple', newSimple);
|
|
||||||
|
|
||||||
// Sync all detailed units
|
|
||||||
isSyncing = true;
|
|
||||||
const newDetailed = {};
|
|
||||||
for (const side of sides) {
|
|
||||||
newDetailed[side.key] = { ...props.detailed[side.key], unit };
|
|
||||||
}
|
|
||||||
emit('update:detailed', newDetailed);
|
|
||||||
isSyncing = false;
|
|
||||||
|
|
||||||
emit('change', { type: 'simple', simple: newSimple });
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateDetailedValue = (key, value) => {
|
|
||||||
if (isSyncing) return;
|
|
||||||
const newDetailed = { ...props.detailed, [key]: { ...props.detailed[key], value } };
|
|
||||||
emit('update:detailed', newDetailed);
|
|
||||||
if (expanded.value) {
|
|
||||||
emit('change', { type: 'detailed', detailed: newDetailed });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateDetailedUnit = (key, unit) => {
|
|
||||||
if (isSyncing) return;
|
|
||||||
const newDetailed = { ...props.detailed, [key]: { ...props.detailed[key], unit } };
|
|
||||||
emit('update:detailed', newDetailed);
|
|
||||||
if (expanded.value) {
|
|
||||||
emit('change', { type: 'detailed', detailed: newDetailed });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
defineExpose({ expanded });
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="unit-toggle">
|
|
||||||
<button
|
|
||||||
v-for="unit in units"
|
|
||||||
:key="unit"
|
|
||||||
type="button"
|
|
||||||
:class="{ active: modelValue === unit }"
|
|
||||||
@click="$emit('update:modelValue', unit)"
|
|
||||||
>
|
|
||||||
{{ unit }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
defineProps({
|
|
||||||
modelValue: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
units: {
|
|
||||||
type: Array,
|
|
||||||
default: () => ['mm', 'px']
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
defineEmits(['update:modelValue']);
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,119 +0,0 @@
|
||||||
import { useStylesheetStore } from '../stores/stylesheet';
|
|
||||||
|
|
||||||
export function useCssSync() {
|
|
||||||
const store = useStylesheetStore();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract a simple CSS value (string)
|
|
||||||
*/
|
|
||||||
const extractValue = (selector, property) => {
|
|
||||||
const block = store.extractBlock(selector);
|
|
||||||
if (!block) return null;
|
|
||||||
|
|
||||||
const match = block.match(new RegExp(`${property}:\\s*([^;]+)`, 'i'));
|
|
||||||
return match ? match[1].trim() : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract a numeric CSS value with unit
|
|
||||||
* Returns { value: number, unit: string } or null
|
|
||||||
*/
|
|
||||||
const extractNumericValue = (selector, property, allowedUnits = ['px', 'em', 'rem', 'mm']) => {
|
|
||||||
const block = store.extractBlock(selector);
|
|
||||||
if (!block) return null;
|
|
||||||
|
|
||||||
const unitsPattern = allowedUnits.join('|');
|
|
||||||
const match = block.match(new RegExp(`${property}:\\s*([0-9.]+)(${unitsPattern})`, 'i'));
|
|
||||||
|
|
||||||
if (match) {
|
|
||||||
return {
|
|
||||||
value: parseFloat(match[1]),
|
|
||||||
unit: match[2].toLowerCase()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract margin/padding shorthand (handles 1 or 4 values)
|
|
||||||
* Returns { simple: { value, unit } } or { detailed: { top, right, bottom, left } }
|
|
||||||
*/
|
|
||||||
const extractSpacing = (selector, property, allowedUnits = ['mm', 'px', 'rem']) => {
|
|
||||||
const block = store.extractBlock(selector);
|
|
||||||
if (!block) return null;
|
|
||||||
|
|
||||||
const unitsPattern = allowedUnits.join('|');
|
|
||||||
|
|
||||||
// Check for detailed properties first (property-top, property-right, etc.)
|
|
||||||
const topMatch = block.match(new RegExp(`${property}-top:\\s*([0-9.]+)(${unitsPattern})`, 'i'));
|
|
||||||
|
|
||||||
if (topMatch) {
|
|
||||||
const rightMatch = block.match(new RegExp(`${property}-right:\\s*([0-9.]+)(${unitsPattern})`, 'i'));
|
|
||||||
const bottomMatch = block.match(new RegExp(`${property}-bottom:\\s*([0-9.]+)(${unitsPattern})`, 'i'));
|
|
||||||
const leftMatch = block.match(new RegExp(`${property}-left:\\s*([0-9.]+)(${unitsPattern})`, 'i'));
|
|
||||||
|
|
||||||
return {
|
|
||||||
detailed: {
|
|
||||||
top: topMatch ? { value: parseFloat(topMatch[1]), unit: topMatch[2] } : { value: 0, unit: 'mm' },
|
|
||||||
right: rightMatch ? { value: parseFloat(rightMatch[1]), unit: rightMatch[2] } : { value: 0, unit: 'mm' },
|
|
||||||
bottom: bottomMatch ? { value: parseFloat(bottomMatch[1]), unit: bottomMatch[2] } : { value: 0, unit: 'mm' },
|
|
||||||
left: leftMatch ? { value: parseFloat(leftMatch[1]), unit: leftMatch[2] } : { value: 0, unit: 'mm' },
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for shorthand property
|
|
||||||
const shorthandMatch = block.match(new RegExp(`${property}:\\s*([^;]+)`, 'i'));
|
|
||||||
if (!shorthandMatch) return null;
|
|
||||||
|
|
||||||
const shorthandValue = shorthandMatch[1].trim();
|
|
||||||
|
|
||||||
// Check for 4-value format: "0mm 0mm 24mm 0mm" (top right bottom left)
|
|
||||||
const fourValuePattern = new RegExp(
|
|
||||||
`^([0-9.]+)(${unitsPattern})\\s+([0-9.]+)(${unitsPattern})\\s+([0-9.]+)(${unitsPattern})\\s+([0-9.]+)(${unitsPattern})$`,
|
|
||||||
'i'
|
|
||||||
);
|
|
||||||
const fourValueMatch = shorthandValue.match(fourValuePattern);
|
|
||||||
|
|
||||||
if (fourValueMatch) {
|
|
||||||
return {
|
|
||||||
detailed: {
|
|
||||||
top: { value: parseFloat(fourValueMatch[1]), unit: fourValueMatch[2] },
|
|
||||||
right: { value: parseFloat(fourValueMatch[3]), unit: fourValueMatch[4] },
|
|
||||||
bottom: { value: parseFloat(fourValueMatch[5]), unit: fourValueMatch[6] },
|
|
||||||
left: { value: parseFloat(fourValueMatch[7]), unit: fourValueMatch[8] },
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Single value format: "10mm"
|
|
||||||
const singleValuePattern = new RegExp(`^([0-9.]+)(${unitsPattern})$`, 'i');
|
|
||||||
const singleValueMatch = shorthandValue.match(singleValuePattern);
|
|
||||||
|
|
||||||
if (singleValueMatch) {
|
|
||||||
return {
|
|
||||||
simple: {
|
|
||||||
value: parseFloat(singleValueMatch[1]),
|
|
||||||
unit: singleValueMatch[2]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a property value equals a specific string
|
|
||||||
*/
|
|
||||||
const hasValue = (selector, property, expectedValue) => {
|
|
||||||
const value = extractValue(selector, property);
|
|
||||||
return value === expectedValue;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
extractValue,
|
|
||||||
extractNumericValue,
|
|
||||||
extractSpacing,
|
|
||||||
hasValue,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,120 +0,0 @@
|
||||||
import { useStylesheetStore } from '../stores/stylesheet';
|
|
||||||
|
|
||||||
export function useCssUpdater() {
|
|
||||||
const store = useStylesheetStore();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update or add a CSS property for a given selector
|
|
||||||
*/
|
|
||||||
const updateStyle = (selector, property, value) => {
|
|
||||||
const currentBlock = store.extractBlock(selector) || createRule(selector);
|
|
||||||
|
|
||||||
if (currentBlock.includes(`${property}:`)) {
|
|
||||||
const updatedBlock = currentBlock.replace(
|
|
||||||
new RegExp(`(${property}:\\s*)[^;]+`, 'i'),
|
|
||||||
`$1${value}`
|
|
||||||
);
|
|
||||||
store.content = store.content.replace(currentBlock, updatedBlock);
|
|
||||||
} else {
|
|
||||||
const updatedBlock = currentBlock.replace(
|
|
||||||
/(\s*})$/,
|
|
||||||
` ${property}: ${value};\n$1`
|
|
||||||
);
|
|
||||||
store.content = store.content.replace(currentBlock, updatedBlock);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a CSS property from a selector
|
|
||||||
*/
|
|
||||||
const removeProperty = (selector, property) => {
|
|
||||||
const currentBlock = store.extractBlock(selector);
|
|
||||||
if (!currentBlock) return;
|
|
||||||
|
|
||||||
const updatedBlock = currentBlock.replace(
|
|
||||||
new RegExp(`\\s*${property}:\\s*[^;]+;\\n?`, 'gi'),
|
|
||||||
''
|
|
||||||
);
|
|
||||||
|
|
||||||
if (updatedBlock !== currentBlock) {
|
|
||||||
store.content = store.content.replace(currentBlock, updatedBlock);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove multiple CSS properties from a selector
|
|
||||||
*/
|
|
||||||
const removeProperties = (selector, properties) => {
|
|
||||||
let currentBlock = store.extractBlock(selector);
|
|
||||||
if (!currentBlock) return;
|
|
||||||
|
|
||||||
let updatedBlock = currentBlock;
|
|
||||||
for (const property of properties) {
|
|
||||||
updatedBlock = updatedBlock.replace(
|
|
||||||
new RegExp(`\\s*${property}:\\s*[^;]+;\\n?`, 'gi'),
|
|
||||||
''
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updatedBlock !== currentBlock) {
|
|
||||||
store.content = store.content.replace(currentBlock, updatedBlock);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new CSS rule for a selector
|
|
||||||
*/
|
|
||||||
const createRule = (selector) => {
|
|
||||||
store.content += `\n\n${selector} {\n}\n`;
|
|
||||||
return `${selector} {\n}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove detailed margin properties and set shorthand
|
|
||||||
*/
|
|
||||||
const setMargin = (selector, value, unit) => {
|
|
||||||
removeProperties(selector, ['margin-top', 'margin-right', 'margin-bottom', 'margin-left']);
|
|
||||||
updateStyle(selector, 'margin', `${value}${unit}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove shorthand margin and set detailed margins
|
|
||||||
*/
|
|
||||||
const setDetailedMargins = (selector, top, right, bottom, left) => {
|
|
||||||
removeProperty(selector, 'margin');
|
|
||||||
updateStyle(selector, 'margin-top', `${top.value}${top.unit}`);
|
|
||||||
updateStyle(selector, 'margin-right', `${right.value}${right.unit}`);
|
|
||||||
updateStyle(selector, 'margin-bottom', `${bottom.value}${bottom.unit}`);
|
|
||||||
updateStyle(selector, 'margin-left', `${left.value}${left.unit}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove detailed padding properties and set shorthand
|
|
||||||
*/
|
|
||||||
const setPadding = (selector, value, unit) => {
|
|
||||||
removeProperties(selector, ['padding-top', 'padding-right', 'padding-bottom', 'padding-left']);
|
|
||||||
updateStyle(selector, 'padding', `${value}${unit}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove shorthand padding and set detailed padding
|
|
||||||
*/
|
|
||||||
const setDetailedPadding = (selector, top, right, bottom, left) => {
|
|
||||||
removeProperty(selector, 'padding');
|
|
||||||
updateStyle(selector, 'padding-top', `${top.value}${top.unit}`);
|
|
||||||
updateStyle(selector, 'padding-right', `${right.value}${right.unit}`);
|
|
||||||
updateStyle(selector, 'padding-bottom', `${bottom.value}${bottom.unit}`);
|
|
||||||
updateStyle(selector, 'padding-left', `${left.value}${left.unit}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
updateStyle,
|
|
||||||
removeProperty,
|
|
||||||
removeProperties,
|
|
||||||
createRule,
|
|
||||||
setMargin,
|
|
||||||
setDetailedMargins,
|
|
||||||
setPadding,
|
|
||||||
setDetailedPadding,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,44 +1,9 @@
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { ref, watch } from 'vue';
|
import { ref } from 'vue';
|
||||||
import cssParsingUtils from '../utils/css-parsing';
|
import cssParsingUtils from '../utils/css-parsing';
|
||||||
import prettier from 'prettier/standalone';
|
|
||||||
import parserPostcss from 'prettier/plugins/postcss';
|
|
||||||
|
|
||||||
export const useStylesheetStore = defineStore('stylesheet', () => {
|
export const useStylesheetStore = defineStore('stylesheet', () => {
|
||||||
const content = ref('');
|
const content = ref('');
|
||||||
let formatTimer = null;
|
|
||||||
let isFormatting = false;
|
|
||||||
|
|
||||||
// Format CSS with Prettier
|
|
||||||
const formatContent = async () => {
|
|
||||||
if (isFormatting || !content.value) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
isFormatting = true;
|
|
||||||
const formatted = await prettier.format(content.value, {
|
|
||||||
parser: 'css',
|
|
||||||
plugins: [parserPostcss],
|
|
||||||
printWidth: 80,
|
|
||||||
tabWidth: 2,
|
|
||||||
useTabs: false,
|
|
||||||
});
|
|
||||||
content.value = formatted;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('CSS formatting error:', error);
|
|
||||||
} finally {
|
|
||||||
isFormatting = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Watch content and format after 500ms of inactivity
|
|
||||||
watch(content, () => {
|
|
||||||
if (isFormatting) return;
|
|
||||||
|
|
||||||
clearTimeout(formatTimer);
|
|
||||||
formatTimer = setTimeout(() => {
|
|
||||||
formatContent();
|
|
||||||
}, 500);
|
|
||||||
});
|
|
||||||
|
|
||||||
const loadStylesheet = async () => {
|
const loadStylesheet = async () => {
|
||||||
const response = await fetch('/assets/css/stylesheet.css');
|
const response = await fetch('/assets/css/stylesheet.css');
|
||||||
|
|
@ -68,7 +33,6 @@ export const useStylesheetStore = defineStore('stylesheet', () => {
|
||||||
loadStylesheet,
|
loadStylesheet,
|
||||||
updateProperty,
|
updateProperty,
|
||||||
extractValue,
|
extractValue,
|
||||||
extractBlock,
|
extractBlock
|
||||||
formatContent
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue