feat(storefront): render product description as markdown
Some checks failed
Deploy — Staging / Detect changed apps (push) Successful in 16s
Deploy — Staging / Lint, Typecheck & Test (push) Successful in 1m29s
Deploy — Staging / Build & push — ${{ matrix.app }} (push) Failing after 49s
Deploy — Staging / Deploy to staging VPS (push) Has been skipped

- Add react-markdown dependency to storefront
- Use ReactMarkdown in ProductDetailDescriptionSection for formatted descriptions

Made-with: Cursor
This commit is contained in:
2026-03-08 16:27:48 +03:00
parent 0bd0d90f45
commit f6156c78d1
3 changed files with 1167 additions and 14 deletions

View File

@@ -19,6 +19,7 @@
"@stripe/react-stripe-js": "^5.6.0",
"@stripe/stripe-js": "^8.8.0",
"framer-motion": "^11.0.0",
"lucide-react": "^0.400.0"
"lucide-react": "^0.400.0",
"react-markdown": "^10.1.0"
}
}

View File

@@ -1,11 +1,16 @@
import ReactMarkdown from "react-markdown";
type ProductDetailDescriptionSectionProps = {
/** Product description (HTML or plain text); server-rendered in initial HTML per SEO. */
/** Product description (Markdown); server-rendered in initial HTML per SEO. */
description?: string | null;
};
const descriptionClasses =
"max-w-3xl text-sm leading-relaxed text-[var(--foreground)]/80 [&_ol]:mb-3 [&_ol]:list-inside [&_ol]:list-decimal [&_p:last-child]:mb-0 [&_p]:mb-3 [&_ul]:mb-3 [&_ul]:list-inside [&_ul]:list-disc";
/**
* Description content for the PDP tabs section.
* Renders inside a parent <section> provided by ProductDetailTabsSection.
* Renders Markdown as HTML inside a parent <section> provided by ProductDetailTabsSection.
* If empty, shows a short fallback message.
*/
export function ProductDetailDescriptionSection({
@@ -15,10 +20,9 @@ export function ProductDetailDescriptionSection({
typeof description === "string" && description.trim().length > 0;
return hasContent ? (
<div
className="max-w-3xl text-sm leading-relaxed text-[var(--foreground)]/80 [&_ol]:mb-3 [&_ol]:list-inside [&_ol]:list-decimal [&_p:last-child]:mb-0 [&_p]:mb-3 [&_ul]:mb-3 [&_ul]:list-inside [&_ul]:list-disc"
dangerouslySetInnerHTML={{ __html: description!.trim() }}
/>
<div className={descriptionClasses}>
<ReactMarkdown>{description!.trim()}</ReactMarkdown>
</div>
) : (
<p className="text-sm text-[var(--muted)]">No description available.</p>
);

1162
package-lock.json generated

File diff suppressed because it is too large Load Diff