first commit

This commit is contained in:
Colin-Joel Scupin
2026-08-05 01:29:39 +02:00
commit 86d4bcdc37
85 changed files with 7706 additions and 0 deletions
+110
View File
@@ -0,0 +1,110 @@
const resource = typeof GetParentResourceName === 'function' ? GetParentResourceName() : 'devx_housing';
const preview = document.querySelector('#preview');
const panel = document.querySelector('#panel');
const building = document.querySelector('#building');
const label = document.querySelector('#label');
const meta = document.querySelector('#meta');
const price = document.querySelector('#price');
const buy = document.querySelector('#buy');
const buyText = document.querySelector('#buyText');
const panelTitle = document.querySelector('#panelTitle');
const panelText = document.querySelector('#panelText');
const panelBody = document.querySelector('#panelBody');
let currentDoor = null;
async function post(name, data = {}) {
const response = await fetch(`https://${resource}/${name}`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
});
return response.json();
}
function money(value){return `${new Intl.NumberFormat('de-DE').format(Number(value)||0)} $`}
function closePanel(){panel.classList.add('hidden');post('uiClose')}
document.querySelector('#previous').onclick = () => post('previewPrevious');
document.querySelector('#next').onclick = () => post('previewNext');
document.querySelector('#previewClose').onclick = () => post('previewClose');
document.querySelector('#panelClose').onclick = closePanel;
buy.onclick = async () => {
buy.disabled = true;
const result = await post('previewBuy');
if (!result.ok) {
buyText.textContent = result.error || 'KAUF FEHLGESCHLAGEN';
setTimeout(() => buyText.textContent = 'KAUFEN', 2200);
buy.disabled = false;
}
};
document.addEventListener('keyup', event => {
if (event.key === 'Escape') {
if (!preview.classList.contains('hidden')) post('previewClose');
else if (!panel.classList.contains('hidden')) closePanel();
}
});
function elevator(data){
panel.classList.remove('hidden');
panelTitle.textContent = data.building;
panelText.textContent = `Aufzug · aktuelle Etage ${data.currentFloor || 'Lobby'}`;
panelBody.innerHTML = '';
for(let floor=1;floor<=Number(data.floors||1);floor++){
const button=document.createElement('button');button.className='panel-action';
button.innerHTML=`<b>Etage ${floor}</b><span>Wohnungen ${floor}01${floor}04</span>`;
button.onclick=()=>post('elevatorFloor',{floor});
panelBody.appendChild(button);
}
}
function invite(data){
panel.classList.remove('hidden');
panelTitle.textContent=data.title||'Spieler einladen';
panelText.textContent='Der ausgewählte Spieler erhält eine Einladung und wird erst nach der Annahme teleportiert.';
panelBody.innerHTML='';
const players=Array.isArray(data.players)?data.players:[];
if(players.length===0){
const empty=document.createElement('div');empty.className='empty-state';empty.textContent='Aktuell ist kein anderer Spieler online.';panelBody.appendChild(empty);return;
}
for(const player of players){
const button=document.createElement('button');button.className='panel-action';
button.innerHTML=`<b>${player.name||'Spieler'}</b><span>Server-ID ${player.source}</span>`;
button.onclick=async()=>{button.disabled=true;const result=await post('invitePlayer',{target:player.source});if(!result.ok)button.disabled=false;};
panelBody.appendChild(button);
}
}
function door(data){
currentDoor=data;
panel.classList.remove('hidden');
panelTitle.textContent=data.label;
panelText.textContent=data.sold?`Bewohner: ${data.ownerName||'Unbekannt'}`:'Diese Wohnung ist noch frei.';
panelBody.innerHTML='';
const actions=document.createElement('div');actions.className='door-actions';
if(data.sold){
const ring=document.createElement('button');ring.className='panel-action';ring.innerHTML='<b>Klingeln</b>';ring.onclick=()=>post('doorRing',{propertyKey:data.propertyKey});
const knock=document.createElement('button');knock.className='panel-action';knock.innerHTML='<b>Klopfen</b>';knock.onclick=()=>post('doorKnock',{propertyKey:data.propertyKey});
actions.append(ring,knock);
const enter=document.createElement('button');enter.className='panel-action enter';enter.innerHTML='<b>Mit Einladung eintreten</b>';enter.onclick=()=>post('doorEnter',{propertyKey:data.propertyKey});actions.appendChild(enter);
}
panelBody.appendChild(actions);
}
window.addEventListener('message', event => {
const data=event.data||{};
if(data.action==='previewOpen'){preview.classList.remove('hidden');panel.classList.add('hidden')}
if(data.action==='previewData'){
building.textContent=data.building||'DEVX IMMOBILIEN';
label.textContent=data.label||'Wohnung';
meta.textContent=`Etage ${data.floor} · Wohnung ${data.unitNumber} · ${data.style} · ${data.index}/${data.total}`;
price.textContent=money(data.price);
buy.disabled=Boolean(data.sold);
buyText.textContent=data.ownedByMe?'DEINE WOHNUNG':data.sold?`VERKAUFT · ${data.ownerName||'Bewohnt'}`:'KAUFEN';
}
if(data.action==='elevatorOpen')elevator(data);
if(data.action==='doorOpen')door(data);
if(data.action==='inviteOpen')invite(data);
if(data.action==='close'){preview.classList.add('hidden');panel.classList.add('hidden')}
});
@@ -0,0 +1,38 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main id="preview" class="hidden">
<section class="preview-bar">
<button id="previous" class="arrow" aria-label="Vorherige Wohnung"></button>
<div class="preview-copy">
<small id="building">DEVX IMMOBILIEN</small>
<strong id="label">Wohnung</strong>
<span id="meta">Etage · Stil</span>
</div>
<button id="buy" class="buy">
<span id="buyText">KAUFEN</span>
<b id="price">0 $</b>
</button>
<button id="next" class="arrow" aria-label="Nächste Wohnung"></button>
<button id="previewClose" class="close">×</button>
</section>
</main>
<main id="panel" class="hidden overlay">
<section class="panel-card">
<button id="panelClose" class="close panel-close">×</button>
<small id="panelEyebrow">DEVX-CITY</small>
<h1 id="panelTitle">Aufzug</h1>
<p id="panelText"></p>
<div id="panelBody" class="panel-body"></div>
</section>
</main>
<script src="app.js"></script>
</body>
</html>
@@ -0,0 +1,2 @@
:root{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:#fff}*{box-sizing:border-box}body{margin:0;background:transparent;overflow:hidden}.hidden{display:none!important}button{font:inherit}.preview-bar{position:fixed;left:50%;bottom:42px;transform:translateX(-50%);display:grid;grid-template-columns:64px minmax(260px,1fr) 190px 64px;align-items:stretch;width:min(860px,calc(100vw - 80px));min-height:98px;border:1px solid rgba(255,255,255,.14);border-radius:18px;background:linear-gradient(180deg,rgba(12,17,28,.96),rgba(7,10,18,.97));box-shadow:0 25px 80px rgba(0,0,0,.55);backdrop-filter:blur(14px);overflow:visible}.preview-copy{display:flex;flex-direction:column;justify-content:center;padding:14px 22px}.preview-copy small,#panelEyebrow{font-size:10px;font-weight:900;letter-spacing:.2em;color:#79a7ff}.preview-copy strong{font-size:20px;margin-top:4px}.preview-copy span{font-size:12px;color:rgba(255,255,255,.58);margin-top:4px}.arrow,.buy{border:0;cursor:pointer;color:#fff}.arrow{font-size:42px;background:rgba(255,255,255,.035);transition:.15s}.arrow:hover{background:rgba(90,136,255,.22)}.buy{display:flex;flex-direction:column;align-items:center;justify-content:center;background:linear-gradient(135deg,#4977f3,#6e95ff);font-weight:900}.buy span{font-size:13px;letter-spacing:.1em}.buy b{font-size:18px;margin-top:4px}.buy:disabled{cursor:not-allowed;background:#2b303c;color:rgba(255,255,255,.5)}.close{border:1px solid rgba(255,255,255,.16);background:#111722;color:white;border-radius:999px;width:34px;height:34px;cursor:pointer;font-size:22px;line-height:1}.preview-bar>.close{position:absolute;right:-14px;top:-14px}.overlay{position:fixed;inset:0;display:grid;place-items:center;background:rgba(2,5,11,.62);backdrop-filter:blur(8px)}.panel-card{position:relative;width:min(520px,calc(100vw - 60px));max-height:76vh;padding:30px;border:1px solid rgba(255,255,255,.14);border-radius:22px;background:linear-gradient(180deg,#101725,#080d16);box-shadow:0 35px 100px rgba(0,0,0,.65)}.panel-close{position:absolute;right:18px;top:18px}.panel-card h1{margin:6px 0 8px;font-size:28px}.panel-card p{margin:0 0 20px;color:rgba(255,255,255,.62)}.panel-body{display:grid;gap:10px;max-height:52vh;overflow:auto}.panel-action{display:flex;align-items:center;justify-content:space-between;width:100%;padding:14px 16px;border:1px solid rgba(255,255,255,.11);border-radius:12px;background:rgba(255,255,255,.04);color:white;cursor:pointer;text-align:left}.panel-action:hover{border-color:#6e95ff;background:rgba(80,120,235,.15)}.panel-action b{font-size:15px}.panel-action span{font-size:12px;color:rgba(255,255,255,.55)}.door-actions{display:grid;grid-template-columns:1fr 1fr;gap:10px}.door-actions .panel-action{justify-content:center;text-align:center}.door-actions .enter{grid-column:1/-1;background:linear-gradient(135deg,#4977f3,#6e95ff);border:0}
.empty-state{padding:18px;border:1px dashed rgba(255,255,255,.16);border-radius:12px;color:rgba(255,255,255,.62);text-align:center}.panel-action:disabled{opacity:.55;cursor:wait}