(() => { "use strict"; const categories = window.AKASHI_WIKI_CATEGORIES || []; const docs = window.AKASHI_WIKI_DOCS || []; if (!categories.length || !docs.length) { throw new Error("Akashi wiki data is not loaded. Check docs-data.js script order."); } const els = { body: document.body, sidebar: document.getElementById("sidebar"), menuButton: document.getElementById("menuButton"), searchInput: document.getElementById("searchInput"), categoryNav: document.getElementById("categoryNav"), tagFilter: document.getElementById("tagFilter"), docList: document.getElementById("docList"), resultCount: document.getElementById("resultCount"), activeFilter: document.getElementById("activeFilter"), articleView: document.getElementById("articleView"), currentPath: document.getElementById("currentPath"), clearButton: document.getElementById("clearButton"), copyLinkButton: document.getElementById("copyLinkButton"), toast: document.getElementById("toast") }; const state = { query: "", category: "all", tag: null, activeDocId: getDocIdFromHash() || "home" }; const categoryLabel = (id) => categories.find((category) => category.id === id)?.label || id; const normalize = (value) => value.toLocaleLowerCase("ko-KR").trim(); const uniqueTags = [...new Set(docs.flatMap((doc) => doc.tags))].sort((a, b) => a.localeCompare(b)); function getDocIdFromHash() { const match = decodeURIComponent(window.location.hash).match(/^#\/doc\/([a-z0-9-]+)$/i); return match ? match[1] : null; } function escapeHtml(value) { return String(value) .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'"); } function docSearchText(doc) { const blockText = doc.blocks.map((block) => { if (block.body) return block.body.join(" "); if (block.items) return block.items.map((item) => typeof item === "string" ? item : Object.values(item).join(" ")).join(" "); if (block.rows) return block.rows.flat().join(" "); if (block.text) return block.text; return ""; }).join(" "); return normalize([doc.title, doc.summary, doc.category, doc.owner, doc.status, doc.tags.join(" "), blockText].join(" ")); } function filteredDocs() { const query = normalize(state.query); return docs.filter((doc) => { const categoryMatch = state.category === "all" || doc.category === state.category; const tagMatch = !state.tag || doc.tags.includes(state.tag); const queryMatch = !query || docSearchText(doc).includes(query); return categoryMatch && tagMatch && queryMatch; }); } function renderCategories() { els.categoryNav.innerHTML = categories.map((category) => { const count = category.id === "all" ? docs.length : docs.filter((doc) => doc.category === category.id).length; return ` `; }).join(""); } function renderTags() { els.tagFilter.innerHTML = uniqueTags.map((tag) => ` `).join(""); } function renderDocList() { const list = filteredDocs(); if (!list.some((doc) => doc.id === state.activeDocId)) { state.activeDocId = list[0]?.id || docs[0].id; } els.resultCount.textContent = `${list.length} docs`; els.activeFilter.textContent = [categoryLabel(state.category), state.tag ? `#${state.tag}` : null].filter(Boolean).join(" · "); if (!list.length) { els.docList.innerHTML = `
검색 결과가 없습니다.
`; return; } els.docList.innerHTML = list.map((doc) => ` `).join(""); } function renderArticle() { const doc = docs.find((item) => item.id === state.activeDocId) || docs[0]; const tags = doc.tags.map((tag) => `#${escapeHtml(tag)}`).join(""); els.currentPath.textContent = `${categoryLabel(doc.category)} / ${doc.title}`; document.title = `${doc.title} | 아카시 LLM 위키`; els.articleView.innerHTML = `
${escapeHtml(categoryLabel(doc.category))}

${escapeHtml(doc.title)}

${escapeHtml(doc.summary)}

Owner ${escapeHtml(doc.owner)} ${escapeHtml(doc.status)} ${escapeHtml(doc.updated)}
${doc.blocks.map(renderBlock).join("")} `; } function renderBlock(block) { if (block.type === "section") { const body = block.body.map((paragraph) => `

${escapeHtml(paragraph)}

`).join(""); return `

${escapeHtml(block.title)}

${body}
`; } if (block.type === "callout") { return `
${escapeHtml(block.title)}${escapeHtml(block.text)}
`; } if (block.type === "code") { return `
${escapeHtml(block.text)}
`; } if (block.type === "checklist") { return `
${block.items.map((item) => `
${escapeHtml(item)}
`).join("")}
`; } if (block.type === "metrics") { return `
${block.items.map((item) => `
${escapeHtml(item.label)}${escapeHtml(item.value)}

${escapeHtml(item.text)}

`).join("")}
`; } if (block.type === "flow") { return `
${block.items.map((item) => `
${escapeHtml(item.label)}${escapeHtml(item.title)}${escapeHtml(item.text)}
`).join("")}
`; } if (block.type === "matrix") { return `
${block.rows.map((row) => `
${escapeHtml(row[0])}${escapeHtml(row[1])}${escapeHtml(row[2])}
`).join("")}
`; } return ""; } function renderAll() { renderCategories(); renderTags(); renderDocList(); renderArticle(); } function setActiveDoc(id, updateHash = true) { if (!docs.some((doc) => doc.id === id)) return; state.activeDocId = id; if (updateHash) history.replaceState(null, "", `#/doc/${id}`); renderDocList(); renderArticle(); els.articleView.focus({ preventScroll: true }); els.body.classList.remove("nav-open"); } function showToast(message) { els.toast.textContent = message; els.toast.classList.add("is-visible"); window.clearTimeout(showToast.timer); showToast.timer = window.setTimeout(() => els.toast.classList.remove("is-visible"), 1800); } els.categoryNav.addEventListener("click", (event) => { const button = event.target.closest("[data-category]"); if (!button) return; state.category = button.dataset.category; renderAll(); }); els.tagFilter.addEventListener("click", (event) => { const button = event.target.closest("[data-tag]"); if (!button) return; state.tag = state.tag === button.dataset.tag ? null : button.dataset.tag; renderAll(); }); els.docList.addEventListener("click", (event) => { const button = event.target.closest("[data-doc-id]"); if (button) setActiveDoc(button.dataset.docId); }); els.searchInput.addEventListener("input", (event) => { state.query = event.target.value; renderAll(); }); els.clearButton.addEventListener("click", () => { state.query = ""; state.category = "all"; state.tag = null; els.searchInput.value = ""; renderAll(); showToast("필터를 초기화했습니다."); }); els.copyLinkButton.addEventListener("click", async () => { const url = `${location.origin}${location.pathname}#/doc/${state.activeDocId}`; try { await navigator.clipboard.writeText(url); showToast("문서 링크를 복사했습니다."); } catch (error) { showToast("현재 브라우저에서 복사를 지원하지 않습니다."); } }); els.menuButton.addEventListener("click", () => { els.body.classList.toggle("nav-open"); }); document.addEventListener("keydown", (event) => { if (event.key === "Escape") els.body.classList.remove("nav-open"); if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "k") { event.preventDefault(); els.searchInput.focus(); els.body.classList.add("nav-open"); } }); window.addEventListener("hashchange", () => { const id = getDocIdFromHash(); if (id) setActiveDoc(id, false); }); if (!getDocIdFromHash()) history.replaceState(null, "", "#/doc/home"); renderAll(); })();