feat: add per-article expand/collapse button when display is compact

When the slider is not at full (level < 4), each truncated article
shows a "Lire la suite" button to expand its summary inline.
A "Reduire" button collapses it back. Expansion is per-card and
independent of the global slider.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
master
oabrivard 3 months ago
parent 2650356c01
commit 44606ca3eb

@ -34,6 +34,17 @@ function truncateSummary(text: string, level: number): string {
/** Renders a single news article with its title (linked) and summary. */ /** Renders a single news article with its title (linked) and summary. */
const NewsItemCard: Component<{ item: NewsItemType; displayLevel: number }> = (props) => { const NewsItemCard: Component<{ item: NewsItemType; displayLevel: number }> = (props) => {
const [expanded, setExpanded] = createSignal(false);
const effectiveLevel = () => expanded() ? 4 : props.displayLevel;
const isTruncated = () => {
if (!props.item.summary || effectiveLevel() >= 4) return false;
if (effectiveLevel() === 1) return !!props.item.summary;
if (effectiveLevel() === 2) return props.item.summary.length > 160;
// level 3
return true;
};
return ( return (
<div class="bg-white rounded-lg shadow-sm border border-gray-100 p-6 hover:shadow-md transition-shadow"> <div class="bg-white rounded-lg shadow-sm border border-gray-100 p-6 hover:shadow-md transition-shadow">
<h3 class="text-lg font-semibold text-indigo-700 mb-2"> <h3 class="text-lg font-semibold text-indigo-700 mb-2">
@ -50,11 +61,27 @@ const NewsItemCard: Component<{ item: NewsItemType; displayLevel: number }> = (p
<Show when={props.item.date}> <Show when={props.item.date}>
<p class="text-xs text-gray-400 mb-1">{props.item.date}</p> <p class="text-xs text-gray-400 mb-1">{props.item.date}</p>
</Show> </Show>
<Show when={props.displayLevel > 1 && props.item.summary}> <Show when={effectiveLevel() > 1 && props.item.summary}>
<p class={`text-gray-700 leading-relaxed text-sm ${props.displayLevel < 4 ? 'text-gray-500' : ''}`}> <p class="text-gray-700 leading-relaxed text-sm">
{truncateSummary(props.item.summary, props.displayLevel)} {truncateSummary(props.item.summary, effectiveLevel())}
</p> </p>
</Show> </Show>
<Show when={props.displayLevel < 4 && !expanded() && isTruncated()}>
<button
onClick={() => setExpanded(true)}
class="mt-2 text-xs text-indigo-600 hover:text-indigo-800 font-medium"
>
Lire la suite &darr;
</button>
</Show>
<Show when={expanded() && props.displayLevel < 4}>
<button
onClick={() => setExpanded(false)}
class="mt-2 text-xs text-indigo-600 hover:text-indigo-800 font-medium"
>
Reduire &uarr;
</button>
</Show>
</div> </div>
); );
}; };

Loading…
Cancel
Save