styling popup title

This commit is contained in:
Tykayn 2025-09-23 12:53:52 +02:00 committed by tykayn
parent c194862e00
commit 114bcca24e
3 changed files with 171 additions and 90 deletions

View file

@ -69,18 +69,48 @@ class DemoMainResource:
border-radius: 5px; border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
max-width: 300px; max-width: 300px;
transition: all 0.3s ease;
z-index: 10;
} }
/* Styles pour listes dépliantes */
#endpoints_list, #demo_pages_list { /* Responsive styles for the menu */
@media (max-width: 768px) {
.map-overlay {
max-width: 85%;
width: 85%;
font-size: 0.9em;
}
.map-overlay h2 {
font-size: 1.2em;
}
}
@media (max-width: 480px) {
.map-overlay {
max-width: 90%;
width: 90%;
font-size: 0.85em;
}
}
/* Styles pour listes dépliantes et sections collapsibles */
#endpoints_list, #demo_pages_list, .collapsible-content {
display: none; display: none;
overflow: hidden; overflow: hidden;
transition: all 0.3s ease; transition: all 0.3s ease;
} }
#endpoints_list_header, #demo_pages_list_header { #endpoints_list_header, #demo_pages_list_header, .collapsible-header {
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
position: relative; position: relative;
padding-right: 20px; padding-right: 20px;
margin-top: 15px;
margin-bottom: 10px;
}
.toggle-icon {
position: absolute;
right: 0;
font-size: 0.8em;
transition: transform 0.3s ease;
} }
#endpoints_list_header:after, #demo_pages_list_header:after { #endpoints_list_header:after, #demo_pages_list_header:after {
content: ''; content: '';
@ -89,7 +119,8 @@ class DemoMainResource:
font-size: 0.8em; font-size: 0.8em;
transition: transform 0.3s ease; transition: transform 0.3s ease;
} }
#endpoints_list_header.active:after, #demo_pages_list_header.active:after { #endpoints_list_header.active:after, #demo_pages_list_header.active:after,
.collapsible-header.active .toggle-icon {
transform: rotate(180deg); transform: rotate(180deg);
} }
.map-style-control { .map-style-control {
@ -213,79 +244,84 @@ class DemoMainResource:
<img src="/static/oedb.png" class="logo" /> <img src="/static/oedb.png" class="logo" />
OpenEventDatabase Demo</h2> OpenEventDatabase Demo</h2>
<p>This map shows current events from the OpenEventDatabase.</p> <p>This map shows current events from the OpenEventDatabase.</p>
<!-- Event addition buttons - always visible -->
<p><a href="/demo/traffic" class="add-event-btn" style="display: block; text-align: center; margin-top: 15px; padding: 8px; background-color: #0078ff; color: white; border-radius: 4px; font-weight: bold;">+ Traffic event</a></p> <p><a href="/demo/traffic" class="add-event-btn" style="display: block; text-align: center; margin-top: 15px; padding: 8px; background-color: #0078ff; color: white; border-radius: 4px; font-weight: bold;">+ Traffic event</a></p>
<p><a href="/demo/add" class="add-event-btn" style="display: block; text-align: center; margin-top: 15px; padding: 8px; background-color: #0078ff; color: white; border-radius: 4px; font-weight: bold;">+ Any Event</a></p> <p><a href="/demo/add" class="add-event-btn" style="display: block; text-align: center; margin-top: 15px; padding: 8px; background-color: #0078ff; color: white; border-radius: 4px; font-weight: bold;">+ Any Event</a></p>
<!-- User Information Panel --> <!-- Collapsible information section -->
<div id="user-info-panel" class="user-info-panel" style="display: none; background-color: #f5f5f5; border-radius: 4px; padding: 10px; margin: 10px 0; box-shadow: 0 2px 4px rgba(0,0,0,0.1);"> <h3 id="info_panel_header" class="collapsible-header">Information Panel <span class="toggle-icon"></span></h3>
<h3 style="margin-top: 0; margin-bottom: 10px; color: #333;">User Information</h3> <div id="info_panel_content" class="collapsible-content">
<p>Username: <strong id="username-display">Anonymous</strong></p> <!-- User Information Panel -->
<p>Points: <span id="points-display" style="font-weight: bold; color: #0078ff;">0</span></p> <div id="user-info-panel" class="user-info-panel" style="display: none; background-color: #f5f5f5; border-radius: 4px; padding: 10px; margin: 10px 0; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
</div> <h3 style="margin-top: 0; margin-bottom: 10px; color: #333;">User Information</h3>
<p>Username: <strong id="username-display">Anonymous</strong></p>
<p>Points: <span id="points-display" style="font-weight: bold; color: #0078ff;">0</span></p>
</div>
<!-- Authentication section --> <!-- Authentication section -->
<!-- <!--
# <div id="auth-section" class="auth-section"> # <div id="auth-section" class="auth-section">
# <h3>OpenStreetMap Authentication</h3> # <h3>OpenStreetMap Authentication</h3>
# #
<a href="https://www.openstreetmap.org/oauth2/authorize?client_id={client_id}&redirect_uri={client_redirect}&response_type=code&scope=read_prefs" class="osm-login-btn"> <a href="https://www.openstreetmap.org/oauth2/authorize?client_id={client_id}&redirect_uri={client_redirect}&response_type=code&scope=read_prefs" class="osm-login-btn">
<span class="osm-logo"></span> <span class="osm-logo"></span>
Login with OpenStreetMap Login with OpenStreetMap
</a> </a>
<script> <script>
# // Replace server-side auth section with JavaScript-rendered version if available # // Replace server-side auth section with JavaScript-rendered version if available
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
fetchEvents(); fetchEvents();
if (window.osmAuth) { if (window.osmAuth) {
const clientId = document.getElementById('osmClientId').value; const clientId = document.getElementById('osmClientId').value;
const redirectUri = document.getElementById('osmRedirectUri').value; const redirectUri = document.getElementById('osmRedirectUri').value;
const authSection = document.getElementById('auth-section'); const authSection = document.getElementById('auth-section');
// Only replace if osmAuth is loaded and has renderAuthSection method // Only replace if osmAuth is loaded and has renderAuthSection method
if (osmAuth.renderAuthSection) { if (osmAuth.renderAuthSection) {
authSection.innerHTML = osmAuth.renderAuthSection(clientId, redirectUri); authSection.innerHTML = osmAuth.renderAuthSection(clientId, redirectUri);
}
} }
} });
}); </script>
</script> </div> -->
</div> -->
<h3 id="endpoints_list_header">API Endpoints:</h3> <h3 id="endpoints_list_header">API Endpoints:</h3>
<ul id="endpoints_list"> <ul id="endpoints_list">
<li><a href="/" >/ - API Information</a></li> <li><a href="/" >/ - API Information</a></li>
<li><a href="/event" >/event - Get Events</a></li> <li><a href="/event" >/event - Get Events</a></li>
<li><a href="/stats" >/stats - Database Statistics</a></li> <li><a href="/stats" >/stats - Database Statistics</a></li>
</ul> </ul>
<h3 id="demo_pages_list_header">Demo Pages:</h3> <h3 id="demo_pages_list_header">Demo Pages:</h3>
<ul id="demo_pages_list"> <ul id="demo_pages_list">
<li><a href="/demo/search" >/demo/search - Advanced Search</a></li> <li><a href="/demo/search" >/demo/search - Advanced Search</a></li>
<li><a href="/demo/by-what" >/demo/by-what - Events by Type</a></li> <li><a href="/demo/by-what" >/demo/by-what - Events by Type</a></li>
<li><a href="/demo/map-by-what" >/demo/map-by-what - Map by Event Type</a></li> <li><a href="/demo/map-by-what" >/demo/map-by-what - Map by Event Type</a></li>
<li><a href="/demo/traffic" >/demo/traffic - Report Traffic Jam</a></li> <li><a href="/demo/traffic" >/demo/traffic - Report Traffic Jam</a></li>
<li><a href="/demo/view-events" >/demo/view-events - View Saved Events</a></li> <li><a href="/demo/view-events" >/demo/view-events - View Saved Events</a></li>
<li><a href="/event?what=music" >Search Music Events</a></li> <li><a href="/event?what=music" >Search Music Events</a></li>
<li><a href="/event?what=sport" >Search Sport Events</a></li> <li><a href="/event?what=sport" >Search Sport Events</a></li>
</ul> </ul>
<p class="sources" style="text-align: center; margin-top: 10px;"> <p class="sources" style="text-align: center; margin-top: 10px;">
<a href="https://source.cipherbliss.com/tykayn/oedb-backend" title="View Source Code on Cipherbliss" style="font-size: 24px;"> <a href="https://source.cipherbliss.com/tykayn/oedb-backend" title="View Source Code on Cipherbliss" style="font-size: 24px;">
<i class="fas fa-code-branch"></i> sources <i class="fas fa-code-branch"></i> sources
</a> </a>
</p> </p>
</div>
</div> </div>
<script> <script>
// Fonction pour gérer les listes dépliantes // Fonction pour gérer les listes dépliantes et sections collapsibles
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
const endpointsHeader = document.getElementById('endpoints_list_header'); const endpointsHeader = document.getElementById('endpoints_list_header');
const endpointsList = document.getElementById('endpoints_list'); const endpointsList = document.getElementById('endpoints_list');
const demoPagesHeader = document.getElementById('demo_pages_list_header'); const demoPagesHeader = document.getElementById('demo_pages_list_header');
const demoPagesList = document.getElementById('demo_pages_list'); const demoPagesList = document.getElementById('demo_pages_list');
const infoPanelHeader = document.getElementById('info_panel_header');
const infoPanelContent = document.getElementById('info_panel_content');
// Fonction pour basculer l'affichage d'une liste // Fonction pour basculer l'affichage d'une liste ou section
function toggleList(header, list) { function toggleList(header, list) {
header.addEventListener('click', function() { header.addEventListener('click', function() {
if (list.style.display === 'none' || list.style.display === '') { if (list.style.display === 'none' || list.style.display === '') {
@ -298,13 +334,15 @@ class DemoMainResource:
}); });
} }
// Initialiser les listes comme repliées // Initialiser les listes et sections comme repliées
endpointsList.style.display = 'none'; endpointsList.style.display = 'none';
demoPagesList.style.display = 'none'; demoPagesList.style.display = 'none';
infoPanelContent.style.display = 'none';
// Ajouter les écouteurs d'événements // Ajouter les écouteurs d'événements
toggleList(endpointsHeader, endpointsList); toggleList(endpointsHeader, endpointsList);
toggleList(demoPagesHeader, demoPagesList); toggleList(demoPagesHeader, demoPagesList);
toggleList(infoPanelHeader, infoPanelContent);
}); });
// Map style URLs // Map style URLs
@ -346,6 +384,15 @@ class DemoMainResource:
// Add navigation controls // Add navigation controls
map.addControl(new maplibregl.NavigationControl()); map.addControl(new maplibregl.NavigationControl());
// Add geolocation control
map.addControl(new maplibregl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true,
showUserHeading: true
}));
// Add attribution control with OpenStreetMap attribution // Add attribution control with OpenStreetMap attribution
map.addControl(new maplibregl.AttributionControl({ map.addControl(new maplibregl.AttributionControl({
customAttribution: '© <a href="https://www.openstreetmap.org/copyright" >OpenStreetMap</a> contributors' customAttribution: '© <a href="https://www.openstreetmap.org/copyright" >OpenStreetMap</a> contributors'
@ -355,11 +402,20 @@ class DemoMainResource:
let currentStyle = 'default'; let currentStyle = 'default';
let eventsData = null; let eventsData = null;
// Array to store markers so they can be removed on refresh
let currentMarkers = [];
// Fetch events when the map is loaded
// Fetch events when the map is loaded and every 30 seconds thereafter
map.on('load', function() { map.on('load', function() {
// Initial fetch
fetchEvents(); fetchEvents();
// Set up interval to fetch events every 30 seconds
setInterval(fetchEvents, 30000);
console.log('Event refresh interval set: events will update every 30 seconds');
}); });
// Function to fetch events from the API // Function to fetch events from the API
@ -387,24 +443,39 @@ class DemoMainResource:
// Function to add events to the map // Function to add events to the map
function addEventsToMap(geojson) { function addEventsToMap(geojson) {
// Add a GeoJSON source for events // Remove all existing markers
map.addSource('events', { if (currentMarkers.length > 0) {
type: 'geojson', currentMarkers.forEach(marker => marker.remove());
data: geojson currentMarkers = [];
}); console.log('Removed existing markers');
}
// Add a circle layer for events // Check if the source already exists
map.addLayer({ if (map.getSource('events')) {
id: 'events-circle', // Update the existing source with new data
type: 'circle', map.getSource('events').setData(geojson);
source: 'events', console.log('Updated existing events source with new data');
paint: { } else {
'circle-radius': 8, // Add a new GeoJSON source for events
'circle-color': '#FF5722', map.addSource('events', {
'circle-stroke-width': 2, type: 'geojson',
'circle-stroke-color': '#FFFFFF' data: geojson
} });
});
// Add a circle layer for events
map.addLayer({
id: 'events-circle',
type: 'circle',
source: 'events',
paint: {
'circle-radius': 8,
'circle-color': '#FF5722',
'circle-stroke-width': 2,
'circle-stroke-color': '#FFFFFF'
}
});
console.log('Added new events source and layer');
}
// Add popups for events // Add popups for events
geojson.features.forEach(feature => { geojson.features.forEach(feature => {
@ -531,11 +602,14 @@ class DemoMainResource:
<i class="fas fa-${iconClass}" style="color: ${iconColor}; font-size: 16px;"></i> <i class="fas fa-${iconClass}" style="color: ${iconColor}; font-size: 16px;"></i>
</span>`; </span>`;
// Add marker with popup // Add marker with popup and store reference
new maplibregl.Marker(el) const marker = new maplibregl.Marker(el)
.setLngLat(coordinates) .setLngLat(coordinates)
.setPopup(popup) .setPopup(popup)
.addTo(map); .addTo(map);
// Store marker reference for later removal
currentMarkers.push(marker);
}); });
} }

View file

@ -516,3 +516,11 @@ select:invalid {
min-width: 300px; min-width: 300px;
max-width: 95vw; max-width: 95vw;
} }
.event-popup h3{
font-size: 1.5rem !important;
}
.add-event-btn{
float: left;
width: 130px;
}

View file

@ -96,4 +96,3 @@
font-size: 12px; font-size: 12px;
color: #555; color: #555;
} }