From 78303bc77e9ee2349639707bd211e1f23033a657 Mon Sep 17 00:00:00 2001 From: Bertrand Benjamin Date: Fri, 5 Sep 2025 11:20:00 +0200 Subject: [PATCH] feat: add preview --- index.html | 94 +++++--- script.js | 410 ++++++++++++++++++++++++++++++++- style.css | 658 ++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 1037 insertions(+), 125 deletions(-) diff --git a/index.html b/index.html index 7f585bb..ee300d2 100644 --- a/index.html +++ b/index.html @@ -7,45 +7,67 @@ -

Index of /

- - -
-

Mode Développement

-
- - +
+ + + + +
+ +
+ + + + + + + + + + + + + +
+ + + +
- - - - - - - - - - - - - - - - - - - - -
-
MinIO Explorer
- \ No newline at end of file diff --git a/script.js b/script.js index 0541e5d..e389551 100644 --- a/script.js +++ b/script.js @@ -25,6 +25,10 @@ function setupEventListeners() { // Gestion de la navigation arrière/avant du navigateur window.addEventListener('popstate', handlePopState); + + // Gestionnaires pour la prévisualisation + document.getElementById('close-preview').addEventListener('click', hidePreview); + document.getElementById('download-file').addEventListener('click', downloadCurrentFile); } function handlePopState(event) { @@ -309,6 +313,9 @@ function displayContents(contents) { // Afficher le tableau document.getElementById('files-table').style.display = 'table'; + + // Chercher et ouvrir automatiquement index.rst s'il existe + autoOpenIndexRst(contents.files); } function createParentRow(parentPath) { @@ -360,7 +367,7 @@ function createFileRow(file) { row.innerHTML = ` - ${file.name} + ${file.name} ${formatFileSize(file.size)} ${formatDate(file.modified)} @@ -369,6 +376,12 @@ function createFileRow(file) { `; + const fileLink = row.querySelector('.file-link'); + fileLink.addEventListener('click', (e) => { + e.preventDefault(); + showPreview(fileUrl, file.name); + }); + const copyBtn = row.querySelector('.copy-btn'); copyBtn.addEventListener('click', () => copyToClipboard(fileUrl)); @@ -419,4 +432,399 @@ async function copyToClipboard(text) { document.execCommand('copy'); document.body.removeChild(textArea); } +} + +// Variables globales pour la prévisualisation +let currentPreviewFile = { + url: '', + name: '' +}; + +function detectFileType(fileName) { + const extension = fileName.toLowerCase().split('.').pop(); + + const fileTypes = { + images: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp'], + text: ['txt', 'json', 'xml', 'csv', 'log'], + code: ['js', 'css', 'html', 'htm', 'py', 'java', 'cpp', 'c', 'php', 'rb', 'go', 'rs', 'ts', 'jsx', 'tsx', 'vue', 'svelte', 'tex', 'latex'], + markdown: ['md', 'markdown'], + rst: ['rst', 'rest'], + pdf: ['pdf'], + video: ['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm', 'mkv'], + audio: ['mp3', 'wav', 'ogg', 'aac', 'flac', 'm4a'], + archive: ['zip', 'rar', '7z', 'tar', 'gz', 'bz2'] + }; + + for (const [type, extensions] of Object.entries(fileTypes)) { + if (extensions.includes(extension)) { + return type; + } + } + + return 'unknown'; +} + +function showPreview(fileUrl, fileName) { + currentPreviewFile = { url: fileUrl, name: fileName }; + + const previewSection = document.getElementById('preview-section'); + const previewTitle = document.getElementById('preview-title'); + const previewContent = document.getElementById('preview-content'); + + previewTitle.textContent = `Prévisualisation: ${fileName}`; + previewContent.innerHTML = '
Chargement...
'; + + previewSection.style.display = 'flex'; + + const fileType = detectFileType(fileName); + + switch (fileType) { + case 'images': + showImagePreview(fileUrl, previewContent); + break; + case 'text': + case 'code': + showTextPreview(fileUrl, previewContent); + break; + case 'markdown': + showMarkdownPreview(fileUrl, previewContent); + break; + case 'rst': + showRstPreview(fileUrl, previewContent); + break; + case 'pdf': + showPdfPreview(fileUrl, previewContent); + break; + case 'video': + showVideoPreview(fileUrl, previewContent); + break; + case 'audio': + showAudioPreview(fileUrl, previewContent); + break; + default: + showUnsupportedPreview(fileName, previewContent); + } +} + +function showImagePreview(fileUrl, container) { + const img = document.createElement('img'); + img.src = fileUrl; + img.alt = 'Prévisualisation image'; + + img.onload = () => { + container.innerHTML = ''; + container.appendChild(img); + }; + + img.onerror = () => { + container.innerHTML = '
Erreur: Impossible de charger l\'image
'; + }; +} + +function showTextPreview(fileUrl, container) { + fetch(fileUrl) + .then(response => { + if (!response.ok) { + throw new Error(`Erreur HTTP: ${response.status}`); + } + return response.text(); + }) + .then(text => { + const pre = document.createElement('pre'); + pre.textContent = text; + container.innerHTML = ''; + container.appendChild(pre); + }) + .catch(error => { + console.error('Erreur chargement texte:', error); + container.innerHTML = '
Erreur: Impossible de charger le fichier texte
'; + }); +} + +function showPdfPreview(fileUrl, container) { + const iframe = document.createElement('iframe'); + iframe.src = fileUrl; + iframe.style.width = '100%'; + iframe.style.height = '500px'; + + container.innerHTML = ''; + container.appendChild(iframe); +} + +function showVideoPreview(fileUrl, container) { + const video = document.createElement('video'); + video.src = fileUrl; + video.controls = true; + video.style.maxWidth = '100%'; + + container.innerHTML = ''; + container.appendChild(video); +} + +function showAudioPreview(fileUrl, container) { + const audio = document.createElement('audio'); + audio.src = fileUrl; + audio.controls = true; + audio.style.width = '100%'; + + container.innerHTML = ''; + container.appendChild(audio); +} + +function showUnsupportedPreview(fileName, container) { + const extension = fileName.toLowerCase().split('.').pop(); + container.innerHTML = ` +
+

Prévisualisation non disponible pour ce type de fichier (.${extension})

+

Utilisez le bouton "Télécharger" ci-dessous pour obtenir le fichier.

+
+ `; +} + +function hidePreview() { + const previewSection = document.getElementById('preview-section'); + previewSection.style.display = 'none'; + + currentPreviewFile = { url: '', name: '' }; +} + +function downloadCurrentFile() { + if (currentPreviewFile.url) { + const link = document.createElement('a'); + link.href = currentPreviewFile.url; + link.download = currentPreviewFile.name; + link.target = '_blank'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } +} + +// Fonction pour ouvrir automatiquement index.rst s'il existe +function autoOpenIndexRst(files) { + // Chercher un fichier index.rst dans la liste + const indexRstFile = files.find(file => + file.name.toLowerCase() === 'index.rst' + ); + + if (indexRstFile) { + // Construire l'URL complète du fichier + const fileUrl = `${config.baseUrl}/${indexRstFile.fullKey}`; + + // Ouvrir automatiquement la prévisualisation + console.log('Auto-ouverture de index.rst trouvé:', indexRstFile.name); + showPreview(fileUrl, indexRstFile.name); + } else { + // Pas d'index.rst trouvé, fermer le preview s'il est ouvert + console.log('Aucun index.rst trouvé, fermeture du preview'); + hidePreview(); + } +} + +// Fonction simple de parsing Markdown vers HTML +function parseMarkdown(text) { + let html = text; + + // Headers + html = html.replace(/^### (.*$)/gim, '

$1

'); + html = html.replace(/^## (.*$)/gim, '

$1

'); + html = html.replace(/^# (.*$)/gim, '

$1

'); + + // Bold + html = html.replace(/\*\*(.*?)\*\*/g, '$1'); + html = html.replace(/__(.*?)__/g, '$1'); + + // Italic + html = html.replace(/\*(.*?)\*/g, '$1'); + html = html.replace(/_(.*?)_/g, '$1'); + + // Code inline + html = html.replace(/`(.*?)`/g, '$1'); + + // Code blocks + html = html.replace(/```([\s\S]*?)```/g, '
$1
'); + + // Links + html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); + + // Images + html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '$1'); + + // Lists + html = html.replace(/^\* (.*$)/gim, '
  • $1
  • '); + html = html.replace(/^- (.*$)/gim, '
  • $1
  • '); + html = html.replace(/^\d+\. (.*$)/gim, '
  • $1
  • '); + + // Wrap consecutive
  • items in
      + html = html.replace(/(
    • .*<\/li>)/gs, (match) => { + return '
        ' + match + '
      '; + }); + + // Line breaks + html = html.replace(/\n\n/g, '

      '); + html = '

      ' + html + '

      '; + + // Clean up empty paragraphs + html = html.replace(/

      <\/p>/g, ''); + html = html.replace(/

      ()/g, '$1'); + html = html.replace(/(<\/h[1-6]>)<\/p>/g, '$1'); + html = html.replace(/

      (

        )/g, '$1'); + html = html.replace(/(<\/ul>)<\/p>/g, '$1'); + html = html.replace(/

        (

        )/g, '$1');
        +    html = html.replace(/(<\/pre>)<\/p>/g, '$1');
        +    
        +    return html;
        +}
        +
        +// Fonction simple de parsing reStructuredText vers HTML
        +function parseRst(text) {
        +    let html = text;
        +    
        +    // Créer un système de placeholders pour éviter les liens imbriqués
        +    const linkPlaceholders = new Map();
        +    let placeholderIndex = 0;
        +    
        +    // Fonction pour créer un placeholder unique
        +    const createLinkPlaceholder = (linkText, linkUrl) => {
        +        const placeholder = `__LINK_PLACEHOLDER_${placeholderIndex++}__`;
        +        linkPlaceholders.set(placeholder, `${linkText}`);
        +        return placeholder;
        +    };
        +    
        +    // Headers (RST style with underlines) - ordre important pour éviter les conflits
        +    html = html.replace(/^(.*)\n#{3,}$/gim, '

        $1

        '); + html = html.replace(/^(.*)\n={3,}$/gim, '

        $1

        '); + html = html.replace(/^(.*)\n-{3,}$/gim, '

        $1

        '); + html = html.replace(/^(.*)\n~{3,}$/gim, '

        $1

        '); + html = html.replace(/^(.*)\n\^{3,}$/gim, '
        $1
        '); + + // Metadata fields + html = html.replace(/^:([^:]+):\s*(.*)$/gim, (match, key, value) => { + // Remplacer les liens par des placeholders dans les métadonnées + const processedValue = value.replace(/`([^<]+) <([^>]+)>`_/g, (match, text, url) => { + return createLinkPlaceholder(text, url); + }); + return ``; + }); + + // Custom directives (.. directive::) + html = html.replace(/^\.\. ([^:]+)::\s*(.*)$/gim, '
        '); + + // Directive options (:option: value) + html = html.replace(/^ :([^:]+):\s*(.*)$/gim, (match, key, value) => { + // Remplacer les liens par des placeholders dans les options + const processedValue = value.replace(/`([^<]+) <([^>]+)>`_/g, (match, text, url) => { + return createLinkPlaceholder(text, url); + }); + return `
        ${key}: ${processedValue}
        `; + }); + + // Special handling for big_button directive + html = html.replace(/
        ]*>/g, '
        '); + + // Process directive content blocks (indented text after directive) + html = html.replace(/(
        ' + processedContent + '
        '; + } + return directive + '
        '; + }); + + // Bold + html = html.replace(/\*\*(.*?)\*\*/g, '$1'); + + // Italic + html = html.replace(/\*(.*?)\*/g, '$1'); + + // Code inline + html = html.replace(/``(.*?)``/g, '$1'); + + // Code blocks (:: at end of line followed by indented block) + html = html.replace(/::\s*\n\n((?: .*\n?)+)/g, '
        $1
        '); + + // Links restants dans le texte principal + html = html.replace(/`([^<]+) <([^>]+)>`_/g, (match, text, url) => { + return createLinkPlaceholder(text, url); + }); + + // Lists + html = html.replace(/^\* (.*$)/gim, '
      • $1
      • '); + html = html.replace(/^- (.*$)/gim, '
      • $1
      • '); + html = html.replace(/^\d+\. (.*$)/gim, '
      • $1
      • '); + + // Wrap consecutive
      • items in
          + html = html.replace(/(
        • .*<\/li>)/gs, (match) => { + return '
            ' + match + '
          '; + }); + + // Line breaks + html = html.replace(/\n\n/g, '

          '); + html = '

          ' + html + '

          '; + + // Clean up empty paragraphs and fix structure + html = html.replace(/

          <\/p>/g, ''); + html = html.replace(/

          ()/g, '$1'); + html = html.replace(/(<\/h[1-6]>)<\/p>/g, '$1'); + html = html.replace(/

          (

          )<\/p>/g, '$1'); + html = html.replace(/

          (

            )/g, '$1'); + html = html.replace(/(<\/ul>)<\/p>/g, '$1'); + html = html.replace(/

            (

            )/g, '$1');
            +    html = html.replace(/(<\/pre>)<\/p>/g, '$1');
            +    
            +    // Restaurer tous les liens à partir des placeholders
            +    for (const [placeholder, linkHtml] of linkPlaceholders) {
            +        html = html.replace(new RegExp(placeholder, 'g'), linkHtml);
            +    }
            +    
            +    return html;
            +}
            +
            +function showMarkdownPreview(fileUrl, container) {
            +    fetch(fileUrl)
            +        .then(response => {
            +            if (!response.ok) {
            +                throw new Error(`Erreur HTTP: ${response.status}`);
            +            }
            +            return response.text();
            +        })
            +        .then(text => {
            +            const htmlContent = parseMarkdown(text);
            +            const div = document.createElement('div');
            +            div.className = 'markdown-content';
            +            div.innerHTML = htmlContent;
            +            container.innerHTML = '';
            +            container.appendChild(div);
            +        })
            +        .catch(error => {
            +            console.error('Erreur chargement markdown:', error);
            +            container.innerHTML = '
            Erreur: Impossible de charger le fichier Markdown
            '; + }); +} + +function showRstPreview(fileUrl, container) { + fetch(fileUrl) + .then(response => { + if (!response.ok) { + throw new Error(`Erreur HTTP: ${response.status}`); + } + return response.text(); + }) + .then(text => { + const htmlContent = parseRst(text); + const div = document.createElement('div'); + div.className = 'rst-content'; + div.innerHTML = htmlContent; + container.innerHTML = ''; + container.appendChild(div); + }) + .catch(error => { + console.error('Erreur chargement RST:', error); + container.innerHTML = '
            Erreur: Impossible de charger le fichier reStructuredText
            '; + }); } \ No newline at end of file diff --git a/style.css b/style.css index eab46e3..1935c51 100644 --- a/style.css +++ b/style.css @@ -1,188 +1,670 @@ -/* Style type "Index of" Apache classique */ +/* Reset pour layout pleine page */ +html, body { - font-family: monospace; - margin: 20px; - background-color: white; - color: black; + height: 100%; + margin: 0; + padding: 0; + overflow: auto; /* Pas de scroll global */ + font-family: monospace; + background-color: white; + color: black; +} + +* { + box-sizing: border-box; +} + +/* Container principal pleine page */ +#page-container { + height: 100vh; + display: flex; + flex-direction: column; +} + +/* Header fixe */ +#header { + flex: 0 0 auto; + padding: 15px 20px; + background-color: white; } h1 { - font-size: 18px; - font-weight: bold; - margin-bottom: 20px; + font-size: 18px; + font-weight: bold; + margin-bottom: 20px; } /* Section développement */ .dev-section { - background-color: #f0f0f0; - border: 1px solid #ccc; - padding: 15px; - margin-bottom: 20px; - border-radius: 4px; + background-color: #f0f0f0; + border: 1px solid #ccc; + padding: 15px; + margin-bottom: 20px; + border-radius: 4px; } .dev-section h2 { - font-size: 16px; - margin-top: 0; - margin-bottom: 10px; - color: #333; + font-size: 16px; + margin-top: 0; + margin-bottom: 10px; + color: #333; } .dev-section form { - margin-bottom: 10px; + margin-bottom: 10px; } .dev-section label { - display: block; - margin-bottom: 5px; - font-weight: bold; + display: block; + margin-bottom: 5px; + font-weight: bold; } .dev-section input[type="text"] { - width: 400px; - padding: 5px; - border: 1px solid #ccc; - font-family: monospace; + width: 400px; + padding: 5px; + border: 1px solid #ccc; + font-family: monospace; } .dev-section button { - padding: 5px 15px; - margin-left: 10px; - background-color: #007acc; - color: white; - border: none; - cursor: pointer; + padding: 5px 15px; + margin-left: 10px; + background-color: #007acc; + color: white; + border: none; + cursor: pointer; } .dev-section button:hover { - background-color: #005999; + background-color: #005999; } #config-info { - font-size: 12px; - color: #666; - margin-top: 10px; + font-size: 12px; + color: #666; + margin-top: 10px; } /* Messages d'erreur */ .error { - background-color: #ffe6e6; - border: 1px solid #ff9999; - padding: 10px; - margin-bottom: 20px; - color: #cc0000; - border-radius: 4px; + background-color: #ffe6e6; + border: 1px solid #ff9999; + padding: 10px; + margin-bottom: 20px; + color: #cc0000; + border-radius: 4px; } /* Loading */ #loading { - font-style: italic; - color: #666; - margin: 20px 0; + font-style: italic; + color: #666; + margin: 20px 0; } /* Tableau des fichiers */ table { - border-collapse: collapse; - width: 100%; - font-family: monospace; - font-size: 13px; + border-collapse: collapse; + width: 100%; + font-family: monospace; + font-size: 13px; } th { - background-color: #f0f0f0; - border: 1px solid #ccc; - padding: 8px; - text-align: left; - font-weight: bold; + background-color: #f0f0f0; + border: 1px solid #ccc; + padding: 8px; + text-align: left; + font-weight: bold; } td { - border: 1px solid #ccc; - padding: 8px; - vertical-align: top; + border: 1px solid #ccc; + padding: 8px; + vertical-align: top; } tr:nth-child(even) { - background-color: #f9f9f9; + background-color: #f9f9f9; } tr:hover { - background-color: #e6f3ff; + background-color: #e6f3ff; } /* Liens et dossiers */ .folder-link { - color: #0066cc; - text-decoration: none; - font-weight: bold; + color: #0066cc; + text-decoration: none; + font-weight: bold; } .folder-link:hover { - text-decoration: underline; + text-decoration: underline; } .file-link { - color: #0066cc; - text-decoration: none; + color: #0066cc; + text-decoration: none; } .file-link:hover { - text-decoration: underline; + text-decoration: underline; } .parent-dir { - font-weight: bold; + font-weight: bold; } /* Bouton copier lien */ .copy-btn { - background-color: #f0f0f0; - border: 1px solid #ccc; - padding: 2px 6px; - font-size: 11px; - cursor: pointer; - border-radius: 2px; + background-color: #f0f0f0; + border: 1px solid #ccc; + padding: 2px 6px; + font-size: 11px; + cursor: pointer; + border-radius: 2px; } .copy-btn:hover { - background-color: #e0e0e0; + background-color: #e0e0e0; } .copy-btn:active { - background-color: #d0d0d0; + background-color: #d0d0d0; } /* Tailles de fichiers */ .file-size { - text-align: right; - font-family: monospace; + text-align: right; + font-family: monospace; } .file-date { - font-family: monospace; - white-space: nowrap; + font-family: monospace; + white-space: nowrap; +} + +/* Container principal avec layout adaptatif - prend l'espace restant */ +#main-container { + flex: 1; + display: flex; + gap: 20px; + padding: 0 20px 20px 20px; + min-height: 0; +} + +#content-section { + display: flex; + flex-direction: column; + overflow: hidden; + min-height: 0; +} + +/* Section de prévisualisation */ +#preview-section { + border: 1px solid #ccc; + border-radius: 4px; + background-color: #f9f9f9; + display: flex; + flex-direction: column; +} + +/* Mode paysage (landscape) - par défaut */ +@media screen and (orientation: landscape) { + #main-container { + flex-direction: row; + } + + #content-section { + flex: 1; /* Tableau prend la moitié disponible */ + overflow-y: auto; + } + + #files-table { + width: 100%; + border-collapse: collapse; + } + + #preview-section { + flex: 1; /* Prévisualisation prend la moitié disponible */ + } + + .preview-content { + flex: 1; + overflow-y: auto; + } +} + +/* Mode portrait (vertical) */ +@media screen and (orientation: portrait) { + #main-container { + flex-direction: column; + } + + #content-section { + flex: 0 0 25%; /* Tableau prend seulement 25% de la hauteur */ + overflow-y: auto; + } + + #files-table { + width: 100%; + border-collapse: collapse; + } + + #preview-section { + flex: 1; /* Prévisualisation prend 75% restant */ + } + + .preview-content { + flex: 1; + overflow-y: auto; + } +} + +/* Styles pour écrans très petits (mobile) */ +@media screen and (max-width: 768px) { + #main-container { + flex-direction: column; + gap: 10px; + } + + #content-section { + flex: 0 0 20%; /* Encore moins d'espace pour le tableau sur mobile */ + overflow-y: auto; + } + + #files-table { + width: 100%; + border-collapse: collapse; + } + + #preview-section { + flex: 1; + } + + .preview-content { + flex: 1; + overflow-y: auto; + } +} + +.preview-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 15px; + background-color: #f0f0f0; + border-bottom: 1px solid #ccc; + border-radius: 4px 4px 0 0; + flex: none; +} + +.preview-title { + font-weight: bold; + font-size: 14px; + color: #333; +} + +#close-preview { + background: none; + border: none; + font-size: 16px; + cursor: pointer; + color: #666; + padding: 0; + width: 20px; + height: 20px; + display: flex; + align-items: center; + justify-content: center; +} + +#close-preview:hover { + color: #333; + background-color: #e0e0e0; + border-radius: 2px; +} + +.preview-content { + padding: 15px; + background-color: white; + flex: 1; + overflow-y: auto; +} + +.preview-content img { + max-width: 100%; + height: auto; + border: 1px solid #ddd; +} + +.preview-content pre { + background-color: #f8f8f8; + border: 1px solid #ddd; + padding: 10px; + overflow-x: auto; + overflow-y: auto; + font-family: monospace; + font-size: 12px; + line-height: 1.4; + margin: 0; + white-space: pre-wrap; +} + +.preview-content video, +.preview-content audio { + max-width: 100%; + height: auto; +} + +.preview-content iframe { + width: 100%; + height: 500px; + border: 1px solid #ddd; +} + +.preview-error { + color: #cc0000; + font-style: italic; + padding: 20px; + text-align: center; +} + +.preview-actions { + padding: 10px 15px; + border-top: 1px solid #ccc; + background-color: #f0f0f0; + border-radius: 0 0 4px 4px; + flex: none; +} + +#download-file { + background-color: #007acc; + color: white; + border: none; + padding: 5px 15px; + cursor: pointer; + border-radius: 2px; + font-size: 12px; +} + +#download-file:hover { + background-color: #005999; +} + +/* Styles pour le contenu Markdown et reStructuredText rendu */ +.markdown-content, +.rst-content { + line-height: 1.6; + color: #333; +} + +.markdown-content h1, +.rst-content h1 { + color: #2c3e50; + border-bottom: 2px solid #3498db; + padding-bottom: 10px; + margin-top: 25px; + margin-bottom: 15px; + font-size: 24px; +} + +.markdown-content h2, +.rst-content h2 { + color: #34495e; + border-bottom: 1px solid #bdc3c7; + padding-bottom: 5px; + margin-top: 20px; + margin-bottom: 12px; + font-size: 20px; +} + +.markdown-content h3, +.rst-content h3 { + color: #34495e; + margin-top: 18px; + margin-bottom: 10px; + font-size: 16px; +} + +.markdown-content h4, +.rst-content h4 { + color: #34495e; + margin-top: 15px; + margin-bottom: 8px; + font-size: 14px; +} + +.markdown-content p, +.rst-content p { + margin-bottom: 12px; + text-align: justify; +} + +.markdown-content ul, +.rst-content ul { + margin: 10px 0; + padding-left: 20px; +} + +.markdown-content li, +.rst-content li { + margin-bottom: 5px; +} + +.markdown-content code, +.rst-content code { + background-color: #f1f2f6; + color: #e74c3c; + padding: 2px 4px; + border-radius: 3px; + font-family: "Courier New", monospace; + font-size: 90%; +} + +.markdown-content pre, +.rst-content pre { + background-color: #f8f9fa; + border: 1px solid #e9ecef; + border-radius: 4px; + padding: 12px; + overflow-x: auto; + margin: 15px 0; + font-family: "Courier New", monospace; + font-size: 13px; + line-height: 1.4; +} + +.markdown-content pre code, +.rst-content pre code { + background: none; + color: inherit; + padding: 0; + border-radius: 0; + font-size: inherit; +} + +.markdown-content a, +.rst-content a { + color: #3498db; + text-decoration: none; + border-bottom: 1px solid transparent; +} + +.markdown-content a:hover, +.rst-content a:hover { + border-bottom-color: #3498db; +} + +.markdown-content strong, +.rst-content strong { + color: #2c3e50; + font-weight: bold; +} + +.markdown-content em, +.rst-content em { + color: #34495e; + font-style: italic; +} + +.markdown-content img, +.rst-content img { + max-width: 100%; + height: auto; + border: 1px solid #ddd; + border-radius: 4px; + padding: 4px; + margin: 10px 0; + display: block; +} + +/* Styles spécifiques pour les métadonnées et directives RST */ +.rst-metadata { + background-color: #f8f9fa; + border-left: 4px solid #17a2b8; + padding: 8px 12px; + margin: 5px 0; + font-size: 14px; + border-radius: 0 4px 4px 0; +} + +.metadata-key { + font-weight: bold; + color: #17a2b8; + text-transform: capitalize; +} + +.metadata-value { + color: #495057; + margin-left: 8px; +} + +/* Directives générales */ +.rst-directive { + background-color: #fff3cd; + border: 1px solid #ffeaa7; + border-radius: 4px; + padding: 12px; + margin: 15px 0; +} + +.directive-option { + margin: 5px 0; + padding-left: 15px; + font-size: 13px; +} + +.option-key { + font-weight: bold; + color: #6c757d; +} + +.option-value { + color: #495057; + margin-left: 5px; +} + +.directive-content { + margin-top: 8px; + padding-top: 8px; + border-top: 1px solid #e9ecef; + color: #495057; + line-height: 1.4; +} + +/* Directive big_button spécialement stylée */ +.rst-big-button { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + border-radius: 8px; + padding: 20px; + margin: 20px 0; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); + transition: transform 0.2s ease; +} + +.rst-big-button:hover { + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); +} + +.rst-big-button .option-key { + color: #e3f2fd; + font-size: 12px; + text-transform: uppercase; + letter-spacing: 1px; +} + +.rst-big-button .option-value { + color: white; + font-size: 16px; + font-weight: bold; + margin-left: 0; + display: block; + margin-top: 2px; +} + +.rst-big-button .directive-content { + border-top: 1px solid rgba(255, 255, 255, 0.2); + color: #f8f9fa; + font-size: 14px; + margin-top: 12px; + padding-top: 12px; +} + +/* Ajustement des titres RST pour la hiérarchie complète */ +.rst-content h1 { + color: #2c3e50; + border-bottom: 3px solid #3498db; + font-size: 26px; +} + +.rst-content h2 { + color: #34495e; + border-bottom: 2px solid #3498db; + font-size: 22px; +} + +.rst-content h3 { + color: #34495e; + border-bottom: 1px solid #bdc3c7; + font-size: 18px; +} + +.rst-content h4 { + color: #34495e; + border-bottom: 1px dotted #bdc3c7; + font-size: 16px; +} + +.rst-content h5 { + color: #34495e; + font-size: 14px; + font-weight: bold; } /* Footer */ address { - margin-top: 30px; - font-style: italic; - font-size: 12px; - color: #666; - border-top: 1px solid #ccc; - padding-top: 10px; + margin-top: 30px; + font-style: italic; + font-size: 12px; + color: #666; + border-top: 1px solid #ccc; + padding-top: 10px; } /* Icônes (caractères simples) */ .icon-folder::before { - content: "📁 "; + content: "📁 "; } .icon-file::before { - content: "📄 "; + content: "📄 "; } .icon-parent::before { - content: "⬆️ "; -} \ No newline at end of file + content: "⬆️ "; +}