-
{{ note.title }}
-
{{ note.filePath }}
+
+
+
+
{{ typeIcon(note.filePath) }}
+
+
{{ note.title }}
+
{{ note.filePath }}
+
âïž {{ a }}
+
{{ d }}
+
đ {{ formatDateTime(ts) }}
+
+
+
+
@@ -1030,6 +1039,82 @@ export class PaginatedNotesListComponent implements OnInit, OnDestroy {
} catch { return 'đ'; }
}
+ // Metadata helpers used by Comfortable/Detailed modes
+ getUpdatedTimestampById(meta: NoteMetadata): number | null {
+ try {
+ const full = this.getFullNoteById(meta.id) as any;
+ const m = Number(full?.mtime || 0);
+ if (m && !Number.isNaN(m)) return m;
+ } catch {}
+ const parse = (s?: string) => {
+ if (!s) return 0;
+ const t = Date.parse(s);
+ return Number.isFinite(t) ? t : 0;
+ };
+ const u = parse(meta.updatedAt);
+ if (u) return u;
+ const c = parse(meta.createdAt);
+ return c || null;
+ }
+
+ formatDateTime(ts: number): string {
+ try {
+ const d = new Date(ts);
+ return d.toLocaleString('fr-FR', { year: 'numeric', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' });
+ } catch { return ''; }
+ }
+
+ getAuthorById(id: string): string | null {
+ const full = this.getFullNoteById(id) as any;
+ const fm = (full?.frontmatter || {}) as any;
+ const v = (fm.author ?? fm.auteur ?? full?.author) as any;
+ return (typeof v === 'string' && v.trim().length > 0) ? v : null;
+ }
+
+ getDescriptionById(id: string): string | null {
+ const full = this.getFullNoteById(id) as any;
+ const fm = (full?.frontmatter || {}) as any;
+ const v = (fm.description ?? fm.desc) as any;
+ return (typeof v === 'string' && v.trim().length > 0) ? v : null;
+ }
+
+ private extractFirstImageFromFull(full: any): string | null {
+ if (!full) return null;
+ const content = String(full.rawContent ?? full.content ?? '');
+ if (!content) return null;
+ try {
+ const embed = content.match(/!\[\[(.*?)\]\]/);
+ if (embed && embed[1]) {
+ const name = embed[1].trim();
+ if (name) {
+ const notePath = String(full.filePath || full.originalPath || '').replace(/\\/g, '/');
+ return `/api/attachments/resolve?name=${encodeURIComponent(name)}¬e=${encodeURIComponent(notePath)}`;
+ }
+ }
+ const md = content.match(/!\[[^\]]*\]\(([^\)\s]+)(?:\s+\"[^\"]*\")?\)/);
+ if (md && md[1]) {
+ const p = md[1].trim();
+ if (/^(data:|https?:)/i.test(p)) return p;
+ if (p.startsWith('/')) return `/vault/${encodeURI(p.replace(/^\/+/, ''))}`;
+ const notePath = String(full.filePath || full.originalPath || '').replace(/\\/g, '/');
+ return `/api/attachments/resolve?name=${encodeURIComponent(p)}¬e=${encodeURIComponent(notePath)}`;
+ }
+ } catch {}
+ return null;
+ }
+
+ getThumbnailSrcById(meta: NoteMetadata): string | null {
+ try {
+ const full = this.getFullNoteById(meta.id) as any;
+ const path = full?.filePath || meta.filePath || '';
+ const kind = this.fileTypes.getViewerType(path, full?.rawContent ?? full?.content ?? '');
+ if (kind === 'image') {
+ return `/vault/${encodeURI(path)}`;
+ }
+ return this.extractFirstImageFromFull(full);
+ } catch { return null; }
+ }
+
// Sort/View menus
toggleSortMenu(): void { this.sortMenuOpen.set(!this.sortMenuOpen()); this.viewModeMenuOpen.set(false); }
toggleViewModeMenu(): void { this.viewModeMenuOpen.set(!this.viewModeMenuOpen()); this.sortMenuOpen.set(false); }
diff --git a/src/app/layout/app-shell-nimbus/app-shell-nimbus.component.ts b/src/app/layout/app-shell-nimbus/app-shell-nimbus.component.ts
index 7bef1c3..3b44727 100644
--- a/src/app/layout/app-shell-nimbus/app-shell-nimbus.component.ts
+++ b/src/app/layout/app-shell-nimbus/app-shell-nimbus.component.ts
@@ -1,4 +1,4 @@
-import { Component, EventEmitter, HostListener, Input, Output, inject, effect, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
+import { Component, EventEmitter, HostListener, Input, Output, inject, effect, signal, computed, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
import { CommonModule } from '@angular/common';
import { UiModeService } from '../../shared/services/ui-mode.service';
import { ResponsiveService } from '../../shared/services/responsive.service';
@@ -431,6 +431,22 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
quickLinkFilter: 'favoris' | 'publish' | 'draft' | 'template' | 'task' | 'private' | 'archive' | 'bookmarks' | null = null;
private suppressNextNoteSelection = false;
+ // Signaux pour tracker les filtres et déclencher la sélection automatique
+ private filterStateSignal = signal<{
+ tag: string | null;
+ folder: string | null;
+ quick: string | null;
+ search: string;
+ }>({
+ tag: null,
+ folder: null,
+ quick: null,
+ search: ''
+ });
+
+ // Signal pour forcer un recalcul de la liste filtrée
+ private filterChangeCounter = signal(0);
+
// --- URL State <-> Layout sync ---
private mapUrlQuickToInternal(q: string | null): AppShellNimbusLayoutComponent['quickLinkFilter'] {
switch ((q || '').toLowerCase()) {
@@ -525,7 +541,7 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
this.tagFilter = norm || null;
this.folderFilter = null;
this.quickLinkFilter = null;
- if (!hasNote) this.autoSelectFirstNote();
+ if (!hasNote) this.notifyFilterChange();
if (!this.responsive.isDesktop()) this.mobileNav.setActiveTab('list');
}
// Auto-open tags flyout when tag filter is active
@@ -538,7 +554,7 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
this.folderFilter = folder || null;
this.tagFilter = null;
this.quickLinkFilter = null;
- if (!hasNote) this.autoSelectFirstNote();
+ if (!hasNote) this.notifyFilterChange();
if (!this.responsive.isDesktop()) this.mobileNav.setActiveTab('list');
}
// Auto-open folders flyout when folder filter is active
@@ -552,12 +568,12 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
this.quickLinkFilter = internal;
this.folderFilter = null;
this.tagFilter = null;
- this.autoSelectFirstNote();
+ this.notifyFilterChange();
if (!this.responsive.isDesktop()) {
this.mobileNav.setActiveTab('list');
}
} else {
- this.autoSelectFirstNote();
+ this.notifyFilterChange();
}
// Auto-open quick flyout when quick filter is active
if (this.hoveredFlyout !== 'quick') {
@@ -571,7 +587,7 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
this.folderFilter = null;
this.tagFilter = null;
this.quickLinkFilter = null;
- this.autoSelectFirstNote();
+ this.notifyFilterChange();
}
this.suppressNextNoteSelection = false;
// Close any open flyout when no filters
@@ -589,11 +605,58 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
});
});
+ // Effect pour sélection automatique quand les filtres changent
+ private _autoSelectEffect = effect(() => {
+ // Ăcouter le signal de changement de filtre
+ const filterState = this.filterStateSignal();
+ const counter = this.filterChangeCounter();
+
+ // Ăviter l'exĂ©cution lors de l'initialisation
+ if (counter === 0) return;
+
+ console.log('đŻ Auto-select effect triggered:', { filterState, counter });
+
+ // Utiliser queueMicrotask pour s'assurer que la liste est mise Ă jour
+ queueMicrotask(() => {
+ this.autoSelectFirstNote(true);
+ });
+ });
+
+ // Méthode helper pour notifier les changements de filtres
+ private notifyFilterChange() {
+ const currentState = {
+ tag: this.tagFilter,
+ folder: this.folderFilter,
+ quick: this.quickLinkFilter,
+ search: this.listQuery
+ };
+
+ console.log('đ Notifying filter change:', currentState);
+
+ // Mettre à jour le signal d'état
+ this.filterStateSignal.set(currentState);
+
+ // Incrémenter le compteur pour déclencher l'effect
+ this.filterChangeCounter.update(c => c + 1);
+ }
+
// Auto-select first note when filters change
- private autoSelectFirstNote() {
+ private autoSelectFirstNote(forceSelection = false) {
const filteredNotes = this.getFilteredNotes();
- if (filteredNotes.length > 0 && filteredNotes[0].id !== this.selectedNoteId) {
- this.noteSelected.emit(filteredNotes[0].id);
+ console.log('đŻ autoSelectFirstNote called:', {
+ forceSelection,
+ notesCount: filteredNotes.length,
+ firstNoteId: filteredNotes[0]?.id,
+ selectedNoteId: this.selectedNoteId
+ });
+
+ if (filteredNotes.length > 0) {
+ const firstNote = filteredNotes[0];
+ // Forcer la sélection si demandé, ou si la note est différente
+ if (forceSelection || firstNote.id !== this.selectedNoteId) {
+ console.log('â
Emitting noteSelected for:', firstNote.title, firstNote.id);
+ this.noteSelected.emit(firstNote.id);
+ }
}
}
@@ -685,8 +748,8 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
onQueryChange(query: string) {
this.listQuery = query;
- // Auto-select first note on any list change including search updates
- this.autoSelectFirstNote();
+ // Notifier le changement pour déclencher la sélection automatique
+ this.notifyFilterChange();
// Sync URL search term
this.urlState.updateSearch(query);
}
@@ -747,6 +810,7 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
onClearFolderFromList() {
this.folderFilter = null;
+ this.notifyFilterChange();
this.urlState.clearFolderFilter();
}
@@ -807,7 +871,8 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
this.listQuery = '';
try { this.filters.clearKinds(); } catch {}
try { this.filters.clearTags(); } catch {}
- this.autoSelectFirstNote();
+ // Notifier le changement pour déclencher la sélection automatique
+ this.notifyFilterChange();
if (this.responsive.isMobile() || this.responsive.isTablet()) {
this.mobileNav.setActiveTab('list');
}
@@ -829,7 +894,8 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
this.listQuery = '';
try { this.filters.clearKinds(); } catch {}
try { this.filters.clearTags(); } catch {}
- this.autoSelectFirstNote();
+ // Notifier le changement pour déclencher la sélection automatique
+ this.notifyFilterChange();
this.mobileNav.setActiveTab('list');
this.mobileNav.sidebarOpen.set(false);
if (path) {
@@ -987,8 +1053,8 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
this.urlState.setQuickWithMarkdown(label);
}
}
- // Auto-select first note after filter changes
- this.autoSelectFirstNote();
+ // Notifier le changement pour déclencher la sélection automatique
+ this.notifyFilterChange();
this.suppressNextNoteSelection = false;
}
@@ -1000,8 +1066,8 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
// Clear other filters and search to focus on tag results
this.quickLinkFilter = null;
this.listQuery = '';
- // Auto-select first note after filter changes
- this.autoSelectFirstNote();
+ // Notifier le changement pour déclencher la sélection automatique
+ this.notifyFilterChange();
// Ensure the list is visible: exit fullscreen if active
if (this.noteFullScreen) {
this.noteFullScreen = false;
@@ -1104,6 +1170,6 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
this.tagFilter = null;
this.quickLinkFilter = null;
this.listQuery = '';
- this.autoSelectFirstNote();
+ this.notifyFilterChange();
}
}
diff --git a/vault/.test/test.md b/vault/.test/test.md
index 1a87b4f..ac9a1b5 100644
--- a/vault/.test/test.md
+++ b/vault/.test/test.md
@@ -1,13 +1,10 @@
---
-titre: test
-auteur: Bruno Charest
-creation_date: 2025-09-25T07:45:20-04:00
-modification_date: 2025-11-02T12:07:38-04:00
-catégorie: ""
-tags: []
-aliases:
- - ""
-status: en-cours
+titre: "test"
+auteur: "Bruno Charest"
+creation_date: "2025-09-25T07:45:20-04:00"
+modification_date: "2025-11-02T12:07:38-04:00"
+tags: [""]
+status: "en-cours"
publish: true
favoris: false
template: true
@@ -15,14 +12,14 @@ task: true
archive: true
draft: true
private: true
-first_name: Bruno
-birth_date: 2025-06-18
-email: bruno.charest@gmail.com
+first_name: "Bruno"
+birth_date: "2025-06-18"
+email: "bruno.charest@gmail.com"
number: "12345"
todo: false
-url: https://google.com
-image: https://images.unsplash.com/photo-1675789652575-0a5d2425b6c2?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80
-color: "#64748B"
+url: "https://google.com"
+image: "https://images.unsplash.com/photo-1675789652575-0a5d2425b6c2?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80"
+color: "#22C55E"
---
# Test 1 Markdown
diff --git a/vault/Allo-3/Stargate Atlantis.md b/vault/Allo-3/Stargate Atlantis.md
index dd5d76c..61ec8da 100644
--- a/vault/Allo-3/Stargate Atlantis.md
+++ b/vault/Allo-3/Stargate Atlantis.md
@@ -9,7 +9,7 @@ publish: false
favoris: true
template: false
task: false
-archive: false
+archive: true
draft: false
private: false
description: "Stargate Atlantis: une expédition militaire et scientifique découvre la cité mythique d'Atlantis dans la galaxie de Pégase et affronte les Wraiths."
diff --git a/vault/tata/Les Compléments Alimentaires Un Guide Général.md b/vault/tata/Les Compléments Alimentaires Un Guide Général.md
index 289bb94..6c8f204 100644
--- a/vault/tata/Les Compléments Alimentaires Un Guide Général.md
+++ b/vault/tata/Les Compléments Alimentaires Un Guide Général.md
@@ -12,24 +12,9 @@ archive: false
draft: true
private: false
titre: ""
-Les Compléments Alimentaires: "Un Guide Général"
-catégorie: ""
readOnly: false
description: "Les ComplĂ©ments Alimentaires : Un Guide GĂ©nĂ©ral Dans notre quĂȘte constante de bien-ĂȘtre et de..."
-tags:
- - supplments
- - tag2
- - configuration
- - accueil
- - home
- - markdown
- - bruno
- - tag4
- - tag3
- - test
- - tag1
- - test2
- - tagtag
+color: "#00AEEF"
---
## Les Compléments Alimentaires : Un Guide Général