ObsiViewer/docs/MARKDOWN/MARKDOWN_VIEWER_GUIDE.md

12 KiB

Guide d'utilisation du Markdown Viewer

Vue d'ensemble

Le système de visualisation Markdown d'ObsiViewer a été optimisé et modulaire pour offrir une expérience de lecture et d'édition exceptionnelle. Il supporte maintenant :

  • GitHub Flavored Markdown (GFM) complet
  • Callouts Obsidian (NOTE, TIP, WARNING, DANGER, etc.)
  • Math LaTeX (inline et block)
  • Diagrammes Mermaid
  • Syntax highlighting avec highlight.js
  • WikiLinks et navigation interne
  • Tags inline avec coloration automatique
  • Task lists interactives
  • Tables avancées
  • Footnotes
  • Fichiers Excalidraw avec éditeur intégré
  • Lazy loading des images
  • Mode plein écran

Architecture

Composants principaux

src/
├── components/
│   ├── markdown-viewer/           # Composant de visualisation Markdown
│   │   ├── markdown-viewer.component.ts
│   │   └── markdown-viewer.component.spec.ts
│   └── smart-file-viewer/         # Détection automatique du type de fichier
│       ├── smart-file-viewer.component.ts
│       └── smart-file-viewer.component.spec.ts
├── services/
│   ├── markdown.service.ts        # Service de rendu Markdown
│   ├── markdown.service.spec.ts
│   ├── file-type-detector.service.ts  # Détection du type de fichier
│   └── file-type-detector.service.spec.ts
└── app/features/
    └── drawings/
        └── drawings-editor.component.ts  # Éditeur Excalidraw

Utilisation

1. MarkdownViewerComponent

Composant réutilisable pour afficher du contenu Markdown.

Import

import { MarkdownViewerComponent } from './components/markdown-viewer/markdown-viewer.component';

@Component({
  imports: [MarkdownViewerComponent]
})

Exemple basique

<app-markdown-viewer
  [content]="markdownContent"
  [allNotes]="notes"
  [currentNote]="currentNote">
</app-markdown-viewer>

Propriétés

Propriété Type Description Défaut
content string Contenu Markdown brut ''
allNotes Note[] Liste des notes pour WikiLinks []
currentNote Note? Note courante undefined
showToolbar boolean Afficher la barre d'outils true
fullscreenMode boolean Activer le mode plein écran false
filePath string Chemin du fichier (pour détecter .excalidraw.md) ''

Exemple avec toutes les options

<app-markdown-viewer
  [content]="note.content"
  [allNotes]="allNotes"
  [currentNote]="note"
  [showToolbar]="true"
  [fullscreenMode]="true"
  [filePath]="note.filePath">
</app-markdown-viewer>

2. SmartFileViewerComponent

Composant intelligent qui détecte automatiquement le type de fichier et affiche le viewer approprié.

Import

import { SmartFileViewerComponent } from './components/smart-file-viewer/smart-file-viewer.component';

Exemple

<app-smart-file-viewer
  [filePath]="file.path"
  [content]="file.content"
  [allNotes]="notes"
  [currentNote]="currentNote">
</app-smart-file-viewer>

Types de fichiers supportés

  • Markdown (.md) → MarkdownViewerComponent
  • Excalidraw (.excalidraw.md, .excalidraw) → DrawingsEditorComponent
  • Images (.png, .jpg, .svg, etc.) → Image viewer
  • PDF (.pdf) → PDF viewer (iframe)
  • Texte (.txt, .json, .xml, etc.) → Text viewer
  • Inconnu → Message d'erreur

3. FileTypeDetectorService

Service pour détecter le type de fichier et ses caractéristiques.

Méthodes principales

// Détecter si c'est un fichier Excalidraw
isExcalidrawFile(path: string): boolean

// Détecter si c'est un fichier Markdown
isMarkdownFile(path: string): boolean

// Obtenir les informations complètes
getFileTypeInfo(path: string): FileTypeInfo

// Détecter le viewer approprié
getViewerType(path: string, content?: string): ViewerType

