1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// This tool uses the DBpedia Lookup API and SPARQL endpoint to find entities and their details, including images.
// It provides a web interface and a JSON API endpoint for entity search, including hero images.
// Helper function to strip HTML tags and decode HTML entities
function sanitizeHtml(html: string): string {
const decoded = html.replace(/"/g, '"')
.replace(/&/g, "&")
.replace(/&lt;/g, "<")
.replace(/&gt;/g, ">")
.replace(/&#39;/g, "'");
return decoded.replace(/<[^>]*>/g, '');
}
import React, { useEffect, useState } from "https://esm.sh/react@18.2.0";
import { createRoot } from "https://esm.sh/react-dom@18.2.0/client";
function App() {
const [query, setQuery] = useState("");
const [results, setResults] = useState([]);
useEffect(() => {
const urlParams = new URLSearchParams(window.location.search);
const urlQuery = urlParams.get("query");
if (urlQuery) {
setQuery(urlQuery);
fetchResults(urlQuery);
}
}, []);
const fetchResults = async (searchQuery) => {
const response = await fetch(`/api/search?query=${encodeURIComponent(searchQuery)}`);
const data = await response.json();
setResults(data);
};
const handleSubmit = (e) => {
e.preventDefault();
if (query) {
window.history.pushState({}, "", `?query=${encodeURIComponent(query)}`);
fetchResults(query);
}
};
return React.createElement(
"div",
{ className: "container mx-auto px-4 py-8" },
React.createElement("h1", { className: "text-3xl font-bold text-center mb-8" }, "DBpedia Entity Search"),
React.createElement(
"form",
{ onSubmit: handleSubmit, className: "flex mb-8" },
React.createElement("input", {
type: "text",
value: query,
onChange: (e) => setQuery(e.target.value),
placeholder: "Enter your search query",
className: "flex-grow p-2 border border-gray-300 rounded-l-md focus:outline-none focus:ring-2 focus:ring-blue-500"
}),
React.createElement(
"button",
{ type: "submit", className: "bg-blue-500 text-white px-4 py-2 rounded-r-md hover:bg-blue-600 transition duration-300" },
"Search"
)
),
results.length > 0 && React.createElement(
"div",
{ className: "bg-white shadow-md rounded-md p-6" },
React.createElement("h2", { className: "text-2xl font-semibold mb-4" }, "Results:"),
React.createElement(
"div",
{ className: "grid gap-6" },
results.map((result, index) =>
React.createElement(
"div",
{ key: index, className: "border-b border-gray-200 pb-4 last:border-b-0 flex" },
result.image && React.createElement(
"div",
{ className: "mr-4 flex-shrink-0" },
React.createElement("img", {
src: result.image,
alt: result.label,
className: "w-32 h-32 object-cover rounded"
})
),
React.createElement(
"div",
{ className: "flex-grow" },
React.createElement(
"a",
{ href: result.uri, target: "_blank", rel: "noopener noreferrer", className: "text-xl font-medium text-blue-600 hover:underline" },
result.label
),
React.createElement("p", { className: "mt-2 text-gray-600" }, result.description),
React.createElement("pre", { className: "mt-2 bg-gray-100 p-2 rounded text-sm overflow-x-auto" }, JSON.stringify(result, null, 2))
)
)
)
)
),
React.createElement(
"footer",