Update README.md, colors.txt, config.sh, and 10 more files for alpha v0.3

This commit is contained in:
Rainer 2025-06-22 02:50:07 +02:00
parent a08a86dc40
commit 6d9651b4ff
13 changed files with 449 additions and 109 deletions

View file

@ -94,13 +94,14 @@ a.world-preview:hover {
.world-preview-text p { color: #ccc !important; margin-top: 0; text-decoration: none !important; }
.world-preview-footer { font-size: 0.85em; color: #aaa; border-top: 1px solid #666; margin-top: 10px; padding-top: 10px; }
.online-status-badge { font-size: 0.8em; padding: 3px 8px; border-radius: 10px; color: white !important; margin-left: 10px; }
.online-status-badge.online { background-color: #3E8E41; } .online-status-badge.offline { background-color: #C0392B; }
.online-status-badge.online { background-color: #3E8E41; }
.online-status-badge.offline { background-color: #C0392B; }
.online-status-badge.unknown { background-color: #808080; } /* HINZUGEFÜGT */
/* Welt-Detailseite */
.page-nav-buttons { text-align: right; margin-top: 10px; margin-bottom: 15px; }
.page-nav-buttons .button { background-color: #555; color: #FFA500; border: 1px solid #666; padding: 5px 10px; margin-left: 5px; margin-bottom: 5px; border-radius: 3px; text-decoration: none; font-size: 0.9em; display: inline-block; }
.page-nav-buttons .button:hover { background-color: #666; color: #FFC500; }
/* KORREKTUR: Klasse umbenannt von .leaflet-map zu .map-view-container */
.map-view-container {
width: 100%;
height: 600px;
@ -467,10 +468,9 @@ a.read-more-link {
margin: 5px;
width: auto;
}
.player-box { width: calc((100% - 15px) / 2); } /* 2 Spalten auf Tablets */
.player-box { width: calc((100% - 15px) / 2); }
.page-nav-buttons .button { margin-top: 5px;}
/* Responsive Stile für Welt-Vorschau */
.world-preview .world-preview-content {
flex-direction: column;
}
@ -481,15 +481,15 @@ a.read-more-link {
margin-right: 0;
margin-bottom: 15px;
}
.map-view-container { /* KORREKTUR: Klasse umbenannt */
.map-view-container {
height: auto;
aspect-ratio: 4 / 3;
max-height: 70vh;
}
}
@media (max-width: 480px) {
.player-box { width: 100%; } /* 1 Spalte auf Handys */
.admin-box { flex-basis: 100%; } /* 1 Spalte auf Handys */
.player-box { width: 100%; }
.admin-box { flex-basis: 100%; }
}
/* Stile für OpenLayers Popups (Leaflet-Look-and-Feel) */

View file

@ -5,5 +5,41 @@
<a href="#" id="scrollToTopBtn" class="scroll-to-top-btn" title="Nach oben scrollen">▲</a>
<script>
document.addEventListener('DOMContentLoaded', function() {
const statusBadges = document.querySelectorAll('.online-status-badge[data-status-url]');
if (statusBadges.length > 0) {
statusBadges.forEach(badge => {
const url = badge.dataset.statusUrl + '?v=' + new Date().getTime();
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok for ' + url);
}
return response.text();
})
.then(text => {
badge.classList.remove('unknown');
if (text.trim().startsWith('online')) {
badge.textContent = 'online';
badge.classList.add('online');
} else {
badge.textContent = 'offline';
badge.classList.add('offline');
}
})
.catch(error => {
console.error('Fehler beim Abrufen des Welt-Status:', error);
badge.textContent = 'n.a.'; // Nicht verfügbar
badge.classList.remove('unknown');
badge.classList.add('offline'); // Bei Fehler als offline markieren
});
});
}
});
</script>
</body>
</html>

View file

@ -103,7 +103,8 @@ function fetchWorldStatus_%%current_world_key%%() {
function fetchDataForElement(elementId, filePath, isRawText, prefixText, suffixText, isJsonPlayerList) {
const el = document.getElementById(elementId);
if (!el && !isJsonPlayerList) return;
if (!el && !isJsonPlayerList) return;
fetch('/' + filePath + '?v=%%CACHE_BUSTER%%&t=' + new Date().getTime())
.then(r => { if (!r.ok) throw new Error('Datei ' + filePath + ' nicht erreichbar (' + r.status + ')'); return r.text(); })
.then(t => {
@ -111,9 +112,10 @@ function fetchDataForElement(elementId, filePath, isRawText, prefixText, suffixT
if (t.trim() === "") {
content = (elementId.startsWith("map-last-update") ? "<em>unbekannt</em>" : "<em>Keine Daten verfügbar.</em>");
if (isJsonPlayerList && window.playerListLogic_%%current_world_key%%) {
window.playerListLogic_%%current_world_key%%.masterPlayerData = {};
window.playerListLogic_%%current_world_key%%.updatePlayerMarkers({});
window.playerListLogic_%%current_world_key%%.applyPlayerFiltersAndRender();
const logic = window.playerListLogic_%%current_world_key%%;
logic.masterPlayerData = {};
logic.updatePlayerMarkers({});
logic.applyPlayerFiltersAndRender();
}
} else {
if (isJsonPlayerList && window.playerListLogic_%%current_world_key%%) {
@ -125,7 +127,11 @@ function fetchDataForElement(elementId, filePath, isRawText, prefixText, suffixT
logic.applyPlayerFiltersAndRender();
} catch (e) { console.error("Fehler beim Parsen der Spielerdaten:", e); }
return;
} else { content = isRawText ? t.replace(/\n/g, '<br>') : t; }
} else {
const dv = document.createElement('div');
dv.textContent = t;
content = dv.innerHTML.replace(/\n/g, '<br>');
}
}
if(el) { el.innerHTML = (prefixText || '') + content + (suffixText || ''); }
}).catch(e => {
@ -168,6 +174,7 @@ document.addEventListener('DOMContentLoaded', function() {
// Periodische Updates
setInterval(fetchWorldStatus_%%current_world_key%%, 60000);
setInterval(() => fetchDataForElement('map-last-update-text-%%current_world_key%%', '%%web_last_update_rel_path%%', true, '', ''), 60000);
setInterval(() => fetchDataForElement('player-info-%%current_world_key%%', '%%web_players_txt_rel_path%%', false, '', '', true), 70000);
// KORREKTUR: Intervall von 70000ms auf 30000ms (30 Sekunden) geändert
setInterval(() => fetchDataForElement('player-info-%%current_world_key%%', '%%web_players_txt_rel_path%%', false, '', '', true), 30000);
setInterval(() => fetchDataForElement('weather-info-%%current_world_key%%', '%%web_weather_txt_rel_path%%', true, '<p><strong>Wetter:</strong> ', '</p>'), 300000);
</script>

View file

@ -39,22 +39,6 @@ if (!window.playerListLogic_%%current_world_key%%) {
source.clear(); // Entferne alle alten Marker
// KORREKTUR: Marker-Stile auf Kreise umgestellt
const adminIconStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({ color: 'rgba(255, 255, 0, 0.9)' }), // Gelb
stroke: new ol.style.Stroke({ color: '#fff', width: 2 })
})
});
const playerIconStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 6,
fill: new ol.style.Fill({ color: 'rgba(255, 0, 0, 0.9)' }), // Rot
stroke: new ol.style.Stroke({ color: '#fff', width: 1 })
})
});
const features = [];
const now_epoch = Math.floor(Date.now() / 1000);
const twentyFourHoursInSeconds = 24 * 60 * 60;
@ -72,13 +56,35 @@ if (!window.playerListLogic_%%current_world_key%%) {
lastLoginFormatted = formatTimestampForDisplay(p.last_login);
}
// HINZUGEFÜGT: Erstelle den kombinierten Stil aus Kreis und Text
const circleStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: isAdmin ? 7 : 6,
fill: new ol.style.Fill({ color: isAdmin ? 'rgba(255, 190, 0, 0.9)' : 'rgba(255, 40, 40, 0.9)' }),
stroke: new ol.style.Stroke({ color: '#ffffff', width: isAdmin ? 2 : 1 })
})
});
const textStyle = new ol.style.Style({
text: new ol.style.Text({
text: p.name,
font: 'bold 11px "Helvetica Neue", Arial, sans-serif',
fill: new ol.style.Fill({ color: '#ffffff' }),
stroke: new ol.style.Stroke({ color: 'rgba(0, 0, 0, 0.9)', width: 3 }),
offsetY: -20, // Positioniert den Text über dem Kreismittelpunkt
textAlign: 'center'
})
});
const feature = new ol.Feature({
geometry: new ol.geom.Point(coords),
playerData: p,
statusDotClass: statusDotClass,
lastLoginFormatted: lastLoginFormatted
});
feature.set('style', isAdmin ? adminIconStyle : playerIconStyle);
// Setze den kombinierten Stil (Kreis und Text) für das Feature
feature.set('style', [circleStyle, textStyle]);
features.push(feature);
}
source.addFeatures(features);

View file

@ -7,7 +7,7 @@
</h3>
<div id="live-map-container-%%current_world_key%%">
<div id="ol-map-container-%%current_world_key%%" class="map-view-container"></div>
<div id="ol-map-container-%%current_world_key%%" class="map-view-container" style="background-color: %%map_background_color%%;"></div>
<div id="popup-%%current_world_key%%" class="ol-popup">
<a href="#" id="popup-closer-%%current_world_key%%" class="ol-popup-closer"></a>
@ -78,7 +78,17 @@ document.addEventListener('DOMContentLoaded', function() {
mapContainer.innerHTML = '';
const extent = [0, -mapData.mapHeight, mapData.mapWidth, 0];
const resolutions = %%RESOLUTIONS_JS_ARRAY%%;
// KORREKTUR: Wir trennen die echten von den virtuellen Auflösungen
const sourceResolutions = %%RESOLUTIONS_JS_ARRAY%%;
const viewResolutions = [...sourceResolutions]; // Kopie für die Ansicht
const digitalZoomLevels = 3;
let lastResolution = viewResolutions[viewResolutions.length - 1];
for (let i = 0; i < digitalZoomLevels; i++) {
lastResolution = lastResolution / 2;
viewResolutions.push(lastResolution);
}
const projection = new ol.proj.Projection({
code: 'pixel-map-%%current_world_key%%',
@ -88,7 +98,7 @@ document.addEventListener('DOMContentLoaded', function() {
const tileGrid = new ol.tilegrid.TileGrid({
origin: ol.extent.getTopLeft(extent),
resolutions: resolutions,
resolutions: sourceResolutions, // Das TileGrid kennt NUR die echten Auflösungen
});
const tileSource = new ol.source.TileImage({
@ -96,6 +106,8 @@ document.addEventListener('DOMContentLoaded', function() {
tileGrid: tileGrid,
tileUrlFunction: function(tileCoord) {
if (!tileCoord) return '';
// OpenLayers wählt jetzt selbst die beste verfügbare Kachel aus.
// Die URL-Funktion kann wieder einfach sein.
return ('/%%web_tiles_rel_path%%/' + tileCoord[0] + '/' + tileCoord[1] + '/' + tileCoord[2] + '.png?v=%%CACHE_BUSTER%%');
}
});
@ -107,8 +119,7 @@ document.addEventListener('DOMContentLoaded', function() {
const view = new ol.View({
projection: projection,
center: ol.extent.getCenter(extent),
resolutions: resolutions,
maxZoom: resolutions.length - 1
resolutions: viewResolutions, // Die View kennt ALLE Auflösungen (echte + digitale)
});
const popupContainer = document.getElementById('popup-%%current_world_key%%');
@ -129,10 +140,6 @@ document.addEventListener('DOMContentLoaded', function() {
});
const map = window.olMap_%%current_world_key%%;
// KORREKTUR: Hintergrundfarbe wird hier per JavaScript gesetzt
map.getViewport().style.backgroundColor = '%%map_background_color%%';
map.getView().fit(extent, { size: map.getSize() });
map.on('click', function(evt) {

View file

@ -1,7 +1,7 @@
<a href='%%detail_page_filename%%' class='world-preview'>
<div class='world-preview-header'>
<h3>%%world_display_name_ov%%</h3>
<span class='online-status-badge %%online_status_class%%'>%%online_status_text%%</span>
<span class='online-status-badge unknown' data-status-url="%%status_url%%">lädt...</span>
</div>
<div class='world-preview-content'>
%%preview_img_html%%