New search function et drag and drop clean

This commit is contained in:
2025-11-10 19:40:14 +01:00
parent d969b05ead
commit cd9a96c760
42 changed files with 2164 additions and 34 deletions

View File

@ -69,7 +69,7 @@ class FileTree {
// Setup drag events pour les fichiers // Setup drag events pour les fichiers
fileItems.forEach(file => { fileItems.forEach(file => {
file.addEventListener('dragstart', (e) => this.handleDragStart(e)); file.addEventListener('dragstart', (e) => this.handleDragStart(e, 'file'));
file.addEventListener('dragend', (e) => this.handleDragEnd(e)); file.addEventListener('dragend', (e) => this.handleDragEnd(e));
// Empêcher htmx de gérer le clic pendant le drag // Empêcher htmx de gérer le clic pendant le drag
file.addEventListener('click', (e) => { file.addEventListener('click', (e) => {
@ -79,49 +79,106 @@ class FileTree {
}, true); }, true);
}); });
// Setup drop zones pour les dossiers // Setup drag events pour les dossiers (headers)
folderItems.forEach(folder => { folderItems.forEach(folder => {
const header = folder.querySelector('.folder-header'); const header = folder.querySelector('.folder-header');
const isRoot = folder.dataset.isRoot === 'true';
// La racine ne doit pas être draggable
if (!isRoot) {
header.setAttribute('draggable', 'true');
header.addEventListener('dragstart', (e) => this.handleDragStart(e, 'folder'));
header.addEventListener('dragend', (e) => this.handleDragEnd(e));
}
// Tous les dossiers (y compris la racine) sont des drop zones
header.addEventListener('dragover', (e) => this.handleDragOver(e)); header.addEventListener('dragover', (e) => this.handleDragOver(e));
header.addEventListener('dragleave', (e) => this.handleDragLeave(e)); header.addEventListener('dragleave', (e) => this.handleDragLeave(e));
header.addEventListener('drop', (e) => this.handleDrop(e)); header.addEventListener('drop', (e) => this.handleDrop(e));
}); });
} }
handleDragStart(e) { handleDragStart(e, type) {
const item = e.target; const item = e.currentTarget;
item.classList.add('dragging'); item.classList.add('dragging');
const path = item.dataset.path; let path, name;
if (type === 'file') {
path = item.dataset.path;
name = path.split('/').pop();
} else if (type === 'folder') {
const folderItem = item.closest('.folder-item');
path = folderItem.dataset.path;
name = folderItem.querySelector('.folder-name').textContent.trim();
}
e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/plain', path); e.dataTransfer.setData('text/plain', path);
e.dataTransfer.setData('application/note-path', path); e.dataTransfer.setData('application/note-path', path);
e.dataTransfer.setData('application/note-type', type);
e.dataTransfer.setData('application/note-name', name);
// Stocker le chemin source pour validation
this.draggedPath = path;
this.draggedType = type;
console.log('Drag start:', { type, path, name });
} }
handleDragEnd(e) { handleDragEnd(e) {
const item = e.target; const item = e.currentTarget;
item.classList.remove('dragging'); item.classList.remove('dragging');
// Supprimer les highlights de tous les dossiers // Supprimer les highlights de tous les dossiers
document.querySelectorAll('.folder-item.drag-over').forEach(f => { document.querySelectorAll('.folder-item.drag-over').forEach(f => {
f.classList.remove('drag-over'); f.classList.remove('drag-over');
}); });
// Supprimer l'indicateur de destination
const indicator = document.getElementById('drag-destination-indicator');
if (indicator) {
indicator.remove();
}
this.draggedPath = null;
this.draggedType = null;
} }
handleDragOver(e) { handleDragOver(e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
e.dataTransfer.dropEffect = 'move';
const folderHeader = e.currentTarget; const folderHeader = e.currentTarget;
const folderItem = folderHeader.closest('.folder-item'); const folderItem = folderHeader.closest('.folder-item');
const targetPath = folderItem.dataset.path;
// Empêcher de déplacer un dossier dans lui-même ou dans ses enfants
if (this.draggedType === 'folder' && this.draggedPath) {
if (targetPath === this.draggedPath || targetPath.startsWith(this.draggedPath + '/')) {
e.dataTransfer.dropEffect = 'none';
folderItem.classList.remove('drag-over');
this.removeDestinationIndicator();
return;
}
}
e.dataTransfer.dropEffect = 'move';
if (folderItem && !folderItem.classList.contains('drag-over')) { if (folderItem && !folderItem.classList.contains('drag-over')) {
// Retirer la classe des autres dossiers
document.querySelectorAll('.folder-item.drag-over').forEach(f => {
if (f !== folderItem) {
f.classList.remove('drag-over');
}
});
folderItem.classList.add('drag-over'); folderItem.classList.add('drag-over');
// Afficher l'indicateur de destination
this.showDestinationIndicator(folderItem, targetPath);
} }
} }
handleDragLeave(e) { handleDragLeave(e) {
e.stopPropagation();
const folderHeader = e.currentTarget; const folderHeader = e.currentTarget;
const folderItem = folderHeader.closest('.folder-item'); const folderItem = folderHeader.closest('.folder-item');
@ -131,10 +188,39 @@ class FileTree {
e.clientY < rect.top || e.clientY >= rect.bottom) { e.clientY < rect.top || e.clientY >= rect.bottom) {
if (folderItem) { if (folderItem) {
folderItem.classList.remove('drag-over'); folderItem.classList.remove('drag-over');
this.removeDestinationIndicator();
} }
} }
} }
showDestinationIndicator(folderItem, targetPath) {
let indicator = document.getElementById('drag-destination-indicator');
if (!indicator) {
indicator = document.createElement('div');
indicator.id = 'drag-destination-indicator';
indicator.className = 'drag-destination-indicator';
document.body.appendChild(indicator);
}
const folderName = folderItem.querySelector('.folder-name').textContent.trim();
const isRoot = folderItem.dataset.isRoot === 'true';
const displayPath = isRoot ? 'notes/' : targetPath;
indicator.innerHTML = `
<span class="indicator-icon">📥</span>
<span class="indicator-text">Déplacer vers: <strong>${folderName}</strong></span>
<span class="indicator-path">${displayPath}</span>
`;
indicator.style.display = 'flex';
}
removeDestinationIndicator() {
const indicator = document.getElementById('drag-destination-indicator');
if (indicator) {
indicator.style.display = 'none';
}
}
handleDrop(e) { handleDrop(e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@ -143,40 +229,57 @@ class FileTree {
const folderItem = folderHeader.closest('.folder-item'); const folderItem = folderHeader.closest('.folder-item');
folderItem.classList.remove('drag-over'); folderItem.classList.remove('drag-over');
// Supprimer l'indicateur de destination
this.removeDestinationIndicator();
const sourcePath = e.dataTransfer.getData('application/note-path') || const sourcePath = e.dataTransfer.getData('application/note-path') ||
e.dataTransfer.getData('text/plain'); e.dataTransfer.getData('text/plain');
const sourceType = e.dataTransfer.getData('application/note-type');
const targetFolderPath = folderItem.dataset.path; const targetFolderPath = folderItem.dataset.path;
console.log('Drop event:', { console.log('Drop event:', {
sourcePath, sourcePath,
sourceType,
targetFolderPath, targetFolderPath,
dataTransfer: e.dataTransfer.types, dataTransfer: e.dataTransfer.types
folderItem: folderItem
}); });
if (!sourcePath || !targetFolderPath) { // Validation : sourcePath doit exister, targetFolderPath peut être vide (racine)
if (!sourcePath || targetFolderPath === undefined || targetFolderPath === null) {
console.error('Chemins invalides pour le drag & drop', { console.error('Chemins invalides pour le drag & drop', {
sourcePath, sourcePath,
targetFolderPath, targetFolderPath
folderItemDataset: folderItem.dataset
}); });
alert(`Erreur: source='${sourcePath}', destination='${targetFolderPath}'`); alert(`Erreur: source='${sourcePath}', destination='${targetFolderPath}'`);
return; return;
} }
// Ne pas déplacer si c'est le même dossier // Empêcher de déplacer un dossier dans lui-même ou dans ses enfants
if (sourceType === 'folder') {
if (targetFolderPath === sourcePath || targetFolderPath.startsWith(sourcePath + '/')) {
alert('Impossible de déplacer un dossier dans lui-même ou dans un de ses sous-dossiers');
return;
}
}
// Ne pas déplacer si c'est déjà dans le même dossier parent
const sourceDir = sourcePath.includes('/') ? const sourceDir = sourcePath.includes('/') ?
sourcePath.substring(0, sourcePath.lastIndexOf('/')) : ''; sourcePath.substring(0, sourcePath.lastIndexOf('/')) : '';
if (sourceDir === targetFolderPath) { if (sourceDir === targetFolderPath) {
console.log('Déjà dans le même dossier parent, rien à faire');
return; return;
} }
// Extraire le nom du fichier // Extraire le nom du fichier/dossier
const fileName = sourcePath.includes('/') ? const itemName = sourcePath.includes('/') ?
sourcePath.substring(sourcePath.lastIndexOf('/') + 1) : sourcePath.substring(sourcePath.lastIndexOf('/') + 1) :
sourcePath; sourcePath;
const destinationPath = targetFolderPath + '/' + fileName;
// Construire le chemin de destination
// Si targetFolderPath est vide (racine), ne pas ajouter de slash
const destinationPath = targetFolderPath === '' ? itemName : targetFolderPath + '/' + itemName;
console.log(`Déplacement: ${sourcePath}${destinationPath}`);
this.moveFile(sourcePath, destinationPath); this.moveFile(sourcePath, destinationPath);
} }

805
generate_notes.sh Executable file
View File

@ -0,0 +1,805 @@
#!/bin/bash
# Fonction pour créer une note avec front matter
create_note() {
local path="$1"
local title="$2"
local tags="$3"
local content="$4"
local date=$(date +%d-%m-%Y)
local time=$(date +%d-%m-%Y:%H:%M)
cat > "$path" << NOTEEOF
---
title: "$title"
date: "$date"
last_modified: "$time"
tags: [$tags]
---
$content
NOTEEOF
}
# Créer la structure de dossiers
mkdir -p projets/{backend,frontend,mobile}
mkdir -p meetings/2025
mkdir -p documentation/{api,guides}
mkdir -p ideas
mkdir -p tasks
mkdir -p research/{ai,tech,design}
mkdir -p personal
mkdir -p archive
echo "Dossiers créés..."
# Notes dans projets/backend
create_note "projets/backend/api-design.md" "API Design" '"projet", "backend", "api"' \
"# API Design
## Architecture REST
Notre API suit les principes REST avec les endpoints suivants:
- \`GET /api/v1/notes\` - Liste toutes les notes
- \`GET /api/v1/notes/{path}\` - Récupère une note
- \`PUT /api/v1/notes/{path}\` - Crée/met à jour une note
- \`DELETE /api/v1/notes/{path}\` - Supprime une note
## Authentification
Pour l'instant, pas d'authentification. À implémenter avec JWT.
## Rate Limiting
À considérer pour la production."
create_note "projets/backend/database-schema.md" "Database Schema" '"projet", "backend", "database"' \
"# Database Schema
## Indexer
L'indexer maintient une structure en mémoire:
\`\`\`go
type Indexer struct {
tags map[string][]string
docs map[string]*Document
mu sync.RWMutex
}
\`\`\`
## Performance
- Indexation en O(n) au démarrage
- Recherche en O(1) pour les tags
- Re-indexation incrémentale avec fsnotify"
create_note "projets/backend/deployment.md" "Deployment Strategy" '"projet", "backend", "devops"' \
"# Deployment Strategy
## Production
1. Compiler le binaire Go
2. Copier les fichiers statiques
3. Configurer nginx comme reverse proxy
4. Systemd pour gérer le service
## Docker
À créer un Dockerfile pour faciliter le déploiement.
\`\`\`dockerfile
FROM golang:1.22 AS builder
WORKDIR /app
COPY . .
RUN go build -o server ./cmd/server
\`\`\`"
# Notes dans projets/frontend
create_note "projets/frontend/codemirror-integration.md" "CodeMirror Integration" '"projet", "frontend", "editor"' \
"# CodeMirror 6 Integration
## Configuration
Nous utilisons CodeMirror 6 avec:
- \`@codemirror/lang-markdown\` pour le Markdown
- \`@codemirror/theme-one-dark\` pour le thème
- \`@codemirror/basic-setup\` pour les fonctionnalités de base
## Slash Commands
Système de commandes rapides avec \`/\`:
- /h1, /h2, /h3 - Titres
- /date - Date actuelle
- /table - Tableau
- /code - Bloc de code
## Auto-save
Déclenché après 2 secondes d'inactivité."
create_note "projets/frontend/vite-build.md" "Vite Build Process" '"projet", "frontend", "build"' \
"# Vite Build Process
## Structure
\`\`\`
frontend/
├── src/
│ ├── main.js
│ ├── editor.js
│ ├── file-tree.js
│ └── ui.js
├── vite.config.js
└── package.json
\`\`\`
## Build
\`npm run build\` génère:
- \`project-notes-frontend.es.js\` (ES modules)
- \`project-notes-frontend.umd.js\` (UMD)
## Watch Mode
\`npm run build -- --watch\` pour le dev."
create_note "projets/frontend/drag-and-drop.md" "Drag and Drop System" '"projet", "frontend", "ux"' \
"# Drag and Drop System
## Fonctionnalités
- Déplacer fichiers entre dossiers
- Déplacer dossiers entre dossiers
- Zone de drop racine
- Indicateur visuel de destination
## Implémentation
Utilise l'API HTML5 Drag & Drop:
- \`dragstart\` / \`dragend\`
- \`dragover\` / \`dragleave\`
- \`drop\`
## Validations
- Impossible de déplacer un dossier dans lui-même
- Impossible de déplacer la racine"
# Notes dans projets/mobile
create_note "projets/mobile/responsive-design.md" "Responsive Design" '"projet", "mobile", "css"' \
"# Responsive Design
## Media Queries
\`\`\`css
@media (max-width: 768px) {
/* Tablettes */
}
@media (max-width: 480px) {
/* Smartphones */
}
\`\`\`
## Mobile-First
- Sidebar masquée par défaut
- Preview-only mode
- Touch-friendly buttons"
create_note "projets/mobile/pwa.md" "Progressive Web App" '"projet", "mobile", "pwa"' \
"# PWA Features
## À implémenter
1. Service Worker
2. Manifest.json
3. Offline support
4. Install prompt
## Avantages
- Fonctionne offline
- Installable sur mobile
- Notifications push possibles"
# Notes dans meetings
create_note "meetings/2025/sprint-planning.md" "Sprint Planning January" '"meeting", "planning"' \
"# Sprint Planning - Janvier 2025
## Participants
- Équipe Dev
- Product Owner
- Scrum Master
## Objectifs
1. Améliorer le drag & drop
2. Ajouter l'API REST
3. Search modal avec Ctrl+K
## Vélocité
20 story points pour ce sprint.
## Risques
- Complexité du drag & drop de dossiers
- Tests E2E à mettre en place"
create_note "meetings/2025/retrospective.md" "Sprint Retrospective" '"meeting", "retro"' \
"# Retrospective - Sprint 1
## What went well ✅
- API REST implémentée rapidement
- Bonne collaboration
- Tests unitaires en place
## What to improve ⚠️
- Documentation à jour
- CI/CD pipeline
- Code reviews plus rapides
## Action items
1. Créer CONTRIBUTING.md
2. Setup GitHub Actions
3. Daily standups à 10h"
create_note "meetings/client-feedback.md" "Client Feedback Session" '"meeting", "client"' \
"# Client Feedback - Session 1
## Points positifs
- Interface épurée et rapide
- Édition Markdown fluide
- Recherche efficace
## Demandes
1. Export PDF des notes
2. Partage de notes par lien
3. Mode collaboratif
4. Dark/Light theme toggle
## Priorités
Focus sur l'export PDF pour la v1.1"
# Notes dans documentation/api
create_note "documentation/api/endpoints.md" "API Endpoints Reference" '"documentation", "api"' \
"# API Endpoints
## Notes
### List Notes
\`\`\`
GET /api/v1/notes
\`\`\`
Returns array of all notes.
### Get Note
\`\`\`
GET /api/v1/notes/{path}
Accept: application/json | text/markdown
\`\`\`
### Create/Update Note
\`\`\`
PUT /api/v1/notes/{path}
Content-Type: application/json
\`\`\`
### Delete Note
\`\`\`
DELETE /api/v1/notes/{path}
\`\`\`
## Examples
See API.md for complete examples."
create_note "documentation/api/authentication.md" "Authentication Guide" '"documentation", "api", "security"' \
"# Authentication
## Current Status
⚠️ No authentication currently implemented.
## Future Implementation
### JWT Tokens
\`\`\`
POST /api/auth/login
{
\"username\": \"user\",
\"password\": \"pass\"
}
Response:
{
\"token\": \"eyJhbGc...\"
}
\`\`\`
### Bearer Token
\`\`\`
Authorization: Bearer eyJhbGc...
\`\`\`
## Security
- HTTPS only in production
- Reverse proxy with nginx
- Rate limiting"
# Notes dans documentation/guides
create_note "documentation/guides/getting-started.md" "Getting Started Guide" '"documentation", "guide", "tutorial"' \
"# Getting Started
## Installation
1. Clone the repo
2. Install Go 1.22+
3. Install Node.js dependencies
4. Build frontend
5. Run server
\`\`\`bash
git clone https://github.com/user/project-notes.git
cd project-notes
cd frontend && npm install && npm run build
cd ..
go run ./cmd/server
\`\`\`
## First Steps
1. Create a note
2. Add tags
3. Search with Ctrl+K
4. Organize with folders"
create_note "documentation/guides/markdown-syntax.md" "Markdown Syntax Guide" '"documentation", "guide", "markdown"' \
"# Markdown Syntax
## Headers
\`\`\`markdown
# H1
## H2
### H3
\`\`\`
## Emphasis
**bold** and *italic*
## Lists
- Item 1
- Item 2
- Nested
## Code
Inline \`code\` and blocks:
\`\`\`python
def hello():
print('Hello')
\`\`\`
## Tables
| Column | Column |
|--------|--------|
| Data | Data |"
# Notes dans ideas
create_note "ideas/mobile-app.md" "Native Mobile App" '"idea", "mobile"' \
"# 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"
create_note "ideas/ai-assistant.md" "AI Writing Assistant" '"idea", "ai"' \
"# AI Writing Assistant
## Vision
Intégrer un assistant IA pour:
- Suggestions d'écriture
- Résumés automatiques
- Tags suggestions
- Recherche sémantique
## APIs
- OpenAI GPT-4
- Anthropic Claude
- Local LLM avec Ollama
## Privacy
Données restent locales, API optionnelle."
create_note "ideas/collaboration.md" "Real-time Collaboration" '"idea", "collaboration"' \
"# 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"
# Notes dans tasks
create_note "tasks/backlog.md" "Product Backlog" '"task", "planning"' \
"# Product Backlog
## High Priority
- [ ] Export notes to PDF
- [ ] Bulk operations (delete, move)
- [ ] Tags management page
- [ ] Keyboard shortcuts documentation
## Medium Priority
- [ ] Note templates
- [ ] Trash/Recycle bin
- [ ] Note history/versions
- [ ] Full-text search improvements
## Low Priority
- [ ] Themes customization
- [ ] Plugin system
- [ ] Graph view of notes links"
create_note "tasks/bugs.md" "Known Bugs" '"task", "bug"' \
"# Known Bugs
## Critical
None currently! 🎉
## Medium
- [ ] Search doesn't highlight in preview
- [ ] Drag over nested folders can be glitchy
- [ ] Mobile: sidebar animation stutters
## Low
- [ ] File tree doesn't remember expanded state
- [ ] Tags with special chars break search
- [ ] Long filenames overflow in sidebar
## Fixed
- [x] Slash commands not working consistently
- [x] Drag and drop to root not working"
# Notes dans research/ai
create_note "research/ai/semantic-search.md" "Semantic Search Research" '"research", "ai", "search"' \
"# Semantic Search
## Current Search
Keyword-based with scoring.
## Semantic Search
Use embeddings for similarity:
- OpenAI embeddings API
- Local models (sentence-transformers)
- Vector database (Pinecone, Weaviate)
## Implementation
1. Generate embeddings for all notes
2. Store in vector DB
3. Query with user search
4. Return top-k similar
## Cost Analysis
OpenAI: $0.0001 per 1K tokens
Local: Free but slower"
create_note "research/ai/auto-tagging.md" "Automatic Tagging" '"research", "ai", "nlp"' \
"# Automatic Tagging
## Goal
Suggest tags based on note content.
## Approaches
### Rule-based
- Keyword extraction
- TF-IDF
### ML-based
- Zero-shot classification
- Fine-tuned model
### Hybrid
- Combine both approaches
## Training Data
Use existing notes with tags as training set."
# Notes dans research/tech
create_note "research/tech/go-performance.md" "Go Performance Optimization" '"research", "tech", "performance"' \
"# Go Performance
## Current Bottlenecks
- Full re-index on file changes
- No caching of parsed front matter
## Optimizations
### Incremental Indexing
Only re-parse changed files.
### Caching
\`\`\`go
type Cache struct {
entries map[string]*CachedEntry
mu sync.RWMutex
}
\`\`\`
### Profiling
\`\`\`bash
go test -cpuprofile=cpu.prof
go tool pprof cpu.prof
\`\`\`"
create_note "research/tech/websockets.md" "WebSockets for Live Updates" '"research", "tech", "websocket"' \
"# WebSockets
## Use Cases
- Live file tree updates
- Real-time collaboration
- Presence indicators
## Libraries
- \`gorilla/websocket\`
- \`nhooyr.io/websocket\`
## Architecture
\`\`\`
Client <-> WebSocket <-> Hub <-> Indexer
\`\`\`
## Broadcasting
\`\`\`go
type Hub struct {
clients map[*Client]bool
broadcast chan []byte
}
\`\`\`"
# Notes dans research/design
create_note "research/design/ui-inspiration.md" "UI Design Inspiration" '"research", "design", "ui"' \
"# UI Inspiration
## Apps to Study
- Notion - Clean, minimal
- Obsidian - Graph view
- Bear - Beautiful typography
- Craft - Smooth animations
## Design Systems
- Material Design 3
- Apple HIG
- Tailwind components
## Colors
Current: Material Darker
Consider:
- Nord theme
- Dracula
- Catppuccin"
create_note "research/design/typography.md" "Typography Research" '"research", "design", "typography"' \
"# Typography
## Current Fonts
- System fonts for UI
- Fira Code for code
## Alternatives
### Sans-serif
- Inter
- Poppins
- Public Sans
### Monospace
- JetBrains Mono
- Cascadia Code
- Source Code Pro
## Readability
- Line height: 1.6
- Max width: 65ch
- Font size: 16px base"
# Notes dans personal
create_note "personal/learning-goals.md" "2025 Learning Goals" '"personal", "learning"' \
"# Learning Goals 2025
## Technical
- [ ] Master Go concurrency patterns
- [ ] Learn Rust basics
- [ ] Deep dive into databases
- [ ] System design courses
## Soft Skills
- [ ] Technical writing
- [ ] Public speaking
- [ ] Mentoring
## Books to Read
1. Designing Data-Intensive Applications
2. The Pragmatic Programmer
3. Clean Architecture"
create_note "personal/book-notes.md" "Book Notes" '"personal", "notes", "books"' \
"# Book Notes
## Currently Reading
**Atomic Habits** by James Clear
Key takeaways:
- 1% improvement daily = 37x better in a year
- Identity-based habits
- Environment design
## Want to Read
- Deep Work - Cal Newport
- The Mom Test - Rob Fitzpatrick
- Shape Up - Basecamp"
# Notes dans archive
create_note "archive/old-ideas.md" "Archived Ideas" '"archive", "ideas"' \
"# Archived Ideas
Ideas that didn't make the cut:
## WYSIWYG Editor
Too complex, Markdown is better.
## Desktop App
Web app is sufficient.
## Blockchain Integration
No real use case.
## Gamification
Not aligned with minimalist approach."
# Quelques notes à la racine
create_note "welcome.md" "Welcome" '"default"' \
"# Welcome to Project Notes
This is your personal note-taking app.
## Quick Start
1. Press **Ctrl/Cmd+K** to search
2. Click **✨ Nouvelle note** to create
3. Use **/** for quick Markdown commands
## Features
- **Fast** - Go backend, instant search
- **Simple** - Just Markdown files
- **Organized** - Folders, tags, drag & drop
- **Beautiful** - Dark theme, live preview
Enjoy! 📝"
create_note "todo.md" "Quick TODO List" '"task", "todo"' \
"# TODO
## Today
- [x] Fix drag & drop
- [x] Add root drop zone
- [ ] Write documentation
- [ ] Deploy to production
## This Week
- [ ] Add export feature
- [ ] Improve mobile experience
- [ ] Write blog post
## Someday
- [ ] Collaboration features
- [ ] Mobile app
- [ ] Plugin system"
create_note "scratch.md" "Scratch Pad" '"default"' \
"# Scratch Pad
Random thoughts and quick notes...
## Ideas
- Maybe add a daily note feature?
- Graph view of linked notes
- Vim mode for power users
## Links
- https://example.com
- https://github.com/user/repo
## Code Snippet
\`\`\`javascript
const hello = () => {
console.log('Hello World');
};
\`\`\`"
echo "✅ Structure créée avec succès!"
echo ""
echo "📊 Statistiques:"
echo "- Dossiers: $(find . -type d | wc -l)"
echo "- Notes: $(find . -name '*.md' | wc -l)"
echo "- Tags uniques: $(grep -h "^tags:" **/*.md 2>/dev/null | sort -u | wc -l)"

View File

@ -266,7 +266,6 @@ func (h *Handler) generateHomeMarkdown() string {
// En-tête // En-tête
sb.WriteString("# 📚 Index des Notes\n\n") sb.WriteString("# 📚 Index des Notes\n\n")
sb.WriteString("_Mise à jour automatique • " + time.Now().Format("02/01/2006 à 15:04") + "_\n\n") sb.WriteString("_Mise à jour automatique • " + time.Now().Format("02/01/2006 à 15:04") + "_\n\n")
sb.WriteString("---\n\n")
// Construire l'arborescence // Construire l'arborescence
tree, err := h.buildFileTree() tree, err := h.buildFileTree()
@ -278,7 +277,16 @@ func (h *Handler) generateHomeMarkdown() string {
// Compter le nombre de notes // Compter le nombre de notes
noteCount := h.countNotes(tree) noteCount := h.countNotes(tree)
// Section des tags (en premier)
h.generateTagsSection(&sb)
// Statistiques
sb.WriteString(fmt.Sprintf("**%d note(s) au total**\n\n", noteCount)) sb.WriteString(fmt.Sprintf("**%d note(s) au total**\n\n", noteCount))
sb.WriteString("---\n\n")
// Titre de l'arborescence
sb.WriteString("## 📂 Toutes les notes\n\n")
// Générer l'arborescence en Markdown // Générer l'arborescence en Markdown
h.generateMarkdownTree(&sb, tree, 0) h.generateMarkdownTree(&sb, tree, 0)
@ -286,6 +294,29 @@ func (h *Handler) generateHomeMarkdown() string {
return sb.String() return sb.String()
} }
// generateTagsSection génère la section des tags avec comptage
func (h *Handler) generateTagsSection(sb *strings.Builder) {
tags := h.idx.GetAllTagsWithCount()
if len(tags) == 0 {
return
}
sb.WriteString("## 🏷️ Tags\n\n")
sb.WriteString("<div class=\"tags-cloud\">\n")
for _, tc := range tags {
// Créer un lien HTML discret et fonctionnel
sb.WriteString(fmt.Sprintf(
`<a href="#" class="tag-item" hx-get="/api/search?query=tag:%s" hx-target="#search-results" hx-swap="innerHTML"><kbd class="tag-badge">#%s</kbd> <mark class="tag-count">%d</mark></a>`,
tc.Tag, tc.Tag, tc.Count,
))
sb.WriteString("\n")
}
sb.WriteString("</div>\n\n")
}
// countNotes compte le nombre de fichiers .md dans l'arborescence // countNotes compte le nombre de fichiers .md dans l'arborescence
func (h *Handler) countNotes(node *TreeNode) int { func (h *Handler) countNotes(node *TreeNode) int {
count := 0 count := 0

View File

@ -638,3 +638,33 @@ func extractFrontMatter(path string) (frontMatter, error) {
fm, _, err := ExtractFrontMatterAndBody(path) fm, _, err := ExtractFrontMatterAndBody(path)
return frontMatter{Tags: fm.Tags}, err return frontMatter{Tags: fm.Tags}, err
} }
// TagCount représente un tag avec son nombre d'utilisations
type TagCount struct {
Tag string
Count int
}
// GetAllTagsWithCount retourne tous les tags avec leur nombre d'utilisations, triés par popularité
func (i *Indexer) GetAllTagsWithCount() []TagCount {
i.mu.RLock()
defer i.mu.RUnlock()
result := make([]TagCount, 0, len(i.tags))
for tag, files := range i.tags {
result = append(result, TagCount{
Tag: tag,
Count: len(files),
})
}
// Trier par popularité (nombre décroissant), puis par nom alphabétique
sort.Slice(result, func(a, b int) bool {
if result[a].Count == result[b].Count {
return result[a].Tag < result[b].Tag
}
return result[a].Count > result[b].Count
})
return result
}

View File

@ -0,0 +1,22 @@
---
title: "Archived Ideas"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["archive", "ideas"]
---
# Archived Ideas
Ideas that didn't make the cut:
## WYSIWYG Editor
Too complex, Markdown is better.
## Desktop App
Web app is sufficient.
## Blockchain Integration
No real use case.
## Gamification
Not aligned with minimalist approach.

View File

@ -0,0 +1,41 @@
---
title: "Authentication Guide"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["documentation", "api", "security"]
---
# Authentication
## Current Status
⚠️ No authentication currently implemented.
## Future Implementation
### JWT Tokens
```
POST /api/auth/login
{
"username": "user",
"password": "pass"
}
Response:
{
"token": "eyJhbGc..."
}
```
### Bearer Token
```
Authorization: Bearer eyJhbGc...
```
## Security
- HTTPS only in production
- Reverse proxy with nginx
- Rate limiting

View File

@ -0,0 +1,38 @@
---
title: "API Endpoints Reference"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["documentation", "api"]
---
# API Endpoints
## Notes
### List Notes
```
GET /api/v1/notes
```
Returns array of all notes.
### Get Note
```
GET /api/v1/notes/{path}
Accept: application/json | text/markdown
```
### Create/Update Note
```
PUT /api/v1/notes/{path}
Content-Type: application/json
```
### Delete Note
```
DELETE /api/v1/notes/{path}
```
## Examples
See API.md for complete examples.

View File

@ -0,0 +1,31 @@
---
title: "Getting Started Guide"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["documentation", "guide", "tutorial"]
---
# Getting Started
## Installation
1. Clone the repo
2. Install Go 1.22+
3. Install Node.js dependencies
4. Build frontend
5. Run server
```bash
git clone https://github.com/user/project-notes.git
cd project-notes
cd frontend && npm install && npm run build
cd ..
go run ./cmd/server
```
## First Steps
1. Create a note
2. Add tags
3. Search with Ctrl+K
4. Organize with folders

View File

@ -0,0 +1,41 @@
---
title: "Markdown Syntax Guide"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["documentation", "guide", "markdown"]
---
# Markdown Syntax
## Headers
```markdown
# H1
## H2
### H3
```
## Emphasis
**bold** and *italic*
## Lists
- Item 1
- Item 2
- Nested
## Code
Inline `code` and blocks:
```python
def hello():
print('Hello')
```
## Tables
| Column | Column |
|--------|--------|
| Data | Data |

View File

@ -0,0 +1,26 @@
---
title: "AI Writing Assistant"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["idea", "ai"]
---
# AI Writing Assistant
## Vision
Intégrer un assistant IA pour:
- Suggestions d'écriture
- Résumés automatiques
- Tags suggestions
- Recherche sémantique
## APIs
- OpenAI GPT-4
- Anthropic Claude
- Local LLM avec Ollama
## Privacy
Données restent locales, API optionnelle.

View File

@ -0,0 +1,24 @@
---
title: "Real-time Collaboration"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["idea", "collaboration"]
---
# 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

30
notes/ideas/mobile-app.md Normal file
View File

@ -0,0 +1,30 @@
---
title: "Native Mobile App"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["idea", "mobile"]
---
# 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

View File

@ -0,0 +1,26 @@
---
title: "Sprint Retrospective"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["meeting", "retro"]
---
# Retrospective - Sprint 1
## What went well ✅
- API REST implémentée rapidement
- Bonne collaboration
- Tests unitaires en place
## What to improve ⚠️
- Documentation à jour
- CI/CD pipeline
- Code reviews plus rapides
## Action items
1. Créer CONTRIBUTING.md
2. Setup GitHub Actions
3. Daily standups à 10h

View File

@ -0,0 +1,28 @@
---
title: "Sprint Planning January"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["meeting", "planning"]
---
# Sprint Planning - Janvier 2025
## Participants
- Équipe Dev
- Product Owner
- Scrum Master
## Objectifs
1. Améliorer le drag & drop
2. Ajouter l'API REST
3. Search modal avec Ctrl+K
## Vélocité
20 story points pour ce sprint.
## Risques
- Complexité du drag & drop de dossiers
- Tests E2E à mettre en place

View File

@ -0,0 +1,25 @@
---
title: "Client Feedback Session"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["meeting", "client"]
---
# Client Feedback - Session 1
## Points positifs
- Interface épurée et rapide
- Édition Markdown fluide
- Recherche efficace
## Demandes
1. Export PDF des notes
2. Partage de notes par lien
3. Mode collaboratif
4. Dark/Light theme toggle
## Priorités
Focus sur l'export PDF pour la v1.1

View File

@ -0,0 +1,23 @@
---
title: "Book Notes"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["personal", "notes", "books"]
---
# Book Notes
## Currently Reading
**Atomic Habits** by James Clear
Key takeaways:
- 1% improvement daily = 37x better in a year
- Identity-based habits
- Environment design
## Want to Read
- Deep Work - Cal Newport
- The Mom Test - Rob Fitzpatrick
- Shape Up - Basecamp

View File

@ -0,0 +1,27 @@
---
title: "2025 Learning Goals"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["personal", "learning"]
---
# Learning Goals 2025
## Technical
- [ ] Master Go concurrency patterns
- [ ] Learn Rust basics
- [ ] Deep dive into databases
- [ ] System design courses
## Soft Skills
- [ ] Technical writing
- [ ] Public speaking
- [ ] Mentoring
## Books to Read
1. Designing Data-Intensive Applications
2. The Pragmatic Programmer
3. Clean Architecture

View File

@ -0,0 +1,25 @@
---
title: "API Design"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["projet", "backend", "api"]
---
# API Design
## Architecture REST
Notre API suit les principes REST avec les endpoints suivants:
- `GET /api/v1/notes` - Liste toutes les notes
- `GET /api/v1/notes/{path}` - Récupère une note
- `PUT /api/v1/notes/{path}` - Crée/met à jour une note
- `DELETE /api/v1/notes/{path}` - Supprime une note
## Authentification
Pour l'instant, pas d'authentification. À implémenter avec JWT.
## Rate Limiting
À considérer pour la production.

View File

@ -0,0 +1,26 @@
---
title: "Database Schema"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["projet", "backend", "database"]
---
# Database Schema
## Indexer
L'indexer maintient une structure en mémoire:
```go
type Indexer struct {
tags map[string][]string
docs map[string]*Document
mu sync.RWMutex
}
```
## Performance
- Indexation en O(n) au démarrage
- Recherche en O(1) pour les tags
- Re-indexation incrémentale avec fsnotify

View File

@ -0,0 +1,26 @@
---
title: "Deployment Strategy"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["projet", "backend", "devops"]
---
# Deployment Strategy
## Production
1. Compiler le binaire Go
2. Copier les fichiers statiques
3. Configurer nginx comme reverse proxy
4. Systemd pour gérer le service
## Docker
À créer un Dockerfile pour faciliter le déploiement.
```dockerfile
FROM golang:1.22 AS builder
WORKDIR /app
COPY . .
RUN go build -o server ./cmd/server
```

View File

@ -0,0 +1,27 @@
---
title: "CodeMirror Integration"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["projet", "frontend", "editor"]
---
# CodeMirror 6 Integration
## Configuration
Nous utilisons CodeMirror 6 avec:
- `@codemirror/lang-markdown` pour le Markdown
- `@codemirror/theme-one-dark` pour le thème
- `@codemirror/basic-setup` pour les fonctionnalités de base
## Slash Commands
Système de commandes rapides avec `/`:
- /h1, /h2, /h3 - Titres
- /date - Date actuelle
- /table - Tableau
- /code - Bloc de code
## Auto-save
Déclenché après 2 secondes d'inactivité.

View File

@ -0,0 +1,27 @@
---
title: "Drag and Drop System"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["projet", "frontend", "ux"]
---
# Drag and Drop System
## Fonctionnalités
- Déplacer fichiers entre dossiers
- Déplacer dossiers entre dossiers
- Zone de drop racine
- Indicateur visuel de destination
## Implémentation
Utilise l'API HTML5 Drag & Drop:
- `dragstart` / `dragend`
- `dragover` / `dragleave`
- `drop`
## Validations
- Impossible de déplacer un dossier dans lui-même
- Impossible de déplacer la racine

View File

@ -0,0 +1,31 @@
---
title: "Vite Build Process"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["projet", "frontend", "build"]
---
# Vite Build Process
## Structure
```
frontend/
├── src/
│ ├── main.js
│ ├── editor.js
│ ├── file-tree.js
│ └── ui.js
├── vite.config.js
└── package.json
```
## Build
`npm run build` génère:
- `project-notes-frontend.es.js` (ES modules)
- `project-notes-frontend.umd.js` (UMD)
## Watch Mode
`npm run build -- --watch` pour le dev.

View File

@ -0,0 +1,21 @@
---
title: "Progressive Web App"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["projet", "mobile", "pwa"]
---
# PWA Features
## À implémenter
1. Service Worker
2. Manifest.json
3. Offline support
4. Install prompt
## Avantages
- Fonctionne offline
- Installable sur mobile
- Notifications push possibles

View File

@ -0,0 +1,26 @@
---
title: "Responsive Design"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["projet", "mobile", "css"]
---
# Responsive Design
## Media Queries
```css
@media (max-width: 768px) {
/* Tablettes */
}
@media (max-width: 480px) {
/* Smartphones */
}
```
## Mobile-First
- Sidebar masquée par défaut
- Preview-only mode
- Touch-friendly buttons

View File

@ -0,0 +1,29 @@
---
title: "Automatic Tagging"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["research", "ai", "nlp"]
---
# Automatic Tagging
## Goal
Suggest tags based on note content.
## Approaches
### Rule-based
- Keyword extraction
- TF-IDF
### ML-based
- Zero-shot classification
- Fine-tuned model
### Hybrid
- Combine both approaches
## Training Data
Use existing notes with tags as training set.

View File

@ -0,0 +1,31 @@
---
title: "Semantic Search Research"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["research", "ai", "search"]
---
# Semantic Search
## Current Search
Keyword-based with scoring.
## Semantic Search
Use embeddings for similarity:
- OpenAI embeddings API
- Local models (sentence-transformers)
- Vector database (Pinecone, Weaviate)
## Implementation
1. Generate embeddings for all notes
2. Store in vector DB
3. Query with user search
4. Return top-k similar
## Cost Analysis
OpenAI: /tmp/generate_notes.sh.0001 per 1K tokens
Local: Free but slower

View File

@ -0,0 +1,31 @@
---
title: "Typography Research"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["research", "design", "typography"]
---
# Typography
## Current Fonts
- System fonts for UI
- Fira Code for code
## Alternatives
### Sans-serif
- Inter
- Poppins
- Public Sans
### Monospace
- JetBrains Mono
- Cascadia Code
- Source Code Pro
## Readability
- Line height: 1.6
- Max width: 65ch
- Font size: 16px base

View File

@ -0,0 +1,29 @@
---
title: "UI Design Inspiration"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["research", "design", "ui"]
---
# UI Inspiration
## Apps to Study
- Notion - Clean, minimal
- Obsidian - Graph view
- Bear - Beautiful typography
- Craft - Smooth animations
## Design Systems
- Material Design 3
- Apple HIG
- Tailwind components
## Colors
Current: Material Darker
Consider:
- Nord theme
- Dracula
- Catppuccin

View File

@ -0,0 +1,32 @@
---
title: "Go Performance Optimization"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["research", "tech", "performance"]
---
# Go Performance
## Current Bottlenecks
- Full re-index on file changes
- No caching of parsed front matter
## Optimizations
### Incremental Indexing
Only re-parse changed files.
### Caching
```go
type Cache struct {
entries map[string]*CachedEntry
mu sync.RWMutex
}
```
### Profiling
```bash
go test -cpuprofile=cpu.prof
go tool pprof cpu.prof
```

View File

@ -0,0 +1,34 @@
---
title: "WebSockets for Live Updates"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["research", "tech", "websocket"]
---
# WebSockets
## Use Cases
- Live file tree updates
- Real-time collaboration
- Presence indicators
## Libraries
- `gorilla/websocket`
- `nhooyr.io/websocket`
## Architecture
```
Client <-> WebSocket <-> Hub <-> Indexer
```
## Broadcasting
```go
type Hub struct {
clients map[*Client]bool
broadcast chan []byte
}
```

27
notes/scratch.md Normal file
View File

@ -0,0 +1,27 @@
---
title: "Scratch Pad"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["default"]
---
# Scratch Pad
Random thoughts and quick notes...
## Ideas
- Maybe add a daily note feature?
- Graph view of linked notes
- Vim mode for power users
## Links
- https://example.com
- https://github.com/user/repo
## Code Snippet
```javascript
const hello = () => {
console.log('Hello World');
};
```

28
notes/tasks/backlog.md Normal file
View File

@ -0,0 +1,28 @@
---
title: "Product Backlog"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["task", "planning"]
---
# Product Backlog
## High Priority
- [ ] Export notes to PDF
- [ ] Bulk operations (delete, move)
- [ ] Tags management page
- [ ] Keyboard shortcuts documentation
## Medium Priority
- [ ] Note templates
- [ ] Trash/Recycle bin
- [ ] Note history/versions
- [ ] Full-text search improvements
## Low Priority
- [ ] Themes customization
- [ ] Plugin system
- [ ] Graph view of notes links

29
notes/tasks/bugs.md Normal file
View File

@ -0,0 +1,29 @@
---
title: "Known Bugs"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["task", "bug"]
---
# Known Bugs
## Critical
None currently! 🎉
## Medium
- [ ] Search doesn't highlight in preview
- [ ] Drag over nested folders can be glitchy
- [ ] Mobile: sidebar animation stutters
## Low
- [ ] File tree doesn't remember expanded state
- [ ] Tags with special chars break search
- [ ] Long filenames overflow in sidebar
## Fixed
- [x] Slash commands not working consistently
- [x] Drag and drop to root not working

24
notes/todo.md Normal file
View File

@ -0,0 +1,24 @@
---
title: "Quick TODO List"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["task", "todo"]
---
# TODO
## Today
- [x] Fix drag & drop
- [x] Add root drop zone
- [ ] Write documentation
- [ ] Deploy to production
## This Week
- [ ] Add export feature
- [ ] Improve mobile experience
- [ ] Write blog post
## Someday
- [ ] Collaboration features
- [ ] Mobile app
- [ ] Plugin system

25
notes/welcome.md Normal file
View File

@ -0,0 +1,25 @@
---
title: "Welcome"
date: "10-11-2025"
last_modified: "10-11-2025:19:21"
tags: ["default"]
---
# Welcome to Project Notes
This is your personal note-taking app.
## Quick Start
1. Press **Ctrl/Cmd+K** to search
2. Click **✨ Nouvelle note** to create
3. Use **/** for quick Markdown commands
## Features
- **Fast** - Go backend, instant search
- **Simple** - Just Markdown files
- **Organized** - Folders, tags, drag & drop
- **Beautiful** - Dark theme, live preview
Enjoy! 📝

View File

@ -1133,14 +1133,35 @@ body, html {
/* Drag and drop styles */ /* Drag and drop styles */
.file-item.dragging { .file-item.dragging {
opacity: 0.5; opacity: 0.4;
background: var(--bg-tertiary); background: var(--bg-tertiary);
cursor: grabbing;
}
.folder-header.dragging {
opacity: 0.4;
background: var(--bg-tertiary);
cursor: grabbing;
} }
.folder-item.drag-over .folder-header { .folder-item.drag-over .folder-header {
background: linear-gradient(135deg, var(--accent-blue), var(--accent-violet)); background: linear-gradient(135deg, var(--accent-blue), var(--accent-violet));
color: white; color: white;
box-shadow: var(--shadow-glow); box-shadow: var(--shadow-glow);
border: 2px solid var(--accent-blue);
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 { .file-item.drag-over {
@ -1149,6 +1170,109 @@ body, html {
box-shadow: var(--shadow-glow); box-shadow: var(--shadow-glow);
} }
/* 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-blue);
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-blue);
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 */
.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-blue), var(--accent-violet));
color: white;
border-color: var(--accent-blue);
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;
}
/* Folder creation button */ /* Folder creation button */
.folder-create-btn { .folder-create-btn {
background: var(--bg-tertiary); background: var(--bg-tertiary);
@ -1221,10 +1345,15 @@ body, html {
.folder-header { .folder-header {
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
padding: 0.5rem 0; padding: 0.4rem 0;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
transition: all var(--transition-fast);
}
.folder-header:hover {
color: var(--accent-blue);
} }
.folder-icon { .folder-icon {
@ -1236,7 +1365,7 @@ body, html {
} }
.file { .file {
padding: 0.5rem 0; padding: 0.3rem 0;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
@ -1244,30 +1373,37 @@ body, html {
.file-icon { .file-icon {
flex-shrink: 0; flex-shrink: 0;
opacity: 0.6;
transition: opacity var(--transition-fast);
} }
.file a { .file a {
color: var(--accent-blue); color: var(--text-primary);
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
word-break: break-word; word-break: break-word;
flex: 1; flex: 1;
font-size: 0.95rem;
transition: color var(--transition-fast);
} }
.file a:hover { .file a:hover {
color: var(--accent-blue-hover); color: var(--accent-blue);
text-decoration: underline; }
.file:hover .file-icon {
opacity: 1;
} }
/* Indentation levels - Desktop */ /* Indentation levels - Desktop */
.indent-level-1 { padding-left: 0; } .indent-level-1 { padding-left: 0; }
.indent-level-2 { padding-left: 1.5rem; } .indent-level-2 { padding-left: 0.5rem; }
.indent-level-3 { padding-left: 3rem; } .indent-level-3 { padding-left: 1rem; }
.indent-level-4 { padding-left: 4.5rem; } .indent-level-4 { padding-left: 1.5rem; }
.indent-level-5 { padding-left: 6rem; } .indent-level-5 { padding-left: 2rem; }
.indent-level-6 { padding-left: 7.5rem; } .indent-level-6 { padding-left: 2.5rem; }
.indent-level-7 { padding-left: 9rem; } .indent-level-7 { padding-left: 3rem; }
.indent-level-8 { padding-left: 10.5rem; } .indent-level-8 { padding-left: 3.5rem; }
/* ======================================== /* ========================================
RESPONSIVE DESIGN - Mobile & Tablet RESPONSIVE DESIGN - Mobile & Tablet
@ -1506,9 +1642,9 @@ body, html {
.indent-level-3 { padding-left: 1.5rem !important; } .indent-level-3 { padding-left: 1.5rem !important; }
.indent-level-4 { padding-left: 2.25rem !important; } .indent-level-4 { padding-left: 2.25rem !important; }
.indent-level-5 { padding-left: 3rem !important; } .indent-level-5 { padding-left: 3rem !important; }
.indent-level-6 { padding-left: 3.75rem !important; } .indent-level-6 { padding-left: 3.5rem !important; }
.indent-level-7 { padding-left: 4.5rem !important; } .indent-level-7 { padding-left: 4rem !important; }
.indent-level-8 { padding-left: 5.25rem !important; } .indent-level-8 { padding-left: 4.5rem !important; }
/* Les dossiers et fichiers */ /* Les dossiers et fichiers */
.folder, .folder,
@ -2044,3 +2180,107 @@ body, html {
.search-modal-results::-webkit-scrollbar-thumb:hover { .search-modal-results::-webkit-scrollbar-thumb:hover {
background: var(--text-muted); 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-blue);
}
.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-blue);
}
/* 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;
}
}

View File

@ -1,3 +1,14 @@
<!-- Zone de drop racine -->
<div class="root-drop-zone folder-item" data-path="" data-is-dir="true" data-is-root="true">
<div class="folder-header root-folder-header">
<span class="folder-icon">🏠</span>
<span class="folder-name">Racine</span>
<span class="root-hint">(notes/)</span>
</div>
</div>
<hr style="border: none; border-top: 1px solid var(--border-primary); margin: 0.75rem 0;">
{{if .Tree}} {{if .Tree}}
{{if .Tree.Children}} {{if .Tree.Children}}
{{template "tree-node" .Tree}} {{template "tree-node" .Tree}}