feat: enhance navigation and filtering behavior
- Added clickable app title links in header and sidebar that reset view to all markdown files - Fixed quicklink filtering to use correct frontmatter boolean keys (favoris, publish, draft, etc.) - Updated sidebar behavior to auto-open Quick Links section when viewing markdown files - Added filter clearing when switching between views to prevent conflicting filters - Modified URL state handling to preserve kind parameter when navigating - Enforced markdown-only
This commit is contained in:
		
							parent
							
								
									58b22a47c9
								
							
						
					
					
						commit
						1545dbb20a
					
				
							
								
								
									
										29
									
								
								e2e/quicklinks-sync.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								e2e/quicklinks-sync.spec.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					import { test, expect } from '@playwright/test';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Quick Links → Search/Filters → Notes-list sync
 | 
				
			||||||
 | 
					 * - One click on a Quick Link shows the filter pill above the search immediately
 | 
				
			||||||
 | 
					 * - Notes-list updates accordingly
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test.describe('Quick Links state sync', () => {
 | 
				
			||||||
 | 
					  test.beforeEach(async ({ page }) => {
 | 
				
			||||||
 | 
					    await page.goto('http://localhost:4200');
 | 
				
			||||||
 | 
					    await page.waitForLoadState('networkidle');
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test('one-click Favoris shows pill above search', async ({ page }) => {
 | 
				
			||||||
 | 
					    // Open Quick Links if inside an accordion in desktop left sidebar
 | 
				
			||||||
 | 
					    await page.getByText('Quick Links').first().click({ trial: true }).catch(() => {});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Click on Favoris in Quick Links
 | 
				
			||||||
 | 
					    await page.getByText('Favoris', { exact: true }).first().click();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Expect a pill with label "Favoris" to appear above the search input in the list panel
 | 
				
			||||||
 | 
					    const pill = page.locator('app-filter-badge .label', { hasText: 'Favoris' });
 | 
				
			||||||
 | 
					    await expect(pill).toBeVisible({ timeout: 3000 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // URL should contain quick=Favoris
 | 
				
			||||||
 | 
					    await expect.poll(async () => new URL(page.url()).searchParams.get('quick')).toBe('Favoris');
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -318,7 +318,9 @@
 | 
				
			|||||||
            <div class="min-w-0 flex flex-col gap-1">
 | 
					            <div class="min-w-0 flex flex-col gap-1">
 | 
				
			||||||
              <div class="flex items-center gap-2 min-w-0">
 | 
					              <div class="flex items-center gap-2 min-w-0">
 | 
				
			||||||
                <span class="inline-flex items-center rounded-lg border border-border bg-bg-muted/70 px-2.5 py-1 text-xs font-semibold uppercase tracking-wide text-text-muted">{{ vaultName() }}</span>
 | 
					                <span class="inline-flex items-center rounded-lg border border-border bg-bg-muted/70 px-2.5 py-1 text-xs font-semibold uppercase tracking-wide text-text-muted">{{ vaultName() }}</span>
 | 
				
			||||||
                <h1 class="text-lg font-semibold leading-tight text-text-main">ObsiWatcher</h1>
 | 
					                <h1 class="text-lg font-semibold leading-tight text-text-main">
 | 
				
			||||||
 | 
					                  <a href="/" (click)="onAppTitleClick($event)" class="hover:underline">ObsiWatcher</a>
 | 
				
			||||||
 | 
					                </h1>
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
              @if (selectedNoteBreadcrumb().length > 0) {
 | 
					              @if (selectedNoteBreadcrumb().length > 0) {
 | 
				
			||||||
                <p class="truncate text-xs text-text-muted">{{ selectedNoteBreadcrumb().join(' / ') }}</p>
 | 
					                <p class="truncate text-xs text-text-muted">{{ selectedNoteBreadcrumb().join(' / ') }}</p>
 | 
				
			||||||
 | 
				
			|||||||
@ -884,6 +884,16 @@ export class AppComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  onAppTitleClick(event: MouseEvent): void {
 | 
				
			||||||
 | 
					    event.preventDefault();
 | 
				
			||||||
 | 
					    this.isSidebarOpen.set(true);
 | 
				
			||||||
 | 
					    this.activeView.set('files');
 | 
				
			||||||
 | 
					    queueMicrotask(async () => {
 | 
				
			||||||
 | 
					      await this.urlState.showAllAndReset();
 | 
				
			||||||
 | 
					      await this.urlState.filterByKind('markdown');
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  onCalendarSearchErrorChange(message: string | null): void {
 | 
					  onCalendarSearchErrorChange(message: string | null): void {
 | 
				
			||||||
    this.calendarSearchError.set(message);
 | 
					    this.calendarSearchError.set(message);
 | 
				
			||||||
    if (message) {
 | 
					    if (message) {
 | 
				
			||||||
 | 
				
			|||||||
@ -663,13 +663,14 @@ export class NotesListComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  private mapInternalQuickToFrontmatter(id: 'favoris' | 'publish' | 'draft' | 'template' | 'task' | 'private' | 'archive' | null): string | null {
 | 
					  private mapInternalQuickToFrontmatter(id: 'favoris' | 'publish' | 'draft' | 'template' | 'task' | 'private' | 'archive' | null): string | null {
 | 
				
			||||||
    switch (id || '') {
 | 
					    switch (id || '') {
 | 
				
			||||||
      case 'favoris': return 'Favoris';
 | 
					      // Match actual frontmatter boolean keys used in the vault service and writers
 | 
				
			||||||
      case 'publish': return 'Publié';
 | 
					      case 'favoris': return 'favoris';
 | 
				
			||||||
      case 'draft': return 'Brouillons';
 | 
					      case 'publish': return 'publish';
 | 
				
			||||||
      case 'template': return 'Modèles';
 | 
					      case 'draft': return 'draft';
 | 
				
			||||||
      case 'task': return 'Tâches';
 | 
					      case 'template': return 'template';
 | 
				
			||||||
      case 'private': return 'Privé';
 | 
					      case 'task': return 'task';
 | 
				
			||||||
      case 'archive': return 'Archive';
 | 
					      case 'private': return 'private';
 | 
				
			||||||
 | 
					      case 'archive': return 'archive';
 | 
				
			||||||
      default: return null;
 | 
					      default: return null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -720,9 +721,13 @@ export class NotesListComponent {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (quickLink) {
 | 
					    if (quickLink) {
 | 
				
			||||||
      const fmKey = this.mapInternalQuickToFrontmatter(quickLink);
 | 
					      const fmKey = this.mapInternalQuickToFrontmatter(quickLink);
 | 
				
			||||||
 | 
					      // Enforce Markdown-only when a Quick Link is active and match frontmatter boolean flag
 | 
				
			||||||
      list = list.filter(n => {
 | 
					      list = list.filter(n => {
 | 
				
			||||||
        const frontmatter = n.frontmatter || {} as any;
 | 
					        const frontmatter = n.frontmatter || ({} as any);
 | 
				
			||||||
        return fmKey ? frontmatter[fmKey] === true : false;
 | 
					        return (
 | 
				
			||||||
 | 
					          this.matchesKind(n, 'markdown') &&
 | 
				
			||||||
 | 
					          (fmKey ? frontmatter[fmKey] === true : false)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -20,10 +20,10 @@ import { FilterService } from '../../services/filter.service';
 | 
				
			|||||||
    <div class="h-full flex flex-col overflow-hidden select-none">
 | 
					    <div class="h-full flex flex-col overflow-hidden select-none">
 | 
				
			||||||
      <!-- Header -->
 | 
					      <!-- Header -->
 | 
				
			||||||
      <div class="h-12 flex items-center justify-between px-3 border-b border-border dark:border-gray-800">
 | 
					      <div class="h-12 flex items-center justify-between px-3 border-b border-border dark:border-gray-800">
 | 
				
			||||||
        <div class="flex items-center gap-2 min-w-0">
 | 
					        <a href="/" (click)="onHomeClick($event)" class="flex items-center gap-2 min-w-0 text-inherit no-underline">
 | 
				
			||||||
          <img src="assets/favicon.svg" alt="ObsiViewer" class="h-6 w-6 flex-shrink-0" />
 | 
					          <img src="assets/favicon.svg" alt="ObsiViewer" class="h-6 w-6 flex-shrink-0" />
 | 
				
			||||||
          <div class="text-sm font-semibold truncate">{{ vaultName }} - ObsiViewer</div>
 | 
					          <span class="text-sm font-semibold truncate">{{ vaultName }} - ObsiViewer</span>
 | 
				
			||||||
        </div>
 | 
					        </a>
 | 
				
			||||||
        <button (click)="toggleSidebarRequest.emit()" class="p-2 rounded hover:bg-surface1 dark:hover:bg-card" title="Hide Sidebar">⟨⟨</button>
 | 
					        <button (click)="toggleSidebarRequest.emit()" class="p-2 rounded hover:bg-surface1 dark:hover:bg-card" title="Hide Sidebar">⟨⟨</button>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -217,7 +217,7 @@ export class NimbusSidebarComponent implements OnChanges {
 | 
				
			|||||||
  @Output() aboutSelected = new EventEmitter<void>();
 | 
					  @Output() aboutSelected = new EventEmitter<void>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  env = environment;
 | 
					  env = environment;
 | 
				
			||||||
  open = { quick: true, folders: true, tags: false, trash: false, tests: false };
 | 
					  open = { quick: true, folders: false, tags: false, trash: false, tests: false };
 | 
				
			||||||
  private vault = inject(VaultService);
 | 
					  private vault = inject(VaultService);
 | 
				
			||||||
  urlState = inject(UrlStateService);
 | 
					  urlState = inject(UrlStateService);
 | 
				
			||||||
  private sidebar = inject(SidebarStateService);
 | 
					  private sidebar = inject(SidebarStateService);
 | 
				
			||||||
@ -239,6 +239,15 @@ export class NimbusSidebarComponent implements OnChanges {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  onQuickLink(id: string) { this.quickLinkSelected.emit(id); }
 | 
					  onQuickLink(id: string) { this.quickLinkSelected.emit(id); }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
 | 
					  onHomeClick(event: MouseEvent): void {
 | 
				
			||||||
 | 
					    event.preventDefault();
 | 
				
			||||||
 | 
					    this.toggleSection('quick');
 | 
				
			||||||
 | 
					    this.quickLinkSelected.emit('all');
 | 
				
			||||||
 | 
					    queueMicrotask(async () => {
 | 
				
			||||||
 | 
					      await this.urlState.filterByKind('markdown');
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  onMarkdownPlaygroundClick(): void {
 | 
					  onMarkdownPlaygroundClick(): void {
 | 
				
			||||||
    this.markdownPlaygroundSelected.emit();
 | 
					    this.markdownPlaygroundSelected.emit();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -21,6 +21,7 @@ import { TestExcalidrawPageComponent } from '../../features/tests/test-excalidra
 | 
				
			|||||||
import { ParametersPage } from '../../features/parameters/parameters.page';
 | 
					import { ParametersPage } from '../../features/parameters/parameters.page';
 | 
				
			||||||
import { AboutPanelComponent } from '../../features/about/about-panel.component';
 | 
					import { AboutPanelComponent } from '../../features/about/about-panel.component';
 | 
				
			||||||
import { UrlStateService } from '../../services/url-state.service';
 | 
					import { UrlStateService } from '../../services/url-state.service';
 | 
				
			||||||
 | 
					import { FilterService } from '../../services/filter.service';
 | 
				
			||||||
import { NoteInfoModalComponent } from '../../features/note-info/note-info-modal.component';
 | 
					import { NoteInfoModalComponent } from '../../features/note-info/note-info-modal.component';
 | 
				
			||||||
import { NoteInfoModalService } from '../../services/note-info-modal.service';
 | 
					import { NoteInfoModalService } from '../../services/note-info-modal.service';
 | 
				
			||||||
import { InPageSearchService } from '../../shared/search/in-page-search.service';
 | 
					import { InPageSearchService } from '../../shared/search/in-page-search.service';
 | 
				
			||||||
@ -67,7 +68,11 @@ import { InPageSearchOverlayComponent } from '../../shared/search/in-page-search
 | 
				
			|||||||
              [selectedNoteId]="selectedNoteId"
 | 
					              [selectedNoteId]="selectedNoteId"
 | 
				
			||||||
              [tags]="tags"
 | 
					              [tags]="tags"
 | 
				
			||||||
              [quickLinkFilter]="quickLinkFilter"
 | 
					              [quickLinkFilter]="quickLinkFilter"
 | 
				
			||||||
              [forceOpenSection]="tagFilter ? 'tags' : (folderFilter ? 'folders' : (quickLinkFilter ? 'quick' : null))"
 | 
					              [forceOpenSection]="
 | 
				
			||||||
 | 
					                (!tagFilter && !folderFilter && !quickLinkFilter && urlState.activeKind() === 'markdown')
 | 
				
			||||||
 | 
					                  ? 'quick'
 | 
				
			||||||
 | 
					                  : (tagFilter ? 'tags' : (folderFilter ? 'folders' : (quickLinkFilter ? 'quick' : null)))
 | 
				
			||||||
 | 
					              "
 | 
				
			||||||
              (toggleSidebarRequest)="toggleSidebarRequest.emit()"
 | 
					              (toggleSidebarRequest)="toggleSidebarRequest.emit()"
 | 
				
			||||||
              (folderSelected)="onFolderSelected($event)"
 | 
					              (folderSelected)="onFolderSelected($event)"
 | 
				
			||||||
              (fileSelected)="noteSelected.emit($event)"
 | 
					              (fileSelected)="noteSelected.emit($event)"
 | 
				
			||||||
@ -341,6 +346,7 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
 | 
				
			|||||||
  responsive = inject(ResponsiveService);
 | 
					  responsive = inject(ResponsiveService);
 | 
				
			||||||
  mobileNav = inject(MobileNavService);
 | 
					  mobileNav = inject(MobileNavService);
 | 
				
			||||||
  urlState = inject(UrlStateService);
 | 
					  urlState = inject(UrlStateService);
 | 
				
			||||||
 | 
					  filters = inject(FilterService);
 | 
				
			||||||
  noteInfo = inject(NoteInfoModalService);
 | 
					  noteInfo = inject(NoteInfoModalService);
 | 
				
			||||||
  inPageSearch = inject(InPageSearchService);
 | 
					  inPageSearch = inject(InPageSearchService);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -722,17 +728,22 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
 | 
				
			|||||||
      this.tagFilter = null;
 | 
					      this.tagFilter = null;
 | 
				
			||||||
      this.quickLinkFilter = null;
 | 
					      this.quickLinkFilter = null;
 | 
				
			||||||
      this.listQuery = '';
 | 
					      this.listQuery = '';
 | 
				
			||||||
 | 
					      // Clear local filters (kinds, cumulative tags) to avoid conflicting filters
 | 
				
			||||||
 | 
					      try { this.filters.clearKinds(); } catch {}
 | 
				
			||||||
 | 
					      try { this.filters.clearTags(); } catch {}
 | 
				
			||||||
      if (!this.responsive.isDesktop()) {
 | 
					      if (!this.responsive.isDesktop()) {
 | 
				
			||||||
        this.mobileNav.setActiveTab('list');
 | 
					        this.mobileNav.setActiveTab('list');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      this.scheduleCloseFlyout(150);
 | 
					      this.scheduleCloseFlyout(150);
 | 
				
			||||||
      this.urlState.resetState();
 | 
					      this.urlState.showAllAndReset();
 | 
				
			||||||
    } else if (_id === 'publish') {
 | 
					    } else if (_id === 'publish') {
 | 
				
			||||||
      // Filter by publish: true
 | 
					      // Filter by publish: true
 | 
				
			||||||
      this.folderFilter = null;
 | 
					      this.folderFilter = null;
 | 
				
			||||||
      this.tagFilter = null;
 | 
					      this.tagFilter = null;
 | 
				
			||||||
      this.quickLinkFilter = 'publish';
 | 
					      this.quickLinkFilter = 'publish';
 | 
				
			||||||
      this.listQuery = '';
 | 
					      this.listQuery = '';
 | 
				
			||||||
 | 
					      try { this.filters.clearKinds(); } catch {}
 | 
				
			||||||
 | 
					      try { this.filters.clearTags(); } catch {}
 | 
				
			||||||
      if (!this.responsive.isDesktop()) {
 | 
					      if (!this.responsive.isDesktop()) {
 | 
				
			||||||
        this.mobileNav.setActiveTab('list');
 | 
					        this.mobileNav.setActiveTab('list');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -745,6 +756,8 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
 | 
				
			|||||||
      this.tagFilter = null;
 | 
					      this.tagFilter = null;
 | 
				
			||||||
      this.quickLinkFilter = 'favoris';
 | 
					      this.quickLinkFilter = 'favoris';
 | 
				
			||||||
      this.listQuery = '';
 | 
					      this.listQuery = '';
 | 
				
			||||||
 | 
					      try { this.filters.clearKinds(); } catch {}
 | 
				
			||||||
 | 
					      try { this.filters.clearTags(); } catch {}
 | 
				
			||||||
      if (!this.responsive.isDesktop()) {
 | 
					      if (!this.responsive.isDesktop()) {
 | 
				
			||||||
        this.mobileNav.setActiveTab('list');
 | 
					        this.mobileNav.setActiveTab('list');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -757,6 +770,8 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
 | 
				
			|||||||
      this.tagFilter = null;
 | 
					      this.tagFilter = null;
 | 
				
			||||||
      this.quickLinkFilter = 'template';
 | 
					      this.quickLinkFilter = 'template';
 | 
				
			||||||
      this.listQuery = '';
 | 
					      this.listQuery = '';
 | 
				
			||||||
 | 
					      try { this.filters.clearKinds(); } catch {}
 | 
				
			||||||
 | 
					      try { this.filters.clearTags(); } catch {}
 | 
				
			||||||
      if (!this.responsive.isDesktop()) {
 | 
					      if (!this.responsive.isDesktop()) {
 | 
				
			||||||
        this.mobileNav.setActiveTab('list');
 | 
					        this.mobileNav.setActiveTab('list');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -769,6 +784,8 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
 | 
				
			|||||||
      this.tagFilter = null;
 | 
					      this.tagFilter = null;
 | 
				
			||||||
      this.quickLinkFilter = 'task';
 | 
					      this.quickLinkFilter = 'task';
 | 
				
			||||||
      this.listQuery = '';
 | 
					      this.listQuery = '';
 | 
				
			||||||
 | 
					      try { this.filters.clearKinds(); } catch {}
 | 
				
			||||||
 | 
					      try { this.filters.clearTags(); } catch {}
 | 
				
			||||||
      if (!this.responsive.isDesktop()) {
 | 
					      if (!this.responsive.isDesktop()) {
 | 
				
			||||||
        this.mobileNav.setActiveTab('list');
 | 
					        this.mobileNav.setActiveTab('list');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -781,6 +798,8 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
 | 
				
			|||||||
      this.tagFilter = null;
 | 
					      this.tagFilter = null;
 | 
				
			||||||
      this.quickLinkFilter = 'draft';
 | 
					      this.quickLinkFilter = 'draft';
 | 
				
			||||||
      this.listQuery = '';
 | 
					      this.listQuery = '';
 | 
				
			||||||
 | 
					      try { this.filters.clearKinds(); } catch {}
 | 
				
			||||||
 | 
					      try { this.filters.clearTags(); } catch {}
 | 
				
			||||||
      if (!this.responsive.isDesktop()) {
 | 
					      if (!this.responsive.isDesktop()) {
 | 
				
			||||||
        this.mobileNav.setActiveTab('list');
 | 
					        this.mobileNav.setActiveTab('list');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -793,6 +812,8 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
 | 
				
			|||||||
      this.tagFilter = null;
 | 
					      this.tagFilter = null;
 | 
				
			||||||
      this.quickLinkFilter = 'private';
 | 
					      this.quickLinkFilter = 'private';
 | 
				
			||||||
      this.listQuery = '';
 | 
					      this.listQuery = '';
 | 
				
			||||||
 | 
					      try { this.filters.clearKinds(); } catch {}
 | 
				
			||||||
 | 
					      try { this.filters.clearTags(); } catch {}
 | 
				
			||||||
      if (!this.responsive.isDesktop()) {
 | 
					      if (!this.responsive.isDesktop()) {
 | 
				
			||||||
        this.mobileNav.setActiveTab('list');
 | 
					        this.mobileNav.setActiveTab('list');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -805,6 +826,8 @@ export class AppShellNimbusLayoutComponent implements AfterViewInit {
 | 
				
			|||||||
      this.tagFilter = null;
 | 
					      this.tagFilter = null;
 | 
				
			||||||
      this.quickLinkFilter = 'archive';
 | 
					      this.quickLinkFilter = 'archive';
 | 
				
			||||||
      this.listQuery = '';
 | 
					      this.listQuery = '';
 | 
				
			||||||
 | 
					      try { this.filters.clearKinds(); } catch {}
 | 
				
			||||||
 | 
					      try { this.filters.clearTags(); } catch {}
 | 
				
			||||||
      if (!this.responsive.isDesktop()) {
 | 
					      if (!this.responsive.isDesktop()) {
 | 
				
			||||||
        this.mobileNav.setActiveTab('list');
 | 
					        this.mobileNav.setActiveTab('list');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
				
			|||||||
@ -189,7 +189,8 @@ export class UrlStateService implements OnDestroy {
 | 
				
			|||||||
                folder: nextSection === 'folder' ? newState.folder! : null,
 | 
					                folder: nextSection === 'folder' ? newState.folder! : null,
 | 
				
			||||||
                quick: nextSection === 'quick' ? newState.quick! : null,
 | 
					                quick: nextSection === 'quick' ? newState.quick! : null,
 | 
				
			||||||
                search: null,
 | 
					                search: null,
 | 
				
			||||||
                kind: 'all',
 | 
					                // Preserve provided kind if any; fallback to 'all'
 | 
				
			||||||
 | 
					                kind: newState.kind ?? 'all',
 | 
				
			||||||
                note: null,
 | 
					                note: null,
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
              this.updateUrl(partial);
 | 
					              this.updateUrl(partial);
 | 
				
			||||||
@ -381,15 +382,18 @@ export class UrlStateService implements OnDestroy {
 | 
				
			|||||||
   * Filtrer par quick link
 | 
					   * Filtrer par quick link
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  async filterByQuickLink(quickLink: string): Promise<void> {
 | 
					  async filterByQuickLink(quickLink: string): Promise<void> {
 | 
				
			||||||
    const validQuickLinks = ['Favoris', 'Publié', 'Modèles', 'Tâches', 'Brouillons', 'Privé', 'Archive', 'Corbeille'];
 | 
					    const validQuickLinks = ['all', 'All Pages', 'Favoris', 'Publié', 'Modèles', 'Tâches', 'Brouillons', 'Privé', 'Archive', 'Corbeille', 'favorites', 'publish', 'drafts', 'templates', 'tasks', 'private', 'archive'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!validQuickLinks.includes(quickLink)) {
 | 
					    if (!validQuickLinks.includes(quickLink)) {
 | 
				
			||||||
      console.warn(`Invalid quick link: ${quickLink}`);
 | 
					      console.warn(`Invalid quick link: ${quickLink}`);
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Si 'All Pages' est sélectionné, on veut supprimer le filtre 'quick'.
 | 
				
			||||||
 | 
					    const newQuickValue = (quickLink === 'all' || quickLink === 'All Pages') ? null : quickLink;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Mettre à jour l'URL
 | 
					    // Mettre à jour l'URL
 | 
				
			||||||
    await this.updateUrl({ quick: quickLink, note: null, tag: null, folder: null, search: null });
 | 
					    await this.updateUrl({ quick: newQuickValue, note: null, tag: null, folder: null, search: null });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
@ -460,15 +464,15 @@ export class UrlStateService implements OnDestroy {
 | 
				
			|||||||
    const currentState = this.currentStateSignal();
 | 
					    const currentState = this.currentStateSignal();
 | 
				
			||||||
    const newState = { ...currentState, ...partialState };
 | 
					    const newState = { ...currentState, ...partialState };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Nettoyer les propriétés undefined
 | 
					    // Nettoyer les propriétés undefined ou null
 | 
				
			||||||
    const cleanState = Object.fromEntries(
 | 
					    const cleanState = Object.fromEntries(
 | 
				
			||||||
      Object.entries(newState).filter(([_, v]) => v !== undefined)
 | 
					      Object.entries(newState).filter(([_, v]) => v !== undefined && v !== null)
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Naviguer avec les nouveaux queryParams
 | 
					    // Naviguer avec les nouveaux queryParams, en remplaçant les anciens.
 | 
				
			||||||
    await this.router.navigate([], {
 | 
					    await this.router.navigate([], {
 | 
				
			||||||
      queryParams: cleanState,
 | 
					      queryParams: cleanState,
 | 
				
			||||||
      queryParamsHandling: 'merge',
 | 
					      queryParamsHandling: '', // Remplacer au lieu de fusionner
 | 
				
			||||||
      preserveFragment: true
 | 
					      preserveFragment: true
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user