164 lines
5.6 KiB
TypeScript
164 lines
5.6 KiB
TypeScript
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';
|
|
import { MarkdownViewerComponent } from '../../../../components/markdown-viewer/markdown-viewer.component';
|
|
|
|
const DEFAULT_MD_PATH = 'assets/samples/markdown-playground.md';
|
|
const DEFAULT_MD_PATH_ABS = '/assets/samples/markdown-playground.md';
|
|
|
|
@Component({
|
|
selector: 'app-markdown-playground',
|
|
standalone: true,
|
|
imports: [CommonModule, FormsModule, HttpClientModule, MarkdownViewerComponent],
|
|
template: `
|
|
<div class="h-full flex flex-col bg-surface1 dark:bg-main">
|
|
<!-- Header -->
|
|
<header class="bg-card dark:bg-card border-b border-border dark:border-border px-6 py-4">
|
|
<h1 class="text-2xl font-semibold text-main dark:text-gray-100">Markdown Playground</h1>
|
|
<p class="text-sm text-muted dark:text-muted 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-card dark:bg-card rounded-lg border border-border dark:border-border overflow-hidden">
|
|
<div class="px-4 py-2 border-b border-border dark:border-border bg-surface1 dark:bg-gray-750">
|
|
<h2 class="text-sm font-semibold text-main dark:text-main">Markdown Source</h2>
|
|
</div>
|
|
<textarea
|
|
[ngModel]="sample()"
|
|
(ngModelChange)="sample.set($event)"
|
|
class="flex-1 p-4 font-mono text-sm bg-card dark:bg-card text-main 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-card dark:bg-card rounded-lg border border-border dark:border-border overflow-hidden">
|
|
<div class="px-4 py-2 border-b border-border dark:border-border bg-surface1 dark:bg-gray-750 flex items-center justify-between">
|
|
<h2 class="text-sm font-semibold text-main dark:text-main">Preview</h2>
|
|
<div class="flex items-center gap-2">
|
|
<button
|
|
(click)="toggleViewMode()"
|
|
class="text-xs px-3 py-1 rounded bg-surface2 dark:bg-surface2 hover:bg-muted dark:hover:bg-gray-600 text-main dark:text-main"
|
|
title="Toggle between inline and component view"
|
|
>
|
|
{{ useComponentView() ? 'Inline View' : 'Component View' }}
|
|
</button>
|
|
<button
|
|
(click)="resetToDefault()"
|
|
class="text-xs px-3 py-1 rounded bg-surface2 dark:bg-surface2 hover:bg-muted dark:hover:bg-gray-600 text-main dark:text-main"
|
|
>
|
|
Reset
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="flex-1 overflow-auto" [class.p-4]="!useComponentView()">
|
|
<!-- Component View -->
|
|
<app-markdown-viewer
|
|
*ngIf="useComponentView()"
|
|
[content]="sample()"
|
|
[allNotes]="[]"
|
|
[showToolbar]="false"
|
|
[fullscreenMode]="false">
|
|
</app-markdown-viewer>
|
|
|
|
<!-- Inline View -->
|
|
<div
|
|
*ngIf="!useComponentView()"
|
|
class="md-view"
|
|
[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>('');
|
|
useComponentView = signal<boolean>(true);
|
|
|
|
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.warn('Fallback: retry loading default markdown via absolute path', err);
|
|
this.http.get(DEFAULT_MD_PATH_ABS, { responseType: 'text' }).subscribe({
|
|
next: (text) => this.sample.set(text ?? ''),
|
|
error: (err2) => {
|
|
console.error('Failed to load default markdown (both paths):', err2);
|
|
this.sample.set('');
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
resetToDefault(): void {
|
|
this.loadDefaultSample();
|
|
}
|
|
|
|
toggleViewMode(): void {
|
|
this.useComponentView.update(v => !v);
|
|
}
|
|
}
|