İlk commit: Stepstead web (statik panel + db)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
commit
dea01dd6a8
18 changed files with 3764 additions and 0 deletions
131
assets/upload.html
Normal file
131
assets/upload.html
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
<!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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue