Add recemment modifié page accueil

This commit is contained in:
2025-11-12 17:44:02 +01:00
parent f903e28728
commit 6585b1765a
13 changed files with 218 additions and 60 deletions

View File

@ -9,7 +9,8 @@
"Bash(go build:*)", "Bash(go build:*)",
"Bash(/home/mathieu/git/project-notes/notes/test-delete-1.md)", "Bash(/home/mathieu/git/project-notes/notes/test-delete-1.md)",
"Bash(/home/mathieu/git/project-notes/notes/test-delete-2.md)", "Bash(/home/mathieu/git/project-notes/notes/test-delete-2.md)",
"Bash(/home/mathieu/git/project-notes/notes/test-delete-folder/test.md)" "Bash(/home/mathieu/git/project-notes/notes/test-delete-folder/test.md)",
"Bash(npm install)"
], ],
"deny": [], "deny": [],
"ask": [] "ask": []

View File

@ -4,3 +4,9 @@ import './ui.js';
import './search.js'; import './search.js';
import './daily-notes.js'; import './daily-notes.js';
import './link-inserter.js'; import './link-inserter.js';
import './theme-manager.js';
import './font-manager.js';
import './vim-mode-manager.js';
import './favorites.js';
import './sidebar-sections.js';
import './keyboard-shortcuts.js';

View File

