/* Stepstead ortak header + footer. Kullanım: Panel linkleri role/izin bazlı görünür: GET /auth/me → permissions[]. İzinler: upload, lore, map_view, map_edit, users ("*" = admin). */ (function(){ "use strict"; const API="https://api.stepstead.com"; const PUBLIC_LINKS=[ {href:"/",label:"🏠 Ana Sayfa"}, {href:"/db/",label:"📖 Craft Veritabanı"}, {href:"/items/",label:"🎒 Eşyalar"}, ]; const PANEL_LINKS=[ {href:"/assets/",label:"🎨 Asset Takip",perms:["upload"]}, {href:"/assets/upload.html",label:"📤 Dosya Yükle",perms:["upload"]}, {href:"/assets/lore.html",label:"📜 Lore",perms:["lore"]}, {href:"/assets/quests.html",label:"🗡 Görevler",perms:["lore"]}, {href:"/assets/npcs.html",label:"🧙 NPC'ler",perms:["npc"]}, {href:"/assets/chars.html",label:"⚔ Karakterler",perms:["chars"]}, {href:"/assets/map-editor.html",label:"🗺 Harita Editörü",perms:["map_view","map_edit"]}, {href:"/assets/users.html",label:"👥 Kullanıcılar",perms:["users"]}, ]; const script=document.currentScript; const theme=(script&&script.dataset.theme)==="light"?"light":"dark"; const css=` .ss-nav{font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;line-height:1.4;position:relative} .ss-nav .ss-in{max-width:1040px;margin:0 auto;padding:0 16px;display:flex;align-items:center;gap:4px;flex-wrap:wrap;min-height:46px} .ss-nav .ss-brand{font-weight:700;font-size:15px;text-decoration:none;margin-right:10px;letter-spacing:.2px} .ss-nav a.ss-lnk{text-decoration:none;font-size:13px;padding:5px 10px;border-radius:6px;white-space:nowrap} .ss-nav .ss-adm{display:none;align-items:center;gap:4px;flex-wrap:wrap} .ss-nav .ss-adm.on{display:flex} .ss-nav .ss-admtag{font-size:10px;text-transform:uppercase;letter-spacing:.08em;opacity:.6;margin:0 2px 0 8px} .ss-nav .ss-authbtn{margin-left:auto;background:none;border:1px solid transparent;font-size:13px;padding:5px 10px;border-radius:6px;cursor:pointer;white-space:nowrap} .ss-nav .ss-loginbox{display:none;position:absolute;right:16px;top:100%;margin-top:6px;z-index:50;padding:12px;border-radius:10px;box-shadow:0 8px 28px rgba(0,0,0,.35);min-width:230px} .ss-nav .ss-loginbox.on{display:block} .ss-nav .ss-loginbox input{display:block;width:100%;box-sizing:border-box;margin-bottom:8px;padding:7px 9px;border-radius:6px;font-size:13px} .ss-nav .ss-loginbox button{width:100%;padding:7px;border:none;border-radius:6px;font-size:13px;font-weight:600;cursor:pointer} .ss-nav .ss-loginmsg{font-size:12px;margin-top:6px;min-height:14px} .ss-foot{font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;font-size:12px;margin-top:48px} .ss-foot .ss-in{max-width:1040px;margin:0 auto;padding:16px;display:flex;gap:14px;flex-wrap:wrap;align-items:center} .ss-foot a{text-decoration:none} .ss-foot .ss-sp{margin-left:auto} /* dark */ .ss-dark.ss-nav{background:#0b1016;border-bottom:1px solid #2c3a4f} .ss-dark.ss-nav .ss-brand{color:#e8b923} .ss-dark.ss-nav a.ss-lnk{color:#8b99a8} .ss-dark.ss-nav a.ss-lnk:hover{color:#e6edf3;background:#1a2230} .ss-dark.ss-nav a.ss-lnk.on{color:#e8b923;background:#1a2230} .ss-dark.ss-nav .ss-admtag{color:#8b99a8} .ss-dark.ss-nav .ss-authbtn{color:#8b99a8;border-color:#2c3a4f;background:#0b1016} .ss-dark.ss-nav .ss-authbtn:hover{color:#e8b923;border-color:#e8b923} .ss-dark.ss-nav .ss-loginbox{background:#1a2230;border:1px solid #2c3a4f} .ss-dark.ss-nav .ss-loginbox input{background:#222d3d;color:#e6edf3;border:1px solid #2c3a4f} .ss-dark.ss-nav .ss-loginbox button{background:#e8b923;color:#1a1300} .ss-dark.ss-nav .ss-loginmsg{color:#e5534b} .ss-dark.ss-foot{background:#0b1016;border-top:1px solid #2c3a4f;color:#8b99a8} .ss-dark.ss-foot a{color:#8b99a8} .ss-dark.ss-foot a:hover{color:#e8b923} /* light */ .ss-light.ss-nav{background:#2f4a35;border-bottom:1px solid #253b2a} .ss-light.ss-nav .ss-brand{color:#fff} .ss-light.ss-nav a.ss-lnk{color:rgba(255,255,255,.75)} .ss-light.ss-nav a.ss-lnk:hover{color:#fff;background:rgba(255,255,255,.12)} .ss-light.ss-nav a.ss-lnk.on{color:#fff;background:rgba(255,255,255,.18)} .ss-light.ss-nav .ss-admtag{color:rgba(255,255,255,.6)} .ss-light.ss-nav .ss-authbtn{color:rgba(255,255,255,.75);border-color:rgba(255,255,255,.3);background:transparent} .ss-light.ss-nav .ss-authbtn:hover{color:#fff;border-color:#fff} .ss-light.ss-nav .ss-loginbox{background:#fff;border:1px solid #e4e0d6} .ss-light.ss-nav .ss-loginbox input{background:#f5f3ee;color:#2d3a2e;border:1px solid #e4e0d6} .ss-light.ss-nav .ss-loginbox button{background:#3a5a40;color:#fff} .ss-light.ss-nav .ss-loginmsg{color:#c0392b} .ss-light.ss-foot{background:transparent;border-top:1px solid #e4e0d6;color:#77806f} .ss-light.ss-foot a{color:#77806f} .ss-light.ss-foot a:hover{color:#3a5a40} `; let PERMS=[]; function tok(){return localStorage.getItem("ss_upload_token")||"";} function hasPerm(p){return PERMS.includes("*")||PERMS.includes(p);} function anyPerm(list){return list.some(hasPerm);} function norm(p){return p.replace(/index\.html$/,"");} function link(l){ const a=document.createElement("a"); a.className="ss-lnk"+(norm(location.pathname)===norm(l.href)?" on":""); a.href=l.href;a.textContent=l.label; return a; } function applyPerms(role){ const adm=document.getElementById("ssAdmLinks"); adm.innerHTML=""; // Panel yetkisi olan (bir rolü/izni bulunan) herkes TÜM sekmeleri görür. // İşlem yetkisi sayfa/backend tarafında izne göre ayrıca denetlenir. const isPanel=PERMS.length>0; if(isPanel){ const tag=document.createElement("span"); tag.className="ss-admtag";tag.textContent=role||"panel"; adm.appendChild(tag); for(const l of PANEL_LINKS)adm.appendChild(link(l)); adm.classList.add("on"); }else adm.classList.remove("on"); document.getElementById("ssAuthBtn").textContent=PERMS.length?"🚪 Çıkış":"🔑 Giriş"; if(PERMS.length)sessionStorage.setItem("ss_nav_perms",JSON.stringify({p:PERMS,r:role||""})); else sessionStorage.removeItem("ss_nav_perms"); } function build(){ const st=document.createElement("style");st.textContent=css;document.head.appendChild(st); const nav=document.createElement("nav"); nav.className="ss-nav ss-"+theme; const inner=document.createElement("div");inner.className="ss-in"; const brand=document.createElement("a"); brand.className="ss-brand";brand.href="/";brand.textContent="👣 Stepstead"; inner.appendChild(brand); for(const l of PUBLIC_LINKS)inner.appendChild(link(l)); const adm=document.createElement("span");adm.className="ss-adm";adm.id="ssAdmLinks"; inner.appendChild(adm); const authBtn=document.createElement("button"); authBtn.className="ss-authbtn";authBtn.id="ssAuthBtn";authBtn.textContent="🔑 Giriş"; authBtn.onclick=()=>{ if(PERMS.length){ localStorage.removeItem("ss_upload_token"); PERMS=[];applyPerms(null); return; } document.getElementById("ssLoginBox").classList.toggle("on"); document.getElementById("ssLgEmail").focus(); }; inner.appendChild(authBtn); const box=document.createElement("div"); box.className="ss-loginbox";box.id="ssLoginBox"; box.innerHTML=`
`; nav.appendChild(inner); nav.appendChild(box); document.body.prepend(nav); document.getElementById("ssLgBtn").onclick=doLogin; document.getElementById("ssLgPass").addEventListener("keydown",e=>{if(e.key==="Enter")doLogin();}); document.addEventListener("click",e=>{ if(!box.contains(e.target)&&e.target!==authBtn)box.classList.remove("on"); }); const foot=document.createElement("footer"); foot.className="ss-foot ss-"+theme; foot.innerHTML=``; document.body.appendChild(foot); } async function doLogin(){ const msg=document.getElementById("ssLgMsg"); msg.textContent="…"; try{ const r=await fetch(API+"/auth/login",{method:"POST",headers:{"Content-Type":"application/json"}, body:JSON.stringify({email:document.getElementById("ssLgEmail").value.trim(), password:document.getElementById("ssLgPass").value})}); const b=await r.json().catch(()=>({})); if(!r.ok||!b.access_token){msg.textContent=b.detail||"Giriş başarısız";return;} localStorage.setItem("ss_upload_token",b.access_token); msg.textContent=""; await refresh(); if(PERMS.length){ document.getElementById("ssLoginBox").classList.remove("on"); document.getElementById("ssLgPass").value=""; }else msg.textContent="Giriş tamam — ama bu hesabın panel yetkisi yok"; }catch(e){msg.textContent="Bağlantı hatası";} } async function refresh(){ if(!tok()){PERMS=[];applyPerms(null);return;} try{ const r=await fetch(API+"/auth/me",{headers:{Authorization:"Bearer "+tok()}}); if(r.ok){ const u=await r.json(); PERMS=u.permissions||[]; applyPerms(u.role); }else{ if(r.status===401)localStorage.removeItem("ss_upload_token"); PERMS=[];applyPerms(null); } }catch(e){ // geçici ağ hatası: cache'e güven try{ const c=JSON.parse(sessionStorage.getItem("ss_nav_perms")||"null"); if(c){PERMS=c.p;applyPerms(c.r);return;} }catch(_){} PERMS=[];applyPerms(null); } } window.ssNavRefresh=refresh; function init(){ build(); try{ const c=JSON.parse(sessionStorage.getItem("ss_nav_perms")||"null"); if(c&&tok()){PERMS=c.p;applyPerms(c.r);} }catch(_){} refresh(); } if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",init); else init(); })();