mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-13 02:31:39 -05:00
Make popups respect dark theme
This commit is contained in:
parent
756cda06f6
commit
39307e1bb3
6 changed files with 72 additions and 39 deletions
|
|
@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||
- Heatmap and Fog of War now are moving correctly during map interactions. #1798
|
||||
- Polyline crossing international date line now are rendered correctly. #1162
|
||||
- Place popup tags parsing (MapLibre GL JS compatibility)
|
||||
- Stats calculation should be faster now.
|
||||
|
||||
## Changed
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { formatTimestamp } from '../utils/geojson_transformers'
|
||||
import { getCurrentTheme, getThemeColors } from '../utils/popup_theme'
|
||||
|
||||
/**
|
||||
* Factory for creating map popups
|
||||
|
|
@ -12,38 +13,42 @@ export class PopupFactory {
|
|||
static createPointPopup(properties) {
|
||||
const { id, timestamp, altitude, battery, accuracy, velocity } = properties
|
||||
|
||||
// Get theme colors
|
||||
const theme = getCurrentTheme()
|
||||
const colors = getThemeColors(theme)
|
||||
|
||||
return `
|
||||
<div class="point-popup">
|
||||
<div class="popup-header">
|
||||
<div class="point-popup" style="color: ${colors.textPrimary};">
|
||||
<div class="popup-header" style="border-bottom: 1px solid ${colors.border};">
|
||||
<strong>Point #${id}</strong>
|
||||
</div>
|
||||
<div class="popup-body">
|
||||
<div class="popup-row">
|
||||
<span class="label">Time:</span>
|
||||
<span class="value">${formatTimestamp(timestamp)}</span>
|
||||
<span class="label" style="color: ${colors.textMuted};">Time:</span>
|
||||
<span class="value" style="color: ${colors.textPrimary};">${formatTimestamp(timestamp)}</span>
|
||||
</div>
|
||||
${altitude ? `
|
||||
<div class="popup-row">
|
||||
<span class="label">Altitude:</span>
|
||||
<span class="value">${Math.round(altitude)}m</span>
|
||||
<span class="label" style="color: ${colors.textMuted};">Altitude:</span>
|
||||
<span class="value" style="color: ${colors.textPrimary};">${Math.round(altitude)}m</span>
|
||||
</div>
|
||||
` : ''}
|
||||
${battery ? `
|
||||
<div class="popup-row">
|
||||
<span class="label">Battery:</span>
|
||||
<span class="value">${battery}%</span>
|
||||
<span class="label" style="color: ${colors.textMuted};">Battery:</span>
|
||||
<span class="value" style="color: ${colors.textPrimary};">${battery}%</span>
|
||||
</div>
|
||||
` : ''}
|
||||
${accuracy ? `
|
||||
<div class="popup-row">
|
||||
<span class="label">Accuracy:</span>
|
||||
<span class="value">${Math.round(accuracy)}m</span>
|
||||
<span class="label" style="color: ${colors.textMuted};">Accuracy:</span>
|
||||
<span class="value" style="color: ${colors.textPrimary};">${Math.round(accuracy)}m</span>
|
||||
</div>
|
||||
` : ''}
|
||||
${velocity ? `
|
||||
<div class="popup-row">
|
||||
<span class="label">Speed:</span>
|
||||
<span class="value">${Math.round(velocity * 3.6)} km/h</span>
|
||||
<span class="label" style="color: ${colors.textMuted};">Speed:</span>
|
||||
<span class="value" style="color: ${colors.textPrimary};">${Math.round(velocity * 3.6)} km/h</span>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
|
|
@ -59,6 +64,10 @@ export class PopupFactory {
|
|||
static createPlacePopup(properties) {
|
||||
const { id, name, latitude, longitude, note, tags } = properties
|
||||
|
||||
// Get theme colors
|
||||
const theme = getCurrentTheme()
|
||||
const colors = getThemeColors(theme)
|
||||
|
||||
// Parse tags if they're stringified
|
||||
let parsedTags = tags
|
||||
if (typeof tags === 'string') {
|
||||
|
|
@ -76,27 +85,27 @@ export class PopupFactory {
|
|||
${tag.icon} #${tag.name}
|
||||
</span>
|
||||
`).join(' ')
|
||||
: '<span class="badge badge-sm badge-outline">Untagged</span>'
|
||||
: `<span class="badge badge-sm badge-outline" style="border-color: ${colors.border}; color: ${colors.textMuted};">Untagged</span>`
|
||||
|
||||
return `
|
||||
<div class="place-popup">
|
||||
<div class="popup-header">
|
||||
<div class="place-popup" style="color: ${colors.textPrimary};">
|
||||
<div class="popup-header" style="border-bottom: 1px solid ${colors.border};">
|
||||
<strong>${name || `Place #${id}`}</strong>
|
||||
</div>
|
||||
<div class="popup-body">
|
||||
${note ? `
|
||||
<div class="popup-row">
|
||||
<span class="label">Note:</span>
|
||||
<span class="value">${note}</span>
|
||||
<span class="label" style="color: ${colors.textMuted};">Note:</span>
|
||||
<span class="value" style="color: ${colors.textPrimary};">${note}</span>
|
||||
</div>
|
||||
` : ''}
|
||||
<div class="popup-row">
|
||||
<span class="label">Tags:</span>
|
||||
<span class="label" style="color: ${colors.textMuted};">Tags:</span>
|
||||
<div class="value">${tagsHtml}</div>
|
||||
</div>
|
||||
<div class="popup-row">
|
||||
<span class="label">Coordinates:</span>
|
||||
<span class="value">${latitude.toFixed(5)}, ${longitude.toFixed(5)}</span>
|
||||
<span class="label" style="color: ${colors.textMuted};">Coordinates:</span>
|
||||
<span class="value" style="color: ${colors.textPrimary};">${latitude.toFixed(5)}, ${longitude.toFixed(5)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { formatTimestamp } from '../utils/geojson_transformers'
|
||||
import { getCurrentTheme, getThemeColors } from '../utils/popup_theme'
|
||||
|
||||
/**
|
||||
* Factory for creating visit popups
|
||||
|
|
@ -17,6 +18,10 @@ export class VisitPopupFactory {
|
|||
const durationHours = Math.round(duration / 3600)
|
||||
const durationDisplay = durationHours >= 1 ? `${durationHours}h` : `${Math.round(duration / 60)}m`
|
||||
|
||||
// Get theme colors
|
||||
const theme = getCurrentTheme()
|
||||
const colors = getThemeColors(theme)
|
||||
|
||||
return `
|
||||
<div class="visit-popup">
|
||||
<div class="popup-header">
|
||||
|
|
@ -54,7 +59,7 @@ export class VisitPopupFactory {
|
|||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
border-bottom: 1px solid ${colors.border};
|
||||
}
|
||||
|
||||
.visit-badge {
|
||||
|
|
@ -67,13 +72,13 @@ export class VisitPopupFactory {
|
|||
}
|
||||
|
||||
.visit-badge.suggested {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
background: ${colors.badgeSuggested.bg};
|
||||
color: ${colors.badgeSuggested.text};
|
||||
}
|
||||
|
||||
.visit-badge.confirmed {
|
||||
background: #d1fae5;
|
||||
color: #065f46;
|
||||
background: ${colors.badgeConfirmed.bg};
|
||||
color: ${colors.badgeConfirmed.text};
|
||||
}
|
||||
|
||||
.popup-body {
|
||||
|
|
@ -89,24 +94,24 @@ export class VisitPopupFactory {
|
|||
}
|
||||
|
||||
.popup-row .label {
|
||||
color: #6b7280;
|
||||
color: ${colors.textMuted};
|
||||
}
|
||||
|
||||
.popup-row .value {
|
||||
font-weight: 500;
|
||||
color: #111827;
|
||||
color: ${colors.textPrimary};
|
||||
}
|
||||
|
||||
.popup-footer {
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
border-top: 1px solid ${colors.border};
|
||||
}
|
||||
|
||||
.view-details-btn {
|
||||
display: block;
|
||||
text-align: center;
|
||||
padding: 6px 12px;
|
||||
background: #3b82f6;
|
||||
background: ${colors.accent};
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 6px;
|
||||
|
|
@ -116,7 +121,7 @@ export class VisitPopupFactory {
|
|||
}
|
||||
|
||||
.view-details-btn:hover {
|
||||
background: #2563eb;
|
||||
background: ${colors.accentHover};
|
||||
}
|
||||
</style>
|
||||
`
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { BaseLayer } from './base_layer'
|
||||
import maplibregl from 'maplibre-gl'
|
||||
import { getCurrentTheme, getThemeColors } from '../utils/popup_theme'
|
||||
|
||||
/**
|
||||
* Photos layer with thumbnail markers
|
||||
|
|
@ -131,10 +132,14 @@ export class PhotosLayer extends BaseLayer {
|
|||
const location = [city, state, country].filter(Boolean).join(', ') || 'Unknown location'
|
||||
const mediaType = type === 'VIDEO' ? '🎥 Video' : '📷 Photo'
|
||||
|
||||
// Create popup HTML with thumbnail image
|
||||
// Get theme colors
|
||||
const theme = getCurrentTheme()
|
||||
const colors = getThemeColors(theme)
|
||||
|
||||
// Create popup HTML with theme-aware styling
|
||||
const popupHTML = `
|
||||
<div class="photo-popup" style="font-family: system-ui, -apple-system, sans-serif; max-width: 350px;">
|
||||
<div style="width: 100%; border-radius: 8px; overflow: hidden; margin-bottom: 12px; background: #f3f4f6;">
|
||||
<div style="width: 100%; border-radius: 8px; overflow: hidden; margin-bottom: 12px; background: ${colors.backgroundAlt};">
|
||||
<img
|
||||
src="${thumbnail_url}"
|
||||
alt="${filename || 'Photo'}"
|
||||
|
|
@ -143,12 +148,12 @@ export class PhotosLayer extends BaseLayer {
|
|||
/>
|
||||
</div>
|
||||
<div style="font-size: 13px;">
|
||||
${filename ? `<div style="font-weight: 600; color: #111827; margin-bottom: 6px; word-wrap: break-word;">${filename}</div>` : ''}
|
||||
<div style="color: #6b7280; font-size: 12px; margin-bottom: 6px;">📅 ${takenDate}</div>
|
||||
<div style="color: #6b7280; font-size: 12px; margin-bottom: 6px;">📍 ${location}</div>
|
||||
<div style="color: #6b7280; font-size: 12px; margin-bottom: 6px;">Coordinates: ${lat.toFixed(6)}, ${lng.toFixed(6)}</div>
|
||||
${source ? `<div style="color: #9ca3af; font-size: 11px; margin-bottom: 6px;">Source: ${source}</div>` : ''}
|
||||
<div style="font-size: 14px; margin-top: 8px;">${mediaType}</div>
|
||||
${filename ? `<div style="font-weight: 600; color: ${colors.textPrimary}; margin-bottom: 6px; word-wrap: break-word;">${filename}</div>` : ''}
|
||||
<div style="color: ${colors.textMuted}; font-size: 12px; margin-bottom: 6px;">📅 ${takenDate}</div>
|
||||
<div style="color: ${colors.textMuted}; font-size: 12px; margin-bottom: 6px;">📍 ${location}</div>
|
||||
<div style="color: ${colors.textMuted}; font-size: 12px; margin-bottom: 6px;">Coordinates: ${lat.toFixed(6)}, ${lng.toFixed(6)}</div>
|
||||
${source ? `<div style="color: ${colors.textSecondary}; font-size: 11px; margin-bottom: 6px;">Source: ${source}</div>` : ''}
|
||||
<div style="font-size: 14px; margin-top: 8px; color: ${colors.textPrimary};">${mediaType}</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
class AddUserIdReverseGeocodedAtIndexToPoints < ActiveRecord::Migration[8.0]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def change
|
||||
add_index :points,
|
||||
[:user_id, :reverse_geocoded_at],
|
||||
where: 'reverse_geocoded_at IS NOT NULL',
|
||||
algorithm: :concurrently,
|
||||
name: 'index_points_on_user_id_and_reverse_geocoded_at',
|
||||
if_not_exists: true
|
||||
end
|
||||
end
|
||||
3
db/schema.rb
generated
3
db/schema.rb
generated
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_11_18_210506) do
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_12_01_192510) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_catalog.plpgsql"
|
||||
enable_extension "postgis"
|
||||
|
|
@ -243,6 +243,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_11_18_210506) do
|
|||
t.index ["track_id"], name: "index_points_on_track_id"
|
||||
t.index ["trigger"], name: "index_points_on_trigger"
|
||||
t.index ["user_id", "country_name"], name: "idx_points_user_country_name"
|
||||
t.index ["user_id", "reverse_geocoded_at"], name: "index_points_on_user_id_and_reverse_geocoded_at", where: "(reverse_geocoded_at IS NOT NULL)"
|
||||
t.index ["user_id", "timestamp", "track_id"], name: "idx_points_track_generation"
|
||||
t.index ["user_id"], name: "index_points_on_user_id"
|
||||
t.index ["visit_id"], name: "index_points_on_visit_id"
|
||||
|
|
|
|||
Loading…
Reference in a new issue