131 lines
5.7 KiB
HTML
131 lines
5.7 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="tr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="robots" content="noindex,nofollow">
|
||
<title>Stepstead — Asset Yükle</title>
|
||
<style>
|
||
:root{--bg:#0f1419;--panel:#1a2230;--line:#2c3a4f;--txt:#e6edf3;--muted:#8b99a8;--gold:#e8b923;--ok:#2ea043;--err:#e5534b}
|
||
*{box-sizing:border-box}
|
||
body{margin:0;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;background:var(--bg);color:var(--txt);line-height:1.5}
|
||
.wrap{max-width:640px;margin:0 auto;padding:24px 16px}
|
||
h1{font-size:20px;color:var(--gold);margin:0 0 4px}
|
||
.sub{color:var(--muted);font-size:13px;margin-bottom:20px}
|
||
.card{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:18px;margin-bottom:16px}
|
||
input,button{font-size:14px;border-radius:6px}
|
||
input[type=email],input[type=password]{width:100%;background:#222d3d;color:var(--txt);border:1px solid var(--line);padding:9px 10px;margin-bottom:10px}
|
||
.btn{background:var(--gold);color:#1a1300;border:none;padding:9px 18px;font-weight:600;cursor:pointer}
|
||
.btn:disabled{opacity:.5;cursor:default}
|
||
.msg{font-size:13px;margin-top:10px}
|
||
.msg.ok{color:var(--ok)} .msg.err{color:var(--err)}
|
||
.drop{border:2px dashed var(--line);border-radius:10px;padding:36px 16px;text-align:center;color:var(--muted);cursor:pointer;transition:.15s}
|
||
.drop.over{border-color:var(--gold);color:var(--gold)}
|
||
table{width:100%;border-collapse:collapse;font-size:13px}
|
||
td,th{text-align:left;padding:7px 4px;border-top:1px solid var(--line)}
|
||
th{color:var(--muted);font-weight:500;font-size:12px}
|
||
a{color:var(--gold)}
|
||
.hide{display:none}
|
||
.size{color:var(--muted)}
|
||
img.thumb{max-height:40px;border-radius:4px;vertical-align:middle}
|
||
</style>
|
||
<script src="/nav.js?v=8" data-theme="dark" defer></script>
|
||
</head>
|
||
<body>
|
||
<div class="wrap">
|
||
<h1>📤 Asset Yükle</h1>
|
||
<div class="sub">Harita ve görselleri buradan yükle → <code>https://stepstead.com/assets/uploads/…</code></div>
|
||
|
||
<div class="card" id="loginCard">
|
||
<input type="email" id="email" placeholder="E-posta" autocomplete="username">
|
||
<input type="password" id="pass" placeholder="Şifre" autocomplete="current-password">
|
||
<button class="btn" id="loginBtn">Giriş</button>
|
||
<div class="msg" id="loginMsg"></div>
|
||
</div>
|
||
|
||
<div class="card hide" id="upCard">
|
||
<div class="drop" id="drop">Dosyayı buraya sürükle ya da tıkla<br><small>png / jpg / webp / svg / json / zip — max 30 MB</small></div>
|
||
<input type="file" id="file" hidden accept=".png,.jpg,.jpeg,.webp,.svg,.json,.zip">
|
||
<div class="msg" id="upMsg"></div>
|
||
</div>
|
||
|
||
<div class="card hide" id="listCard">
|
||
<table><thead><tr><th></th><th>Dosya</th><th>Boyut</th></tr></thead><tbody id="rows"></tbody></table>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
const API="https://api.stepstead.com";
|
||
let TOKEN=localStorage.getItem("ss_upload_token")||"";
|
||
|
||
const $=id=>document.getElementById(id);
|
||
function fmt(n){return n>1048576?(n/1048576).toFixed(1)+" MB":Math.round(n/1024)+" KB";}
|
||
|
||
async function api(path,opts={}){
|
||
opts.headers=Object.assign({},opts.headers,{Authorization:"Bearer "+TOKEN});
|
||
const r=await fetch(API+path,opts);
|
||
let body={}; try{body=await r.json();}catch(e){}
|
||
return {ok:r.ok,status:r.status,body};
|
||
}
|
||
|
||
async function login(){
|
||
$("loginMsg").textContent="…";
|
||
const r=await fetch(API+"/auth/login",{method:"POST",headers:{"Content-Type":"application/json"},
|
||
body:JSON.stringify({email:$("email").value.trim(),password:$("pass").value})});
|
||
const b=await r.json().catch(()=>({}));
|
||
if(r.ok&&b.access_token){
|
||
TOKEN=b.access_token; localStorage.setItem("ss_upload_token",TOKEN);
|
||
show();
|
||
}else{
|
||
$("loginMsg").className="msg err";
|
||
$("loginMsg").textContent=b.detail||"Giriş başarısız";
|
||
}
|
||
}
|
||
|
||
async function show(){
|
||
const r=await api("/admin/uploads");
|
||
if(!r.ok){
|
||
if(r.status===401||r.status===403){TOKEN="";localStorage.removeItem("ss_upload_token");}
|
||
$("loginCard").classList.remove("hide");
|
||
$("upCard").classList.add("hide"); $("listCard").classList.add("hide");
|
||
if(r.status===403){$("loginMsg").className="msg err";$("loginMsg").textContent="Bu hesabın yükleme yetkisi yok";}
|
||
return;
|
||
}
|
||
$("loginCard").classList.add("hide");
|
||
$("upCard").classList.remove("hide"); $("listCard").classList.remove("hide");
|
||
const tb=$("rows"); tb.innerHTML="";
|
||
for(const f of r.body){
|
||
const tr=document.createElement("tr");
|
||
const img=/\.(png|jpe?g|webp|svg)$/i.test(f.filename)?`<img class="thumb" src="${f.url}" loading="lazy">`:"📄";
|
||
tr.innerHTML=`<td>${img}</td><td><a href="${f.url}" target="_blank">${f.filename}</a></td><td class="size">${fmt(f.size)}</td>`;
|
||
tb.appendChild(tr);
|
||
}
|
||
}
|
||
|
||
async function upload(file){
|
||
if(!file)return;
|
||
$("upMsg").className="msg"; $("upMsg").textContent="⏳ Yükleniyor: "+file.name;
|
||
const fd=new FormData(); fd.append("file",file);
|
||
const r=await api("/admin/upload",{method:"POST",body:fd});
|
||
if(r.ok){
|
||
$("upMsg").className="msg ok";
|
||
$("upMsg").innerHTML=`✅ Yüklendi: <a href="${r.body.url}" target="_blank">${r.body.url}</a>`;
|
||
show();
|
||
}else{
|
||
$("upMsg").className="msg err";
|
||
$("upMsg").textContent="⚠ "+(r.body.detail||("Hata "+r.status));
|
||
}
|
||
}
|
||
|
||
$("loginBtn").onclick=login;
|
||
$("pass").addEventListener("keydown",e=>{if(e.key==="Enter")login();});
|
||
$("drop").onclick=()=>$("file").click();
|
||
$("file").onchange=e=>upload(e.target.files[0]);
|
||
$("drop").addEventListener("dragover",e=>{e.preventDefault();$("drop").classList.add("over");});
|
||
$("drop").addEventListener("dragleave",()=>$("drop").classList.remove("over"));
|
||
$("drop").addEventListener("drop",e=>{e.preventDefault();$("drop").classList.remove("over");upload(e.dataTransfer.files[0]);});
|
||
|
||
if(TOKEN)show();
|
||
</script>
|
||
</body>
|
||
</html>
|