remove placeholder sentry and add mobil menu

This commit is contained in:
2026-04-27 12:04:34 +02:00
parent a42f1b87e9
commit 10deecfb35
5 changed files with 82 additions and 60 deletions
+4 -41
View File
@@ -5,22 +5,14 @@ const Sentry = require("@sentry/node");
// Initialize Sentry BEFORE requiring any other modules! // Initialize Sentry BEFORE requiring any other modules!
Sentry.init({ Sentry.init({
// DSN should now be available from process.env if set in .env dsn: process.env.SENTRY_DSN,
dsn: process.env.SENTRY_DSN || "https://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@oooooooooooooooo.ingest.sentry.io/123456",
// Enable tracing - Adjust sample rate as needed
tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0, tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0,
integrations: [ integrations: [
// send console.log, console.warn, and console.error calls as logs to Sentry Sentry.consoleLoggingIntegration({ levels: ["warn", "error"] }),
Sentry.consoleLoggingIntegration({ levels: ["log", "warn", "error"] }),
], ],
// Enable logs to be sent to Sentry
enableLogs: true, enableLogs: true,
}); });
// DEBUG: Check Sentry object after init
console.log("Sentry object after init:", typeof Sentry, Sentry ? Object.keys(Sentry) : 'Sentry is undefined/null');
// --- Ende Sentry Initialisierung ---
// Require necessary core modules AFTER Sentry is initialized // Require necessary core modules AFTER Sentry is initialized
const express = require('express'); const express = require('express');
@@ -53,20 +45,6 @@ const logger = pino({
const app = express(); const app = express();
const PORT = process.env.PORT || 3000; const PORT = process.env.PORT || 3000;
// --- Sentry Middleware (Request Handler & Tracing) ---
// Must be the first middleware
if (Sentry.Handlers && Sentry.Handlers.requestHandler) {
app.use(Sentry.Handlers.requestHandler());
} else {
logger.error("Sentry.Handlers.requestHandler is not available!");
}
// Must be after requestHandler, before routes
if (Sentry.Handlers && Sentry.Handlers.tracingHandler) {
app.use(Sentry.Handlers.tracingHandler());
} else {
logger.error("Sentry.Handlers.tracingHandler is not available!");
}
// --- Ende Sentry Middleware ---
// --- Core Middleware --- // --- Core Middleware ---
@@ -112,23 +90,8 @@ app.use('/api/mac-lookup', macLookupRoutes);
app.use('/api/asn-lookup', asnLookupRoutes); app.use('/api/asn-lookup', asnLookupRoutes);
// --- Sentry Error Handler --- // Sentry error handler — must be after routes, before custom error handler
// Must be AFTER all controllers and BEFORE any other error handling middleware Sentry.setupExpressErrorHandler(app);
if (Sentry.Handlers && Sentry.Handlers.errorHandler) {
app.use(Sentry.Handlers.errorHandler({
shouldHandleError(error) {
// Capture all 500 errors
if (error.status === 500) return true;
// Capture specific client errors if needed, e.g., 403
// if (error.status === 403) return true;
// By default, capture only server errors (5xx)
return error.status >= 500;
},
}));
} else {
logger.error("Sentry.Handlers.errorHandler is not available!");
}
// --- Ende Sentry Error Handler ---
// --- Fallback Error Handler --- // --- Fallback Error Handler ---
+7 -1
View File
@@ -4,6 +4,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>uTools Network Suite</title> <title>uTools Network Suite</title>
<link rel="icon" href="https://mrunk.de/pic/favicon/favicon.svg" type="image/svg+xml">
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""> integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="">
@@ -12,10 +13,15 @@
<body class="bg-gray-950 text-gray-100 font-sans p-4 md:p-8 min-h-screen bg-[url('https://tailwindcss.com/_next/static/media/hero-dark.939eb757.png')] bg-cover bg-center bg-fixed selection:bg-purple-500 selection:text-white"> <body class="bg-gray-950 text-gray-100 font-sans p-4 md:p-8 min-h-screen bg-[url('https://tailwindcss.com/_next/static/media/hero-dark.939eb757.png')] bg-cover bg-center bg-fixed selection:bg-purple-500 selection:text-white">
<header class="glass-panel"> <header class="glass-panel">
<div class="header-top">
<h1 style="background:linear-gradient(to right,#c084fc,#e879f9);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent" class="text-2xl font-bold"> <h1 style="background:linear-gradient(to right,#c084fc,#e879f9);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent" class="text-2xl font-bold">
uTools <span style="-webkit-text-fill-color:#9ca3af" class="text-sm font-normal tracking-wider uppercase ml-2">Network Suite</span> uTools <span style="-webkit-text-fill-color:#9ca3af" class="text-sm font-normal tracking-wider uppercase ml-2">Network Suite</span>
</h1> </h1>
<nav> <button id="nav-toggle" class="nav-toggle" aria-label="Toggle navigation" aria-expanded="false">
<span></span><span></span><span></span>
</button>
</div>
<nav id="main-nav">
<ul> <ul>
<li><a href="/">IP Info &amp; Tools</a></li> <li><a href="/">IP Info &amp; Tools</a></li>
<li><a href="/subnet">Subnetz Rechner</a></li> <li><a href="/subnet">Subnetz Rechner</a></li>
+6 -10
View File
@@ -421,18 +421,14 @@ export const page = {
let ipToLookup = query; let ipToLookup = query;
if (!isValidIp(query)) { if (!isValidIp(query)) {
try { try {
const r = await fetch(`${API}/dns-lookup?domain=${encodeURIComponent(query)}&type=A`); const r = await fetch(`${API}/dns-lookup?domain=${encodeURIComponent(query)}&type=ANY`);
const data = await r.json(); const data = await r.json();
if (r.ok && data.success && data.records?.length) { if (r.ok && data.success) {
ipToLookup = Array.isArray(data.records) ? data.records[0] : data.records; const ip = data.records?.A?.[0] ?? data.records?.AAAA?.[0];
if (ip) ipToLookup = ip;
else throw new Error('No A or AAAA records found.');
} else { } else {
const r2 = await fetch(`${API}/dns-lookup?domain=${encodeURIComponent(query)}&type=AAAA`); throw new Error(data.error || 'DNS lookup failed.');
const data2 = await r2.json();
if (r2.ok && data2.success && data2.records?.length) {
ipToLookup = Array.isArray(data2.records) ? data2.records[0] : data2.records;
} else {
throw new Error(data.error || 'No A or AAAA records found.');
}
} }
} catch (err) { } catch (err) {
lookupErrorEl.textContent = `Error: Could not resolve domain — ${err.message}`; lookupErrorEl.textContent = `Error: Could not resolve domain — ${err.message}`;
+13
View File
@@ -15,8 +15,18 @@ const routes = {
}; };
const app = document.getElementById('app'); const app = document.getElementById('app');
const header = document.querySelector('header');
let currentCleanup = null; let currentCleanup = null;
// ── Hamburger toggle ─────────────────────────────────────────────
const navToggle = document.getElementById('nav-toggle');
if (navToggle) {
navToggle.addEventListener('click', () => {
const open = header.classList.toggle('nav-open');
navToggle.setAttribute('aria-expanded', open);
});
}
function setActiveNav(path) { function setActiveNav(path) {
document.querySelectorAll('nav a').forEach(a => { document.querySelectorAll('nav a').forEach(a => {
try { try {
@@ -29,6 +39,9 @@ function setActiveNav(path) {
async function navigate(path, { push = true, search = '' } = {}) { async function navigate(path, { push = true, search = '' } = {}) {
const route = routes[path] ?? routes['/']; const route = routes[path] ?? routes['/'];
// ── close mobile nav on navigate ────────────────────────────
if (header) { header.classList.remove('nav-open'); navToggle?.setAttribute('aria-expanded', 'false'); }
// ── leave animation ────────────────────────────────────────── // ── leave animation ──────────────────────────────────────────
app.classList.add('page-leaving'); app.classList.add('page-leaving');
if (currentCleanup) { try { currentCleanup(); } catch {} currentCleanup = null; } if (currentCleanup) { try { currentCleanup(); } catch {} currentCleanup = null; }
+49 -5
View File
@@ -109,15 +109,59 @@ header {
border: 1px solid rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.05);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; gap: 0;
gap: 1rem;
box-shadow: 0 4px 6px -1px rgba(0,0,0,.1), 0 2px 4px -1px rgba(0,0,0,.06); box-shadow: 0 4px 6px -1px rgba(0,0,0,.1), 0 2px 4px -1px rgba(0,0,0,.06);
} }
@media (min-width: 768px) {
header { flex-direction: row; justify-content: space-between; }
}
header h1 { background-clip: text; } header h1 { background-clip: text; }
/* ── Header top row (title + hamburger) ────────────────────────── */
.header-top {
display: flex;
justify-content: space-between;
align-items: center;
}
/* ── Hamburger button ──────────────────────────────────────────── */
.nav-toggle {
display: flex;
flex-direction: column;
justify-content: center;
gap: 5px;
background: none;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 6px;
padding: 8px 10px;
cursor: pointer;
}
.nav-toggle span {
display: block;
width: 22px;
height: 2px;
background: #d1d5db;
border-radius: 2px;
transition: transform 0.25s ease, opacity 0.2s ease;
}
header.nav-open .nav-toggle span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
header.nav-open .nav-toggle span:nth-child(2) { opacity: 0; transform: scaleX(0); }
header.nav-open .nav-toggle span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
/* ── Mobile nav ────────────────────────────────────────────────── */
#main-nav {
display: none;
padding-top: 1rem;
margin-top: 1rem;
border-top: 1px solid rgba(255, 255, 255, 0.06);
}
header.nav-open #main-nav { display: block; }
/* ── Desktop nav ───────────────────────────────────────────────── */
@media (min-width: 768px) {
header { flex-direction: row; align-items: center; gap: 1rem; }
.header-top { flex: 0 0 auto; }
.nav-toggle { display: none; }
#main-nav { display: block !important; padding-top: 0; margin-top: 0; border-top: none; }
}
/* ── Text gradient ─────────────────────────────────────────────── */ /* ── Text gradient ─────────────────────────────────────────────── */
.text-gradient { .text-gradient {
background: linear-gradient(to right, #c084fc, #e879f9); background: linear-gradient(to right, #c084fc, #e879f9);