summaryrefslogtreecommitdiff
path: root/makima/frontend/src/components/files/BodyRenderer.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'makima/frontend/src/components/files/BodyRenderer.tsx')
-rw-r--r--makima/frontend/src/components/files/BodyRenderer.tsx125
1 files changed, 125 insertions, 0 deletions
diff --git a/makima/frontend/src/components/files/BodyRenderer.tsx b/makima/frontend/src/components/files/BodyRenderer.tsx
new file mode 100644
index 0000000..9d008e2
--- /dev/null
+++ b/makima/frontend/src/components/files/BodyRenderer.tsx
@@ -0,0 +1,125 @@
+import type { BodyElement } from "../../lib/api";
+import { ChartRenderer } from "../charts/ChartRenderer";
+
+interface BodyRendererProps {
+ elements: BodyElement[];
+}
+
+export function BodyRenderer({ elements }: BodyRendererProps) {
+ if (elements.length === 0) {
+ return (
+ <div className="text-[#555] font-mono text-sm italic">
+ No content yet. Use the CLI below to add content.
+ </div>
+ );
+ }
+
+ return (
+ <div className="space-y-4">
+ {elements.map((element, index) => (
+ <BodyElementRenderer key={index} element={element} />
+ ))}
+ </div>
+ );
+}
+
+function BodyElementRenderer({ element }: { element: BodyElement }) {
+ switch (element.type) {
+ case "heading":
+ return <HeadingElement level={element.level} text={element.text} />;
+ case "paragraph":
+ return <ParagraphElement text={element.text} />;
+ case "chart":
+ return (
+ <ChartElement
+ chartType={element.chartType}
+ data={element.data}
+ title={element.title}
+ config={element.config}
+ />
+ );
+ case "image":
+ return (
+ <ImageElement
+ src={element.src}
+ alt={element.alt}
+ caption={element.caption}
+ />
+ );
+ default:
+ return null;
+ }
+}
+
+function HeadingElement({ level, text }: { level: number; text: string }) {
+ const className = "font-mono text-[#9bc3ff]";
+
+ switch (level) {
+ case 1:
+ return <h1 className={`${className} text-2xl font-bold`}>{text}</h1>;
+ case 2:
+ return <h2 className={`${className} text-xl font-bold`}>{text}</h2>;
+ case 3:
+ return <h3 className={`${className} text-lg font-semibold`}>{text}</h3>;
+ case 4:
+ return <h4 className={`${className} text-base font-semibold`}>{text}</h4>;
+ case 5:
+ return <h5 className={`${className} text-sm font-semibold`}>{text}</h5>;
+ case 6:
+ return <h6 className={`${className} text-xs font-semibold`}>{text}</h6>;
+ default:
+ return <h3 className={`${className} text-lg font-semibold`}>{text}</h3>;
+ }
+}
+
+function ParagraphElement({ text }: { text: string }) {
+ return <p className="font-mono text-sm text-white/80 leading-relaxed">{text}</p>;
+}
+
+function ChartElement({
+ chartType,
+ data,
+ title,
+ config,
+}: {
+ chartType: "line" | "bar" | "pie" | "area";
+ data: Record<string, unknown>[];
+ title?: string;
+ config?: Record<string, unknown>;
+}) {
+ return (
+ <div className="border border-[#333] p-4 bg-black/30">
+ <ChartRenderer
+ chartType={chartType}
+ data={data}
+ title={title}
+ config={config}
+ />
+ </div>
+ );
+}
+
+function ImageElement({
+ src,
+ alt,
+ caption,
+}: {
+ src: string;
+ alt?: string;
+ caption?: string;
+}) {
+ return (
+ <figure className="space-y-2">
+ <img
+ src={src}
+ alt={alt || ""}
+ className="max-w-full border border-[#333]"
+ />
+ {caption && (
+ <figcaption className="text-[#555] font-mono text-xs italic">
+ {caption}
+ </figcaption>
+ )}
+ </figure>
+ );
+}