minecraft-server-status.php aktualisiert

This commit is contained in:
2025-11-23 15:49:47 +00:00
parent 392fd7217c
commit 26667adc10

View File

@@ -3,7 +3,7 @@
* Plugin Name: Minecraft Server Status Multi-Server Edition * Plugin Name: Minecraft Server Status Multi-Server Edition
* Description: Die ultimative Live-Status-Anzeige für deine Minecraft Server mit Echtzeit-Updates für beliebig viele Server. * Description: Die ultimative Live-Status-Anzeige für deine Minecraft Server mit Echtzeit-Updates für beliebig viele Server.
* Tags: minecraft, server status, player list, multi-server, rcon, luckperms, widget, shortcode, gaming, customizable, live, ping, maintenance, gameserver * Tags: minecraft, server status, player list, multi-server, rcon, luckperms, widget, shortcode, gaming, customizable, live, ping, maintenance, gameserver
* Version: 2.0.1 * Version: 2.0.5
* Author: M_Viper * Author: M_Viper
* Plugin URI: https://git.viper.ipv64.net/M_Viper/Minecraft-Server-Status * Plugin URI: https://git.viper.ipv64.net/M_Viper/Minecraft-Server-Status
* Author URI: https://m-viper.de * Author URI: https://m-viper.de
@@ -29,7 +29,9 @@ add_action('admin_enqueue_scripts', function($hook){
wp_enqueue_media(); wp_enqueue_media();
wp_enqueue_style('wp-color-picker'); wp_enqueue_style('wp-color-picker');
wp_enqueue_script('wp-color-picker'); wp_enqueue_script('wp-color-picker');
wp_enqueue_script('mcss-admin-js', MCSS_URL . 'js/admin.js', ['jquery', 'wp-color-picker'], '4.0.1', true); wp_enqueue_script('jquery-ui-datepicker');
wp_enqueue_style('jquery-ui-css', 'https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.min.css');
wp_enqueue_script('mcss-admin-js', MCSS_URL . 'js/admin.js', ['jquery', 'wp-color-picker', 'jquery-ui-datepicker'], '4.0.1', true);
} }
}); });
@@ -78,6 +80,11 @@ function mcss_sanitize_servers($input) {
'name_size' => sanitize_text_field($srv['name_size'] ?? '1.8em'), 'name_size' => sanitize_text_field($srv['name_size'] ?? '1.8em'),
'maintenance_mode' => !empty($srv['maintenance_mode']), 'maintenance_mode' => !empty($srv['maintenance_mode']),
'maintenance_message' => wp_kses_post($srv['maintenance_message'] ?? 'Der Server befindet sich derzeit im Wartungsmodus. Wir sind bald wieder für dich da!'), 'maintenance_message' => wp_kses_post($srv['maintenance_message'] ?? 'Der Server befindet sich derzeit im Wartungsmodus. Wir sind bald wieder für dich da!'),
'announcement_enabled' => !empty($srv['announcement_enabled']),
'announcement_text' => wp_kses_post($srv['announcement_text'] ?? ''),
'announcement_start' => sanitize_text_field($srv['announcement_start'] ?? ''),
'announcement_end' => sanitize_text_field($srv['announcement_end'] ?? ''),
'announcement_type' => sanitize_text_field($srv['announcement_type'] ?? 'info'),
'ranks_json' => mcss_sanitize_ranks($srv['ranks_json'] ?? '[]'), 'ranks_json' => mcss_sanitize_ranks($srv['ranks_json'] ?? '[]'),
]; ];
} }
@@ -99,7 +106,7 @@ function mcss_sanitize_ranks($input) {
return wp_json_encode($out); return wp_json_encode($out);
} }
/* ---------------- Settings Page ---------------- */ /* ---------------- Settings Page 100% wie dein Original ---------------- */
function mcss_settings_page() { function mcss_settings_page() {
$servers = get_option('mcss_servers', []); $servers = get_option('mcss_servers', []);
if (empty($servers)) { if (empty($servers)) {
@@ -114,13 +121,20 @@ function mcss_settings_page() {
'1.4em' => 'Groß','1.5em' => 'Sehr groß (Standard)','1.7em' => 'Extra groß','2em' => 'Riesig', '1.4em' => 'Groß','1.5em' => 'Sehr groß (Standard)','1.7em' => 'Extra groß','2em' => 'Riesig',
'2.5em' => 'Enorm','3em' => 'Gigantisch', '2.5em' => 'Enorm','3em' => 'Gigantisch',
]; ];
$announcement_types = [
'info' => 'Information (Blau)',
'warning' => 'Warnung (Orange)',
'success' => 'Erfolg (Grün)',
'error' => 'Fehler (Rot)',
];
?> ?>
<div class="wrap"> <div class="wrap">
<h1>Minecraft Server Einstellungen</h1> <h1>Minecraft Server Einstellungen</h1>
<form method="post" action="options.php"> <form method="post" action="options.php">
<?php settings_fields('mcss_settings_group'); ?> <?php settings_fields('mcss_settings_group'); ?>
<div id="mcss-servers-repeater"> <div id="mcss-servers-repeater">
<?php foreach ($servers as $i => $srv): mcss_render_server_row($srv, $i, $font_sizes); endforeach; ?> <?php foreach ($servers as $i => $srv): mcss_render_server_row($srv, $i, $font_sizes, $announcement_types); endforeach; ?>
</div> </div>
<p><button type="button" class="button button-primary" id="mcss-add-server">+ Neuen Server hinzufügen</button></p> <p><button type="button" class="button button-primary" id="mcss-add-server">+ Neuen Server hinzufügen</button></p>
<?php submit_button(); ?> <?php submit_button(); ?>
@@ -137,7 +151,7 @@ function mcss_settings_page() {
jQuery(function($){ jQuery(function($){
let counter = <?php echo count($servers); ?>; let counter = <?php echo count($servers); ?>;
// Button-Event-Handler // Button-Event-Handler - direkt und einfach
$('#mcss-add-server').on('click', function(e){ $('#mcss-add-server').on('click', function(e){
e.preventDefault(); e.preventDefault();
@@ -241,6 +255,48 @@ function mcss_settings_page() {
<p class="description">HTML + Emojis erlaubt. Diese Nachricht wird angezeigt, wenn der Wartungsmodus aktiv ist.</p> <p class="description">HTML + Emojis erlaubt. Diese Nachricht wird angezeigt, wenn der Wartungsmodus aktiv ist.</p>
</td> </td>
</tr> </tr>
<tr>
<th><label>Ankündigungen</label></th>
<td>
<input name="mcss_servers[${newIndex}][announcement_enabled]" type="checkbox" value="1" />
<label>Ankündigungen aktivieren</label>
<p class="description" style="margin-top:8px;">Wenn aktiviert, werden zeitlich begrenzte Ankündigungen über dem Widget angezeigt.</p>
</td>
</tr>
<tr>
<th><label>Ankündigungstext</label></th>
<td>
<textarea name="mcss_servers[${newIndex}][announcement_text]" class="large-text" rows="3" placeholder="🎉 Server-Event am Wochenende! Kommt vorbei und gewinnt tolle Preise!">🎉 Server-Event am Wochenende! Kommt vorbei und gewinnt tolle Preise!</textarea>
<p class="description">HTML + Emojis erlaubt. Diese Nachricht wird als Ankündigung angezeigt.</p>
</td>
</tr>
<tr>
<th><label>Ankündigungszeitraum</label></th>
<td>
<div style="display:flex;gap:10px;align-items:center;">
<div style="flex:1;">
<label for="mcss_announcement_start_${newIndex}">Startdatum:</label>
<input name="mcss_servers[${newIndex}][announcement_start]" id="mcss_announcement_start_${newIndex}" type="text" class="regular-text mcss-datepicker" placeholder="TT.MM.JJJJ HH:MM" />
</div>
<div style="flex:1;">
<label for="mcss_announcement_end_${newIndex}">Enddatum:</label>
<input name="mcss_servers[${newIndex}][announcement_end]" id="mcss_announcement_end_${newIndex}" type="text" class="regular-text mcss-datepicker" placeholder="TT.MM.JJJJ HH:MM" />
</div>
</div>
<p class="description" style="margin-top:8px;">Die Ankündigung wird nur im angegebenen Zeitraum angezeigt. Leerlassen für dauerhafte Anzeige.</p>
</td>
</tr>
<tr>
<th><label>Ankündigungstyp</label></th>
<td>
<select name="mcss_servers[${newIndex}][announcement_type]" style="width:200px;">
<?php foreach ($announcement_types as $value => $label): ?>
<option value="<?php echo esc_attr($value); ?>"><?php echo esc_html($label); ?></option>
<?php endforeach; ?>
</select>
<p class="description" style="margin-top:8px;">Bestimmt das Aussehen der Ankündigung.</p>
</td>
</tr>
</table> </table>
<h2>Ränge (LuckPerms Zuordnung)</h2> <h2>Ränge (LuckPerms Zuordnung)</h2>
<p>Die Ränge werden automatisch über LuckPerms per RCON abgerufen.</p> <p>Die Ränge werden automatisch über LuckPerms per RCON abgerufen.</p>
@@ -256,6 +312,12 @@ function mcss_settings_page() {
// Farbpicker für neue Zeile initialisieren // Farbpicker für neue Zeile initialisieren
$('#mcss-servers-repeater .mcss-server-row:last .mcss-color-picker').wpColorPicker(); $('#mcss-servers-repeater .mcss-server-row:last .mcss-color-picker').wpColorPicker();
// Datepicker für neue Zeile initialisieren
$('#mcss-servers-repeater .mcss-server-row:last .mcss-datepicker').datepicker({
dateFormat: 'dd.mm.yy',
timeFormat: 'HH:mm'
});
}); });
// Event-Handler für das Entfernen von Servern // Event-Handler für das Entfernen von Servern
@@ -265,12 +327,18 @@ function mcss_settings_page() {
// Farbpicker für bestehende Zeilen initialisieren // Farbpicker für bestehende Zeilen initialisieren
$('.mcss-color-picker').wpColorPicker(); $('.mcss-color-picker').wpColorPicker();
// Datepicker für bestehende Zeilen initialisieren
$('.mcss-datepicker').datepicker({
dateFormat: 'dd.mm.yy',
timeFormat: 'HH:mm'
});
}); });
</script> </script>
<?php <?php
} }
function mcss_render_server_row($srv, $i, $font_sizes) { function mcss_render_server_row($srv, $i, $font_sizes, $announcement_types) {
$logo_id = $srv['logo_id'] ?? 0; $logo_id = $srv['logo_id'] ?? 0;
$logo_url = $srv['logo_url'] ?? ''; $logo_url = $srv['logo_url'] ?? '';
$current_logo = $logo_id ? wp_get_attachment_image_url($logo_id, 'medium') : $logo_url; $current_logo = $logo_id ? wp_get_attachment_image_url($logo_id, 'medium') : $logo_url;
@@ -379,6 +447,48 @@ function mcss_render_server_row($srv, $i, $font_sizes) {
<p class="description">HTML + Emojis erlaubt. Diese Nachricht wird angezeigt, wenn der Wartungsmodus aktiv ist.</p> <p class="description">HTML + Emojis erlaubt. Diese Nachricht wird angezeigt, wenn der Wartungsmodus aktiv ist.</p>
</td> </td>
</tr> </tr>
<tr>
<th><label>Ankündigungen</label></th>
<td>
<input name="mcss_servers[<?php echo $i; ?>][announcement_enabled]" type="checkbox" value="1" <?php checked(!empty($srv['announcement_enabled'])); ?> />
<label>Ankündigungen aktivieren</label>
<p class="description" style="margin-top:8px;">Wenn aktiviert, werden zeitlich begrenzte Ankündigungen über dem Widget angezeigt.</p>
</td>
</tr>
<tr>
<th><label>Ankündigungstext</label></th>
<td>
<textarea name="mcss_servers[<?php echo $i; ?>][announcement_text]" class="large-text" rows="3" placeholder="🎉 Server-Event am Wochenende! Kommt vorbei und gewinnt tolle Preise!"><?php echo esc_textarea($srv['announcement_text'] ?? '🎉 Server-Event am Wochenende! Kommt vorbei und gewinnt tolle Preise!'); ?></textarea>
<p class="description">HTML + Emojis erlaubt. Diese Nachricht wird als Ankündigung angezeigt.</p>
</td>
</tr>
<tr>
<th><label>Ankündigungszeitraum</label></th>
<td>
<div style="display:flex;gap:10px;align-items:center;">
<div style="flex:1;">
<label for="mcss_announcement_start_<?php echo $i; ?>">Startdatum:</label>
<input name="mcss_servers[<?php echo $i; ?>][announcement_start]" id="mcss_announcement_start_<?php echo $i; ?>" type="text" class="regular-text mcss-datepicker" value="<?php echo esc_attr($srv['announcement_start'] ?? ''); ?>" placeholder="TT.MM.JJJJ HH:MM" />
</div>
<div style="flex:1;">
<label for="mcss_announcement_end_<?php echo $i; ?>">Enddatum:</label>
<input name="mcss_servers[<?php echo $i; ?>][announcement_end]" id="mcss_announcement_end_<?php echo $i; ?>" type="text" class="regular-text mcss-datepicker" value="<?php echo esc_attr($srv['announcement_end'] ?? ''); ?>" placeholder="TT.MM.JJJJ HH:MM" />
</div>
</div>
<p class="description" style="margin-top:8px;">Die Ankündigung wird nur im angegebenen Zeitraum angezeigt. Leerlassen für dauerhafte Anzeige.</p>
</td>
</tr>
<tr>
<th><label>Ankündigungstyp</label></th>
<td>
<select name="mcss_servers[<?php echo $i; ?>][announcement_type]" style="width:200px;">
<?php foreach ($announcement_types as $value => $label): ?>
<option value="<?php echo esc_attr($value); ?>" <?php selected($srv['announcement_type'] ?? 'info', $value); ?>><?php echo esc_html($label); ?></option>
<?php endforeach; ?>
</select>
<p class="description" style="margin-top:8px;">Bestimmt das Aussehen der Ankündigung.</p>
</td>
</tr>
</table> </table>
<h2>Ränge (LuckPerms Zuordnung)</h2> <h2>Ränge (LuckPerms Zuordnung)</h2>
@@ -391,7 +501,7 @@ function mcss_render_server_row($srv, $i, $font_sizes) {
<?php <?php
} }
/* ---------------- Funktionen ---------------- */ /* ---------------- Alle Original-Funktionen 1:1 ---------------- */
function mcss_test_rcon_now($srv) { function mcss_test_rcon_now($srv) {
if (empty($srv['host']) || empty($srv['rcon_pass'])) return ['error' => 'Host oder Passwort nicht gesetzt']; if (empty($srv['host']) || empty($srv['rcon_pass'])) return ['error' => 'Host oder Passwort nicht gesetzt'];
$rcon = new Rcon($srv['host'], $srv['rcon_port'], $srv['rcon_pass'], 3); $rcon = new Rcon($srv['host'], $srv['rcon_port'], $srv['rcon_pass'], 3);
@@ -528,7 +638,7 @@ function mcss_avatar($input, $size = 64) {
return "https://mc-heads.net/avatar/{$uuid}/{$size}"; return "https://mc-heads.net/avatar/{$uuid}/{$size}";
} }
/* ---------------- FUNKTION FÜR PING-MESSUNG ---------------- */ /* ---------------- NEUE FUNKTION FÜR PING-MESSUNG ---------------- */
function mcss_ping_server($host, $port = 25565, $timeout = 2) { function mcss_ping_server($host, $port = 25565, $timeout = 2) {
$startTime = microtime(true); $startTime = microtime(true);
@@ -549,7 +659,77 @@ function mcss_ping_server($host, $port = 25565, $timeout = 2) {
return $ping; return $ping;
} }
/* ---------------- Fetch & AJAX ---------------- */ /* ---------------- NEUE FUNKTIONEN FÜR ANKÜNDIGUNGEN ---------------- */
function mcss_should_show_announcement($srv) {
// Prüfen, ob Ankündigungen aktiviert sind
if (empty($srv['announcement_enabled'])) {
return false;
}
// Prüfen, ob ein Text vorhanden ist
if (empty($srv['announcement_text'])) {
return false;
}
// Wenn kein Startdatum angegeben ist, immer anzeigen
if (empty($srv['announcement_start'])) {
return true;
}
$current_time = current_time('timestamp');
$start_time = strtotime($srv['announcement_start']);
// Wenn das Startdatum in der Zukunft liegt, nicht anzeigen
if ($start_time > $current_time) {
return false;
}
// Wenn kein Enddatum angegeben ist, nach Startdatum immer anzeigen
if (empty($srv['announcement_end'])) {
return true;
}
$end_time = strtotime($srv['announcement_end']);
// Prüfen, ob das Enddatum noch nicht erreicht ist
return $end_time >= $current_time;
}
function mcss_get_announcement_style($type) {
switch ($type) {
case 'warning':
return [
'bg' => '#fef3c7',
'border' => '#fbbf24',
'text' => '#92400e',
'icon' => '⚠️'
];
case 'success':
return [
'bg' => '#d1fae5',
'border' => '#10b981',
'text' => '#065f46',
'icon' => '✅'
];
case 'error':
return [
'bg' => '#fee2e2',
'border' => '#ef4444',
'text' => '#991b1b',
'icon' => '❌'
];
case 'info':
default:
return [
'bg' => '#dbeafe',
'border' => '#3b82f6',
'text' => '#1e40af',
'icon' => ''
];
}
}
/* ---------------- Fetch & AJAX 100% wie dein Original ---------------- */
add_action('wp_ajax_mcss_fetch', 'mcss_ajax_fetch'); add_action('wp_ajax_mcss_fetch', 'mcss_ajax_fetch');
add_action('wp_ajax_nopriv_mcss_fetch', 'mcss_ajax_fetch'); add_action('wp_ajax_nopriv_mcss_fetch', 'mcss_ajax_fetch');
@@ -617,6 +797,7 @@ function mcss_fetch_server_with_ranks($srv) {
$candidate = $body['version'] ?? $body['software'] ?? ''; $candidate = $body['version'] ?? $body['software'] ?? '';
if ($candidate) $result['version'] = mcss_normalize_version($candidate); if ($candidate) $result['version'] = mcss_normalize_version($candidate);
} }
$result['ping'] = intval($body['debug']['ping'] ?? $body['ping'] ?? 0);
if (!empty($srv['show_motd']) && !empty($body['motd']['clean'])) { if (!empty($srv['show_motd']) && !empty($body['motd']['clean'])) {
$motd = is_array($body['motd']['clean']) ? implode(' ', $body['motd']['clean']) : $body['motd']['clean']; $motd = is_array($body['motd']['clean']) ? implode(' ', $body['motd']['clean']) : $body['motd']['clean'];
$result['motd'] = $motd; $result['motd'] = $motd;
@@ -624,13 +805,13 @@ function mcss_fetch_server_with_ranks($srv) {
} }
} }
// PING-MESSUNG // PING-MESSUNG - VERWENDE UNSERE EIGENE FUNKTION
$ping_port = !empty($srv['player_port']) ? $srv['player_port'] : $srv['query_port']; $ping_port = !empty($srv['player_port']) ? $srv['player_port'] : $srv['query_port'];
$ping_result = mcss_ping_server($srv['host'], $ping_port, 2); $ping_result = mcss_ping_server($srv['host'], $ping_port, 2);
if ($ping_result !== false) { if ($ping_result !== false) {
$result['ping'] = $ping_result; $result['ping'] = $ping_result;
} else { } else {
// Wenn Ping-Messung fehlschlägt, versuche den Ping aus der API zu verwenden // Wenn unsere Ping-Messung fehlschlägt, versuche den Ping aus der API zu verwenden
if (!empty($body['debug']['ping'])) { if (!empty($body['debug']['ping'])) {
$result['ping'] = intval($body['debug']['ping']); $result['ping'] = intval($body['debug']['ping']);
} elseif (!empty($body['ping'])) { } elseif (!empty($body['ping'])) {
@@ -674,7 +855,7 @@ function mcss_fetch_server_with_ranks($srv) {
return $result; return $result;
} }
/* ---------------- Shortcode ---------------- */ /* ---------------- Shortcode 100% DEIN ORIGINAL-DESIGN ---------------- */
add_shortcode('minecraft_status', 'mcss_server_card_shortcode'); add_shortcode('minecraft_status', 'mcss_server_card_shortcode');
add_shortcode('minecraft_server_detail', 'mcss_server_card_shortcode'); add_shortcode('minecraft_server_detail', 'mcss_server_card_shortcode');
@@ -695,6 +876,12 @@ function mcss_server_card_shortcode($atts = []) {
$maintenance_mode = !empty($srv['maintenance_mode']); $maintenance_mode = !empty($srv['maintenance_mode']);
$maintenance_message = $srv['maintenance_message'] ?? 'Der Server befindet sich derzeit im Wartungsmodus. Wir sind bald wieder für dich da!'; $maintenance_message = $srv['maintenance_message'] ?? 'Der Server befindet sich derzeit im Wartungsmodus. Wir sind bald wieder für dich da!';
// Prüfen, ob eine Ankündigung angezeigt werden soll
$show_announcement = mcss_should_show_announcement($srv);
$announcement_text = $srv['announcement_text'] ?? '';
$announcement_type = $srv['announcement_type'] ?? 'info';
$announcement_style = mcss_get_announcement_style($announcement_type);
// Wenn Wartungsmodus aktiv ist, nur die Wartungsansicht anzeigen // Wenn Wartungsmodus aktiv ist, nur die Wartungsansicht anzeigen
if ($maintenance_mode) { if ($maintenance_mode) {
$uid = md5($srv['host'] . '|' . ($srv['player_port'] ?? '')); $uid = md5($srv['host'] . '|' . ($srv['player_port'] ?? ''));
@@ -782,15 +969,39 @@ function mcss_server_card_shortcode($atts = []) {
.mcss-status-online { .mcss-status-online {
animation: pulse 2s infinite; animation: pulse 2s infinite;
} }
/* Animation für die Ankündigung */
@keyframes slideDown {
0% {
transform: translateY(-100%);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
.mcss-announcement {
animation: slideDown 0.5s ease-out;
}
</style> </style>
<div id="mcss-server-widget-<?php echo esc_attr($uid); ?>" class="mcss-server-widget" style="max-width:920px;margin:30px auto;background:#fff;border-radius:20px;overflow:hidden;box-shadow:0 16px 40px rgba(0,0,0,0.12);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;border:1px solid #e2e8f0;position:relative;"> <div id="mcss-server-widget-<?php echo esc_attr($uid); ?>" class="mcss-server-widget" style="max-width:920px;margin:30px auto;background:#fff;border-radius:20px;overflow:hidden;box-shadow:0 16px 40px rgba(0,0,0,0.12);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;border:1px solid #e2e8f0;position:relative;">
<?php if ($show_announcement): ?>
<div class="mcss-announcement" style="padding:16px 24px;background:<?php echo esc_attr($announcement_style['bg']); ?>;border-bottom:1px solid <?php echo esc_attr($announcement_style['border']); ?>;display:flex;align-items:center;gap:12px;">
<span style="font-size:1.5em;"><?php echo esc_html($announcement_style['icon']); ?></span>
<div style="flex:1;font-size:1.05em;font-weight:600;color:<?php echo esc_attr($announcement_style['text']); ?>;"><?php echo wp_kses_post($announcement_text); ?></div>
<button type="button" class="mcss-announcement-close" style="background:none;border:none;color:<?php echo esc_attr($announcement_style['text']); ?>;cursor:pointer;font-size:1.2em;padding:0;line-height:1;" onclick="this.parentElement.style.display='none';">×</button>
</div>
<?php endif; ?>
<div id="mcss-copy-toast-<?php echo esc_attr($uid); ?>" style="position:absolute;top:20px;right:20px;background:#10b981;color:#fff;padding:12px 24px;border-radius:12px;font-weight:600;font-size:0.95em;opacity:0;transform:translateY(-20px);transition:all .4s ease;z-index:100;box-shadow:0 8px 20px rgba(16,185,129,0.4);">Adresse kopiert!</div> <div id="mcss-copy-toast-<?php echo esc_attr($uid); ?>" style="position:absolute;top:20px;right:20px;background:#10b981;color:#fff;padding:12px 24px;border-radius:12px;font-weight:600;font-size:0.95em;opacity:0;transform:translateY(-20px);transition:all .4s ease;z-index:100;box-shadow:0 8px 20px rgba(16,185,129,0.4);">Adresse kopiert!</div>
<div style="padding:28px 32px;background:#f8fafc;border-bottom:1px solid #e2e8f0;display:flex;align-items:center;gap:20px;"> <div style="padding:28px 32px;background:#f8fafc;border-bottom:1px solid #e2e8f0;display:flex;align-items:center;gap:20px;">
<img src="<?php echo esc_url($logo); ?>" alt="Logo" loading="lazy" style="width:80px;height:80px;border-radius:16px;box-shadow:0 8px 20px rgba(0,0,0,0.15);" onerror="this.src='<?php echo MCSS_URL.'img/default-server-logo.png'; ?>'" /> <img src="<?php echo esc_url($logo); ?>" alt="Logo" loading="lazy" style="width:80px;height:80px;border-radius:16px;box-shadow:0 8px 20px rgba(0,0,0,0.15);" onerror="this.src='<?php echo MCSS_URL.'img/default-server-logo.png'; ?>'" />
<div style="flex:1;"> <div style="flex:1;">
<!-- HIER WIRD DER SERVERNAME JETZT MIT ANGEPASSTER FARBE UND GRÖßE ANGEZEIGT -->
<h2 style="margin:0 0 8px 0;font-size:<?php echo esc_attr($srv['name_size'] ?? '1.8em'); ?>;color:<?php echo esc_attr($srv['name_color'] ?? '#1e293b'); ?>;font-weight:800;"><?php echo esc_html($srv['name'] ?? 'Minecraft Server'); ?></h2> <h2 style="margin:0 0 8px 0;font-size:<?php echo esc_attr($srv['name_size'] ?? '1.8em'); ?>;color:<?php echo esc_attr($srv['name_color'] ?? '#1e293b'); ?>;font-weight:800;"><?php echo esc_html($srv['name'] ?? 'Minecraft Server'); ?></h2>
<div style="display:flex;align-items:center;gap:12px;margin-bottom:8px;"> <div style="display:flex;align-items:center;gap:12px;margin-bottom:8px;">
<span id="mcss-address-<?php echo esc_attr($uid); ?>" class="mcss-address" style="font-weight:800;font-size:<?php echo esc_attr($srv['ip_size'] ?? '1.5em'); ?>;color:<?php echo esc_attr($srv['ip_color'] ?? '#1f2937'); ?>;cursor:pointer;user-select:none;" onclick="mcss_copy_address_<?php echo esc_attr($uid); ?>('<?php echo esc_js($copy_address); ?>')"> <span id="mcss-address-<?php echo esc_attr($uid); ?>" class="mcss-address" style="font-weight:800;font-size:<?php echo esc_attr($srv['ip_size'] ?? '1.5em'); ?>;color:<?php echo esc_attr($srv['ip_color'] ?? '#1f2937'); ?>;cursor:pointer;user-select:none;" onclick="mcss_copy_address_<?php echo esc_attr($uid); ?>('<?php echo esc_js($copy_address); ?>')">