website/src/pages/qa.ts
2026-03-18 17:04:48 -07:00

87 lines
3.2 KiB
TypeScript

import { getQuestions, submitQuestion } from "~/lib/api";
import { frostedBox } from "~/components/frosted-box";
function escapeHtml(str: string): string {
const div = document.createElement("div");
div.textContent = str;
return div.innerHTML;
}
export async function qaPage(outlet: HTMLElement) {
outlet.innerHTML = `
<div class="flex flex-col items-center justify-start px-4">
${frostedBox(`
<form id="qa-form">
<fieldset class="border-2 border-white px-[calc(1.5ch-0.5px)] pb-[1ch] pt-[1ch]">
<legend class="-mx-[0.5ch] px-[0.5ch] text-white">Ask a Question</legend>
<textarea id="qa-input" maxlength="200" rows="3"
class="qa-textarea"
placeholder="Type your question..."></textarea>
<div class="flex justify-between mt-[1ch]">
<span id="char-count" style="color: var(--dark-gray);">0/200</span>
<button type="submit" class="qa-button">[SUBMIT]</button>
</div>
<p id="qa-status" class="mt-[0.5ch]" aria-live="polite"></p>
</fieldset>
</form>
<div id="qa-list" class="mt-[2ch]">Loading...</div>
`)}
</div>`;
const form = document.getElementById("qa-form") as HTMLFormElement;
const input = document.getElementById("qa-input") as HTMLTextAreaElement;
const charCount = document.getElementById("char-count")!;
const status = document.getElementById("qa-status")!;
const list = document.getElementById("qa-list")!;
input.addEventListener("input", () => {
charCount.textContent = `${input.value.length}/200`;
});
form.addEventListener("submit", (e) => {
e.preventDefault();
const question = input.value.trim();
if (!question) return;
status.textContent = "Submitting...";
status.style.color = "var(--light-gray)";
submitQuestion(question)
.then(() => {
input.value = "";
charCount.textContent = "0/200";
status.textContent = "Question submitted! It will appear here once answered.";
status.style.color = "var(--light-green)";
})
.catch((err: unknown) => {
status.textContent = err instanceof Error ? err.message : "Failed to submit question.";
status.style.color = "var(--light-red)";
});
});
try {
const questions = await getQuestions();
if (questions.length === 0) {
list.textContent = "No questions answered yet.";
list.style.color = "var(--dark-gray)";
} else {
list.innerHTML = questions
.map(
(q) => `
<fieldset class="border-2 border-white px-[calc(1.5ch-0.5px)] pb-[1ch] pt-0 mb-[2ch]">
<legend class="-mx-[0.5ch] px-[0.5ch]" style="color: var(--dark-gray);">#${String(q.id)}</legend>
<p style="color: var(--light-cyan);">${escapeHtml(q.question)}</p>
<p class="mt-[1ch]" style="color: var(--light-green);">${escapeHtml(q.answer)}</p>
<p class="mt-[0.5ch]" style="color: var(--dark-gray);">
Asked ${q.created_at} · Answered ${q.answered_at}
</p>
</fieldset>`,
)
.join("");
}
} catch {
list.textContent = "Failed to load questions.";
list.style.color = "var(--light-red)";
list.style.textAlign = "center";
}
}