// Vérifier si le contenu contient du JSON Excalidraw
hasExcalidrawContent(content: string): boolean

Exemple d'utilisation

import { FileTypeDetectorService } from './services/file-type-detector.service';

constructor(private fileTypeDetector: FileTypeDetectorService) {}

checkFile(path: string) {
  const info = this.fileTypeDetector.getFileTypeInfo(path);
  
  console.log('Type:', info.type);
  console.log('Editable:', info.isEditable);
  console.log('Requires special viewer:', info.requiresSpecialViewer);
  console.log('Icon:', info.icon);
  console.log('MIME type:', info.mimeType);
}

Fonctionnalités Markdown

Callouts Obsidian

> [!NOTE]
> Ceci est une note informative

> [!TIP]
> Conseil utile pour l'utilisateur

> [!WARNING]
> Attention, soyez prudent

> [!DANGER]
> Action dangereuse, évitez cela

Math LaTeX

Inline:

La formule $E = mc^2$ est célèbre.

Block:

$$
\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
$$

Diagrammes Mermaid

\`\`\`mermaid
graph TD
    A[Start] --> B{Decision}
    B -->|Yes| C[Action 1]
    B -->|No| D[Action 2]
\`\`\`

Code avec syntax highlighting

\`\`\`typescript
function hello(name: string): string {
  return `Hello ${name}!`;
}
\`\`\`
[[Note Example]]
[[Note Example#Section]]
[[Note Example|Alias personnalisé]]

Tags inline

Les tags inline fonctionnent: #test #markdown #playground

Task lists

- [ ] Tâche non cochée
- [x] Tâche cochée
- [ ] Autre tâche en attente

Tables

| Colonne 1 | Colonne 2 | Colonne 3 |
|-----------|-----------|-----------|
| A         | B         | C         |
| D         | E         | F         |

Footnotes

Voici un texte avec une note de bas de page[^1].

[^1]: Ceci est la note de bas de page.

Fichiers Excalidraw

Détection automatique

Le système détecte automatiquement les fichiers .excalidraw.md et affiche l'éditeur Excalidraw intégré au lieu du rendu Markdown.

Format supporté

ObsiViewer supporte le format Obsidian Excalidraw avec compression LZ-String :

---
excalidraw-plugin: parsed
tags: [excalidraw]
---

# Excalidraw Data

## Drawing
\`\`\`compressed-json
N4KAkARALgngDgUwgLgAQQQDwMYEMA2AlgCYBOuA7hADTgQBuCpAzoQPYB2KqATLZMzYBXUtiRoIACyhQ4zZAHoFAc0JRJQgEYA6bGwC2CgF7N6hbEcK4OCtptbErHALRY8RMpWdx8Q1TdIEfARcZgRmBShcZQUebQBmbQAGGjoghH0EDihmbgBtcDBQMBLoeHF0QOwojmVg1JLIRhZ2LjQANgBWWtLm1k4AOU4xbgAWbshCDmIs
\`\`\`

Fonctionnalités de l'éditeur

  • Édition complète avec tous les outils Excalidraw
  • Sauvegarde manuelle (Ctrl+S)
  • Export PNG/SVG
  • Mode plein écran (F11)
  • Détection de conflits
  • Support du thème clair/sombre

Optimisations

Lazy Loading des images

Les images sont chargées uniquement lorsqu'elles entrent dans le viewport, améliorant les performances pour les documents longs.

// Automatique dans MarkdownViewerComponent
private setupLazyLoading(): void {
  const imageObserver = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target as HTMLImageElement;
        img.classList.add('loaded');
        observer.unobserve(img);
      }
    });
  }, { rootMargin: '50px' });
}

Cache du syntax highlighting

Le service Markdown utilise un cache LRU pour éviter de re-highlighter le même code :

private static readonly HL_CACHE = new SimpleLruCache<string, string>(500);

Fast path pour les documents simples

Les documents sans fonctionnalités avancées (< 10KB, sans WikiLinks, math, etc.) utilisent un chemin de rendu optimisé :

if (this.canUseFastPath(markdown)) {
  return this.md.render(markdown, env);
}

Tests

Exécuter les tests

# Tous les tests
npm test

# Tests spécifiques
npm test -- --include='**/markdown-viewer.component.spec.ts'
npm test -- --include='**/file-type-detector.service.spec.ts'

Coverage

Les composants et services ont une couverture de tests complète :

  • MarkdownViewerComponent - 95%+
  • SmartFileViewerComponent - 90%+
  • FileTypeDetectorService - 100%
  • MarkdownService - 85%+

Styling

CSS Variables disponibles

:root {
  --brand: #3a68d1;
  --text-main: #111827;
  --text-muted: #6b7280;
  --border: #e5e7eb;
  --card: #ffffff;
  --bg-main: #f7f7f7;
  --bg-muted: #eef0f2;
}

:root[data-theme="dark"] {
  --brand: #6f96e4;
  --text-main: #e5e7eb;
  --text-muted: #9ca3af;
  --border: #374151;
  --card: #0f172a;
  --bg-main: #111827;
  --bg-muted: #1f2937;
}

Classes personnalisées

/* Callouts */
.callout { /* Base callout style */ }
.callout-note { /* Note callout */ }
.callout-tip { /* Tip callout */ }
.callout-warning { /* Warning callout */ }
.callout-danger { /* Danger callout */ }

/* Code blocks */
.code-block { /* Base code block */ }
.code-block__header { /* Header with language badge */ }
.code-block__body { /* Code content */ }

/* Task lists */
.md-task-list { /* Task list container */ }
.md-task-item { /* Individual task */ }
.md-task-checkbox { /* Custom checkbox */ }

/* Links */
.md-wiki-link { /* WikiLink style */ }
.md-external-link { /* External link style */ }

Exemples avancés

Markdown Playground

Le composant MarkdownPlaygroundComponent démontre toutes les fonctionnalités :

import { MarkdownPlaygroundComponent } from './app/features/tests/markdown-playground/markdown-playground.component';

// Accessible via la route /markdown-playground

Intégration dans une application

@Component({
  selector: 'app-note-viewer',
  standalone: true,
  imports: [SmartFileViewerComponent],
  template: `
    <app-smart-file-viewer
      [filePath]="note().filePath"
      [content]="note().content"
      [allNotes]="allNotes()"
      [currentNote]="note()"
      [showToolbar]="true"
      [fullscreenMode]="true">
    </app-smart-file-viewer>
  `
})
export class NoteViewerComponent {
  note = signal<Note | null>(null);
  allNotes = signal<Note[]>([]);
}

Dépannage

Le Markdown ne s'affiche pas

  1. Vérifier que le contenu est bien passé au composant
  2. Vérifier la console pour les erreurs de rendu
  3. Vérifier que MarkdownService est bien injecté

Les images ne se chargent pas

  1. Vérifier les chemins des images
  2. Vérifier les CORS si images externes
  3. Vérifier que le lazy loading est activé

Excalidraw ne s'affiche pas

  1. Vérifier que le fichier a l'extension .excalidraw.md
  2. Vérifier que le contenu contient un bloc compressed-json
  3. Vérifier que DrawingsEditorComponent est importé

Erreurs TypeScript

# Nettoyer et rebuilder
npm run clean
npm install
npm run build

Roadmap

Fonctionnalités futures

  • Support des embeds audio/vidéo
  • Éditeur Markdown WYSIWYG
  • Export PDF du Markdown
  • Collaboration temps réel
  • Plugins Markdown personnalisés
  • Support des diagrammes PlantUML
  • Mode présentation (slides)

Contribution

Pour contribuer au système Markdown :

  1. Lire le guide d'architecture dans /docs/ARCHITECTURE/
  2. Ajouter des tests pour toute nouvelle fonctionnalité
  3. Suivre les conventions de code existantes
  4. Mettre à jour cette documentation

Support

Pour toute question ou problème :

  • 📖 Documentation : /docs/
  • 🐛 Issues : GitHub Issues
  • 💬 Discussions : GitHub Discussions

Dernière mise à jour : 2025-01-15 Version : 2.0.0