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
|
# 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
|
## [1.2.11] - 2025-09-04
|
||||||
|
|
||||||
### Ajouté
|
### Ajouté
|
||||||
|
|||||||
@@ -105,6 +105,7 @@
|
|||||||
|
|
||||||
<!-- Zone de notes rapides - Panneau latéral -->
|
<!-- Zone de notes rapides - Panneau latéral -->
|
||||||
<div id="notesSection" class="notes-section">
|
<div id="notesSection" class="notes-section">
|
||||||
|
<div class="notes-resize-handle" id="notesResizeHandle"></div>
|
||||||
<div class="notes-header">
|
<div class="notes-header">
|
||||||
<h4>Notes rapides</h4>
|
<h4>Notes rapides</h4>
|
||||||
<button id="closeNotesBtn" class="btn-close-notes" title="Fermer">×</button>
|
<button id="closeNotesBtn" class="btn-close-notes" title="Fermer">×</button>
|
||||||
|
|||||||
128
renderer.js
128
renderer.js
@@ -11,6 +11,11 @@ let callStats = {
|
|||||||
appointments: 0
|
appointments: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Variables pour le redimensionnement des notes
|
||||||
|
let isResizingNotes = false;
|
||||||
|
let notesStartWidth = 380;
|
||||||
|
let notesStartX = 0;
|
||||||
|
|
||||||
// === GESTION DE LA CONNEXION ===
|
// === GESTION DE LA CONNEXION ===
|
||||||
document.addEventListener('DOMContentLoaded', async () => {
|
document.addEventListener('DOMContentLoaded', async () => {
|
||||||
// Initialiser l'indicateur SignalR
|
// Initialiser l'indicateur SignalR
|
||||||
@@ -90,6 +95,9 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
// Charger les préférences utilisateur
|
// Charger les préférences utilisateur
|
||||||
loadUserPreferences();
|
loadUserPreferences();
|
||||||
|
|
||||||
|
// Initialiser le redimensionnement des notes
|
||||||
|
initNotesResize();
|
||||||
|
|
||||||
|
|
||||||
// Gérer les boutons de la modal de déconnexion (si on est sur la page principale)
|
// Gérer les boutons de la modal de déconnexion (si on est sur la page principale)
|
||||||
const cancelLogoutBtn = document.getElementById('cancelLogoutBtn');
|
const cancelLogoutBtn = document.getElementById('cancelLogoutBtn');
|
||||||
@@ -860,6 +868,16 @@ function showNotes() {
|
|||||||
const toggleBtn = document.getElementById('toggleNotesBtn');
|
const toggleBtn = document.getElementById('toggleNotesBtn');
|
||||||
const webviewContainer = document.getElementById('webviewContainer');
|
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');
|
notesSection.classList.add('visible');
|
||||||
toggleBtn.classList.add('active');
|
toggleBtn.classList.add('active');
|
||||||
|
|
||||||
@@ -915,6 +933,19 @@ function loadUserPreferences() {
|
|||||||
// L'utilisateur devra cliquer pour les afficher
|
// 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
|
// Charger d'autres préférences si nécessaire
|
||||||
const lastTheme = localStorage.getItem('theme');
|
const lastTheme = localStorage.getItem('theme');
|
||||||
if (lastTheme) {
|
if (lastTheme) {
|
||||||
@@ -924,8 +955,10 @@ function loadUserPreferences() {
|
|||||||
|
|
||||||
function saveUserPreferences() {
|
function saveUserPreferences() {
|
||||||
// Cette fonction peut être étendue pour sauvegarder d'autres préférences
|
// Cette fonction peut être étendue pour sauvegarder d'autres préférences
|
||||||
|
const notesSection = document.getElementById('notesSection');
|
||||||
const preferences = {
|
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'
|
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 ===
|
// === FONCTION DE RAFRAÎCHISSEMENT ===
|
||||||
function refreshCurrentWebview() {
|
function refreshCurrentWebview() {
|
||||||
if (activeCenter && webviews[activeCenter]) {
|
if (activeCenter && webviews[activeCenter]) {
|
||||||
|
|||||||
@@ -618,6 +618,8 @@ body {
|
|||||||
top: 60px; /* Juste sous le header */
|
top: 60px; /* Juste sous le header */
|
||||||
right: -400px; /* Caché par défaut */
|
right: -400px; /* Caché par défaut */
|
||||||
width: 380px;
|
width: 380px;
|
||||||
|
min-width: 280px;
|
||||||
|
max-width: 600px;
|
||||||
height: calc(100vh - 60px);
|
height: calc(100vh - 60px);
|
||||||
background: white;
|
background: white;
|
||||||
box-shadow: -4px 0 20px rgba(0,0,0,0.1);
|
box-shadow: -4px 0 20px rgba(0,0,0,0.1);
|
||||||
@@ -628,6 +630,69 @@ body {
|
|||||||
border-left: 1px solid #e1e4e8;
|
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 {
|
.notes-section.visible {
|
||||||
right: 0;
|
right: 0;
|
||||||
animation: slideInRight 0.3s ease-out;
|
animation: slideInRight 0.3s ease-out;
|
||||||
@@ -750,7 +815,7 @@ body {
|
|||||||
|
|
||||||
/* Ajustement de la webview quand les notes sont visibles */
|
/* Ajustement de la webview quand les notes sont visibles */
|
||||||
.webview-container.notes-open {
|
.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);
|
transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user