ObsiGate/frontend/index.html

557 lines
28 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="fr" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ObsiGate</title>
<link rel="stylesheet" href="/static/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css" id="hljs-theme-dark">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css" id="hljs-theme-light" disabled>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<script src="https://unpkg.com/lucide@0.344.0/dist/umd/lucide.min.js"></script>
<script type="importmap">
{
"imports": {
"@codemirror/state": "https://esm.sh/@codemirror/state@6.2.0"
}
}
</script>
<!-- CodeMirror 6 -->
<script type="module">
import { EditorView, keymap, lineNumbers, highlightActiveLineGutter, highlightSpecialChars, drawSelection, dropCursor, rectangularSelection, crosshairCursor, highlightActiveLine } from "https://esm.sh/@codemirror/view@6.9.0?external=@codemirror/state";
import { EditorState } from "@codemirror/state";
import { defaultHighlightStyle, syntaxHighlighting, indentOnInput, bracketMatching, foldGutter, foldKeymap } from "https://esm.sh/@codemirror/language@6.6.0?external=@codemirror/state";
import { defaultKeymap, history, historyKeymap } from "https://esm.sh/@codemirror/commands@6.2.3?external=@codemirror/state";
import { searchKeymap, highlightSelectionMatches } from "https://esm.sh/@codemirror/search@6.3.0?external=@codemirror/state";
import { autocompletion, completionKeymap, closeBrackets, closeBracketsKeymap } from "https://esm.sh/@codemirror/autocomplete@6.5.0?external=@codemirror/state";
import { markdown } from "https://esm.sh/@codemirror/lang-markdown@6.1.0?external=@codemirror/state";
import { python } from "https://esm.sh/@codemirror/lang-python@6.1.3?external=@codemirror/state";
import { javascript } from "https://esm.sh/@codemirror/lang-javascript@6.1.7?external=@codemirror/state";
import { html } from "https://esm.sh/@codemirror/lang-html@6.4.3?external=@codemirror/state";
import { css } from "https://esm.sh/@codemirror/lang-css@6.2.0?external=@codemirror/state";
import { json } from "https://esm.sh/@codemirror/lang-json@6.0.1?external=@codemirror/state";
import { xml } from "https://esm.sh/@codemirror/lang-xml@6.0.2?external=@codemirror/state";
import { sql } from "https://esm.sh/@codemirror/lang-sql@6.5.0?external=@codemirror/state";
import { php } from "https://esm.sh/@codemirror/lang-php@6.0.1?external=@codemirror/state";
import { cpp } from "https://esm.sh/@codemirror/lang-cpp@6.0.2?external=@codemirror/state";
import { java } from "https://esm.sh/@codemirror/lang-java@6.0.1?external=@codemirror/state";
import { rust } from "https://esm.sh/@codemirror/lang-rust@6.0.1?external=@codemirror/state";
import { oneDark } from "https://esm.sh/@codemirror/theme-one-dark@6.1.0?external=@codemirror/state";
const basicSetup = [
lineNumbers(),
highlightActiveLineGutter(),
highlightSpecialChars(),
history(),
foldGutter(),
drawSelection(),
dropCursor(),
EditorState.allowMultipleSelections.of(true),
indentOnInput(),
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
bracketMatching(),
closeBrackets(),
autocompletion(),
rectangularSelection(),
crosshairCursor(),
highlightActiveLine(),
highlightSelectionMatches(),
keymap.of([
...closeBracketsKeymap,
...defaultKeymap,
...searchKeymap,
...historyKeymap,
...foldKeymap,
...completionKeymap,
])
];
window.CodeMirror = { EditorView, EditorState, basicSetup, markdown, python, javascript, html, css, json, xml, sql, php, cpp, java, rust, oneDark, keymap };
</script>
</head>
<body>
<div class="search-progress-bar" id="search-progress-bar"><div class="search-progress-bar__fill"></div></div>
<div class="app-container">
<!-- Header -->
<header class="header">
<div class="header-left">
<button class="hamburger-btn" id="hamburger-btn" title="Menu">
<i data-lucide="menu" style="width:20px;height:20px"></i>
</button>
<button class="sidebar-toggle-btn" id="sidebar-toggle-btn" title="Afficher/Masquer la sidebar">
<i data-lucide="sidebar" style="width:20px;height:20px"></i>
</button>
<div class="header-logo" id="header-logo">
<i data-lucide="book-open" style="width:20px;height:20px"></i>
ObsiGate
</div>
</div>
<div class="header-center">
<div class="search-wrapper">
<i data-lucide="search" class="search-icon" style="width:16px;height:16px"></i>
<div class="search-input-wrapper">
<input type="text" id="search-input" placeholder="Recherche..." autocomplete="off">
<div class="search-actions">
<button class="search-btn" id="search-case-btn" type="button" title="Respecter la casse" aria-label="Respecter la casse">
<span>Aa</span>
</button>
<button class="search-btn" id="search-clear-btn" type="button" title="Effacer la recherche" aria-label="Effacer la recherche">
<i data-lucide="x" style="width:14px;height:14px"></i>
</button>
</div>
</div>
<!-- Advanced search autocomplete dropdown -->
<div class="search-dropdown" id="search-dropdown" role="listbox" aria-label="Suggestions de recherche" hidden>
<div class="search-dropdown__section search-dropdown__section--history" id="search-dropdown-history">
<div class="search-dropdown__section-header">
<span>Historique</span>
<button class="search-dropdown__clear-btn" id="search-dropdown-clear-history" type="button" title="Effacer l'historique">
<i data-lucide="trash-2" style="width:12px;height:12px"></i>
</button>
</div>
<ul class="search-dropdown__list" id="search-dropdown-history-list"></ul>
</div>
<div class="search-dropdown__section search-dropdown__section--titles" id="search-dropdown-titles">
<div class="search-dropdown__section-header"><span>Fichiers</span></div>
<ul class="search-dropdown__list" id="search-dropdown-titles-list"></ul>
</div>
<div class="search-dropdown__section search-dropdown__section--tags" id="search-dropdown-tags">
<div class="search-dropdown__section-header"><span>Tags</span></div>
<ul class="search-dropdown__list" id="search-dropdown-tags-list"></ul>
</div>
<div class="search-dropdown__empty" id="search-dropdown-empty" hidden>
Aucune suggestion
</div>
</div>
<!-- Active search filter chips -->
<div class="search-chips" id="search-chips" hidden></div>
</div>
</div>
<div class="header-right">
<div class="header-menu">
<button class="header-menu-btn" id="header-menu-btn" title="Options">
<i data-lucide="settings" style="width:18px;height:18px"></i>
</button>
<div class="header-menu-dropdown" id="header-menu-dropdown">
<div class="menu-list" role="menu" aria-label="Options">
<label class="menu-list-row menu-list-select-row" for="vault-filter">
<span class="menu-list-icon" aria-hidden="true">
<i data-lucide="folders" style="width:17px;height:17px"></i>
</span>
<span class="menu-list-content">
<span class="menu-list-title">Vault</span>
<div class="custom-dropdown" id="vault-filter-dropdown">
<button class="custom-dropdown-trigger" type="button" aria-haspopup="listbox" aria-expanded="false">
<span class="custom-dropdown-selected">Tous les vaults</span>
<i data-lucide="chevron-down" style="width:14px;height:14px"></i>
</button>
<ul class="custom-dropdown-menu" role="listbox" id="vault-filter-options">
<li role="option" data-value="all" class="custom-dropdown-option selected">Tous les vaults</li>
</ul>
<input type="hidden" id="vault-filter" value="all">
</div>
</span>
</label>
<button class="menu-list-row menu-list-button" id="theme-toggle" type="button" role="menuitem">
<span class="menu-list-icon" aria-hidden="true">
<i data-lucide="sun" style="width:17px;height:17px"></i>
</span>
<span class="menu-list-content">
<span class="menu-list-title">Thème</span>
<span class="menu-list-subtitle" id="theme-label">Clair</span>
</span>
</button>
<button class="menu-list-row menu-list-button" id="config-open-btn" type="button" role="menuitem">
<span class="menu-list-icon" aria-hidden="true">
<i data-lucide="settings" style="width:17px;height:17px"></i>
</span>
<span class="menu-list-content">
<span class="menu-list-title">Configurations</span>
<span class="menu-list-subtitle">Paramètres de l'application</span>
</span>
</button>
<button class="menu-list-row menu-list-button" id="help-open-btn" type="button" role="menuitem">
<span class="menu-list-icon" aria-hidden="true">
<i data-lucide="book-open" style="width:17px;height:17px"></i>
</span>
<span class="menu-list-content">
<span class="menu-list-title">Guide d'utilisation</span>
<span class="menu-list-subtitle">Ouvrir l'aide</span>
</span>
</button>
</div>
</div>
</div>
</div>
</header>
<!-- Main -->
<div class="main-body">
<!-- Mobile overlay -->
<div class="sidebar-overlay" id="sidebar-overlay"></div>
<!-- Sidebar -->
<aside class="sidebar" id="sidebar" role="navigation" aria-label="Navigation des vaults">
<!-- Sidebar filter -->
<div class="sidebar-filter">
<div class="sidebar-filter-input-wrapper">
<i data-lucide="filter" class="sidebar-filter-icon" style="width:14px;height:14px"></i>
<input type="text" id="sidebar-filter-input" placeholder="Filtrer fichiers..." autocomplete="off">
<div class="sidebar-filter-actions">
<button class="sidebar-filter-btn" id="sidebar-filter-case-btn" type="button" title="Respecter la casse" aria-label="Respecter la casse">
<span>Aa</span>
</button>
<button class="sidebar-filter-btn" id="sidebar-filter-clear-btn" type="button" title="Effacer le filtrage" aria-label="Effacer le filtrage">
<i data-lucide="x" style="width:14px;height:14px"></i>
</button>
</div>
</div>
</div>
<!-- Tab bar -->
<div class="sidebar-tabs" role="tablist" aria-label="Sections sidebar">
<button class="sidebar-tab active" id="sidebar-tab-vaults" role="tab"
aria-selected="true" aria-controls="sidebar-panel-vaults" data-tab="vaults">
<i data-lucide="folder-tree" style="width:13px;height:13px"></i>
<span>Vaults</span>
</button>
<button class="sidebar-tab" id="sidebar-tab-tags" role="tab"
aria-selected="false" aria-controls="sidebar-panel-tags" data-tab="tags">
<i data-lucide="tag" style="width:13px;height:13px"></i>
<span>Tags</span>
</button>
</div>
<!-- Vaults panel -->
<div class="sidebar-tab-panel active" id="sidebar-panel-vaults" role="tabpanel" aria-labelledby="sidebar-tab-vaults">
<div class="custom-dropdown sidebar-dropdown" id="vault-quick-select-dropdown">
<button class="custom-dropdown-trigger" type="button" aria-haspopup="listbox" aria-expanded="false">
<span class="custom-dropdown-selected">Tous les vaults</span>
<i data-lucide="chevron-down" style="width:14px;height:14px"></i>
</button>
<ul class="custom-dropdown-menu" role="listbox" id="vault-quick-select-options">
<li role="option" data-value="all" class="custom-dropdown-option selected">Tous les vaults</li>
</ul>
<input type="hidden" id="vault-quick-select" value="all">
</div>
<div id="vault-tree" role="tree" aria-label="Arborescence des fichiers"></div>
</div>
<!-- Tags panel -->
<div class="sidebar-tab-panel" id="sidebar-panel-tags" role="tabpanel" aria-labelledby="sidebar-tab-tags">
<div class="tag-cloud" id="tag-cloud"></div>
</div>
</aside>
<!-- Sidebar resize handle -->
<div class="sidebar-resize-handle" id="sidebar-resize-handle"></div>
<!-- Content -->
<main class="content-area" id="content-area" aria-label="Contenu principal">
<div class="welcome" id="welcome" role="status">
<i data-lucide="library" style="width:48px;height:48px;color:var(--text-muted)"></i>
<h2>ObsiGate</h2>
<p>Sélectionnez un fichier dans la sidebar ou utilisez la recherche pour commencer.</p>
</div>
</main>
</div>
</div>
<!-- Editor Modal -->
<div class="editor-modal" id="editor-modal">
<div class="editor-container">
<div class="editor-header">
<div class="editor-title" id="editor-title">Édition</div>
<div class="editor-actions">
<button class="editor-btn danger" id="editor-delete" title="Supprimer" aria-label="Supprimer">
<i data-lucide="trash-2" style="width:16px;height:16px"></i>
</button>
<button class="editor-btn" id="editor-cancel" title="Annuler" aria-label="Annuler">
<i data-lucide="x" style="width:16px;height:16px"></i>
</button>
<button class="editor-btn primary" id="editor-save" title="Sauvegarder" aria-label="Sauvegarder">
<i data-lucide="check" style="width:16px;height:16px"></i>
</button>
</div>
</div>
<div class="editor-body" id="editor-body"></div>
</div>
</div>
<!-- Configurations Modal -->
<div class="editor-modal" id="config-modal">
<div class="editor-container">
<div class="editor-header">
<div class="editor-title">Configurations</div>
<div class="editor-actions">
<button class="editor-btn" id="config-close" title="Fermer" aria-label="Fermer">
<i data-lucide="x" style="width:16px;height:16px"></i>
</button>
</div>
</div>
<div class="editor-body" id="config-body">
<div class="config-content">
<!-- Performance Settings — Frontend -->
<section class="config-section">
<h2>Paramètres de recherche</h2>
<p class="config-description">Ces paramètres s'appliquent immédiatement côté client.</p>
<div class="config-row">
<label class="config-label" for="cfg-debounce">Délai debounce (ms)</label>
<input type="number" id="cfg-debounce" class="config-input config-input--num" min="100" max="2000" step="50" value="300">
<span class="config-hint">Délai avant exécution de la recherche (1002000)</span>
</div>
<div class="config-row">
<label class="config-label" for="cfg-results-per-page">Résultats par page</label>
<input type="number" id="cfg-results-per-page" class="config-input config-input--num" min="10" max="200" step="10" value="50">
<span class="config-hint">Nombre de résultats affichés par page (10200)</span>
</div>
<div class="config-row">
<label class="config-label" for="cfg-min-query">Longueur min. requête</label>
<input type="number" id="cfg-min-query" class="config-input config-input--num" min="1" max="5" step="1" value="2">
<span class="config-hint">Nombre minimum de caractères avant recherche (15)</span>
</div>
<div class="config-row">
<label class="config-label" for="cfg-timeout">Timeout recherche (ms)</label>
<input type="number" id="cfg-timeout" class="config-input config-input--num" min="5000" max="120000" step="5000" value="30000">
<span class="config-hint">Annuler la recherche après ce délai (5000120000)</span>
</div>
</section>
<!-- Performance Settings — Backend -->
<section class="config-section">
<h2>Paramètres backend <span class="config-badge-restart">Redémarrage requis</span></h2>
<p class="config-description">Ces paramètres sont sauvegardés sur le serveur. Certains nécessitent un redémarrage ou une réindexation.</p>
<div class="config-row">
<label class="config-label" for="cfg-workers">Workers de recherche</label>
<input type="number" id="cfg-workers" class="config-input config-input--num" min="1" max="8" step="1" value="2">
<span class="config-hint">Threads dédiés à la recherche (18)</span>
</div>
<div class="config-row">
<label class="config-label" for="cfg-max-content">Taille max contenu (octets)</label>
<input type="number" id="cfg-max-content" class="config-input config-input--num" min="10000" max="1000000" step="10000" value="100000">
<span class="config-hint">Contenu indexé par fichier (10K1M). Réindexation requise.</span>
</div>
<div class="config-row">
<label class="config-label" for="cfg-title-boost">Boost titre</label>
<input type="number" id="cfg-title-boost" class="config-input config-input--num" min="0" max="10" step="0.5" value="3.0">
<span class="config-hint">Multiplicateur de pertinence pour les correspondances dans le titre</span>
</div>
<div class="config-row">
<label class="config-label" for="cfg-tag-boost">Boost tags</label>
<input type="number" id="cfg-tag-boost" class="config-input config-input--num" min="0" max="10" step="0.5" value="2.0">
<span class="config-hint">Multiplicateur de pertinence pour les correspondances dans les tags</span>
</div>
<div class="config-row">
<label class="config-label" for="cfg-prefix-exp">Expansions préfixe max</label>
<input type="number" id="cfg-prefix-exp" class="config-input config-input--num" min="10" max="200" step="10" value="50">
<span class="config-hint">Nombre max de tokens élargis par préfixe (10200)</span>
</div>
<div class="config-actions-row">
<button class="config-btn-save" id="cfg-save-backend">Sauvegarder</button>
<button class="config-btn-secondary" id="cfg-reindex">Forcer réindexation</button>
<button class="config-btn-secondary" id="cfg-reset-defaults">Réinitialiser</button>
</div>
</section>
<!-- Tag Filtering (existing) -->
<section class="config-section">
<h2>Filtrage de tags</h2>
<p class="config-description">Définissez les patterns de tags à masquer dans la sidebar. Vous pouvez utiliser des wildcards pour cibler les tags de template.</p>
<div class="config-filters-list" id="config-filters-list"></div>
<div class="config-add-pattern">
<input type="text" id="config-pattern-input" placeholder="Ex: #&lt;% ... %&gt; ou #{{ ... }}" class="config-input">
<button id="config-add-btn" class="config-btn-add">Ajouter</button>
</div>
<div class="config-regex-preview" id="config-regex-preview" style="display:none;">
<small>Regex : <code id="config-regex-code"></code></small>
</div>
</section>
<!-- Diagnostics -->
<section class="config-section">
<h2>Diagnostics</h2>
<p class="config-description">Statistiques de l'index et du moteur de recherche.</p>
<div id="config-diagnostics" class="config-diagnostics">
<div class="config-diag-loading">Chargement...</div>
</div>
<button class="config-btn-secondary" id="cfg-refresh-diag" style="margin-top:8px">Rafraîchir</button>
</section>
</div>
</div>
</div>
</div>
<!-- Help Modal -->
<div class="editor-modal" id="help-modal">
<div class="editor-container help-container">
<div class="editor-header">
<div class="editor-title" id="help-title">Aide ObsiGate</div>
<div class="editor-actions">
<button class="editor-btn" id="help-close" title="Fermer l'aide" aria-label="Fermer l'aide">
<i data-lucide="x" style="width:16px;height:16px"></i>
</button>
</div>
</div>
<div class="editor-body help-body" id="help-body">
<div class="help-content">
<section class="help-hero">
<div class="help-hero-copy">
<div class="help-kicker">📘 Guide d'utilisation</div>
<h1>Bienvenue dans ObsiGate</h1>
<p>Explorez vos notes, changez de vault en un clic, filtrez avec les tags et retrouvez immédiatement le bon document grâce à une navigation pensée pour aller vite.</p>
<div class="help-badges">
<span class="help-badge">⚡ Navigation rapide</span>
<span class="help-badge">🗂️ Multi-vault</span>
<span class="help-badge">🏷️ Tags intelligents</span>
<span class="help-badge">📝 Lecture et édition</span>
</div>
</div>
<div class="help-hero-visual" aria-hidden="true">
<div class="help-mini-window">
<div class="help-mini-window-bar">
<span></span>
<span></span>
<span></span>
</div>
<div class="help-mini-window-body">
<div class="help-mini-sidebar"></div>
<div class="help-mini-content">
<div class="help-mini-line short"></div>
<div class="help-mini-line"></div>
<div class="help-mini-tags">
<span>#docker</span>
<span>#infra</span>
<span>#linux</span>
</div>
<div class="help-mini-card"></div>
</div>
</div>
</div>
</div>
</section>
<section class="help-grid">
<article class="help-card">
<div class="help-card-icon">🔎</div>
<h2>Rechercher vite</h2>
<p>Utilisez la barre de recherche en haut pour retrouver un mot, un titre ou un contenu dans vos notes.</p>
</article>
<article class="help-card">
<div class="help-card-icon">🗃️</div>
<h2>Changer de vault</h2>
<p>Le sélecteur de vault vous permet de rester sur <code>Tous les vaults</code> ou de vous concentrer sur un espace précis.</p>
</article>
<article class="help-card">
<div class="help-card-icon">🏷️</div>
<h2>Filtrer par tags</h2>
<p>Cliquez sur un tag pour affiner les résultats et retrouver rapidement les notes associées.</p>
</article>
</section>
<section class="help-section">
<h2>🧭 Comprendre linterface</h2>
<div class="help-feature-list">
<div class="help-feature-item">
<div class="help-feature-emoji">🧱</div>
<div>
<h3>En-tête</h3>
<p>Il regroupe la recherche globale, le bouton menu des options et laccès rapide à lidentité de lapplication.</p>
</div>
</div>
<div class="help-feature-item">
<div class="help-feature-emoji">🌲</div>
<div>
<h3>Sidebar</h3>
<p>La barre latérale affiche les vaults, les dossiers, les fichiers et les tags. Elle peut être redimensionnée sur desktop.</p>
</div>
</div>
<div class="help-feature-item">
<div class="help-feature-emoji">📄</div>
<div>
<h3>Zone centrale</h3>
<p>Elle sert à lire la note, afficher son chemin, voir ses tags et déclencher les actions comme copier, source, télécharger ou éditer.</p>
</div>
</div>
</div>
</section>
<section class="help-section">
<h2>🚀 Parcours recommandé</h2>
<div class="help-steps">
<div class="help-step">
<div class="help-step-number">1</div>
<div>
<h3>Choisissez un contexte</h3>
<p>Sélectionnez un vault dans le menu du haut ou dans la sidebar pour réduire le bruit et cibler votre navigation.</p>
</div>
</div>
<div class="help-step">
<div class="help-step-number">2</div>
<div>
<h3>Explorez larborescence</h3>
<p>Dépliez les dossiers, ouvrez une note et utilisez le chemin en haut de page pour revenir visuellement au bon endroit dans la sidebar.</p>
</div>
</div>
<div class="help-step">
<div class="help-step-number">3</div>
<div>
<h3>Affinez avec les tags</h3>
<p>Ajoutez un ou plusieurs tags pour filtrer vos contenus de façon plus fine et faire émerger les notes pertinentes.</p>
</div>
</div>
</div>
</section>
<section class="help-section">
<h2>✨ Actions utiles au quotidien</h2>
<div class="help-checklist">
<div class="help-check-item"><span></span><p>Basculer entre thème <strong>clair</strong> et <strong>sombre</strong> depuis le menu Options.</p></div>
<div class="help-check-item"><span></span><p>Utiliser <code>Tous les vaults</code> pour une vue globale ou cibler un seul vault pour une navigation plus nette.</p></div>
<div class="help-check-item"><span></span><p>Cliquer sur un tag dans la note ou dans la sidebar pour lancer un filtrage rapide.</p></div>
<div class="help-check-item"><span></span><p>Ouvrir une note puis utiliser <strong>Copier</strong>, <strong>Source</strong>, <strong>Télécharger</strong> ou <strong>Éditer</strong>.</p></div>
</div>
</section>
<section class="help-section help-tip-panel">
<h2>💡 Astuces</h2>
<div class="help-tip-grid">
<div class="help-tip-card">
<h3>Navigation visuelle</h3>
<p>Quand vous cliquez sur le chemin dune note, la sidebar se repositionne automatiquement pour montrer lélément correspondant.</p>
</div>
<div class="help-tip-card">
<h3>Gestion de lespace</h3>
<p>Réduisez <code>VAULTS</code> ou <code>TAGS</code> pour donner plus despace à la section qui vous intéresse le plus.</p>
</div>
<div class="help-tip-card">
<h3>Confort de lecture</h3>
<p>Adaptez la largeur de la sidebar et la hauteur de la zone tags sur desktop pour un affichage plus confortable.</p>
</div>
</div>
</section>
</div>
</div>
</div>
</div>
<script src="/static/app.js"></script>
</body>
</html>