192 lines
No EOL
8.5 KiB
HTML
192 lines
No EOL
8.5 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>{{ server_type }} Dashboard</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
<style>
|
|
body {
|
|
background-color: #0f0f0f;
|
|
background-image:
|
|
radial-gradient(circle at 25% 25%, rgba(40, 40, 40, 0.05) 0%, transparent 50%),
|
|
radial-gradient(circle at 75% 75%, rgba(40, 40, 40, 0.05) 0%, transparent 50%);
|
|
}
|
|
|
|
/* Subtle grid pattern */
|
|
.bg-grid {
|
|
background-size: 50px 50px;
|
|
background-image:
|
|
linear-gradient(to right, rgba(40, 40, 40, 0.05) 1px, transparent 1px),
|
|
linear-gradient(to bottom, rgba(40, 40, 40, 0.05) 1px, transparent 1px);
|
|
}
|
|
|
|
.card {
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.card:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
|
|
}
|
|
|
|
.search-popup {
|
|
opacity: 0;
|
|
visibility: hidden;
|
|
transition: opacity 0.15s ease, visibility 0.15s;
|
|
}
|
|
|
|
.search-popup.active {
|
|
opacity: 1;
|
|
visibility: visible;
|
|
}
|
|
</style>
|
|
<script>
|
|
function toggleSearch() {
|
|
let searchContainer = document.getElementById("search-container");
|
|
searchContainer.classList.toggle("active");
|
|
if (searchContainer.classList.contains("active")) {
|
|
document.getElementById("search-box").focus();
|
|
}
|
|
}
|
|
|
|
function filterEntries() {
|
|
let query = document.getElementById("search-box").value.toLowerCase();
|
|
let cards = document.querySelectorAll(".domain-card");
|
|
cards.forEach(card => {
|
|
let domain = card.dataset.domain.toLowerCase();
|
|
card.style.display = domain.includes(query) ? "" : "none";
|
|
});
|
|
}
|
|
|
|
function deleteServer(serverName) {
|
|
if (confirm(`Möchten Sie den Server "${serverName}" wirklich löschen?`)) {
|
|
fetch('/delete', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ "server": serverName })
|
|
}).then(response => {
|
|
if (response.ok) {
|
|
const serverBox = document.getElementById("server-box-" + serverName);
|
|
serverBox.classList.add('opacity-0');
|
|
setTimeout(() => {
|
|
serverBox.remove();
|
|
}, 300);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
document.addEventListener("keydown", function (event) {
|
|
if (event.key === "/" && !event.ctrlKey && !event.metaKey) {
|
|
event.preventDefault();
|
|
toggleSearch();
|
|
}
|
|
if (event.key === "Escape") {
|
|
let searchContainer = document.getElementById("search-container");
|
|
if (searchContainer.classList.contains("active")) {
|
|
toggleSearch();
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
</head>
|
|
|
|
<body class="text-gray-200 min-h-screen bg-grid">
|
|
<!-- Minimal header -->
|
|
<header class="py-4 px-6 bg-black/50 backdrop-blur-sm border-b border-gray-800/50">
|
|
<div class="container mx-auto flex justify-between items-center">
|
|
<div class="flex items-center">
|
|
<a href="/" class="text-gray-400 hover:text-white mr-3">
|
|
<i class="fas fa-home"></i>
|
|
</a>
|
|
<h1 class="text-xl font-medium tracking-tight text-white">
|
|
{{ server_type }} Dashboard
|
|
</h1>
|
|
</div>
|
|
<div class="flex items-center gap-3">
|
|
<a href="/caddy"
|
|
class="text-sm px-3 py-1.5 {% if server_type == 'Caddy' %}bg-blue-900/50 border-blue-700/50{% else %}bg-zinc-800 border-zinc-700{% endif %} hover:bg-zinc-700 border rounded-md transition-colors">
|
|
<i class="fas fa-server text-xs mr-1.5"></i>Caddy
|
|
</a>
|
|
<a href="/nginx"
|
|
class="text-sm px-3 py-1.5 {% if server_type == 'Nginx' %}bg-green-900/50 border-green-700/50{% else %}bg-zinc-800 border-zinc-700{% endif %} hover:bg-zinc-700 border rounded-md transition-colors">
|
|
<i class="fas fa-server text-xs mr-1.5"></i>Nginx
|
|
</a>
|
|
<button onclick="toggleSearch()" class="text-sm px-3 py-1.5 bg-zinc-800 hover:bg-zinc-700 border border-zinc-700 rounded-md
|
|
transition-colors flex items-center gap-2">
|
|
<i class="fas fa-search text-xs"></i>
|
|
<span class="hidden sm:inline">/</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Search popup -->
|
|
<div id="search-container"
|
|
class="search-popup fixed inset-0 z-50 flex items-start justify-center pt-20 px-4 bg-black/50 backdrop-blur-sm">
|
|
<div class="w-full max-w-xl bg-zinc-900 border border-zinc-800 rounded-lg overflow-hidden shadow-2xl">
|
|
<div class="flex items-center px-4 border-b border-zinc-800">
|
|
<i class="fas fa-search text-gray-500 mr-3"></i>
|
|
<input type="text" id="search-box"
|
|
class="w-full py-3 bg-transparent text-white border-none focus:outline-none"
|
|
placeholder="Domain suchen..." onkeyup="filterEntries()">
|
|
<button onclick="toggleSearch()" class="text-gray-500 hover:text-white">
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
<div class="p-2 text-xs text-gray-500">
|
|
Drücke <kbd class="px-1.5 py-0.5 bg-zinc-800 rounded border border-zinc-700">/</kbd> zum Öffnen, <kbd
|
|
class="px-1.5 py-0.5 bg-zinc-800 rounded border border-zinc-700">ESC</kbd> zum Schließen
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="container mx-auto p-4 md:p-6">
|
|
{% for server, entries in proxies.items() %}
|
|
<div id="server-box-{{ server }}" class="mb-8 opacity-100 transition-opacity duration-300">
|
|
<div class="flex justify-between items-center mb-4 px-1">
|
|
<div>
|
|
<h2 class="text-lg font-medium text-white">{{ server }}</h2>
|
|
<p class="text-xs text-gray-500 mt-0.5">Zuletzt aktualisiert: {{ timestamps[server] }}</p>
|
|
</div>
|
|
<button onclick="deleteServer('{{ server }}')" class="text-xs px-3 py-1.5 bg-zinc-900 hover:bg-red-900/70 border border-zinc-800 hover:border-red-800/50 text-gray-400 hover:text-white rounded
|
|
transition-colors">
|
|
<i class="fas fa-trash-alt mr-1.5"></i>Löschen
|
|
</button>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
|
{% for domain, target in entries.items() %}
|
|
<div class="domain-card card bg-zinc-900 border border-zinc-800 rounded-lg overflow-hidden"
|
|
data-domain="{{ domain }}">
|
|
<div class="px-4 py-3 flex justify-between items-center border-b border-zinc-800">
|
|
<a href="https://{{ domain }}" target="_blank"
|
|
class="text-white hover:text-blue-400 text-sm font-medium truncate transition-colors flex items-center gap-2 max-w-[calc(100%-24px)]">
|
|
<i class="fas fa-globe text-xs text-gray-500"></i>
|
|
<span class="truncate">{{ domain }}</span>
|
|
</a>
|
|
<div class="ml-2 flex-shrink-0">
|
|
<div class="w-2 h-2 bg-green-500 rounded-full"></div>
|
|
</div>
|
|
</div>
|
|
<div class="px-4 py-2.5">
|
|
<p class="text-gray-400 text-xs font-mono truncate">{{ target }}</p>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<footer class="py-4 mt-12 border-t border-zinc-900">
|
|
<div class="container mx-auto px-4 text-center text-xs text-gray-600">
|
|
Caddy Dashboard
|
|
</div>
|
|
</footer>
|
|
</body>
|
|
|
|
</html> |