mirror of
https://github.com/patarapolw/cjdic2.git
synced 2026-11-09 17:39:35 +00:00
component renderer
This commit is contained in:
1 parent
098ee45b81
commit
d96346bfea
2 files changed
+155
-5
No files matched your search
@@ -0,0 +1,130 @@
|
||||
import { createElement as h } from "react";
|
||||
|
||||
export default function Glossary({
|
||||
glossary,
|
||||
onTermClicked,
|
||||
}: {
|
||||
glossary: any;
|
||||
onTermClicked: (t: string) => void;
|
||||
}) {
|
||||
// Plain string
|
||||
if (typeof glossary === "string") {
|
||||
return glossary;
|
||||
}
|
||||
|
||||
// GlossaryText
|
||||
if ("type" in glossary && glossary.type === "text") {
|
||||
return glossary.text;
|
||||
}
|
||||
|
||||
// GlossaryImage
|
||||
if ("type" in glossary && glossary.type === "image") {
|
||||
return <GlossaryImage {...glossary} />;
|
||||
}
|
||||
|
||||
// GlossaryStructuredContent
|
||||
if ("type" in glossary && glossary.type === "structured-content") {
|
||||
const sc = glossary;
|
||||
return (
|
||||
<StructuredContent node={sc.content} onTermClicked={onTermClicked} />
|
||||
);
|
||||
}
|
||||
|
||||
// GlossaryDeinflection
|
||||
if (Array.isArray(glossary) && glossary.length === 2) {
|
||||
const [term, rules] = glossary;
|
||||
return <small>{`${term} (${rules.join(", ")})`}</small>;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function GlossaryImage(img: any) {
|
||||
return (
|
||||
<img
|
||||
src={img.path}
|
||||
width={img.width}
|
||||
height={img.height}
|
||||
title={img.title}
|
||||
alt={img.alt}
|
||||
style={{
|
||||
imageRendering: img.imageRendering || "auto",
|
||||
width: `${img.width}em`,
|
||||
height: `${img.height}em`,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function StructuredContent({
|
||||
node,
|
||||
onTermClicked,
|
||||
}: {
|
||||
node: any;
|
||||
onTermClicked: (t: string) => void;
|
||||
}): any {
|
||||
if (typeof node === "string") {
|
||||
return node;
|
||||
}
|
||||
|
||||
if (Array.isArray(node)) {
|
||||
return (
|
||||
<>
|
||||
{...node.map((n) => (
|
||||
<StructuredContent node={n} onTermClicked={onTermClicked} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// Line break
|
||||
if ("tag" in node && node.tag === "br") {
|
||||
return <br />;
|
||||
}
|
||||
|
||||
// Image
|
||||
if ("tag" in node && node.tag === "img") {
|
||||
return <GlossaryImage {...node} />;
|
||||
}
|
||||
|
||||
// Link
|
||||
if ("tag" in node && node.tag === "a") {
|
||||
const link = node as any;
|
||||
const { href, content } = link;
|
||||
|
||||
const isWebLink = /^https?:\/\//.test(href);
|
||||
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
target={isWebLink ? "_blank" : ""}
|
||||
onClick={(ev) => {
|
||||
if (isWebLink) return true;
|
||||
ev.preventDefault();
|
||||
const querySearch = "?query=";
|
||||
if (href.startsWith(querySearch)) {
|
||||
onTermClicked(href.substring(querySearch.length));
|
||||
}
|
||||
return false;
|
||||
}}
|
||||
>
|
||||
{content ? (
|
||||
<StructuredContent node={content} onTermClicked={onTermClicked} />
|
||||
) : null}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
// Block/container elements (span, div, ol, ul, li, ruby, table, etc.)
|
||||
if ("tag" in node) {
|
||||
const block = node as any;
|
||||
|
||||
return h(
|
||||
block.tag,
|
||||
{ style: block.style, title: block.title, open: block.open },
|
||||
StructuredContent({ node: block.content, onTermClicked }),
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in new issue
Block a user