refactor(create): DRY rule export media + TextBlock row view

This commit is contained in:
adilallo
2026-05-08 21:40:43 -06:00
parent 89fd5f3ade
commit 4595e2648a
4 changed files with 112 additions and 58 deletions
@@ -3,6 +3,8 @@
import { memo } from "react";
import type { TextBlockProps } from "./TextBlock.types";
type TextRow = NonNullable<TextBlockProps["rows"]>[number];
/**
* Figma: Utility / **Community Rule / Text Block** (22001:29793).
* Title + body paragraphs and/or labeled rows (12px between stacks, 8px label→body).
@@ -38,6 +40,45 @@ function ParagraphGroup({ text }: { text: string }) {
);
}
function LabeledRowView({ row }: { row: TextRow }) {
const imageSrc = row.imageUrl?.trim();
const fileHref = row.fileUrl?.trim();
const caption = row.body.trim();
const hasCaption = caption.length > 0;
const alt = hasCaption ? caption : row.label;
const linkText = hasCaption ? caption : fileHref;
return (
<div className="flex min-w-0 flex-col gap-2">
<p className={ROW_LABEL_CLASS}>{row.label}</p>
{imageSrc ? (
<>
{/* eslint-disable-next-line @next/next/no-img-element -- same-origin or absolute upload URL */}
<img
src={imageSrc}
alt={alt}
className="max-h-[240px] max-w-full rounded-[var(--measures-radius-200,8px)] object-contain"
/>
{hasCaption ? <ParagraphGroup text={row.body} /> : null}
</>
) : fileHref ? (
<p className={`${PARAGRAPH_CLASS} whitespace-pre-wrap`}>
<a
href={fileHref}
className="underline"
target="_blank"
rel="noopener noreferrer"
>
{linkText}
</a>
</p>
) : (
<ParagraphGroup text={row.body} />
)}
</div>
);
}
function TextBlockView({
title,
body = "",
@@ -54,42 +95,7 @@ function TextBlockView({
<p className={`${ENTRY_TITLE_CLASS} w-full min-w-0`}>{title}</p>
<div className="flex min-w-0 flex-col gap-3">
{hasRows
? rows!.map((row, i) => {
const imageSrc = row.imageUrl?.trim();
const fileHref = row.fileUrl?.trim();
const caption = row.body.trim();
return (
<div key={i} className="flex min-w-0 flex-col gap-2">
<p className={ROW_LABEL_CLASS}>{row.label}</p>
{imageSrc ? (
<>
{/* eslint-disable-next-line @next/next/no-img-element -- same-origin or absolute upload URL */}
<img
src={imageSrc}
alt={caption.length > 0 ? caption : row.label}
className="max-h-[240px] max-w-full rounded-[var(--measures-radius-200,8px)] object-contain"
/>
{caption.length > 0 ? (
<ParagraphGroup text={row.body} />
) : null}
</>
) : fileHref ? (
<p className={`${PARAGRAPH_CLASS} whitespace-pre-wrap`}>
<a
href={fileHref}
className="underline"
target="_blank"
rel="noopener noreferrer"
>
{caption.length > 0 ? caption : fileHref}
</a>
</p>
) : (
<ParagraphGroup text={row.body} />
)}
</div>
);
})
? rows!.map((row, i) => <LabeledRowView key={i} row={row} />)
: body.trim().length > 0 && <ParagraphGroup text={body} />}
</div>
</div>