feat: implement new tag management system with filtering and modern UI overlay
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { Component, EventEmitter, Output, computed, signal, effect } from '@angular/core';
|
||||
import { Component, EventEmitter, Output, computed, signal, effect, inject } from '@angular/core';
|
||||
import { input } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import type { Note } from '../../../types';
|
||||
import { ScrollableOverlayDirective } from '../../shared/overlay-scrollbar/scrollable-overlay.directive';
|
||||
import { TagFilterStore } from '../../core/stores/tag-filter.store';
|
||||
|
||||
@Component({
|
||||
selector: 'app-notes-list',
|
||||
@@ -10,7 +11,16 @@ import { ScrollableOverlayDirective } from '../../shared/overlay-scrollbar/scrol
|
||||
imports: [CommonModule, ScrollableOverlayDirective],
|
||||
template: `
|
||||
<div class="h-full flex flex-col">
|
||||
<div class="p-2 border-b border-gray-200 dark:border-gray-800">
|
||||
<div class="p-2 border-b border-gray-200 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-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-200 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-slate-200/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)"
|
||||
@@ -55,15 +65,26 @@ export class NotesListComponent {
|
||||
@Output() openNote = new EventEmitter<string>();
|
||||
@Output() queryChange = new EventEmitter<string>();
|
||||
|
||||
private store = inject(TagFilterStore);
|
||||
private q = signal('');
|
||||
activeTag = signal<string | null>(null);
|
||||
private syncQuery = effect(() => {
|
||||
this.q.set(this.query() || '');
|
||||
});
|
||||
private syncTagFromStore = effect(() => {
|
||||
// Prefer explicit input; otherwise, take store value
|
||||
const inputTag = this.tagFilter();
|
||||
if (inputTag !== null && inputTag !== undefined) {
|
||||
this.activeTag.set(inputTag || null);
|
||||
return;
|
||||
}
|
||||
this.activeTag.set(this.store.get());
|
||||
});
|
||||
|
||||
filtered = computed(() => {
|
||||
const q = (this.q() || '').toLowerCase().trim();
|
||||
const folder = (this.folderFilter() || '').toLowerCase().replace(/^\/+|\/+$/g, '');
|
||||
const tag = (this.tagFilter() || '').toLowerCase();
|
||||
const tag = (this.activeTag() || '').toLowerCase();
|
||||
const quickLink = this.quickLinkFilter();
|
||||
let list = this.notes();
|
||||
|
||||
@@ -113,4 +134,12 @@ export class NotesListComponent {
|
||||
this.q.set(v);
|
||||
this.queryChange.emit(v);
|
||||
}
|
||||
|
||||
clearTagFilter(): void {
|
||||
// Clear both local input state and store
|
||||
this.activeTag.set(null);
|
||||
if (this.tagFilter() == null) {
|
||||
this.store.set(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<app-tags-editor class="note-header__tags"
|
||||
<app-tag-manager class="note-header__tags"
|
||||
[noteId]="noteId"
|
||||
[tags]="tags"
|
||||
(tagsUpdated)="tagsChange.emit($event)"
|
||||
></app-tags-editor>
|
||||
(saved)="tagsChange.emit($event)"
|
||||
></app-tag-manager>
|
||||
</header>
|
||||
|
||||
@@ -2,12 +2,12 @@ import { AfterViewInit, Component, ElementRef, Input, OnDestroy, Output, EventEm
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { debounceTime, Subject } from 'rxjs';
|
||||
import { splitPathKeepFilename } from '../../../../shared/utils/path';
|
||||
import { TagsEditorComponent } from '../../../../shared/tags-editor/tags-editor.component';
|
||||
import { TagManagerComponent } from '../../../../shared/tags/tag-manager/tag-manager.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-note-header',
|
||||
standalone: true,
|
||||
imports: [CommonModule, TagsEditorComponent],
|
||||
imports: [CommonModule, TagManagerComponent],
|
||||
templateUrl: './note-header.component.html',
|
||||
styleUrls: ['./note-header.component.scss']
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user