/* ============================================================
宇森官网 · 公共脚本(所有子页面共享)
common.js — 含:导航高亮 / 登录态 / SVG 缩略图生成器
依赖:assets/game-api.js(需在本文件之前加载)
============================================================ */
// ---------- 导航栏:根据当前 URL 自动高亮对应链接 ----------
(function(){
const links = document.querySelectorAll('.nav a');
const page = location.pathname.split('/').pop().replace(/\.html$/,'') || 'index';
links.forEach(a => {
const href = a.getAttribute('href') || '';
const target = href.replace(/\.html$/,'').replace(/^\.\//,'');
if (target === page || (page === '' && target === 'index')) {
a.classList.add('active');
}
});
})();
// ---------- 登录态 / 右上角用户信息(从 Odoo 取) ----------
(function(){
const userBox = document.getElementById('userBox');
if (!userBox) return;
// sessionStorage key:'yusen:me' = JSON({uid,name,login}) 或 '' 表示已确认未登录
function saveMe(me){ try{ sessionStorage.setItem('yusen:me', me ? JSON.stringify(me) : ''); }catch(e){} }
function loadMe(){ try{ const v=sessionStorage.getItem('yusen:me'); return v===null?undefined:(v?JSON.parse(v):null); }catch(e){return undefined;} }
function renderLoggedOut(){
userBox.innerHTML = '登录注册';
document.querySelectorAll('.nav .auth-only').forEach(el => el.classList.remove('visible'));
}
function renderLoggedIn(me){
userBox.innerHTML = '';
const nm = userBox.querySelector('.ub-name');
if (nm) nm.textContent = me.name || me.login;
document.querySelectorAll('.nav .auth-only').forEach(el => el.classList.add('visible'));
const lb = document.getElementById('ubLogout');
if (lb) lb.addEventListener('click', async ()=>{
try { await API.logout(); } catch(e){}
saveMe(null);
sessionStorage.removeItem('yusen:me');
location.href = 'index.html';
});
}
// 1) 同步首屏:从 sessionStorage 立即渲染正确状态(消除 topbar 闪一下)
const cached = loadMe();
if (cached === undefined) {
// 第一次访问:渲染一个不闪烁的占位(保持默认空,等异步结果)
userBox.innerHTML = '…';
} else if (cached && cached.uid) {
renderLoggedIn(cached);
} else {
renderLoggedOut();
}
// 2) 异步校验:拿真实登录态,纠正缓存
async function refreshUserBox(){
try{
const me = await API.me();
if (me && me.uid) { saveMe(me); renderLoggedIn(me); }
else { saveMe(null); renderLoggedOut(); }
}catch(e){
if (cached === undefined) renderLoggedOut(); // 首次访问 + 接口挂了才退回未登录
}
}
if (typeof API !== 'undefined') refreshUserBox();
else document.addEventListener('DOMContentLoaded', ()=>{ if (typeof API !== 'undefined') refreshUserBox(); });
})();
// ---------- 程序化矢量缩略图(图鉴/首页共用) ----------
function hashStr(s){let h=2166136261;for(let i=0;i>>0;}
function rng(seed){let s=seed>>>0;return function(){s=(Math.imul(s,1664525)+1013904223)>>>0;return s/4294967296;};}
const TIERCOL={'普通':'#9aa6c4','精良':'#5fd38a','稀有':'#4cc9f0','史诗':'#c77dff','传说':'#e7b85c'};
function starPts(cx,cy,spikes,outer,inner){
let pts=[],rot=-Math.PI/2;
for(let i=0;i`;
if(v===0){s+=``;}
else if(v===1){s+=``;}
else{s+=``;}
s+=``;
return s;
}
function shBuild(r,seed){
let s=``;
s+=``;
for(let i=0;i<3;i++)s+=``;
return s;
}
function shElement(r,seed){
const sides=3+Math.floor(r()*6);
let s=``;
s+=``;
return s;
}
function shPersona(r,seed){
let s=``;
s+=``;
s+=``;
return s;
}
function shTalent(r,seed){
const sp=4+Math.floor(r()*4);
let s=``;
s+=``;
return s;
}
function shRelic(r,seed){
let s=``;
s+=``;
return s;
}
function shEquip(sub,seed){
switch(sub){
case 'head': return ``;
case 'hand': {let s=``;for(let i=0;i<3;i++)s+=``;return s;}
case 'chest': return ``;
case 'pants': return ``;
case 'shoes': return ``;
case 'ring': return ``;
case 'neck': return ``;
case 'treasure': return ``;
default: return ``;
}
}
function shEvent(r,seed){
let s=``;
s+=``;
return s;
}
function shapeFor(cat,sub,r,seed){
switch(cat){
case 'race': return shRace(r,seed);
case 'build': return shBuild(r,seed);
case 'element': return shElement(r,seed);
case 'persona': return shPersona(r,seed);
case 'talent': return shTalent(r,seed);
case 'relic': return shRelic(r,seed);
case 'equip': return shEquip(sub,seed);
case 'event': return shEvent(r,seed);
default: return ``;
}
}
function thumbSVG(it){
const seed=hashStr(it.cat+it.sub+it.name);
const r=rng(seed);
const h=Math.floor(r()*360);
const h2=(h+40)%360;
const tcol=TIERCOL[it.tier]||'#9aa6c4';
const shape=shapeFor(it.cat,it.sub,r,seed);
return ``;
}