Compare commits

..

No commits in common. "9af36fb4221c295e04ea381ba5a36b7be93e2aa1" and "960f509d5c466195ef87ed69030696eeb0400a38" have entirely different histories.

19 changed files with 209 additions and 851 deletions

7
package-lock.json generated
View file

@ -8,7 +8,6 @@
"name": "geoproject",
"version": "0.0.0",
"dependencies": {
"@melloware/coloris": "^0.25.0",
"highlight.js": "^11.11.1",
"pagedjs": "^0.4.3",
"pinia": "^3.0.4",
@ -533,12 +532,6 @@
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"license": "MIT"
},
"node_modules/@melloware/coloris": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@melloware/coloris/-/coloris-0.25.0.tgz",
"integrity": "sha512-RBWVFLjWbup7GRkOXb9g3+ZtR9AevFtJinrRz2cYPLjZ3TCkNRGMWuNbmQWbZ5cF3VU7aQDZwUsYgIY/bGrh2g==",
"license": "MIT"
},
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-beta.50",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.50.tgz",

View file

@ -9,7 +9,6 @@
"preview": "vite preview"
},
"dependencies": {
"@melloware/coloris": "^0.25.0",
"highlight.js": "^11.11.1",
"pagedjs": "^0.4.3",
"pinia": "^3.0.4",

View file

@ -0,0 +1 @@

View file

@ -1,21 +0,0 @@
button {
cursor: pointer;
border: 1px solid var(--color-browngray-300);
color: var(--color-browngray-300);
border-radius: var(--border-radius);
padding: 0.1rem 0.3rem;
&.active {
border: 1px solid #000;
color: #000;
}
&.tab {
&.active {
background-color: #000;
color: #fff;
border: none;
}
}
}

View file

@ -1,72 +0,0 @@
select,
input[type="text"],
input[type="number"] {
background-color: var(--color-browngray-300);
}
.field--view-only {
opacity: 0.3;
}
.settings-section {
h2 {
border-bottom: 1px solid #000;
}
.settings-subsection:not(:last-child) {
border-bottom: 1px solid var(--color-browngray-050);
}
.settings-subsection {
padding: 0.5rem 0;
.field {
display: flex;
label {
width: 50%;
}
.input-with-unit {
display: flex;
}
.input-with-color {
.clr-field {
display: flex;
button {
position: absolute;
transform: none;
height: 1rem;
top: auto;
right: auto;
cursor: pointer;
}
input {
padding-left: 2.5rem;
}
}
}
}
&.margins {
display: flex;
flex-wrap: wrap;
h3 {
width: 100%;
}
.field {
width: 50%;
label {
width: 50%;
}
.input-with-unit {
input {
width: 50%;
}
}
}
}
}
}

View file

@ -1,27 +0,0 @@
body,
html {
padding: 0;
margin: 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
}
input,
select {
border: none;
outline: none;
border-radius: var(--border-radius);
}
button {
background-color: transparent;
border: none;
}

View file

@ -1,15 +0,0 @@
body,
h1,
h2,
h3,
h4,
h5,
h6,
p,
a,
input,
select,
figcaption,
label {
font-family: sans-serif;
}

View file

@ -1,8 +0,0 @@
:root {
--color-panel-bg: #e8e6e5;
--color-browngray-050: #f5f3f0;
--color-browngray-200: #d0c4ba;
--color-browngray-300: #b5a9a1;
--border-radius: 0.2rem;
}

View file

@ -1,145 +0,0 @@
body,
html {
padding: 0;
margin: 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
}
input,
select {
border: none;
outline: none;
border-radius: var(--border-radius);
}
button {
background-color: transparent;
border: none;
}
:root {
--color-panel-bg: #e8e6e5;
--color-browngray-050: #f5f3f0;
--color-browngray-200: #d0c4ba;
--color-browngray-300: #b5a9a1;
--border-radius: 0.2rem;
}
body,
h1,
h2,
h3,
h4,
h5,
h6,
p,
a,
input,
select,
figcaption,
label {
font-family: sans-serif;
}
/* PagedJS print styles */
@page {
size: A4;
margin: 20mm 15mm 26mm 15mm;
}
h2 {
-moz-column-break-before: page;
break-before: page;
}
@page {
@bottom-center {
content: string(title);
}
}
.chapter > h2 {
string-set: title content(text);
}
select,
input[type=text],
input[type=number] {
background-color: var(--color-browngray-300);
}
.field--view-only {
opacity: 0.3;
}
.settings-section h2 {
border-bottom: 1px solid #000;
}
.settings-section .settings-subsection:not(:last-child) {
border-bottom: 1px solid var(--color-browngray-050);
}
.settings-section .settings-subsection {
padding: 0.5rem 0;
}
.settings-section .settings-subsection .field {
display: flex;
}
.settings-section .settings-subsection .field label {
width: 50%;
}
.settings-section .settings-subsection .field .input-with-unit {
display: flex;
}
.settings-section .settings-subsection .field .input-with-color .clr-field {
display: flex;
}
.settings-section .settings-subsection .field .input-with-color .clr-field button {
position: absolute;
transform: none;
height: 1rem;
top: auto;
right: auto;
cursor: pointer;
}
.settings-section .settings-subsection .field .input-with-color .clr-field input {
padding-left: 2.5rem;
}
.settings-section .settings-subsection.margins {
display: flex;
flex-wrap: wrap;
}
.settings-section .settings-subsection.margins h3 {
width: 100%;
}
.settings-section .settings-subsection.margins .field {
width: 50%;
}
.settings-section .settings-subsection.margins .field label {
width: 50%;
}
.settings-section .settings-subsection.margins .field .input-with-unit input {
width: 50%;
}
button {
cursor: pointer;
border: 1px solid var(--color-browngray-300);
color: var(--color-browngray-300);
border-radius: var(--border-radius);
padding: 0.1rem 0.3rem;
}
button.active {
border: 1px solid #000;
color: #000;
}
button.tab.active {
background-color: #000;
color: #fff;
border: none;
}/*# sourceMappingURL=style.css.map */

View file

@ -1 +0,0 @@
{"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"}

View file

@ -1,6 +0,0 @@
@import "src/_reset.scss";
@import "src/_variables.scss";
@import "src/_text.scss";
@import "src/_print-styles.scss";
@import "src/_forms.scss";
@import "src/_buttons.scss";

View file

@ -8,8 +8,8 @@
<?= e($page->isHomePage() != true, $page->title() . ' - ') . $site->title() ?>
</title>
<link rel="stylesheet" href="<?= url('assets/css/style..css') ?>">
<link rel="stylesheet" href="<?= url('assets/css/pagedjs-interface.css') ?>">
<link rel="stylesheet" href="<?= url('assets/pagedjs-interface.css') ?>">
<link rel="stylesheet" href="<?= url('assets/stylesheet.css') ?>">
<!-- À SUPPRIMER EN PRODUCTION -->
<meta name="robots" content="noindex, nofollow, noarchive">

View file

@ -1,6 +1,7 @@
<script setup>
import PagedJsWrapper from './components/PagedJsWrapper.vue';
import EditorPanel from './components/editor/EditorPanel.vue';
import StylesheetViewer from './components/StylesheetViewer.vue';
import ElementPopup from './components/ElementPopup.vue';
import { onMounted, ref, watch } from 'vue';
import { useStylesheetStore } from './stores/stylesheet';
@ -41,10 +42,7 @@ const renderPreview = async (shouldReloadFromFile = false) => {
`;
iframe.onload = () => {
iframe.contentDocument.addEventListener(
'click',
elementPopup.value.handleIframeClick
);
iframe.contentDocument.addEventListener('click', elementPopup.value.handleIframeClick);
setTimeout(() => {
const scrollHeight = iframe.contentDocument.documentElement.scrollHeight;
@ -57,12 +55,9 @@ const renderPreview = async (shouldReloadFromFile = false) => {
};
};
watch(
() => stylesheetStore.content,
() => {
watch(() => stylesheetStore.content, () => {
renderPreview();
}
);
});
onMounted(() => renderPreview(true));
</script>
@ -76,6 +71,8 @@ onMounted(() => renderPreview(true));
<iframe ref="previewFrame" id="preview-frame"></iframe>
<StylesheetViewer :stylesheet="stylesheetStore.content" />
<ElementPopup ref="elementPopup" :iframeRef="previewFrame" />
</template>
@ -83,8 +80,8 @@ onMounted(() => renderPreview(true));
#preview-frame {
position: fixed;
top: 0;
left: 0;
width: 100vw;
left: 250px;
width: calc(100% - 600px);
height: 100vh;
border: none;
}

View file

@ -1,5 +1,5 @@
<template>
<div id="stylesheet-viewer">
<aside id="stylesheet-viewer">
<div class="header">
<h3>Stylesheet</h3>
<label class="toggle">
@ -17,7 +17,7 @@
@input="handleInput"
spellcheck="false"
></textarea>
</div>
</aside>
</template>
<script setup>
@ -53,9 +53,14 @@ const handleInput = (event) => {
<style scoped>
#stylesheet-viewer {
display: flex;
flex-direction: column;
height: 100%;
position: fixed;
top: 0;
right: 0;
width: 350px;
height: 100vh;
padding: 1rem;
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
overflow-y: auto;
background: #282c34;
color: #fff;
}
@ -125,7 +130,7 @@ h3 {
.readonly {
margin: 0;
flex: 1;
height: calc(100vh - 5rem);
overflow-y: auto;
padding: 0.5rem;
background: #1e1e1e;
@ -140,7 +145,7 @@ h3 {
textarea {
width: 100%;
flex: 1;
height: calc(100vh - 5rem);
background: #1e1e1e;
color: #abb2bf;
border: none;

View file

@ -3,7 +3,6 @@
<nav class="tabs">
<button
type="button"
class="tab"
:class="{ active: activeTab === 'document' }"
@click="activeTab = 'document'"
>
@ -11,7 +10,6 @@
</button>
<button
type="button"
class="tab"
:class="{ active: activeTab === 'code' }"
@click="activeTab = 'code'"
>
@ -19,7 +17,6 @@
</button>
<button
type="button"
class="tab"
:class="{ active: activeTab === 'contenu' }"
@click="activeTab = 'contenu'"
>
@ -34,7 +31,7 @@
</div>
<div v-else-if="activeTab === 'code'" class="tab-panel">
<StylesheetViewer />
<!-- Code tab content -->
</div>
<div v-else-if="activeTab === 'contenu'" class="tab-panel">
@ -45,48 +42,43 @@
</template>
<script setup>
import { ref, provide } from 'vue';
import { ref } from 'vue';
import PageSettings from './PageSettings.vue';
import TextSettings from './TextSettings.vue';
import StylesheetViewer from '../StylesheetViewer.vue';
// Tab management
const activeTab = ref('document');
// Provide activeTab to child components
provide('activeTab', activeTab);
</script>
<style lang="scss" scoped>
<style scoped>
#editor-panel {
padding: 1rem;
position: fixed;
top: 0;
left: 0;
width: 30rem;
width: 250px;
height: 100vh;
display: flex;
flex-direction: column;
z-index: 2;
background-color: var(--color-panel-bg);
box-shadow: -5px 0px 12px;
}
nav {
margin-bottom: 2rem;
display: flex;
gap: 0.5rem;
}
.tab-content {
flex: 1;
overflow: hidden;
}
.tab-panel {
height: 100%;
background: #f5f5f5;
padding: 1rem;
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
overflow-y: auto;
}
h3 {
margin-top: 0;
}
.control {
margin-bottom: 1rem;
}
.control label {
display: block;
margin-bottom: 0.25rem;
font-size: 0.875rem;
}
.control input {
width: 80px;
padding: 0.25rem;
}
</style>

View file

@ -2,7 +2,6 @@
<section class="settings-section">
<h2>Réglage des pages</h2>
<div class="settings-subsection">
<div class="field">
<label for="page-format">Format d'impression</label>
<select id="page-format" v-model="pageFormat">
@ -13,38 +12,33 @@
<option value="legal">Legal</option>
</select>
</div>
</div>
<div class="settings-subsection">
<div class="field field--view-only">
<div class="field">
<label for="page-width">Largeur</label>
<input
id="page-width"
type="number"
:value="parseInt(pageWidth)"
type="text"
:value="pageWidth"
disabled
/>
<button type="button" disabled>mm</button>
</div>
<div class="field field--view-only">
<div class="field">
<label for="page-height">Hauteur</label>
<input
id="page-height"
type="number"
:value="parseInt(pageHeight)"
type="text"
:value="pageHeight"
disabled
/>
<button type="button" disabled>mm</button>
</div>
</div>
<div class="settings-subsection margins">
<div class="subsection">
<h3>Marges</h3>
<div class="field">
<label for="margin-top">Haut</label>
<div class="input-with-unit">
<div class="field-with-unit">
<input
id="margin-top"
type="number"
@ -72,7 +66,7 @@
<div class="field">
<label for="margin-bottom">Bas</label>
<div class="input-with-unit">
<div class="field-with-unit">
<input
id="margin-bottom"
type="number"
@ -100,7 +94,7 @@
<div class="field">
<label for="margin-left">Gauche</label>
<div class="input-with-unit">
<div class="field-with-unit">
<input
id="margin-left"
type="number"
@ -128,7 +122,7 @@
<div class="field">
<label for="margin-right">Droite</label>
<div class="input-with-unit">
<div class="field-with-unit">
<input
id="margin-right"
type="number"
@ -155,18 +149,14 @@
</div>
</div>
<div class="settings-subsection">
<div class="field">
<label for="background">Arrière-plan</label>
<div class="input-with-color">
<div class="field-with-unit">
<input
ref="backgroundColorInput"
type="text"
id="background"
type="text"
v-model="background.value"
data-coloris
/>
<!-- Temporarily commented out
<div class="unit-toggle">
<button
type="button"
@ -183,12 +173,9 @@
hex
</button>
</div>
-->
</div>
</div>
</div>
<div class="settings-subsection">
<div class="field">
<label for="pattern">Motif</label>
<select id="pattern" v-model="pattern">
@ -198,31 +185,32 @@
<option value="grid">Grille</option>
</select>
</div>
</div>
<div class="settings-subsection">
<div class="field checkbox-field">
<input id="page-numbers" type="checkbox" v-model="pageNumbers" />
<input
id="page-numbers"
type="checkbox"
v-model="pageNumbers"
/>
<label for="page-numbers">Numéro de page</label>
</div>
<div class="field checkbox-field">
<input id="running-title" type="checkbox" v-model="runningTitle" />
<input
id="running-title"
type="checkbox"
v-model="runningTitle"
/>
<label for="running-title">Titre courant</label>
</div>
</div>
</section>
</template>
<script setup>
import { ref, computed, watch, onMounted, inject } from 'vue';
import { ref, computed, watch, onMounted } from 'vue';
import { useStylesheetStore } from '../../stores/stylesheet';
import Coloris from '@melloware/coloris';
import '@melloware/coloris/dist/coloris.css';
const stylesheetStore = useStylesheetStore();
const backgroundColorInput = ref(null);
const activeTab = inject('activeTab', ref('document'));
let isUpdatingFromStore = false;
let updateTimer = null;
@ -234,7 +222,7 @@ const pageFormats = {
A5: { width: '148mm', height: '210mm' },
A3: { width: '297mm', height: '420mm' },
letter: { width: '8.5in', height: '11in' },
legal: { width: '8.5in', height: '14in' },
legal: { width: '8.5in', height: '14in' }
};
const pageWidth = computed(() => pageFormats[pageFormat.value].width);
@ -244,12 +232,12 @@ const margins = ref({
top: { value: 20, unit: 'mm' },
bottom: { value: 20, unit: 'mm' },
left: { value: 20, unit: 'mm' },
right: { value: 20, unit: 'mm' },
right: { value: 20, unit: 'mm' }
});
const background = ref({
value: '',
format: 'hex',
format: 'hex'
});
const pattern = ref('');
@ -261,20 +249,19 @@ const debouncedUpdate = (callback) => {
updateTimer = setTimeout(callback, 1000);
};
const immediateUpdate = (callback) => {
callback();
};
watch(pageFormat, (newFormat) => {
if (isUpdatingFromStore) return;
immediateUpdate(() => {
debouncedUpdate(() => {
stylesheetStore.updateProperty('@page', 'size', newFormat, '');
});
});
const updateMargins = () => {
const marginValue = `${margins.value.top.value}${margins.value.top.unit} ${margins.value.right.value}${margins.value.right.unit} ${margins.value.bottom.value}${margins.value.bottom.unit} ${margins.value.left.value}${margins.value.left.unit}`;
watch(margins, (newMargins) => {
if (isUpdatingFromStore) return;
debouncedUpdate(() => {
const marginValue = `${newMargins.top.value}${newMargins.top.unit} ${newMargins.right.value}${newMargins.right.unit} ${newMargins.bottom.value}${newMargins.bottom.unit} ${newMargins.left.value}${newMargins.left.unit}`;
const currentBlock = stylesheetStore.extractBlock('@page');
const updatedBlock = currentBlock.replace(
@ -282,88 +269,37 @@ const updateMargins = () => {
`$1${marginValue}`
);
stylesheetStore.content = stylesheetStore.content.replace(
currentBlock,
updatedBlock
);
};
stylesheetStore.content = stylesheetStore.content.replace(currentBlock, updatedBlock);
});
}, { deep: true });
// Watch margin values (number inputs) with debounce
watch(
() => [
margins.value.top.value,
margins.value.bottom.value,
margins.value.left.value,
margins.value.right.value,
],
() => {
watch(background, (newBg) => {
if (!newBg.value) return;
if (isUpdatingFromStore) return;
debouncedUpdate(updateMargins);
}
);
// Watch margin units (button clicks) without debounce
watch(
() => [
margins.value.top.unit,
margins.value.bottom.unit,
margins.value.left.unit,
margins.value.right.unit,
],
() => {
if (isUpdatingFromStore) return;
immediateUpdate(updateMargins);
}
);
const updateBackground = () => {
if (!background.value.value) return;
debouncedUpdate(() => {
const currentBlock = stylesheetStore.extractBlock('@page');
if (currentBlock.includes('background:')) {
const updatedBlock = currentBlock.replace(
/(background:\s*)[^;]+/,
`$1${background.value.value}`
);
stylesheetStore.content = stylesheetStore.content.replace(
currentBlock,
updatedBlock
`$1${newBg.value}`
);
stylesheetStore.content = stylesheetStore.content.replace(currentBlock, updatedBlock);
} else {
const updatedBlock = currentBlock.replace(
/(\s*})$/,
` background: ${background.value.value};\n$1`
);
stylesheetStore.content = stylesheetStore.content.replace(
currentBlock,
updatedBlock
` background: ${newBg.value};\n$1`
);
stylesheetStore.content = stylesheetStore.content.replace(currentBlock, updatedBlock);
}
};
// Watch background value (text input) with debounce
watch(
() => background.value.value,
() => {
if (isUpdatingFromStore) return;
debouncedUpdate(updateBackground);
}
);
// Watch background format (button clicks) without debounce
watch(
() => background.value.format,
() => {
if (isUpdatingFromStore) return;
immediateUpdate(updateBackground);
}
);
});
}, { deep: true });
watch(pattern, (newPattern) => {
if (!newPattern || isUpdatingFromStore) return;
immediateUpdate(() => {
debouncedUpdate(() => {
// TODO: implement pattern application
});
});
@ -371,7 +307,7 @@ watch(pattern, (newPattern) => {
watch(pageNumbers, (enabled) => {
if (isUpdatingFromStore) return;
immediateUpdate(() => {
debouncedUpdate(() => {
// TODO: implement page numbers toggle
});
});
@ -379,7 +315,7 @@ watch(pageNumbers, (enabled) => {
watch(runningTitle, (enabled) => {
if (isUpdatingFromStore) return;
immediateUpdate(() => {
debouncedUpdate(() => {
// TODO: implement running title toggle
});
});
@ -395,26 +331,12 @@ const syncFromStore = () => {
pageFormat.value = sizeMatch[1];
}
const marginMatch = pageBlock.match(
/margin:\s*([0-9.]+)([a-z]+)\s+([0-9.]+)([a-z]+)\s+([0-9.]+)([a-z]+)\s+([0-9.]+)([a-z]+)/i
);
const marginMatch = pageBlock.match(/margin:\s*([0-9.]+)([a-z]+)\s+([0-9.]+)([a-z]+)\s+([0-9.]+)([a-z]+)\s+([0-9.]+)([a-z]+)/i);
if (marginMatch) {
margins.value.top = {
value: parseFloat(marginMatch[1]),
unit: marginMatch[2],
};
margins.value.right = {
value: parseFloat(marginMatch[3]),
unit: marginMatch[4],
};
margins.value.bottom = {
value: parseFloat(marginMatch[5]),
unit: marginMatch[6],
};
margins.value.left = {
value: parseFloat(marginMatch[7]),
unit: marginMatch[8],
};
margins.value.top = { value: parseFloat(marginMatch[1]), unit: marginMatch[2] };
margins.value.right = { value: parseFloat(marginMatch[3]), unit: marginMatch[4] };
margins.value.bottom = { value: parseFloat(marginMatch[5]), unit: marginMatch[6] };
margins.value.left = { value: parseFloat(marginMatch[7]), unit: marginMatch[8] };
}
const bgMatch = pageBlock.match(/background:\s*([^;]+)/);
@ -426,67 +348,13 @@ const syncFromStore = () => {
}
};
watch(
() => stylesheetStore.content,
() => {
watch(() => stylesheetStore.content, () => {
if (!isUpdatingFromStore) {
syncFromStore();
}
}
);
const updateColorisButton = () => {
const input = backgroundColorInput.value;
if (input && background.value.value) {
// Force Coloris to update by triggering a change event
const event = new Event('input', { bubbles: true });
input.dispatchEvent(event);
}
};
// Watch for when the user returns to the "document" tab
watch(activeTab, (newTab, oldTab) => {
if (newTab === 'document' && oldTab !== 'document' && background.value.value) {
// Small delay to ensure DOM is ready
setTimeout(updateColorisButton, 100);
}
});
onMounted(() => {
syncFromStore();
// Initialize Coloris
Coloris.init();
Coloris({
el: '[data-coloris]',
theme: 'pill',
themeMode: 'dark',
formatToggle: true,
alpha: true,
closeButton: true,
closeLabel: 'Fermer',
clearButton: true,
clearLabel: 'Effacer',
swatchesOnly: false,
inline: false,
wrap: true,
swatches: [
'#264653',
'#2a9d8f',
'#e9c46a',
'#f4a261',
'#e76f51',
'#d62828',
'#023e8a',
'#0077b6',
'#ffffff',
'#000000',
],
});
// Initialize button color if value exists
if (background.value.value) {
setTimeout(updateColorisButton, 100);
}
});
</script>

View file

@ -2,8 +2,8 @@
<section class="settings-section">
<h2>Réglage du texte</h2>
<p class="infos">
Ces réglages s'appliquent à l'ensemble des éléments du document. Vous
pouvez modifier ensuite les éléments indépendamment.
Ces réglages s'appliquent à l'ensemble des éléments du document.
Vous pouvez modifier ensuite les éléments indépendamment.
</p>
<div class="field">
@ -17,7 +17,11 @@
<option value="Times New Roman">Times New Roman</option>
</select>
<div class="field-checkbox">
<input id="text-italic" type="checkbox" v-model="italic" />
<input
id="text-italic"
type="checkbox"
v-model="italic"
/>
<label for="text-italic">Italique</label>
</div>
</div>
@ -80,7 +84,7 @@
<div class="field">
<label for="text-size-range">Taille du texte</label>
<div class="input-with-unit">
<div class="field-with-unit">
<input
id="text-size-range"
type="range"
@ -136,7 +140,11 @@
<div class="field">
<label for="text-color">Couleur</label>
<div class="field-with-color">
<input type="color" v-model="color.picker" class="color-picker" />
<input
type="color"
v-model="color.picker"
class="color-picker"
/>
<input
id="text-color"
type="text"
@ -220,7 +228,7 @@
<div class="field">
<label for="margin-outer">Marges extérieures</label>
<div class="input-with-unit">
<div class="field-with-unit">
<input
id="margin-outer"
type="number"
@ -258,7 +266,7 @@
<div v-if="marginOuterExpanded" class="subsection collapsed-section">
<div class="field">
<label for="margin-outer-top">Haut</label>
<div class="input-with-unit">
<div class="field-with-unit">
<input
id="margin-outer-top"
type="number"
@ -286,7 +294,7 @@
<div class="field">
<label for="margin-outer-bottom">Bas</label>
<div class="input-with-unit">
<div class="field-with-unit">
<input
id="margin-outer-bottom"
type="number"
@ -314,7 +322,7 @@
<div class="field">
<label for="margin-outer-left">Gauche</label>
<div class="input-with-unit">
<div class="field-with-unit">
<input
id="margin-outer-left"
type="number"
@ -342,7 +350,7 @@
<div class="field">
<label for="margin-outer-right">Droite</label>
<div class="input-with-unit">
<div class="field-with-unit">
<input
id="margin-outer-right"
type="number"
@ -371,7 +379,7 @@
<div class="field">
<label for="margin-inner">Marges intérieures</label>
<div class="input-with-unit">
<div class="field-with-unit">
<input
id="margin-inner"
type="number"
@ -409,7 +417,7 @@
<div v-if="marginInnerExpanded" class="subsection collapsed-section">
<div class="field">
<label for="margin-inner-top">Haut</label>
<div class="input-with-unit">
<div class="field-with-unit">
<input
id="margin-inner-top"
type="number"
@ -437,7 +445,7 @@
<div class="field">
<label for="margin-inner-bottom">Bas</label>
<div class="input-with-unit">
<div class="field-with-unit">
<input
id="margin-inner-bottom"
type="number"
@ -465,7 +473,7 @@
<div class="field">
<label for="margin-inner-left">Gauche</label>
<div class="input-with-unit">
<div class="field-with-unit">
<input
id="margin-inner-left"
type="number"
@ -493,7 +501,7 @@
<div class="field">
<label for="margin-inner-right">Droite</label>
<div class="input-with-unit">
<div class="field-with-unit">
<input
id="margin-inner-right"
type="number"
@ -523,22 +531,7 @@
</template>
<script setup>
import { ref, watch } from 'vue';
import { useStylesheetStore } from '../../stores/stylesheet';
const stylesheetStore = useStylesheetStore();
let isUpdatingFromStore = false;
let updateTimer = null;
const debouncedUpdate = (callback) => {
clearTimeout(updateTimer);
updateTimer = setTimeout(callback, 1000);
};
const immediateUpdate = (callback) => {
callback();
};
import { ref } from 'vue';
// Font
const font = ref('Alegreya Sans');
@ -550,7 +543,7 @@ const weight = ref('400');
// Font size
const fontSize = ref({
value: 23,
unit: 'px',
unit: 'px'
});
// Alignment
@ -560,7 +553,7 @@ const alignment = ref('left');
const color = ref({
picker: '#000000',
value: 'rgb(250, 250, 250)',
format: 'rgb',
format: 'rgb'
});
const clearColor = () => {
@ -572,7 +565,7 @@ const clearColor = () => {
const background = ref({
enabled: false,
value: 'transparent',
format: 'hex',
format: 'hex'
});
const clearBackground = () => {
@ -582,7 +575,7 @@ const clearBackground = () => {
// Margin outer
const marginOuter = ref({
value: 23,
unit: 'mm',
unit: 'mm'
});
const marginOuterExpanded = ref(false);
@ -591,13 +584,13 @@ const marginOuterDetailed = ref({
top: { value: 23, unit: 'mm' },
bottom: { value: 23, unit: 'mm' },
left: { value: 23, unit: 'mm' },
right: { value: 23, unit: 'mm' },
right: { value: 23, unit: 'mm' }
});
// Margin inner
const marginInner = ref({
value: 23,
unit: 'mm',
unit: 'mm'
});
const marginInnerExpanded = ref(false);
@ -606,202 +599,6 @@ const marginInnerDetailed = ref({
top: { value: 23, unit: 'mm' },
bottom: { value: 23, unit: 'mm' },
left: { value: 23, unit: 'mm' },
right: { value: 23, unit: 'mm' },
right: { value: 23, unit: 'mm' }
});
// Watchers - Immediate updates for select/buttons/checkboxes
watch(font, () => {
if (isUpdatingFromStore) return;
immediateUpdate(() => {
// TODO: implement font update
});
});
watch(italic, () => {
if (isUpdatingFromStore) return;
immediateUpdate(() => {
// TODO: implement italic update
});
});
watch(weight, () => {
if (isUpdatingFromStore) return;
immediateUpdate(() => {
// TODO: implement weight update
});
});
watch(alignment, () => {
if (isUpdatingFromStore) return;
immediateUpdate(() => {
// TODO: implement alignment update
});
});
// Font size - debounced for value, immediate for unit
watch(
() => fontSize.value.value,
() => {
if (isUpdatingFromStore) return;
debouncedUpdate(() => {
// TODO: implement font size update
});
}
);
watch(
() => fontSize.value.unit,
() => {
if (isUpdatingFromStore) return;
immediateUpdate(() => {
// TODO: implement font size update
});
}
);
// Color - debounced for text value, immediate for format and picker
watch(
() => color.value.value,
() => {
if (isUpdatingFromStore) return;
debouncedUpdate(() => {
// TODO: implement color update
});
}
);
watch(
() => [color.value.format, color.value.picker],
() => {
if (isUpdatingFromStore) return;
immediateUpdate(() => {
// TODO: implement color update
});
}
);
// Background - debounced for value, immediate for format and enabled
watch(
() => background.value.value,
() => {
if (isUpdatingFromStore) return;
debouncedUpdate(() => {
// TODO: implement background update
});
}
);
watch(
() => [background.value.format, background.value.enabled],
() => {
if (isUpdatingFromStore) return;
immediateUpdate(() => {
// TODO: implement background update
});
}
);
// Margin outer - debounced for value, immediate for unit
watch(
() => marginOuter.value.value,
() => {
if (isUpdatingFromStore) return;
debouncedUpdate(() => {
// TODO: implement margin outer update
});
}
);
watch(
() => marginOuter.value.unit,
() => {
if (isUpdatingFromStore) return;
immediateUpdate(() => {
// TODO: implement margin outer update
});
}
);
// Margin outer detailed - debounced for values, immediate for units
watch(
() => [
marginOuterDetailed.value.top.value,
marginOuterDetailed.value.bottom.value,
marginOuterDetailed.value.left.value,
marginOuterDetailed.value.right.value,
],
() => {
if (isUpdatingFromStore) return;
debouncedUpdate(() => {
// TODO: implement margin outer detailed update
});
}
);
watch(
() => [
marginOuterDetailed.value.top.unit,
marginOuterDetailed.value.bottom.unit,
marginOuterDetailed.value.left.unit,
marginOuterDetailed.value.right.unit,
],
() => {
if (isUpdatingFromStore) return;
immediateUpdate(() => {
// TODO: implement margin outer detailed update
});
}
);
// Margin inner - debounced for value, immediate for unit
watch(
() => marginInner.value.value,
() => {
if (isUpdatingFromStore) return;
debouncedUpdate(() => {
// TODO: implement margin inner update
});
}
);
watch(
() => marginInner.value.unit,
() => {
if (isUpdatingFromStore) return;
immediateUpdate(() => {
// TODO: implement margin inner update
});
}
);
// Margin inner detailed - debounced for values, immediate for units
watch(
() => [
marginInnerDetailed.value.top.value,
marginInnerDetailed.value.bottom.value,
marginInnerDetailed.value.left.value,
marginInnerDetailed.value.right.value,
],
() => {
if (isUpdatingFromStore) return;
debouncedUpdate(() => {
// TODO: implement margin inner detailed update
});
}
);
watch(
() => [
marginInnerDetailed.value.top.unit,
marginInnerDetailed.value.bottom.unit,
marginInnerDetailed.value.left.unit,
marginInnerDetailed.value.right.unit,
],
() => {
if (isUpdatingFromStore) return;
immediateUpdate(() => {
// TODO: implement margin inner detailed update
});
}
);
</script>

View file

@ -1 +1,2 @@
@import url('/assets/css/style.css');
@import url('/assets/css/pagedjs-interface.css');
@import url('/assets/css/editor-ui.css');