docs: remove Phase 2 completion and executive summary files

This commit is contained in:
2025-10-23 11:50:27 -04:00
parent 291b2e61b0
commit 69df390f58
47 changed files with 12901 additions and 523 deletions
@@ -50,255 +50,271 @@ export interface WikiLinkActivation {
template: `
<div class="relative p-1 prose prose-lg dark:prose-invert max-w-none prose-p:leading-[1] prose-li:leading-[1] prose-blockquote:leading-[1]">
<div class="sr-only" role="status" aria-live="polite">{{ copyStatus() }}</div>
<!-- Compact Top Bar -->
<div class="flex items-start justify-between gap-2 pl-1 pr-2 py-1 mb-2 text-text-muted text-xs">
<app-note-header class="flex-1 min-w-0"
[fullPath]="note().filePath"
[noteId]="note().id"
[tags]="note().tags ?? []"
(copyRequested)="copyPath()"
(openDirectory)="directoryClicked.emit(getDirectoryFromPath(note().filePath))"
(tagsChange)="onTagsChange($event)"
(tagSelected)="tagClicked.emit($event)"
></app-note-header>
<div class="flex items-center gap-1 self-start pt-1">
<button
type="button"
class="note-toolbar-icon"
(click)="enterEdit()"
title="Éditer"
aria-label="Éditer"
>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
</svg>
</button>
<button
type="button"
class="note-toolbar-icon"
(click)="fullScreenRequested.emit()"
[attr.title]="fullScreenActive() ? 'Exit full screen' : 'Open in full screen'"
[attr.aria-label]="fullScreenActive() ? 'Exit full screen' : 'Open in full screen'"
>
{{ fullScreenActive() ? '⤢' : '⤢' }}
</button>
<ng-container *ngIf="note() as note">
<!-- Compact Top Bar -->
<div class="flex items-start justify-between gap-2 pl-1 pr-2 py-1 mb-2 text-text-muted text-xs">
<app-note-header class="flex-1 min-w-0"
[fullPath]="note.filePath"
[noteId]="note.id"
[tags]="note.tags ?? []"
(copyRequested)="copyPath()"
(openDirectory)="directoryClicked.emit(getDirectoryFromPath(note.filePath))"
(tagsChange)="onTagsChange($event)"
(tagSelected)="tagClicked.emit($event)"
></app-note-header>
<div class="hidden sm:block">
<div class="flex items-center gap-1 self-start pt-1">
<button
type="button"
class="note-toolbar-icon"
(click)="showToc.emit()"
[attr.title]="tocOpen() ? 'Cacher sommaire' : 'Afficher sommaire'"
[attr.aria-label]="tocOpen() ? 'Cacher sommaire' : 'Afficher sommaire'"
(click)="enterEdit()"
title="Éditer"
aria-label="Éditer"
>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" [ngClass]="tocOpen() ? 'toc-toggle--active' : 'toc-toggle--idle'"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M9 3v18"/><path d="M13 8h5"/><path d="M13 12h5"/><path d="M13 16h5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
</svg>
</button>
</div>
<button
type="button"
class="note-toolbar-icon"
(click)="copyMarkdown()"
aria-label="Copier tout le markdown"
title="Copier tout le markdown">
<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="M14 2H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8"/><path d="M20 7v11a2 2 0 0 1-2 2H9"/><path d="M8 7h8"/><path d="M8 11h8"/></svg>
</button>
<div class="relative">
<button
type="button"
class="note-toolbar-icon"
(click)="toggleMenu()"
aria-haspopup="menu"
[attr.aria-expanded]="menuOpen()"
title="More options"
aria-label="More options"
(click)="fullScreenRequested.emit()"
[attr.title]="fullScreenActive() ? 'Exit full screen' : 'Open in full screen'"
[attr.aria-label]="fullScreenActive() ? 'Exit full screen' : 'Open in full screen'"
>
⋯
{{ fullScreenActive() ? '⤢' : '⤢' }}
</button>
@if (menuOpen()) {
<div class="absolute right-0 mt-2 w-56 rounded-xl border border-border bg-card shadow-subtle not-prose z-10 overflow-hidden">
<button type="button" class="block w-full text-left px-3 py-2 text-sm transition-colors hover:bg-[rgba(99,102,241,0.12)] dark:hover:bg-[rgba(99,102,241,0.28)] focus-visible:bg-[rgba(99,102,241,0.16)] dark:focus-visible:bg-[rgba(99,102,241,0.35)]" (click)="parametersRequested.emit(); closeMenu()">
<svg xmlns="http://www.w3.org/2000/svg" class="inline h-4 w-4 mr-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3"/>
<path d="M12 1v6m0 6v6m-6-6h6m6 0h-6M4.93 4.93l4.24 4.24m5.66 5.66l4.24 4.24m-4.24-14.14l4.24-4.24M4.93 19.07l4.24-4.24"/>
</svg>
Parameters
</button>
<button type="button" class="block w-full text-left px-3 py-2 text-sm transition-colors hover:bg-[rgba(99,102,241,0.12)] dark:hover:bg-[rgba(99,102,241,0.28)] focus-visible:bg-[rgba(99,102,241,0.16)] dark:focus-visible:bg-[rgba(99,102,241,0.35)]" (click)="legacyRequested.emit(); closeMenu()">🔧 Legacy</button>
</div>
}
</div>
</div>
</div>
@if (isEditMode()) {
<app-markdown-editor
[initialPath]="note().filePath"
[initialContent]="note().rawContent ?? note().content"
/>
} @else {
<div class="hidden sm:block">
<button
type="button"
class="note-toolbar-icon"
(click)="showToc.emit()"
[attr.title]="tocOpen() ? 'Cacher sommaire' : 'Afficher sommaire'"
[attr.aria-label]="tocOpen() ? 'Cacher sommaire' : 'Afficher sommaire'"
>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" [ngClass]="tocOpen() ? 'toc-toggle--active' : 'toc-toggle--idle'"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M9 3v18"/><path d="M13 8h5"/><path d="M13 12h5"/><path d="M13 16h5"/></svg>
</button>
</div>
@if (frontmatterTags().length > 0) {
<div class="mb-6 md-tag-group not-prose">
@for (tag of frontmatterTags(); track tag) {
<button
type="button"
class="md-tag-badge"
[ngClass]="tagColorClass(tag)"
data-origin="frontmatter"
[attr.data-tag]="tag"
(click)="tagClicked.emit(tag)">
{{ tag }}
class="note-toolbar-icon"
(click)="searchRequested.emit()"
title="Rechercher"
aria-label="Rechercher">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="11" cy="11" r="8"/>
<path d="m21 21-4.35-4.35"/>
</svg>
</button>
<button
type="button"
class="note-toolbar-icon"
(click)="copyMarkdown()"
aria-label="Copier tout le markdown"
title="Copier tout le markdown">
<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="M14 2H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8"/><path d="M20 7v11a2 2 0 0 1-2 2H9"/><path d="M8 7h8"/><path d="M8 11h8"/></svg>
</button>
<div class="relative">
<button
type="button"
class="note-toolbar-icon"
(click)="toggleMenu()"
aria-haspopup="menu"
[attr.aria-expanded]="menuOpen()"
title="More options"
aria-label="More options"
>
⋯
</button>
@if (menuOpen()) {
<div class="absolute right-0 mt-2 w-56 rounded-xl border border-border bg-card shadow-subtle not-prose z-10 overflow-hidden">
<button type="button" class="block w-full text-left px-3 py-2 text-sm transition-colors hover:bg-[rgba(99,102,241,0.12)] dark:hover:bg-[rgba(99,102,241,0.28)] focus-visible:bg-[rgba(99,102,241,0.16)] dark:focus-visible:bg-[rgba(99,102,241,0.35)]" (click)="parametersRequested.emit(); closeMenu()">
<svg xmlns="http://www.w3.org/2000/svg" class="inline h-4 w-4 mr-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3"/>
<path d="M12 1v6m0 6v6m-6-6h6m6 0h-6M4.93 4.93l4.24 4.24m5.66 5.66l4.24 4.24m-4.24-14.14l4.24-4.24M4.93 19.07l4.24-4.24"/>
</svg>
Parameters
</button>
<button type="button" class="block w-full text-left px-3 py-2 text-sm transition-colors hover:bg-[rgba(99,102,241,0.12)] dark:hover:bg-[rgba(99,102,241,0.28)] focus-visible:bg-[rgba(99,102,241,0.16)] dark:focus-visible:bg-[rgba(99,102,241,0.35)]" (click)="legacyRequested.emit(); closeMenu()">🔧 Legacy</button>
</div>
}
</div>
</div>
</div>
@if (isEditMode()) {
<app-markdown-editor
[initialPath]="note.filePath"
[initialContent]="note.rawContent ?? note.content"
/>
} @else {
@if (frontmatterTags().length > 0) {
<div class="mb-6 md-tag-group not-prose">
@for (tag of frontmatterTags(); track tag) {
<button
type="button"
class="md-tag-badge"
[ngClass]="tagColorClass(tag)"
data-origin="frontmatter"
[attr.data-tag]="tag"
(click)="tagClicked.emit(tag)">
{{ tag }}
</button>
}
</div>
}
<div class="not-prose flex flex-col gap-2 text-sm text-text-muted my-4">
<!-- Row 1: date + author -->
<div class="flex flex-wrap items-center gap-4">
<span class="inline-flex items-center gap-1">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2h-1.5a1.5 1.5 0 01-3 0h-5a1.5 1.5 0 01-3 0H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
{{ note.updatedAt | date:'medium' }}
</span>
<span class="inline-flex items-center gap-1">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM5.5 21a6.5 6.5 0 0113 0" />
</svg>
{{ getAuthorFromFrontmatter() ?? note.author ?? 'Auteur inconnu' }}
</span>
</div>
<!-- Row 2: state icons (toggle buttons) -->
<div class="flex flex-wrap items-center gap-3">
@if (hasState('favoris')) {
<button type="button" class="inline-flex items-center gap-1 transition-colors focus:outline-none" [ngClass]="state('favoris') ? 'text-rose-500' : 'text-muted'" title="{{ state('favoris') ? 'Ajouté aux favoris' : 'Non favori' }}" aria-label="{{ state('favoris') ? 'Ajouté aux favoris' : 'Non favori' }}" (click)="toggleState('favoris')">
@if (state('favoris')) {
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="currentColor" stroke="none">
<path d="M19 14.5c1.5-1.5 2-4 0-6s-5-2-7 1c-2-3-5-3.5-7-1s-1.5 4.5 0 6l7 6z" />
</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="M19 14.5c1.5-1.5 2-4 0-6s-5-2-7 1c-2-3-5-3.5-7-1s-1.5 4.5 0 6l7 6z" />
</svg>
}
</button>
}
</div>
}
<div class="not-prose flex flex-col gap-2 text-sm text-text-muted my-4">
<!-- Row 1: date + author -->
<div class="flex flex-wrap items-center gap-4">
<span class="inline-flex items-center gap-1">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2h-1.5a1.5 1.5 0 01-3 0h-5a1.5 1.5 0 01-3 0H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
{{ note().updatedAt | date:'medium' }}
</span>
<span class="inline-flex items-center gap-1">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 8c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM5.5 21a6.5 6.5 0 0113 0" />
</svg>
{{ getAuthorFromFrontmatter() ?? note().author ?? 'Auteur inconnu' }}
</span>
</div>
<!-- Row 2: state icons (toggle buttons) -->
<div class="flex flex-wrap items-center gap-3">
@if (hasState('favoris')) {
<button type="button" class="inline-flex items-center gap-1 transition-colors focus:outline-none" [ngClass]="state('favoris') ? 'text-rose-500' : 'text-muted'" title="{{ state('favoris') ? 'Ajouté aux favoris' : 'Non favori' }}" aria-label="{{ state('favoris') ? 'Ajouté aux favoris' : 'Non favori' }}" (click)="toggleState('favoris')">
@if (state('favoris')) {
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="currentColor" stroke="none">
<path d="M19 14.5c1.5-1.5 2-4 0-6s-5-2-7 1c-2-3-5-3.5-7-1s-1.5 4.5 0 6l7 6z" />
</svg>
} @else {
@if (hasState('publish')) {
<button type="button" class="inline-flex items-center gap-1 transition-colors focus:outline-none" [ngClass]="state('publish') ? 'text-green-500' : 'text-muted'" title="{{ state('publish') ? 'Publié sur le web' : 'Non publié' }}" aria-label="{{ state('publish') ? 'Publié sur le web' : 'Non publié' }}" (click)="toggleState('publish')">
<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="M19 14.5c1.5-1.5 2-4 0-6s-5-2-7 1c-2-3-5-3.5-7-1s-1.5 4.5 0 6l7 6z" />
<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>
}
</button>
}
@if (hasState('publish')) {
<button type="button" class="inline-flex items-center gap-1 transition-colors focus:outline-none" [ngClass]="state('publish') ? 'text-green-500' : 'text-muted'" title="{{ state('publish') ? 'Publié sur le web' : 'Non publié' }}" aria-label="{{ state('publish') ? 'Publié sur le web' : 'Non publié' }}" (click)="toggleState('publish')">
<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>
</button>
}
@if (hasState('draft')) {
<button type="button" class="inline-flex items-center gap-1 transition-colors focus:outline-none" [ngClass]="state('draft') ? 'text-yellow-500' : 'text-muted'" title="{{ state('draft') ? 'Brouillon actif' : 'Pas un brouillon' }}" aria-label="{{ state('draft') ? 'Brouillon actif' : 'Pas un brouillon' }}" (click)="toggleState('draft')">
@if (state('draft')) {
<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="M3 3h18v4H3z" />
<path d="M6 7v14h12V7" />
<path d="M9 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="4" width="18" height="16" rx="2" />
</svg>
}
</button>
}
@if (hasState('template')) {
<button type="button" class="inline-flex items-center gap-1 transition-colors focus:outline-none" [ngClass]="state('template') ? 'text-amber-500' : 'text-muted'" title="{{ state('template') ? 'Modèle' : 'Non modèle' }}" aria-label="{{ state('template') ? 'Modèle' : 'Non modèle' }}" (click)="toggleState('template')">
@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>
}
</button>
}
@if (hasState('task')) {
<button type="button" class="inline-flex items-center gap-1 transition-colors focus:outline-none" [ngClass]="state('task') ? 'text-indigo-500' : 'text-muted'" title="{{ state('task') ? 'Tâche' : 'Pas une tâche' }}" aria-label="{{ state('task') ? 'Tâche' : 'Pas une tâche' }}" (click)="toggleState('task')">
@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>
}
</button>
}
@if (hasState('private')) {
<button type="button" class="inline-flex items-center gap-1 transition-colors focus:outline-none" [ngClass]="state('private') ? 'text-purple-500' : 'text-muted'" title="{{ state('private') ? 'Privé' : 'Public' }}" aria-label="{{ state('private') ? 'Privé' : 'Public' }}" (click)="toggleState('private')">
@if (state('private')) {
<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="11" width="18" height="11" rx="2" />
<path d="M7 11V7a5 5 0 0 1 10 0v4" />
</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="11" width="18" height="11" rx="2" ry="2" />
<path d="M7 11V7a5 5 0 0 1 9.9-1" />
</svg>
}
</button>
}
@if (hasState('archive')) {
<button type="button" class="inline-flex items-center gap-1 transition-colors focus:outline-none" [ngClass]="state('archive') ? 'text-amber-600' : 'text-muted'" title="{{ state('archive') ? 'Document archivé' : 'Document non archivé' }}" aria-label="{{ state('archive') ? 'Document archivé' : 'Document non archivé' }}" (click)="toggleState('archive')">
@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>
</button>
}
</button>
}
</div>
</div>
<div [innerHTML]="sanitizedHtmlContent()"></div>
@if (note().backlinks.length > 0) {
<div class="mt-12 pt-6 border-t border-border not-prose">
<h2 class="text-2xl font-bold mb-4">Backlinks</h2>
<ul>
@for (backlinkId of note().backlinks; track backlinkId) {
<li class="mb-2">
<a
(click)="noteLinkClicked.emit(backlinkId)"
class="cursor-pointer text-accent hover:underline">
{{ formatBacklinkId(backlinkId) }}
</a>
</li>
@if (hasState('draft')) {
<button type="button" class="inline-flex items-center gap-1 transition-colors focus:outline-none" [ngClass]="state('draft') ? 'text-yellow-500' : 'text-muted'" title="{{ state('draft') ? 'Brouillon actif' : 'Pas un brouillon' }}" aria-label="{{ state('draft') ? 'Brouillon actif' : 'Pas un brouillon' }}" (click)="toggleState('draft')">
@if (state('draft')) {
<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="M3 3h18v4H3z" />
<path d="M6 7v14h12V7" />
<path d="M9 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="4" width="18" height="16" rx="2" />
</svg>
}
</button>
}
@if (hasState('template')) {
<button type="button" class="inline-flex items-center gap-1 transition-colors focus:outline-none" [ngClass]="state('template') ? 'text-amber-500' : 'text-muted'" title="{{ state('template') ? 'Modèle' : 'Non modèle' }}" aria-label="{{ state('template') ? 'Modèle' : 'Non modèle' }}" (click)="toggleState('template')">
@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>
}
</button>
}
@if (hasState('task')) {
<button type="button" class="inline-flex items-center gap-1 transition-colors focus:outline-none" [ngClass]="state('task') ? 'text-indigo-500' : 'text-muted'" title="{{ state('task') ? 'Tâche' : 'Pas une tâche' }}" aria-label="{{ state('task') ? 'Tâche' : 'Pas une tâche' }}" (click)="toggleState('task')">
@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>
}
</button>
}
@if (hasState('private')) {
<button type="button" class="inline-flex items-center gap-1 transition-colors focus:outline-none" [ngClass]="state('private') ? 'text-purple-500' : 'text-muted'" title="{{ state('private') ? 'Privé' : 'Public' }}" aria-label="{{ state('private') ? 'Privé' : 'Public' }}" (click)="toggleState('private')">
@if (state('private')) {
<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="11" width="18" height="11" rx="2" />
<path d="M7 11V7a5 5 0 0 1 10 0v4" />
</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="11" width="18" height="11" rx="2" ry="2" />
<path d="M7 11V7a5 5 0 0 1 9.9-1" />
</svg>
}
</button>
}
@if (hasState('archive')) {
<button type="button" class="inline-flex items-center gap-1 transition-colors focus:outline-none" [ngClass]="state('archive') ? 'text-amber-600' : 'text-muted'" title="{{ state('archive') ? 'Document archivé' : 'Document non archivé' }}" aria-label="{{ state('archive') ? 'Document archivé' : 'Document non archivé' }}" (click)="toggleState('archive')">
@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>
}
</ul>
</button>
}
</div>
</div>
}
}
<div [innerHTML]="sanitizedHtmlContent()"></div>
}
</ng-container>
<ng-container *ngIf="note() as backlinksNote">
@if (backlinksNote.backlinks.length > 0) {
<div class="mt-12 pt-6 border-t border-border not-prose">
<h2 class="text-2xl font-bold mb-4">Backlinks</h2>
<ul>
@for (backlinkId of backlinksNote.backlinks; track backlinkId) {
<li class="mb-2">
<a
(click)="noteLinkClicked.emit(backlinkId)"
class="cursor-pointer text-accent hover:underline">
{{ formatBacklinkId(backlinkId) }}
</a>
</li>
}
</ul>
</div>
}
</ng-container>
</div>
`,
})
@@ -959,8 +975,10 @@ export class NoteViewerComponent implements OnDestroy {
hasState(key: 'publish' | 'favoris' | 'archive' | 'draft' | 'private' | 'template' | 'task'): boolean {
try {
const fm = (this.note()?.frontmatter ?? {}) as any;
const raw = (fm as any)[key];
const note = this.note();
if (!note?.frontmatter) return false;
const fm = note.frontmatter as any;
const raw = fm[key];
return raw !== undefined && raw !== null;
} catch {
return false;
@@ -969,8 +987,10 @@ export class NoteViewerComponent implements OnDestroy {
state(key: 'publish' | 'favoris' | 'archive' | 'draft' | 'private' | 'template' | 'task'): boolean {
try {
const fm = (this.note()?.frontmatter ?? {}) as any;
const raw = (fm as any)[key];
const note = this.note();
if (!note?.frontmatter) return false;
const fm = note.frontmatter as any;
const raw = fm[key];
return this.toBoolean(raw);
} catch {
return false;