Files
decision/frontend/app/components/common/MarkdownRenderer.vue
Yvv 21ceae4866 Français soigné, labels signalétiques, formule N1.1 visuelle, F1.2 lisible
- Accents français partout (seed + composants Vue)
- Labels discrets: Engagements, Préambule, Application, Variables
- N1.1: présentation visuelle des niveaux d'inertie avec formule
- F1.2: paramètres + lecture du curseur d'inertie
- MarkdownRenderer: espacement resserré, support code inline
- Toutes descriptions et meta en bon français

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 09:29:50 +01:00

113 lines
2.2 KiB
Vue

<script setup lang="ts">
const props = defineProps<{
content: string
}>()
/**
* Basic markdown rendering: bold, line breaks, unordered lists.
* Returns sanitized HTML string for v-html usage.
*/
const renderedHtml = computed(() => {
if (!props.content) return ''
let html = props.content
// Escape HTML entities to prevent XSS
html = html
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
// Convert **bold** to <strong>
html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
// Convert *italic* to <em>
html = html.replace(/\*(.+?)\*/g, '<em>$1</em>')
// Convert `code` to <code>
html = html.replace(/`([^`]+)`/g, '<code class="md-code">$1</code>')
// Process lines for list items
const lines = html.split('\n')
const result: string[] = []
let inList = false
for (const line of lines) {
const trimmed = line.trim()
if (trimmed.startsWith('- ')) {
if (!inList) {
result.push('<ul class="md-list">')
inList = true
}
result.push(`<li>${trimmed.slice(2)}</li>`)
} else {
if (inList) {
result.push('</ul>')
inList = false
}
if (trimmed === '') {
result.push('<br>')
} else {
result.push(`<p class="md-para">${line}</p>`)
}
}
}
if (inList) {
result.push('</ul>')
}
return result.join('\n')
})
</script>
<template>
<div
class="md-rendered"
v-html="renderedHtml"
/>
</template>
<style scoped>
.md-rendered {
color: var(--mood-text);
line-height: 1.65;
}
.md-rendered :deep(.md-list) {
list-style-type: disc;
padding-left: 1.25em;
margin: 0.25em 0;
}
.md-rendered :deep(.md-list li) {
padding: 0.05em 0;
line-height: 1.5;
}
.md-rendered :deep(.md-para) {
margin: 0.2em 0;
}
.md-rendered :deep(.md-code) {
font-family: monospace;
font-size: 0.875em;
padding: 0.1em 0.35em;
border-radius: 4px;
background: color-mix(in srgb, var(--mood-accent) 8%, var(--mood-bg));
color: var(--mood-text);
}
.md-rendered :deep(strong) {
font-weight: 700;
color: var(--mood-text);
}
.md-rendered :deep(em) {
font-style: italic;
color: var(--mood-text-muted);
font-size: 0.875em;
}
</style>