Add logo and rename
This commit is contained in:
@ -16,7 +16,8 @@ function initDailyNotesShortcut() {
|
||||
if (typeof htmx !== 'undefined') {
|
||||
htmx.ajax('GET', '/api/daily/today', {
|
||||
target: '#editor-container',
|
||||
swap: 'innerHTML'
|
||||
swap: 'innerHTML',
|
||||
pushUrl: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,12 @@ class FileTree {
|
||||
}
|
||||
|
||||
init() {
|
||||
this.setupEventListeners();
|
||||
|
||||
console.log('FileTree initialized with event delegation');
|
||||
}
|
||||
|
||||
setupEventListeners() {
|
||||
// Utiliser la délégation d'événements sur le conteneur de la sidebar
|
||||
// Cela évite de perdre les listeners après les swaps htmx
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
@ -18,8 +24,13 @@ class FileTree {
|
||||
return;
|
||||
}
|
||||
|
||||
// Event listener délégué pour les clics sur les folder-headers
|
||||
sidebar.addEventListener('click', (e) => {
|
||||
// Supprimer les anciens listeners s'ils existent
|
||||
if (this.clickHandler) {
|
||||
sidebar.removeEventListener('click', this.clickHandler);
|
||||
}
|
||||
|
||||
// Créer et stocker le handler pour pouvoir le supprimer plus tard
|
||||
this.clickHandler = (e) => {
|
||||
// Ignorer les clics sur les checkboxes
|
||||
if (e.target.classList.contains('selection-checkbox')) {
|
||||
return;
|
||||
@ -41,12 +52,13 @@ class FileTree {
|
||||
// Ne pas bloquer la propagation pour les fichiers
|
||||
return;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Attacher le handler
|
||||
sidebar.addEventListener('click', this.clickHandler);
|
||||
|
||||
// Event listeners délégués pour le drag & drop
|
||||
this.setupDelegatedDragAndDrop(sidebar);
|
||||
|
||||
console.log('FileTree initialized with event delegation');
|
||||
}
|
||||
|
||||
toggleFolder(header) {
|
||||
@ -69,8 +81,17 @@ class FileTree {
|
||||
}
|
||||
|
||||
setupDelegatedDragAndDrop(sidebar) {
|
||||
// Supprimer les anciens handlers s'ils existent
|
||||
if (this.dragStartHandler) {
|
||||
sidebar.removeEventListener('dragstart', this.dragStartHandler);
|
||||
sidebar.removeEventListener('dragend', this.dragEndHandler);
|
||||
sidebar.removeEventListener('dragover', this.dragOverHandler);
|
||||
sidebar.removeEventListener('dragleave', this.dragLeaveHandler);
|
||||
sidebar.removeEventListener('drop', this.dropHandler);
|
||||
}
|
||||
|
||||
// Drag start - délégué pour fichiers et dossiers
|
||||
sidebar.addEventListener('dragstart', (e) => {
|
||||
this.dragStartHandler = (e) => {
|
||||
const fileItem = e.target.closest('.file-item');
|
||||
const folderHeader = e.target.closest('.folder-header');
|
||||
|
||||
@ -79,41 +100,48 @@ class FileTree {
|
||||
} else if (folderHeader && folderHeader.draggable) {
|
||||
this.handleDragStart(e, 'folder', folderHeader);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Drag end - délégué
|
||||
sidebar.addEventListener('dragend', (e) => {
|
||||
this.dragEndHandler = (e) => {
|
||||
const fileItem = e.target.closest('.file-item');
|
||||
const folderHeader = e.target.closest('.folder-header');
|
||||
|
||||
if (fileItem || folderHeader) {
|
||||
this.handleDragEnd(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Drag over - délégué sur les folder-headers
|
||||
sidebar.addEventListener('dragover', (e) => {
|
||||
this.dragOverHandler = (e) => {
|
||||
const folderHeader = e.target.closest('.folder-header');
|
||||
if (folderHeader) {
|
||||
this.handleDragOver(e, folderHeader);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Drag leave - délégué
|
||||
sidebar.addEventListener('dragleave', (e) => {
|
||||
this.dragLeaveHandler = (e) => {
|
||||
const folderHeader = e.target.closest('.folder-header');
|
||||
if (folderHeader) {
|
||||
this.handleDragLeave(e, folderHeader);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Drop - délégué
|
||||
sidebar.addEventListener('drop', (e) => {
|
||||
this.dropHandler = (e) => {
|
||||
const folderHeader = e.target.closest('.folder-header');
|
||||
if (folderHeader) {
|
||||
this.handleDrop(e, folderHeader);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Attacher les handlers
|
||||
sidebar.addEventListener('dragstart', this.dragStartHandler);
|
||||
sidebar.addEventListener('dragend', this.dragEndHandler);
|
||||
sidebar.addEventListener('dragover', this.dragOverHandler);
|
||||
sidebar.addEventListener('dragleave', this.dragLeaveHandler);
|
||||
sidebar.addEventListener('drop', this.dropHandler);
|
||||
|
||||
// Rendre les dossiers draggables (sauf racine)
|
||||
this.updateDraggableAttributes();
|
||||
@ -124,6 +152,7 @@ class FileTree {
|
||||
// Vérifier si le swap concerne le file-tree
|
||||
const target = event.detail?.target;
|
||||
if (target && (target.id === 'file-tree' || target.closest('#file-tree'))) {
|
||||
console.log('FileTree: afterSwap detected, updating attributes...');
|
||||
this.updateDraggableAttributes();
|
||||
}
|
||||
});
|
||||
@ -131,10 +160,22 @@ class FileTree {
|
||||
// Écouter aussi les swaps out-of-band (oob) qui mettent à jour le file-tree
|
||||
document.body.addEventListener('htmx:oobAfterSwap', (event) => {
|
||||
const target = event.detail?.target;
|
||||
// Ignorer les swaps de statut (auto-save-status, save-status)
|
||||
if (target && target.id === 'file-tree') {
|
||||
console.log('FileTree: oobAfterSwap detected, updating attributes...');
|
||||
this.updateDraggableAttributes();
|
||||
}
|
||||
});
|
||||
|
||||
// Écouter les restaurations d'historique (bouton retour du navigateur)
|
||||
document.body.addEventListener('htmx:historyRestore', () => {
|
||||
console.log('FileTree: History restored, re-initializing event listeners...');
|
||||
// Réinitialiser complètement les event listeners après restauration de l'historique
|
||||
setTimeout(() => {
|
||||
this.setupEventListeners();
|
||||
this.updateDraggableAttributes();
|
||||
}, 50);
|
||||
});
|
||||
}
|
||||
|
||||
updateDraggableAttributes() {
|
||||
@ -415,7 +456,8 @@ window.handleNewNote = function(event) {
|
||||
if (typeof htmx !== 'undefined') {
|
||||
htmx.ajax('GET', `/api/notes/${encodeURIComponent(noteName)}`, {
|
||||
target: '#editor-container',
|
||||
swap: 'innerHTML'
|
||||
swap: 'innerHTML',
|
||||
pushUrl: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
193
frontend/src/sidebar-sections.js
Normal file
193
frontend/src/sidebar-sections.js
Normal file
@ -0,0 +1,193 @@
|
||||
/**
|
||||
* SidebarSections - Gère les sections rétractables de la sidebar
|
||||
* Permet de replier/déplier les favoris et le répertoire de notes
|
||||
*/
|
||||
class SidebarSections {
|
||||
constructor() {
|
||||
this.sections = {
|
||||
favorites: { key: 'sidebar-favorites-expanded', defaultState: true },
|
||||
notes: { key: 'sidebar-notes-expanded', defaultState: true }
|
||||
};
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
console.log('SidebarSections: Initialisation...');
|
||||
|
||||
// Restaurer l'état sauvegardé au démarrage
|
||||
this.restoreStates();
|
||||
|
||||
// Écouter les événements HTMX pour réattacher les handlers après les swaps
|
||||
document.body.addEventListener('htmx:afterSwap', (event) => {
|
||||
const targetId = event.detail?.target?.id;
|
||||
|
||||
if (targetId === 'favorites-list') {
|
||||
console.log('Favoris rechargés, restauration de l\'état...');
|
||||
setTimeout(() => this.restoreSectionState('favorites'), 50);
|
||||
}
|
||||
|
||||
if (targetId === 'file-tree') {
|
||||
console.log('File-tree rechargé, restauration de l\'état...');
|
||||
setTimeout(() => this.restoreSectionState('notes'), 50);
|
||||
}
|
||||
});
|
||||
|
||||
document.body.addEventListener('htmx:oobAfterSwap', (event) => {
|
||||
const targetId = event.detail?.target?.id;
|
||||
|
||||
// Ne restaurer l'état que pour les swaps du file-tree complet
|
||||
// Les swaps de statut (auto-save-status) ne doivent pas déclencher la restauration
|
||||
if (targetId === 'file-tree') {
|
||||
console.log('File-tree rechargé (oob), restauration de l\'état...');
|
||||
setTimeout(() => this.restoreSectionState('notes'), 50);
|
||||
}
|
||||
});
|
||||
|
||||
// Écouter les restaurations d'historique (bouton retour du navigateur)
|
||||
document.body.addEventListener('htmx:historyRestore', () => {
|
||||
console.log('SidebarSections: History restored, restoring section states...');
|
||||
// Restaurer les états des sections après restauration de l'historique
|
||||
setTimeout(() => {
|
||||
this.restoreSectionState('favorites');
|
||||
this.restoreSectionState('notes');
|
||||
}, 100);
|
||||
});
|
||||
|
||||
console.log('SidebarSections: Initialisé');
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère l'état sauvegardé d'une section
|
||||
*/
|
||||
getSectionState(sectionName) {
|
||||
const section = this.sections[sectionName];
|
||||
if (!section) return true;
|
||||
|
||||
const saved = localStorage.getItem(section.key);
|
||||
return saved !== null ? saved === 'true' : section.defaultState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sauvegarde l'état d'une section
|
||||
*/
|
||||
setSectionState(sectionName, isExpanded) {
|
||||
const section = this.sections[sectionName];
|
||||
if (!section) return;
|
||||
|
||||
localStorage.setItem(section.key, isExpanded.toString());
|
||||
console.log(`État sauvegardé: ${sectionName} = ${isExpanded}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle une section (ouvert/fermé)
|
||||
*/
|
||||
toggleSection(sectionName, headerElement) {
|
||||
if (!headerElement) {
|
||||
console.error(`Header element not found for section: ${sectionName}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const contentElement = headerElement.nextElementSibling;
|
||||
const toggleIcon = headerElement.querySelector('.section-toggle');
|
||||
|
||||
if (!contentElement) {
|
||||
console.error(`Content element not found for section: ${sectionName}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const isCurrentlyExpanded = contentElement.style.display !== 'none';
|
||||
const newState = !isCurrentlyExpanded;
|
||||
|
||||
if (newState) {
|
||||
// Ouvrir
|
||||
contentElement.style.display = 'block';
|
||||
if (toggleIcon) {
|
||||
toggleIcon.classList.add('expanded');
|
||||
}
|
||||
} else {
|
||||
// Fermer
|
||||
contentElement.style.display = 'none';
|
||||
if (toggleIcon) {
|
||||
toggleIcon.classList.remove('expanded');
|
||||
}
|
||||
}
|
||||
|
||||
this.setSectionState(sectionName, newState);
|
||||
console.log(`Section ${sectionName} ${newState ? 'ouverte' : 'fermée'}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restaure l'état d'une section depuis localStorage
|
||||
*/
|
||||
restoreSectionState(sectionName) {
|
||||
const isExpanded = this.getSectionState(sectionName);
|
||||
const header = document.querySelector(`[data-section="${sectionName}"]`);
|
||||
|
||||
if (!header) {
|
||||
console.warn(`Header not found for section: ${sectionName}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const content = header.nextElementSibling;
|
||||
const toggleIcon = header.querySelector('.section-toggle');
|
||||
|
||||
if (!content) {
|
||||
console.warn(`Content not found for section: ${sectionName}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExpanded) {
|
||||
content.style.display = 'block';
|
||||
if (toggleIcon) {
|
||||
toggleIcon.classList.add('expanded');
|
||||
}
|
||||
} else {
|
||||
content.style.display = 'none';
|
||||
if (toggleIcon) {
|
||||
toggleIcon.classList.remove('expanded');
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`État restauré: ${sectionName} = ${isExpanded ? 'ouvert' : 'fermé'}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restaure tous les états au démarrage
|
||||
*/
|
||||
restoreStates() {
|
||||
// Attendre que le DOM soit complètement chargé et que HTMX ait fini de charger les contenus
|
||||
// Délai augmenté pour correspondre aux délais des triggers HTMX (250ms + marge)
|
||||
setTimeout(() => {
|
||||
this.restoreSectionState('favorites');
|
||||
this.restoreSectionState('notes');
|
||||
}, 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fonction globale pour toggle une section (appelée depuis le HTML)
|
||||
*/
|
||||
window.toggleSidebarSection = function(sectionName, event) {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
const headerElement = event?.currentTarget || document.querySelector(`[data-section="${sectionName}"]`);
|
||||
|
||||
if (window.sidebarSections && headerElement) {
|
||||
window.sidebarSections.toggleSection(sectionName, headerElement);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialisation automatique
|
||||
*/
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
window.sidebarSections = new SidebarSections();
|
||||
});
|
||||
} else {
|
||||
// DOM déjà chargé
|
||||
window.sidebarSections = new SidebarSections();
|
||||
}
|
||||
@ -13,8 +13,8 @@ export default defineConfig({
|
||||
build: {
|
||||
lib: {
|
||||
entry: 'src/main.js', // This will be our main entry point
|
||||
name: 'ProjectNotesFrontend',
|
||||
fileName: (format) => `project-notes-frontend.${format}.js`
|
||||
name: 'PersoNotesFrontend',
|
||||
fileName: (format) => `personotes-frontend.${format}.js`
|
||||
},
|
||||
outDir: '../static/dist', // Output to a new 'dist' folder inside the existing 'static' directory
|
||||
emptyOutDir: true,
|
||||
|
||||
Reference in New Issue
Block a user