\n", indent, indentClass))
sb.WriteString(fmt.Sprintf("%s \n", indent))
sb.WriteString(fmt.Sprintf("%s
\n", indent, safeID))
@@ -688,12 +741,14 @@ func (h *Handler) createAndRenderNote(w http.ResponseWriter, r *http.Request, fi
Filename string
Content string
IsHome bool
+ IsPublic bool
Backlinks []BacklinkInfo
}{
Filename: filename,
Content: initialContent,
IsHome: false,
- Backlinks: nil, // Pas de backlinks pour une nouvelle note
+ IsPublic: false, // Nouvelle note, pas publique par défaut
+ Backlinks: nil, // Pas de backlinks pour une nouvelle note
}
err = h.templates.ExecuteTemplate(w, "editor.html", data)
@@ -832,12 +887,14 @@ func (h *Handler) handleGetNote(w http.ResponseWriter, r *http.Request, filename
Filename string
Content string
IsHome bool
+ IsPublic bool
Backlinks []BacklinkInfo
Breadcrumb template.HTML
}{
Filename: filename,
Content: string(content),
IsHome: false,
+ IsPublic: h.isPublic(filename),
Backlinks: backlinkData,
Breadcrumb: h.generateBreadcrumb(filename),
}
@@ -1347,15 +1404,17 @@ func (h *Handler) handleFolderView(w http.ResponseWriter, r *http.Request) {
// Utiliser le template editor.html
data := struct {
- Filename string
- Content string
- IsHome bool
- Backlinks []BacklinkInfo
+ Filename string
+ Content string
+ IsHome bool
+ IsPublic bool
+ Backlinks []BacklinkInfo
Breadcrumb template.HTML
}{
Filename: cleanPath,
Content: content,
IsHome: true, // Pas d'édition pour une vue de dossier
+ IsPublic: false,
Backlinks: nil,
Breadcrumb: h.generateBreadcrumb(cleanPath),
}
@@ -1370,7 +1429,7 @@ func (h *Handler) handleFolderView(w http.ResponseWriter, r *http.Request) {
// generateBreadcrumb génère un fil d'Ariane HTML cliquable
func (h *Handler) generateBreadcrumb(path string) template.HTML {
if path == "" {
- return template.HTML(`
📁 Racine `)
+ return template.HTML(`
Racine`)
}
parts := strings.Split(filepath.ToSlash(path), "/")
@@ -1379,7 +1438,7 @@ func (h *Handler) generateBreadcrumb(path string) template.HTML {
sb.WriteString(`
`)
// Lien racine
- sb.WriteString(`📁 Racine `)
+ sb.WriteString(` Racine `)
// Construire les liens pour chaque partie
currentPath := ""
diff --git a/internal/api/public.go b/internal/api/public.go
new file mode 100644
index 0000000..39dcb58
--- /dev/null
+++ b/internal/api/public.go
@@ -0,0 +1,607 @@
+package api
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "html/template"
+ "io"
+ "net/http"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+ "time"
+
+ "github.com/mathieu/personotes/internal/indexer"
+ "github.com/yuin/goldmark"
+ "github.com/yuin/goldmark/extension"
+ "github.com/yuin/goldmark/parser"
+ "github.com/yuin/goldmark/renderer/html"
+)
+
+// PublicNote représente une note partagée publiquement
+type PublicNote struct {
+ Path string `json:"path"`
+ Title string `json:"title"`
+ PublishedAt time.Time `json:"published_at"`
+}
+
+// PublicNotesData contient la liste des notes publiques
+type PublicNotesData struct {
+ Notes []PublicNote `json:"notes"`
+}
+
+// getPublicDirPath retourne le chemin du dossier public HTML
+func (h *Handler) getPublicDirPath() string {
+ return filepath.Join(h.notesDir, "..", "public")
+}
+
+// getPublicNotesFilePath retourne le chemin du fichier .public.json
+func (h *Handler) getPublicNotesFilePath() string {
+ return filepath.Join(h.notesDir, ".public.json")
+}
+
+// loadPublicNotes charge les notes publiques depuis le fichier JSON
+func (h *Handler) loadPublicNotes() (*PublicNotesData, error) {
+ path := h.getPublicNotesFilePath()
+
+ // Si le fichier n'existe pas, retourner une liste vide
+ if _, err := os.Stat(path); os.IsNotExist(err) {
+ return &PublicNotesData{Notes: []PublicNote{}}, nil
+ }
+
+ data, err := os.ReadFile(path)
+ if err != nil {
+ return nil, err
+ }
+
+ var publicNotes PublicNotesData
+ if err := json.Unmarshal(data, &publicNotes); err != nil {
+ return nil, err
+ }
+
+ // Trier par date de publication (plus récent d'abord)
+ sort.Slice(publicNotes.Notes, func(i, j int) bool {
+ return publicNotes.Notes[i].PublishedAt.After(publicNotes.Notes[j].PublishedAt)
+ })
+
+ return &publicNotes, nil
+}
+
+// savePublicNotes sauvegarde les notes publiques dans le fichier JSON
+func (h *Handler) savePublicNotes(publicNotes *PublicNotesData) error {
+ path := h.getPublicNotesFilePath()
+
+ data, err := json.MarshalIndent(publicNotes, "", " ")
+ if err != nil {
+ return err
+ }
+
+ return os.WriteFile(path, data, 0644)
+}
+
+// isPublic vérifie si une note est publique
+func (h *Handler) isPublic(notePath string) bool {
+ publicNotes, err := h.loadPublicNotes()
+ if err != nil {
+ return false
+ }
+
+ for _, note := range publicNotes.Notes {
+ if note.Path == notePath {
+ return true
+ }
+ }
+ return false
+}
+
+// ensurePublicDir crée le dossier public s'il n'existe pas
+func (h *Handler) ensurePublicDir() error {
+ publicDir := h.getPublicDirPath()
+
+ // Créer public/
+ if err := os.MkdirAll(publicDir, 0755); err != nil {
+ return err
+ }
+
+ // Créer public/static/
+ staticDir := filepath.Join(publicDir, "static")
+ if err := os.MkdirAll(staticDir, 0755); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// copyStaticAssets copie les fichiers CSS/fonts nécessaires
+func (h *Handler) copyStaticAssets() error {
+ publicStaticDir := filepath.Join(h.getPublicDirPath(), "static")
+
+ // Fichiers à copier
+ filesToCopy := []string{
+ "static/theme.css",
+ "static/themes.css",
+ }
+
+ for _, file := range filesToCopy {
+ src := file
+ dst := filepath.Join(publicStaticDir, filepath.Base(file))
+
+ if err := copyFile(src, dst); err != nil {
+ h.logger.Printf("Avertissement: impossible de copier %s: %v", file, err)
+ // Continuer même si la copie échoue
+ }
+ }
+
+ return nil
+}
+
+// copyFile copie un fichier
+func copyFile(src, dst string) error {
+ sourceFile, err := os.Open(src)
+ if err != nil {
+ return err
+ }
+ defer sourceFile.Close()
+
+ destFile, err := os.Create(dst)
+ if err != nil {
+ return err
+ }
+ defer destFile.Close()
+
+ _, err = io.Copy(destFile, sourceFile)
+ return err
+}
+
+// generateNoteHTML génère le fichier HTML pour une note publique
+func (h *Handler) generateNoteHTML(notePath string) error {
+ // Lire le fichier Markdown
+ absPath := filepath.Join(h.notesDir, notePath)
+ content, err := os.ReadFile(absPath)
+ if err != nil {
+ return fmt.Errorf("lecture fichier: %w", err)
+ }
+
+ // Extraire le front matter et le contenu
+ fm, body, err := indexer.ExtractFrontMatterAndBodyFromReader(bytes.NewReader(content))
+ if err != nil {
+ // Continuer avec le contenu complet si erreur
+ body = string(content)
+ }
+
+ // Déterminer le titre
+ title := filepath.Base(notePath)
+ if fm.Title != "" {
+ title = fm.Title
+ } else {
+ title = strings.TrimSuffix(title, ".md")
+ }
+
+ // Convertir Markdown en HTML avec goldmark
+ md := goldmark.New(
+ goldmark.WithExtensions(
+ extension.GFM,
+ extension.Typographer,
+ ),
+ goldmark.WithParserOptions(
+ parser.WithAutoHeadingID(),
+ ),
+ goldmark.WithRendererOptions(
+ html.WithHardWraps(),
+ html.WithXHTML(),
+ ),
+ )
+
+ var buf bytes.Buffer
+ if err := md.Convert([]byte(body), &buf); err != nil {
+ return fmt.Errorf("conversion markdown: %w", err)
+ }
+
+ // Générer le HTML complet standalone
+ htmlContent := h.generateStandaloneHTML(title, buf.String(), fm.Tags, fm.Date)
+
+ // Écrire le fichier HTML - structure plate avec seulement le nom du fichier
+ filename := filepath.Base(notePath)
+ outputPath := filepath.Join(h.getPublicDirPath(), strings.TrimSuffix(filename, ".md")+".html")
+
+ if err := os.WriteFile(outputPath, []byte(htmlContent), 0644); err != nil {
+ return fmt.Errorf("écriture fichier: %w", err)
+ }
+
+ h.logger.Printf("HTML généré: %s", outputPath)
+ return nil
+}
+
+// deleteNoteHTML supprime le fichier HTML d'une note
+func (h *Handler) deleteNoteHTML(notePath string) error {
+ filename := filepath.Base(notePath)
+ outputPath := filepath.Join(h.getPublicDirPath(), strings.TrimSuffix(filename, ".md")+".html")
+
+ if err := os.Remove(outputPath); err != nil && !os.IsNotExist(err) {
+ return err
+ }
+
+ h.logger.Printf("HTML supprimé: %s", outputPath)
+ return nil
+}
+
+// generatePublicIndex génère le fichier index.html avec la liste des notes
+func (h *Handler) generatePublicIndex() error {
+ publicNotes, err := h.loadPublicNotes()
+ if err != nil {
+ return fmt.Errorf("chargement notes publiques: %w", err)
+ }
+
+ // Enrichir avec les métadonnées
+ enrichedNotes := []map[string]interface{}{}
+ for _, note := range publicNotes.Notes {
+ filename := filepath.Base(note.Path)
+ item := map[string]interface{}{
+ "Path": strings.TrimSuffix(filename, ".md") + ".html",
+ "Title": note.Title,
+ "PublishedAt": note.PublishedAt.Format("02/01/2006"),
+ "Tags": []string{},
+ }
+
+ // Essayer de lire le fichier pour obtenir les métadonnées
+ absPath := filepath.Join(h.notesDir, note.Path)
+ if content, err := os.ReadFile(absPath); err == nil {
+ if fm, _, err := indexer.ExtractFrontMatterAndBodyFromReader(bytes.NewReader(content)); err == nil {
+ if fm.Title != "" {
+ item["Title"] = fm.Title
+ }
+ item["Tags"] = fm.Tags
+ }
+ }
+
+ enrichedNotes = append(enrichedNotes, item)
+ }
+
+ // Générer le HTML de l'index
+ htmlContent := h.generateIndexHTML(enrichedNotes)
+
+ // Écrire index.html
+ indexPath := filepath.Join(h.getPublicDirPath(), "index.html")
+ if err := os.WriteFile(indexPath, []byte(htmlContent), 0644); err != nil {
+ return fmt.Errorf("écriture index.html: %w", err)
+ }
+
+ h.logger.Printf("Index généré: %s", indexPath)
+ return nil
+}
+
+// handlePublicList retourne la liste des notes publiques
+func (h *Handler) handlePublicList(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodGet {
+ http.Error(w, "Méthode non autorisée", http.StatusMethodNotAllowed)
+ return
+ }
+
+ publicNotes, err := h.loadPublicNotes()
+ if err != nil {
+ h.logger.Printf("Erreur chargement notes publiques: %v", err)
+ http.Error(w, "Erreur de chargement", http.StatusInternalServerError)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(publicNotes)
+}
+
+// handlePublicToggle bascule le statut public d'une note + génère/supprime HTML
+func (h *Handler) handlePublicToggle(w http.ResponseWriter, r *http.Request) {
+ h.logger.Printf("handlePublicToggle appelé")
+
+ if r.Method != http.MethodPost {
+ h.logger.Printf("Méthode non autorisée: %s", r.Method)
+ http.Error(w, "Méthode non autorisée", http.StatusMethodNotAllowed)
+ return
+ }
+
+ if err := r.ParseForm(); err != nil {
+ h.logger.Printf("Erreur ParseForm: %v", err)
+ http.Error(w, "Formulaire invalide", http.StatusBadRequest)
+ return
+ }
+
+ path := r.FormValue("path")
+ h.logger.Printf("Chemin reçu: %s", path)
+ if path == "" {
+ h.logger.Printf("Chemin vide")
+ http.Error(w, "Chemin requis", http.StatusBadRequest)
+ return
+ }
+
+ // Valider que le fichier existe
+ absPath := filepath.Join(h.notesDir, path)
+ if _, err := os.Stat(absPath); os.IsNotExist(err) {
+ http.Error(w, "Fichier introuvable", http.StatusNotFound)
+ return
+ }
+
+ publicNotes, err := h.loadPublicNotes()
+ if err != nil {
+ h.logger.Printf("Erreur chargement notes publiques: %v", err)
+ http.Error(w, "Erreur de chargement", http.StatusInternalServerError)
+ return
+ }
+
+ // Vérifier si la note est déjà publique
+ isCurrentlyPublic := false
+ newNotes := []PublicNote{}
+ for _, note := range publicNotes.Notes {
+ if note.Path == path {
+ isCurrentlyPublic = true
+ } else {
+ newNotes = append(newNotes, note)
+ }
+ }
+
+ if isCurrentlyPublic {
+ // Retirer du public - supprimer le HTML
+ publicNotes.Notes = newNotes
+
+ if err := h.deleteNoteHTML(path); err != nil {
+ h.logger.Printf("Erreur suppression HTML: %v", err)
+ }
+ } else {
+ // Ajouter au public - générer le HTML
+ title := filepath.Base(path)
+ title = strings.TrimSuffix(title, ".md")
+
+ // Essayer de lire le titre depuis le fichier
+ if content, err := os.ReadFile(absPath); err == nil {
+ if fm, _, err := indexer.ExtractFrontMatterAndBodyFromReader(bytes.NewReader(content)); err == nil && fm.Title != "" {
+ title = fm.Title
+ }
+ }
+
+ newNote := PublicNote{
+ Path: path,
+ Title: title,
+ PublishedAt: time.Now(),
+ }
+ publicNotes.Notes = append(publicNotes.Notes, newNote)
+
+ // Créer les dossiers nécessaires
+ if err := h.ensurePublicDir(); err != nil {
+ h.logger.Printf("Erreur création dossiers: %v", err)
+ http.Error(w, "Erreur de création des dossiers", http.StatusInternalServerError)
+ return
+ }
+
+ // Copier les assets statiques
+ if err := h.copyStaticAssets(); err != nil {
+ h.logger.Printf("Avertissement copie assets: %v", err)
+ }
+
+ // Générer le HTML de la note
+ if err := h.generateNoteHTML(path); err != nil {
+ h.logger.Printf("Erreur génération HTML: %v", err)
+ http.Error(w, "Erreur de génération HTML", http.StatusInternalServerError)
+ return
+ }
+ }
+
+ // Sauvegarder le fichier .public.json
+ if err := h.savePublicNotes(publicNotes); err != nil {
+ h.logger.Printf("Erreur sauvegarde notes publiques: %v", err)
+ http.Error(w, "Erreur de sauvegarde", http.StatusInternalServerError)
+ return
+ }
+
+ // Régénérer l'index
+ if err := h.generatePublicIndex(); err != nil {
+ h.logger.Printf("Erreur génération index: %v", err)
+ }
+
+ // Retourner le nouveau statut
+ status := "private"
+ if !isCurrentlyPublic {
+ status = "public"
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ json.NewEncoder(w).Encode(map[string]string{
+ "status": status,
+ "path": path,
+ })
+}
+
+// generateStandaloneHTML génère un fichier HTML standalone complet
+func (h *Handler) generateStandaloneHTML(title, content string, tags []string, date string) string {
+ tagsHTML := ""
+ if len(tags) > 0 {
+ tagsHTML = ``
+ for _, tag := range tags {
+ tagsHTML += fmt.Sprintf(`#%s `, template.HTMLEscapeString(tag))
+ }
+ tagsHTML += `
`
+ }
+
+ dateHTML := ""
+ if date != "" {
+ dateHTML = fmt.Sprintf(` %s `, template.HTMLEscapeString(date))
+ }
+
+ return fmt.Sprintf(`
+
+
+
+
+ %s - PersoNotes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`, template.HTMLEscapeString(title), template.HTMLEscapeString(title), dateHTML, tagsHTML, content)
+}
+
+// generateIndexHTML génère le HTML de la page d'index
+func (h *Handler) generateIndexHTML(notes []map[string]interface{}) string {
+ notesHTML := ""
+
+ if len(notes) > 0 {
+ notesHTML = ``
+ for _, note := range notes {
+ path, _ := note["Path"].(string)
+ title, _ := note["Title"].(string)
+ publishedAt, _ := note["PublishedAt"].(string)
+ tags := []string{}
+ if tagsInterface, ok := note["Tags"].([]string); ok {
+ tags = tagsInterface
+ }
+
+ tagsHTML := ""
+ if len(tags) > 0 {
+ tagsHTML = ``
+ for _, tag := range tags {
+ tagsHTML += fmt.Sprintf(`#%s `, template.HTMLEscapeString(tag))
+ }
+ tagsHTML += `
`
+ }
+
+ notesHTML += fmt.Sprintf(`
+
+
+ %s
+
+ Published on %s
+
+ %s
+
+ `, path, template.HTMLEscapeString(title), publishedAt, tagsHTML)
+ }
+ notesHTML += ` `
+ } else {
+ notesHTML = `
+
+
+
+
+
+
No public notes yet
+
`
+ }
+
+ return fmt.Sprintf(`
+
+
+
+
+ Public Notes - PersoNotes
+
+
+
+
+
+
+
+
+
+
+
+
+ %s
+
+
+
+`, notesHTML)
+}
diff --git a/locales/en.json b/locales/en.json
index 3721666..9c892e8 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -260,5 +260,25 @@
"nextMonth": "Next month",
"noNote": "No note",
"noteOf": "Note of"
+ },
+ "public": {
+ "buttonPrivate": "Private",
+ "buttonPublic": "Public",
+ "titlePrivate": "This note is private - Click to make it public",
+ "titlePublic": "This note is public - Click to make it private",
+ "listTitle": "Public Notes",
+ "listSubtitle": "Discover my shared notes",
+ "noPublicNotes": "No public notes yet",
+ "publishedOn": "Published on",
+ "backToList": "Back to public notes",
+ "loading": "Loading...",
+ "notificationPublished": "✅ Note published! It is now visible at /public",
+ "notificationUnpublished": "✅ Note removed from public space",
+ "notificationError": "❌ Error changing status"
+ },
+ "publicNotes": {
+ "title": "Public Notes",
+ "editNote": "Edit note",
+ "viewPublic": "View public page"
}
}
diff --git a/locales/fr.json b/locales/fr.json
index 3dc7fcd..37bb488 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -260,5 +260,25 @@
"nextMonth": "Mois suivant",
"noNote": "Pas de note",
"noteOf": "Note du"
+ },
+ "public": {
+ "buttonPrivate": "Privé",
+ "buttonPublic": "Public",
+ "titlePrivate": "Cette note est privée - Cliquer pour la rendre publique",
+ "titlePublic": "Cette note est publique - Cliquer pour la rendre privée",
+ "listTitle": "Notes Publiques",
+ "listSubtitle": "Découvrez mes notes partagées",
+ "noPublicNotes": "Aucune note publique pour le moment",
+ "publishedOn": "Publié le",
+ "backToList": "Retour aux notes publiques",
+ "loading": "Chargement...",
+ "notificationPublished": "✅ Note publiée ! Elle est maintenant visible sur /public",
+ "notificationUnpublished": "✅ Note retirée de l'espace public",
+ "notificationError": "❌ Erreur lors de la modification du statut"
+ },
+ "publicNotes": {
+ "title": "Notes Publiques",
+ "editNote": "Éditer la note",
+ "viewPublic": "Voir la page publique"
}
}
diff --git a/notes/.favorites.json b/notes/.favorites.json
index 838b57e..b9452ee 100644
--- a/notes/.favorites.json
+++ b/notes/.favorites.json
@@ -7,40 +7,61 @@
"added_at": "2025-11-11T13:55:49.371541279+01:00",
"order": 0
},
- {
- "path": "research/design/ui-inspiration.md",
- "is_dir": false,
- "title": "ui-inspiration",
- "added_at": "2025-11-11T14:20:49.985321698+01:00",
- "order": 1
- },
{
"path": "ideas/client-feedback.md",
"is_dir": false,
"title": "client-feedback",
"added_at": "2025-11-11T14:22:16.497953232+01:00",
+ "order": 1
+ },
+ {
+ "path": "personal/learning-goals.md",
+ "is_dir": false,
+ "title": "learning-goals",
+ "added_at": "2025-12-24T13:17:21.123080299+01:00",
"order": 2
},
{
- "path": "ideas/collaboration.md",
- "is_dir": false,
- "title": "collaboration",
- "added_at": "2025-11-11T14:22:18.012032002+01:00",
+ "path": "archive",
+ "is_dir": true,
+ "title": "archive",
+ "added_at": "2025-12-24T15:48:42.323990909+01:00",
"order": 3
},
{
- "path": "ideas/mobile-app.md",
+ "path": "archive/ai-assistant.md",
"is_dir": false,
- "title": "mobile-app",
- "added_at": "2025-11-11T14:22:19.048311608+01:00",
+ "title": "ai-assistant",
+ "added_at": "2025-12-24T15:49:08.265811752+01:00",
"order": 4
},
{
- "path": "documentation/guides",
- "is_dir": true,
- "title": "guides",
- "added_at": "2025-11-12T18:18:20.53353467+01:00",
+ "path": "meetings/2025/sprint-planning.md",
+ "is_dir": false,
+ "title": "sprint-planning",
+ "added_at": "2025-12-24T15:55:04.58786532+01:00",
"order": 5
+ },
+ {
+ "path": "meetings",
+ "is_dir": true,
+ "title": "meetings",
+ "added_at": "2025-12-24T15:56:40.332077313+01:00",
+ "order": 6
+ },
+ {
+ "path": "Myfolder.txt",
+ "is_dir": true,
+ "title": "Myfolder.txt",
+ "added_at": "2025-12-24T15:57:09.512148418+01:00",
+ "order": 7
+ },
+ {
+ "path": "projets",
+ "is_dir": true,
+ "title": "projets",
+ "added_at": "2025-12-24T15:59:24.938636283+01:00",
+ "order": 8
}
]
}
\ No newline at end of file
diff --git a/notes/.public.json b/notes/.public.json
new file mode 100644
index 0000000..aefcbaf
--- /dev/null
+++ b/notes/.public.json
@@ -0,0 +1,29 @@
+{
+ "notes": [
+ {
+ "path": "ideas/collaboration.md",
+ "title": "Real-time Collaboration",
+ "published_at": "2025-12-24T12:40:15.778895438+01:00"
+ },
+ {
+ "path": "daily/2025/11/11.md",
+ "title": "Daily Note - 2025-11-11",
+ "published_at": "2025-12-24T12:38:12.77519956+01:00"
+ },
+ {
+ "path": "ideas/mobile-app.md",
+ "title": "Native Mobile App",
+ "published_at": "2025-12-24T12:37:20.649319402+01:00"
+ },
+ {
+ "path": "tasks/backlog.md",
+ "title": "Product Backlog",
+ "published_at": "2025-11-13T20:13:05.36334514+01:00"
+ },
+ {
+ "path": "documentation/api/endpoints.md",
+ "title": "API Endpoints Reference",
+ "published_at": "2025-11-13T19:36:57.522466752+01:00"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/notes/projets/backend/api-design.md b/notes/Myfolder.txt/api-design.md
similarity index 100%
rename from notes/projets/backend/api-design.md
rename to notes/Myfolder.txt/api-design.md
diff --git a/notes/daily/2025/12/24.md b/notes/daily/2025/12/24.md
new file mode 100644
index 0000000..3fe4554
--- /dev/null
+++ b/notes/daily/2025/12/24.md
@@ -0,0 +1,25 @@
+---
+title: Daily Note - 2025-12-24
+date: 24-12-2025
+last_modified: 24-12-2025:12:36
+tags:
+ - daily
+---
+
+# 📅 Mercredi 24 Décembre 2025
+
+## 🎯 Objectifs du jour
+-
+
+
+## 📝 Notes
+-
+
+## ✅ Accompli
+-
+
+## 💭 Réflexions
+-
+
+## 🔗 Liens
+-
diff --git a/notes/ideas/mobile-app.md b/notes/meetings/2025/mobile-app.md
similarity index 100%
rename from notes/ideas/mobile-app.md
rename to notes/meetings/2025/mobile-app.md
diff --git a/notes/projets/frontend/codemirror-integration.md b/notes/projets/backend/codemirror-integration.md
similarity index 100%
rename from notes/projets/frontend/codemirror-integration.md
rename to notes/projets/backend/codemirror-integration.md
diff --git a/notes/tasks/backlog.md b/notes/projets/mobile/backlog.md
similarity index 100%
rename from notes/tasks/backlog.md
rename to notes/projets/mobile/backlog.md
diff --git a/public/11.html b/public/11.html
new file mode 100644
index 0000000..6dc0d5f
--- /dev/null
+++ b/public/11.html
@@ -0,0 +1,95 @@
+
+
+
+
+
+ Daily Note - 2025-11-11 - PersoNotes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
📅 Mardi 11 novembre 2025
+
🎯 Objectifs du jour
+
+
📝 Notes
+
+
✅ Accompli
+
+
💭 Réflexions
+
+
🔗 Liens
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/backlog.html b/public/backlog.html
new file mode 100644
index 0000000..9b4a5b7
--- /dev/null
+++ b/public/backlog.html
@@ -0,0 +1,95 @@
+
+
+
+
+
+ Product Backlog - PersoNotes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Product Backlog
+
High Priority
+
+
Medium Priority
+
+
Low Priority
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/collaboration.html b/public/collaboration.html
new file mode 100644
index 0000000..8c2dac9
--- /dev/null
+++ b/public/collaboration.html
@@ -0,0 +1,89 @@
+
+
+
+
+
+ Real-time Collaboration - PersoNotes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Real-time Collaboration
+
Goal
+
Plusieurs utilisateurs éditent la même note simultanément.
+
Technology
+
+WebSockets
+Operational Transforms ou CRDT
+Presence indicators
+
+
Challenges
+
+Conflict resolution
+Performance at scale
+User permissions
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 0000000..a1e6a68
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,92 @@
+
+
+
+
+
+ Public Notes - PersoNotes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/mobile-app.html b/public/mobile-app.html
new file mode 100644
index 0000000..213eda1
--- /dev/null
+++ b/public/mobile-app.html
@@ -0,0 +1,93 @@
+
+
+
+
+
+ Native Mobile App - PersoNotes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Native Mobile App Idea
+
Concept
+
Créer une app native iOS/Android pour l’édition de notes.
+
Tech Stack
+
+React Native ou Flutter
+Sync avec l’API REST
+Offline-first architecture
+
+
Features
+
+Push notifications
+Widget home screen
+Voice notes
+Photo attachments
+
+
Timeline
+
Q2 2025 - Prototype
+Q3 2025 - Beta testing
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/notes/personal/learning-goals.html b/public/notes/personal/learning-goals.html
new file mode 100644
index 0000000..c1a63db
--- /dev/null
+++ b/public/notes/personal/learning-goals.html
@@ -0,0 +1,94 @@
+
+
+
+
+
+ 2025 Learning Goals - PersoNotes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Learning Goals 2025
+
Technical
+
+
Soft Skills
+
+
Books to Read
+
+Designing Data-Intensive Applications
+The Pragmatic Programmer
+Clean Architecture
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/static/theme.css b/public/static/theme.css
new file mode 100644
index 0000000..4990527
--- /dev/null
+++ b/public/static/theme.css
@@ -0,0 +1,3643 @@
+/*
+ * PersoNotes - Material Darker Theme
+ * Inspired by Material Design with dark palette
+ */
+
+:root {
+ /* Colors - Material Dark Theme (Professional) */
+ --bg-primary: #1e1e1e;
+ --bg-secondary: #252525;
+ --bg-tertiary: #2d2d2d;
+ --bg-elevated: #323232;
+
+ --border-primary: #3e3e3e;
+ --border-secondary: #2a2a2a;
+
+ --text-primary: #e0e0e0;
+ --text-secondary: #b0b0b0;
+ --text-muted: #6e6e6e;
+
+ /* Accent colors - Blue focused */
+ --accent-primary: #42a5f5;
+ --accent-primary-hover: #64b5f6;
+ --accent-secondary: #29b6f6;
+ --accent-secondary-hover: #4fc3f7;
+
+ /* Semantic colors */
+ --success: #66bb6a;
+ --warning: #ffa726;
+ --error: #ef5350;
+
+ /* Spacing */
+ --spacing-xs: 0.25rem;
+ --spacing-sm: 0.5rem;
+ --spacing-md: 1rem;
+ --spacing-lg: 1.5rem;
+ --spacing-xl: 2rem;
+
+ /* Sidebar compact spacing */
+ --sidebar-item-gap: 0.05rem;
+ --sidebar-padding-v: 0.3rem;
+ --sidebar-padding-h: 0.75rem;
+ --sidebar-indent: 1rem;
+
+ /* Shadows */
+ --shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.4);
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -2px rgba(0, 0, 0, 0.3);
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -4px rgba(0, 0, 0, 0.3);
+ --shadow-glow: 0 0 20px rgba(66, 165, 245, 0.2);
+
+ /* Border radius */
+ --radius-sm: 4px;
+ --radius-md: 6px;
+ --radius-lg: 8px;
+
+ /* Transitions */
+ --transition-fast: 150ms ease;
+ --transition-normal: 250ms ease;
+}
+
+/* Base styles */
+html {
+ font-size: 16px;
+ background: var(--bg-primary);
+}
+
+body {
+ background: var(--bg-primary);
+ color: var(--text-primary);
+ margin: 0;
+ font-family: 'JetBrainsMono Nerd Font', 'JetBrains Mono', 'Fira Code', 'Monaco', 'Consolas', monospace;
+ line-height: 1.6;
+}
+
+/* Header */
+header {
+ background: var(--bg-secondary);
+ border-bottom: 1px solid var(--border-primary);
+ padding: var(--spacing-md) var(--spacing-lg);
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-md);
+ box-shadow: var(--shadow-sm);
+ position: sticky;
+ top: 0;
+ z-index: 100;
+}
+
+header h1 {
+ margin: 0;
+ font-size: 1.25rem;
+ font-weight: 600;
+ color: var(--text-primary);
+ background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+/* Search input */
+input[type="search"] {
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-primary);
+ color: var(--text-primary);
+ border-radius: var(--radius-md);
+ padding: var(--spacing-sm) var(--spacing-md);
+ font-size: 0.9rem;
+ transition: all var(--transition-fast);
+}
+
+input[type="search"]:focus {
+ outline: none;
+ border-color: var(--accent-primary);
+ box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.1);
+ background: var(--bg-elevated);
+}
+
+input[type="search"]::placeholder {
+ color: var(--text-muted);
+}
+
+/* Main layout */
+.main-layout {
+ position: relative;
+ height: calc(100vh - 65px);
+ overflow-x: hidden;
+}
+
+/* Sidebar */
+aside {
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ width: 300px;
+ min-width: 200px;
+ max-width: 600px;
+ transform: translateX(0);
+ transition: transform 0.25s ease;
+ z-index: 10;
+ background: var(--bg-secondary);
+ border-right: 1px solid var(--border-primary);
+ padding: var(--spacing-md);
+ overflow-y: auto;
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-md);
+}
+
+/* Resize handle for sidebar */
+.sidebar-resize-handle {
+ position: absolute;
+ top: 0;
+ right: -6px; /* Overlap for easier grab */
+ bottom: 0;
+ width: 16px; /* Even wider for Firefox */
+ cursor: col-resize;
+ background: rgba(66, 165, 245, 0.05);
+ border-left: 2px solid transparent;
+ border-right: 2px solid transparent;
+ transition: all 0.2s ease;
+ z-index: 11;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.sidebar-resize-handle:hover {
+ background: rgba(66, 165, 245, 0.15);
+ border-left-color: var(--accent-primary);
+ border-right-color: var(--accent-primary);
+}
+
+.sidebar-resize-handle.resizing {
+ background: rgba(66, 165, 245, 0.25);
+ border-left: 3px solid var(--accent-primary);
+ border-right: 3px solid var(--accent-primary);
+}
+
+/* Visual indicator - always visible */
+.sidebar-resize-handle::before {
+ content: '⋮';
+ font-size: 18px;
+ color: var(--accent-primary);
+ opacity: 0.5;
+ transition: all 0.2s ease;
+ pointer-events: none;
+}
+
+.sidebar-resize-handle:hover::before {
+ opacity: 1;
+ text-shadow: 0 0 4px var(--accent-primary);
+}
+
+aside::-webkit-scrollbar {
+ width: 8px;
+}
+
+aside::-webkit-scrollbar-track {
+ background: var(--bg-secondary);
+}
+
+aside::-webkit-scrollbar-thumb {
+ background: var(--border-primary);
+ border-radius: 4px;
+}
+
+aside::-webkit-scrollbar-thumb:hover {
+ background: var(--text-muted);
+}
+
+/* Titres de section de la sidebar */
+aside h2,
+.sidebar-section-title {
+ font-size: 0.95rem;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ color: var(--text-secondary);
+ margin: 0 0 var(--spacing-sm) 0;
+}
+
+/* Sections rétractables de la sidebar */
+.sidebar-section-header {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.5rem 0;
+ user-select: none;
+ transition: opacity var(--transition-fast);
+}
+
+.sidebar-section-header:hover {
+ opacity: 0.8;
+}
+
+.section-toggle {
+ font-size: 0.75rem;
+ color: var(--text-secondary);
+ display: inline-block;
+ transition: transform var(--transition-fast);
+ width: 1rem;
+ text-align: center;
+}
+
+.section-toggle.expanded {
+ transform: rotate(90deg);
+}
+
+.sidebar-section-content {
+ overflow: hidden;
+ transition: opacity var(--transition-fast);
+}
+
+aside hr {
+ border: none;
+ border-top: 1px solid var(--border-primary);
+ margin: var(--spacing-sm) 0;
+}
+
+/* File tree and search results */
+#file-tree a,
+#search-results a {
+ display: block;
+ padding: var(--spacing-sm) var(--spacing-md);
+ color: var(--text-primary);
+ text-decoration: none;
+ border-radius: var(--radius-sm);
+ transition: all var(--transition-fast);
+ font-size: 0.9rem;
+ margin-bottom: var(--spacing-xs);
+}
+
+#file-tree a:hover,
+#search-results a:hover {
+ background: var(--bg-tertiary);
+ color: var(--accent-primary);
+ transform: translateX(2px);
+}
+
+/* Search results header */
+.search-results-header {
+ padding: var(--spacing-sm) 0;
+ margin-bottom: var(--spacing-sm);
+ border-bottom: 1px solid var(--border-secondary);
+}
+
+.search-results-count {
+ font-size: 0.85rem;
+ color: var(--text-secondary);
+ font-weight: 500;
+}
+
+/* Search results list */
+.search-results-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-sm);
+}
+
+.search-result-item {
+ margin: 0;
+}
+
+.search-result-link {
+ display: flex;
+ align-items: flex-start;
+ gap: var(--spacing-md);
+ background: var(--bg-tertiary);
+ border: 1px solid transparent;
+ border-radius: var(--radius-md);
+ padding: var(--spacing-md);
+ text-decoration: none;
+ color: var(--text-primary);
+ transition: transform var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast);
+}
+
+.search-result-link:hover {
+ transform: translateY(-1px);
+ border-color: var(--accent-primary);
+ box-shadow: var(--shadow-sm);
+}
+
+.search-result-icon {
+ font-size: 1.5rem;
+ flex-shrink: 0;
+ opacity: 0.7;
+ line-height: 1;
+}
+
+.search-result-content {
+ flex: 1;
+ min-width: 0;
+}
+
+.search-result-header {
+ margin-bottom: var(--spacing-xs);
+}
+
+.search-result-title {
+ font-weight: 600;
+ font-size: 0.95rem;
+ color: var(--text-primary);
+}
+
+.search-result-path {
+ font-size: 0.7rem;
+ color: var(--text-muted);
+ font-family: 'Fira Code', 'Cascadia Code', 'Consolas', monospace;
+ margin-bottom: var(--spacing-xs);
+}
+
+.search-result-snippet {
+ margin: var(--spacing-xs) 0;
+ font-size: 0.85rem;
+ color: var(--text-secondary);
+ line-height: 1.5;
+}
+
+.search-result-footer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: var(--spacing-sm);
+ margin-top: var(--spacing-sm);
+ flex-wrap: wrap;
+}
+
+.search-result-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--spacing-xs);
+}
+
+.search-result-date {
+ font-size: 0.7rem;
+ color: var(--text-muted);
+ white-space: nowrap;
+}
+
+.tag-pill {
+ background: rgba(130, 170, 255, 0.15);
+ color: var(--accent-primary);
+ border: 1px solid rgba(130, 170, 255, 0.3);
+ border-radius: 999px;
+ padding: 0 var(--spacing-sm);
+ font-size: 0.7rem;
+ line-height: 1.6;
+ font-family: 'Fira Code', 'Cascadia Code', 'Consolas', monospace;
+ font-weight: 500;
+}
+
+/* No results message */
+.search-no-results {
+ text-align: center;
+ padding: var(--spacing-xl) var(--spacing-md);
+ color: var(--text-secondary);
+}
+
+.search-no-results-icon {
+ font-size: 3rem;
+ margin-bottom: var(--spacing-md);
+ opacity: 0.5;
+}
+
+.search-no-results-text {
+ font-size: 0.95rem;
+ margin-bottom: var(--spacing-sm);
+}
+
+.search-no-results-text strong {
+ color: var(--accent-secondary);
+}
+
+.search-no-results-hint {
+ font-size: 0.85rem;
+ color: var(--text-muted);
+}
+
+/* Search help */
+.search-help {
+ padding: var(--spacing-md);
+}
+
+.search-help-title {
+ font-size: 0.95rem;
+ font-weight: 600;
+ color: var(--accent-primary);
+ margin-bottom: var(--spacing-xs);
+}
+
+.search-help-text {
+ font-size: 0.85rem;
+ color: var(--text-secondary);
+ margin-bottom: var(--spacing-md);
+}
+
+.search-help-examples {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-sm);
+}
+
+.search-help-example {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+ padding: var(--spacing-sm);
+ background: var(--bg-tertiary);
+ border-radius: var(--radius-sm);
+ border: 1px solid var(--border-secondary);
+}
+
+.search-help-example code {
+ background: var(--bg-primary);
+ color: var(--accent-secondary);
+ padding: 0.2rem 0.4rem;
+ border-radius: var(--radius-sm);
+ font-size: 0.8rem;
+ font-family: 'Fira Code', 'Cascadia Code', 'Consolas', monospace;
+ font-weight: 500;
+ min-width: 110px;
+}
+
+.search-help-example span {
+ font-size: 0.8rem;
+ color: var(--text-secondary);
+}
+
+/* Main content */
+main {
+ margin-left: 300px;
+ transition: margin-left 0.25s ease;
+ background: var(--bg-primary);
+ padding: var(--spacing-xl);
+ overflow-y: auto;
+ height: 100%;
+}
+
+main::-webkit-scrollbar {
+ width: 10px;
+}
+
+main::-webkit-scrollbar-track {
+ background: var(--bg-primary);
+}
+
+main::-webkit-scrollbar-thumb {
+ background: var(--border-primary);
+ border-radius: 5px;
+}
+
+main::-webkit-scrollbar-thumb:hover {
+ background: var(--text-muted);
+}
+
+/* Editor */
+.editor-form {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-lg);
+}
+
+.editor-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.editor-header label {
+ font-size: 0.95rem;
+ color: var(--text-secondary);
+}
+
+.toggle-preview-btn {
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-primary);
+ color: var(--text-primary);
+ padding: var(--spacing-sm) var(--spacing-md);
+ border-radius: var(--radius-sm);
+ font-size: 0.85rem;
+ cursor: pointer;
+ transition: all var(--transition-fast);
+ white-space: nowrap;
+}
+
+.toggle-preview-btn:hover {
+ background: var(--bg-elevated);
+ border-color: var(--accent-primary);
+ color: var(--accent-primary);
+ transform: translateY(-1px);
+ box-shadow: var(--shadow-sm);
+}
+
+.editor-grid {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
+ gap: var(--spacing-lg);
+ min-height: 70vh;
+ transition: grid-template-columns var(--transition-normal);
+}
+
+/* Mode: Éditeur seul */
+.editor-grid.preview-hidden {
+ grid-template-columns: 1fr;
+}
+
+.editor-grid.preview-hidden #preview {
+ display: none !important;
+}
+
+/* Mode: Preview seule */
+.editor-grid.editor-hidden {
+ grid-template-columns: 1fr;
+}
+
+.editor-grid.editor-hidden .editor-panel {
+ display: none !important;
+}
+
+/* Mode: Split (défaut) */
+.editor-grid.split-view {
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
+}
+
+.editor-grid.split-view .editor-panel,
+.editor-grid.split-view #preview {
+ display: block !important;
+}
+
+.editor-panel {
+ position: relative;
+}
+
+#editor {
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ color: var(--text-primary);
+ padding: var(--spacing-md);
+ font-family: 'Fira Code', 'Cascadia Code', 'Consolas', 'Monaco', monospace;
+ font-size: 0.95rem;
+ line-height: 1.6;
+ min-height: 75vh;
+ width: 100%;
+ resize: vertical;
+ transition: border-color var(--transition-fast);
+}
+
+#editor:focus {
+ outline: none;
+ border-color: var(--accent-primary);
+ box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.1);
+}
+
+/* CodeMirror integration */
+.CodeMirror {
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ color: var(--text-primary);
+ font-family: 'Fira Code', 'Cascadia Code', 'Consolas', 'Monaco', monospace;
+ font-size: 0.95rem;
+ line-height: 1.6;
+ height: calc(100vh - 180px);
+ transition: border-color var(--transition-fast);
+}
+
+/* Cacher le textarea original quand CodeMirror est actif */
+.editor-panel textarea#editor {
+ display: none !important;
+ position: absolute !important;
+ visibility: hidden !important;
+ opacity: 0 !important;
+ pointer-events: none !important;
+ height: 0 !important;
+ width: 0 !important;
+}
+
+.editor-panel .CodeMirror ~ textarea {
+ display: none !important;
+ position: absolute !important;
+ visibility: hidden !important;
+ opacity: 0 !important;
+ pointer-events: none !important;
+ height: 0 !important;
+ width: 0 !important;
+}
+
+.CodeMirror-focused {
+ outline: none;
+ border-color: var(--accent-primary);
+ box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.1);
+}
+
+.CodeMirror-gutters {
+ background: var(--bg-tertiary);
+ border-right: 1px solid var(--border-primary);
+}
+
+.CodeMirror-linenumber {
+ color: var(--text-muted);
+}
+
+.CodeMirror-cursor {
+ border-left: 2px solid var(--accent-primary);
+}
+
+.CodeMirror-selected {
+ background: rgba(88, 166, 255, 0.2);
+}
+
+.CodeMirror-line::selection,
+.CodeMirror-line > span::selection,
+.CodeMirror-line > span > span::selection {
+ background: rgba(88, 166, 255, 0.2);
+}
+
+.editor-actions {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: var(--spacing-md);
+}
+
+.editor-actions-primary {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--spacing-sm);
+}
+
+.save-status {
+ color: var(--text-secondary);
+ min-height: 1.25rem;
+ display: inline-flex;
+ align-items: center;
+}
+
+/* Preview */
+.preview {
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ padding: 2rem 3rem;
+ overflow-y: auto;
+ max-height: calc(100vh - 180px);
+ height: calc(100vh - 180px);
+}
+
+.markdown-preview {
+ min-height: 75vh;
+ box-shadow: inset 0 0 0 1px rgba(88, 166, 255, 0.05);
+}
+
+.markdown-preview::-webkit-scrollbar {
+ width: 8px;
+}
+
+.markdown-preview::-webkit-scrollbar-thumb {
+ background: var(--border-primary);
+ border-radius: 4px;
+}
+
+.preview h1, .preview h2, .preview h3, .preview h4, .preview h5, .preview h6 {
+ font-weight: 600;
+ margin-top: 0;
+ margin-bottom: 0.8em;
+ line-height: 1.4;
+}
+
+.preview h1 {
+ font-size: 2em;
+ color: var(--accent-primary);
+ border-bottom: 1px solid var(--border-primary);
+ padding-bottom: 0.3em;
+ margin-bottom: 1em;
+}
+
+.preview h2 {
+ font-size: 1.5em;
+ color: var(--accent-secondary);
+ margin-bottom: 0.9em;
+}
+
+.preview h3 {
+ font-size: 1.25em;
+ color: var(--text-primary);
+}
+
+.preview h4 {
+ font-size: 1.1em;
+ color: var(--text-secondary);
+}
+
+.preview h5 {
+ font-size: 1em;
+ color: var(--text-secondary);
+}
+
+.preview h6 {
+ font-size: 1em;
+ color: var(--text-muted);
+}
+
+.preview p {
+ margin-top: 0;
+ margin-bottom: 1em;
+ line-height: 1.6;
+}
+
+.preview p:last-child {
+ margin-bottom: 0;
+}
+
+.preview ul, .preview ol {
+ margin-top: 0;
+ margin-bottom: 1em;
+ padding-left: 2em;
+}
+
+.preview li {
+ margin-top: 0.3em;
+ margin-bottom: 0.3em;
+ line-height: 1.5;
+}
+
+.preview ul > li::marker {
+ color: var(--accent-primary);
+}
+
+.preview ol > li::marker {
+ color: var(--accent-secondary);
+ font-weight: 600;
+}
+
+.preview blockquote {
+ margin: 0 0 1em 0;
+ padding-left: 1.5em;
+ border-left: 4px solid var(--accent-primary);
+ color: var(--text-secondary);
+ font-style: italic;
+}
+
+.preview hr {
+ margin: 1.5em 0;
+ border: none;
+ border-top: 1px solid var(--border-primary);
+}
+
+.preview a {
+ color: var(--accent-primary);
+ text-decoration: none;
+ font-weight: 500;
+}
+
+.preview a:hover {
+ text-decoration: underline;
+ color: var(--accent-primary-hover);
+}
+
+.preview strong, .preview b {
+ color: var(--text-primary);
+ font-weight: 600;
+}
+
+.preview em, .preview i {
+ color: var(--text-secondary);
+ font-style: italic;
+}
+
+.preview code {
+ background: var(--bg-tertiary);
+ padding: 0.2em 0.4em;
+ border-radius: var(--radius-sm);
+ font-size: 0.85em;
+ color: var(--accent-secondary);
+ font-weight: 500;
+}
+
+.preview pre {
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ padding: var(--spacing-md);
+ overflow-x: auto;
+ margin: 0 0 1em 0;
+ line-height: 1.5;
+}
+
+.preview pre code {
+ background: none;
+ padding: 0;
+ color: var(--text-primary);
+}
+
+.preview blockquote {
+ border-left: 3px solid var(--accent-primary);
+ padding-left: var(--spacing-md);
+ margin-left: 0;
+ color: var(--text-secondary);
+ font-style: italic;
+}
+
+.preview table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 1em 0;
+ background: var(--bg-tertiary);
+ border-radius: var(--radius-md);
+ overflow: hidden;
+}
+
+.preview table thead {
+ background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+}
+
+.preview table thead th {
+ color: white;
+ font-weight: 600;
+ text-align: left;
+ padding: var(--spacing-md);
+ border: none;
+}
+
+.preview table tbody tr {
+ border-bottom: 1px solid var(--border-primary);
+ transition: background var(--transition-fast);
+}
+
+.preview table tbody tr:last-child {
+ border-bottom: none;
+}
+
+.preview table tbody tr:hover {
+ background: var(--bg-secondary);
+}
+
+.preview table td {
+ padding: var(--spacing-md);
+ border: none;
+ color: var(--text-primary);
+}
+
+.preview table tbody td {
+ border-right: 1px solid var(--border-primary);
+}
+
+.preview table tbody td:last-child {
+ border-right: none;
+}
+
+/* Buttons */
+button,
+[type="submit"],
+[type="button"] {
+ background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ color: white;
+ border: none;
+ border-radius: var(--radius-md);
+ padding: var(--spacing-sm) var(--spacing-lg);
+ font-size: 0.9rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all var(--transition-fast);
+ box-shadow: var(--shadow-sm);
+}
+
+button:hover,
+[type="submit"]:hover,
+[type="button"]:hover {
+ transform: translateY(-1px);
+ box-shadow: var(--shadow-md), var(--shadow-glow);
+}
+
+button:active,
+[type="submit"]:active,
+[type="button"]:active {
+ transform: translateY(0);
+}
+
+button.secondary {
+ background: var(--bg-tertiary);
+ color: var(--text-primary);
+ border: 1px solid var(--border-primary);
+}
+
+button.secondary:hover {
+ background: var(--bg-elevated);
+ border-color: var(--accent-primary);
+ box-shadow: var(--shadow-sm);
+}
+
+/* Slash command palette */
+#slash-commands-palette {
+ background: var(--bg-secondary);
+ border: 1px solid var(--accent-primary);
+ border-radius: var(--radius-lg);
+ box-shadow: var(--shadow-lg), var(--shadow-glow);
+ padding: var(--spacing-xs);
+ min-width: 220px;
+ max-height: 320px;
+ overflow-y: auto;
+}
+
+#slash-commands-palette::-webkit-scrollbar {
+ width: 6px;
+}
+
+#slash-commands-palette::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+#slash-commands-palette::-webkit-scrollbar-thumb {
+ background: var(--border-primary);
+ border-radius: 3px;
+}
+
+#slash-commands-palette li {
+ padding: var(--spacing-sm) var(--spacing-md);
+ cursor: pointer;
+ color: var(--text-primary);
+ transition: all var(--transition-fast);
+ border-radius: var(--radius-sm);
+ margin: var(--spacing-xs) 0;
+ font-size: 0.9rem;
+ font-family: 'Fira Code', 'Cascadia Code', 'Consolas', monospace;
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+}
+
+#slash-commands-palette li::before {
+ content: '⌘';
+ color: var(--text-muted);
+ font-size: 0.85em;
+}
+
+#slash-commands-palette li:hover {
+ background: var(--bg-tertiary);
+ color: var(--accent-primary);
+ transform: translateX(2px);
+}
+
+#slash-commands-palette li[style*="background-color"] {
+ background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary)) !important;
+ color: white !important;
+ font-weight: 500;
+ transform: translateX(2px);
+}
+
+#slash-commands-palette li[style*="background-color"]::before {
+ color: rgba(255, 255, 255, 0.8);
+}
+
+/* Labels */
+label {
+ color: var(--text-secondary);
+ font-size: 0.9rem;
+ font-weight: 500;
+ margin-bottom: var(--spacing-sm);
+ display: block;
+}
+
+/* Progress indicator */
+progress {
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-sm);
+}
+
+progress::-webkit-progress-bar {
+ background: var(--bg-tertiary);
+ border-radius: var(--radius-sm);
+}
+
+progress::-webkit-progress-value {
+ background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
+ border-radius: var(--radius-sm);
+}
+
+/* CSS Reset */
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+/* Form elements base styles */
+input, textarea, select {
+ font-family: inherit;
+ font-size: inherit;
+}
+
+/* Remove default form margins */
+form {
+ margin: 0;
+}
+
+/* Ensure flex containers work properly */
+body, html {
+ margin: 0;
+ padding: 0;
+ height: 100%;
+ width: 100%;
+}
+
+/* Modal styles */
+#new-note-modal,
+#new-folder-modal {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 9999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.modal-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: rgba(0, 0, 0, 0.7);
+ backdrop-filter: blur(4px);
+ animation: fadeIn 0.2s ease;
+}
+
+.modal-content {
+ position: relative;
+ background: var(--bg-secondary);
+ border: 1px solid var(--accent-primary);
+ border-radius: var(--radius-lg);
+ padding: var(--spacing-lg);
+ min-width: 350px;
+ max-width: 90%;
+ box-shadow: var(--shadow-lg), var(--shadow-glow);
+ animation: slideUp 0.3s ease;
+ z-index: 1;
+}
+
+.modal-content h2 {
+ margin: 0 0 var(--spacing-md) 0;
+ color: var(--text-primary);
+ font-size: 1.2rem;
+}
+
+.modal-content label {
+ display: block;
+ margin-bottom: var(--spacing-xs);
+ color: var(--text-secondary);
+ font-weight: 500;
+ font-size: 0.9rem;
+}
+
+.modal-content input[type="text"] {
+ width: 100%;
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-primary);
+ color: var(--text-primary);
+ border-radius: var(--radius-md);
+ padding: var(--spacing-sm) var(--spacing-md);
+ font-size: 0.95rem;
+ transition: all var(--transition-fast);
+}
+
+.modal-content input[type="text"]:focus {
+ outline: none;
+ border-color: var(--accent-primary);
+ box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.1);
+}
+
+.modal-content p {
+ font-size: 0.8rem;
+ margin-top: 0.25rem;
+ margin-bottom: 0;
+}
+
+.modal-content form > div {
+ margin-top: 1rem !important;
+}
+
+.modal-content button {
+ padding: var(--spacing-sm) var(--spacing-md);
+ font-size: 0.9rem;
+}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+@keyframes slideUp {
+ from {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+/* File tree hierarchical styles */
+#file-tree {
+ font-size: 0.9rem;
+}
+
+.folder-item {
+ margin: var(--sidebar-item-gap) 0;
+}
+
+.folder-header {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-xs);
+ padding: var(--sidebar-padding-v) var(--sidebar-padding-h);
+ cursor: pointer;
+ border-radius: var(--radius-sm);
+ transition: all var(--transition-fast);
+ user-select: none;
+ font-size: 0.875rem;
+}
+
+.folder-header:hover {
+ background: var(--bg-tertiary);
+ color: var(--accent-primary);
+}
+
+.folder-toggle {
+ display: inline-block;
+ font-size: 0.65rem;
+ transition: transform var(--transition-fast);
+ min-width: 10px;
+}
+
+.folder-toggle.expanded {
+ transform: rotate(90deg);
+}
+
+.folder-icon {
+ font-size: 0.95rem;
+}
+
+.folder-name {
+ flex: 1;
+ font-weight: 500;
+}
+
+.folder-children {
+ padding-left: var(--sidebar-indent);
+ overflow: hidden;
+ transition: all var(--transition-fast);
+}
+
+.file-item {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-xs);
+ padding: var(--sidebar-padding-v) var(--sidebar-padding-h);
+ color: var(--text-primary);
+ text-decoration: none;
+ border-radius: var(--radius-sm);
+ transition: all var(--transition-fast);
+ font-size: 0.85rem;
+ margin: var(--sidebar-item-gap) 0;
+ cursor: pointer;
+}
+
+.file-item:hover {
+ background: var(--bg-tertiary);
+ color: var(--accent-primary);
+ transform: translateX(2px);
+}
+
+/* Drag and drop styles */
+.file-item.dragging {
+ opacity: 0.4;
+ background: var(--bg-tertiary);
+ cursor: grabbing;
+}
+
+.folder-header.dragging {
+ opacity: 0.4;
+ background: var(--bg-tertiary);
+ cursor: grabbing;
+}
+
+.folder-item.drag-over .folder-header {
+ background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ color: white;
+ box-shadow: var(--shadow-glow);
+ border: 2px solid var(--accent-primary);
+ border-radius: var(--radius-md);
+ animation: pulse 1s ease-in-out infinite;
+}
+
+@keyframes pulse {
+ 0%, 100% {
+ transform: scale(1);
+ box-shadow: var(--shadow-glow);
+ }
+ 50% {
+ transform: scale(1.02);
+ box-shadow: 0 0 30px rgba(88, 166, 255, 0.4);
+ }
+}
+
+.file-item.drag-over {
+ background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ color: white;
+ box-shadow: var(--shadow-glow);
+}
+
+/* Style pour la racine en drag-over */
+.sidebar-section-header.drag-over {
+ background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary)) !important;
+ color: white !important;
+ box-shadow: var(--shadow-glow);
+ border: 2px solid var(--accent-primary);
+ border-radius: var(--radius-md);
+ animation: pulse 1s ease-in-out infinite;
+}
+
+.sidebar-section-header.drag-over .folder-name,
+.sidebar-section-header.drag-over .root-hint,
+.sidebar-section-header.drag-over .folder-icon {
+ color: white !important;
+}
+
+/* Indicateur de destination pendant le drag */
+.drag-destination-indicator {
+ position: fixed;
+ bottom: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ background: var(--bg-secondary);
+ border: 2px solid var(--accent-primary);
+ border-radius: var(--radius-lg);
+ padding: var(--spacing-md) var(--spacing-lg);
+ box-shadow: var(--shadow-lg), var(--shadow-glow);
+ z-index: 10000;
+ display: none;
+ align-items: center;
+ gap: var(--spacing-md);
+ min-width: 300px;
+ animation: slideUp 0.3s ease;
+}
+
+.drag-destination-indicator .indicator-icon {
+ font-size: 1.5rem;
+ flex-shrink: 0;
+}
+
+.drag-destination-indicator .indicator-text {
+ color: var(--text-primary);
+ font-size: 0.95rem;
+ flex: 1;
+}
+
+.drag-destination-indicator .indicator-text strong {
+ color: var(--accent-primary);
+ font-weight: 600;
+}
+
+.drag-destination-indicator .indicator-path {
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ font-family: 'Fira Code', 'Cascadia Code', monospace;
+ padding: 2px 6px;
+ background: var(--bg-tertiary);
+ border-radius: var(--radius-sm);
+ border: 1px solid var(--border-primary);
+}
+
+/* Curseur pendant le drag */
+.folder-header[draggable="true"] {
+ cursor: grab;
+}
+
+.folder-header[draggable="true"]:active {
+ cursor: grabbing;
+}
+
+/* Zone de drop racine */
+/* Indicateur de racine (non cliquable) */
+.root-indicator {
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ padding: var(--spacing-sm) var(--spacing-md);
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ cursor: default;
+ user-select: none;
+ margin-bottom: 0.5rem;
+}
+
+.root-indicator .folder-icon {
+ font-size: 1.1rem;
+ opacity: 0.8;
+}
+
+.root-indicator .folder-name {
+ font-weight: 500;
+ color: var(--text-secondary);
+ font-size: 0.85rem;
+}
+
+.root-indicator .root-hint {
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ font-family: 'Fira Code', 'Cascadia Code', monospace;
+ margin-left: auto;
+}
+
+/* Styles pour root-drop-zone conservés pour la compatibilité drag & drop */
+.root-drop-zone {
+ margin-bottom: 0.5rem;
+}
+
+.root-folder-header {
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ padding: var(--spacing-sm) var(--spacing-md) !important;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ cursor: default !important; /* Pas draggable */
+ transition: all var(--transition-fast);
+ user-select: none;
+}
+
+.root-folder-header .folder-icon {
+ font-size: 1.1rem;
+}
+
+.root-folder-header .folder-name {
+ font-weight: 600;
+ color: var(--text-primary);
+ font-size: 0.9rem;
+}
+
+.root-folder-header .root-hint {
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ font-family: 'Fira Code', 'Cascadia Code', monospace;
+ margin-left: auto;
+}
+
+/* Quand on drag au-dessus de la racine */
+.root-drop-zone.drag-over .root-folder-header {
+ background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ color: white;
+ border-color: var(--accent-primary);
+ box-shadow: var(--shadow-glow);
+ animation: pulse 1s ease-in-out infinite;
+}
+
+.root-drop-zone.drag-over .root-folder-header .folder-name,
+.root-drop-zone.drag-over .root-folder-header .root-hint {
+ color: white;
+}
+
+/* Sidebar toggle styles */
+.main-layout.sidebar-hidden aside {
+ transform: translateX(-100%);
+}
+
+.main-layout.sidebar-hidden main {
+ margin-left: 0;
+}
+
+.auto-save-status {
+ margin-left: 1rem;
+ font-size: 0.8rem;
+ color: var(--text-muted);
+ font-style: italic;
+}
+
+/* Utility class to hide elements */
+.hidden {
+ display: none !important;
+}
+
+/* Bouton de fermeture sidebar - caché par défaut (desktop) */
+.sidebar-close-btn {
+ display: none;
+}
+
+/* ========================================
+ STYLES POUR L'ARBORESCENCE DE NOTES
+ ======================================== */
+
+.note-tree {
+ width: 100%;
+ max-width: 100%;
+ box-sizing: border-box;
+}
+
+.folder, .file {
+ width: 100%;
+ max-width: 100%;
+ box-sizing: border-box;
+ overflow: hidden;
+}
+
+.folder-header {
+ cursor: pointer;
+ user-select: none;
+ padding: 0.4rem 0;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ transition: all var(--transition-fast);
+}
+
+.folder-header:hover {
+ color: var(--accent-primary);
+}
+
+.folder-icon {
+ flex-shrink: 0;
+}
+
+.folder-content {
+ display: block;
+}
+
+.file {
+ padding: 0.3rem 0;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.file-icon {
+ flex-shrink: 0;
+ opacity: 0.6;
+ transition: opacity var(--transition-fast);
+}
+
+.file a {
+ color: var(--text-primary);
+ text-decoration: none;
+ cursor: pointer;
+ word-break: break-word;
+ flex: 1;
+ font-size: 0.95rem;
+ transition: color var(--transition-fast);
+}
+
+.file a:hover {
+ color: var(--accent-primary);
+}
+
+.file:hover .file-icon {
+ opacity: 1;
+}
+
+/* Indentation levels - Desktop */
+.indent-level-1 { padding-left: 0; }
+.indent-level-2 { padding-left: 0.5rem; }
+.indent-level-3 { padding-left: 1rem; }
+.indent-level-4 { padding-left: 1.5rem; }
+.indent-level-5 { padding-left: 2rem; }
+.indent-level-6 { padding-left: 2.5rem; }
+.indent-level-7 { padding-left: 3rem; }
+.indent-level-8 { padding-left: 3.5rem; }
+
+/* ========================================
+ RESPONSIVE DESIGN - Mobile & Tablet
+ ======================================== */
+
+/* Tablettes et petits écrans (max 768px) */
+@media screen and (max-width: 768px) {
+ /* Empêcher tout débordement horizontal */
+ html, body {
+ overflow-x: hidden;
+ max-width: 100vw;
+ }
+
+ body {
+ position: relative;
+ }
+
+ /* Tous les éléments doivent respecter la largeur */
+ * {
+ max-width: 100%;
+ }
+
+ /* Header responsive */
+ header {
+ flex-wrap: wrap;
+ padding: 0.75rem;
+ gap: 0.5rem;
+ width: 100%;
+ box-sizing: border-box;
+ }
+
+ header h1 {
+ font-size: 1.2rem;
+ margin: 0;
+ }
+
+ header input[type="search"] {
+ max-width: 100%;
+ flex: 1 1 100%;
+ order: 10;
+ }
+
+ header button {
+ padding: 0.4rem 0.8rem;
+ font-size: 0.85rem;
+ }
+
+ /* Main layout en colonne pour mobile */
+ .main-layout {
+ flex-direction: column;
+ width: 100%;
+ max-width: 100vw;
+ overflow-x: hidden;
+ }
+
+ /* Sidebar masquée par défaut sur mobile */
+ aside {
+ position: fixed;
+ top: 0;
+ left: -280px;
+ width: 280px !important; /* Force width on mobile, ignore resize */
+ min-width: 280px;
+ max-width: 280px;
+ height: 100vh;
+ z-index: 1000;
+ transition: left 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ overflow-y: auto;
+ overflow-x: hidden;
+ box-shadow: var(--shadow-lg);
+ background: var(--bg-primary);
+ }
+
+ /* Hide resize handle on mobile */
+ .sidebar-resize-handle {
+ display: none;
+ }
+
+ aside.sidebar-visible {
+ left: 0;
+ }
+
+ /* Overlay pour fermer la sidebar */
+ .sidebar-overlay {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.6);
+ z-index: 999;
+ cursor: pointer;
+ -webkit-tap-highlight-color: transparent;
+ }
+
+ .sidebar-overlay.active {
+ display: block;
+ animation: fadeIn 0.3s ease;
+ }
+
+ @keyframes fadeIn {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+ }
+
+ /* Main content prend toute la largeur */
+ main {
+ margin-left: 0 !important;
+ width: 100%;
+ max-width: 100vw;
+ padding: 1rem;
+ box-sizing: border-box;
+ overflow-x: hidden;
+ }
+
+ #editor-container,
+ #main-content {
+ width: 100%;
+ max-width: 100%;
+ box-sizing: border-box;
+ overflow-x: hidden;
+ }
+
+ /* Editor grid en colonne sur mobile */
+ .editor-grid {
+ grid-template-columns: 1fr !important;
+ gap: 0;
+ width: 100%;
+ max-width: 100%;
+ box-sizing: border-box;
+ }
+
+ .editor-panel,
+ .editor-form {
+ width: 100%;
+ max-width: 100%;
+ box-sizing: border-box;
+ overflow-x: hidden;
+ }
+
+ /* Forcer la preview seule visible par défaut sur mobile */
+ .editor-grid.mobile-preview-only .editor-panel {
+ display: none !important;
+ }
+
+ /* Ajuster les tailles de police */
+ body {
+ font-size: 14px;
+ }
+
+ /* Modales en plein écran sur mobile */
+ .modal-content {
+ width: 95%;
+ max-width: 95%;
+ margin: 1rem;
+ }
+
+ /* Boutons d'action en colonne */
+ .editor-actions-primary {
+ flex-direction: column;
+ gap: 0.5rem;
+ }
+
+ .editor-actions-primary button {
+ width: 100%;
+ }
+
+ /* Toggle preview button plus visible */
+ .toggle-preview-btn {
+ min-width: auto;
+ }
+
+ /* File tree compact */
+ #file-tree {
+ font-size: 0.9rem;
+ }
+
+ /* Réduire le padding des sections sidebar */
+ aside section {
+ padding: 0.75rem;
+ }
+
+ /* Preview prend tout l'espace et est centré */
+ .preview {
+ min-height: 60vh;
+ padding: 0.75rem;
+ max-width: 100%;
+ width: 100%;
+ margin: 0 auto;
+ box-sizing: border-box;
+ overflow-x: auto;
+ word-wrap: break-word;
+ overflow-wrap: break-word;
+ }
+
+ /* S'assurer que le contenu du preview ne déborde pas */
+ .preview * {
+ max-width: 100%;
+ box-sizing: border-box;
+ }
+
+ .preview pre {
+ overflow-x: auto;
+ max-width: 100%;
+ }
+
+ .preview table {
+ display: block;
+ overflow-x: auto;
+ max-width: 100%;
+ }
+
+ .preview img {
+ max-width: 100%;
+ height: auto;
+ }
+
+ .preview code {
+ word-break: break-all;
+ }
+
+ /* Centrer le contenu de la page d'accueil sur mobile */
+ .note-tree {
+ max-width: 100%;
+ width: 100%;
+ padding: 0.5rem;
+ box-sizing: border-box;
+ overflow-x: hidden;
+ }
+
+ .note-tree * {
+ max-width: 100%;
+ box-sizing: border-box;
+ }
+
+ /* Indentation réduite sur mobile pour éviter les débordements */
+ .indent-level-1 { padding-left: 0 !important; }
+ .indent-level-2 { padding-left: 0.75rem !important; }
+ .indent-level-3 { padding-left: 1.5rem !important; }
+ .indent-level-4 { padding-left: 2.25rem !important; }
+ .indent-level-5 { padding-left: 3rem !important; }
+ .indent-level-6 { padding-left: 3.5rem !important; }
+ .indent-level-7 { padding-left: 4rem !important; }
+ .indent-level-8 { padding-left: 4.5rem !important; }
+
+ /* Les dossiers et fichiers */
+ .folder,
+ .file {
+ max-width: 100%;
+ overflow: hidden;
+ padding-top: 0.3rem !important;
+ padding-bottom: 0.3rem !important;
+ }
+
+ .folder-header {
+ max-width: 100%;
+ overflow: hidden;
+ padding: 0.3rem 0 !important;
+ font-size: 0.9rem;
+ }
+
+ .file {
+ font-size: 0.9rem;
+ }
+
+ .file-icon,
+ .folder-icon {
+ font-size: 1rem;
+ }
+
+ /* Améliorer la sidebar sur mobile */
+ aside {
+ padding-top: 1rem;
+ }
+
+ /* Bouton de fermeture dans le menu mobile */
+ .sidebar-close-btn {
+ display: block;
+ position: sticky;
+ top: 0;
+ right: 0;
+ background: var(--bg-tertiary);
+ border: none;
+ color: var(--text-primary);
+ font-size: 1.5rem;
+ padding: 0.5rem;
+ cursor: pointer;
+ width: 100%;
+ text-align: right;
+ z-index: 10;
+ margin-bottom: 1rem;
+ }
+
+ /* CodeMirror ajusté pour mobile */
+ .CodeMirror,
+ .cm-editor {
+ font-size: 14px;
+ max-width: 100%;
+ width: 100%;
+ box-sizing: border-box;
+ }
+
+ .cm-scroller {
+ overflow-x: auto;
+ max-width: 100%;
+ }
+
+ /* Accordéon de dossiers plus compact */
+ .folder-header {
+ padding: 0.4rem 0 !important;
+ font-size: 0.9rem;
+ }
+
+ .file {
+ padding: 0.3rem 0 !important;
+ font-size: 0.9rem;
+ }
+}
+
+/* Smartphones en mode portrait (max 480px) */
+@media screen and (max-width: 480px) {
+ /* Encore plus strict sur les débordements */
+ html, body {
+ overflow-x: hidden;
+ max-width: 100vw;
+ width: 100vw;
+ }
+
+ header h1 {
+ font-size: 1rem;
+ }
+
+ header button {
+ padding: 0.3rem 0.6rem;
+ font-size: 0.8rem;
+ }
+
+ aside {
+ width: 100%;
+ left: -100%;
+ }
+
+ .modal-content {
+ width: 100%;
+ height: 100vh;
+ margin: 0;
+ border-radius: 0;
+ }
+
+ body {
+ font-size: 13px;
+ }
+
+ /* Réduire encore plus les marges */
+ main {
+ padding: 0.25rem;
+ }
+
+ .preview {
+ padding: 0.5rem;
+ }
+
+ /* Centrage parfait pour très petits écrans */
+ #editor-container {
+ padding: 0;
+ }
+
+ .note-tree {
+ padding: 0.25rem;
+ }
+
+ /* Texte plus petit si nécessaire */
+ .folder-header,
+ .file {
+ font-size: 0.85rem;
+ }
+
+ /* Adapter la modale de recherche sur mobile */
+ .search-modal-container {
+ width: 100%;
+ max-width: 100%;
+ margin: 0;
+ border-radius: 0;
+ max-height: 100vh;
+ }
+
+ .search-modal-input {
+ font-size: 14px;
+ }
+
+ .search-modal-results {
+ max-height: calc(100vh - 200px);
+ }
+}
+
+/* ==========================================================================
+ Search Modal Styles
+ ========================================================================== */
+
+.search-modal {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 10000;
+ align-items: flex-start;
+ justify-content: center;
+ padding-top: 10vh;
+ opacity: 0;
+ transition: opacity 200ms ease;
+}
+
+.search-modal.active {
+ opacity: 1;
+}
+
+.search-modal-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.7);
+ backdrop-filter: blur(4px);
+}
+
+.search-modal-container {
+ position: relative;
+ width: 90%;
+ max-width: 680px;
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-lg);
+ box-shadow: var(--shadow-lg), var(--shadow-glow);
+ display: flex;
+ flex-direction: column;
+ max-height: 70vh;
+ transform: translateY(-20px);
+ transition: transform 200ms ease;
+}
+
+.search-modal.active .search-modal-container {
+ transform: translateY(0);
+}
+
+/* Header */
+.search-modal-header {
+ padding: var(--spacing-md);
+ border-bottom: 1px solid var(--border-primary);
+}
+
+.search-modal-input-wrapper {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+}
+
+.search-modal-icon {
+ color: var(--text-muted);
+ flex-shrink: 0;
+}
+
+.search-modal-input {
+ flex: 1;
+ background: transparent;
+ border: none;
+ color: var(--text-primary);
+ font-size: 16px;
+ outline: none;
+ padding: var(--spacing-sm) 0;
+}
+
+.search-modal-input::placeholder {
+ color: var(--text-muted);
+}
+
+.search-modal-kbd {
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-sm);
+ padding: 2px 6px;
+ font-size: 11px;
+ font-family: monospace;
+ color: var(--text-muted);
+ flex-shrink: 0;
+}
+
+/* Body */
+.search-modal-body {
+ flex: 1;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+}
+
+.search-modal-results {
+ flex: 1;
+ overflow-y: auto;
+ padding: var(--spacing-sm);
+}
+
+/* Results Header */
+.search-modal-results-header {
+ padding: var(--spacing-sm) var(--spacing-md);
+ color: var(--text-muted);
+ font-size: 0.85rem;
+}
+
+.search-modal-results-count {
+ font-weight: 500;
+}
+
+/* Result Item */
+.search-modal-result-item {
+ display: flex;
+ gap: var(--spacing-md);
+ padding: var(--spacing-md);
+ margin: var(--spacing-xs) 0;
+ border-radius: var(--radius-md);
+ cursor: pointer;
+ transition: all var(--transition-fast);
+ border: 1px solid transparent;
+}
+
+.search-modal-result-item:hover {
+ background: var(--bg-tertiary);
+}
+
+.search-modal-result-item.selected {
+ background: linear-gradient(135deg, rgba(130, 170, 255, 0.15), rgba(199, 146, 234, 0.15));
+ border-color: var(--accent-primary);
+}
+
+.search-modal-result-icon {
+ font-size: 1.5rem;
+ flex-shrink: 0;
+}
+
+.search-modal-result-content {
+ flex: 1;
+ min-width: 0;
+}
+
+.search-modal-result-title {
+ font-weight: 500;
+ color: var(--text-primary);
+ margin-bottom: 4px;
+}
+
+.search-modal-result-title mark {
+ background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ color: white;
+ padding: 2px 4px;
+ border-radius: 3px;
+ font-weight: 600;
+}
+
+.search-modal-result-path {
+ font-size: 0.8rem;
+ color: var(--text-muted);
+ margin-bottom: 6px;
+}
+
+.search-modal-result-snippet {
+ font-size: 0.85rem;
+ color: var(--text-secondary);
+ margin-bottom: 8px;
+ line-height: 1.5;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+
+.search-modal-result-snippet mark {
+ background: rgba(130, 170, 255, 0.3);
+ color: var(--accent-primary);
+ padding: 2px 4px;
+ border-radius: 3px;
+ font-weight: 500;
+}
+
+.search-modal-result-footer {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-md);
+ flex-wrap: wrap;
+}
+
+.search-modal-result-tags {
+ display: flex;
+ gap: var(--spacing-xs);
+ flex-wrap: wrap;
+}
+
+.search-modal-result-tags .tag-pill {
+ background: var(--bg-tertiary);
+ color: var(--accent-primary);
+ border: 1px solid var(--border-primary);
+ padding: 2px 8px;
+ border-radius: 12px;
+ font-size: 0.75rem;
+ font-weight: 500;
+}
+
+.search-modal-result-date {
+ font-size: 0.75rem;
+ color: var(--text-muted);
+}
+
+/* Help */
+.search-modal-help {
+ padding: var(--spacing-lg);
+ text-align: center;
+}
+
+.search-modal-help-title {
+ font-size: 1.1rem;
+ font-weight: 500;
+ color: var(--text-primary);
+ margin-bottom: var(--spacing-lg);
+}
+
+.search-modal-help-items {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: var(--spacing-md);
+}
+
+.search-modal-help-item {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-xs);
+ padding: var(--spacing-md);
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ transition: all var(--transition-fast);
+}
+
+.search-modal-help-item:hover {
+ border-color: var(--accent-primary);
+ transform: translateY(-2px);
+}
+
+.search-modal-help-item code {
+ background: var(--bg-primary);
+ color: var(--accent-primary);
+ padding: 4px 8px;
+ border-radius: var(--radius-sm);
+ font-size: 0.9rem;
+ font-family: 'Fira Code', 'Cascadia Code', monospace;
+ border: 1px solid var(--border-primary);
+}
+
+.search-modal-help-item span {
+ font-size: 0.85rem;
+ color: var(--text-muted);
+}
+
+/* Loading */
+.search-modal-loading {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: var(--spacing-xl);
+ gap: var(--spacing-md);
+}
+
+.search-modal-spinner {
+ width: 40px;
+ height: 40px;
+ border: 3px solid var(--border-primary);
+ border-top-color: var(--accent-primary);
+ border-radius: 50%;
+ animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+ to { transform: rotate(360deg); }
+}
+
+.search-modal-loading p {
+ color: var(--text-muted);
+ margin: 0;
+}
+
+/* No Results */
+.search-modal-no-results {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: var(--spacing-xl);
+ text-align: center;
+}
+
+.search-modal-no-results-icon {
+ font-size: 3rem;
+ margin-bottom: var(--spacing-md);
+ opacity: 0.5;
+}
+
+.search-modal-no-results-text {
+ color: var(--text-primary);
+ margin: 0 0 var(--spacing-sm) 0;
+}
+
+.search-modal-no-results-hint {
+ color: var(--text-muted);
+ font-size: 0.9rem;
+ margin: 0;
+}
+
+/* Error */
+.search-modal-error {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: var(--spacing-xl);
+ text-align: center;
+}
+
+.search-modal-error-icon {
+ font-size: 3rem;
+ margin-bottom: var(--spacing-md);
+}
+
+.search-modal-error p {
+ color: var(--error);
+ margin: 0;
+}
+
+/* Footer */
+.search-modal-footer {
+ border-top: 1px solid var(--border-primary);
+ padding: var(--spacing-sm) var(--spacing-md);
+ background: var(--bg-tertiary);
+}
+
+.search-modal-footer-hint {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+ font-size: 0.8rem;
+ color: var(--text-muted);
+}
+
+.search-modal-footer-hint kbd {
+ background: var(--bg-primary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-sm);
+ padding: 2px 6px;
+ font-size: 11px;
+ font-family: monospace;
+ color: var(--text-secondary);
+}
+
+/* Scrollbar pour les résultats */
+.search-modal-results::-webkit-scrollbar {
+ width: 8px;
+}
+
+.search-modal-results::-webkit-scrollbar-track {
+ background: var(--bg-secondary);
+}
+
+.search-modal-results::-webkit-scrollbar-thumb {
+ background: var(--border-primary);
+ border-radius: 4px;
+}
+
+.search-modal-results::-webkit-scrollbar-thumb:hover {
+ background: var(--text-muted);
+}
+
+/* ==========================================================================
+ Tags Cloud (Home Page)
+ ========================================================================== */
+
+.tags-cloud {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ padding: 12px 0;
+ margin: 12px 0 24px 0;
+ max-height: 150px;
+ overflow-y: auto;
+ line-height: 1.4;
+ border-bottom: 1px solid var(--border-primary);
+}
+
+.tag-item {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ padding: 3px 8px;
+ background: transparent;
+ border: 1px solid var(--border-primary);
+ border-radius: 4px;
+ text-decoration: none;
+ font-size: 0.8rem;
+ transition: all var(--transition-fast);
+ cursor: pointer;
+}
+
+.tag-item:hover {
+ background: var(--bg-tertiary);
+ border-color: var(--accent-primary);
+}
+
+.tag-item:active {
+ transform: scale(0.98);
+}
+
+/* Badge style pour le tag (kbd) - version discrète */
+.tag-badge {
+ background: transparent;
+ color: var(--text-secondary);
+ padding: 0;
+ font-family: inherit;
+ font-size: 1em;
+ font-weight: 500;
+ border: none;
+ box-shadow: none;
+}
+
+.tag-item:hover .tag-badge {
+ color: var(--accent-primary);
+}
+
+/* Badge count style (mark) - version discrète */
+.tag-count {
+ background: transparent;
+ color: var(--text-muted);
+ padding: 0;
+ border-radius: 0;
+ font-size: 0.9em;
+ font-weight: 400;
+ border: none;
+ min-width: auto;
+}
+
+.tag-item:hover .tag-count {
+ color: var(--text-secondary);
+}
+
+
+/* Scrollbar pour le nuage de tags */
+.tags-cloud::-webkit-scrollbar {
+ width: 6px;
+ height: 6px;
+}
+
+.tags-cloud::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+.tags-cloud::-webkit-scrollbar-thumb {
+ background: var(--border-primary);
+ border-radius: 3px;
+}
+
+.tags-cloud::-webkit-scrollbar-thumb:hover {
+ background: var(--text-muted);
+}
+
+/* Responsive */
+@media (max-width: 768px) {
+ .tags-cloud {
+ gap: 4px;
+ max-height: 120px;
+ }
+
+ .tag-item {
+ font-size: 0.75rem;
+ padding: 2px 6px;
+ }
+}
+
+/* ==========================================================================
+ SECTION FAVORIS SUR LA PAGE D'ACCUEIL
+ ========================================================================== */
+
+/* Les favoris utilisent les mêmes styles que note-tree */
+.favorites-tree {
+ /* Hérite des styles de .note-tree */
+ margin-bottom: 24px;
+ border-bottom: 1px solid var(--border-primary);
+ padding-bottom: 12px;
+ max-height: 400px;
+ overflow-y: auto;
+ overflow-x: hidden;
+}
+
+/* Scrollbar pour la liste des favoris */
+.favorites-tree::-webkit-scrollbar {
+ width: 8px;
+}
+
+.favorites-tree::-webkit-scrollbar-track {
+ background: var(--bg-tertiary);
+ border-radius: 4px;
+}
+
+.favorites-tree::-webkit-scrollbar-thumb {
+ background: var(--border-primary);
+ border-radius: 4px;
+}
+
+.favorites-tree::-webkit-scrollbar-thumb:hover {
+ background: var(--text-muted);
+}
+
+/* Responsive */
+@media (max-width: 768px) {
+ .favorites-tree {
+ font-size: 0.9rem;
+ max-height: 300px;
+ }
+}
+
+/* ==========================================================================
+ Daily Notes Calendar & Recent
+ ========================================================================== */
+
+/* Calendar Container */
+.daily-calendar {
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ padding: var(--spacing-md);
+ margin-bottom: var(--spacing-md);
+}
+
+/* Calendar Header (Navigation) */
+.daily-calendar-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: var(--spacing-md);
+ padding-bottom: var(--spacing-sm);
+ border-bottom: 1px solid var(--border-primary);
+}
+
+.calendar-month-year {
+ font-weight: 600;
+ font-size: 0.95rem;
+ color: var(--text-primary);
+}
+
+.calendar-nav-btn {
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-primary);
+ color: var(--text-primary);
+ padding: 0.25rem 0.5rem;
+ border-radius: var(--radius-sm);
+ cursor: pointer;
+ font-size: 1.2rem;
+ transition: all var(--transition-fast);
+ line-height: 1;
+}
+
+.calendar-nav-btn:hover {
+ background: var(--bg-elevated);
+ border-color: var(--accent-primary);
+ color: var(--accent-primary);
+ transform: translateY(-1px);
+}
+
+/* Calendar Grid */
+.calendar-grid {
+ display: grid;
+ grid-template-columns: repeat(7, 1fr);
+ gap: 2px;
+}
+
+/* Weekday Headers */
+.calendar-weekday-header {
+ text-align: center;
+ font-size: 0.75rem;
+ font-weight: 600;
+ color: var(--text-secondary);
+ padding: 0.5rem 0;
+ text-transform: uppercase;
+}
+
+/* Calendar Day Cells */
+.calendar-day {
+ aspect-ratio: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ background: var(--bg-tertiary);
+ border-radius: var(--radius-sm);
+ cursor: default;
+ transition: all var(--transition-fast);
+ position: relative;
+ border: 2px solid transparent;
+ font-size: 0.85rem;
+}
+
+/* Clickable days (with notes) */
+.calendar-day-clickable {
+ cursor: pointer;
+}
+
+.calendar-day-clickable:hover {
+ background: var(--bg-elevated);
+ border-color: var(--accent-primary);
+ transform: scale(1.05);
+}
+
+/* Days without notes */
+.calendar-day-no-note {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+.calendar-day-no-note .calendar-day-number {
+ color: var(--text-muted);
+}
+
+/* Day Number */
+.calendar-day-number {
+ font-weight: 500;
+ color: var(--text-primary);
+}
+
+/* Indicator for notes */
+.calendar-day-indicator {
+ position: absolute;
+ bottom: 2px;
+ font-size: 0.5rem;
+ color: var(--accent-primary);
+}
+
+/* Today */
+.calendar-day-today {
+ border-color: var(--accent-secondary);
+ background: linear-gradient(135deg, rgba(130, 170, 255, 0.1), rgba(199, 146, 234, 0.1));
+}
+
+.calendar-day-today .calendar-day-number {
+ color: var(--accent-secondary);
+ font-weight: 700;
+}
+
+/* Has Note */
+.calendar-day-has-note {
+ font-weight: 600;
+}
+
+.calendar-day-has-note .calendar-day-number {
+ color: var(--accent-primary);
+}
+
+/* Other Month Days (grayed out) */
+.calendar-day-other-month {
+ opacity: 0.3;
+ cursor: default;
+ pointer-events: none;
+}
+
+/* Today Button */
+.daily-today-btn {
+ width: 100%;
+ margin-top: var(--spacing-sm);
+ padding: var(--spacing-sm);
+ background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ color: white;
+ border: none;
+ border-radius: var(--radius-md);
+ font-size: 0.85rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all var(--transition-fast);
+}
+
+.daily-today-btn:hover {
+ transform: translateY(-1px);
+ box-shadow: var(--shadow-md), var(--shadow-glow);
+}
+
+/* Recent Notes List */
+.daily-recent {
+ display: flex;
+ flex-direction: column;
+ gap: 0.15rem;
+}
+
+.daily-recent-item {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+ padding: 0.4rem 0.6rem;
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-sm);
+ text-decoration: none;
+ color: var(--text-primary);
+ transition: all var(--transition-fast);
+ cursor: pointer;
+}
+
+.daily-recent-item:hover {
+ background: var(--bg-elevated);
+ border-color: var(--accent-primary);
+ transform: translateX(2px);
+}
+
+.daily-recent-icon {
+ font-size: 0.9rem;
+ flex-shrink: 0;
+}
+
+.daily-recent-content {
+ display: flex;
+ flex-direction: column;
+ gap: 0.05rem;
+ flex: 1;
+}
+
+.daily-recent-weekday {
+ font-size: 0.65rem;
+ color: var(--text-muted);
+ text-transform: uppercase;
+ font-weight: 600;
+ letter-spacing: 0.02em;
+}
+
+.daily-recent-title {
+ font-size: 0.8rem;
+ color: var(--text-primary);
+ font-weight: 500;
+}
+
+/* Selection Mode - Suppression en masse */
+
+/* Checkboxes de sélection */
+.selection-checkbox {
+ margin-right: var(--spacing-sm);
+ width: 18px;
+ height: 18px;
+ cursor: pointer;
+ accent-color: var(--accent-primary);
+ flex-shrink: 0;
+}
+
+/* Wrapper pour les fichiers avec checkbox */
+.file-item-wrapper {
+ display: flex;
+ align-items: center;
+ padding: 0;
+ margin: var(--sidebar-item-gap) 0;
+}
+
+.file-item-wrapper .file-item {
+ flex: 1;
+}
+
+/* Bouton de mode sélection */
+.icon-button {
+ background: transparent;
+ border: 1px solid transparent;
+ color: var(--text-muted);
+ cursor: pointer;
+ padding: var(--spacing-xs);
+ border-radius: var(--radius-sm);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all var(--transition-fast);
+}
+
+.icon-button:hover {
+ background: var(--bg-tertiary);
+ border-color: var(--border-primary);
+ color: var(--text-primary);
+}
+
+.icon-button.active {
+ background: var(--accent-primary);
+ border-color: var(--accent-primary);
+ color: var(--bg-primary);
+}
+
+.icon-button.active:hover {
+ background: var(--accent-primary-hover);
+ border-color: var(--accent-primary-hover);
+}
+
+/* Toolbar de sélection flottante */
+.selection-toolbar {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: var(--bg-elevated);
+ border-top: 2px solid var(--accent-primary);
+ padding: var(--spacing-md) var(--spacing-lg);
+ box-shadow: var(--shadow-lg);
+ z-index: 1000;
+ animation: slideUp 0.3s ease;
+}
+
+@keyframes slideUp {
+ from {
+ transform: translateY(100%);
+ opacity: 0;
+ }
+ to {
+ transform: translateY(0);
+ opacity: 1;
+ }
+}
+
+.toolbar-content {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ max-width: 1200px;
+ margin: 0 auto;
+}
+
+.selection-count {
+ font-size: 1rem;
+ font-weight: 600;
+ color: var(--text-primary);
+}
+
+.toolbar-actions {
+ display: flex;
+ gap: var(--spacing-md);
+}
+
+/* Bouton danger */
+.danger-button {
+ background: var(--error);
+ border: 1px solid var(--error);
+ color: var(--bg-primary);
+ padding: var(--spacing-sm) var(--spacing-md);
+ border-radius: var(--radius-md);
+ font-size: 0.9rem;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all var(--transition-fast);
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+ white-space: nowrap;
+}
+
+.danger-button:hover {
+ background: #ff5370;
+ border-color: #ff5370;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(240, 113, 120, 0.4);
+}
+
+.danger-button:active {
+ transform: translateY(0);
+}
+
+/* Modale de confirmation de suppression */
+#delete-confirmation-modal {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 9999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+#delete-confirmation-modal h2 {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+}
+
+#delete-items-list code {
+ background: var(--bg-secondary);
+ padding: 0.2rem 0.5rem;
+ border-radius: var(--radius-sm);
+ font-size: 0.85rem;
+ color: var(--text-secondary);
+}
+
+/* Responsive */
+@media (max-width: 768px) {
+ .daily-calendar {
+ padding: var(--spacing-sm);
+ }
+
+ .calendar-day {
+ font-size: 0.75rem;
+ }
+
+ .calendar-day-indicator {
+ font-size: 0.4rem;
+ }
+
+ .daily-recent-item {
+ padding: var(--spacing-xs) var(--spacing-sm);
+ }
+
+ /* Toolbar responsive */
+ .selection-toolbar {
+ padding: var(--spacing-sm) var(--spacing-md);
+ }
+
+ .toolbar-content {
+ flex-direction: column;
+ gap: var(--spacing-sm);
+ }
+
+ .toolbar-actions {
+ width: 100%;
+ justify-content: space-between;
+ }
+
+ .selection-count {
+ font-size: 0.9rem;
+ }
+}
+
+/* ===========================
+ FAVORIS
+ =========================== */
+
+/* Container des favoris avec scrolling */
+#favorites-list {
+ max-height: 300px;
+ overflow-y: auto;
+ overflow-x: hidden;
+ margin-bottom: var(--spacing-xs);
+ display: flex;
+ flex-direction: column;
+ gap: 0.1rem;
+}
+
+/* Scrollbar pour la liste des favoris */
+#favorites-list::-webkit-scrollbar {
+ width: 6px;
+}
+
+#favorites-list::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+#favorites-list::-webkit-scrollbar-thumb {
+ background: var(--border-primary);
+ border-radius: 3px;
+}
+
+#favorites-list::-webkit-scrollbar-thumb:hover {
+ background: var(--text-muted);
+}
+
+.favorite-item {
+ position: relative;
+}
+
+.favorite-folder,
+.favorite-file {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-xs);
+ padding: var(--sidebar-padding-v) var(--sidebar-padding-h);
+ border-radius: var(--radius-sm);
+ transition: all var(--transition-fast);
+ font-size: 0.85rem;
+ cursor: pointer;
+ text-decoration: none;
+ color: var(--text-primary);
+ position: relative;
+}
+
+.favorite-folder:hover,
+.favorite-file:hover {
+ background: var(--bg-tertiary);
+ color: var(--accent-primary);
+ transform: translateX(2px);
+}
+
+.favorite-icon {
+ font-size: 0.9rem;
+ color: var(--warning);
+ flex-shrink: 0;
+}
+
+.favorite-folder-icon,
+.favorite-file-icon {
+ font-size: 0.9rem;
+ flex-shrink: 0;
+}
+
+.favorite-name {
+ flex: 1;
+ font-weight: 500;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.favorite-remove {
+ opacity: 0;
+ background: var(--error);
+ color: white;
+ border: none;
+ border-radius: 50%;
+ width: 18px;
+ height: 18px;
+ font-size: 1rem;
+ line-height: 1;
+ cursor: pointer;
+ transition: all var(--transition-fast);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0;
+ flex-shrink: 0;
+}
+
+.favorite-folder:hover .favorite-remove,
+.favorite-file:hover .favorite-remove {
+ opacity: 1;
+}
+
+.favorite-remove:hover {
+ background: #d32f2f;
+ transform: scale(1.1);
+}
+
+.favorites-empty {
+ text-align: center;
+ color: var(--text-muted);
+ font-size: 0.85rem;
+ padding: var(--spacing-md);
+ line-height: 1.5;
+}
+
+/* Bouton d'ajout aux favoris (dans le file tree) */
+.add-to-favorites {
+ opacity: 0;
+ background: transparent;
+ border: none;
+ color: var(--text-muted);
+ cursor: pointer;
+ font-size: 0.9rem;
+ padding: 0 0.2rem;
+ transition: all var(--transition-fast);
+ margin-left: auto;
+}
+
+.folder-header:hover .add-to-favorites,
+.file-item:hover .add-to-favorites {
+ opacity: 1;
+}
+
+.add-to-favorites:hover {
+ color: var(--warning);
+ transform: scale(1.2);
+}
+
+.add-to-favorites.is-favorite {
+ opacity: 1;
+ color: var(--warning);
+}
+
+/* Responsive - Hauteurs adaptatives pour #favorites-list */
+@media screen and (max-height: 800px) {
+ #favorites-list {
+ max-height: 200px;
+ }
+}
+
+@media screen and (min-height: 801px) and (max-height: 1000px) {
+ #favorites-list {
+ max-height: 300px;
+ }
+}
+
+@media screen and (min-height: 1001px) {
+ #favorites-list {
+ max-height: 400px;
+ }
+}
+
+/* Mobile - hauteur encore plus réduite */
+@media screen and (max-width: 768px) {
+ #favorites-list {
+ max-height: 180px;
+ }
+}
+
+/* ==========================================================================
+ Link Inserter Modal Styles
+ ========================================================================== */
+
+.link-inserter-modal {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 10000;
+ align-items: flex-start;
+ justify-content: center;
+ padding-top: 15vh;
+ opacity: 0;
+ transition: opacity 200ms ease;
+}
+
+.link-inserter-modal.active {
+ opacity: 1;
+}
+
+.link-inserter-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.6);
+ backdrop-filter: blur(3px);
+}
+
+.link-inserter-container {
+ position: relative;
+ width: 90%;
+ max-width: 560px;
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-lg);
+ box-shadow: var(--shadow-lg), var(--shadow-glow);
+ display: flex;
+ flex-direction: column;
+ max-height: 60vh;
+ transform: translateY(-20px);
+ transition: transform 200ms ease;
+}
+
+.link-inserter-modal.active .link-inserter-container {
+ transform: translateY(0);
+}
+
+/* Header */
+.link-inserter-header {
+ padding: var(--spacing-md);
+ border-bottom: 1px solid var(--border-primary);
+}
+
+.link-inserter-input-wrapper {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+}
+
+.link-inserter-icon {
+ color: var(--accent-primary);
+ flex-shrink: 0;
+}
+
+.link-inserter-input {
+ flex: 1;
+ background: transparent;
+ border: none;
+ color: var(--text-primary);
+ font-size: 15px;
+ outline: none;
+ padding: var(--spacing-sm) 0;
+}
+
+.link-inserter-input::placeholder {
+ color: var(--text-muted);
+}
+
+.link-inserter-kbd {
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-sm);
+ padding: 2px 6px;
+ font-size: 11px;
+ font-family: monospace;
+ color: var(--text-muted);
+ flex-shrink: 0;
+}
+
+/* Body */
+.link-inserter-body {
+ flex: 1;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+}
+
+.link-inserter-results {
+ flex: 1;
+ overflow-y: auto;
+ padding: var(--spacing-sm);
+}
+
+/* Results Header */
+.link-inserter-results-header {
+ padding: var(--spacing-sm) var(--spacing-md);
+ color: var(--text-muted);
+ font-size: 0.8rem;
+}
+
+.link-inserter-results-count {
+ font-weight: 500;
+}
+
+/* Result Item */
+.link-inserter-result-item {
+ display: flex;
+ gap: var(--spacing-sm);
+ padding: var(--spacing-sm) var(--spacing-md);
+ margin: var(--spacing-xs) 0;
+ border-radius: var(--radius-md);
+ cursor: pointer;
+ transition: all var(--transition-fast);
+ border: 1px solid transparent;
+}
+
+.link-inserter-result-item:hover {
+ background: var(--bg-tertiary);
+}
+
+.link-inserter-result-item.selected {
+ background: linear-gradient(135deg, rgba(130, 170, 255, 0.15), rgba(199, 146, 234, 0.15));
+ border-color: var(--accent-primary);
+}
+
+.link-inserter-result-icon {
+ font-size: 1.2rem;
+ flex-shrink: 0;
+}
+
+.link-inserter-result-content {
+ flex: 1;
+ min-width: 0;
+}
+
+.link-inserter-result-title {
+ font-weight: 500;
+ color: var(--text-primary);
+ margin-bottom: 3px;
+ font-size: 0.95rem;
+}
+
+.link-inserter-result-title mark {
+ background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ color: white;
+ padding: 2px 4px;
+ border-radius: 3px;
+ font-weight: 600;
+}
+
+.link-inserter-result-path {
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ margin-bottom: 4px;
+}
+
+.link-inserter-result-tags {
+ display: flex;
+ gap: 4px;
+ flex-wrap: wrap;
+ margin-top: 4px;
+}
+
+.tag-pill-small {
+ background: var(--bg-tertiary);
+ color: var(--accent-primary);
+ border: 1px solid var(--border-primary);
+ padding: 1px 6px;
+ border-radius: 10px;
+ font-size: 0.7rem;
+ font-weight: 500;
+}
+
+/* Help */
+.link-inserter-help {
+ padding: var(--spacing-xl);
+ text-align: center;
+}
+
+.link-inserter-help-text {
+ font-size: 0.95rem;
+ color: var(--text-muted);
+}
+
+/* Loading */
+.link-inserter-loading {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: var(--spacing-xl);
+ gap: var(--spacing-md);
+}
+
+.link-inserter-spinner {
+ width: 32px;
+ height: 32px;
+ border: 3px solid var(--bg-tertiary);
+ border-top-color: var(--accent-primary);
+ border-radius: 50%;
+ animation: spin 0.8s linear infinite;
+}
+
+.link-inserter-loading p {
+ color: var(--text-muted);
+ font-size: 0.9rem;
+}
+
+/* No Results */
+.link-inserter-no-results {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: var(--spacing-xl);
+ gap: var(--spacing-sm);
+}
+
+.link-inserter-no-results-icon {
+ font-size: 2.5rem;
+ opacity: 0.6;
+}
+
+.link-inserter-no-results p {
+ color: var(--text-secondary);
+ font-size: 0.9rem;
+ text-align: center;
+}
+
+/* Error */
+.link-inserter-error {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: var(--spacing-xl);
+ gap: var(--spacing-sm);
+}
+
+.link-inserter-error-icon {
+ font-size: 2.5rem;
+}
+
+.link-inserter-error p {
+ color: var(--text-secondary);
+ font-size: 0.9rem;
+}
+
+/* Footer */
+.link-inserter-footer {
+ padding: var(--spacing-sm) var(--spacing-md);
+ border-top: 1px solid var(--border-primary);
+ background: var(--bg-tertiary);
+}
+
+.link-inserter-footer-hint {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+ font-size: 0.75rem;
+ color: var(--text-muted);
+}
+
+.link-inserter-footer-hint kbd {
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-sm);
+ padding: 2px 5px;
+ font-family: monospace;
+ font-size: 0.7rem;
+}
+
+/* ============================================
+ BACKLINKS SECTION
+ ============================================ */
+
+/* Preview wrapper to contain both preview and backlinks */
+.preview-wrapper {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-md);
+ min-height: 0;
+ height: 100%;
+}
+
+/* Backlinks section styling */
+.backlinks-section {
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ padding: var(--spacing-md);
+ margin-top: var(--spacing-md);
+}
+
+.backlinks-title {
+ font-size: 1rem;
+ font-weight: 600;
+ color: var(--text-primary);
+ margin: 0 0 var(--spacing-sm) 0;
+ padding-bottom: var(--spacing-sm);
+ border-bottom: 1px solid var(--border-primary);
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-xs);
+}
+
+.backlinks-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-xs);
+}
+
+.backlink-item {
+ margin: 0;
+ padding: 0;
+}
+
+.backlink-link {
+ display: block;
+ padding: var(--spacing-sm) var(--spacing-md);
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-secondary);
+ border-radius: var(--radius-sm);
+ color: var(--text-primary);
+ text-decoration: none;
+ transition: all var(--transition-fast);
+ font-size: 0.9rem;
+ font-weight: 500;
+}
+
+.backlink-link:hover {
+ background: var(--bg-primary);
+ border-color: var(--accent-primary);
+ color: var(--accent-primary);
+ transform: translateX(4px);
+ box-shadow: var(--shadow-sm);
+}
+
+.backlink-link:active {
+ transform: translateX(2px);
+}
+
+/* Mobile Adaptation */
+@media screen and (max-width: 768px) {
+ .link-inserter-container {
+ width: 100%;
+ max-width: 100%;
+ margin: 0;
+ border-radius: 0;
+ max-height: 100vh;
+ }
+
+ .link-inserter-input {
+ font-size: 14px;
+ }
+
+ .link-inserter-results {
+ max-height: calc(100vh - 200px);
+ }
+}
+
+/* ========================================
+ Recent Notes Section
+ ======================================== */
+.recent-notes-container {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-md);
+ max-height: 500px;
+ overflow-y: auto;
+ padding: var(--spacing-sm);
+ margin-bottom: var(--spacing-lg);
+ /* Masquer la scrollbar mais garder le scroll */
+ scrollbar-width: none; /* Firefox */
+ -ms-overflow-style: none; /* IE et Edge */
+}
+
+/* Masquer la scrollbar pour Chrome, Safari et Opera */
+.recent-notes-container::-webkit-scrollbar {
+ display: none;
+}
+
+.recent-note-card {
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ padding: var(--spacing-md);
+ transition: all var(--transition-fast);
+ box-shadow: var(--shadow-sm);
+}
+
+.recent-note-card:hover {
+ border-color: var(--accent-primary);
+ box-shadow: var(--shadow-md), var(--shadow-glow);
+ transform: translateY(-2px);
+}
+
+.recent-note-link {
+ text-decoration: none;
+ color: inherit;
+ display: block;
+}
+
+.recent-note-title {
+ font-size: 1.1rem;
+ font-weight: 600;
+ color: var(--text-primary);
+ margin-bottom: var(--spacing-sm);
+ line-height: 1.4;
+}
+
+.recent-note-meta {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--spacing-md);
+ align-items: center;
+ margin-bottom: var(--spacing-sm);
+ font-size: 0.85rem;
+}
+
+.recent-note-date {
+ color: var(--text-secondary);
+ display: flex;
+ align-items: center;
+ gap: 0.25rem;
+}
+
+.recent-note-tags {
+ color: var(--accent-primary);
+ font-size: 0.8rem;
+ font-weight: 500;
+}
+
+.recent-note-preview {
+ color: var(--text-muted);
+ font-size: 0.9rem;
+ line-height: 1.5;
+ margin-top: var(--spacing-sm);
+ display: -webkit-box;
+ -webkit-line-clamp: 3;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+
+/* ========================================
+ Home Page Sections with Accordions
+ ======================================== */
+.home-section {
+ margin-bottom: var(--spacing-lg);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-lg);
+ background: var(--bg-secondary);
+ overflow: hidden;
+ transition: all var(--transition-fast);
+}
+
+.home-section:hover {
+ border-color: var(--border-secondary);
+ box-shadow: var(--shadow-sm);
+}
+
+.home-section-header {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+ padding: var(--spacing-md) var(--spacing-lg);
+ cursor: pointer;
+ background: var(--bg-tertiary);
+ border-bottom: 1px solid var(--border-primary);
+ transition: all var(--transition-fast);
+ user-select: none;
+}
+
+.home-section-header:hover {
+ background: var(--bg-secondary);
+}
+
+.home-section-header:active {
+ background: var(--bg-primary);
+}
+
+.home-section-title {
+ margin: 0;
+ font-size: 1.3rem;
+ font-weight: 600;
+ color: var(--text-primary);
+ flex: 1;
+}
+
+.home-section-content {
+ padding: var(--spacing-lg);
+ overflow-y: auto;
+ transition: all var(--transition-medium);
+ max-height: 600px;
+ /* Masquer la scrollbar mais garder le scroll */
+ scrollbar-width: none; /* Firefox */
+ -ms-overflow-style: none; /* IE et Edge */
+}
+
+/* Masquer la scrollbar pour Chrome, Safari et Opera */
+.home-section-content::-webkit-scrollbar {
+ display: none;
+}
+
+/* Adjust nested containers for accordion layout */
+.home-section .recent-notes-container {
+ padding: 0;
+ margin-bottom: 0;
+}
+
+/* ========================================
+ Breadcrumb Navigation
+ ======================================== */
+.breadcrumb {
+ display: inline-flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 0.25rem;
+ font-size: 0.95rem;
+}
+
+.breadcrumb-link {
+ color: var(--accent-primary);
+ text-decoration: none;
+ padding: 0.25rem 0.5rem;
+ border-radius: var(--radius-sm);
+ transition: all var(--transition-fast);
+}
+
+.breadcrumb-link:hover {
+ background: var(--bg-tertiary);
+ color: var(--accent-secondary);
+}
+
+.breadcrumb-separator {
+ color: var(--text-muted);
+ font-size: 0.9rem;
+}
+
+/* ========================================
+ Folder and File Lists (Folder View)
+ ======================================== */
+/* Styles spécifiques pour la vue de dossier dans l'éditeur */
+#editor-content .folder-list,
+#editor-content .file-list {
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-sm);
+ margin-bottom: var(--spacing-lg);
+}
+
+#editor-content .folder-list .folder-item,
+#editor-content .file-list .file-item {
+ padding: var(--spacing-md);
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ transition: all var(--transition-fast);
+}
+
+#editor-content .folder-list .folder-item:hover,
+#editor-content .file-list .file-item:hover {
+ border-color: var(--accent-primary);
+ box-shadow: var(--shadow-sm);
+ transform: translateX(4px);
+}
+
+#editor-content .folder-list .folder-item a,
+#editor-content .file-list .file-item a {
+ color: var(--text-primary);
+ text-decoration: none;
+ display: block;
+ font-weight: 500;
+}
+
+#editor-content .folder-list .folder-item:hover a,
+#editor-content .file-list .file-item:hover a {
+ color: var(--accent-primary);
+}
+
+
+
+/* Public toggle button */
+#toggle-public-btn {
+ transition: all 0.3s ease;
+}
+
+#toggle-public-btn.public-active {
+ background: var(--accent-green, #2ecc71);
+ color: white;
+ border-color: var(--accent-green, #2ecc71);
+}
+
+#toggle-public-btn.public-active:hover {
+ background: var(--accent-green-dark, #27ae60);
+ border-color: var(--accent-green-dark, #27ae60);
+}
diff --git a/public/static/themes.css b/public/static/themes.css
new file mode 100644
index 0000000..344907d
--- /dev/null
+++ b/public/static/themes.css
@@ -0,0 +1,695 @@
+/*
+ * PersoNotes - Multi-Theme System
+ * Supports: Material Dark (default), Monokai Dark, Dracula, One Dark, Solarized Dark, Nord
+ */
+
+/* ===========================
+ THEME: MATERIAL DARK (défaut)
+ =========================== */
+:root,
+[data-theme="material-dark"] {
+ --bg-primary: #1e1e1e;
+ --bg-secondary: #252525;
+ --bg-tertiary: #2d2d2d;
+ --bg-elevated: #323232;
+
+ --border-primary: #3e3e3e;
+ --border-secondary: #2a2a2a;
+
+ --text-primary: #e0e0e0;
+ --text-secondary: #b0b0b0;
+ --text-muted: #6e6e6e;
+
+ --accent-primary: #42a5f5;
+ --accent-primary-hover: #5ab3f7;
+ --accent-secondary: #29b6f6;
+ --accent-secondary-hover: #4fc3f7;
+
+ --success: #66bb6a;
+ --warning: #ffa726;
+ --error: #ef5350;
+}
+
+/* ===========================
+ THEME: MONOKAI DARK
+ =========================== */
+[data-theme="monokai-dark"] {
+ --bg-primary: #272822;
+ --bg-secondary: #2d2e27;
+ --bg-tertiary: #3e3d32;
+ --bg-elevated: #49483e;
+
+ --border-primary: #49483e;
+ --border-secondary: #3e3d32;
+
+ --text-primary: #f8f8f2;
+ --text-secondary: #cfcfc2;
+ --text-muted: #75715e;
+
+ --accent-primary: #66d9ef;
+ --accent-primary-hover: #7ee5f7;
+ --accent-secondary: #88c070;
+ --accent-secondary-hover: #9acc84;
+
+ --success: #88c070;
+ --warning: #e6db74;
+ --error: #f92672;
+}
+
+/* ===========================
+ THEME: DRACULA
+ =========================== */
+[data-theme="dracula"] {
+ --bg-primary: #282a36;
+ --bg-secondary: #2f3241;
+ --bg-tertiary: #373844;
+ --bg-elevated: #44475a;
+
+ --border-primary: #44475a;
+ --border-secondary: #373844;
+
+ --text-primary: #f8f8f2;
+ --text-secondary: #d6d6d6;
+ --text-muted: #6272a4;
+
+ --accent-primary: #8be9fd;
+ --accent-primary-hover: #9ff3ff;
+ --accent-secondary: #bd93f9;
+ --accent-secondary-hover: #cba6ff;
+
+ --success: #50fa7b;
+ --warning: #f1fa8c;
+ --error: #ff5555;
+}
+
+/* ===========================
+ THEME: ONE DARK
+ =========================== */
+[data-theme="one-dark"] {
+ --bg-primary: #282c34;
+ --bg-secondary: #2c313a;
+ --bg-tertiary: #333842;
+ --bg-elevated: #3e4451;
+
+ --border-primary: #3e4451;
+ --border-secondary: #333842;
+
+ --text-primary: #abb2bf;
+ --text-secondary: #9ca3af;
+ --text-muted: #5c6370;
+
+ --accent-primary: #61afef;
+ --accent-primary-hover: #75bdf5;
+ --accent-secondary: #c678dd;
+ --accent-secondary-hover: #d48ae9;
+
+ --success: #98c379;
+ --warning: #e5c07b;
+ --error: #e06c75;
+}
+
+/* ===========================
+ THEME: SOLARIZED DARK
+ =========================== */
+[data-theme="solarized-dark"] {
+ --bg-primary: #002b36;
+ --bg-secondary: #073642;
+ --bg-tertiary: #094454;
+ --bg-elevated: #0e5261;
+
+ --border-primary: #0e5261;
+ --border-secondary: #094454;
+
+ --text-primary: #839496;
+ --text-secondary: #93a1a1;
+ --text-muted: #586e75;
+
+ --accent-primary: #268bd2;
+ --accent-primary-hover: #4098d9;
+ --accent-secondary: #2aa198;
+ --accent-secondary-hover: #3eb3a8;
+
+ --success: #859900;
+ --warning: #b58900;
+ --error: #dc322f;
+}
+
+/* ===========================
+ THEME: NORD
+ =========================== */
+[data-theme="nord"] {
+ --bg-primary: #2e3440;
+ --bg-secondary: #3b4252;
+ --bg-tertiary: #434c5e;
+ --bg-elevated: #4c566a;
+
+ --border-primary: #4c566a;
+ --border-secondary: #434c5e;
+
+ --text-primary: #eceff4;
+ --text-secondary: #d8dee9;
+ --text-muted: #616e88;
+
+ --accent-primary: #88c0d0;
+ --accent-primary-hover: #9dcadb;
+ --accent-secondary: #81a1c1;
+ --accent-secondary-hover: #94b0cc;
+
+ --success: #a3be8c;
+ --warning: #ebcb8b;
+ --error: #bf616a;
+}
+
+/* ===========================
+ THEME: CATPPUCCIN MOCHA
+ =========================== */
+[data-theme="catppuccin"] {
+ --bg-primary: #1e1e2e;
+ --bg-secondary: #181825;
+ --bg-tertiary: #313244;
+ --bg-elevated: #45475a;
+
+ --border-primary: #45475a;
+ --border-secondary: #313244;
+
+ --text-primary: #cdd6f4;
+ --text-secondary: #bac2de;
+ --text-muted: #6c7086;
+
+ --accent-primary: #89b4fa;
+ --accent-primary-hover: #a6c8ff;
+ --accent-secondary: #f5c2e7;
+ --accent-secondary-hover: #f9d5ee;
+
+ --success: #a6e3a1;
+ --warning: #f9e2af;
+ --error: #f38ba8;
+}
+
+/* ===========================
+ THEME: EVERFOREST DARK
+ =========================== */
+[data-theme="everforest"] {
+ --bg-primary: #2d353b;
+ --bg-secondary: #272e33;
+ --bg-tertiary: #343f44;
+ --bg-elevated: #3d484d;
+
+ --border-primary: #3d484d;
+ --border-secondary: #343f44;
+
+ --text-primary: #d3c6aa;
+ --text-secondary: #b4a990;
+ --text-muted: #7a8478;
+
+ --accent-primary: #7fbbb3;
+ --accent-primary-hover: #93c9c1;
+ --accent-secondary: #a7c080;
+ --accent-secondary-hover: #b8cc94;
+
+ --success: #a7c080;
+ --warning: #dbbc7f;
+ --error: #e67e80;
+}
+
+/* ===========================
+ BOUTONS D'ACTION DE LA SIDEBAR
+ =========================== */
+.sidebar-action-btn {
+ width: 100%;
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ color: var(--text-primary);
+ padding: var(--spacing-md);
+ cursor: pointer;
+ transition: all var(--transition-fast);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: var(--spacing-sm);
+ font-size: 0.9rem;
+ font-weight: 500;
+ margin-top: var(--spacing-sm);
+}
+
+.sidebar-action-btn:hover {
+ background: var(--bg-elevated);
+ border-color: var(--accent-primary);
+ color: var(--accent-primary);
+ transform: translateY(-1px);
+ box-shadow: var(--shadow-sm);
+}
+
+/* Style spécifique pour le bouton paramètres (avec animation) */
+.theme-settings-btn {
+ width: 100%;
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ color: var(--text-primary);
+ padding: var(--spacing-md);
+ cursor: pointer;
+ transition: all var(--transition-fast);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: var(--spacing-sm);
+ font-size: 0.9rem;
+ font-weight: 500;
+ margin-top: var(--spacing-sm);
+}
+
+.theme-settings-btn:hover {
+ background: var(--bg-elevated);
+ border-color: var(--accent-primary);
+ color: var(--accent-primary);
+ transform: translateY(-1px);
+ box-shadow: var(--shadow-sm);
+}
+
+.theme-settings-btn svg {
+ animation: rotate 2s linear infinite;
+ animation-play-state: paused;
+}
+
+.theme-settings-btn:hover svg {
+ animation-play-state: running;
+}
+
+@keyframes rotate {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+/* ===========================
+ MODALE DE SÉLECTION DE THÈME
+ =========================== */
+#theme-modal {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 9999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.theme-modal-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: rgba(0, 0, 0, 0.7);
+ backdrop-filter: blur(4px);
+}
+
+.theme-modal-content {
+ position: relative;
+ background: var(--bg-secondary);
+ border: 1px solid var(--accent-primary);
+ border-radius: var(--radius-lg);
+ padding: var(--spacing-xl);
+ max-width: 600px;
+ width: 90%;
+ max-height: 80vh;
+ overflow-y: auto;
+ box-shadow: var(--shadow-lg), var(--shadow-glow);
+ animation: slideUp 0.3s ease;
+ z-index: 1;
+}
+
+.theme-modal-content h2 {
+ margin: 0 0 var(--spacing-lg) 0;
+ color: var(--text-primary);
+ font-size: 1.4rem;
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+}
+
+.theme-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: var(--spacing-md);
+ margin-bottom: var(--spacing-lg);
+}
+
+.theme-card {
+ background: var(--bg-tertiary);
+ border: 2px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ padding: var(--spacing-md);
+ cursor: pointer;
+ transition: all var(--transition-fast);
+ position: relative;
+}
+
+.theme-card:hover {
+ border-color: var(--accent-primary);
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-md);
+}
+
+.theme-card.active {
+ border-color: var(--accent-primary);
+ box-shadow: 0 0 0 3px rgba(66, 165, 245, 0.2);
+}
+
+.theme-card.active::before {
+ content: '✓';
+ position: absolute;
+ top: var(--spacing-xs);
+ right: var(--spacing-xs);
+ background: var(--accent-primary);
+ color: white;
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-weight: bold;
+ font-size: 0.8rem;
+}
+
+.theme-card-header {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+ margin-bottom: var(--spacing-md);
+}
+
+.theme-card-icon {
+ font-size: 1.5rem;
+}
+
+.theme-card-name {
+ font-weight: 600;
+ color: var(--text-primary);
+ font-size: 1rem;
+}
+
+.theme-preview {
+ display: flex;
+ gap: var(--spacing-xs);
+ margin-bottom: var(--spacing-sm);
+ height: 40px;
+ border-radius: var(--radius-sm);
+ overflow: hidden;
+}
+
+.theme-preview-color {
+ flex: 1;
+ transition: all var(--transition-fast);
+}
+
+.theme-card:hover .theme-preview-color {
+ transform: scaleY(1.1);
+}
+
+.theme-description {
+ font-size: 0.85rem;
+ color: var(--text-secondary);
+ line-height: 1.4;
+}
+
+/* Couleurs de prévisualisation pour chaque thème */
+.theme-card[data-theme="material-dark"] .theme-preview-color:nth-child(1) { background: #1e1e1e; }
+.theme-card[data-theme="material-dark"] .theme-preview-color:nth-child(2) { background: #42a5f5; }
+.theme-card[data-theme="material-dark"] .theme-preview-color:nth-child(3) { background: #29b6f6; }
+.theme-card[data-theme="material-dark"] .theme-preview-color:nth-child(4) { background: #e0e0e0; }
+
+.theme-card[data-theme="monokai-dark"] .theme-preview-color:nth-child(1) { background: #272822; }
+.theme-card[data-theme="monokai-dark"] .theme-preview-color:nth-child(2) { background: #66d9ef; }
+.theme-card[data-theme="monokai-dark"] .theme-preview-color:nth-child(3) { background: #88c070; }
+.theme-card[data-theme="monokai-dark"] .theme-preview-color:nth-child(4) { background: #f8f8f2; }
+
+.theme-card[data-theme="dracula"] .theme-preview-color:nth-child(1) { background: #282a36; }
+.theme-card[data-theme="dracula"] .theme-preview-color:nth-child(2) { background: #8be9fd; }
+.theme-card[data-theme="dracula"] .theme-preview-color:nth-child(3) { background: #bd93f9; }
+.theme-card[data-theme="dracula"] .theme-preview-color:nth-child(4) { background: #f8f8f2; }
+
+.theme-card[data-theme="one-dark"] .theme-preview-color:nth-child(1) { background: #282c34; }
+.theme-card[data-theme="one-dark"] .theme-preview-color:nth-child(2) { background: #61afef; }
+.theme-card[data-theme="one-dark"] .theme-preview-color:nth-child(3) { background: #c678dd; }
+.theme-card[data-theme="one-dark"] .theme-preview-color:nth-child(4) { background: #abb2bf; }
+
+.theme-card[data-theme="solarized-dark"] .theme-preview-color:nth-child(1) { background: #002b36; }
+.theme-card[data-theme="solarized-dark"] .theme-preview-color:nth-child(2) { background: #268bd2; }
+.theme-card[data-theme="solarized-dark"] .theme-preview-color:nth-child(3) { background: #2aa198; }
+.theme-card[data-theme="solarized-dark"] .theme-preview-color:nth-child(4) { background: #839496; }
+
+.theme-card[data-theme="nord"] .theme-preview-color:nth-child(1) { background: #2e3440; }
+.theme-card[data-theme="nord"] .theme-preview-color:nth-child(2) { background: #88c0d0; }
+.theme-card[data-theme="nord"] .theme-preview-color:nth-child(3) { background: #81a1c1; }
+.theme-card[data-theme="nord"] .theme-preview-color:nth-child(4) { background: #eceff4; }
+
+.theme-card[data-theme="catppuccin"] .theme-preview-color:nth-child(1) { background: #1e1e2e; }
+.theme-card[data-theme="catppuccin"] .theme-preview-color:nth-child(2) { background: #89b4fa; }
+.theme-card[data-theme="catppuccin"] .theme-preview-color:nth-child(3) { background: #f5c2e7; }
+.theme-card[data-theme="catppuccin"] .theme-preview-color:nth-child(4) { background: #cdd6f4; }
+
+.theme-card[data-theme="everforest"] .theme-preview-color:nth-child(1) { background: #2d353b; }
+.theme-card[data-theme="everforest"] .theme-preview-color:nth-child(2) { background: #7fbbb3; }
+.theme-card[data-theme="everforest"] .theme-preview-color:nth-child(3) { background: #a7c080; }
+.theme-card[data-theme="everforest"] .theme-preview-color:nth-child(4) { background: #d3c6aa; }
+
+.theme-modal-footer {
+ display: flex;
+ justify-content: flex-end;
+ gap: var(--spacing-sm);
+ margin-top: var(--spacing-lg);
+ padding-top: var(--spacing-md);
+ border-top: 1px solid var(--border-primary);
+}
+
+/* Onglets de paramètres */
+.settings-tabs {
+ display: flex;
+ gap: var(--spacing-sm);
+ margin-bottom: var(--spacing-lg);
+ border-bottom: 2px solid var(--border-primary);
+}
+
+.settings-tab {
+ background: transparent;
+ border: none;
+ padding: var(--spacing-sm) var(--spacing-md);
+ color: var(--text-secondary);
+ font-size: 0.95rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all var(--transition-fast);
+ border-bottom: 2px solid transparent;
+ margin-bottom: -2px;
+}
+
+.settings-tab:hover {
+ color: var(--text-primary);
+ background: var(--bg-tertiary);
+}
+
+.settings-tab.active {
+ color: var(--accent-primary);
+ border-bottom-color: var(--accent-primary);
+}
+
+.settings-section {
+ animation: fadeIn 0.3s ease;
+}
+
+/* Grille de polices */
+.font-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: var(--spacing-md);
+ margin-bottom: var(--spacing-lg);
+}
+
+.font-card {
+ background: var(--bg-tertiary);
+ border: 2px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ padding: var(--spacing-md);
+ cursor: pointer;
+ transition: all var(--transition-fast);
+ position: relative;
+}
+
+.font-card:hover {
+ border-color: var(--accent-primary);
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-md);
+}
+
+.font-card.active {
+ border-color: var(--accent-primary);
+ box-shadow: 0 0 0 3px rgba(66, 165, 245, 0.2);
+}
+
+.font-card.active::before {
+ content: '✓';
+ position: absolute;
+ top: var(--spacing-xs);
+ right: var(--spacing-xs);
+ background: var(--accent-primary);
+ color: white;
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-weight: bold;
+ font-size: 0.8rem;
+}
+
+.font-card-header {
+ display: flex;
+ align-items: center;
+ gap: var(--spacing-sm);
+ margin-bottom: var(--spacing-md);
+}
+
+.font-card-icon {
+ font-size: 1.3rem;
+}
+
+.font-card-name {
+ font-weight: 600;
+ color: var(--text-primary);
+ font-size: 0.95rem;
+}
+
+.font-preview {
+ background: var(--bg-primary);
+ border: 1px solid var(--border-primary);
+ border-radius: var(--radius-sm);
+ padding: var(--spacing-md);
+ margin-bottom: var(--spacing-sm);
+ font-size: 1.1rem;
+ text-align: center;
+ color: var(--text-primary);
+ min-height: 50px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.font-description {
+ font-size: 0.8rem;
+ color: var(--text-secondary);
+ line-height: 1.4;
+}
+
+/* Sélecteur de taille de police */
+.font-size-selector {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
+ gap: var(--spacing-sm);
+}
+
+.font-size-option {
+ background: var(--bg-tertiary);
+ border: 2px solid var(--border-primary);
+ border-radius: var(--radius-md);
+ padding: var(--spacing-md);
+ cursor: pointer;
+ transition: all var(--transition-fast);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--spacing-xs);
+}
+
+.font-size-option:hover {
+ border-color: var(--accent-primary);
+ transform: translateY(-2px);
+ box-shadow: var(--shadow-sm);
+}
+
+.font-size-option.active {
+ border-color: var(--accent-primary);
+ background: rgba(66, 165, 245, 0.1);
+ box-shadow: 0 0 0 3px rgba(66, 165, 245, 0.2);
+}
+
+.size-label {
+ font-size: 0.85rem;
+ color: var(--text-secondary);
+ font-weight: 500;
+}
+
+.font-size-option.active .size-label {
+ color: var(--accent-primary);
+}
+
+.size-preview {
+ font-weight: 600;
+ color: var(--text-primary);
+ line-height: 1;
+}
+
+/* ===========================
+ TOGGLE SWITCH (pour Mode Vim)
+ =========================== */
+.toggle-switch {
+ position: relative;
+ display: inline-block;
+ width: 50px;
+ height: 26px;
+ flex-shrink: 0;
+}
+
+.toggle-switch input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+
+.toggle-slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: var(--bg-tertiary);
+ transition: 0.3s;
+ border-radius: 26px;
+ border: 1px solid var(--border-primary);
+}
+
+.toggle-slider:before {
+ position: absolute;
+ content: "";
+ height: 18px;
+ width: 18px;
+ left: 4px;
+ bottom: 3px;
+ background-color: var(--text-muted);
+ transition: 0.3s;
+ border-radius: 50%;
+}
+
+.toggle-switch input:checked + .toggle-slider {
+ background-color: var(--accent-primary);
+ border-color: var(--accent-primary);
+}
+
+.toggle-switch input:checked + .toggle-slider:before {
+ transform: translateX(24px);
+ background-color: white;
+}
+
+.toggle-switch input:focus + .toggle-slider {
+ box-shadow: 0 0 0 3px rgba(66, 165, 245, 0.2);
+}
diff --git a/static/theme.css b/static/theme.css
index 811d3f5..aa0e521 100644
--- a/static/theme.css
+++ b/static/theme.css
@@ -17,35 +17,33 @@
--text-secondary: #b0b0b0;
--text-muted: #6e6e6e;
- /* Accent colors - Blue focused */
+ /* Accent color - Single blue accent for consistency */
--accent-primary: #42a5f5;
- --accent-primary-hover: #64b5f6;
- --accent-secondary: #29b6f6;
- --accent-secondary-hover: #4fc3f7;
+ --accent-hover: #64b5f6;
/* Semantic colors */
--success: #66bb6a;
--warning: #ffa726;
--error: #ef5350;
- /* Spacing */
- --spacing-xs: 0.25rem;
- --spacing-sm: 0.5rem;
- --spacing-md: 1rem;
- --spacing-lg: 1.5rem;
- --spacing-xl: 2rem;
-
- /* Sidebar compact spacing */
- --sidebar-item-gap: 0.05rem;
- --sidebar-padding-v: 0.3rem;
- --sidebar-padding-h: 0.75rem;
- --sidebar-indent: 1rem;
+ /* Spacing - 8px base unit system */
+ --spacing-xs: 0.5rem; /* 8px - 1 unit */
+ --spacing-sm: 1rem; /* 16px - 2 units */
+ --spacing-md: 1.5rem; /* 24px - 3 units */
+ --spacing-lg: 2rem; /* 32px - 4 units */
+ --spacing-xl: 3rem; /* 48px - 6 units */
- /* Shadows */
- --shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.4);
- --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -2px rgba(0, 0, 0, 0.3);
- --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -4px rgba(0, 0, 0, 0.3);
- --shadow-glow: 0 0 20px rgba(66, 165, 245, 0.2);
+ /* Sidebar spacing - aligned to 8px grid */
+ --sidebar-item-gap: 0.125rem; /* 2px - minimal spacing between items */
+ --sidebar-padding-v: 0.25rem; /* 4px - compact vertical padding */
+ --sidebar-padding-h: 1rem; /* 16px */
+ --sidebar-indent: 1.5rem; /* 24px */
+
+ /* Shadows - reduced opacity for minimal look */
+ --shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.08);
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.12), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
+ --shadow-glow: 0 0 20px rgba(66, 165, 245, 0.1);
/* Border radius */
--radius-sm: 4px;
@@ -55,8 +53,59 @@
/* Transitions */
--transition-fast: 150ms ease;
--transition-normal: 250ms ease;
+
+ /* Typography scale - consistent font sizes */
+ --text-xs: 0.75rem; /* 12px */
+ --text-sm: 0.875rem; /* 14px */
+ --text-base: 1rem; /* 16px - default */
+ --text-md: 1.125rem; /* 18px */
+ --text-lg: 1.25rem; /* 20px */
+ --text-xl: 1.5rem; /* 24px */
+ --text-2xl: 2rem; /* 32px */
+ --text-3xl: 3rem; /* 48px */
+
+ /* Touch targets - minimum sizes for accessibility */
+ --touch-sm: 2rem; /* 32px - compact */
+ --touch-md: 2.75rem; /* 44px - standard mobile minimum */
+ --touch-lg: 3rem; /* 48px - comfortable */
+
+ /* Lucide Icons - Professional SVG icons */
+ --icon-xs: 14px;
+ --icon-sm: 16px;
+ --icon-md: 20px;
+ --icon-lg: 24px;
+ --icon-xl: 32px;
}
+/* Lucide Icons Styling */
+.lucide {
+ display: inline-block;
+ vertical-align: middle;
+ stroke-width: 2;
+ stroke: currentColor;
+ fill: none;
+}
+
+/* Icon size variants */
+.icon-xs { width: var(--icon-xs); height: var(--icon-xs); }
+.icon-sm { width: var(--icon-sm); height: var(--icon-sm); }
+.icon-md { width: var(--icon-md); height: var(--icon-md); }
+.icon-lg { width: var(--icon-lg); height: var(--icon-lg); }
+.icon-xl { width: var(--icon-xl); height: var(--icon-xl); }
+
+/* Icon with text alignment */
+.icon-text {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+/* Icon color variants */
+.icon-primary { color: var(--text-primary); }
+.icon-secondary { color: var(--text-secondary); }
+.icon-muted { color: var(--text-muted); }
+.icon-accent { color: var(--accent-primary); }
+
/* Base styles */
html {
font-size: 16px;
@@ -90,7 +139,7 @@ header h1 {
font-size: 1.25rem;
font-weight: 600;
color: var(--text-primary);
- background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ background: var(--accent-primary);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
@@ -257,25 +306,7 @@ aside hr {
margin: var(--spacing-sm) 0;
}
-/* File tree and search results */
-#file-tree a,
-#search-results a {
- display: block;
- padding: var(--spacing-sm) var(--spacing-md);
- color: var(--text-primary);
- text-decoration: none;
- border-radius: var(--radius-sm);
- transition: all var(--transition-fast);
- font-size: 0.9rem;
- margin-bottom: var(--spacing-xs);
-}
-
-#file-tree a:hover,
-#search-results a:hover {
- background: var(--bg-tertiary);
- color: var(--accent-primary);
- transform: translateX(2px);
-}
+/* File tree and search results - styles now handled by .file-item class */
/* Search results header */
.search-results-header {
@@ -411,7 +442,7 @@ aside hr {
}
.search-no-results-text strong {
- color: var(--accent-secondary);
+ color: var(--accent-primary);
}
.search-no-results-hint {
@@ -455,7 +486,7 @@ aside hr {
.search-help-example code {
background: var(--bg-primary);
- color: var(--accent-secondary);
+ color: var(--accent-primary);
padding: 0.2rem 0.4rem;
border-radius: var(--radius-sm);
font-size: 0.8rem;
@@ -720,7 +751,7 @@ main::-webkit-scrollbar-thumb:hover {
.preview h2 {
font-size: 1.5em;
- color: var(--accent-secondary);
+ color: var(--accent-primary);
margin-bottom: 0.9em;
}
@@ -771,7 +802,7 @@ main::-webkit-scrollbar-thumb:hover {
}
.preview ol > li::marker {
- color: var(--accent-secondary);
+ color: var(--accent-primary);
font-weight: 600;
}
@@ -797,7 +828,7 @@ main::-webkit-scrollbar-thumb:hover {
.preview a:hover {
text-decoration: underline;
- color: var(--accent-primary-hover);
+ color: var(--accent-hover);
}
.preview strong, .preview b {
@@ -815,7 +846,7 @@ main::-webkit-scrollbar-thumb:hover {
padding: 0.2em 0.4em;
border-radius: var(--radius-sm);
font-size: 0.85em;
- color: var(--accent-secondary);
+ color: var(--accent-primary);
font-weight: 500;
}
@@ -853,7 +884,7 @@ main::-webkit-scrollbar-thumb:hover {
}
.preview table thead {
- background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ background: var(--accent-primary);
}
.preview table thead th {
@@ -895,7 +926,7 @@ main::-webkit-scrollbar-thumb:hover {
button,
[type="submit"],
[type="button"] {
- background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ background: var(--accent-primary);
color: white;
border: none;
border-radius: var(--radius-md);
@@ -984,7 +1015,7 @@ button.secondary:hover {
}
#slash-commands-palette li[style*="background-color"] {
- background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary)) !important;
+ background: var(--accent-primary) !important;
color: white !important;
font-weight: 500;
transform: translateX(2px);
@@ -1016,7 +1047,7 @@ progress::-webkit-progress-bar {
}
progress::-webkit-progress-value {
- background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
+ background: var(--accent-primary);
border-radius: var(--radius-sm);
}
@@ -1236,39 +1267,26 @@ body, html {
}
.folder-item.drag-over .folder-header {
- background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ background: var(--accent-primary);
color: white;
box-shadow: var(--shadow-glow);
border: 2px solid var(--accent-primary);
border-radius: var(--radius-md);
- animation: pulse 1s ease-in-out infinite;
-}
-
-@keyframes pulse {
- 0%, 100% {
- transform: scale(1);
- box-shadow: var(--shadow-glow);
- }
- 50% {
- transform: scale(1.02);
- box-shadow: 0 0 30px rgba(88, 166, 255, 0.4);
- }
}
.file-item.drag-over {
- background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ background: var(--accent-primary);
color: white;
box-shadow: var(--shadow-glow);
}
/* Style pour la racine en drag-over */
.sidebar-section-header.drag-over {
- background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary)) !important;
+ background: var(--accent-primary) !important;
color: white !important;
box-shadow: var(--shadow-glow);
border: 2px solid var(--accent-primary);
border-radius: var(--radius-md);
- animation: pulse 1s ease-in-out infinite;
}
.sidebar-section-header.drag-over .folder-name,
@@ -1401,11 +1419,10 @@ body, html {
/* Quand on drag au-dessus de la racine */
.root-drop-zone.drag-over .root-folder-header {
- background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ background: var(--accent-primary);
color: white;
border-color: var(--accent-primary);
box-shadow: var(--shadow-glow);
- animation: pulse 1s ease-in-out infinite;
}
.root-drop-zone.drag-over .root-folder-header .folder-name,
@@ -2053,7 +2070,7 @@ body, html {
}
.search-modal-result-item.selected {
- background: linear-gradient(135deg, rgba(130, 170, 255, 0.15), rgba(199, 146, 234, 0.15));
+ background: var(--bg-secondary);
border-color: var(--accent-primary);
}
@@ -2074,7 +2091,7 @@ body, html {
}
.search-modal-result-title mark {
- background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ background: var(--accent-primary);
color: white;
padding: 2px 4px;
border-radius: 3px;
@@ -2200,11 +2217,6 @@ body, html {
border: 3px solid var(--border-primary);
border-top-color: var(--accent-primary);
border-radius: 50%;
- animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
- to { transform: rotate(360deg); }
}
.search-modal-loading p {
@@ -2566,12 +2578,12 @@ body, html {
/* Today */
.calendar-day-today {
- border-color: var(--accent-secondary);
- background: linear-gradient(135deg, rgba(130, 170, 255, 0.1), rgba(199, 146, 234, 0.1));
+ border-color: var(--accent-primary);
+ background: var(--bg-secondary);
}
.calendar-day-today .calendar-day-number {
- color: var(--accent-secondary);
+ color: var(--accent-primary);
font-weight: 700;
}
@@ -2596,7 +2608,7 @@ body, html {
width: 100%;
margin-top: var(--spacing-sm);
padding: var(--spacing-sm);
- background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ background: var(--accent-primary);
color: white;
border: none;
border-radius: var(--radius-md);
@@ -2681,11 +2693,12 @@ body, html {
display: flex;
align-items: center;
padding: 0;
- margin: var(--sidebar-item-gap) 0;
+ margin: 0; /* No margin on wrapper - use same spacing as folders */
}
.file-item-wrapper .file-item {
flex: 1;
+ margin: 0 !important; /* Force remove margin to avoid double spacing */
}
/* Bouton de mode sélection */
@@ -2715,8 +2728,8 @@ body, html {
}
.icon-button.active:hover {
- background: var(--accent-primary-hover);
- border-color: var(--accent-primary-hover);
+ background: var(--accent-hover);
+ border-color: var(--accent-hover);
}
/* Toolbar de sélection flottante */
@@ -2784,7 +2797,7 @@ body, html {
background: #ff5370;
border-color: #ff5370;
transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(240, 113, 120, 0.4);
+ box-shadow: 0 4px 12px rgba(240, 113, 120, 0.15);
}
.danger-button:active {
@@ -2974,30 +2987,38 @@ body, html {
/* Bouton d'ajout aux favoris (dans le file tree) */
.add-to-favorites {
- opacity: 0;
+ opacity: 0.4; /* Always slightly visible */
background: transparent;
border: none;
color: var(--text-muted);
cursor: pointer;
- font-size: 0.9rem;
- padding: 0 0.2rem;
+ font-size: 1rem;
+ padding: 0.25rem;
transition: all var(--transition-fast);
margin-left: auto;
+ border-radius: var(--radius-sm);
}
.folder-header:hover .add-to-favorites,
.file-item:hover .add-to-favorites {
opacity: 1;
+ background: var(--bg-tertiary);
}
.add-to-favorites:hover {
color: var(--warning);
- transform: scale(1.2);
+ transform: scale(1.15);
+ background: rgba(255, 193, 7, 0.1); /* Subtle yellow background */
}
.add-to-favorites.is-favorite {
- opacity: 1;
+ opacity: 1 !important; /* Always fully visible when favorited */
color: var(--warning);
+ background: rgba(255, 193, 7, 0.15);
+}
+
+.add-to-favorites.is-favorite:hover {
+ background: rgba(255, 193, 7, 0.2);
}
/* Responsive - Hauteurs adaptatives pour #favorites-list */
@@ -3162,7 +3183,7 @@ body, html {
}
.link-inserter-result-item.selected {
- background: linear-gradient(135deg, rgba(130, 170, 255, 0.15), rgba(199, 146, 234, 0.15));
+ background: var(--bg-secondary);
border-color: var(--accent-primary);
}
@@ -3184,7 +3205,7 @@ body, html {
}
.link-inserter-result-title mark {
- background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
+ background: var(--accent-primary);
color: white;
padding: 2px 4px;
border-radius: 3px;
@@ -3241,7 +3262,6 @@ body, html {
border: 3px solid var(--bg-tertiary);
border-top-color: var(--accent-primary);
border-radius: 50%;
- animation: spin 0.8s linear infinite;
}
.link-inserter-loading p {
@@ -3575,7 +3595,7 @@ body, html {
.breadcrumb-link:hover {
background: var(--bg-tertiary);
- color: var(--accent-secondary);
+ color: var(--accent-primary);
}
.breadcrumb-separator {
@@ -3624,3 +3644,20 @@ body, html {
color: var(--accent-primary);
}
+
+
+/* Public toggle button */
+#toggle-public-btn {
+ transition: all 0.3s ease;
+}
+
+#toggle-public-btn.public-active {
+ background: var(--accent-green, #2ecc71);
+ color: white;
+ border-color: var(--accent-green, #2ecc71);
+}
+
+#toggle-public-btn.public-active:hover {
+ background: var(--accent-green-dark, #27ae60);
+ border-color: var(--accent-green-dark, #27ae60);
+}
diff --git a/static/themes.css b/static/themes.css
index 344907d..1b64352 100644
--- a/static/themes.css
+++ b/static/themes.css
@@ -21,9 +21,7 @@
--text-muted: #6e6e6e;
--accent-primary: #42a5f5;
- --accent-primary-hover: #5ab3f7;
- --accent-secondary: #29b6f6;
- --accent-secondary-hover: #4fc3f7;
+ --accent-hover: #5ab3f7;
--success: #66bb6a;
--warning: #ffa726;
@@ -47,9 +45,7 @@
--text-muted: #75715e;
--accent-primary: #66d9ef;
- --accent-primary-hover: #7ee5f7;
- --accent-secondary: #88c070;
- --accent-secondary-hover: #9acc84;
+ --accent-hover: #7ee5f7;
--success: #88c070;
--warning: #e6db74;
@@ -73,9 +69,7 @@
--text-muted: #6272a4;
--accent-primary: #8be9fd;
- --accent-primary-hover: #9ff3ff;
- --accent-secondary: #bd93f9;
- --accent-secondary-hover: #cba6ff;
+ --accent-hover: #9ff3ff;
--success: #50fa7b;
--warning: #f1fa8c;
@@ -99,9 +93,7 @@
--text-muted: #5c6370;
--accent-primary: #61afef;
- --accent-primary-hover: #75bdf5;
- --accent-secondary: #c678dd;
- --accent-secondary-hover: #d48ae9;
+ --accent-hover: #75bdf5;
--success: #98c379;
--warning: #e5c07b;
@@ -125,9 +117,7 @@
--text-muted: #586e75;
--accent-primary: #268bd2;
- --accent-primary-hover: #4098d9;
- --accent-secondary: #2aa198;
- --accent-secondary-hover: #3eb3a8;
+ --accent-hover: #4098d9;
--success: #859900;
--warning: #b58900;
@@ -151,9 +141,7 @@
--text-muted: #616e88;
--accent-primary: #88c0d0;
- --accent-primary-hover: #9dcadb;
- --accent-secondary: #81a1c1;
- --accent-secondary-hover: #94b0cc;
+ --accent-hover: #9dcadb;
--success: #a3be8c;
--warning: #ebcb8b;
@@ -177,9 +165,7 @@
--text-muted: #6c7086;
--accent-primary: #89b4fa;
- --accent-primary-hover: #a6c8ff;
- --accent-secondary: #f5c2e7;
- --accent-secondary-hover: #f9d5ee;
+ --accent-hover: #a6c8ff;
--success: #a6e3a1;
--warning: #f9e2af;
@@ -203,9 +189,7 @@
--text-muted: #7a8478;
--accent-primary: #7fbbb3;
- --accent-primary-hover: #93c9c1;
- --accent-secondary: #a7c080;
- --accent-secondary-hover: #b8cc94;
+ --accent-hover: #93c9c1;
--success: #a7c080;
--warning: #dbbc7f;
diff --git a/templates/about.html b/templates/about.html
index 1daecc1..38d4c5d 100644
--- a/templates/about.html
+++ b/templates/about.html
@@ -1,7 +1,7 @@
- 📝 About PersoNotes
+ About PersoNotes
Un gestionnaire de notes Markdown moderne et puissant
@@ -10,23 +10,23 @@
- 🚀 Démarrage rapide
+ Démarrage rapide
-
📁 Parcourir
+
Parcourir
Explorez vos notes dans l'arborescence à gauche
-
🔍 Rechercher
+
Rechercher
Utilisez la barre de recherche en haut pour trouver vos notes
-
⚡ Slash commands
+
Slash commands
Tapez / dans l'éditeur pour insérer du Markdown
@@ -36,7 +36,7 @@
- ✨ Fonctionnalités
+ Fonctionnalités
@@ -62,13 +62,13 @@
- 💡 Astuce : Cliquez sur une note dans l'arborescence pour commencer à éditer
+ Astuce : Cliquez sur une note dans l'arborescence pour commencer à éditer
- ⌨️ Raccourcis clavier
+ Raccourcis clavier
- 💡 Sur Mac, utilisez Cmd au lieu de Ctrl
+ Sur Mac, utilisez Cmd au lieu de Ctrl
\ No newline at end of file
diff --git a/templates/daily-calendar.html b/templates/daily-calendar.html
index 4e71df2..1571b88 100644
--- a/templates/daily-calendar.html
+++ b/templates/daily-calendar.html
@@ -57,7 +57,7 @@
data-i18n="calendar.today"
title="Ouvrir la note du jour (Ctrl/Cmd+D)"
style="flex: 1; padding: 0.5rem; font-size: 0.85rem;">
- 📅 Aujourd'hui
+
Aujourd'hui
- 🗓️ Ce mois
+ Ce mois
diff --git a/templates/editor.html b/templates/editor.html
index 8999b00..d0f060f 100644
--- a/templates/editor.html
+++ b/templates/editor.html
@@ -19,7 +19,7 @@
{{if .IsHome}}
- 🔄 Actualiser
+ Actualiser
{{else}}
@@ -36,12 +36,12 @@
{{if .Backlinks}}
-
🔗 Référencé par
+
Référencé par
{{range .Backlinks}}
- 📄 {{.Title}}
+ {{.Title}}
{{end}}
@@ -54,6 +54,17 @@
Enregistrer
+
+ {{if .IsPublic}} Public {{else}} Private {{end}}
+
{{if .IsDir}}
- ⭐
+
{{.Icon}}
{{.Title}}
- ×
+
{{else}}
- ⭐
+
{{.Icon}}
{{.Title}}
- ×
+
{{end}}
@@ -32,7 +32,7 @@
Aucun favori.
- Cliquez sur ⭐ à côté d'une note ou d'un dossier pour l'ajouter.
+ Cliquez sur à côté d'une note ou d'un dossier pour l'ajouter.
{{end}}
diff --git a/templates/file-tree.html b/templates/file-tree.html
index 817670c..c2160d4 100644
--- a/templates/file-tree.html
+++ b/templates/file-tree.html
@@ -1,7 +1,7 @@
@@ -28,7 +28,7 @@
@@ -49,7 +49,7 @@
hx-swap="innerHTML"
hx-push-url="true"
draggable="true">
- 📄 {{.Name}}
+ {{.Name}}
{{end}}
diff --git a/templates/index.html b/templates/index.html
index 4bec0de..c81dd96 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -16,13 +16,15 @@
+
+