diff --git a/frontend/src/i18n/fr.ts b/frontend/src/i18n/fr.ts index c254e78..b699ed6 100644 --- a/frontend/src/i18n/fr.ts +++ b/frontend/src/i18n/fr.ts @@ -98,6 +98,8 @@ const fr = { 'synthesis.deleteError': 'Erreur lors de la suppression.', 'synthesis.backToHome': 'Retour a l\'accueil', 'synthesis.noSections': 'Aucune section trouvee dans cette synthese.', + 'synthesis.displayCompact': 'Compact', + 'synthesis.displayFull': 'Complet', // Synthesis - Email 'synthesis.email.title': 'Envoyer par email', diff --git a/frontend/src/pages/SynthesisDetail.tsx b/frontend/src/pages/SynthesisDetail.tsx index 357b16b..184262a 100644 --- a/frontend/src/pages/SynthesisDetail.tsx +++ b/frontend/src/pages/SynthesisDetail.tsx @@ -17,8 +17,23 @@ import type { Synthesis, NewsItem as NewsItemType, ArticleHistoryEntry } from '~ import { extractWeekNumber, formatDateLong } from '~/utils/dates'; import LoadingSpinner from '~/components/ui/LoadingSpinner'; +/** Truncate text to approximately N lines (assuming ~80 chars per line). */ +function truncateSummary(text: string, level: number): string { + if (level >= 4 || !text) return text; + if (level === 1) return ''; + if (level === 2) { + // ~2 lines ≈ 160 chars + if (text.length <= 160) return text; + return text.slice(0, 157) + '...'; + } + // level 3: half + const half = Math.ceil(text.length / 2); + if (text.length <= half + 3) return text; + return text.slice(0, half) + '...'; +} + /** Renders a single news article with its title (linked) and summary. */ -const NewsItemCard: Component<{ item: NewsItemType }> = (props) => { +const NewsItemCard: Component<{ item: NewsItemType; displayLevel: number }> = (props) => { return (

@@ -35,24 +50,26 @@ const NewsItemCard: Component<{ item: NewsItemType }> = (props) => {

{props.item.date}

-

- {props.item.summary} -

+ 1 && props.item.summary}> +

+ {truncateSummary(props.item.summary, props.displayLevel)} +

+

); }; /** Renders a titled category section containing a list of {@link NewsItemCard}s. */ -const Section: Component<{ title: string; items: NewsItemType[] }> = (props) => { +const Section: Component<{ title: string; items: NewsItemType[]; displayLevel: number }> = (props) => { return ( 0}>

{props.title}

-
+
- {(item) => } + {(item) => }
@@ -94,6 +111,9 @@ const SynthesisDetail: Component = () => { if (t) clearTimeout(t); }); + // Display level for article cards (1=title only, 2=+2 lines, 3=+half, 4=full) + const [displayLevel, setDisplayLevel] = createSignal(4); + // Export state const [exportingMarkdown, setExportingMarkdown] = createSignal(false); const [exportingPdf, setExportingPdf] = createSignal(false); @@ -402,6 +422,21 @@ const SynthesisDetail: Component = () => {
{/* Sections */} + {/* Display level slider */} +
+ {t('synthesis.displayCompact')} + setDisplayLevel(parseInt(e.currentTarget.value) || 4)} + /> + {t('synthesis.displayFull')} +
+
0} @@ -412,7 +447,7 @@ const SynthesisDetail: Component = () => { } > - {(section) =>
} + {(section) =>
}