chore: delete unused trash explorer documentation files

This commit is contained in:
2025-10-23 09:40:06 -04:00
parent c030f91ebe
commit 291b2e61b0
46 changed files with 11814 additions and 6 deletions
@@ -0,0 +1,224 @@
import { Component, EventEmitter, Output, input, signal, computed, effect, inject, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ScrollingModule, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { PaginationService, NoteMetadata } from '../../services/pagination.service';
import { TagFilterStore } from '../../core/stores/tag-filter.store';
import { ScrollableOverlayDirective } from '../../shared/overlay-scrollbar/scrollable-overlay.directive';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-paginated-notes-list',
standalone: true,
imports: [CommonModule, ScrollingModule, ScrollableOverlayDirective],
template: `
<div class="h-full flex flex-col">
<!-- Search and filters header -->
<div class="p-2 border-b border-border dark:border-gray-800 space-y-2">
<div *ngIf="activeTag() as t" class="flex items-center gap-2 text-xs">
<span class="inline-flex items-center gap-1 rounded-full bg-surface1 dark:bg-card text-main dark:text-main px-2 py-1">
<svg class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 7h.01"/><path d="M3 7h5a2 2 0 0 1 1.414.586l7 7a2 2 0 0 1 0 2.828l-3.172 3.172a2 2 0 0 1-2.828 0l-7-7A2 2 0 0 1 3 12V7Z"/></svg>
Filtre: #{{ t }}
</span>
<button type="button" (click)="clearTagFilter()" class="rounded-full hover:bg-slate-500/10 dark:hover:bg-surface2/10 w-6 h-6 inline-flex items-center justify-center" title="Effacer le filtre">
<svg class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
</button>
</div>
<div *ngIf="quickLinkFilter() && getQuickLinkDisplay(quickLinkFilter()) as ql" class="flex items-center gap-2 text-xs">
<span class="inline-flex items-center gap-1 rounded-full bg-surface1 dark:bg-card text-main dark:text-main px-2 py-1">
{{ ql.icon }} {{ ql.name }}
</span>
<button type="button" (click)="clearQuickLinkFilter.emit()" class="rounded-full hover:bg-slate-500/10 dark:hover:bg-surface2/10 w-6 h-6 inline-flex items-center justify-center" title="Effacer le filtre">
<svg class="h-3.5 w-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
</button>
</div>
<input type="text"
[value]="query()"
(input)="onQuery($any($event.target).value)"
placeholder="Rechercher..."
class="w-full rounded border border-border dark:border-border bg-card dark:bg-main px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring" />
</div>
<!-- Virtual scroll viewport -->
<div class="flex-1 min-h-0 overflow-hidden">
<cdk-virtual-scroll-viewport
#viewport
itemSize="60"
class="h-full w-full"
(scrolledIndexChange)="onScroll($event)"
appScrollableOverlay>
<ul class="divide-y divide-gray-100 dark:divide-gray-800">
<!-- Virtual items -->
<li *cdkVirtualFor="let note of paginatedNotes(); trackBy: trackByFn"
class="p-3 hover:bg-surface1 dark:hover:bg-card cursor-pointer transition-colors min-h-[60px] flex flex-col justify-center"
[class.selected]="note.id === selectedNoteId()"
(click)="selectNote(note)">
<div class="text-sm font-semibold truncate">{{ note.title }}</div>
<div class="text-xs text-muted truncate">{{ note.filePath }}</div>
</li>
<!-- Loading indicator -->
<li *ngIf="isLoadingMore()" class="p-4 text-center text-muted min-h-[60px] flex items-center justify-center">
<div class="inline-flex items-center gap-2">
<div class="inline-block animate-spin rounded-full h-4 w-4 border-b-2 border-primary"></div>
<span>Chargement...</span>
</div>
</li>
<!-- End of list indicator -->
<li *ngIf="!hasMore() && totalLoaded() > 0" class="p-4 text-center text-muted min-h-[60px] flex items-center justify-center">
{{ totalLoaded() }} notes chargées
</li>
<!-- Empty state -->
<li *ngIf="totalLoaded() === 0 && !isLoadingMore()" class="p-4 text-center text-muted min-h-[60px] flex items-center justify-center">
Aucune note trouvée
</li>
</ul>
</cdk-virtual-scroll-viewport>
</div>
</div>
`,
styles: [`
:host {
display: block;
height: 100%;
min-height: 0;
}
.notes-list-container {
min-height: 400px;
}
.note-item {
min-height: 60px;
display: flex;
flex-direction: column;
justify-content: center;
}
.note-item.selected {
background-color: var(--surface1);
border-left: 3px solid var(--primary);
}
cdk-virtual-scroll-viewport {
height: 100%;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
margin: 0;
}
`]
})
export class PaginatedNotesListComponent implements OnInit, OnDestroy {
private paginationService = inject(PaginationService);
private store = inject(TagFilterStore);
private destroy$ = new Subject<void>();
@ViewChild(CdkVirtualScrollViewport) viewport?: CdkVirtualScrollViewport;
// Inputs
folderFilter = input<string | null>(null);
query = input<string>('');
tagFilter = input<string | null>(null);
quickLinkFilter = input<'favoris' | 'publish' | 'draft' | 'template' | 'task' | 'private' | 'archive' | null>(null);
// Outputs
@Output() openNote = new EventEmitter<string>();
@Output() queryChange = new EventEmitter<string>();
@Output() clearQuickLinkFilter = new EventEmitter<void>();
// Local state
private q = signal('');
selectedNoteId = signal<string | null>(null);
activeTag = signal<string | null>(null);
// Pagination state
paginatedNotes = this.paginationService.allItems;
isLoadingMore = this.paginationService.isLoadingMore;
hasMore = this.paginationService.hasMore;
totalLoaded = this.paginationService.totalLoaded;
canLoadMore = this.paginationService.canLoadMore;
// Effects
private syncQuery = effect(() => {
this.q.set(this.query() || '');
});
private syncTagFromStore = effect(() => {
const inputTag = this.tagFilter();
if (inputTag !== null && inputTag !== undefined) {
this.activeTag.set(inputTag || null);
return;
}
this.activeTag.set(this.store.get());
});
ngOnInit() {
// Load initial page
this.paginationService.loadInitial();
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
// Handle virtual scroll
onScroll(index: number) {
const items = this.paginatedNotes();
// Load more when approaching the end (20 items before the end)
if (index > items.length - 20 && this.canLoadMore()) {
this.paginationService.loadNextPage();
}
}
// Select a note
selectNote(note: NoteMetadata) {
this.selectedNoteId.set(note.id);
this.openNote.emit(note.id);
}
// Search
onQuery(v: string) {
this.q.set(v);
this.queryChange.emit(v);
// Trigger search with pagination
this.paginationService.search(v);
}
// Clear tag filter
clearTagFilter(): void {
this.activeTag.set(null);
if (this.tagFilter() == null) {
this.store.set(null);
}
}
// Track by function for virtual scroll
trackByFn(index: number, item: NoteMetadata): string {
return item.id;
}
// Quick link display
getQuickLinkDisplay(quickLink: string): { icon: string; name: string } | null {
const displays: Record<string, { icon: string; name: string }> = {
'favoris': { icon: '❤️', name: 'Favoris' },
'publish': { icon: '🌐', name: 'Publish' },
'draft': { icon: '📝', name: 'Draft' },
'template': { icon: '📑', name: 'Template' },
'task': { icon: '🗒️', name: 'Task' },
'private': { icon: '🔒', name: 'Private' },
'archive': { icon: '🗃️', name: 'Archive' }
};
return displays[quickLink] || null;
}
}