MediaWiki:Common.js: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
| Line 562: | Line 562: | ||
items: [ | items: [ | ||
{ label: "Main Page", href: "/" }, | { 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: "Recent Changes", href: "/index.php?title=Special:RecentChanges" }, | ||
{ label: "Random Article", href: "/index.php?title=Special:Random" }, | { label: "Random Article", href: "/index.php?title=Special:Random" }, | ||
| Line 571: | Line 573: | ||
{ label: "Editing Guide", href: "/index.php?title=Erakh_Codex:Editing_guide" }, | { label: "Editing Guide", href: "/index.php?title=Erakh_Codex:Editing_guide" }, | ||
{ label: "Policies & Guidelines", href: "/index.php?title=Erakh_Codex:Policies" }, | { label: "Policies & Guidelines", href: "/index.php?title=Erakh_Codex:Policies" }, | ||
], | ], | ||
gold: false | gold: false | ||
Revision as of 16:49, 10 May 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) {}
// ─── [추가] 페이지명 및 sysop 여부 ───
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");
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");
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);
// ─── [추가] 서브바 Create 버튼 (sysop only) ───
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: "Editing Guide", href: "/index.php?title=Erakh_Codex:Editing_guide" },
{ 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"); });
li.appendChild(a);
ul.appendChild(li);
});
toc.appendChild(ul);
return toc;
}
function buildLayout() {
// ─── [추가] Create 페이지에서는 레이아웃 빌드 스킵 ───
if (pageName === "Erakh_Codex:Create") 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 scrollY = window.scrollY + 108;
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);
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: "Disciplines", preload: "Template:Preload/Discipline" },
{ label: "Culture", preload: "Template:Preload/Culture" },
{ label: "Artifacts", preload: "Template:Preload/Artifact" },
{ label: "Chronicle", preload: null },
];
// MW 기본 UI 숨김
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;
// 비sysop 접근 시 안내
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);
// ── Chronicle 안내
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);
// ── Create 버튼
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");
}
}
}
// ─── 실행 ───
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", function() {
buildLayout();
buildCreatePage();
});
} else {
buildLayout();
buildCreatePage();
}
})();