Enhance frontend components and introduce new features

- Added a custom light theme in app.css to match the dark theme's palette.
- Introduced AdminBreadcrumbs component for improved navigation in admin pages.
- Implemented Skeleton component for loading states in various views.
- Added ToastContainer for displaying notifications and alerts.
- Enhanced MapView with loading indicators and improved marker handling.
- Updated MapCoordsDisplay to allow copying of shareable links.
- Refactored MapControls and MapContextMenu for better usability.
- Improved user experience in profile and admin pages with loading states and search functionality.
This commit is contained in:
2026-03-01 15:19:55 +03:00
parent 6529d7370e
commit 2bd2c8dbca
15 changed files with 817 additions and 212 deletions

View File

@@ -26,6 +26,10 @@ export interface MapLayersOptions {
getTrackingCharacterId: () => number
setTrackingCharacterId: (id: number) => void
onMarkerContextMenu: (clientX: number, clientY: number, id: number, name: string) => void
/** Resolves relative marker icon path to absolute URL. If omitted, relative paths are used. */
resolveIconUrl?: (path: string) => string
/** Fallback icon URL when a marker image fails to load. */
fallbackIconUrl?: string
}
export interface MapLayersManager {
@@ -55,6 +59,8 @@ export function createMapLayers(options: MapLayersOptions): MapLayersManager {
getTrackingCharacterId,
setTrackingCharacterId,
onMarkerContextMenu,
resolveIconUrl,
fallbackIconUrl,
} = options
const markers = createUniqueList<MapMarker>()
@@ -93,9 +99,13 @@ export function createMapLayers(options: MapLayersOptions): MapLayersManager {
function updateMarkers(markersData: ApiMarker[]) {
const list = Array.isArray(markersData) ? markersData : []
const ctx = markerCtx()
const iconOptions =
resolveIconUrl != null
? { resolveIconUrl, fallbackIconUrl }
: undefined
uniqueListUpdate(
markers,
list.map((it) => createMarker(it as MarkerData)),
list.map((it) => createMarker(it as MarkerData, iconOptions)),
(marker: MapMarker) => {
if (marker.map === getCurrentMapId() || marker.map === overlayLayer.map) marker.add(ctx)
marker.setClickCallback(() => {