feat: integrate Coloris color picker for background field

Add Coloris.js library for enhanced color selection in PageSettings with
automatic button state sync across tab changes.

Features:
- Color picker with swatches, alpha support, and format toggle (hex/rgb/hsl)
- Button positioned to the left of input field
- Automatic sync when switching tabs (remembers selected color)
- Close button and click-outside-to-close functionality
- Dark theme with pill UI style

Changes:
- Install @melloware/coloris package
- PageSettings.vue: Integrate Coloris with data-coloris attribute,
  add tab visibility detection via provide/inject, force button update
  when returning to document tab
- EditorPanel.vue: Provide activeTab to child components, increase
  panel width to 30rem
- _forms.scss: Add .input-with-color styles with custom Coloris
  button positioning (absolute positioned to left of input)
- Temporarily comment out rgb/hex format buttons (replaced by Coloris
  format toggle)

Technical details:
- Uses provide/inject pattern to detect tab changes
- Triggers synthetic input events to force Coloris button refresh
- Custom CSS overrides to position swatch button correctly

🤖 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 15:03:29 +01:00
parent 467ae905bd
commit 9af36fb422
17 changed files with 359 additions and 179 deletions

View file

@ -45,13 +45,16 @@
</template>
<script setup>
import { ref } from 'vue';
import { ref, provide } 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>
@ -60,7 +63,7 @@ const activeTab = ref('document');
position: fixed;
top: 0;
left: 0;
width: 25rem;
width: 30rem;
height: 100vh;
display: flex;
flex-direction: column;

View file

@ -18,12 +18,24 @@
<div class="settings-subsection">
<div class="field field--view-only">
<label for="page-width">Largeur</label>
<input id="page-width" type="text" :value="pageWidth" disabled />
<input
id="page-width"
type="number"
:value="parseInt(pageWidth)"
disabled
/>
<button type="button" disabled>mm</button>
</div>
<div class="field field--view-only">
<label for="page-height">Hauteur</label>
<input id="page-height" type="text" :value="pageHeight" disabled />
<input
id="page-height"
type="number"
:value="parseInt(pageHeight)"
disabled
/>
<button type="button" disabled>mm</button>
</div>
</div>
@ -146,8 +158,15 @@
<div class="settings-subsection">
<div class="field">
<label for="background">Arrière-plan</label>
<div class="input-with-unit">
<input id="background" type="text" v-model="background.value" />
<div class="input-with-color">
<input
ref="backgroundColorInput"
type="text"
id="background"
v-model="background.value"
data-coloris
/>
<!-- Temporarily commented out
<div class="unit-toggle">
<button
type="button"
@ -164,6 +183,7 @@
hex
</button>
</div>
-->
</div>
</div>
</div>
@ -195,10 +215,14 @@
</template>
<script setup>
import { ref, computed, watch, onMounted } from 'vue';
import { ref, computed, watch, onMounted, inject } 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;
@ -411,7 +435,58 @@ watch(
}
);
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>