tests
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
import { CanMatchFn } from '@angular/router';
|
||||
import { environment } from '../../../environments/environment';
|
||||
|
||||
/**
|
||||
* Guard qui bloque l'accès aux routes en mode production.
|
||||
* Utilisé pour protéger les routes de test et de développement.
|
||||
*/
|
||||
export const devOnlyGuard: CanMatchFn = () => {
|
||||
return !environment.production;
|
||||
};
|
||||
@@ -1,14 +1,16 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { FileExplorerComponent } from '../../../components/file-explorer/file-explorer.component';
|
||||
import { QuickLinksComponent } from '../quick-links/quick-links.component';
|
||||
import { ScrollableOverlayDirective } from '../../shared/overlay-scrollbar/scrollable-overlay.directive';
|
||||
import type { VaultNode, TagInfo } from '../../../types';
|
||||
import { environment } from '../../../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-nimbus-sidebar',
|
||||
standalone: true,
|
||||
imports: [CommonModule, FileExplorerComponent, QuickLinksComponent, ScrollableOverlayDirective],
|
||||
imports: [CommonModule, RouterModule, FileExplorerComponent, QuickLinksComponent, ScrollableOverlayDirective],
|
||||
host: { class: 'block h-full' },
|
||||
template: `
|
||||
<div class="h-full flex flex-col overflow-hidden select-none">
|
||||
@@ -20,6 +22,22 @@ import type { VaultNode, TagInfo } from '../../../types';
|
||||
|
||||
<!-- Content (scroll) -->
|
||||
<div class="flex-1 overflow-y-auto min-h-0" appScrollableOverlay>
|
||||
<!-- Section Tests (dev-only) -->
|
||||
<section *ngIf="env.features.showTestSection" 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.tests = !open.tests">
|
||||
<span>Section Tests</span>
|
||||
<span class="text-xs text-gray-500">{{ open.tests ? '▾' : '▸' }}</span>
|
||||
</button>
|
||||
<div *ngIf="open.tests" class="px-3 py-2">
|
||||
<button
|
||||
(click)="onMarkdownPlaygroundClick()"
|
||||
class="w-full text-left block text-sm px-2 py-1.5 rounded hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100">
|
||||
Markdown Playground
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Quick Links 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"
|
||||
@@ -91,8 +109,14 @@ export class NimbusSidebarComponent {
|
||||
@Output() fileSelected = new EventEmitter<string>();
|
||||
@Output() tagSelected = new EventEmitter<string>();
|
||||
@Output() quickLinkSelected = new EventEmitter<string>();
|
||||
@Output() markdownPlaygroundSelected = new EventEmitter<void>();
|
||||
|
||||
open = { quick: true, folders: true, tags: false, trash: false };
|
||||
env = environment;
|
||||
open = { quick: true, folders: true, tags: false, trash: false, tests: true };
|
||||
|
||||
onQuickLink(id: string) { this.quickLinkSelected.emit(id); }
|
||||
|
||||
onMarkdownPlaygroundClick(): void {
|
||||
this.markdownPlaygroundSelected.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
import { Component, signal, computed, inject } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MarkdownService } from '../../../../services/markdown.service';
|
||||
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
||||
|
||||
const DEFAULT_MD_PATH = 'assets/samples/markdown-playground.md';
|
||||
|
||||
@Component({
|
||||
selector: 'app-markdown-playground',
|
||||
standalone: true,
|
||||
imports: [CommonModule, FormsModule, HttpClientModule],
|
||||
template: `
|
||||
<div class="h-full flex flex-col bg-gray-50 dark:bg-gray-900">
|
||||
<!-- Header -->
|
||||
<header class="bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 px-6 py-4">
|
||||
<h1 class="text-2xl font-semibold text-gray-900 dark:text-gray-100">Markdown Playground</h1>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400 mt-1">
|
||||
Page de test interne pour valider tous les formatages Markdown supportés par ObsiViewer.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="flex-1 flex gap-4 p-4 overflow-hidden">
|
||||
<!-- Editor Panel -->
|
||||
<div class="flex-1 flex flex-col bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden">
|
||||
<div class="px-4 py-2 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-750">
|
||||
<h2 class="text-sm font-semibold text-gray-700 dark:text-gray-300">Markdown Source</h2>
|
||||
</div>
|
||||
<textarea
|
||||
[(ngModel)]="sample"
|
||||
class="flex-1 p-4 font-mono text-sm bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 resize-none focus:outline-none"
|
||||
placeholder="Entrez votre Markdown ici..."
|
||||
spellcheck="false"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Preview Panel -->
|
||||
<div class="flex-1 flex flex-col bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden">
|
||||
<div class="px-4 py-2 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-750 flex items-center justify-between">
|
||||
<h2 class="text-sm font-semibold text-gray-700 dark:text-gray-300">Preview</h2>
|
||||
<button
|
||||
(click)="resetToDefault()"
|
||||
class="text-xs px-3 py-1 rounded bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 text-gray-700 dark:text-gray-300"
|
||||
>
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex-1 overflow-auto p-4">
|
||||
<div
|
||||
class="prose prose-slate dark:prose-invert max-w-none"
|
||||
[innerHTML]="renderedHtml()"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
styles: [`
|
||||
:host {
|
||||
display: block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
textarea {
|
||||
tab-size: 2;
|
||||
}
|
||||
|
||||
textarea::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
textarea::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
textarea::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
textarea::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.dark textarea::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.dark textarea::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
`]
|
||||
})
|
||||
export class MarkdownPlaygroundComponent {
|
||||
private markdownService = inject(MarkdownService);
|
||||
private http = inject(HttpClient);
|
||||
|
||||
sample = signal<string>('');
|
||||
|
||||
renderedHtml = computed(() => {
|
||||
const markdown = this.sample();
|
||||
try {
|
||||
return this.markdownService.render(markdown, [], undefined);
|
||||
} catch (error) {
|
||||
console.error('Markdown render error:', error);
|
||||
return `<div class="text-red-500">Erreur de rendu: ${error}</div>`;
|
||||
}
|
||||
});
|
||||
|
||||
constructor() {
|
||||
this.loadDefaultSample();
|
||||
}
|
||||
|
||||
private loadDefaultSample(): void {
|
||||
this.http.get(DEFAULT_MD_PATH, { responseType: 'text' }).subscribe({
|
||||
next: (text) => this.sample.set(text ?? ''),
|
||||
error: (err) => {
|
||||
console.error('Failed to load default markdown:', err);
|
||||
this.sample.set('');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
resetToDefault(): void {
|
||||
this.loadDefaultSample();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Routes } from '@angular/router';
|
||||
import { MarkdownPlaygroundComponent } from './markdown-playground/markdown-playground.component';
|
||||
|
||||
export const TESTS_ROUTES: Routes = [
|
||||
{
|
||||
path: 'markdown',
|
||||
component: MarkdownPlaygroundComponent
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
pathMatch: 'full',
|
||||
redirectTo: 'markdown'
|
||||
}
|
||||
];
|
||||
@@ -15,11 +15,12 @@ import { NotesListComponent } from '../../features/list/notes-list.component';
|
||||
import { NimbusSidebarComponent } from '../../features/sidebar/nimbus-sidebar.component';
|
||||
import { QuickLinksComponent } from '../../features/quick-links/quick-links.component';
|
||||
import { ScrollableOverlayDirective } from '../../shared/overlay-scrollbar/scrollable-overlay.directive';
|
||||
import { MarkdownPlaygroundComponent } from '../../features/tests/markdown-playground/markdown-playground.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-shell-nimbus-layout',
|
||||
standalone: true,
|
||||
imports: [CommonModule, FileExplorerComponent, NoteViewerComponent, AppBottomNavigationComponent, AppSidebarDrawerComponent, AppTocOverlayComponent, SwipeNavDirective, NotesListComponent, NimbusSidebarComponent, QuickLinksComponent, ScrollableOverlayDirective],
|
||||
imports: [CommonModule, FileExplorerComponent, NoteViewerComponent, AppBottomNavigationComponent, AppSidebarDrawerComponent, AppTocOverlayComponent, SwipeNavDirective, NotesListComponent, NimbusSidebarComponent, QuickLinksComponent, ScrollableOverlayDirective, MarkdownPlaygroundComponent],
|
||||
template: `
|
||||
<div class="h-screen flex flex-col bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
|
||||
<!-- Header (desktop/tablet), compact on mobile) -->
|
||||
@@ -57,6 +58,7 @@ import { ScrollableOverlayDirective } from '../../shared/overlay-scrollbar/scrol
|
||||
(fileSelected)="noteSelected.emit($event)"
|
||||
(tagSelected)="onTagSelected($event)"
|
||||
(quickLinkSelected)="onQuickLink($event)"
|
||||
(markdownPlaygroundSelected)="onMarkdownPlaygroundSelected()"
|
||||
/>
|
||||
</aside>
|
||||
</ng-container>
|
||||
@@ -117,7 +119,8 @@ import { ScrollableOverlayDirective } from '../../shared/overlay-scrollbar/scrol
|
||||
<!-- Note View + ToC -->
|
||||
<section class="flex-1 relative min-w-0 flex">
|
||||
<div class="note-content-area flex-1 overflow-y-auto px-4 py-4 lg:px-8" appScrollableOverlay>
|
||||
<app-note-viewer
|
||||
<app-markdown-playground *ngIf="activeView === 'markdown-playground'"></app-markdown-playground>
|
||||
<app-note-viewer *ngIf="activeView !== 'markdown-playground'"
|
||||
[note]="selectedNote || null"
|
||||
[noteHtmlContent]="renderedNoteContent"
|
||||
[allNotes]="vault.allNotes()"
|
||||
@@ -201,6 +204,7 @@ export class AppShellNimbusLayoutComponent {
|
||||
@Input() searchTerm = '';
|
||||
@Input() centerPanelWidth = 384;
|
||||
@Input() tags: TagInfo[] = [];
|
||||
@Input() activeView: string = 'files';
|
||||
|
||||
@Output() noteSelected = new EventEmitter<string>();
|
||||
@Output() tagClicked = new EventEmitter<string>();
|
||||
@@ -213,6 +217,7 @@ export class AppShellNimbusLayoutComponent {
|
||||
@Output() navigateHeading = new EventEmitter<string>();
|
||||
@Output() searchTermChange = new EventEmitter<string>();
|
||||
@Output() searchOptionsChange = new EventEmitter<any>();
|
||||
@Output() markdownPlaygroundSelected = new EventEmitter<void>();
|
||||
|
||||
folderFilter: string | null = null;
|
||||
listQuery: string = '';
|
||||
@@ -303,4 +308,8 @@ export class AppShellNimbusLayoutComponent {
|
||||
this.flyoutCloseTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
onMarkdownPlaygroundSelected(): void {
|
||||
this.markdownPlaygroundSelected.emit();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user