From 25757da3ac3f923dbe014a9dbb14c059d808a9ff Mon Sep 17 00:00:00 2001 From: TheOnlyMace <0815cracky@gmail.com> Date: Sun, 1 Feb 2026 15:52:11 +0100 Subject: [PATCH] Refactor index.php: Removed extensive inline CSS styles to improve maintainability and reduce file size. This change streamlines the code and enhances readability, setting the stage for future styling improvements. --- hexadns/assets/css/style.css | 769 +++++++++++++++++++++++++++++++++++ hexadns/assets/js/main.js | 373 +++++++++++++++++ hexadns/index.php | 379 +---------------- 3 files changed, 1145 insertions(+), 376 deletions(-) create mode 100644 hexadns/assets/css/style.css create mode 100644 hexadns/assets/js/main.js diff --git a/hexadns/assets/css/style.css b/hexadns/assets/css/style.css new file mode 100644 index 0000000..0cafeb0 --- /dev/null +++ b/hexadns/assets/css/style.css @@ -0,0 +1,769 @@ +/** + * HexaDNS.de - DNS Tools & Server Landing Page + * Stylesheet + */ + +* { margin: 0; padding: 0; box-sizing: border-box; } + +:root { + --bg-color: #0d0821; + --primary: #ff51f9; + --accent-1: #a348ff; + --accent-2: #3978ff; + --neon-blue: #00cfff; + --success: #32fba2; + --warning: #ffcc00; + --error: #ff4d6d; + --text: #ffffff; + --text-dim: #cfc9dd; + --glass-bg: rgba(255,255,255,0.05); + --glass-border: rgba(255,255,255,0.1); + --font: 'Inter', sans-serif; + --font-logo: 'Russo One', sans-serif; + --font-mono: 'JetBrains Mono', monospace; +} + +body { + font-family: var(--font); + line-height: 1.6; + color: var(--text); + background: var(--bg-color); + min-height: 100vh; + overflow-x: hidden; +} + +.glass { + background: var(--glass-bg); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + border: 1px solid var(--glass-border); + border-radius: 1rem; +} + +/* Header */ +.header { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 1000; + background: rgba(13,8,33,0.9); + backdrop-filter: blur(20px); + border-bottom: 1px solid var(--glass-border); +} + +.nav { + max-width: 1400px; + margin: 0 auto; + padding: 0 1.5rem; + display: flex; + align-items: center; + justify-content: space-between; + height: 70px; +} + +.nav-left { + display: flex; + align-items: center; + gap: 1.5rem; +} + +.logo { + font-family: var(--font-logo); + font-size: 1.5rem; + text-decoration: none; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.logo-icon { + width: 40px; + height: 40px; + color: var(--primary); +} + +.logo span { + background: linear-gradient(135deg, var(--primary), var(--neon-blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +.status-badge { + display: inline-flex; + align-items: center; + gap: 0.5rem; + background: rgba(50,251,162,0.1); + border: 1px solid rgba(50,251,162,0.3); + padding: 0.4rem 0.875rem; + border-radius: 2rem; + font-size: 0.8rem; + font-weight: 500; + color: var(--success); +} + +.status-dot { + width: 8px; + height: 8px; + background: var(--success); + border-radius: 50%; + animation: pulse 2s infinite; +} + +@keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.5; } +} + +.nav-link { + color: var(--text-dim); + text-decoration: none; + font-weight: 500; + padding: 0.5rem 1rem; + border-radius: 0.5rem; + transition: 0.3s; +} + +.nav-link:hover { + color: var(--text); + background: var(--glass-bg); +} + +/* Network Background */ +.network-bg { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: -1; +} + +/* Hero */ +.hero { + min-height: 70vh; + display: flex; + align-items: center; + justify-content: center; + padding: 120px 1.5rem 60px; + text-align: center; +} + +.hero-content { + max-width: 800px; +} + +.hero-icon { + width: 100px; + height: 100px; + margin: 0 auto 1.5rem; + color: var(--primary); + animation: float 3s ease-in-out infinite; +} + +@keyframes float { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-10px); } +} + +.hero h1 { + font-size: clamp(2rem, 5vw, 3.5rem); + font-weight: 700; + margin-bottom: 1rem; +} + +.highlight { + background: linear-gradient(135deg, var(--primary), var(--neon-blue)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} + +.hero p { + font-size: 1.1rem; + color: var(--text-dim); + margin-bottom: 2rem; +} + +/* Tools Section */ +.tools-section { + padding: 2rem 1.5rem 4rem; + max-width: 1400px; + margin: 0 auto; +} + +.section-title { + font-size: 1.75rem; + font-weight: 700; + text-align: center; + margin-bottom: 2rem; +} + +/* Tool Tabs */ +.tool-tabs { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + justify-content: center; + margin-bottom: 2rem; + padding: 0.5rem; + border-radius: 1rem; + background: rgba(0,0,0,0.2); +} + +.tool-tab { + padding: 0.75rem 1.25rem; + border: none; + background: transparent; + color: var(--text-dim); + font-family: var(--font); + font-size: 0.9rem; + font-weight: 500; + cursor: pointer; + border-radius: 0.75rem; + transition: 0.3s; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.tool-tab:hover { + color: var(--text); + background: var(--glass-bg); +} + +.tool-tab.active { + background: linear-gradient(135deg, var(--primary), var(--accent-1)); + color: var(--text); +} + +.tool-tab svg { + width: 18px; + height: 18px; +} + +/* Tool Panels */ +.tool-panel { + display: none; + animation: fadeIn 0.3s ease; +} + +.tool-panel.active { + display: block; +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(10px); } + to { opacity: 1; transform: translateY(0); } +} + +/* Tool Card */ +.tool-card { + padding: 2rem; + max-width: 900px; + margin: 0 auto; +} + +.tool-header { + text-align: center; + margin-bottom: 1.5rem; +} + +.tool-header h2 { + font-size: 1.5rem; + margin-bottom: 0.5rem; +} + +.tool-header p { + color: var(--text-dim); + font-size: 0.95rem; +} + +/* Input Group */ +.input-group { + display: flex; + gap: 1rem; + margin-bottom: 1.5rem; +} + +.input-group input, +.input-group select { + flex: 1; + padding: 0.875rem 1rem; + border: 1px solid var(--glass-border); + border-radius: 0.5rem; + background: rgba(255,255,255,0.05); + color: var(--text); + font-family: var(--font); + font-size: 1rem; + transition: 0.3s; +} + +.input-group input:focus, +.input-group select:focus { + outline: none; + border-color: var(--primary); + background: rgba(255,255,255,0.08); +} + +.input-group input::placeholder { + color: var(--text-dim); +} + +.input-group select { + min-width: 120px; + flex: 0; + cursor: pointer; +} + +.input-group select option { + background: var(--bg-color); +} + +.btn { + padding: 0.875rem 1.5rem; + background: linear-gradient(135deg, var(--primary), var(--accent-1)); + border: none; + border-radius: 0.5rem; + color: var(--text); + font-family: var(--font); + font-weight: 600; + cursor: pointer; + transition: 0.3s; + display: flex; + align-items: center; + gap: 0.5rem; + white-space: nowrap; +} + +.btn:hover { + transform: translateY(-2px); + box-shadow: 0 8px 25px rgba(255,81,249,0.4); +} + +.btn:disabled { + opacity: 0.6; + cursor: not-allowed; + transform: none; +} + +.btn svg { + width: 18px; + height: 18px; +} + +/* Results */ +.results { + background: rgba(0,0,0,0.3); + border-radius: 0.75rem; + padding: 1.25rem; + font-family: var(--font-mono); + font-size: 0.85rem; + min-height: 200px; + max-height: 500px; + overflow-y: auto; +} + +.results::-webkit-scrollbar { + width: 6px; +} + +.results::-webkit-scrollbar-track { + background: rgba(255,255,255,0.05); + border-radius: 3px; +} + +.results::-webkit-scrollbar-thumb { + background: var(--primary); + border-radius: 3px; +} + +.line { + padding: 0.2rem 0; + animation: typeLine 0.2s ease forwards; +} + +@keyframes typeLine { + from { opacity: 0; transform: translateX(-5px); } + to { opacity: 1; transform: translateX(0); } +} + +.line.comment { color: var(--text-dim); } +.line.header { color: var(--primary); font-weight: 600; } +.line.record { color: var(--neon-blue); } +.line.success { color: var(--success); } +.line.warning { color: var(--warning); } +.line.error { color: var(--error); } +.line.info { color: var(--text-dim); } + +/* Propagation Grid */ +.prop-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 1rem; + margin-top: 1rem; +} + +.prop-card { + padding: 1rem; + border-radius: 0.75rem; + background: rgba(255,255,255,0.03); + border: 1px solid var(--glass-border); +} + +.prop-card-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 0.75rem; +} + +.prop-card-header h4 { + font-size: 0.95rem; + font-weight: 600; +} + +.prop-status { + width: 10px; + height: 10px; + border-radius: 50%; +} + +.prop-status.online { background: var(--success); } +.prop-status.offline { background: var(--error); } + +.prop-card-info { + font-size: 0.8rem; + color: var(--text-dim); + margin-bottom: 0.5rem; +} + +.prop-card-result { + font-family: var(--font-mono); + font-size: 0.85rem; + color: var(--neon-blue); + word-break: break-all; +} + +.prop-card-time { + font-size: 0.75rem; + color: var(--text-dim); + margin-top: 0.5rem; +} + +/* Progress Bar */ +.progress-bar { + height: 6px; + background: rgba(255,255,255,0.1); + border-radius: 3px; + overflow: hidden; + margin: 1rem 0; +} + +.progress-fill { + height: 100%; + background: linear-gradient(90deg, var(--primary), var(--neon-blue)); + border-radius: 3px; + transition: width 0.3s; +} + +/* SSL/WHOIS Cards */ +.info-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1rem; + margin-top: 1rem; +} + +.info-card { + padding: 1.25rem; + border-radius: 0.75rem; + background: rgba(255,255,255,0.03); + border: 1px solid var(--glass-border); +} + +.info-card h4 { + font-size: 0.8rem; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--primary); + margin-bottom: 0.5rem; +} + +.info-card p { + font-size: 0.95rem; + color: var(--text); + word-break: break-all; +} + +.info-card.success { border-color: rgba(50,251,162,0.3); } +.info-card.warning { border-color: rgba(255,204,0,0.3); } +.info-card.error { border-color: rgba(255,77,109,0.3); } + +/* DNS Explanation Section */ +.dns-explain { + padding: 4rem 1.5rem; + background: rgba(255,255,255,0.02); +} + +.dns-explain-container { + max-width: 1200px; + margin: 0 auto; +} + +.record-types { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 1.5rem; + margin-top: 2rem; +} + +.record-type { + padding: 1.5rem; + transition: transform 0.3s, box-shadow 0.3s; +} + +.record-type:hover { + transform: translateY(-3px); + box-shadow: 0 10px 30px rgba(255,81,249,0.2); +} + +.record-type-header { + display: flex; + align-items: center; + gap: 0.75rem; + margin-bottom: 1rem; +} + +.record-type-badge { + padding: 0.25rem 0.75rem; + background: linear-gradient(135deg, var(--primary), var(--accent-1)); + border-radius: 0.5rem; + font-family: var(--font-mono); + font-size: 0.85rem; + font-weight: 600; +} + +.record-type h3 { + font-size: 1.1rem; + font-weight: 600; +} + +.record-type p { + color: var(--text-dim); + font-size: 0.9rem; + line-height: 1.6; +} + +.record-type code { + background: rgba(0,207,255,0.1); + color: var(--neon-blue); + padding: 0.1rem 0.4rem; + border-radius: 0.25rem; + font-family: var(--font-mono); + font-size: 0.85rem; +} + +/* DNS Flow Animation */ +.dns-flow { + margin-top: 3rem; + padding: 2rem; + text-align: center; +} + +.dns-flow h3 { + margin-bottom: 2rem; + font-size: 1.25rem; +} + +.flow-container { + display: flex; + align-items: center; + justify-content: center; + gap: 1rem; + flex-wrap: wrap; + padding: 2rem 0; +} + +.flow-step { + padding: 1rem 1.5rem; + border-radius: 0.75rem; + background: var(--glass-bg); + border: 1px solid var(--glass-border); + min-width: 120px; + text-align: center; + position: relative; +} + +.flow-step-num { + position: absolute; + top: -10px; + left: 50%; + transform: translateX(-50%); + width: 24px; + height: 24px; + background: var(--primary); + border-radius: 50%; + font-size: 0.75rem; + font-weight: 700; + display: flex; + align-items: center; + justify-content: center; +} + +.flow-step-icon { + width: 32px; + height: 32px; + margin: 0 auto 0.5rem; + color: var(--neon-blue); +} + +.flow-step p { + font-size: 0.85rem; + color: var(--text-dim); +} + +.flow-step strong { + display: block; + margin-bottom: 0.25rem; + color: var(--text); +} + +.flow-arrow { + color: var(--primary); + font-size: 1.5rem; +} + +/* Features Section */ +.features { + padding: 4rem 1.5rem; + max-width: 1200px; + margin: 0 auto; +} + +.features-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1.5rem; +} + +.feature { + padding: 1.5rem; + text-align: center; + transition: transform 0.3s; +} + +.feature:hover { + transform: translateY(-5px); +} + +.feature-icon { + width: 48px; + height: 48px; + margin: 0 auto 1rem; + color: var(--primary); +} + +.feature h3 { + font-size: 1.1rem; + margin-bottom: 0.5rem; +} + +.feature p { + color: var(--text-dim); + font-size: 0.9rem; +} + +/* DNS Server Info */ +.dns-servers { + padding: 4rem 1.5rem; + background: rgba(255,255,255,0.02); +} + +.dns-servers-container { + max-width: 800px; + margin: 0 auto; + text-align: center; +} + +.server-cards { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 1.5rem; + margin-top: 2rem; +} + +.server-card { + padding: 1.5rem; + text-align: center; +} + +.server-card h4 { + color: var(--primary); + font-size: 0.8rem; + text-transform: uppercase; + letter-spacing: 0.1em; + margin-bottom: 0.75rem; +} + +.server-name { + font-family: var(--font-mono); + font-size: 1rem; + color: var(--neon-blue); + background: rgba(0,207,255,0.1); + padding: 0.5rem 1rem; + border-radius: 0.5rem; + display: inline-block; +} + +/* Footer */ +.footer { + padding: 3rem 1.5rem 2rem; + text-align: center; + border-top: 1px solid var(--glass-border); + margin-top: 4rem; +} + +.footer p { + color: var(--text-dim); + font-size: 0.875rem; + margin-bottom: 1rem; +} + +.footer-links { + display: flex; + justify-content: center; + gap: 2rem; + flex-wrap: wrap; +} + +.footer-links a { + color: var(--text-dim); + text-decoration: none; + font-size: 0.875rem; + transition: 0.3s; +} + +.footer-links a:hover { + color: var(--primary); +} + +/* Responsive */ +@media (max-width: 768px) { + .nav-left .status-badge { display: none; } + .input-group { flex-direction: column; } + .input-group select { min-width: 100%; } + .btn { width: 100%; justify-content: center; } + .tool-tabs { gap: 0.25rem; } + .tool-tab { padding: 0.6rem 0.8rem; font-size: 0.8rem; } + .tool-tab span { display: none; } + .flow-container { flex-direction: column; } + .flow-arrow { transform: rotate(90deg); } + .footer-links { flex-direction: column; gap: 1rem; } +} + +@keyframes spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} diff --git a/hexadns/assets/js/main.js b/hexadns/assets/js/main.js new file mode 100644 index 0000000..a4125b9 --- /dev/null +++ b/hexadns/assets/js/main.js @@ -0,0 +1,373 @@ +/** + * HexaDNS.de - DNS Tools & Server Landing Page + * Main JavaScript + */ + +// API Base URL (wird über data-attribute im HTML gesetzt) +const API = document.body.dataset.api || '/api'; + +// Tab Switching +document.querySelectorAll('.tool-tab').forEach(tab => { + tab.addEventListener('click', () => { + document.querySelectorAll('.tool-tab').forEach(t => t.classList.remove('active')); + document.querySelectorAll('.tool-panel').forEach(p => p.classList.remove('active')); + tab.classList.add('active'); + document.getElementById('panel-' + tab.dataset.tool).classList.add('active'); + }); +}); + +// Enter key handlers +['dns-domain', 'prop-domain', 'whois-domain', 'ssl-domain', 'ping-domain', 'reverse-ip'].forEach(id => { + const el = document.getElementById(id); + if (el) { + el.addEventListener('keypress', e => { + if (e.key === 'Enter') { + el.closest('.tool-card').querySelector('.btn').click(); + } + }); + } +}); + +// DNS Lookup +async function dnsLookup() { + const domain = document.getElementById('dns-domain').value.trim(); + const results = document.getElementById('dns-results'); + + if (!domain) { + results.innerHTML = '
Bitte Domain eingeben
WHOIS-Daten werden abgefragt...
${data.error}
${p.domain_name}
${p.registrar}
${p.creation_date}
${p.expiration_date}
${p.updated_date}
${p.nameservers.join('
')}
${p.dnssec}
${data.whois.raw.replace(/`;
+ } catch (e) {
+ results.innerHTML = `Fehler
${e.message}
`;
+ }
+}
+
+// SSL Check
+async function sslCheck() {
+ const domain = document.getElementById('ssl-domain').value.trim();
+ const results = document.getElementById('ssl-results');
+
+ if (!domain) {
+ results.innerHTML = 'Fehler
Bitte Domain eingeben
';
+ return;
+ }
+
+ results.innerHTML = 'Laden...
SSL-Zertifikat wird geprüft...
';
+
+ try {
+ const res = await fetch(`${API}/ssl-check.php?domain=${encodeURIComponent(domain)}`);
+ const data = await res.json();
+ const ssl = data.ssl;
+
+ if (!ssl.has_ssl) {
+ results.innerHTML = `Kein SSL
${ssl.error || 'Kein SSL-Zertifikat gefunden'}
`;
+ return;
+ }
+
+ const cert = ssl.certificate;
+ const statusClass = ssl.is_valid ? (cert.days_until_expiry <= 30 ? 'warning' : 'success') : 'error';
+
+ results.innerHTML = `
+ Status
${ssl.is_valid ? (cert.is_expired ? '❌ Abgelaufen' : '✅ Gültig') : '❌ Ungültig'}
+ Domain
${cert.subject?.common_name || domain}
+ Aussteller
${cert.issuer?.organization || cert.issuer?.common_name || '-'}
+ Gültig ab
${cert.valid_from}
+ Gültig bis
${cert.valid_to}
${cert.days_until_expiry} Tage verbleibend
+ Algorithmus
${cert.signature_algorithm || '-'}
+ ${cert.san_domains?.length ? `Alternative Namen
${cert.san_domains.slice(0,5).join('
')}${cert.san_domains.length > 5 ? `
+${cert.san_domains.length-5} weitere` : ''}
` : ''}
+ `;
+ } catch (e) {
+ results.innerHTML = `Fehler
${e.message}
`;
+ }
+}
+
+// Ping Check
+async function pingCheck() {
+ const domain = document.getElementById('ping-domain').value.trim();
+ const results = document.getElementById('ping-results');
+
+ if (!domain) {
+ results.innerHTML = 'Fehler
Bitte Domain eingeben
';
+ return;
+ }
+
+ results.innerHTML = 'Laden...
Verfügbarkeit wird geprüft...
';
+
+ try {
+ const res = await fetch(`${API}/ping-check.php?domain=${encodeURIComponent(domain)}`);
+ const data = await res.json();
+ const r = data.results;
+
+ const statusColors = { online: 'success', partial: 'warning', dns_only: 'warning', offline: 'error' };
+ const statusText = { online: '✅ Online', partial: '⚠️ Teilweise erreichbar', dns_only: '⚠️ Nur DNS', offline: '❌ Offline' };
+
+ results.innerHTML = `
+ Status
${statusText[r.overall_status]}
+ DNS
${r.dns_resolution.resolved ? `✅ ${r.dns_resolution.ip}` : '❌ Nicht auflösbar'}
${r.dns_resolution.response_time_ms}ms
+ HTTPS (443)
${r.https.reachable ? `✅ Status ${r.https.status_code}` : '❌ Nicht erreichbar'}
${r.https.response_time_ms}ms
+ HTTP (80)
${r.http.reachable ? `✅ Status ${r.http.status_code}` : '❌ Nicht erreichbar'}
${r.http.response_time_ms}ms
+ ICMP Ping
${r.icmp_ping.reachable ? `✅ ${r.icmp_ping.response_time_ms}ms` : '⚠️ Nicht verfügbar'}
Packet Loss: ${r.icmp_ping.packet_loss ?? '-'}%
+ ${r.https.server ? `Server
${r.https.server}
` : ''}
+ `;
+ } catch (e) {
+ results.innerHTML = `Fehler
${e.message}
`;
+ }
+}
+
+// Reverse DNS
+async function reverseLookup() {
+ const ip = document.getElementById('reverse-ip').value.trim();
+ const results = document.getElementById('reverse-results');
+
+ if (!ip) {
+ results.innerHTML = 'Fehler
Bitte IP-Adresse eingeben
';
+ return;
+ }
+
+ results.innerHTML = 'Laden...
Reverse Lookup wird durchgeführt...
';
+
+ try {
+ const res = await fetch(`${API}/reverse-dns.php?ip=${encodeURIComponent(ip)}`);
+ const data = await res.json();
+
+ if (data.error) {
+ results.innerHTML = `Fehler
${data.error}
`;
+ return;
+ }
+
+ const r = data.result;
+ results.innerHTML = `
+ IP-Adresse
${data.ip}
${data.ip_version}
+ Hostname
${r.hostname || 'Kein PTR-Record gefunden'}
+ ${r.forward_verified !== undefined ? `Forward-Check
${r.forward_verified ? '✅ Verifiziert' : '⚠️ Nicht verifiziert'}
` : ''}
+ IP-Typ
${r.ip_info?.type || '-'}
+ ${r.additional_info?.provider ? `Provider
${r.additional_info.provider}
` : ''}
+ `;
+ } catch (e) {
+ results.innerHTML = `Fehler
${e.message}
`;
+ }
+}
+
+// Network Animation
+(function() {
+ const canvas = document.getElementById('networkCanvas');
+ if (!canvas) return;
+
+ const ctx = canvas.getContext('2d');
+ let width, height, particles = [];
+ const particleCount = 40;
+
+ function init() {
+ resize();
+ particles = [];
+ for (let i = 0; i < particleCount; i++) {
+ particles.push({
+ x: Math.random() * width,
+ y: Math.random() * height,
+ vx: (Math.random() - 0.5) * 0.3,
+ vy: (Math.random() - 0.5) * 0.3,
+ r: Math.random() * 2 + 1
+ });
+ }
+ }
+
+ function resize() {
+ width = canvas.width = window.innerWidth;
+ height = canvas.height = window.innerHeight;
+ }
+
+ function animate() {
+ ctx.clearRect(0, 0, width, height);
+
+ particles.forEach((p, i) => {
+ p.x += p.vx;
+ p.y += p.vy;
+
+ if (p.x < 0 || p.x > width) p.vx *= -1;
+ if (p.y < 0 || p.y > height) p.vy *= -1;
+
+ ctx.beginPath();
+ ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
+ ctx.fillStyle = 'rgba(255,81,249,0.4)';
+ ctx.fill();
+
+ for (let j = i + 1; j < particles.length; j++) {
+ const p2 = particles[j];
+ const dx = p.x - p2.x;
+ const dy = p.y - p2.y;
+ const dist = Math.sqrt(dx * dx + dy * dy);
+
+ if (dist < 120) {
+ ctx.beginPath();
+ ctx.moveTo(p.x, p.y);
+ ctx.lineTo(p2.x, p2.y);
+ ctx.strokeStyle = `rgba(0,207,255,${(1 - dist / 120) * 0.2})`;
+ ctx.stroke();
+ }
+ }
+ });
+
+ requestAnimationFrame(animate);
+ }
+
+ window.addEventListener('resize', resize);
+ init();
+ animate();
+})();
diff --git a/hexadns/index.php b/hexadns/index.php
index 1c7d0a8..c1db60c 100644
--- a/hexadns/index.php
+++ b/hexadns/index.php
@@ -26,192 +26,9 @@ $api_base = '/api';
-
+
-
+
@@ -457,196 +274,6 @@ $api_base = '/api';
-
+