135 lines
5.1 KiB
HTML
135 lines
5.1 KiB
HTML
<!doctype html>
|
|
<html lang="pl">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>Domain Hunter Panel</title>
|
|
<style>
|
|
body{font-family:Inter,Arial,sans-serif;background:#0b1020;color:#e8ecff;margin:0;padding:12px}
|
|
.wrap{max-width:1200px;margin:0 auto}
|
|
.card{background:#121933;border:1px solid #2a376b;border-radius:12px;padding:12px;margin-bottom:12px}
|
|
h1{margin:0 0 8px;font-size:24px} h2{margin:0 0 10px;font-size:17px}
|
|
.muted{color:#9aa6d1}
|
|
input,button,select{background:#0f1530;color:#e8ecff;border:1px solid #3a4a87;border-radius:8px;padding:8px}
|
|
.controls{display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end}
|
|
.controls label{display:flex;flex-direction:column;gap:6px;min-width:150px}
|
|
.grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
|
|
.table-wrap{overflow:auto;-webkit-overflow-scrolling:touch}
|
|
table{width:100%;border-collapse:collapse;font-size:13px;min-width:760px}
|
|
th,td{border-bottom:1px solid #24315f;padding:8px;text-align:left;vertical-align:top}
|
|
.pill{display:inline-flex;align-items:center;gap:6px;background:#1f2b56;border:1px solid #3a4a87;border-radius:999px;padding:4px 8px;margin:4px 6px 4px 0;font-size:12px}
|
|
.pill input{width:78px;padding:4px 6px}
|
|
.ok{color:#63db8f}.bad{color:#ff8b8b}
|
|
.chip{display:inline-block;padding:2px 8px;border-radius:999px;font-size:11px;background:#264a32;color:#9df5bc;border:1px solid #3f8b5b}
|
|
.small{font-size:12px}
|
|
@media (max-width: 980px){.grid{grid-template-columns:1fr}}
|
|
@media (max-width: 700px){
|
|
body{padding:10px}
|
|
.controls{flex-direction:column;align-items:stretch}
|
|
.controls label{width:100%;min-width:0}
|
|
button{width:100%}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="wrap">
|
|
<h1>Domain Hunter Panel</h1>
|
|
<p class="muted">Dynamicznie z DB: domeny z Mongo + status nowości w kolejnych skanach.</p>
|
|
|
|
<div class="card">
|
|
<h2>Filtr domen</h2>
|
|
<div class="controls">
|
|
<label>Szukaj <input id="q" placeholder="np. lead, ai, crm" /></label>
|
|
<label>TLD
|
|
<select id="tld"><option value="">Wszystkie</option><option>pl</option><option>com</option><option>ai</option></select>
|
|
</label>
|
|
<label class="small"><input type="checkbox" id="onlyNew" /> Tylko nowe domeny</label>
|
|
<label class="small"><input type="checkbox" id="autoRefresh" checked /> Auto-refresh 60s</label>
|
|
<button id="reload">Odśwież</button>
|
|
</div>
|
|
<p class="muted" id="meta"></p>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h2>TOP domen</h2>
|
|
<div class="table-wrap">
|
|
<table>
|
|
<thead><tr><th>Domena</th><th>TLD</th><th>Score</th><th>Status</th></tr></thead>
|
|
<tbody id="rows"></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let domains = [];
|
|
|
|
function money(v){ return (v===null || v===undefined || Number.isNaN(Number(v))) ? '—' : `${Number(v).toFixed(2)} zł`; }
|
|
|
|
function domainCheckUrl(domain){
|
|
const d = encodeURIComponent(domain);
|
|
return `https://www.whois.com/whois/${d}`;
|
|
}
|
|
|
|
async function loadDomains(){
|
|
const q = document.getElementById('q').value.trim();
|
|
const tld = document.getElementById('tld').value;
|
|
const onlyNew = document.getElementById('onlyNew').checked;
|
|
const u = new URL('./api.php', location.href);
|
|
u.searchParams.set('action','domains');
|
|
if(q) u.searchParams.set('q', q);
|
|
if(tld) u.searchParams.set('tld', tld);
|
|
if(onlyNew) u.searchParams.set('only_new', '1');
|
|
const d = await (await fetch(u)).json();
|
|
domains = d.domains || [];
|
|
document.getElementById('meta').textContent = `runId: ${d.meta?.runId||'—'} | prev: ${d.meta?.prevRunId||'—'} | scannedAt: ${d.meta?.scannedAt||'—'} | nowe: ${d.meta?.newCount||0} | widoczne: ${domains.length}`;
|
|
}
|
|
|
|
function renderRows(){
|
|
const rows = document.getElementById('rows');
|
|
rows.innerHTML='';
|
|
for(const d of domains.slice(0,300)){
|
|
const tr = document.createElement('tr');
|
|
const checkUrl = domainCheckUrl(d.domain);
|
|
tr.innerHTML = `<td><a href='${checkUrl}' target='_blank'><b>${d.domain}</b></a> ${d.is_new ? `<span class='chip'>NEW</span>` : ''}</td>
|
|
<td>.${d.tld}</td>
|
|
<td>${d.score}</td>
|
|
<td>${d.status || 'available'}</td>`;
|
|
rows.appendChild(tr);
|
|
}
|
|
}
|
|
|
|
async function refreshAll(){
|
|
await loadDomains();
|
|
renderRows();
|
|
}
|
|
|
|
let qTimer;
|
|
let autoTimer;
|
|
|
|
function setupAutoRefresh(){
|
|
if(autoTimer) clearInterval(autoTimer);
|
|
const enabled = document.getElementById('autoRefresh').checked;
|
|
if(enabled){
|
|
autoTimer = setInterval(async()=>{
|
|
await loadDomains();
|
|
renderRows();
|
|
}, 60000);
|
|
}
|
|
}
|
|
|
|
document.getElementById('reload').addEventListener('click', refreshAll);
|
|
document.getElementById('q').addEventListener('input', async()=>{
|
|
clearTimeout(qTimer);
|
|
qTimer = setTimeout(async()=>{ await loadDomains(); renderRows(); }, 250);
|
|
});
|
|
document.getElementById('tld').addEventListener('change', async()=>{await loadDomains(); renderRows();});
|
|
document.getElementById('onlyNew').addEventListener('change', async()=>{await loadDomains(); renderRows();});
|
|
document.getElementById('autoRefresh').addEventListener('change', setupAutoRefresh);
|
|
|
|
refreshAll();
|
|
setupAutoRefresh();
|
|
</script>
|
|
</body>
|
|
</html>
|