feat: Ajout du redimensionnement manuel du panneau de notes
- Poignée de redimensionnement avec indicateur visuel permanent (3 points) - Largeur ajustable entre 280px et 600px - Sauvegarde automatique de la largeur préférée - Optimisations avec requestAnimationFrame pour la fluidité - Overlay pendant le drag pour capturer tous les mouvements - Indicateur change de couleur au survol (gris → violet)
This commit is contained in:
@@ -1,5 +1,29 @@
|
||||
# Changelog - SimpleConnect Electron
|
||||
|
||||
## [1.2.12] - 2025-09-04
|
||||
|
||||
### Ajouté
|
||||
- **Redimensionnement du panneau de notes** : Possibilité d'ajuster la largeur
|
||||
- Poignée de redimensionnement sur le bord gauche du panneau
|
||||
- Indicateur visuel permanent (3 points verticaux)
|
||||
- Largeur minimale : 280px, maximale : 600px
|
||||
- Sauvegarde automatique de la largeur préférée dans localStorage
|
||||
- Restauration de la largeur à la réouverture
|
||||
|
||||
### Amélioré
|
||||
- **Fluidité du redimensionnement** : Optimisations pour une meilleure performance
|
||||
- Utilisation de requestAnimationFrame pour 60 FPS
|
||||
- Overlay invisible pendant le drag pour capturer tous les mouvements
|
||||
- Désactivation des transitions CSS pendant le redimensionnement
|
||||
- Indicateur visuel toujours visible (pas seulement au survol)
|
||||
- Changement de couleur de l'indicateur au survol (gris → violet)
|
||||
|
||||
### Technique
|
||||
- Variable CSS `--notes-width` pour synchroniser panneau et webview
|
||||
- Classes `.resizing` pour désactiver les transitions pendant le drag
|
||||
- Gestion des événements mouse avec requestAnimationFrame
|
||||
- Limites de taille avec Math.min/max pour contraindre la largeur
|
||||
|
||||
## [1.2.11] - 2025-09-04
|
||||
|
||||
### Ajouté
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
|
||||
<!-- Zone de notes rapides - Panneau latéral -->
|
||||
<div id="notesSection" class="notes-section">
|
||||
<div class="notes-resize-handle" id="notesResizeHandle"></div>
|
||||
<div class="notes-header">
|
||||
<h4>Notes rapides</h4>
|
||||
<button id="closeNotesBtn" class="btn-close-notes" title="Fermer">×</button>
|
||||
|
||||
128
renderer.js
128
renderer.js
@@ -11,6 +11,11 @@ let callStats = {
|
||||
appointments: 0
|
||||
};
|
||||
|
||||
// Variables pour le redimensionnement des notes
|
||||
let isResizingNotes = false;
|
||||
let notesStartWidth = 380;
|
||||
let notesStartX = 0;
|
||||
|
||||
// === GESTION DE LA CONNEXION ===
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Initialiser l'indicateur SignalR
|
||||
@@ -90,6 +95,9 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Charger les préférences utilisateur
|
||||
loadUserPreferences();
|
||||
|
||||
// Initialiser le redimensionnement des notes
|
||||
initNotesResize();
|
||||
|
||||
|
||||
// Gérer les boutons de la modal de déconnexion (si on est sur la page principale)
|
||||
const cancelLogoutBtn = document.getElementById('cancelLogoutBtn');
|
||||
@@ -860,6 +868,16 @@ function showNotes() {
|
||||
const toggleBtn = document.getElementById('toggleNotesBtn');
|
||||
const webviewContainer = document.getElementById('webviewContainer');
|
||||
|
||||
// Restaurer la largeur sauvegardée
|
||||
const savedWidth = localStorage.getItem('notesWidth');
|
||||
if (savedWidth && notesSection) {
|
||||
const width = parseInt(savedWidth);
|
||||
if (width >= 280 && width <= 600) {
|
||||
notesSection.style.width = `${width}px`;
|
||||
document.documentElement.style.setProperty('--notes-width', `${width}px`);
|
||||
}
|
||||
}
|
||||
|
||||
notesSection.classList.add('visible');
|
||||
toggleBtn.classList.add('active');
|
||||
|
||||
@@ -915,6 +933,19 @@ function loadUserPreferences() {
|
||||
// L'utilisateur devra cliquer pour les afficher
|
||||
}
|
||||
|
||||
// Charger la largeur sauvegardée des notes
|
||||
const savedNotesWidth = localStorage.getItem('notesWidth');
|
||||
if (savedNotesWidth) {
|
||||
const width = parseInt(savedNotesWidth);
|
||||
if (width >= 280 && width <= 600) {
|
||||
document.documentElement.style.setProperty('--notes-width', `${width}px`);
|
||||
const notesSection = document.getElementById('notesSection');
|
||||
if (notesSection) {
|
||||
notesSection.style.width = `${width}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Charger d'autres préférences si nécessaire
|
||||
const lastTheme = localStorage.getItem('theme');
|
||||
if (lastTheme) {
|
||||
@@ -924,8 +955,10 @@ function loadUserPreferences() {
|
||||
|
||||
function saveUserPreferences() {
|
||||
// Cette fonction peut être étendue pour sauvegarder d'autres préférences
|
||||
const notesSection = document.getElementById('notesSection');
|
||||
const preferences = {
|
||||
notesVisible: document.getElementById('notesSection').classList.contains('visible'),
|
||||
notesVisible: notesSection.classList.contains('visible'),
|
||||
notesWidth: notesSection ? notesSection.offsetWidth : 380,
|
||||
theme: document.body.getAttribute('data-theme') || 'light'
|
||||
};
|
||||
|
||||
@@ -934,6 +967,99 @@ function saveUserPreferences() {
|
||||
});
|
||||
}
|
||||
|
||||
// === GESTION DU REDIMENSIONNEMENT DES NOTES ===
|
||||
function initNotesResize() {
|
||||
const resizeHandle = document.getElementById('notesResizeHandle');
|
||||
const notesSection = document.getElementById('notesSection');
|
||||
const webviewContainer = document.getElementById('webviewContainer');
|
||||
|
||||
if (!resizeHandle || !notesSection) return;
|
||||
|
||||
let rafId = null;
|
||||
|
||||
resizeHandle.addEventListener('mousedown', (e) => {
|
||||
isResizingNotes = true;
|
||||
notesStartX = e.clientX;
|
||||
notesStartWidth = notesSection.offsetWidth;
|
||||
|
||||
// Ajouter les classes pour désactiver les transitions
|
||||
notesSection.classList.add('resizing');
|
||||
if (webviewContainer) {
|
||||
webviewContainer.classList.add('resizing');
|
||||
}
|
||||
|
||||
// Empêcher la sélection de texte pendant le redimensionnement
|
||||
document.body.style.userSelect = 'none';
|
||||
document.body.style.cursor = 'col-resize';
|
||||
|
||||
// Ajouter un overlay pour capturer tous les mouvements de souris
|
||||
const overlay = document.createElement('div');
|
||||
overlay.id = 'resize-overlay';
|
||||
overlay.style.cssText = 'position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 9999; cursor: col-resize;';
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
const handleMouseMove = (e) => {
|
||||
if (!isResizingNotes) return;
|
||||
|
||||
// Utiliser requestAnimationFrame pour la fluidité
|
||||
if (rafId) cancelAnimationFrame(rafId);
|
||||
|
||||
rafId = requestAnimationFrame(() => {
|
||||
// Calculer la nouvelle largeur (inversé car le panneau est à droite)
|
||||
const deltaX = notesStartX - e.clientX;
|
||||
const newWidth = notesStartWidth + deltaX;
|
||||
|
||||
// Appliquer les limites min/max
|
||||
const clampedWidth = Math.min(Math.max(newWidth, 280), 600);
|
||||
|
||||
// Mettre à jour la largeur avec transform pour plus de fluidité
|
||||
notesSection.style.width = `${clampedWidth}px`;
|
||||
|
||||
// Mettre à jour la variable CSS pour la webview
|
||||
document.documentElement.style.setProperty('--notes-width', `${clampedWidth}px`);
|
||||
});
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
if (!isResizingNotes) return;
|
||||
|
||||
isResizingNotes = false;
|
||||
|
||||
// Annuler l'animation frame en cours
|
||||
if (rafId) cancelAnimationFrame(rafId);
|
||||
|
||||
// Retirer l'overlay
|
||||
const overlay = document.getElementById('resize-overlay');
|
||||
if (overlay) overlay.remove();
|
||||
|
||||
// Retirer les classes de redimensionnement
|
||||
const notesSection = document.getElementById('notesSection');
|
||||
const webviewContainer = document.getElementById('webviewContainer');
|
||||
|
||||
if (notesSection) {
|
||||
notesSection.classList.remove('resizing');
|
||||
}
|
||||
if (webviewContainer) {
|
||||
webviewContainer.classList.remove('resizing');
|
||||
}
|
||||
|
||||
// Réactiver la sélection de texte
|
||||
document.body.style.userSelect = '';
|
||||
document.body.style.cursor = '';
|
||||
|
||||
// Sauvegarder la nouvelle largeur
|
||||
if (notesSection) {
|
||||
localStorage.setItem('notesWidth', notesSection.offsetWidth);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('mousemove', handleMouseMove);
|
||||
document.addEventListener('mouseup', handleMouseUp);
|
||||
}
|
||||
|
||||
// === FONCTION DE RAFRAÎCHISSEMENT ===
|
||||
function refreshCurrentWebview() {
|
||||
if (activeCenter && webviews[activeCenter]) {
|
||||
|
||||
@@ -618,6 +618,8 @@ body {
|
||||
top: 60px; /* Juste sous le header */
|
||||
right: -400px; /* Caché par défaut */
|
||||
width: 380px;
|
||||
min-width: 280px;
|
||||
max-width: 600px;
|
||||
height: calc(100vh - 60px);
|
||||
background: white;
|
||||
box-shadow: -4px 0 20px rgba(0,0,0,0.1);
|
||||
@@ -628,6 +630,69 @@ body {
|
||||
border-left: 1px solid #e1e4e8;
|
||||
}
|
||||
|
||||
/* Poignée de redimensionnement */
|
||||
.notes-resize-handle {
|
||||
position: absolute;
|
||||
left: -5px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 10px;
|
||||
cursor: col-resize;
|
||||
background: linear-gradient(90deg,
|
||||
transparent 0%,
|
||||
transparent 30%,
|
||||
rgba(209, 213, 219, 0.5) 50%,
|
||||
transparent 70%,
|
||||
transparent 100%);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.notes-resize-handle:hover {
|
||||
background: linear-gradient(90deg,
|
||||
transparent 0%,
|
||||
rgba(102, 126, 234, 0.1) 30%,
|
||||
rgba(102, 126, 234, 0.3) 50%,
|
||||
rgba(102, 126, 234, 0.1) 70%,
|
||||
transparent 100%);
|
||||
}
|
||||
|
||||
.notes-resize-handle:active {
|
||||
background: linear-gradient(90deg,
|
||||
transparent 0%,
|
||||
rgba(102, 126, 234, 0.2) 30%,
|
||||
rgba(102, 126, 234, 0.5) 50%,
|
||||
rgba(102, 126, 234, 0.2) 70%,
|
||||
transparent 100%);
|
||||
}
|
||||
|
||||
/* Indicateur visuel permanent - 3 points verticaux */
|
||||
.notes-resize-handle::before {
|
||||
content: '⋮⋮⋮';
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%) rotate(90deg);
|
||||
font-size: 16px;
|
||||
color: #9ca3af;
|
||||
letter-spacing: -4px;
|
||||
font-weight: bold;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.notes-resize-handle:hover::before {
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
/* Désactiver les transitions pendant le redimensionnement */
|
||||
.notes-section.resizing {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.webview-container.resizing {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.notes-section.visible {
|
||||
right: 0;
|
||||
animation: slideInRight 0.3s ease-out;
|
||||
@@ -750,7 +815,7 @@ body {
|
||||
|
||||
/* Ajustement de la webview quand les notes sont visibles */
|
||||
.webview-container.notes-open {
|
||||
margin-right: 380px;
|
||||
margin-right: var(--notes-width, 380px);
|
||||
transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user