[dyad] Improved schema display - wrote 2 file(s)

This commit is contained in:
[dyad]
2026-01-20 14:50:38 +01:00
parent be6a3a24ec
commit f901165a29
2 changed files with 183 additions and 20 deletions

View File

@@ -0,0 +1,146 @@
"use client";
import React from "react";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
Link as LinkIcon,
Type,
Image as ImageIcon,
User,
Building,
Calendar,
HelpCircle,
Hash,
Text,
} from "lucide-react";
const keyMappings: { [key: string]: string } = {
"@type": "Type",
"@context": "Context",
"@id": "ID",
name: "Name",
headline: "Headline",
description: "Description",
author: "Author",
publisher: "Publisher",
mainEntityOfPage: "Main Page",
image: "Image",
datePublished: "Date Published",
dateModified: "Date Modified",
acceptedAnswer: "Answer",
mainEntity: "Main Content",
url: "URL",
text: "Text",
question: "Question",
answer: "Answer",
logo: "Logo",
telephone: "Telephone",
email: "Email",
};
const keyIcons: { [key: string]: React.ElementType } = {
"@type": Type,
"@id": Hash,
url: LinkIcon,
image: ImageIcon,
logo: ImageIcon,
author: User,
publisher: Building,
datePublished: Calendar,
dateModified: Calendar,
question: HelpCircle,
text: Text,
};
const renderValue = (value: any): React.ReactNode => {
if (typeof value === "string") {
if (value.startsWith("http://") || value.startsWith("https://")) {
try {
const url = new URL(value);
return (
<a
href={value}
target="_blank"
rel="noopener noreferrer"
className="text-blue-500 hover:underline break-all inline-flex items-center gap-1.5"
>
<LinkIcon className="h-3 w-3 flex-shrink-0" />
<span>
{url.hostname}
{url.pathname.length > 1 ? "/..." : ""}
</span>
</a>
);
} catch (e) {
return <span className="break-all">{value}</span>;
}
}
return <span className="break-words">{value}</span>;
}
if (typeof value === "object" && value !== null) {
if (Array.isArray(value)) {
return (
<div className="flex flex-col gap-2 pl-4 border-l ml-2 mt-2">
{value.map((item, index) => (
<div key={index}>{renderValue(item)}</div>
))}
</div>
);
}
return <SchemaObjectRenderer data={value} isNested={true} />;
}
return <span>{String(value)}</span>;
};
const SchemaObjectRenderer = ({
data,
isNested = false,
}: {
data: any;
isNested?: boolean;
}) => {
const content = (
<div className="space-y-3">
{Object.entries(data).map(([key, value]) => {
if (key === "@context") return null;
const label =
keyMappings[key] || key.charAt(0).toUpperCase() + key.slice(1);
const Icon = keyIcons[key];
return (
<div
key={key}
className="flex flex-col sm:flex-row sm:items-start gap-1 sm:gap-2"
>
<div className="flex items-center gap-2 font-semibold text-sm text-muted-foreground w-full sm:w-40 flex-shrink-0">
{Icon && <Icon className="h-4 w-4" />}
<span>{label}:</span>
</div>
<div className="flex-grow text-sm text-foreground pl-6 sm:pl-0">
{key === "@type" ? (
<Badge variant="outline">{value as string}</Badge>
) : (
renderValue(value)
)}
</div>
</div>
);
})}
</div>
);
if (isNested) {
return (
<div className="p-3 border rounded-md bg-background/50">{content}</div>
);
}
return content;
};
export function PrettySchemaDisplay({ schema }: { schema: any }) {
return <SchemaObjectRenderer data={schema} />;
}