fix: close Coloris picker on iframe clicks and improve editor styling

Add click handler on iframe to close Coloris color picker when user clicks
in the preview area. Also improve editor panel spacing and styling consistency.

Coloris Close Fix:
- Import Coloris in App.vue
- Add click listener on iframe document to call Coloris.close()
- Fixes issue where Coloris remained open when clicking in preview iframe
  (clicks in iframes don't bubble to parent document)

Editor Styling Improvements:
- Increase EditorPanel width from 30rem to 35rem for better readability
- Add CSS variable --space-xs (0.5rem) for consistent spacing
- Improve form field spacing with gaps and better padding
- Add row-gap to margins subsection
- Fix input-with-color width and button height (1.1rem)
- Add gap to unit-toggle buttons
- Better visual hierarchy with margins on h2 and h3

CSS Changes:
- _forms.scss: Consistent spacing, better input padding, gap utilities
- _variables.scss: Add --space-xs variable
- Compiled CSS updated with new styles

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
isUnknown 2025-12-04 16:14:50 +01:00
parent 6a01909b38
commit 3bd6c7ca19
8 changed files with 91 additions and 21 deletions

View file

@ -11,31 +11,49 @@ input[type="number"] {
.settings-section {
h2 {
border-bottom: 1px solid #000;
margin-bottom: var(--space-xs);
}
.settings-subsection:not(:last-child) {
border-bottom: 1px solid var(--color-browngray-050);
}
.settings-subsection {
padding: 0.5rem 0;
padding: var(--space-xs) 0;
h3 {
margin-bottom: var(--space-xs);
}
.field {
display: flex;
label {
label,
select {
width: 50%;
}
input {
padding: 0.1rem 0.1rem 0.1rem 0.3rem;
}
.input-with-unit {
display: flex;
gap: 0.3rem;
.unit-toggle {
display: flex;
gap: 0.3rem;
}
}
.input-with-color {
width: 50%;
.clr-field {
display: flex;
button {
position: absolute;
transform: none;
height: 1rem;
height: 1.1rem;
top: auto;
right: auto;
cursor: pointer;
@ -43,6 +61,7 @@ input[type="number"] {
input {
padding-left: 2.5rem;
width: 100%;
}
}
}
@ -51,6 +70,8 @@ input[type="number"] {
&.margins {
display: flex;
flex-wrap: wrap;
row-gap: var(--space-xs);
h3 {
width: 100%;
}

View file

@ -5,4 +5,6 @@
--color-browngray-300: #b5a9a1;
--border-radius: 0.2rem;
--space-xs: 0.5rem;
}

View file

@ -31,6 +31,7 @@ button {
--color-browngray-200: #d0c4ba;
--color-browngray-300: #b5a9a1;
--border-radius: 0.2rem;
--space-xs: 0.5rem;
}
body,
@ -80,21 +81,37 @@ input[type=number] {
.settings-section h2 {
border-bottom: 1px solid #000;
margin-bottom: var(--space-xs);
}
.settings-section .settings-subsection:not(:last-child) {
border-bottom: 1px solid var(--color-browngray-050);
}
.settings-section .settings-subsection {
padding: 0.5rem 0;
padding: var(--space-xs) 0;
}
.settings-section .settings-subsection h3 {
margin-bottom: var(--space-xs);
}
.settings-section .settings-subsection .field {
display: flex;
}
.settings-section .settings-subsection .field label {
.settings-section .settings-subsection .field label,
.settings-section .settings-subsection .field select {
width: 50%;
}
.settings-section .settings-subsection .field input {
padding: 0.1rem 0.1rem 0.1rem 0.3rem;
}
.settings-section .settings-subsection .field .input-with-unit {
display: flex;
gap: 0.3rem;
}
.settings-section .settings-subsection .field .input-with-unit .unit-toggle {
display: flex;
gap: 0.3rem;
}
.settings-section .settings-subsection .field .input-with-color {
width: 50%;
}
.settings-section .settings-subsection .field .input-with-color .clr-field {
display: flex;
@ -102,17 +119,19 @@ input[type=number] {
.settings-section .settings-subsection .field .input-with-color .clr-field button {
position: absolute;
transform: none;
height: 1rem;
height: 1.1rem;
top: auto;
right: auto;
cursor: pointer;
}
.settings-section .settings-subsection .field .input-with-color .clr-field input {
padding-left: 2.5rem;
width: 100%;
}
.settings-section .settings-subsection.margins {
display: flex;
flex-wrap: wrap;
row-gap: var(--space-xs);
}
.settings-section .settings-subsection.margins h3 {
width: 100%;

View file

@ -1 +1 @@
{"version":3,"sources":["src/_reset.scss","style.css","src/_variables.scss","src/_text.scss","src/_print-styles.scss","src/_forms.scss","src/_buttons.scss"],"names":[],"mappings":"AAAA;;EAEE,UAAA;EACA,SAAA;ACCF;;ADEA;;;;;;EAME,SAAA;ACCF;;ADEA;;EAEE,YAAA;EACA,aAAA;EAEA,mCAAA;ACAF;;ADGA;EACE,6BAAA;EACA,YAAA;ACAF;;ACzBA;EACE,yBAAA;EACA,8BAAA;EACA,8BAAA;EACA,8BAAA;EAEA,uBAAA;AD2BF;;AEjCA;;;;;;;;;;;;;EAaE,uBAAA;AFoCF;;AGjDA,yBAAA;AACA;EACE,QAAA;EACA,2BAAA;AHoDF;AGlDA;EACE,8BAAA;OAAA,kBAAA;AHoDF;;AGjDA;EACE;IACE,sBAAA;EHoDF;AACF;AGlDA;EACE,+BAAA;AHoDF;;AInEA;;;EAGE,4CAAA;AJsEF;;AInEA;EACE,YAAA;AJsEF;;AIlEE;EACE,6BAAA;AJqEJ;AInEE;EACE,mDAAA;AJqEJ;AIlEE;EACE,iBAAA;AJoEJ;AIlEI;EACE,aAAA;AJoEN;AInEM;EACE,UAAA;AJqER;AIlEM;EACE,aAAA;AJoER;AIhEQ;EACE,aAAA;AJkEV;AIjEU;EACE,kBAAA;EACA,eAAA;EACA,YAAA;EACA,SAAA;EACA,WAAA;EACA,eAAA;AJmEZ;AIhEU;EACE,oBAAA;AJkEZ;AI5DI;EACE,aAAA;EACA,eAAA;AJ8DN;AI7DM;EACE,WAAA;AJ+DR;AI7DM;EACE,UAAA;AJ+DR;AI7DQ;EACE,UAAA;AJ+DV;AI3DU;EACE,UAAA;AJ6DZ;;AK9HA;EACE,eAAA;EAEA,4CAAA;EACA,iCAAA;EACA,mCAAA;EACA,sBAAA;ALgIF;AK9HE;EACE,sBAAA;EACA,WAAA;ALgIJ;AK5HI;EACE,sBAAA;EACA,WAAA;EACA,YAAA;AL8HN","file":"style.css"}
{"version":3,"sources":["src/_reset.scss","style.css","src/_variables.scss","src/_text.scss","src/_print-styles.scss","src/_forms.scss","src/_buttons.scss"],"names":[],"mappings":"AAAA;;EAEE,UAAA;EACA,SAAA;ACCF;;ADEA;;;;;;EAME,SAAA;ACCF;;ADEA;;EAEE,YAAA;EACA,aAAA;EAEA,mCAAA;ACAF;;ADGA;EACE,6BAAA;EACA,YAAA;ACAF;;ACzBA;EACE,yBAAA;EACA,8BAAA;EACA,8BAAA;EACA,8BAAA;EAEA,uBAAA;EAEA,kBAAA;AD0BF;;AElCA;;;;;;;;;;;;;EAaE,uBAAA;AFqCF;;AGlDA,yBAAA;AACA;EACE,QAAA;EACA,2BAAA;AHqDF;AGnDA;EACE,8BAAA;OAAA,kBAAA;AHqDF;;AGlDA;EACE;IACE,sBAAA;EHqDF;AACF;AGnDA;EACE,+BAAA;AHqDF;;AIpEA;;;EAGE,4CAAA;AJuEF;;AIpEA;EACE,YAAA;AJuEF;;AInEE;EACE,6BAAA;EACA,8BAAA;AJsEJ;AIpEE;EACE,mDAAA;AJsEJ;AInEE;EACE,0BAAA;AJqEJ;AInEI;EACE,8BAAA;AJqEN;AIlEI;EACE,aAAA;AJoEN;AIlEM;;EAEE,UAAA;AJoER;AIjEM;EACE,oCAAA;AJmER;AIhEM;EACE,aAAA;EACA,WAAA;AJkER;AIhEQ;EACE,aAAA;EACA,WAAA;AJkEV;AI9DM;EACE,UAAA;AJgER;AI/DQ;EACE,aAAA;AJiEV;AIhEU;EACE,kBAAA;EACA,eAAA;EACA,cAAA;EACA,SAAA;EACA,WAAA;EACA,eAAA;AJkEZ;AI/DU;EACE,oBAAA;EACA,WAAA;AJiEZ;AI3DI;EACE,aAAA;EACA,eAAA;EACA,wBAAA;AJ6DN;AI3DM;EACE,WAAA;AJ6DR;AI3DM;EACE,UAAA;AJ6DR;AI3DQ;EACE,UAAA;AJ6DV;AIzDU;EACE,UAAA;AJ2DZ;;AKjJA;EACE,eAAA;EAEA,4CAAA;EACA,iCAAA;EACA,mCAAA;EACA,sBAAA;ALmJF;AKjJE;EACE,sBAAA;EACA,WAAA;ALmJJ;AK/II;EACE,sBAAA;EACA,WAAA;EACA,YAAA;ALiJN","file":"style.css"}

View file

@ -1,10 +1,13 @@
@page {
size: A4;
margin: 20mm 15mm 26mm 15mm;
background: rgba(255, 255, 255, 0);
}
@page {
@bottom-center { content: string(title); }
@bottom-center {
content: string(title);
}
}
h2 {

View file

@ -4,6 +4,7 @@ import EditorPanel from './components/editor/EditorPanel.vue';
import ElementPopup from './components/ElementPopup.vue';
import { onMounted, ref, watch, computed } from 'vue';
import { useStylesheetStore } from './stores/stylesheet';
import Coloris from '@melloware/coloris';
const stylesheetStore = useStylesheetStore();
const previewFrame1 = ref(null);
@ -73,6 +74,11 @@ const renderPreview = async (shouldReloadFromFile = false) => {
elementPopup.value.handleIframeClick
);
// Close Coloris when clicking in the iframe
hiddenFrame.contentDocument.addEventListener('click', () => {
Coloris.close();
});
// Wait for PagedJS to finish rendering
setTimeout(() => {
// Restore scroll position

View file

@ -63,7 +63,7 @@ provide('activeTab', activeTab);
position: fixed;
top: 0;
left: 0;
width: 30rem;
width: 35rem;
height: 100vh;
display: flex;
flex-direction: column;

View file

@ -392,16 +392,23 @@ const updatePageFooters = () => {
currentCss = currentCss.replace(/@page:right\s*\{[^}]*\}/g, '');
// Remove old @page @bottom-center rule if exists
currentCss = currentCss.replace(/@page\s*\{[^}]*@bottom-center[^}]*\}/g, (match) => {
currentCss = currentCss.replace(
/@page\s*\{[^}]*@bottom-center[^}]*\}/g,
(match) => {
return match.replace(/@bottom-center\s*\{[^}]*\}/g, '');
});
}
);
// Remove string-set rule if running title is disabled
if (!runningTitle.value) {
currentCss = currentCss.replace(/\.chapter\s*>\s*h2\s*\{[^}]*string-set:[^}]*\}\s*/g, '');
currentCss = currentCss.replace(
/\.chapter\s*>\s*h2\s*\{[^}]*string-set:[^}]*\}\s*/g,
''
);
} else if (!currentCss.includes('string-set: title')) {
// Add the string-set rule for h2 titles if running title is enabled
const stringSetRule = '\n.chapter > h2 {\n string-set: title content(text);\n}\n';
const stringSetRule =
'\n.chapter > h2 {\n string-set: title content(text);\n}\n';
currentCss += stringSetRule;
}
@ -416,7 +423,8 @@ const updatePageFooters = () => {
if (pageNumbers.value && runningTitle.value) {
// Page number on the left, title right next to it
leftBottomLeft = ' @bottom-left {\n content: counter(page) " " string(title);\n }\n';
leftBottomLeft =
' @bottom-left {\n content: counter(page) " " string(title);\n }\n';
} else if (pageNumbers.value) {
leftBottomLeft = ' @bottom-left {\n content: counter(page);\n }\n';
} else if (runningTitle.value) {
@ -432,11 +440,14 @@ const updatePageFooters = () => {
if (pageNumbers.value && runningTitle.value) {
// Title on the left of page number
rightBottomRight = ' @bottom-right {\n content: string(title) " " counter(page);\n }\n';
rightBottomRight =
' @bottom-right {\n content: string(title) " " counter(page);\n }\n';
} else if (pageNumbers.value) {
rightBottomRight = ' @bottom-right {\n content: counter(page);\n }\n';
rightBottomRight =
' @bottom-right {\n content: counter(page);\n }\n';
} else if (runningTitle.value) {
rightBottomRight = ' @bottom-right {\n content: string(title);\n }\n';
rightBottomRight =
' @bottom-right {\n content: string(title);\n }\n';
}
if (rightBottomRight) {
@ -498,8 +509,12 @@ const syncFromStore = () => {
}
// Check for page numbers and running title in @page:left and @page:right
const leftPageMatch = stylesheetStore.content.match(/@page:left\s*\{[^}]*\}/);
const rightPageMatch = stylesheetStore.content.match(/@page:right\s*\{[^}]*\}/);
const leftPageMatch = stylesheetStore.content.match(
/@page:left\s*\{[^}]*\}/
);
const rightPageMatch = stylesheetStore.content.match(
/@page:right\s*\{[^}]*\}/
);
// Check if page numbers exist (counter(page) in either left or right)
const hasPageNumbers =
@ -537,7 +552,11 @@ const updateColorisButton = () => {
// Watch for when the user returns to the "document" tab
watch(activeTab, (newTab, oldTab) => {
if (newTab === 'document' && oldTab !== 'document' && background.value.value) {
if (
newTab === 'document' &&
oldTab !== 'document' &&
background.value.value
) {
// Small delay to ensure DOM is ready
setTimeout(updateColorisButton, 100);
}