feat: reorder frontmatter keys and add publish/private quick links
This commit is contained in:
parent
0f7610bed1
commit
168fcaf049
@ -162,13 +162,13 @@ test('Should maintain correct key order', async () => {
|
||||
'tags:',
|
||||
'aliases:',
|
||||
'status:',
|
||||
'publish:',
|
||||
'favoris:',
|
||||
'publish:',
|
||||
'draft:',
|
||||
'template:',
|
||||
'task:',
|
||||
'archive:',
|
||||
'draft:',
|
||||
'private:'
|
||||
'private:',
|
||||
'archive:'
|
||||
];
|
||||
|
||||
let lastIndex = -1;
|
||||
|
||||
@ -50,7 +50,7 @@ export class NotesListComponent {
|
||||
folderFilter = input<string | null>(null); // like "folder/subfolder"
|
||||
query = input<string>('');
|
||||
tagFilter = input<string | null>(null);
|
||||
quickLinkFilter = input<'favoris' | 'template' | 'task' | 'draft' | 'archive' | null>(null);
|
||||
quickLinkFilter = input<'favoris' | 'publish' | 'draft' | 'template' | 'task' | 'private' | 'archive' | null>(null);
|
||||
|
||||
@Output() openNote = new EventEmitter<string>();
|
||||
@Output() queryChange = new EventEmitter<string>();
|
||||
@ -72,7 +72,7 @@ export class NotesListComponent {
|
||||
// All files anywhere under .trash (including subfolders)
|
||||
list = list.filter(n => {
|
||||
const filePath = (n.filePath || n.originalPath || '').toLowerCase().replace(/\\/g, '/');
|
||||
return filePath.includes('/.trash/');
|
||||
return filePath.startsWith('.trash/') || filePath.includes('/.trash/');
|
||||
});
|
||||
} else {
|
||||
list = list.filter(n => {
|
||||
|
||||
@ -6,9 +6,11 @@ import { BadgeCountComponent } from '../../shared/ui/badge-count.component';
|
||||
interface QuickLinkCountsUi {
|
||||
all: number;
|
||||
favorites: number;
|
||||
publish: number;
|
||||
templates: number;
|
||||
tasks: number;
|
||||
drafts: number;
|
||||
private: number;
|
||||
archive: number;
|
||||
}
|
||||
|
||||
@ -21,32 +23,44 @@ interface QuickLinkCountsUi {
|
||||
<ul class="text-sm space-y-1">
|
||||
<li>
|
||||
<button (click)="select('all')" class="flex items-center gap-2 px-3 py-2 rounded-lg cursor-pointer hover:bg-slate-500/10 dark:hover:bg-slate-200/10 transition w-full text-left">
|
||||
<span class="flex items-center gap-2"><span>🗂️</span> <span>All pages</span></span>
|
||||
<span class="flex items-center gap-2"><span>🗂️</span> <span>All Pages</span></span>
|
||||
<app-badge-count class="ml-auto" [count]="counts().all" color="slate"></app-badge-count>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button (click)="select('favorites')" class="flex items-center gap-2 px-3 py-2 rounded-lg cursor-pointer hover:bg-slate-500/10 dark:hover:bg-slate-200/10 transition w-full text-left">
|
||||
<span class="flex items-center gap-2"><span>❤️</span> <span>Favorites</span></span>
|
||||
<span class="flex items-center gap-2"><span>❤️</span> <span>Favoris</span></span>
|
||||
<app-badge-count class="ml-auto" [count]="counts().favorites" color="rose"></app-badge-count>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button (click)="select('templates')" class="flex items-center gap-2 px-3 py-2 rounded-lg cursor-pointer hover:bg-slate-500/10 dark:hover:bg-slate-200/10 transition w-full text-left">
|
||||
<span class="flex items-center gap-2"><span>📑</span> <span>Templates</span></span>
|
||||
<button (click)="select('publish')" class="flex items-center gap-2 px-3 py-2 rounded-lg cursor-pointer hover:bg-slate-500/10 dark:hover:bg-slate-200/10 transition w-full text-left">
|
||||
<span class="flex items-center gap-2"><span>🌐</span> <span>Publish</span></span>
|
||||
<app-badge-count class="ml-auto" [count]="counts().publish" color="green"></app-badge-count>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button (click)="select('drafts')" class="flex items-center gap-2 px-3 py-2 rounded-lg cursor-pointer hover:bg-slate-500/10 dark:hover:bg-slate-200/10 transition w-full text-left">
|
||||
<span class="flex items-center gap-2"><span>📝</span> <span>Draft</span></span>
|
||||
<app-badge-count class="ml-auto" [count]="counts().drafts" color="emerald"></app-badge-count>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button (click)="select('templates')" class="flex items-center gap-2 px-3 py-2 rounded-lg cursor-pointer hover:bg-slate-500/10 dark:hover:bg-slate-200/10 transition w-full text left">
|
||||
<span class="flex items-center gap-2"><span>📑</span> <span>Template</span></span>
|
||||
<app-badge-count class="ml-auto" [count]="counts().templates" color="amber"></app-badge-count>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button (click)="select('tasks')" class="flex items-center gap-2 px-3 py-2 rounded-lg cursor-pointer hover:bg-slate-500/10 dark:hover:bg-slate-200/10 transition w-full text-left">
|
||||
<span class="flex items-center gap-2"><span>🗒️</span> <span>Tasks</span></span>
|
||||
<span class="flex items-center gap-2"><span>🗒️</span> <span>Task</span></span>
|
||||
<app-badge-count class="ml-auto" [count]="counts().tasks" color="indigo"></app-badge-count>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button (click)="select('drafts')" class="flex items-center gap-2 px-3 py-2 rounded-lg cursor-pointer hover:bg-slate-500/10 dark:hover:bg-slate-200/10 transition w-full text-left">
|
||||
<span class="flex items-center gap-2"><span>📝</span> <span>Drafts</span></span>
|
||||
<app-badge-count class="ml-auto" [count]="counts().drafts" color="emerald"></app-badge-count>
|
||||
<button (click)="select('private')" class="flex items-center gap-2 px-3 py-2 rounded-lg cursor-pointer hover:bg-slate-500/10 dark:hover:bg-slate-200/10 transition w-full text-left">
|
||||
<span class="flex items-center gap-2"><span>🔒</span> <span>Private</span></span>
|
||||
<app-badge-count class="ml-auto" [count]="counts().private" color="purple"></app-badge-count>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
|
||||
@ -54,7 +54,7 @@ import { VaultService } from '../../../services/vault.service';
|
||||
<!-- Folders accordion -->
|
||||
<section class="border-b border-gray-200 dark:border-gray-800">
|
||||
<button class="w-full flex items-center justify-between px-3 py-2 text-sm font-semibold hover:bg-gray-100 dark:hover:bg-gray-800"
|
||||
(click)="open.folders = !open.folders">
|
||||
(click)="toggleFoldersSection()">
|
||||
<span>Folders</span>
|
||||
<span class="text-xs text-gray-500">{{ open.folders ? '▾' : '▸' }}</span>
|
||||
</button>
|
||||
@ -92,7 +92,7 @@ import { VaultService } from '../../../services/vault.service';
|
||||
<!-- Trash accordion -->
|
||||
<section class="border-b border-gray-200 dark:border-gray-800">
|
||||
<button class="w-full flex items-center justify-between px-3 py-2 text-sm font-semibold hover:bg-gray-100 dark:hover:bg-gray-800"
|
||||
(click)="open.trash = !open.trash; folderSelected.emit('.trash')">
|
||||
(click)="toggleTrashSection()">
|
||||
<span class="flex items-center gap-2">Trash</span>
|
||||
<span class="text-xs text-gray-500">{{ open.trash ? '▾' : '▸' }}</span>
|
||||
</button>
|
||||
@ -146,4 +146,20 @@ export class NimbusSidebarComponent {
|
||||
trashCount = () => this.vault.counts().trash;
|
||||
trashHasContent = () => (this.vault.trashTree() || []).length > 0;
|
||||
trackNoteId = (_: number, n: { id: string }) => n.id;
|
||||
|
||||
toggleFoldersSection(): void {
|
||||
const next = !this.open.folders;
|
||||
this.open.folders = next;
|
||||
if (next) {
|
||||
this.quickLinkSelected.emit('all');
|
||||
}
|
||||
}
|
||||
|
||||
toggleTrashSection(): void {
|
||||
const next = !this.open.trash;
|
||||
this.open.trash = next;
|
||||
if (next) {
|
||||
this.folderSelected.emit('.trash');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,7 +261,7 @@ export class AppShellNimbusLayoutComponent {
|
||||
hoveredFlyout: 'quick' | 'folders' | 'tags' | 'trash' | null = null;
|
||||
private flyoutCloseTimer: any = null;
|
||||
tagFilter: string | null = null;
|
||||
quickLinkFilter: 'favoris' | 'template' | 'task' | 'draft' | 'archive' | null = null;
|
||||
quickLinkFilter: 'favoris' | 'publish' | 'draft' | 'template' | 'task' | 'private' | 'archive' | null = null;
|
||||
|
||||
toggleNoteFullScreen(): void {
|
||||
this.noteFullScreen = !this.noteFullScreen;
|
||||
@ -324,6 +324,16 @@ export class AppShellNimbusLayoutComponent {
|
||||
this.mobileNav.setActiveTab('list');
|
||||
}
|
||||
this.scheduleCloseFlyout(150);
|
||||
} else if (_id === 'publish') {
|
||||
// Filter by publish: true
|
||||
this.folderFilter = null;
|
||||
this.tagFilter = null;
|
||||
this.quickLinkFilter = 'publish';
|
||||
this.listQuery = '';
|
||||
if (!this.responsive.isDesktop()) {
|
||||
this.mobileNav.setActiveTab('list');
|
||||
}
|
||||
this.scheduleCloseFlyout(150);
|
||||
} else if (_id === 'favorites') {
|
||||
// Filter by favoris: true
|
||||
this.folderFilter = null;
|
||||
@ -364,6 +374,16 @@ export class AppShellNimbusLayoutComponent {
|
||||
this.mobileNav.setActiveTab('list');
|
||||
}
|
||||
this.scheduleCloseFlyout(150);
|
||||
} else if (_id === 'private') {
|
||||
// Filter by private: true
|
||||
this.folderFilter = null;
|
||||
this.tagFilter = null;
|
||||
this.quickLinkFilter = 'private';
|
||||
this.listQuery = '';
|
||||
if (!this.responsive.isDesktop()) {
|
||||
this.mobileNav.setActiveTab('list');
|
||||
}
|
||||
this.scheduleCloseFlyout(150);
|
||||
} else if (_id === 'archive') {
|
||||
// Filter by archive: true
|
||||
this.folderFilter = null;
|
||||
|
||||
@ -202,15 +202,6 @@ interface MetadataEntry {
|
||||
</svg>
|
||||
{{ getAuthorFromFrontmatter() ?? note().author ?? 'Auteur inconnu' }}
|
||||
</span>
|
||||
@if (hasState('publish')) {
|
||||
<span class="inline-flex items-center gap-1 transition-colors" [ngClass]="state('publish') ? 'text-green-500' : 'text-gray-400'" title="{{ state('publish') ? 'Publié sur le web' : 'Non publié' }}" role="img" aria-label="{{ state('publish') ? 'Publié sur le web' : 'Non publié' }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="M2 12h20" />
|
||||
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
@if (hasState('favoris')) {
|
||||
<span class="inline-flex items-center gap-1 transition-colors" [ngClass]="state('favoris') ? 'text-rose-500' : 'text-gray-400'" title="{{ state('favoris') ? 'Ajouté aux favoris' : 'Non favori' }}" role="img" aria-label="{{ state('favoris') ? 'Ajouté aux favoris' : 'Non favori' }}">
|
||||
@if (state('favoris')) {
|
||||
@ -224,21 +215,13 @@ interface MetadataEntry {
|
||||
}
|
||||
</span>
|
||||
}
|
||||
@if (hasState('archive')) {
|
||||
<span class="inline-flex items-center gap-1 transition-colors" [ngClass]="state('archive') ? 'text-amber-600' : 'text-gray-400'" title="{{ state('archive') ? 'Document archivé' : 'Document non archivé' }}" role="img" aria-label="{{ state('archive') ? 'Document archivé' : 'Document non archivé' }}">
|
||||
@if (state('archive')) {
|
||||
@if (hasState('publish')) {
|
||||
<span class="inline-flex items-center gap-1 transition-colors" [ngClass]="state('publish') ? 'text-green-500' : 'text-gray-400'" title="{{ state('publish') ? 'Publié sur le web' : 'Non publié' }}" role="img" aria-label="{{ state('publish') ? 'Publié sur le web' : 'Non publié' }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="22,12 18,12 18,8"/>
|
||||
<path d="M18,2H6a2,2,0,0,0-2,2V22a2,2,0,0,0,2,2H18a2,2,0,0,0,2-2V8Z"/>
|
||||
<line x1="10" y1="12" x2="14" y2="12"/>
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="M2 12h20" />
|
||||
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
|
||||
</svg>
|
||||
} @else {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 8v13a2 2 0 01-2 2H5a2 2 0 01-2-2V8"/>
|
||||
<path d="M3 4h18l-2-2H5l-2 2z"/>
|
||||
<line x1="10" y1="12" x2="14" y2="12"/>
|
||||
</svg>
|
||||
}
|
||||
</span>
|
||||
}
|
||||
@if (hasState('draft')) {
|
||||
@ -256,6 +239,35 @@ interface MetadataEntry {
|
||||
}
|
||||
</span>
|
||||
}
|
||||
@if (hasState('template')) {
|
||||
<span class="inline-flex items-center gap-1 transition-colors" [ngClass]="state('template') ? 'text-amber-500' : 'text-gray-400'" title="{{ state('template') ? 'Modèle' : 'Non modèle' }}" role="img" aria-label="{{ state('template') ? 'Modèle' : 'Non modèle' }}">
|
||||
@if (state('template')) {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="4" width="18" height="14" rx="2" />
|
||||
<path d="M7 8h10" />
|
||||
<path d="M7 12h6" />
|
||||
</svg>
|
||||
} @else {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="5" width="18" height="12" rx="2" />
|
||||
</svg>
|
||||
}
|
||||
</span>
|
||||
}
|
||||
@if (hasState('task')) {
|
||||
<span class="inline-flex items-center gap-1 transition-colors" [ngClass]="state('task') ? 'text-indigo-500' : 'text-gray-400'" title="{{ state('task') ? 'Tâche' : 'Pas une tâche' }}" role="img" aria-label="{{ state('task') ? 'Tâche' : 'Pas une tâche' }}">
|
||||
@if (state('task')) {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="4" width="18" height="16" rx="2" />
|
||||
<path d="M8 12l2 2 4-4" />
|
||||
</svg>
|
||||
} @else {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="4" width="18" height="16" rx="2" />
|
||||
</svg>
|
||||
}
|
||||
</span>
|
||||
}
|
||||
@if (hasState('private')) {
|
||||
<span class="inline-flex items-center gap-1 transition-colors" [ngClass]="state('private') ? 'text-purple-500' : 'text-gray-400'" title="{{ state('private') ? 'Privé' : 'Public' }}" role="img" aria-label="{{ state('private') ? 'Privé' : 'Public' }}">
|
||||
@if (state('private')) {
|
||||
@ -271,6 +283,23 @@ interface MetadataEntry {
|
||||
}
|
||||
</span>
|
||||
}
|
||||
@if (hasState('archive')) {
|
||||
<span class="inline-flex items-center gap-1 transition-colors" [ngClass]="state('archive') ? 'text-amber-600' : 'text-gray-400'" title="{{ state('archive') ? 'Document archivé' : 'Document non archivé' }}" role="img" aria-label="{{ state('archive') ? 'Document archivé' : 'Document non archivé' }}">
|
||||
@if (state('archive')) {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="22,12 18,12 18,8"/>
|
||||
<path d="M18,2H6a2,2,0,0,0-2,2V22a2,2,0,0,0,2,2H18a2,2,0,0,0,2-2V8Z"/>
|
||||
<line x1="10" y1="12" x2="14" y2="12"/>
|
||||
</svg>
|
||||
} @else {
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 8v13a2 2 0 01-2 2H5a2 2 0 01-2-2V8"/>
|
||||
<path d="M3 4h18l-2-2H5l-2 2z"/>
|
||||
<line x1="10" y1="12" x2="14" y2="12"/>
|
||||
</svg>
|
||||
}
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div [innerHTML]="sanitizedHtmlContent()"></div>
|
||||
@ -1148,7 +1177,7 @@ export class NoteViewerComponent implements OnDestroy {
|
||||
this.copyFeedbackTimers.set(block, timeout);
|
||||
}
|
||||
|
||||
hasState(key: 'publish' | 'favoris' | 'archive' | 'draft' | 'private'): boolean {
|
||||
hasState(key: 'publish' | 'favoris' | 'archive' | 'draft' | 'private' | 'template' | 'task'): boolean {
|
||||
try {
|
||||
const fm = (this.note()?.frontmatter ?? {}) as any;
|
||||
const raw = (fm as any)[key];
|
||||
@ -1158,7 +1187,7 @@ export class NoteViewerComponent implements OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
state(key: 'publish' | 'favoris' | 'archive' | 'draft' | 'private'): boolean {
|
||||
state(key: 'publish' | 'favoris' | 'archive' | 'draft' | 'private' | 'template' | 'task'): boolean {
|
||||
try {
|
||||
const fm = (this.note()?.frontmatter ?? {}) as any;
|
||||
const raw = (fm as any)[key];
|
||||
|
||||
@ -29,9 +29,11 @@ interface VaultApiResponse {
|
||||
interface QuickLinkCounts {
|
||||
all: number;
|
||||
favorites: number;
|
||||
publish: number;
|
||||
templates: number;
|
||||
tasks: number;
|
||||
drafts: number;
|
||||
private: number;
|
||||
archive: number;
|
||||
trash: number;
|
||||
}
|
||||
@ -449,9 +451,11 @@ export class VaultService implements OnDestroy {
|
||||
const counts: QuickLinkCounts = {
|
||||
all: 0,
|
||||
favorites: 0,
|
||||
publish: 0,
|
||||
templates: 0,
|
||||
tasks: 0,
|
||||
drafts: 0,
|
||||
private: 0,
|
||||
archive: 0,
|
||||
trash: 0
|
||||
};
|
||||
@ -468,9 +472,11 @@ export class VaultService implements OnDestroy {
|
||||
const fm = note.frontmatter || {};
|
||||
|
||||
if (fm.favoris === true) counts.favorites++;
|
||||
if (fm.publish === true) counts.publish++;
|
||||
if (fm.template === true) counts.templates++;
|
||||
if (fm.task === true) counts.tasks++;
|
||||
if (fm.draft === true) counts.drafts++;
|
||||
if (fm.private === true) counts.private++;
|
||||
if (fm.archive === true) counts.archive++;
|
||||
}
|
||||
|
||||
|
||||
17
vault/Nouveau-markdown.md
Normal file
17
vault/Nouveau-markdown.md
Normal file
@ -0,0 +1,17 @@
|
||||
---
|
||||
titre: Nouveau-markdown
|
||||
auteur: Bruno Charest
|
||||
creation_date: 2025-10-19T21:42:53-04:00
|
||||
modification_date: 2025-10-19T21:43:06-04:00
|
||||
catégorie: ""
|
||||
tags: []
|
||||
aliases: []
|
||||
status: en-cours
|
||||
publish: true
|
||||
favoris: true
|
||||
template: true
|
||||
task: true
|
||||
archive: true
|
||||
draft: true
|
||||
private: true
|
||||
---
|
||||
0
vault/Nouveau-markdown.md.bak
Normal file
0
vault/Nouveau-markdown.md.bak
Normal file
Loading…
x
Reference in New Issue
Block a user