MediaWiki:Common.js: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
| (5 intermediate revisions by the same user not shown) | |||
| Line 41: | Line 41: | ||
// ─── 헤더 ─── | // ─── 헤더 ─── | ||
var header = document.createElement("header"); | var header = document.createElement("header"); | ||
header.id = "erakh-header"; | |||
sp(header, "position", "fixed"); | sp(header, "position", "fixed"); | ||
sp(header, "top", "0"); | sp(header, "top", "0"); | ||
| Line 324: | Line 325: | ||
// ─── 서브바 ─── | // ─── 서브바 ─── | ||
var subbar = document.createElement("div"); | var subbar = document.createElement("div"); | ||
subbar.id = "erakh-subbar"; | |||
sp(subbar, "position", "fixed"); | sp(subbar, "position", "fixed"); | ||
sp(subbar, "top", "56px"); | sp(subbar, "top", "56px"); | ||
| Line 637: | Line 639: | ||
a.addEventListener("mouseover", function() { this.style.setProperty("color", "#2a2218", "important"); }); | a.addEventListener("mouseover", function() { this.style.setProperty("color", "#2a2218", "important"); }); | ||
a.addEventListener("mouseout", function() { this.style.setProperty("color", level === 2 ? "#6b5e4e" : "#9c8e80", "important"); }); | a.addEventListener("mouseout", function() { this.style.setProperty("color", level === 2 ? "#6b5e4e" : "#9c8e80", "important"); }); | ||
a.addEventListener("click", function(e) { | |||
e.preventDefault(); | |||
var target = document.getElementById(id); | |||
if (target) { | |||
var _h = document.getElementById("erakh-header"); | |||
var _s = document.getElementById("erakh-subbar"); | |||
var _offset = (_h ? _h.offsetHeight : 56) + (_s ? _s.offsetHeight : 44) + 8; | |||
var top = target.getBoundingClientRect().top + window.scrollY - _offset; | |||
window.scrollTo({ top: top, behavior: "smooth" }); | |||
} | |||
}); | |||
li.appendChild(a); | li.appendChild(a); | ||
| Line 650: | Line 663: | ||
if (pageName === "Erakh_Codex:Create") return; | if (pageName === "Erakh_Codex:Create") return; | ||
if (pageName === "Main_Page") return; | if (pageName === "Main_Page") return; | ||
// view 액션이 아닌 경우 (edit, delete 등) 레이아웃 빌드 스킵 | |||
if (mw.config.get("wgAction") !== "view") return; | |||
var content = document.querySelector(".mw-body") || document.getElementById("content"); | var content = document.querySelector(".mw-body") || document.getElementById("content"); | ||
| Line 681: | Line 696: | ||
var items = colLeft.querySelectorAll("li[data-id]"); | var items = colLeft.querySelectorAll("li[data-id]"); | ||
window.addEventListener("scroll", function() { | window.addEventListener("scroll", function() { | ||
var scrollY = window.scrollY + | var _h = document.getElementById("erakh-header"); | ||
var _s = document.getElementById("erakh-subbar"); | |||
var _offset = (_h ? _h.offsetHeight : 56) + (_s ? _s.offsetHeight : 44) + 8; | |||
var scrollY = window.scrollY + _offset; | |||
var current = null; | var current = null; | ||
headings.forEach(function(h) { | headings.forEach(function(h) { | ||
| Line 723: | Line 741: | ||
ph2.textContent = "최근 변경 위젯 예정"; | ph2.textContent = "최근 변경 위젯 예정"; | ||
colRight.appendChild(ph2); | colRight.appendChild(ph2); | ||
// ─── sysop 전용 [edit] · [delete] · [json] 버튼 ─── | |||
if (isSysop) { | |||
var firstHeadingEl = document.getElementById("firstHeading"); | |||
if (firstHeadingEl) { | |||
var actionWrap = document.createElement("span"); | |||
sp(actionWrap, "margin-left", "0.75rem"); | |||
sp(actionWrap, "font-size", "0.8125rem"); | |||
sp(actionWrap, "font-weight", "400"); | |||
// [edit] | |||
var editActionLink = document.createElement("a"); | |||
editActionLink.href = "/index.php?title=" + encodeURIComponent(pageName) + "&action=edit"; | |||
editActionLink.textContent = "[edit]"; | |||
sp(editActionLink, "font-family", "'Inter', sans-serif"); | |||
sp(editActionLink, "font-size", "0.8125rem"); | |||
sp(editActionLink, "color", "#9c8e80"); | |||
sp(editActionLink, "text-decoration", "none"); | |||
editActionLink.addEventListener("mouseover", function() { this.style.setProperty("color", "#c8a060", "important"); }); | |||
editActionLink.addEventListener("mouseout", function() { this.style.setProperty("color", "#9c8e80", "important"); }); | |||
// · | |||
var sep1 = document.createElement("span"); | |||
sep1.textContent = " · "; | |||
sp(sep1, "color", "#c8b99a"); | |||
sp(sep1, "font-family", "'Inter', sans-serif"); | |||
// [delete] | |||
var deleteActionLink = document.createElement("a"); | |||
deleteActionLink.href = "/index.php?title=" + encodeURIComponent(pageName) + "&action=delete"; | |||
deleteActionLink.textContent = "[delete]"; | |||
sp(deleteActionLink, "font-family", "'Inter', sans-serif"); | |||
sp(deleteActionLink, "font-size", "0.8125rem"); | |||
sp(deleteActionLink, "color", "#9c8e80"); | |||
sp(deleteActionLink, "text-decoration", "none"); | |||
deleteActionLink.addEventListener("mouseover", function() { this.style.setProperty("color", "#a04040", "important"); }); | |||
deleteActionLink.addEventListener("mouseout", function() { this.style.setProperty("color", "#9c8e80", "important"); }); | |||
// · | |||
var sep2 = document.createElement("span"); | |||
sep2.textContent = " · "; | |||
sp(sep2, "color", "#c8b99a"); | |||
sp(sep2, "font-family", "'Inter', sans-serif"); | |||
// [json] — API URL 클립보드 복사 | |||
var apiUrl = "https://codex.erakh.com/api.php?action=query&titles=" + encodeURIComponent(pageName) + "&prop=revisions&rvprop=content&format=json"; | |||
var jsonBtn = document.createElement("span"); | |||
jsonBtn.textContent = "[json]"; | |||
sp(jsonBtn, "font-family", "'Inter', sans-serif"); | |||
sp(jsonBtn, "font-size", "0.8125rem"); | |||
sp(jsonBtn, "color", "#9c8e80"); | |||
sp(jsonBtn, "cursor", "pointer"); | |||
sp(jsonBtn, "user-select", "none"); | |||
jsonBtn.addEventListener("mouseover", function() { this.style.setProperty("color", "#c8a060", "important"); }); | |||
jsonBtn.addEventListener("mouseout", function() { this.style.setProperty("color", "#9c8e80", "important"); }); | |||
jsonBtn.addEventListener("click", function() { | |||
navigator.clipboard.writeText(apiUrl).then(function() { | |||
jsonBtn.textContent = "[copied!]"; | |||
sp(jsonBtn, "color", "#c8a060"); | |||
setTimeout(function() { | |||
jsonBtn.textContent = "[json]"; | |||
sp(jsonBtn, "color", "#9c8e80"); | |||
}, 1500); | |||
}).catch(function() { | |||
// clipboard API 실패 시 fallback | |||
var ta = document.createElement("textarea"); | |||
ta.value = apiUrl; | |||
ta.style.position = "fixed"; | |||
ta.style.opacity = "0"; | |||
document.body.appendChild(ta); | |||
ta.select(); | |||
document.execCommand("copy"); | |||
document.body.removeChild(ta); | |||
jsonBtn.textContent = "[copied!]"; | |||
sp(jsonBtn, "color", "#c8a060"); | |||
setTimeout(function() { | |||
jsonBtn.textContent = "[json]"; | |||
sp(jsonBtn, "color", "#9c8e80"); | |||
}, 1500); | |||
}); | |||
}); | |||
actionWrap.appendChild(editActionLink); | |||
actionWrap.appendChild(sep1); | |||
actionWrap.appendChild(deleteActionLink); | |||
actionWrap.appendChild(sep2); | |||
actionWrap.appendChild(jsonBtn); | |||
firstHeadingEl.appendChild(actionWrap); | |||
} | |||
} | |||
content.parentNode.insertBefore(layout, content); | content.parentNode.insertBefore(layout, content); | ||
| Line 743: | Line 852: | ||
{ label: "Organizations", preload: "Template:Preload/Organization" }, | { label: "Organizations", preload: "Template:Preload/Organization" }, | ||
{ label: "Events", preload: "Template:Preload/Event" }, | { label: "Events", preload: "Template:Preload/Event" }, | ||
{ label: " | { label: "Lore", preload: "Template:Preload/Lore" }, | ||
{ label: "Artifacts", preload: "Template:Preload/Artifact" }, | { label: "Artifacts", preload: "Template:Preload/Artifact" }, | ||
{ label: "Chronicle", preload: null }, | { label: "Chronicle", preload: null }, | ||
| Line 961: | Line 1,069: | ||
if (pageName !== "Main_Page") return; | if (pageName !== "Main_Page") return; | ||
var firstHeading = document.getElementById("firstHeading"); | var firstHeading = document.getElementById("firstHeading"); | ||
if (firstHeading) sp(firstHeading, "display", "none"); | if (firstHeading) sp(firstHeading, "display", "none"); | ||
| Line 971: | Line 1,078: | ||
var CATS = [ | var CATS = [ | ||
{ label: " | { label: "Characters", icon: "ti-user", href: "/index.php?title=Category:Characters", highlight: false }, | ||
{ label: "Nations", icon: "ti-building", href: "/index.php?title=Category:Nations", highlight: false }, | |||
{ label: "Nations", icon: "ti-building", href: "/index.php?title=Category:Nations" }, | { label: "Regions", icon: "ti-map", href: "/index.php?title=Category:Regions", highlight: false }, | ||
{ label: "Regions", icon: "ti-map", href: "/index.php?title=Category:Regions" }, | { label: "Races", icon: "ti-dna", href: "/index.php?title=Category:Races", highlight: false }, | ||
{ label: " | { label: "Chronicle", icon: "ti-clock", href: "/index.php?title=Category:Chronicle", highlight: true }, | ||
{ label: " | { label: "Organizations", icon: "ti-users", href: "/index.php?title=Category:Organizations", highlight: false }, | ||
{ label: "Organizations", icon: "ti-users", href: "/index.php?title=Category:Organizations" }, | { label: "Events", icon: "ti-sword", href: "/index.php?title=Category:Events", highlight: false }, | ||
{ label: " | { label: "Lore", icon: "ti-book", href: "/index.php?title=Category:Lore", highlight: false }, | ||
{ label: " | { label: "Artifacts", icon: "ti-diamond", href: "/index.php?title=Category:Artifacts", highlight: false }, | ||
{ label: "Artifacts", icon: "ti-diamond", href: "/index.php?title=Category:Artifacts" }, | |||
]; | ]; | ||
var tablerLink = document.createElement("link"); | var tablerLink = document.createElement("link"); | ||
tablerLink.rel = "stylesheet"; | tablerLink.rel = "stylesheet"; | ||
| Line 989: | Line 1,094: | ||
document.head.appendChild(tablerLink); | document.head.appendChild(tablerLink); | ||
var wrap = document.createElement("div"); | var wrap = document.createElement("div"); | ||
sp(wrap, "max-width", "860px"); | sp(wrap, "max-width", "860px"); | ||
| Line 997: | Line 1,101: | ||
sp(wrap, "box-sizing", "border-box"); | sp(wrap, "box-sizing", "border-box"); | ||
var hero = document.createElement("div"); | var hero = document.createElement("div"); | ||
sp(hero, "background", "#f0ebe0"); | sp(hero, "background", "#f0ebe0"); | ||
| Line 1,061: | Line 1,164: | ||
wrap.appendChild(hero); | wrap.appendChild(hero); | ||
function makeSectionTitle(text) { | function makeSectionTitle(text) { | ||
var t = document.createElement("div"); | var t = document.createElement("div"); | ||
| Line 1,077: | Line 1,179: | ||
} | } | ||
wrap.appendChild(makeSectionTitle("Browse by Category")); | wrap.appendChild(makeSectionTitle("Browse by Category")); | ||
var catGrid = document.createElement("div"); | var catGrid = document.createElement("div"); | ||
sp(catGrid, "display", "grid"); | sp(catGrid, "display", "grid"); | ||
sp(catGrid, "grid-template-columns", "repeat( | sp(catGrid, "grid-template-columns", "repeat(3, 1fr)"); | ||
sp(catGrid, "gap", "8px"); | sp(catGrid, "gap", "8px"); | ||
sp(catGrid, "margin-bottom", "2.5rem"); | sp(catGrid, "margin-bottom", "2.5rem"); | ||
| Line 1,091: | Line 1,192: | ||
var card = document.createElement("a"); | var card = document.createElement("a"); | ||
card.href = cat.href; | card.href = cat.href; | ||
sp(card, "border", "1px solid #e2d9c8"); | sp(card, "border", cat.highlight ? "1.5px solid #c8a060" : "1px solid #e2d9c8"); | ||
sp(card, "border-radius", "6px"); | sp(card, "border-radius", "6px"); | ||
sp(card, "background", "#ffffff"); | sp(card, "background", cat.highlight ? "#f5ede0" : "#ffffff"); | ||
sp(card, "padding", "1rem 0.5rem"); | sp(card, "padding", "1rem 0.5rem"); | ||
sp(card, "text-align", "center"); | sp(card, "text-align", "center"); | ||
| Line 1,099: | Line 1,200: | ||
sp(card, "display", "block"); | sp(card, "display", "block"); | ||
sp(card, "box-sizing", "border-box"); | sp(card, "box-sizing", "border-box"); | ||
card.addEventListener("mouseover", function() { this.style.setProperty("background", "#f0ebe0", "important"); this.style.setProperty("border-color", "#c8b99a", "important"); }); | if (cat.highlight) { | ||
card.addEventListener("mouseover", function() { this.style.setProperty("background", "#ede0cc", "important"); this.style.setProperty("border-color", "#a07840", "important"); }); | |||
card.addEventListener("mouseout", function() { this.style.setProperty("background", "#f5ede0", "important"); this.style.setProperty("border-color", "#c8a060", "important"); }); | |||
} else { | |||
card.addEventListener("mouseover", function() { this.style.setProperty("background", "#f0ebe0", "important"); this.style.setProperty("border-color", "#c8b99a", "important"); }); | |||
card.addEventListener("mouseout", function() { this.style.setProperty("background", "#ffffff", "important"); this.style.setProperty("border-color", "#e2d9c8", "important"); }); | |||
} | |||
var icon = document.createElement("i"); | var icon = document.createElement("i"); | ||
icon.className = "ti " + cat.icon; | icon.className = "ti " + cat.icon; | ||
sp(icon, "font-size", "1.25rem"); | sp(icon, "font-size", "1.25rem"); | ||
sp(icon, "color", "#c8a060"); | sp(icon, "color", cat.highlight ? "#a07840" : "#c8a060"); | ||
sp(icon, "display", "block"); | sp(icon, "display", "block"); | ||
sp(icon, "margin-bottom", "0.4rem"); | sp(icon, "margin-bottom", "0.4rem"); | ||
| Line 1,113: | Line 1,219: | ||
sp(name, "font-size", "0.75rem"); | sp(name, "font-size", "0.75rem"); | ||
sp(name, "font-weight", "500"); | sp(name, "font-weight", "500"); | ||
sp(name, "color", "#2a2218"); | sp(name, "color", cat.highlight ? "#a07840" : "#2a2218"); | ||
sp(name, "font-family", "'Inter', sans-serif"); | sp(name, "font-family", "'Inter', sans-serif"); | ||
| Line 1,132: | Line 1,238: | ||
wrap.appendChild(catGrid); | wrap.appendChild(catGrid); | ||
var catTitles = CATS.map(function(c) { return "Category:" + c.label; }).join("|"); | var catTitles = CATS.map(function(c) { return "Category:" + c.label; }).join("|"); | ||
fetch("/api.php?action=query&prop=categoryinfo&titles=" + encodeURIComponent(catTitles) + "&format=json") | fetch("/api.php?action=query&prop=categoryinfo&titles=" + encodeURIComponent(catTitles) + "&format=json") | ||
| Line 1,152: | Line 1,257: | ||
.catch(function() {}); | .catch(function() {}); | ||
var twoCol = document.createElement("div"); | var twoCol = document.createElement("div"); | ||
sp(twoCol, "display", "grid"); | sp(twoCol, "display", "grid"); | ||
| Line 1,158: | Line 1,262: | ||
sp(twoCol, "gap", "1.5rem"); | sp(twoCol, "gap", "1.5rem"); | ||
var welcomeWrap = document.createElement("div"); | var welcomeWrap = document.createElement("div"); | ||
welcomeWrap.appendChild(makeSectionTitle("New to Erakh Codex?")); | welcomeWrap.appendChild(makeSectionTitle("New to Erakh Codex?")); | ||
| Line 1,203: | Line 1,306: | ||
twoCol.appendChild(welcomeWrap); | twoCol.appendChild(welcomeWrap); | ||
var recentWrap = document.createElement("div"); | var recentWrap = document.createElement("div"); | ||
recentWrap.appendChild(makeSectionTitle("Recent Changes")); | recentWrap.appendChild(makeSectionTitle("Recent Changes")); | ||
| Line 1,213: | Line 1,315: | ||
sp(recentBox, "overflow", "hidden"); | sp(recentBox, "overflow", "hidden"); | ||
var loadingMsg = document.createElement("div"); | var loadingMsg = document.createElement("div"); | ||
loadingMsg.textContent = "Loading..."; | loadingMsg.textContent = "Loading..."; | ||
| Line 1,222: | Line 1,323: | ||
recentBox.appendChild(loadingMsg); | recentBox.appendChild(loadingMsg); | ||
fetch("/api.php?action=query&list=recentchanges&rcnamespace=0&rclimit=10&rcprop=title|timestamp&rctype=edit|new&format=json") | fetch("/api.php?action=query&list=recentchanges&rcnamespace=0&rclimit=10&rcprop=title|timestamp&rctype=edit|new&format=json") | ||
.then(function(r) { return r.json(); }) | .then(function(r) { return r.json(); }) | ||
| Line 1,229: | Line 1,329: | ||
var changes = data.query && data.query.recentchanges ? data.query.recentchanges : []; | var changes = data.query && data.query.recentchanges ? data.query.recentchanges : []; | ||
var seen = {}; | var seen = {}; | ||
var unique = []; | var unique = []; | ||
| Line 1,312: | Line 1,411: | ||
})(); | })(); | ||
Latest revision as of 18:03, 13 June 2026
(function () {
var fontLink = document.createElement("link");
fontLink.rel = "stylesheet";
fontLink.href = "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap";
document.head.insertBefore(fontLink, document.head.firstChild);
function getCookie(name) {
var match = document.cookie.match(new RegExp("(?:^|; )" + name + "=([^;]*)"));
return match ? decodeURIComponent(match[1]) : null;
}
var user = null;
try {
var raw = getCookie("erakh_user");
if (raw) user = JSON.parse(raw);
} catch (e) {}
var pageName = mw.config.get("wgPageName");
var isSysop = (mw.config.get("wgUserGroups") || []).indexOf("sysop") !== -1;
// proactive 토큰 갱신
if (user && user.exp) {
var now = Math.floor(Date.now() / 1000);
var remaining = user.exp - now;
if (remaining < 5 * 60) {
fetch("https://erakh.com/api/auth/refresh", { method: "POST", credentials: "include" })
.catch(function() {});
} else {
var delay = (remaining - 5 * 60) * 1000;
setTimeout(function() {
fetch("https://erakh.com/api/auth/refresh", { method: "POST", credentials: "include" })
.catch(function() {});
}, delay);
}
}
function sp(el, prop, val) {
el.style.setProperty(prop, val, "important");
}
// ─── 헤더 ───
var header = document.createElement("header");
header.id = "erakh-header";
sp(header, "position", "fixed");
sp(header, "top", "0");
sp(header, "left", "0");
sp(header, "right", "0");
sp(header, "z-index", "9999");
sp(header, "width", "100%");
sp(header, "background", "#f9f6f0");
sp(header, "border-bottom", "1px solid #e2d9c8");
sp(header, "display", "flex");
sp(header, "align-items", "center");
sp(header, "justify-content", "space-between");
sp(header, "padding", "0 2rem");
sp(header, "height", "56px");
sp(header, "box-sizing", "border-box");
var left = document.createElement("div");
sp(left, "display", "flex");
sp(left, "align-items", "center");
sp(left, "gap", "1.75rem");
var logo = document.createElement("a");
logo.href = "https://erakh.com";
logo.textContent = "Erakh Archive";
sp(logo, "font-family", "'Inter', sans-serif");
sp(logo, "font-size", "1.125rem");
sp(logo, "font-weight", "500");
sp(logo, "color", "#2a2218");
sp(logo, "text-decoration", "none");
sp(logo, "letter-spacing", "-0.01em");
sp(logo, "text-transform", "none");
sp(logo, "font-variant", "normal");
sp(logo, "font-variant-caps", "normal");
sp(logo, "line-height", "1");
var nav = document.createElement("nav");
sp(nav, "display", "flex");
sp(nav, "align-items", "center");
sp(nav, "gap", "1.5rem");
var codexLink = document.createElement("a");
codexLink.href = "https://codex.erakh.com";
codexLink.textContent = "Codex";
sp(codexLink, "font-family", "'Inter', sans-serif");
sp(codexLink, "font-size", "1rem");
sp(codexLink, "color", "#6b5e4e");
sp(codexLink, "text-decoration", "none");
sp(codexLink, "text-transform", "none");
sp(codexLink, "font-variant", "normal");
sp(codexLink, "line-height", "1");
codexLink.addEventListener("mouseover", function() { this.style.setProperty("color", "#2a2218", "important"); });
codexLink.addEventListener("mouseout", function() { this.style.setProperty("color", "#6b5e4e", "important"); });
nav.appendChild(codexLink);
left.appendChild(logo);
left.appendChild(nav);
var right = document.createElement("div");
sp(right, "display", "flex");
sp(right, "align-items", "center");
if (user && user.nickname) {
var profile = document.createElement("div");
sp(profile, "position", "relative");
var avatar = document.createElement("div");
avatar.textContent = user.nickname.slice(0, 1).toUpperCase();
sp(avatar, "width", "32px");
sp(avatar, "height", "32px");
sp(avatar, "border-radius", "50%");
sp(avatar, "background", "#e2d9c8");
sp(avatar, "border", "1px solid #c8b99a");
sp(avatar, "display", "flex");
sp(avatar, "align-items", "center");
sp(avatar, "justify-content", "center");
sp(avatar, "cursor", "pointer");
sp(avatar, "font-family", "'Inter', sans-serif");
sp(avatar, "font-size", "0.75rem");
sp(avatar, "font-weight", "500");
sp(avatar, "color", "#2a2218");
sp(avatar, "box-sizing", "border-box");
var dropdown = document.createElement("div");
sp(dropdown, "display", "none");
sp(dropdown, "position", "absolute");
sp(dropdown, "top", "calc(100% + 8px)");
sp(dropdown, "right", "0");
sp(dropdown, "background", "#f9f6f0");
sp(dropdown, "border", "1px solid #e2d9c8");
sp(dropdown, "min-width", "220px");
sp(dropdown, "padding", "0");
sp(dropdown, "box-shadow", "0 4px 16px rgba(0,0,0,0.06)");
sp(dropdown, "z-index", "10000");
sp(dropdown, "box-sizing", "border-box");
var dpProfile = document.createElement("div");
sp(dpProfile, "padding", "1rem");
sp(dpProfile, "display", "flex");
sp(dpProfile, "flex-direction", "column");
sp(dpProfile, "align-items", "center");
sp(dpProfile, "gap", "0.25rem");
sp(dpProfile, "border-bottom", "1px solid #e2d9c8");
var dpAvatar = document.createElement("div");
dpAvatar.textContent = user.nickname.slice(0, 1).toUpperCase();
sp(dpAvatar, "width", "44px");
sp(dpAvatar, "height", "44px");
sp(dpAvatar, "border-radius", "50%");
sp(dpAvatar, "background", "#f0ebe0");
sp(dpAvatar, "border", "1px solid #c8b99a");
sp(dpAvatar, "display", "flex");
sp(dpAvatar, "align-items", "center");
sp(dpAvatar, "justify-content", "center");
sp(dpAvatar, "font-family", "'Inter', sans-serif");
sp(dpAvatar, "font-size", "1rem");
sp(dpAvatar, "font-weight", "500");
sp(dpAvatar, "color", "#c8a060");
sp(dpAvatar, "margin-bottom", "0.25rem");
var dpName = document.createElement("div");
dpName.textContent = user.nickname;
sp(dpName, "font-family", "'Inter', sans-serif");
sp(dpName, "font-size", "0.875rem");
sp(dpName, "font-weight", "500");
sp(dpName, "color", "#2a2218");
var dpTitle = document.createElement("div");
dpTitle.textContent = user.title || "Chronicler";
sp(dpTitle, "font-family", "'Inter', sans-serif");
sp(dpTitle, "font-size", "0.6875rem");
sp(dpTitle, "color", "#9c8e80");
sp(dpTitle, "font-style", "italic");
dpProfile.appendChild(dpAvatar);
dpProfile.appendChild(dpName);
dpProfile.appendChild(dpTitle);
var dpStats = document.createElement("div");
sp(dpStats, "display", "grid");
sp(dpStats, "grid-template-columns", "1fr 1fr");
sp(dpStats, "border-bottom", "1px solid #e2d9c8");
function makeStatCell(val, lbl, borderRight, borderBottom) {
var cell = document.createElement("div");
sp(cell, "padding", "0.5rem 0");
sp(cell, "text-align", "center");
if (borderRight) sp(cell, "border-right", "1px solid #e2d9c8");
if (borderBottom) sp(cell, "border-bottom", "1px solid #e2d9c8");
var valEl = document.createElement("div");
valEl.textContent = val;
valEl.className = "dp-stat-val";
sp(valEl, "font-family", "'Inter', sans-serif");
sp(valEl, "font-size", "0.8125rem");
sp(valEl, "font-weight", "500");
sp(valEl, "color", "#2a2218");
sp(valEl, "margin-bottom", "2px");
var lblEl = document.createElement("div");
lblEl.textContent = lbl;
sp(lblEl, "font-family", "'Inter', sans-serif");
sp(lblEl, "font-size", "0.5625rem");
sp(lblEl, "letter-spacing", "0.1em");
sp(lblEl, "color", "#9c8e80");
sp(lblEl, "text-transform", "uppercase");
cell.appendChild(valEl);
cell.appendChild(lblEl);
return cell;
}
var cellLevel = makeStatCell("—", "Level", true, true);
var cellExp = makeStatCell("—", "EXP", false, true);
var cellDays = makeStatCell("—", "Days Active", true, false);
var cellEdits = makeStatCell("—", "Edits", false, false);
dpStats.appendChild(cellLevel);
dpStats.appendChild(cellExp);
dpStats.appendChild(cellDays);
dpStats.appendChild(cellEdits);
var dpMenu = document.createElement("div");
sp(dpMenu, "padding", "0.25rem 0");
var profileLink = document.createElement("a");
profileLink.href = "https://erakh.com/profile";
profileLink.textContent = "Profile";
sp(profileLink, "display", "block");
sp(profileLink, "width", "100%");
sp(profileLink, "padding", "0.5rem 1rem");
sp(profileLink, "font-family", "'Inter', sans-serif");
sp(profileLink, "font-size", "0.8125rem");
sp(profileLink, "color", "#2a2218");
sp(profileLink, "text-decoration", "none");
sp(profileLink, "box-sizing", "border-box");
profileLink.addEventListener("mouseover", function() { this.style.setProperty("background", "#f0ebe0", "important"); });
profileLink.addEventListener("mouseout", function() { this.style.setProperty("background", "transparent", "important"); });
var signOutBtn = document.createElement("button");
signOutBtn.textContent = "Sign out";
sp(signOutBtn, "display", "block");
sp(signOutBtn, "width", "100%");
sp(signOutBtn, "padding", "0.5rem 1rem");
sp(signOutBtn, "font-family", "'Inter', sans-serif");
sp(signOutBtn, "font-size", "0.8125rem");
sp(signOutBtn, "color", "#a04040");
sp(signOutBtn, "text-align", "left");
sp(signOutBtn, "background", "transparent");
sp(signOutBtn, "border", "none");
sp(signOutBtn, "cursor", "pointer");
sp(signOutBtn, "box-sizing", "border-box");
signOutBtn.addEventListener("mouseover", function() { this.style.setProperty("background", "#f0ebe0", "important"); });
signOutBtn.addEventListener("mouseout", function() { this.style.setProperty("background", "transparent", "important"); });
signOutBtn.addEventListener("click", function () {
fetch("https://erakh.com/api/auth/logout", { method: "POST", credentials: "include" })
.then(function () { window.location.href = "https://erakh.com"; });
});
dpMenu.appendChild(profileLink);
dpMenu.appendChild(signOutBtn);
dropdown.appendChild(dpProfile);
dropdown.appendChild(dpStats);
dropdown.appendChild(dpMenu);
var profileLoaded = false;
avatar.addEventListener("click", function () {
var isHidden = dropdown.style.display === "none";
dropdown.style.display = isHidden ? "block" : "none";
if (isHidden && !profileLoaded) {
fetch("https://erakh.com/api/auth/me", { method: "GET", credentials: "include" })
.then(function(r) { return r.json(); })
.then(function(data) {
if (data.isNew) return;
profileLoaded = true;
cellLevel.querySelector(".dp-stat-val").textContent = "Lv. " + data.level;
cellExp.querySelector(".dp-stat-val").textContent = data.exp_in_level + " / " + data.exp_to_next;
cellDays.querySelector(".dp-stat-val").textContent = data.login_days;
cellEdits.querySelector(".dp-stat-val").textContent = data.edit_count;
})
.catch(function() {});
}
});
document.addEventListener("click", function (e) {
if (!profile.contains(e.target)) {
dropdown.style.display = "none";
}
});
profile.appendChild(avatar);
profile.appendChild(dropdown);
right.appendChild(profile);
} else {
var loginBtn = document.createElement("a");
loginBtn.href = "https://erakh.com/login?redirect=" + encodeURIComponent(window.location.href);
loginBtn.textContent = "Sign in";
sp(loginBtn, "font-family", "'Inter', sans-serif");
sp(loginBtn, "font-size", "0.8125rem");
sp(loginBtn, "font-weight", "500");
sp(loginBtn, "color", "#2a2218");
sp(loginBtn, "text-decoration", "none");
sp(loginBtn, "padding", "0.4rem 1rem");
sp(loginBtn, "border", "1px solid #c8b99a");
sp(loginBtn, "background", "transparent");
sp(loginBtn, "cursor", "pointer");
sp(loginBtn, "box-sizing", "border-box");
sp(loginBtn, "line-height", "1");
loginBtn.addEventListener("mouseover", function() {
this.style.setProperty("border-color", "#c8a060", "important");
this.style.setProperty("background", "#f0ebe0", "important");
});
loginBtn.addEventListener("mouseout", function() {
this.style.setProperty("border-color", "#c8b99a", "important");
this.style.setProperty("background", "transparent", "important");
});
right.appendChild(loginBtn);
}
header.appendChild(left);
header.appendChild(right);
document.body.insertBefore(header, document.body.firstChild);
// ─── 서브바 ───
var subbar = document.createElement("div");
subbar.id = "erakh-subbar";
sp(subbar, "position", "fixed");
sp(subbar, "top", "56px");
sp(subbar, "left", "0");
sp(subbar, "right", "0");
sp(subbar, "z-index", "9998");
sp(subbar, "height", "44px");
sp(subbar, "background", "#f0ebe0");
sp(subbar, "border-bottom", "1px solid #e2d9c8");
sp(subbar, "display", "flex");
sp(subbar, "align-items", "center");
sp(subbar, "gap", "1rem");
sp(subbar, "padding", "0 1.5rem");
sp(subbar, "box-sizing", "border-box");
sp(subbar, "width", "100%");
var hbBtn = document.createElement("button");
sp(hbBtn, "display", "flex");
sp(hbBtn, "flex-direction", "column");
sp(hbBtn, "justify-content", "center");
sp(hbBtn, "align-items", "center");
sp(hbBtn, "gap", "5px");
sp(hbBtn, "width", "32px");
sp(hbBtn, "height", "32px");
sp(hbBtn, "border", "none");
sp(hbBtn, "background", "transparent");
sp(hbBtn, "cursor", "pointer");
sp(hbBtn, "padding", "4px");
sp(hbBtn, "border-radius", "4px");
sp(hbBtn, "flex-shrink", "0");
sp(hbBtn, "box-sizing", "border-box");
function makeBar() {
var b = document.createElement("span");
b.style.setProperty("display", "block", "important");
b.style.setProperty("width", "18px", "important");
b.style.setProperty("height", "1.5px", "important");
b.style.setProperty("background", "#6b5e4e", "important");
b.style.setProperty("border-radius", "1px", "important");
return b;
}
hbBtn.appendChild(makeBar());
hbBtn.appendChild(makeBar());
hbBtn.appendChild(makeBar());
hbBtn.addEventListener("mouseover", function() { this.style.setProperty("background", "#e2d9c8", "important"); });
hbBtn.addEventListener("mouseout", function() { this.style.setProperty("background", "transparent", "important"); });
var searchWrap = document.createElement("div");
sp(searchWrap, "position", "relative");
sp(searchWrap, "flex", "1");
sp(searchWrap, "max-width", "520px");
var searchIconEl = document.createElement("span");
searchIconEl.innerHTML = "⚲";
sp(searchIconEl, "position", "absolute");
sp(searchIconEl, "left", "0.6rem");
sp(searchIconEl, "top", "50%");
sp(searchIconEl, "transform", "translateY(-50%)");
sp(searchIconEl, "font-size", "13px");
sp(searchIconEl, "color", "#9c8e80");
sp(searchIconEl, "pointer-events", "none");
sp(searchIconEl, "line-height", "1");
var searchInput = document.createElement("input");
searchInput.type = "text";
searchInput.placeholder = "Search Erakh Codex...";
sp(searchInput, "width", "100%");
sp(searchInput, "height", "30px");
sp(searchInput, "padding", "0 0.75rem 0 2rem");
sp(searchInput, "border", "1px solid #c8b99a");
sp(searchInput, "border-radius", "3px");
sp(searchInput, "background", "#f9f6f0");
sp(searchInput, "font-family", "'Inter', sans-serif");
sp(searchInput, "font-size", "0.8125rem");
sp(searchInput, "color", "#2a2218");
sp(searchInput, "outline", "none");
sp(searchInput, "box-sizing", "border-box");
var suggestBox = document.createElement("div");
sp(suggestBox, "position", "absolute");
sp(suggestBox, "top", "calc(100% + 2px)");
sp(suggestBox, "left", "0");
sp(suggestBox, "right", "0");
sp(suggestBox, "background", "#f9f6f0");
sp(suggestBox, "border", "1px solid #c8b99a");
sp(suggestBox, "border-radius", "3px");
sp(suggestBox, "z-index", "10001");
sp(suggestBox, "display", "none");
sp(suggestBox, "box-shadow", "0 4px 12px rgba(0,0,0,0.08)");
searchWrap.appendChild(suggestBox);
var suggestItems = [];
var suggestIndex = -1;
function renderSuggestions(titles) {
suggestBox.innerHTML = "";
suggestItems = titles;
suggestIndex = -1;
if (titles.length === 0) { suggestBox.style.setProperty("display", "none", "important"); return; }
titles.forEach(function(title, i) {
var item = document.createElement("div");
item.textContent = title;
sp(item, "padding", "0.4rem 0.75rem");
sp(item, "font-family", "'Inter', sans-serif");
sp(item, "font-size", "0.8125rem");
sp(item, "color", "#2a2218");
sp(item, "cursor", "pointer");
sp(item, "border-bottom", i < titles.length - 1 ? "1px solid #f0ebe0" : "none");
item.addEventListener("mouseover", function() { this.style.setProperty("background", "#f0ebe0", "important"); });
item.addEventListener("mouseout", function() { this.style.setProperty("background", "transparent", "important"); });
item.addEventListener("mousedown", function(e) {
e.preventDefault();
window.location.href = "/index.php?title=" + encodeURIComponent(title.replace(/ /g, "_"));
});
suggestBox.appendChild(item);
});
suggestBox.style.setProperty("display", "block", "important");
}
var suggestTimer = null;
searchInput.addEventListener("input", function() {
var q = this.value.trim();
clearTimeout(suggestTimer);
if (q.length < 2) { suggestBox.style.setProperty("display", "none", "important"); return; }
suggestTimer = setTimeout(function() {
fetch("/api.php?action=opensearch&search=" + encodeURIComponent(q) + "&limit=8&namespace=0&format=json")
.then(function(r) { return r.json(); })
.then(function(data) { renderSuggestions(data[1] || []); })
.catch(function() {});
}, 200);
});
searchInput.addEventListener("focus", function() { this.style.setProperty("border-color", "#c8a060", "important"); });
searchInput.addEventListener("blur", function() {
this.style.setProperty("border-color", "#c8b99a", "important");
setTimeout(function() { suggestBox.style.setProperty("display", "none", "important"); }, 150);
});
searchInput.addEventListener("keydown", function(e) {
var items = suggestBox.querySelectorAll("div");
if (e.key === "ArrowDown") {
e.preventDefault();
suggestIndex = Math.min(suggestIndex + 1, items.length - 1);
items.forEach(function(el, i) { el.style.setProperty("background", i === suggestIndex ? "#f0ebe0" : "transparent", "important"); });
} else if (e.key === "ArrowUp") {
e.preventDefault();
suggestIndex = Math.max(suggestIndex - 1, -1);
items.forEach(function(el, i) { el.style.setProperty("background", i === suggestIndex ? "#f0ebe0" : "transparent", "important"); });
} else if (e.key === "Enter") {
e.preventDefault();
if (suggestIndex >= 0 && suggestItems[suggestIndex]) {
window.location.href = "/index.php?title=" + encodeURIComponent(suggestItems[suggestIndex].replace(/ /g, "_"));
} else if (this.value.trim()) {
window.location.href = "/index.php?title=Special%3ASearch&search=" + encodeURIComponent(this.value.trim());
}
} else if (e.key === "Escape") {
suggestBox.style.setProperty("display", "none", "important");
}
});
searchWrap.appendChild(searchIconEl);
searchWrap.appendChild(searchInput);
subbar.appendChild(hbBtn);
subbar.appendChild(searchWrap);
if (isSysop) {
var createDocBtn = document.createElement("a");
createDocBtn.href = "/index.php?title=Erakh_Codex:Create";
createDocBtn.textContent = "+ Create";
sp(createDocBtn, "display", "flex");
sp(createDocBtn, "align-items", "center");
sp(createDocBtn, "height", "44px");
sp(createDocBtn, "padding", "0 1.25rem");
sp(createDocBtn, "margin-left", "auto");
sp(createDocBtn, "font-family", "'Inter', sans-serif");
sp(createDocBtn, "font-size", "0.8125rem");
sp(createDocBtn, "font-weight", "500");
sp(createDocBtn, "color", "#c8a060");
sp(createDocBtn, "text-decoration", "none");
sp(createDocBtn, "border-left", "1px solid #e2d9c8");
sp(createDocBtn, "flex-shrink", "0");
sp(createDocBtn, "box-sizing", "border-box");
sp(createDocBtn, "letter-spacing", "-0.01em");
createDocBtn.addEventListener("mouseover", function() {
this.style.setProperty("background", "#e2d9c8", "important");
this.style.setProperty("color", "#a07840", "important");
});
createDocBtn.addEventListener("mouseout", function() {
this.style.setProperty("background", "transparent", "important");
this.style.setProperty("color", "#c8a060", "important");
});
subbar.appendChild(createDocBtn);
}
// ─── 드로어 ───
var drawerOverlay = document.createElement("div");
sp(drawerOverlay, "position", "fixed");
sp(drawerOverlay, "top", "100px");
sp(drawerOverlay, "left", "0");
sp(drawerOverlay, "right", "0");
sp(drawerOverlay, "bottom", "0");
sp(drawerOverlay, "background", "rgba(0,0,0,0.18)");
sp(drawerOverlay, "z-index", "9996");
sp(drawerOverlay, "display", "none");
var drawer = document.createElement("nav");
sp(drawer, "position", "fixed");
sp(drawer, "top", "100px");
sp(drawer, "left", "0");
sp(drawer, "bottom", "0");
sp(drawer, "width", "220px");
sp(drawer, "background", "#f9f6f0");
sp(drawer, "border-right", "1px solid #e2d9c8");
sp(drawer, "z-index", "9997");
sp(drawer, "display", "none");
sp(drawer, "overflow-y", "auto");
var drawerHead = document.createElement("div");
sp(drawerHead, "padding", "0.75rem 1rem 0.5rem");
sp(drawerHead, "border-bottom", "1px solid #e2d9c8");
var drawerLabel = document.createElement("span");
drawerLabel.textContent = "Menu";
sp(drawerLabel, "font-family", "'Inter', sans-serif");
sp(drawerLabel, "font-size", "0.78rem");
sp(drawerLabel, "font-weight", "500");
sp(drawerLabel, "color", "#2a2218");
sp(drawerLabel, "display", "inline-block");
sp(drawerLabel, "padding-bottom", "0.25rem");
sp(drawerLabel, "border-bottom", "2px solid #c8a060");
drawerHead.appendChild(drawerLabel);
drawer.appendChild(drawerHead);
var drawerMenus = [
{
items: [
{ label: "Main Page", href: "/" },
{ label: "Categories", href: "/index.php?title=Special:Categories" },
{ label: "Timeline", href: "/index.php?title=Category:Chronicle" },
{ label: "Recent Changes", href: "/index.php?title=Special:RecentChanges" },
{ label: "Random Article", href: "/index.php?title=Special:Random" },
],
gold: true
},
{
items: [
{ label: "Policies & Guidelines", href: "/index.php?title=Erakh_Codex:Policies" },
],
gold: false
}
];
drawerMenus.forEach(function(section, si) {
var sec = document.createElement("div");
sp(sec, "padding", "0.5rem 0");
if (si < drawerMenus.length - 1) sp(sec, "border-bottom", "1px solid #e2d9c8");
section.items.forEach(function(item) {
var a = document.createElement("a");
a.href = item.href;
a.textContent = item.label;
sp(a, "display", "block");
sp(a, "padding", "0.45rem 1.25rem");
sp(a, "font-family", "'Inter', sans-serif");
sp(a, "font-size", "0.8125rem");
sp(a, "color", section.gold ? "#c8a060" : "#6b5e4e");
sp(a, "text-decoration", "none");
a.addEventListener("mouseover", function() { this.style.setProperty("background", "#f0ebe0", "important"); });
a.addEventListener("mouseout", function() { this.style.setProperty("background", "transparent", "important"); });
sec.appendChild(a);
});
drawer.appendChild(sec);
});
var drawerOpen = false;
function toggleDrawer() {
drawerOpen = !drawerOpen;
drawer.style.setProperty("display", drawerOpen ? "block" : "none", "important");
drawerOverlay.style.setProperty("display", drawerOpen ? "block" : "none", "important");
}
hbBtn.addEventListener("click", toggleDrawer);
drawerOverlay.addEventListener("click", toggleDrawer);
document.body.insertBefore(subbar, document.body.children[1]);
document.body.appendChild(drawerOverlay);
document.body.appendChild(drawer);
// ─── 3컬럼 레이아웃 (JS 직접 목차 빌드) ───
function buildToc(headings) {
var toc = document.createElement("nav");
toc.id = "erakh-toc";
var ul = document.createElement("ul");
sp(ul, "list-style", "none");
sp(ul, "margin", "0");
sp(ul, "padding", "0");
headings.forEach(function(h, i) {
var level = parseInt(h.tagName.replace("H", ""));
var id = h.id || ("erakh-section-" + i);
h.id = id;
var li = document.createElement("li");
li.style.setProperty("padding", "0.25rem 0 0.25rem " + (level === 2 ? "0.5rem" : "1.25rem"), "important");
li.style.setProperty("border-left", "2px solid transparent", "important");
li.style.setProperty("line-height", "1.4", "important");
li.dataset.id = id;
var a = document.createElement("a");
a.href = "#" + id;
a.textContent = h.textContent.replace(/\[edit\]/g, "").trim();
sp(a, "font-family", "'Inter', sans-serif");
sp(a, "font-size", level === 2 ? "0.78rem" : "0.74rem");
sp(a, "color", level === 2 ? "#6b5e4e" : "#9c8e80");
sp(a, "text-decoration", "none");
sp(a, "display", "block");
a.addEventListener("mouseover", function() { this.style.setProperty("color", "#2a2218", "important"); });
a.addEventListener("mouseout", function() { this.style.setProperty("color", level === 2 ? "#6b5e4e" : "#9c8e80", "important"); });
a.addEventListener("click", function(e) {
e.preventDefault();
var target = document.getElementById(id);
if (target) {
var _h = document.getElementById("erakh-header");
var _s = document.getElementById("erakh-subbar");
var _offset = (_h ? _h.offsetHeight : 56) + (_s ? _s.offsetHeight : 44) + 8;
var top = target.getBoundingClientRect().top + window.scrollY - _offset;
window.scrollTo({ top: top, behavior: "smooth" });
}
});
li.appendChild(a);
ul.appendChild(li);
});
toc.appendChild(ul);
return toc;
}
function buildLayout() {
// 메인페이지 / Create 페이지에서는 레이아웃 빌드 스킵
if (pageName === "Erakh_Codex:Create") return;
if (pageName === "Main_Page") return;
// view 액션이 아닌 경우 (edit, delete 등) 레이아웃 빌드 스킵
if (mw.config.get("wgAction") !== "view") return;
var content = document.querySelector(".mw-body") || document.getElementById("content");
if (!content) return;
var headings = Array.from(content.querySelectorAll("h2, h3")).filter(function(h) {
return !h.closest("#toc");
});
var layout = document.createElement("div");
layout.className = "erakh-layout";
var colLeft = document.createElement("aside");
colLeft.className = "erakh-col-left";
var colCenter = document.createElement("div");
colCenter.className = "erakh-col-center";
var colRight = document.createElement("aside");
colRight.className = "erakh-col-right";
var tocLabel = document.createElement("div");
tocLabel.className = "erakh-toc-label";
tocLabel.textContent = "Contents";
colLeft.appendChild(tocLabel);
if (headings.length > 0) {
var toc = buildToc(headings);
colLeft.appendChild(toc);
var items = colLeft.querySelectorAll("li[data-id]");
window.addEventListener("scroll", function() {
var _h = document.getElementById("erakh-header");
var _s = document.getElementById("erakh-subbar");
var _offset = (_h ? _h.offsetHeight : 56) + (_s ? _s.offsetHeight : 44) + 8;
var scrollY = window.scrollY + _offset;
var current = null;
headings.forEach(function(h) {
if (h.offsetTop <= scrollY) current = h.id;
});
items.forEach(function(li) {
if (li.dataset.id === current) {
li.style.setProperty("border-left-color", "#c8a060", "important");
li.querySelector("a").style.setProperty("color", "#2a2218", "important");
li.querySelector("a").style.setProperty("font-weight", "500", "important");
} else {
li.style.setProperty("border-left-color", "transparent", "important");
var level = li.style.paddingLeft === "0.5rem" ? 2 : 3;
li.querySelector("a").style.setProperty("color", level === 2 ? "#6b5e4e" : "#9c8e80", "important");
li.querySelector("a").style.setProperty("font-weight", "400", "important");
}
});
});
} else {
var emptyMsg = document.createElement("div");
sp(emptyMsg, "font-family", "'Inter', sans-serif");
sp(emptyMsg, "font-size", "0.75rem");
sp(emptyMsg, "color", "#9c8e80");
sp(emptyMsg, "padding", "0.25rem 0.5rem");
emptyMsg.textContent = "—";
colLeft.appendChild(emptyMsg);
}
var sidebarLabel = document.createElement("div");
sidebarLabel.className = "erakh-sidebar-label";
sidebarLabel.textContent = "위젯 영역";
colRight.appendChild(sidebarLabel);
var ph1 = document.createElement("div");
ph1.className = "erakh-sidebar-placeholder";
ph1.textContent = "인기 문서 위젯 예정";
colRight.appendChild(ph1);
var ph2 = document.createElement("div");
ph2.className = "erakh-sidebar-placeholder";
ph2.textContent = "최근 변경 위젯 예정";
colRight.appendChild(ph2);
// ─── sysop 전용 [edit] · [delete] · [json] 버튼 ───
if (isSysop) {
var firstHeadingEl = document.getElementById("firstHeading");
if (firstHeadingEl) {
var actionWrap = document.createElement("span");
sp(actionWrap, "margin-left", "0.75rem");
sp(actionWrap, "font-size", "0.8125rem");
sp(actionWrap, "font-weight", "400");
// [edit]
var editActionLink = document.createElement("a");
editActionLink.href = "/index.php?title=" + encodeURIComponent(pageName) + "&action=edit";
editActionLink.textContent = "[edit]";
sp(editActionLink, "font-family", "'Inter', sans-serif");
sp(editActionLink, "font-size", "0.8125rem");
sp(editActionLink, "color", "#9c8e80");
sp(editActionLink, "text-decoration", "none");
editActionLink.addEventListener("mouseover", function() { this.style.setProperty("color", "#c8a060", "important"); });
editActionLink.addEventListener("mouseout", function() { this.style.setProperty("color", "#9c8e80", "important"); });
// ·
var sep1 = document.createElement("span");
sep1.textContent = " · ";
sp(sep1, "color", "#c8b99a");
sp(sep1, "font-family", "'Inter', sans-serif");
// [delete]
var deleteActionLink = document.createElement("a");
deleteActionLink.href = "/index.php?title=" + encodeURIComponent(pageName) + "&action=delete";
deleteActionLink.textContent = "[delete]";
sp(deleteActionLink, "font-family", "'Inter', sans-serif");
sp(deleteActionLink, "font-size", "0.8125rem");
sp(deleteActionLink, "color", "#9c8e80");
sp(deleteActionLink, "text-decoration", "none");
deleteActionLink.addEventListener("mouseover", function() { this.style.setProperty("color", "#a04040", "important"); });
deleteActionLink.addEventListener("mouseout", function() { this.style.setProperty("color", "#9c8e80", "important"); });
// ·
var sep2 = document.createElement("span");
sep2.textContent = " · ";
sp(sep2, "color", "#c8b99a");
sp(sep2, "font-family", "'Inter', sans-serif");
// [json] — API URL 클립보드 복사
var apiUrl = "https://codex.erakh.com/api.php?action=query&titles=" + encodeURIComponent(pageName) + "&prop=revisions&rvprop=content&format=json";
var jsonBtn = document.createElement("span");
jsonBtn.textContent = "[json]";
sp(jsonBtn, "font-family", "'Inter', sans-serif");
sp(jsonBtn, "font-size", "0.8125rem");
sp(jsonBtn, "color", "#9c8e80");
sp(jsonBtn, "cursor", "pointer");
sp(jsonBtn, "user-select", "none");
jsonBtn.addEventListener("mouseover", function() { this.style.setProperty("color", "#c8a060", "important"); });
jsonBtn.addEventListener("mouseout", function() { this.style.setProperty("color", "#9c8e80", "important"); });
jsonBtn.addEventListener("click", function() {
navigator.clipboard.writeText(apiUrl).then(function() {
jsonBtn.textContent = "[copied!]";
sp(jsonBtn, "color", "#c8a060");
setTimeout(function() {
jsonBtn.textContent = "[json]";
sp(jsonBtn, "color", "#9c8e80");
}, 1500);
}).catch(function() {
// clipboard API 실패 시 fallback
var ta = document.createElement("textarea");
ta.value = apiUrl;
ta.style.position = "fixed";
ta.style.opacity = "0";
document.body.appendChild(ta);
ta.select();
document.execCommand("copy");
document.body.removeChild(ta);
jsonBtn.textContent = "[copied!]";
sp(jsonBtn, "color", "#c8a060");
setTimeout(function() {
jsonBtn.textContent = "[json]";
sp(jsonBtn, "color", "#9c8e80");
}, 1500);
});
});
actionWrap.appendChild(editActionLink);
actionWrap.appendChild(sep1);
actionWrap.appendChild(deleteActionLink);
actionWrap.appendChild(sep2);
actionWrap.appendChild(jsonBtn);
firstHeadingEl.appendChild(actionWrap);
}
}
content.parentNode.insertBefore(layout, content);
colCenter.appendChild(content);
layout.appendChild(colLeft);
layout.appendChild(colCenter);
layout.appendChild(colRight);
}
// ─── 문서 생성 페이지 UI ───
function buildCreatePage() {
if (pageName !== "Erakh_Codex:Create") return;
var CATEGORIES = [
{ label: "Characters", preload: "Template:Preload/Character" },
{ label: "Nations", preload: "Template:Preload/Nation" },
{ label: "Regions", preload: "Template:Preload/Region" },
{ label: "Races", preload: "Template:Preload/Race" },
{ label: "Organizations", preload: "Template:Preload/Organization" },
{ label: "Events", preload: "Template:Preload/Event" },
{ label: "Lore", preload: "Template:Preload/Lore" },
{ label: "Artifacts", preload: "Template:Preload/Artifact" },
{ label: "Chronicle", preload: null },
];
var firstHeading = document.getElementById("firstHeading");
if (firstHeading) sp(firstHeading, "display", "none");
var parseOutput = document.querySelector(".mw-parser-output");
if (parseOutput) sp(parseOutput, "display", "none");
var noArticle = document.querySelector(".noarticletext");
if (noArticle) sp(noArticle, "display", "none");
var pViews = document.getElementById("p-views");
if (pViews) sp(pViews, "display", "none");
var pCactions = document.getElementById("p-cactions");
if (pCactions) sp(pCactions, "display", "none");
var target = document.getElementById("mw-content-text");
if (!target) return;
if (!isSysop) {
var denied = document.createElement("div");
sp(denied, "padding", "60px 40px");
sp(denied, "text-align", "center");
sp(denied, "font-family", "'Inter', sans-serif");
sp(denied, "font-size", "0.875rem");
sp(denied, "color", "#9c8e80");
denied.textContent = "Document creation is restricted to administrators.";
target.appendChild(denied);
return;
}
var selectedCat = null;
var wrap = document.createElement("div");
sp(wrap, "max-width", "680px");
sp(wrap, "margin", "40px auto");
sp(wrap, "padding", "0 24px 48px");
sp(wrap, "font-family", "'Inter', sans-serif");
sp(wrap, "color", "#2a2218");
sp(wrap, "box-sizing", "border-box");
var heading = document.createElement("h2");
heading.textContent = "Create New Document";
sp(heading, "font-size", "1.375rem");
sp(heading, "font-weight", "600");
sp(heading, "margin", "0 0 2rem 0");
sp(heading, "color", "#2a2218");
sp(heading, "letter-spacing", "-0.01em");
sp(heading, "font-family", "'Inter', sans-serif");
wrap.appendChild(heading);
var catLabel = document.createElement("p");
catLabel.textContent = "Select Category";
sp(catLabel, "font-size", "0.6875rem");
sp(catLabel, "font-weight", "500");
sp(catLabel, "color", "#9c8e80");
sp(catLabel, "margin", "0 0 0.625rem 0");
sp(catLabel, "letter-spacing", "0.1em");
sp(catLabel, "text-transform", "uppercase");
sp(catLabel, "font-family", "'Inter', sans-serif");
wrap.appendChild(catLabel);
var grid = document.createElement("div");
sp(grid, "display", "grid");
sp(grid, "grid-template-columns", "repeat(5, 1fr)");
sp(grid, "gap", "8px");
sp(grid, "margin-bottom", "0.625rem");
var catCards = [];
CATEGORIES.forEach(function(cat) {
var card = document.createElement("button");
card.textContent = cat.label;
sp(card, "border", "1.5px solid #e2d9c8");
sp(card, "border-radius", "6px");
sp(card, "background", "#f9f6f0");
sp(card, "padding", "0.75rem 0.375rem");
sp(card, "font-size", "0.79rem");
sp(card, "font-weight", "500");
sp(card, "font-family", "'Inter', sans-serif");
sp(card, "color", "#2a2218");
sp(card, "cursor", "pointer");
sp(card, "text-align", "center");
sp(card, "line-height", "1.3");
sp(card, "box-sizing", "border-box");
card.addEventListener("mouseover", function() {
if (selectedCat !== cat.label) {
this.style.setProperty("background", "#f0ebe0", "important");
this.style.setProperty("border-color", "#c8b99a", "important");
}
});
card.addEventListener("mouseout", function() {
if (selectedCat !== cat.label) {
this.style.setProperty("background", "#f9f6f0", "important");
this.style.setProperty("border-color", "#e2d9c8", "important");
}
});
card.addEventListener("click", function() {
catCards.forEach(function(c) {
c.style.setProperty("background", "#f9f6f0", "important");
c.style.setProperty("border-color", "#e2d9c8", "important");
c.style.setProperty("color", "#2a2218", "important");
});
this.style.setProperty("background", "#c8a060", "important");
this.style.setProperty("border-color", "#c8a060", "important");
this.style.setProperty("color", "#ffffff", "important");
selectedCat = cat.label;
if (cat.preload === null) {
chronicleNotice.style.setProperty("display", "block", "important");
} else {
chronicleNotice.style.setProperty("display", "none", "important");
}
updateBtn();
});
catCards.push(card);
grid.appendChild(card);
});
wrap.appendChild(grid);
var chronicleNotice = document.createElement("p");
chronicleNotice.textContent = "Chronicle documents use a timeline format. No infobox template will be applied.";
sp(chronicleNotice, "display", "none");
sp(chronicleNotice, "font-size", "0.75rem");
sp(chronicleNotice, "color", "#9c8e80");
sp(chronicleNotice, "font-style", "italic");
sp(chronicleNotice, "margin", "0.375rem 0 0 0");
sp(chronicleNotice, "font-family", "'Inter', sans-serif");
wrap.appendChild(chronicleNotice);
var divider = document.createElement("div");
sp(divider, "border-top", "1px solid #e2d9c8");
sp(divider, "margin", "1.5rem 0 1.25rem");
wrap.appendChild(divider);
var titleLabel = document.createElement("p");
titleLabel.textContent = "Document Title";
sp(titleLabel, "font-size", "0.6875rem");
sp(titleLabel, "font-weight", "500");
sp(titleLabel, "color", "#9c8e80");
sp(titleLabel, "margin", "0 0 0.5rem 0");
sp(titleLabel, "letter-spacing", "0.1em");
sp(titleLabel, "text-transform", "uppercase");
sp(titleLabel, "font-family", "'Inter', sans-serif");
wrap.appendChild(titleLabel);
var titleInput = document.createElement("input");
titleInput.type = "text";
titleInput.placeholder = "Enter document title...";
sp(titleInput, "width", "100%");
sp(titleInput, "padding", "0.625rem 0.875rem");
sp(titleInput, "border", "1.5px solid #e2d9c8");
sp(titleInput, "border-radius", "6px");
sp(titleInput, "font-size", "0.9375rem");
sp(titleInput, "font-family", "'Inter', sans-serif");
sp(titleInput, "color", "#2a2218");
sp(titleInput, "background", "#ffffff");
sp(titleInput, "box-sizing", "border-box");
sp(titleInput, "outline", "none");
sp(titleInput, "margin-bottom", "1.25rem");
titleInput.addEventListener("focus", function() { this.style.setProperty("border-color", "#c8a060", "important"); });
titleInput.addEventListener("blur", function() { this.style.setProperty("border-color", "#e2d9c8", "important"); });
titleInput.addEventListener("input", updateBtn);
wrap.appendChild(titleInput);
var createBtn = document.createElement("button");
createBtn.textContent = "Create Article";
sp(createBtn, "display", "block");
sp(createBtn, "width", "100%");
sp(createBtn, "padding", "0.75rem");
sp(createBtn, "background", "#e2d9c8");
sp(createBtn, "border", "none");
sp(createBtn, "border-radius", "6px");
sp(createBtn, "font-size", "0.9375rem");
sp(createBtn, "font-weight", "600");
sp(createBtn, "font-family", "'Inter', sans-serif");
sp(createBtn, "color", "#9c8e80");
sp(createBtn, "cursor", "not-allowed");
sp(createBtn, "box-sizing", "border-box");
createBtn.addEventListener("click", function() {
if (!selectedCat) return;
var title = titleInput.value.trim();
if (!title) return;
var catObj = null;
for (var i = 0; i < CATEGORIES.length; i++) {
if (CATEGORIES[i].label === selectedCat) { catObj = CATEGORIES[i]; break; }
}
if (!catObj) return;
var url = "/index.php?title=" + encodeURIComponent(title) + "&action=edit";
if (catObj.preload) url += "&preload=" + encodeURIComponent(catObj.preload);
window.location.href = url;
});
wrap.appendChild(createBtn);
target.appendChild(wrap);
function updateBtn() {
var ready = selectedCat && titleInput.value.trim().length > 0;
if (ready) {
createBtn.style.setProperty("background", "#c8a060", "important");
createBtn.style.setProperty("color", "#ffffff", "important");
createBtn.style.setProperty("cursor", "pointer", "important");
} else {
createBtn.style.setProperty("background", "#e2d9c8", "important");
createBtn.style.setProperty("color", "#9c8e80", "important");
createBtn.style.setProperty("cursor", "not-allowed", "important");
}
}
}
// ─── 메인페이지 빌드 ───
function buildMainPage() {
if (pageName !== "Main_Page") return;
var firstHeading = document.getElementById("firstHeading");
if (firstHeading) sp(firstHeading, "display", "none");
var parseOutput = document.querySelector(".mw-parser-output");
if (parseOutput) sp(parseOutput, "display", "none");
var target = document.getElementById("mw-content-text");
if (!target) return;
var CATS = [
{ label: "Characters", icon: "ti-user", href: "/index.php?title=Category:Characters", highlight: false },
{ label: "Nations", icon: "ti-building", href: "/index.php?title=Category:Nations", highlight: false },
{ label: "Regions", icon: "ti-map", href: "/index.php?title=Category:Regions", highlight: false },
{ label: "Races", icon: "ti-dna", href: "/index.php?title=Category:Races", highlight: false },
{ label: "Chronicle", icon: "ti-clock", href: "/index.php?title=Category:Chronicle", highlight: true },
{ label: "Organizations", icon: "ti-users", href: "/index.php?title=Category:Organizations", highlight: false },
{ label: "Events", icon: "ti-sword", href: "/index.php?title=Category:Events", highlight: false },
{ label: "Lore", icon: "ti-book", href: "/index.php?title=Category:Lore", highlight: false },
{ label: "Artifacts", icon: "ti-diamond", href: "/index.php?title=Category:Artifacts", highlight: false },
];
var tablerLink = document.createElement("link");
tablerLink.rel = "stylesheet";
tablerLink.href = "https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css";
document.head.appendChild(tablerLink);
var wrap = document.createElement("div");
sp(wrap, "max-width", "860px");
sp(wrap, "margin", "0 auto");
sp(wrap, "padding", "2.5rem 2rem 4rem");
sp(wrap, "font-family", "'Inter', sans-serif");
sp(wrap, "box-sizing", "border-box");
var hero = document.createElement("div");
sp(hero, "background", "#f0ebe0");
sp(hero, "border", "1px solid #e2d9c8");
sp(hero, "border-radius", "6px");
sp(hero, "padding", "2rem 2.5rem");
sp(hero, "margin-bottom", "2.5rem");
sp(hero, "display", "flex");
sp(hero, "align-items", "center");
sp(hero, "justify-content", "space-between");
sp(hero, "box-sizing", "border-box");
var heroText = document.createElement("div");
var heroTitle = document.createElement("h1");
heroTitle.textContent = "Erakh Codex";
sp(heroTitle, "font-size", "1.5rem");
sp(heroTitle, "font-weight", "600");
sp(heroTitle, "color", "#2a2218");
sp(heroTitle, "letter-spacing", "-0.01em");
sp(heroTitle, "margin", "0 0 0.5rem 0");
sp(heroTitle, "font-family", "'Inter', sans-serif");
var heroDesc = document.createElement("p");
heroDesc.textContent = "The official encyclopedia of the Mirtess Chronicle. Explore the world, its history, peoples, and events — all in one place.";
sp(heroDesc, "font-size", "0.8125rem");
sp(heroDesc, "color", "#6b5e4e");
sp(heroDesc, "line-height", "1.7");
sp(heroDesc, "margin", "0");
sp(heroDesc, "max-width", "480px");
sp(heroDesc, "font-family", "'Inter', sans-serif");
heroText.appendChild(heroTitle);
heroText.appendChild(heroDesc);
var heroStat = document.createElement("div");
sp(heroStat, "text-align", "center");
sp(heroStat, "border-left", "1px solid #c8b99a");
sp(heroStat, "padding-left", "2.5rem");
sp(heroStat, "flex-shrink", "0");
var statNum = document.createElement("div");
statNum.textContent = "—";
sp(statNum, "font-size", "2rem");
sp(statNum, "font-weight", "600");
sp(statNum, "color", "#c8a060");
sp(statNum, "letter-spacing", "-0.02em");
sp(statNum, "font-family", "'Inter', sans-serif");
var statLbl = document.createElement("div");
statLbl.textContent = "Documents";
sp(statLbl, "font-size", "0.6875rem");
sp(statLbl, "color", "#9c8e80");
sp(statLbl, "text-transform", "uppercase");
sp(statLbl, "letter-spacing", "0.08em");
sp(statLbl, "margin-top", "0.25rem");
sp(statLbl, "font-family", "'Inter', sans-serif");
heroStat.appendChild(statNum);
heroStat.appendChild(statLbl);
hero.appendChild(heroText);
hero.appendChild(heroStat);
wrap.appendChild(hero);
function makeSectionTitle(text) {
var t = document.createElement("div");
t.textContent = text;
sp(t, "font-size", "0.6875rem");
sp(t, "font-weight", "500");
sp(t, "color", "#9c8e80");
sp(t, "text-transform", "uppercase");
sp(t, "letter-spacing", "0.1em");
sp(t, "margin-bottom", "1rem");
sp(t, "padding-bottom", "0.4rem");
sp(t, "border-bottom", "1px solid #e2d9c8");
sp(t, "font-family", "'Inter', sans-serif");
return t;
}
wrap.appendChild(makeSectionTitle("Browse by Category"));
var catGrid = document.createElement("div");
sp(catGrid, "display", "grid");
sp(catGrid, "grid-template-columns", "repeat(3, 1fr)");
sp(catGrid, "gap", "8px");
sp(catGrid, "margin-bottom", "2.5rem");
var countEls = {};
CATS.forEach(function(cat) {
var card = document.createElement("a");
card.href = cat.href;
sp(card, "border", cat.highlight ? "1.5px solid #c8a060" : "1px solid #e2d9c8");
sp(card, "border-radius", "6px");
sp(card, "background", cat.highlight ? "#f5ede0" : "#ffffff");
sp(card, "padding", "1rem 0.5rem");
sp(card, "text-align", "center");
sp(card, "text-decoration", "none");
sp(card, "display", "block");
sp(card, "box-sizing", "border-box");
if (cat.highlight) {
card.addEventListener("mouseover", function() { this.style.setProperty("background", "#ede0cc", "important"); this.style.setProperty("border-color", "#a07840", "important"); });
card.addEventListener("mouseout", function() { this.style.setProperty("background", "#f5ede0", "important"); this.style.setProperty("border-color", "#c8a060", "important"); });
} else {
card.addEventListener("mouseover", function() { this.style.setProperty("background", "#f0ebe0", "important"); this.style.setProperty("border-color", "#c8b99a", "important"); });
card.addEventListener("mouseout", function() { this.style.setProperty("background", "#ffffff", "important"); this.style.setProperty("border-color", "#e2d9c8", "important"); });
}
var icon = document.createElement("i");
icon.className = "ti " + cat.icon;
sp(icon, "font-size", "1.25rem");
sp(icon, "color", cat.highlight ? "#a07840" : "#c8a060");
sp(icon, "display", "block");
sp(icon, "margin-bottom", "0.4rem");
var name = document.createElement("div");
name.textContent = cat.label;
sp(name, "font-size", "0.75rem");
sp(name, "font-weight", "500");
sp(name, "color", cat.highlight ? "#a07840" : "#2a2218");
sp(name, "font-family", "'Inter', sans-serif");
var count = document.createElement("div");
count.textContent = "—";
sp(count, "font-size", "0.65rem");
sp(count, "color", "#9c8e80");
sp(count, "margin-top", "0.2rem");
sp(count, "font-family", "'Inter', sans-serif");
countEls[cat.label] = count;
card.appendChild(icon);
card.appendChild(name);
card.appendChild(count);
catGrid.appendChild(card);
});
wrap.appendChild(catGrid);
var catTitles = CATS.map(function(c) { return "Category:" + c.label; }).join("|");
fetch("/api.php?action=query&prop=categoryinfo&titles=" + encodeURIComponent(catTitles) + "&format=json")
.then(function(r) { return r.json(); })
.then(function(data) {
var pages = data.query && data.query.pages ? data.query.pages : {};
var totalDocs = 0;
Object.keys(pages).forEach(function(id) {
var page = pages[id];
var catName = (page.title || "").replace("Category:", "");
var cnt = (page.categoryinfo && page.categoryinfo.pages) ? page.categoryinfo.pages : 0;
if (countEls[catName]) {
countEls[catName].textContent = cnt + (cnt === 1 ? " article" : " articles");
}
totalDocs += cnt;
});
statNum.textContent = totalDocs;
})
.catch(function() {});
var twoCol = document.createElement("div");
sp(twoCol, "display", "grid");
sp(twoCol, "grid-template-columns", "1fr 1fr");
sp(twoCol, "gap", "1.5rem");
var welcomeWrap = document.createElement("div");
welcomeWrap.appendChild(makeSectionTitle("New to Erakh Codex?"));
var welcomeBox = document.createElement("div");
sp(welcomeBox, "background", "#ffffff");
sp(welcomeBox, "border", "1px solid #e2d9c8");
sp(welcomeBox, "border-radius", "6px");
sp(welcomeBox, "padding", "1.25rem 1.5rem");
sp(welcomeBox, "display", "flex");
sp(welcomeBox, "align-items", "flex-start");
sp(welcomeBox, "gap", "0.875rem");
sp(welcomeBox, "box-sizing", "border-box");
var wIcon = document.createElement("i");
wIcon.className = "ti ti-info-circle";
sp(wIcon, "font-size", "1.125rem");
sp(wIcon, "color", "#c8a060");
sp(wIcon, "flex-shrink", "0");
sp(wIcon, "margin-top", "0.1rem");
var wText = document.createElement("div");
var wTitle = document.createElement("div");
wTitle.textContent = "Welcome to Erakh Codex";
sp(wTitle, "font-size", "0.875rem");
sp(wTitle, "font-weight", "500");
sp(wTitle, "color", "#2a2218");
sp(wTitle, "margin-bottom", "0.3rem");
sp(wTitle, "font-family", "'Inter', sans-serif");
var wDesc = document.createElement("div");
sp(wDesc, "font-size", "0.775rem");
sp(wDesc, "color", "#6b5e4e");
sp(wDesc, "line-height", "1.65");
sp(wDesc, "font-family", "'Inter', sans-serif");
wDesc.innerHTML = "The official encyclopedia of the Mirtess Chronicle, maintained by the author. Before contributing, please read the <a href='/index.php?title=Erakh_Codex:Policies' style='color:#c8a060;text-decoration:none;font-weight:500;'>Policies & Guidelines</a>.";
wText.appendChild(wTitle);
wText.appendChild(wDesc);
welcomeBox.appendChild(wIcon);
welcomeBox.appendChild(wText);
welcomeWrap.appendChild(welcomeBox);
twoCol.appendChild(welcomeWrap);
var recentWrap = document.createElement("div");
recentWrap.appendChild(makeSectionTitle("Recent Changes"));
var recentBox = document.createElement("div");
sp(recentBox, "background", "#ffffff");
sp(recentBox, "border", "1px solid #e2d9c8");
sp(recentBox, "border-radius", "6px");
sp(recentBox, "overflow", "hidden");
var loadingMsg = document.createElement("div");
loadingMsg.textContent = "Loading...";
sp(loadingMsg, "padding", "1rem");
sp(loadingMsg, "font-size", "0.78rem");
sp(loadingMsg, "color", "#9c8e80");
sp(loadingMsg, "font-family", "'Inter', sans-serif");
recentBox.appendChild(loadingMsg);
fetch("/api.php?action=query&list=recentchanges&rcnamespace=0&rclimit=10&rcprop=title|timestamp&rctype=edit|new&format=json")
.then(function(r) { return r.json(); })
.then(function(data) {
recentBox.innerHTML = "";
var changes = data.query && data.query.recentchanges ? data.query.recentchanges : [];
var seen = {};
var unique = [];
changes.forEach(function(c) {
if (!seen[c.title]) { seen[c.title] = true; unique.push(c); }
});
if (unique.length === 0) {
var empty = document.createElement("div");
empty.textContent = "No documents yet.";
sp(empty, "padding", "1.5rem 1rem");
sp(empty, "font-size", "0.78rem");
sp(empty, "color", "#9c8e80");
sp(empty, "text-align", "center");
sp(empty, "font-family", "'Inter', sans-serif");
recentBox.appendChild(empty);
return;
}
unique.forEach(function(c, i) {
var row = document.createElement("a");
row.href = "/index.php?title=" + encodeURIComponent(c.title.replace(/ /g, "_"));
sp(row, "display", "flex");
sp(row, "align-items", "center");
sp(row, "justify-content", "space-between");
sp(row, "padding", "0.55rem 1rem");
sp(row, "border-bottom", i < unique.length - 1 ? "1px solid #f0ebe0" : "none");
sp(row, "text-decoration", "none");
row.addEventListener("mouseover", function() { this.style.setProperty("background", "#f0ebe0", "important"); });
row.addEventListener("mouseout", function() { this.style.setProperty("background", "transparent", "important"); });
var title = document.createElement("div");
title.textContent = c.title;
sp(title, "font-size", "0.78rem");
sp(title, "color", "#2a2218");
sp(title, "font-family", "'Inter', sans-serif");
var date = document.createElement("div");
var d = new Date(c.timestamp);
date.textContent = d.getFullYear() + "." + String(d.getMonth() + 1).padStart(2, "0") + "." + String(d.getDate()).padStart(2, "0");
sp(date, "font-size", "0.7rem");
sp(date, "color", "#9c8e80");
sp(date, "flex-shrink", "0");
sp(date, "margin-left", "1rem");
sp(date, "font-family", "'Inter', sans-serif");
row.appendChild(title);
row.appendChild(date);
recentBox.appendChild(row);
});
})
.catch(function() {
recentBox.innerHTML = "";
var err = document.createElement("div");
err.textContent = "Could not load recent changes.";
sp(err, "padding", "1rem");
sp(err, "font-size", "0.78rem");
sp(err, "color", "#9c8e80");
sp(err, "font-family", "'Inter', sans-serif");
recentBox.appendChild(err);
});
recentWrap.appendChild(recentBox);
twoCol.appendChild(recentWrap);
wrap.appendChild(twoCol);
target.appendChild(wrap);
}
// ─── 실행 ───
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", function() {
buildLayout();
buildCreatePage();
buildMainPage();
});
} else {
buildLayout();
buildCreatePage();
buildMainPage();
}
})();