@ -279,9 +279,9 @@ func (h *Handler) buildCalendarData(year int, month time.Month) *CalendarData {
// Calculer mois précédent et suivant // Calculer mois précédent et suivant
prevMonth := firstDay.AddDate(0, -1, 0) prevMonth := firstDay.AddDate(0, -1, 0)
nextMonth := firstDay.AddDate(0, 1, 0) nextMonth := firstDay.AddDate(0, 1, 0)
data.PrevMonth = fmt.Sprintf("%d-%02d", prevMonth.Year(), prevMonth.Month()) data.PrevMonth = fmt.Sprintf("%d/%02d", prevMonth.Year(), prevMonth.Month())
data.NextMonth = fmt.Sprintf("%d-%02d", nextMonth.Year(), nextMonth.Month()) data.NextMonth = fmt.Sprintf("%d/%02d", nextMonth.Year(), nextMonth.Month())
data.CurrentMonth = fmt.Sprintf("%d-%02d", year, month) data.CurrentMonth = fmt.Sprintf("%d/%02d", year, month)
// Construire les semaines // Construire les semaines
// Lundi = 0, Dimanche = 6 // Lundi = 0, Dimanche = 6

View File

@ -335,6 +335,9 @@ func (h *Handler) generateHomeMarkdown() string {
// Section des favoris (après les tags) // Section des favoris (après les tags)
h.generateFavoritesSection(&sb) h.generateFavoritesSection(&sb)
// Section des notes récemment modifiées (après les favoris)
h.generateRecentNotesSection(&sb)
// Titre de l'arborescence avec le nombre de notes // Titre de l'arborescence avec le nombre de notes
sb.WriteString(fmt.Sprintf("## 📂 Toutes les notes (%d)\n\n", noteCount)) sb.WriteString(fmt.Sprintf("## 📂 Toutes les notes (%d)\n\n", noteCount))
@ -407,6 +410,56 @@ func (h *Handler) generateFavoritesSection(sb *strings.Builder) {
sb.WriteString("</div>\n\n") sb.WriteString("</div>\n\n")
} }
// generateRecentNotesSection génère la section des notes récemment modifiées
func (h *Handler) generateRecentNotesSection(sb *strings.Builder) {
recentDocs := h.idx.GetRecentDocuments(5)
if len(recentDocs) == 0 {
return
}
sb.WriteString("## 🕒 Récemment modifiés\n\n")
sb.WriteString("<div class=\"recent-notes-container\">\n")
for _, doc := range recentDocs {
// Extraire les premières lignes du corps (max 150 caractères)
preview := doc.Summary
if len(preview) > 150 {
preview = preview[:150] + "..."
}
// Parser la date de modification pour un affichage plus lisible
dateStr := doc.LastModified
if dateStr == "" {
dateStr = doc.Date
}
sb.WriteString(" <div class=\"recent-note-card\">\n")
sb.WriteString(fmt.Sprintf(" <a href=\"#\" class=\"recent-note-link\" hx-get=\"/api/notes/%s\" hx-target=\"#editor-container\" hx-swap=\"innerHTML\">\n", doc.Path))
sb.WriteString(fmt.Sprintf(" <div class=\"recent-note-title\">%s</div>\n", doc.Title))
sb.WriteString(fmt.Sprintf(" <div class=\"recent-note-meta\">\n"))
sb.WriteString(fmt.Sprintf(" <span class=\"recent-note-date\">📅 %s</span>\n", dateStr))
if len(doc.Tags) > 0 {
sb.WriteString(fmt.Sprintf(" <span class=\"recent-note-tags\">"))
for i, tag := range doc.Tags {
if i > 0 {
sb.WriteString(" ")
}
sb.WriteString(fmt.Sprintf("#%s", tag))
}
sb.WriteString("</span>\n")
}
sb.WriteString(" </div>\n")
if preview != "" {
sb.WriteString(fmt.Sprintf(" <div class=\"recent-note-preview\">%s</div>\n", preview))
}
sb.WriteString(" </a>\n")
sb.WriteString(" </div>\n")
}
sb.WriteString("</div>\n\n")
}
// generateFavoriteFolderContent génère le contenu d'un dossier favori // generateFavoriteFolderContent génère le contenu d'un dossier favori
func (h *Handler) generateFavoriteFolderContent(sb *strings.Builder, folderPath string, depth int) { func (h *Handler) generateFavoriteFolderContent(sb *strings.Builder, folderPath string, depth int) {
// Construire le chemin absolu // Construire le chemin absolu

View File

@ -710,6 +710,30 @@ func (i *Indexer) GetBacklinks(path string) []string {
return result return result
} }
// GetRecentDocuments retourne les N documents les plus récemment modifiés
func (i *Indexer) GetRecentDocuments(limit int) []*Document {
i.mu.RLock()
defer i.mu.RUnlock()
// Copier tous les documents dans un slice
docs := make([]*Document, 0, len(i.docs))
for _, doc := range i.docs {
docs = append(docs, doc)
}
// Trier par date de dernière modification (décroissant)
sort.Slice(docs, func(i, j int) bool {
return docs[i].LastModified > docs[j].LastModified
})
// Limiter le nombre de résultats
if limit > 0 && len(docs) > limit {
docs = docs[:limit]
}
return docs
}
// extractInternalLinks extrait tous les liens internes d'un texte Markdown/HTML // extractInternalLinks extrait tous les liens internes d'un texte Markdown/HTML
// Format: <a ... hx-get="/api/notes/path/to/note.md" ...> // Format: <a ... hx-get="/api/notes/path/to/note.md" ...>
func extractInternalLinks(body string) []string { func extractInternalLinks(body string) []string {

View File

@ -1,74 +1,67 @@
{ {
"items": [ "items": [
{
"path": "documentation/authentication.md",
"is_dir": false,
"title": "authentication",
"added_at": "2025-11-11T13:55:41.091354066+01:00",
"order": 0
},
{ {
"path": "research/ai", "path": "research/ai",
"is_dir": true, "is_dir": true,
"title": "ai", "title": "ai",
"added_at": "2025-11-11T13:55:49.371541279+01:00", "added_at": "2025-11-11T13:55:49.371541279+01:00",
"order": 1 "order": 0
}, },
{ {
"path": "research/design/ui-inspiration.md", "path": "research/design/ui-inspiration.md",
"is_dir": false, "is_dir": false,
"title": "ui-inspiration", "title": "ui-inspiration",
"added_at": "2025-11-11T14:20:49.985321698+01:00", "added_at": "2025-11-11T14:20:49.985321698+01:00",
"order": 2 "order": 1
}, },
{ {
"path": "research/tech/websockets.md", "path": "research/tech/websockets.md",
"is_dir": false, "is_dir": false,
"title": "websockets", "title": "websockets",
"added_at": "2025-11-11T14:20:55.347335695+01:00", "added_at": "2025-11-11T14:20:55.347335695+01:00",
"order": 3 "order": 2
}, },
{ {
"path": "tasks/backlog.md", "path": "tasks/backlog.md",
"is_dir": false, "is_dir": false,
"title": "backlog", "title": "backlog",
"added_at": "2025-11-11T14:20:57.762787363+01:00", "added_at": "2025-11-11T14:20:57.762787363+01:00",
"order": 4 "order": 3
}, },
{ {
"path": "ideas/client-feedback.md", "path": "ideas/client-feedback.md",
"is_dir": false, "is_dir": false,
"title": "client-feedback", "title": "client-feedback",
"added_at": "2025-11-11T14:22:16.497953232+01:00", "added_at": "2025-11-11T14:22:16.497953232+01:00",
"order": 5 "order": 4
}, },
{ {
"path": "ideas/collaboration.md", "path": "ideas/collaboration.md",
"is_dir": false, "is_dir": false,
"title": "collaboration", "title": "collaboration",
"added_at": "2025-11-11T14:22:18.012032002+01:00", "added_at": "2025-11-11T14:22:18.012032002+01:00",
"order": 6 "order": 5
}, },
{ {
"path": "ideas/mobile-app.md", "path": "ideas/mobile-app.md",
"is_dir": false, "is_dir": false,
"title": "mobile-app", "title": "mobile-app",
"added_at": "2025-11-11T14:22:19.048311608+01:00", "added_at": "2025-11-11T14:22:19.048311608+01:00",
"order": 7 "order": 6
}, },
{ {
"path": "meetings/2025", "path": "meetings/2025",
"is_dir": true, "is_dir": true,
"title": "2025", "title": "2025",
"added_at": "2025-11-11T14:22:21.531283601+01:00", "added_at": "2025-11-11T14:22:21.531283601+01:00",
"order": 8 "order": 7
}, },
{ {
"path": "meetings/outscale.md", "path": "meetings/outscale.md",
"is_dir": false, "is_dir": false,
"title": "outscale", "title": "outscale",
"added_at": "2025-11-11T14:22:22.519332518+01:00", "added_at": "2025-11-11T14:22:22.519332518+01:00",
"order": 9 "order": 8
} }
] ]
} }

View File

@ -1,9 +1,8 @@
--- ---
title: Daily Note - 2025-11-11 title: "Daily Note - 2025-11-11"
date: 11-11-2025 date: "11-11-2025"
last_modified: 11-11-2025:13:58 last_modified: "11-11-2025:00:00"
tags: tags: [daily]
- daily
--- ---
# 📅 Mardi 11 novembre 2025 # 📅 Mardi 11 novembre 2025
@ -11,8 +10,6 @@ tags:
## 🎯 Objectifs du jour ## 🎯 Objectifs du jour
- -
Blouloublou
## 📝 Notes ## 📝 Notes
- -

View File

@ -1,7 +1,7 @@
--- ---
title: Daily Note - 2025-11-12 title: Daily Note - 2025-11-12
date: 12-11-2025 date: 12-11-2025
last_modified: 12-11-2025:10:37 last_modified: 12-11-2025:17:30
tags: tags:
- daily - daily
--- ---
@ -11,12 +11,10 @@ tags:
## 🎯 Objectifs du jour ## 🎯 Objectifs du jour
- -
Blablabla
## 📝 Notes ## 📝 Notes
- C'est la note du jour -
Elle est cool
/i
## ✅ Accompli ## ✅ Accompli
- -

View File

@ -3388,3 +3388,97 @@ body, html {
max-height: calc(100vh - 200px); 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);
scrollbar-width: thin;
scrollbar-color: var(--border-primary) transparent;
}
.recent-notes-container::-webkit-scrollbar {
width: 6px;
}
.recent-notes-container::-webkit-scrollbar-track {
background: transparent;
}
.recent-notes-container::-webkit-scrollbar-thumb {
background: var(--border-primary);
border-radius: 3px;
}
.recent-notes-container::-webkit-scrollbar-thumb:hover {
background: var(--border-secondary);
}
.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;
}

View File

@ -46,12 +46,23 @@
{{end}} {{end}}
</div> </div>
<button class="daily-today-btn" <div style="display: flex; gap: 0.5rem; margin-top: 0.75rem;">
hx-get="/api/daily/today" <button class="daily-today-btn"
hx-target="#editor-container" hx-get="/api/daily/today"
hx-swap="innerHTML" hx-target="#editor-container"
hx-push-url="true" hx-swap="innerHTML"
title="Ouvrir la note du jour"> hx-push-url="true"
📅 Aujourd'hui title="Ouvrir la note du jour (Ctrl/Cmd+D)"
</button> style="flex: 1; padding: 0.5rem; font-size: 0.85rem;">
📅 Aujourd'hui
</button>
<button class="daily-today-btn"
hx-get="/api/daily/calendar/{{.CurrentMonth}}"
hx-target="#daily-calendar"
hx-swap="outerHTML"
title="Revenir au mois actuel"
style="flex: 1; padding: 0.5rem; font-size: 0.85rem;">
🗓️ Ce mois
</button>
</div>
</div> </div>

View File

@ -17,12 +17,6 @@
<script src="https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/highlight.min.js"></script> <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/highlight.min.js"></script>
<script src="/static/sidebar-resize.js"></script> <script src="/static/sidebar-resize.js"></script>
<script src="/frontend/src/theme-manager.js"></script>
<script src="/frontend/src/font-manager.js"></script>
<script src="/frontend/src/vim-mode-manager.js"></script>
<script src="/frontend/src/favorites.js"></script>
<script src="/frontend/src/sidebar-sections.js"></script>
<script src="/frontend/src/keyboard-shortcuts.js"></script>
<script type="module" src="/static/dist/personotes-frontend.es.js"></script> <script type="module" src="/static/dist/personotes-frontend.es.js"></script>
</head> </head>
<body> <body>
@ -41,7 +35,6 @@
hx-get="/api/search" hx-get="/api/search"
hx-trigger="keyup changed delay:500ms, search" hx-trigger="keyup changed delay:500ms, search"
hx-target="#search-results" hx-target="#search-results"
hx-indicator="#search-spinner"
style="flex-grow: 1; max-width: 350px;" style="flex-grow: 1; max-width: 350px;"
/> />
<button <button
@ -53,21 +46,9 @@
title="Retour à la page d'accueil (Ctrl/Cmd+H)"> title="Retour à la page d'accueil (Ctrl/Cmd+H)">
🏠 Accueil 🏠 Accueil
</button> </button>
<button
hx-get="/api/daily/today"
hx-target="#editor-container"
hx-swap="innerHTML"
hx-push-url="true"
style="white-space: nowrap;"
title="Note du jour (Ctrl/Cmd+D)">
📅 Note du jour
</button>
<button onclick="showNewNoteModal()" style="white-space: nowrap;" title="Créer une nouvelle note (Ctrl/Cmd+N)"> <button onclick="showNewNoteModal()" style="white-space: nowrap;" title="Créer une nouvelle note (Ctrl/Cmd+N)">
✨ Nouvelle note ✨ Nouvelle note
</button> </button>
<div id="search-spinner" class="htmx-indicator">
<progress></progress>
</div>
</header> </header>
<!-- Modal pour nouvelle note --> <!-- Modal pour nouvelle note -->