(function (global) {
"use strict";
const ICONS = {
"chevron-left": '',
"chevron-right": '',
"sun": '',
"moon": '',
"bar-chart-3": '',
"wand-2": '',
"notebook-pen": '',
"message-square": '',
"settings": '',
"inbox": ''
};
function icon(name, size) {
const body = ICONS[name] || "";
return '";
}
function escapeHtml(value) {
return String(value == null ? "" : value).replace(/[&<>"']/g, function (ch) {
return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[ch];
});
}
const stack = [];
let internalNav = 0;
let authMode = "login";
function currentHash() {
let hash = window.location.hash || "";
if (!hash || hash === "#" || hash === "#/") return "#/home";
if (hash.charAt(0) !== "#") hash = "#" + hash;
return hash;
}
function routeOf(hash) {
const path = hash.replace(/^#\/?/, "");
const parts = path.split("/").filter(Boolean);
return { name: parts[0] || "home", params: parts.slice(1) };
}
function currentRoute() {
return routeOf(stack.length ? stack[stack.length - 1] : currentHash());
}
function setHash(hash) {
internalNav++;
window.location.hash = hash;
}
function navigate(hash) {
stack.push(hash);
setHash(hash);
render();
}
function replace(hash) {
if (stack.length) stack[stack.length - 1] = hash;
else stack.push(hash);
setHash(hash);
render();
}
function parentRoute(route) {
if (route.name === "hub") return "#/home";
if (route.name === "feature") return "#/hub/" + route.params[0];
if (route.name === "assistant") return "#/home";
return null;
}
function back() {
if (stack.length > 1) {
stack.pop();
setHash(stack[stack.length - 1]);
render();
return;
}
const parent = parentRoute(currentRoute());
replace(parent || "#/home");
}
function updateHeader(options) {
document.getElementById("m-title").textContent = options.title || "小白复盘";
document.getElementById("m-back").hidden = !options.back;
document.getElementById("m-actions").innerHTML = options.actions || "";
}
function themeToggleHtml() {
const dark = document.getElementById("m-app").dataset.theme === "dark";
const label = dark ? "切换到日间模式" : "切换到夜间模式";
return '";
}
function placeholderHtml(title, subtitle) {
return '
' +
'
' + icon("inbox", 26) + "" +
"
" + escapeHtml(title) + "
" +
"
" + escapeHtml(subtitle || "该页面将在后续批次实现,返回即可继续浏览。") + "
" +
"
";
}
function findFeatureLabel(key) {
const hubs = global.MobileNav.hubs;
for (const hubKey in hubs) {
const items = hubs[hubKey].items || [];
for (const item of items) {
if (item.key === key) return item.label;
}
}
return null;
}
function renderHome() {
updateHeader({ title: "小白复盘", back: false, actions: themeToggleHtml() });
const items = global.MobileNav.entries.map(function (entry) {
const route = entry.key === "assistant" ? "#/assistant/chat" : "#/hub/" + entry.key;
return '' +
'";
}).join("");
document.getElementById("m-view").innerHTML = '";
}
function renderHub(key) {
const hub = global.MobileNav.hubs[key];
const title = hub ? hub.title : key;
updateHeader({ title: title, back: true });
document.getElementById("m-view").innerHTML = placeholderHtml(title, "该入口的图标页将在后续批次实现。");
}
function renderFeature(key) {
const title = findFeatureLabel(key) || key;
updateHeader({ title: title, back: true });
document.getElementById("m-view").innerHTML = placeholderHtml(title, "该功能页将在后续批次实现。");
}
function renderAssistant() {
updateHeader({ title: "复盘助手", back: true });
document.getElementById("m-view").innerHTML = placeholderHtml("复盘助手", "聊天工作台将在后续批次实现。");
}
function renderAuth() {
updateHeader({ title: "小白复盘", back: false, actions: "" });
document.getElementById("m-view").innerHTML = [
'',
'
',
'
复',
'
小白复盘
',
'
登录后进入你的复盘空间
',
"
",
'
',
'',
'',
"
",
'
",
"
"
].join("");
authMode = "login";
bindAuth();
}
function setAuthMode(mode) {
authMode = mode === "register" ? "register" : "login";
document.querySelectorAll("[data-auth-mode]").forEach(function (button) {
button.classList.toggle("active", button.dataset.authMode === authMode);
});
document.getElementById("m-auth-confirm-field").hidden = authMode !== "register";
document.getElementById("m-auth-confirm").required = authMode === "register";
document.getElementById("m-auth-password").autocomplete = authMode === "register" ? "new-password" : "current-password";
document.getElementById("m-auth-submit").textContent = authMode === "register" ? "注册并进入" : "登录";
document.getElementById("m-auth-error").hidden = true;
}
function bindAuth() {
document.querySelectorAll("[data-auth-mode]").forEach(function (button) {
button.addEventListener("click", function () { setAuthMode(button.dataset.authMode); });
});
document.getElementById("m-auth-form").addEventListener("submit", submitAuth);
}
async function submitAuth(event) {
event.preventDefault();
const username = document.getElementById("m-auth-username").value.trim();
const password = document.getElementById("m-auth-password").value;
const errorElement = document.getElementById("m-auth-error");
if (authMode === "register" && password !== document.getElementById("m-auth-confirm").value) {
errorElement.textContent = "两次输入的密码不一致。";
errorElement.hidden = false;
return;
}
const submit = document.getElementById("m-auth-submit");
submit.disabled = true;
try {
if (authMode === "register") {
await global.MobileSession.register(username, password);
} else {
await global.MobileSession.login(username, password);
}
replace("#/home");
} catch (error) {
errorElement.textContent = error.message || "账号操作失败";
errorElement.hidden = false;
} finally {
submit.disabled = false;
}
}
function render() {
const route = currentRoute();
if (route.name === "hub") renderHub(route.params[0]);
else if (route.name === "feature") renderFeature(route.params.join("/"));
else if (route.name === "assistant") renderAssistant();
else if (route.name === "auth") renderAuth();
else renderHome();
}
function bindGlobalEvents() {
document.getElementById("m-view").addEventListener("click", function (event) {
const entry = event.target.closest("[data-route]");
if (entry) {
navigate(entry.dataset.route);
}
});
document.getElementById("m-back").addEventListener("click", back);
document.addEventListener("click", function (event) {
const toggle = event.target.closest("[data-theme-toggle]");
if (!toggle) return;
global.MobileTheme.toggle();
if (currentRoute().name === "home") {
document.getElementById("m-actions").innerHTML = themeToggleHtml();
}
});
window.addEventListener("hashchange", function () {
if (internalNav > 0) {
internalNav--;
return;
}
const hash = currentHash();
if (stack.length > 1 && hash === stack[stack.length - 2]) {
stack.pop();
} else if (hash !== stack[stack.length - 1]) {
stack.push(hash);
}
render();
});
}
function init() {
bindGlobalEvents();
stack.length = 0;
stack.push(currentHash());
render();
}
global.MobileRouter = {
init: init,
navigate: navigate,
replace: replace,
back: back,
render: render,
currentRoute: currentRoute
};
})(window);