mirror of
https://github.com/R0m1k3/noteflow.git
synced 2026-10-11 17:29:37 +02:00
1. Titre 'À faire' au lieu de 'Quick Tasks' - Changé public/index.html ligne 126 - Meilleure localisation française 2. Affichage source RSS au lieu du modèle IA - Ajout colonne feed_title à rss_summaries (migration auto) - Backend stocke feed_title lors de la génération - GET /api/rss/summaries retourne feed_title - Frontend affiche 📰 Source + 📅 Date au lieu du modèle - Plus pertinent pour l'utilisateur 3. Tri automatique des todos : actives en premier - renderTodos() trie : actives avant complétées - Si même statut : tri par ID décroissant (récentes en premier) - Sort: a.completed ? 1 : -1 4. Système de notifications internes - Remplacé TOUS les alert() par showNotification() - Types : success, error, warning, info - Animations : slide-in/slide-out depuis la droite - Auto-fermeture après 4 secondes - Bouton de fermeture manuelle - Position : top-right, z-index 300 - Icônes SVG selon le type - Couleurs : vert (success), rouge (error), jaune (warning), bleu (info) Frontend - Notifications: - showNotification(message, type, duration) - closeNotification(notification) - Container fixe en haut à droite - Empilage vertical des notifications - Escape HTML automatique CSS - Nouveaux styles: - .notifications-container (fixed, top-right) - .notification + variations par type - Animations slideInRight / slideOutRight - Border-left colorée selon le type - Responsive et accessible Impact utilisateur: ✓ Plus de popups système alert() invasives ✓ Notifications élégantes et non-bloquantes ✓ Feedback visuel clair avec icônes et couleurs ✓ Source RSS affichée au lieu du modèle IA ✓ Todos actives toujours en haut ✓ Interface 100% en français Files: - public/index.html: Titre + container notifications - public/css/skeleton.css: Styles notifications - public/js/complete-app.js: showNotification() + remplacement 40+ alert() - config/database.js: Migration feed_title - routes/rss.routes.js: Stockage et retour feed_title
312 lines
15 KiB
HTML
312 lines
15 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>NoteFlow - Notes & Tasks</title>
|
|
|
|
<!-- Favicon -->
|
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
|
|
<!-- CSS -->
|
|
<link rel="stylesheet" href="/css/reset.css">
|
|
<link rel="stylesheet" href="/css/variables.css">
|
|
<link rel="stylesheet" href="/css/layout.css">
|
|
<link rel="stylesheet" href="/css/components.css">
|
|
<link rel="stylesheet" href="/css/animations.css">
|
|
<link rel="stylesheet" href="/css/skeleton.css">
|
|
</head>
|
|
<body>
|
|
<!-- Header -->
|
|
<header class="header">
|
|
<div class="header-container">
|
|
<!-- Logo -->
|
|
<div class="logo">
|
|
<svg class="logo-icon" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
|
|
<rect x="8" y="6" width="24" height="28" rx="2" fill="currentColor"/>
|
|
<rect x="10" y="8" width="20" height="24" rx="1" fill="white"/>
|
|
<line x1="13" y1="13" x2="27" y2="13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
<line x1="13" y1="18" x2="24" y2="18" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
<line x1="13" y1="23" x2="27" y2="23" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
<circle cx="15" cy="28" r="2" fill="none" stroke="currentColor" stroke-width="1.2"/>
|
|
<path d="M 14 28 L 14.8 28.8 L 16.5 27" stroke="currentColor" stroke-width="1.2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</svg>
|
|
<span class="logo-text">NoteFlow</span>
|
|
</div>
|
|
|
|
<!-- Search -->
|
|
<div class="search-container">
|
|
<svg class="search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<circle cx="11" cy="11" r="8"></circle>
|
|
<path d="m21 21-4.35-4.35"></path>
|
|
</svg>
|
|
<input type="text" id="searchInput" placeholder="Rechercher des notes..." class="search-input">
|
|
<button id="searchClear" class="search-clear" style="display: none;">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- User -->
|
|
<div class="user-menu">
|
|
<button class="user-button" id="userInfo">
|
|
<svg class="user-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
|
|
<circle cx="12" cy="7" r="4"></circle>
|
|
</svg>
|
|
<span id="userName">User</span>
|
|
<svg class="dropdown-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<polyline points="6 9 12 15 18 9"></polyline>
|
|
</svg>
|
|
</button>
|
|
<div class="user-dropdown" id="userDropdown">
|
|
<button class="dropdown-item" id="adminBtn" style="display: none;">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<circle cx="12" cy="12" r="3"></circle>
|
|
<path d="M12 1v6m0 6v6m5.657-13.657L14 9l-2.343-2.343M9 14l-3.657 3.657M1 12h6m6 0h6m-13.657 5.657L9 14l2.343 2.343M14 9l3.657-3.657"></path>
|
|
</svg>
|
|
Administration
|
|
</button>
|
|
<button class="dropdown-item" id="logoutBtn">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
|
<polyline points="16 17 21 12 16 7"></polyline>
|
|
<line x1="21" y1="12" x2="9" y2="12"></line>
|
|
</svg>
|
|
Déconnexion
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Main Content -->
|
|
<main class="main-content">
|
|
<div class="content-container">
|
|
<!-- Notes Section -->
|
|
<div class="notes-section">
|
|
<div class="section-header">
|
|
<h2 class="section-title">Notes</h2>
|
|
<div class="section-actions">
|
|
<div class="view-filters">
|
|
<button class="view-filter active" data-view="active">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/>
|
|
</svg>
|
|
Actives
|
|
</button>
|
|
<button class="view-filter" data-view="archived">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<polyline points="21 8 21 21 3 21 3 8"></polyline>
|
|
<rect x="1" y="3" width="22" height="5"></rect>
|
|
<line x1="10" y1="12" x2="14" y2="12"></line>
|
|
</svg>
|
|
Archivées
|
|
</button>
|
|
</div>
|
|
<button class="btn-new-note" id="newNoteBtn">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<line x1="12" y1="5" x2="12" y2="19"></line>
|
|
<line x1="5" y1="12" x2="19" y2="12"></line>
|
|
</svg>
|
|
Nouvelle note
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="notes-grid" id="notesGrid">
|
|
<!-- Notes will be inserted here dynamically -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Todo Box -->
|
|
<div class="todo-box">
|
|
<div class="todo-box-header">
|
|
<h2 class="todo-box-title">À faire</h2>
|
|
<span class="todo-counter" id="todoCounter">0 tâches</span>
|
|
</div>
|
|
|
|
<div class="todo-input-wrapper">
|
|
<input type="text" id="todoInput" class="todo-input" placeholder="Ajouter une tâche...">
|
|
<button id="addTodoBtn" class="btn-add-todo">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<line x1="12" y1="5" x2="12" y2="19"></line>
|
|
<line x1="5" y1="12" x2="19" y2="12"></line>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="todo-filters">
|
|
<button class="filter-btn active" data-filter="all">Toutes</button>
|
|
<button class="filter-btn" data-filter="active">Actives</button>
|
|
<button class="filter-btn" data-filter="completed">Terminées</button>
|
|
</div>
|
|
|
|
<div class="todo-list" id="todoList">
|
|
<!-- Todos will be inserted here -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- RSS Box -->
|
|
<div class="rss-box">
|
|
<div class="rss-box-header">
|
|
<h2 class="rss-box-title">📰 Actualités</h2>
|
|
<button class="btn-summarize" id="summarizeRssBtn" title="Générer un résumé avec IA">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M12 2L2 7l10 5 10-5-10-5z"></path>
|
|
<path d="M2 17l10 5 10-5"></path>
|
|
<path d="M2 12l10 5 10-5"></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="rss-articles-list" id="rssArticlesList">
|
|
<p class="rss-empty">Aucun article pour le moment</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<!-- Modal Admin -->
|
|
<div class="modal-backdrop" id="adminModal" style="display: none;">
|
|
<div class="modal-content admin-modal">
|
|
<div class="modal-header">
|
|
<h2>Administration</h2>
|
|
<button class="modal-close" id="closeAdminModal">✕</button>
|
|
</div>
|
|
|
|
<div class="admin-tabs">
|
|
<button class="admin-tab active" data-tab="users">👥 Utilisateurs</button>
|
|
<button class="admin-tab" data-tab="rss">📰 Flux RSS</button>
|
|
<button class="admin-tab" data-tab="openrouter">🤖 OpenRouter</button>
|
|
</div>
|
|
|
|
<!-- Onglet Utilisateurs -->
|
|
<div class="admin-tab-content" id="tab-users">
|
|
<div class="admin-actions">
|
|
<button class="action-btn" id="createUserBtn">+ Créer un utilisateur</button>
|
|
</div>
|
|
|
|
<div class="users-table-container">
|
|
<table class="users-table" id="usersTable">
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Nom d'utilisateur</th>
|
|
<th>Admin</th>
|
|
<th>Créé le</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="usersTableBody">
|
|
<!-- Users will be inserted here -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Onglet RSS -->
|
|
<div class="admin-tab-content" id="tab-rss" style="display: none;">
|
|
<div class="admin-actions">
|
|
<input type="url" id="rssUrlInput" class="rss-url-input" placeholder="https://example.com/feed.xml">
|
|
<button class="action-btn" id="addRssFeedBtn">+ Ajouter un flux</button>
|
|
<button class="action-btn btn-secondary" id="fetchRssBtn">🔄 Récupérer les articles</button>
|
|
</div>
|
|
|
|
<div class="rss-feeds-list" id="rssFeedsList">
|
|
<!-- Feeds will be inserted here -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Onglet OpenRouter -->
|
|
<div class="admin-tab-content" id="tab-openrouter" style="display: none;">
|
|
<div class="openrouter-settings">
|
|
<div class="setting-group">
|
|
<label for="openrouterApiKey">Clé API OpenRouter</label>
|
|
<input type="password" id="openrouterApiKey" class="setting-input" placeholder="sk-or-...">
|
|
<small>Obtenez votre clé sur <a href="https://openrouter.ai" target="_blank">openrouter.ai</a></small>
|
|
</div>
|
|
|
|
<div class="setting-group">
|
|
<label for="openrouterModel">Modèle</label>
|
|
<input type="text" id="modelSearch" class="setting-input" placeholder="Rechercher un modèle...">
|
|
<select id="openrouterModel" class="setting-select" size="8">
|
|
<!-- Models will be inserted here -->
|
|
</select>
|
|
</div>
|
|
|
|
<div class="setting-group">
|
|
<label for="rssSummaryEnabled">
|
|
<input type="checkbox" id="rssSummaryEnabled">
|
|
Activer les résumés automatiques
|
|
</label>
|
|
</div>
|
|
|
|
<div class="setting-group">
|
|
<label for="rssSummaryPrompt">Prompt de résumé</label>
|
|
<textarea id="rssSummaryPrompt" class="setting-textarea" rows="10" placeholder="Le prompt sera chargé..."></textarea>
|
|
</div>
|
|
|
|
<button class="action-btn" id="saveOpenRouterSettings">💾 Sauvegarder les paramètres</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal Change Password -->
|
|
<div class="modal-backdrop" id="changePasswordModal" style="display: none;">
|
|
<div class="modal-content small-modal">
|
|
<div class="modal-header">
|
|
<h3>Changer le mot de passe</h3>
|
|
<button class="modal-close" id="closeChangePasswordModal">✕</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p id="changePasswordUsername"></p>
|
|
<div class="form-group">
|
|
<label for="newPassword">Nouveau mot de passe</label>
|
|
<input type="password" id="newPassword" class="form-input" placeholder="Minimum 6 caractères">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="confirmPassword">Confirmer le mot de passe</label>
|
|
<input type="password" id="confirmPassword" class="form-input">
|
|
</div>
|
|
<div class="modal-actions">
|
|
<button class="btn-cancel" id="cancelChangePassword">Annuler</button>
|
|
<button class="btn-confirm" id="confirmChangePassword">Changer</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal de Confirmation -->
|
|
<div class="modal-backdrop" id="confirmModal" style="display: none;">
|
|
<div class="modal-content confirm-modal">
|
|
<div class="confirm-icon" id="confirmIcon">⚠️</div>
|
|
<h3 class="confirm-title" id="confirmTitle">Confirmer l'action</h3>
|
|
<p class="confirm-message" id="confirmMessage">Êtes-vous sûr de vouloir continuer ?</p>
|
|
<div class="confirm-actions">
|
|
<button class="btn-cancel" id="confirmCancel">Annuler</button>
|
|
<button class="btn-confirm" id="confirmOk">Confirmer</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Hidden file input -->
|
|
<input type="file" id="imageInput" accept="image/*" style="display: none;">
|
|
<input type="file" id="fileInput" style="display: none;">
|
|
|
|
<!-- Refresh indicator -->
|
|
<div class="refresh-indicator" id="refreshIndicator">
|
|
<div class="loading-spinner"></div>
|
|
<span>Mise à jour...</span>
|
|
</div>
|
|
|
|
<!-- Conteneur de notifications -->
|
|
<div class="notifications-container" id="notificationsContainer"></div>
|
|
|
|
<!-- JavaScript -->
|
|
<script src="/js/complete-app.js"></script>
|
|
</body>
|
|
</html>
|