diff options
| author | soryu <soryu@soryu.co> | 2025-12-23 14:43:23 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2025-12-23 14:47:18 +0000 |
| commit | 555061b179b8ec034cb70f9a2dd6c823ced0f637 (patch) | |
| tree | 0545b4395dab6d957884d8d36bf15b8da529dc1f /makima/frontend/src/components/files/BodyRenderer.tsx | |
| parent | a32dc56d2e5447ef8988cb98b8686476cc94e70c (diff) | |
| download | soryu-555061b179b8ec034cb70f9a2dd6c823ced0f637.tar.gz soryu-555061b179b8ec034cb70f9a2dd6c823ced0f637.zip | |
Add file body and initial tool call system
Diffstat (limited to 'makima/frontend/src/components/files/BodyRenderer.tsx')
| -rw-r--r-- | makima/frontend/src/components/files/BodyRenderer.tsx | 125 |
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> + ); +} |
