init
This commit is contained in:
commit
a153bf1bb4
9 changed files with 1808 additions and 0 deletions
103
site/index.html
Normal file
103
site/index.html
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Searchcraft UI</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body class="bg-gray-900 text-white min-h-screen flex items-center justify-center px-4">
|
||||
<div class="w-full max-w-2xl text-center">
|
||||
<h1 class="text-3xl font-bold mb-4">🔍 Searchcraft</h1>
|
||||
|
||||
<div class="mb-4 flex flex-col md:flex-row gap-2 items-center justify-center">
|
||||
<label for="index-select" class="text-gray-300 mr-2">Index:</label>
|
||||
<select id="index-select" class="bg-gray-800 border border-gray-700 text-white p-2 rounded-md">
|
||||
<option value="thoughts-links">thoughts-links</option>
|
||||
<option value="waylonwalker.com">blog-posts</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<input
|
||||
id="search-query"
|
||||
type="text"
|
||||
placeholder="Start typing to search..."
|
||||
class="w-full p-4 text-lg rounded-md bg-gray-800 border border-gray-700 focus:outline-none focus:ring-2 focus:ring-cyan-500"
|
||||
oninput="debouncedSearch()"
|
||||
/>
|
||||
<div id="results" class="mt-8 space-y-4 text-left"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const BASE_URL = "http://localhost:8081";
|
||||
let debounceTimer = null;
|
||||
|
||||
function getSelectedIndex() {
|
||||
return document.getElementById("index-select").value;
|
||||
}
|
||||
|
||||
function debouncedSearch() {
|
||||
clearTimeout(debounceTimer);
|
||||
debounceTimer = setTimeout(search, 300);
|
||||
}
|
||||
|
||||
async function search() {
|
||||
const query = document.getElementById("search-query").value;
|
||||
const resBox = document.getElementById("results");
|
||||
const index = getSelectedIndex();
|
||||
resBox.innerHTML = '';
|
||||
|
||||
if (!query) return;
|
||||
|
||||
const response = await fetch(`${BASE_URL}/index/${index}/search`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
limit: 10,
|
||||
offset: 0,
|
||||
query: { fuzzy: { ctx: query } }
|
||||
}),
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
const hits = result?.data?.hits || [];
|
||||
|
||||
for (const hit of hits) {
|
||||
const { title, description, body, url, image } = hit.doc;
|
||||
const preview = (description || body || "").slice(0, 1000) + ((description || body).length > 1000 ? "..." : "");
|
||||
const link = url || "#";
|
||||
|
||||
const card = document.createElement("a");
|
||||
card.href = link;
|
||||
card.target = "_blank";
|
||||
card.rel = "noopener noreferrer";
|
||||
card.className = "flex gap-4 bg-gray-800 border border-gray-700 rounded-lg overflow-hidden hover:border-cyan-500 transition";
|
||||
|
||||
if (image) {
|
||||
const img = document.createElement("img");
|
||||
img.src = image;
|
||||
img.alt = title || "preview";
|
||||
img.className = "w-32 h-32 object-cover flex-shrink-0";
|
||||
card.appendChild(img);
|
||||
}
|
||||
|
||||
const content = document.createElement("div");
|
||||
content.className = "p-4 flex flex-col justify-center";
|
||||
|
||||
const titleEl = document.createElement("h3");
|
||||
titleEl.className = "text-lg font-semibold text-cyan-400 hover:underline";
|
||||
titleEl.textContent = title || "Untitled";
|
||||
|
||||
const descEl = document.createElement("p");
|
||||
descEl.className = "text-gray-300 text-sm mt-1";
|
||||
descEl.textContent = preview || "(no description)";
|
||||
|
||||
content.appendChild(titleEl);
|
||||
content.appendChild(descEl);
|
||||
card.appendChild(content);
|
||||
resBox.appendChild(card);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
145
site/v1/index.html
Normal file
145
site/v1/index.html
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Searchcraft UI</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
background: #1e1e1e;
|
||||
color: #eee;
|
||||
padding: 2rem;
|
||||
}
|
||||
input, textarea, button {
|
||||
margin: 0.5rem 0;
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
textarea { height: 100px; }
|
||||
.section {
|
||||
margin-bottom: 2rem;
|
||||
border-bottom: 1px solid #444;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.results {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
}
|
||||
.card {
|
||||
background: #2a2a2a;
|
||||
border: 1px solid #444;
|
||||
border-radius: 0.5rem;
|
||||
padding: 1rem;
|
||||
width: calc(50% - 1rem);
|
||||
}
|
||||
.card h3 {
|
||||
margin: 0 0 0.5rem;
|
||||
color: #00ffe0;
|
||||
}
|
||||
.card p {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>🔍 Searchcraft UI</h1>
|
||||
|
||||
<div class="section">
|
||||
<h2>📄 Upload Document</h2>
|
||||
<input id="doc-id" placeholder="Document ID (required)" />
|
||||
<input id="doc-title" placeholder="Title" />
|
||||
<textarea id="doc-body" placeholder="Body"></textarea>
|
||||
<button onclick="uploadDocument()">Upload</button>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>✅ Commit Changes</h2>
|
||||
<button onclick="commitChanges()">Commit</button>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>🔎 Search</h2>
|
||||
<input id="search-query" placeholder="Search query..." oninput="debouncedSearch()" />
|
||||
<div class="results" id="results"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const BASE_URL = "http://0.0.0.0:8000";
|
||||
const INDEX = "thoughts-links";
|
||||
let debounceTimer = null;
|
||||
|
||||
async function uploadDocument() {
|
||||
const id = document.getElementById("doc-id").value;
|
||||
const title = document.getElementById("doc-title").value;
|
||||
const body = document.getElementById("doc-body").value;
|
||||
|
||||
if (!id) {
|
||||
alert("Document ID is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetch(`${BASE_URL}/index/${INDEX}/documents`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify([{ id, title, body }]),
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
alert("Upload: " + JSON.stringify(result));
|
||||
}
|
||||
|
||||
async function commitChanges() {
|
||||
const response = await fetch(`${BASE_URL}/index/${INDEX}/commit`, { method: "POST" });
|
||||
const result = await response.json();
|
||||
alert("Commit: " + JSON.stringify(result));
|
||||
}
|
||||
|
||||
function debouncedSearch() {
|
||||
clearTimeout(debounceTimer);
|
||||
debounceTimer = setTimeout(search, 300); // 300ms debounce
|
||||
}
|
||||
|
||||
async function search() {
|
||||
const query = document.getElementById("search-query").value;
|
||||
const resBox = document.getElementById("results");
|
||||
resBox.innerHTML = '';
|
||||
|
||||
if (!query) return;
|
||||
|
||||
const response = await fetch(`${BASE_URL}/index/${INDEX}/search`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
limit: 10,
|
||||
offset: 0,
|
||||
query: { fuzzy: { ctx: query } }
|
||||
}),
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
const hits = result?.data?.hits || [];
|
||||
|
||||
for (const hit of hits) {
|
||||
const { title, body } = hit.doc;
|
||||
|
||||
const card = document.createElement("div");
|
||||
card.className = "card";
|
||||
|
||||
const titleEl = document.createElement("h3");
|
||||
titleEl.textContent = title || "Untitled";
|
||||
|
||||
const bodyEl = document.createElement("p");
|
||||
bodyEl.textContent = body || "(no body)";
|
||||
|
||||
card.appendChild(titleEl);
|
||||
card.appendChild(bodyEl);
|
||||
resBox.appendChild(card);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
77
site/v2/index.html
Normal file
77
site/v2/index.html
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Searchcraft UI</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body class="bg-gray-900 text-white min-h-screen flex items-center justify-center px-4">
|
||||
<div class="w-full max-w-2xl text-center">
|
||||
<h1 class="text-3xl font-bold mb-6">🔍 Searchcraft</h1>
|
||||
<input
|
||||
id="search-query"
|
||||
type="text"
|
||||
placeholder="Start typing to search..."
|
||||
class="w-full p-4 text-lg rounded-md bg-gray-800 border border-gray-700 focus:outline-none focus:ring-2 focus:ring-cyan-500"
|
||||
oninput="debouncedSearch()"
|
||||
/>
|
||||
<div id="results" class="mt-8 space-y-4 text-left"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const BASE_URL = "http://0.0.0.0:8000";
|
||||
const INDEX = "thoughts-links";
|
||||
let debounceTimer = null;
|
||||
|
||||
function debouncedSearch() {
|
||||
clearTimeout(debounceTimer);
|
||||
debounceTimer = setTimeout(search, 300);
|
||||
}
|
||||
|
||||
async function search() {
|
||||
const query = document.getElementById("search-query").value;
|
||||
const resBox = document.getElementById("results");
|
||||
resBox.innerHTML = '';
|
||||
|
||||
if (!query) return;
|
||||
|
||||
const response = await fetch(`${BASE_URL}/index/${INDEX}/search`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
limit: 10,
|
||||
offset: 0,
|
||||
query: { fuzzy: { ctx: query } }
|
||||
}),
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
const hits = result?.data?.hits || [];
|
||||
|
||||
for (const hit of hits) {
|
||||
const { title, body, url } = hit.doc;
|
||||
const preview = (body || "(no body)").slice(0, 1000) + ((body && body.length > 1000) ? "..." : "");
|
||||
const link = url || "#";
|
||||
|
||||
const card = document.createElement("a");
|
||||
card.href = link;
|
||||
card.target = "_blank";
|
||||
card.rel = "noopener noreferrer";
|
||||
card.className = "block p-4 bg-gray-800 border border-gray-700 rounded-md hover:border-cyan-500 transition";
|
||||
|
||||
const titleEl = document.createElement("h3");
|
||||
titleEl.className = "text-xl font-semibold text-cyan-400 mb-2";
|
||||
titleEl.textContent = title || "Untitled";
|
||||
|
||||
const bodyEl = document.createElement("p");
|
||||
bodyEl.className = "text-gray-300";
|
||||
bodyEl.textContent = preview;
|
||||
|
||||
card.appendChild(titleEl);
|
||||
card.appendChild(bodyEl);
|
||||
resBox.appendChild(card);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue