feat: implement inheritance lock/unlock with CSS commenting system
All checks were successful
Deploy / Build and Deploy to Production (push) Successful in 16s

Add ability to lock/unlock inheritance for element styles while preserving
custom values. Locked styles are commented in the CSS and restored when unlocked.

New utilities:
- Create css-comments.js with comment/uncomment functions
- Add parseValueWithUnit to css-parsing.js for value parsing
- Add getBlockState, commentCssBlock, uncommentCssBlock to stylesheet store

ElementPopup improvements:
- Detect inheritance state from CSS block state (active/commented/none)
- Capture computed styles from iframe when unlocking with no custom CSS
- Comment/uncomment CSS blocks instead of deleting them on lock toggle
- Use nextTick to prevent race condition with watchers during popup init
- Extract values from both active and commented CSS blocks

Workflow:
1. First unlock: Capture computed styles → create CSS block
2. Lock: Comment the CSS block (styles preserved in comments)
3. Unlock again: Uncomment the block (styles restored)

Fixes issue where CSS rules were created on popup open due to
watcher race conditions during initialization.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
isUnknown 2026-01-09 14:31:42 +01:00
parent b123e92da8
commit 93df05c49f
4 changed files with 300 additions and 25 deletions

View file

@ -1,6 +1,7 @@
import { defineStore } from 'pinia';
import { ref, computed, watch } from 'vue';
import cssParsingUtils from '../utils/css-parsing';
import * as cssComments from '../utils/css-comments';
import prettier from 'prettier/standalone';
import parserPostcss from 'prettier/plugins/postcss';
import { getCsrfToken } from '../utils/kirby-auth';
@ -81,10 +82,24 @@ export const useStylesheetStore = defineStore('stylesheet', () => {
});
};
const extractValue = (selector, property) => {
// Try to extract from custom CSS first, then from base CSS
const extractValue = (selector, property, includeCommented = true) => {
// Try to extract from active custom CSS first
const customValue = cssParsingUtils.extractCssValue(customCss.value, selector, property);
if (customValue) return customValue;
// If includeCommented, try to extract from commented block
if (includeCommented) {
const commentedBlock = cssComments.extractCommentedBlock(customCss.value, selector);
if (commentedBlock) {
const commentedValue = cssComments.extractValueFromCommentedBlock(commentedBlock, property);
if (commentedValue) {
// Parse value with unit if needed
return cssParsingUtils.parseValueWithUnit(commentedValue);
}
}
}
// Finally, try base CSS
return cssParsingUtils.extractCssValue(baseCss.value, selector, property);
};
@ -117,6 +132,29 @@ export const useStylesheetStore = defineStore('stylesheet', () => {
customCss.value = newCss;
};
// Comment a CSS block in custom CSS
const commentCssBlock = (selector) => {
const block = cssParsingUtils.extractCssBlock(customCss.value, selector);
if (!block) return;
customCss.value = cssComments.commentBlock(customCss.value, block);
};
// Uncomment a CSS block in custom CSS
const uncommentCssBlock = (selector) => {
customCss.value = cssComments.uncommentBlock(customCss.value, selector);
};
// Check if a CSS block is commented
const isBlockCommented = (selector) => {
return cssComments.isBlockCommented(customCss.value, selector);
};
// Get the state of a CSS block
const getBlockState = (selector) => {
return cssComments.getBlockState(customCss.value, selector);
};
// Load base CSS from stylesheet.print.css
const loadBaseCss = async () => {
const response = await fetch('/assets/css/stylesheet.print.css');
@ -228,6 +266,10 @@ export const useStylesheetStore = defineStore('stylesheet', () => {
replaceBlock,
replaceInCustomCss,
setCustomCss,
commentCssBlock,
uncommentCssBlock,
isBlockCommented,
getBlockState,
formatCustomCss,
loadBaseCss,
initializeFromNarrative,