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

View file

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

View file

@ -31,6 +31,7 @@ button {
--color-browngray-200: #d0c4ba; --color-browngray-200: #d0c4ba;
--color-browngray-300: #b5a9a1; --color-browngray-300: #b5a9a1;
--border-radius: 0.2rem; --border-radius: 0.2rem;
--space-xs: 0.5rem;
} }
body, body,
@ -80,21 +81,37 @@ input[type=number] {
.settings-section h2 { .settings-section h2 {
border-bottom: 1px solid #000; border-bottom: 1px solid #000;
margin-bottom: var(--space-xs);
} }
.settings-section .settings-subsection:not(:last-child) { .settings-section .settings-subsection:not(:last-child) {
border-bottom: 1px solid var(--color-browngray-050); border-bottom: 1px solid var(--color-browngray-050);
} }
.settings-section .settings-subsection { .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 { .settings-section .settings-subsection .field {
display: flex; display: flex;
} }
.settings-section .settings-subsection .field label { .settings-section .settings-subsection .field label,
.settings-section .settings-subsection .field select {
width: 50%; 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 { .settings-section .settings-subsection .field .input-with-unit {
display: flex; 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 { .settings-section .settings-subsection .field .input-with-color .clr-field {
display: flex; display: flex;
@ -102,17 +119,19 @@ input[type=number] {
.settings-section .settings-subsection .field .input-with-color .clr-field button { .settings-section .settings-subsection .field .input-with-color .clr-field button {
position: absolute; position: absolute;
transform: none; transform: none;
height: 1rem; height: 1.1rem;
top: auto; top: auto;
right: auto; right: auto;
cursor: pointer; cursor: pointer;
} }
.settings-section .settings-subsection .field .input-with-color .clr-field input { .settings-section .settings-subsection .field .input-with-color .clr-field input {
padding-left: 2.5rem; padding-left: 2.5rem;
width: 100%;
} }
.settings-section .settings-subsection.margins { .settings-section .settings-subsection.margins {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
row-gap: var(--space-xs);
} }
.settings-section .settings-subsection.margins h3 { .settings-section .settings-subsection.margins h3 {
width: 100%; 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 { @page {
size: A4; size: A4;
margin: 20mm 15mm 26mm 15mm; margin: 20mm 15mm 26mm 15mm;
background: rgba(255, 255, 255, 0);
} }
@page { @page {
@bottom-center { content: string(title); } @bottom-center {
content: string(title);
}
} }
h2 { h2 {

View file

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

View file

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

View file

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