diff --git a/admin/class-spotmap-admin.php b/admin/class-spotmap-admin.php
index 1c8c192..f329d38 100644
--- a/admin/class-spotmap-admin.php
+++ b/admin/class-spotmap-admin.php
@@ -85,6 +85,7 @@ public function enqueue_scripts($hook)
'feeds' => $this->db->get_all_feednames(),
'defaultValues' => Spotmap_Options::get_settings(),
'marker' => Spotmap_Options::get_marker_options(),
+ 'isLoggedIn' => true,
]);
}
diff --git a/public/class-spotmap-public.php b/public/class-spotmap-public.php
index 119ad46..add4a73 100644
--- a/public/class-spotmap-public.php
+++ b/public/class-spotmap-public.php
@@ -152,6 +152,7 @@ function localize_js_script($script_slug){
'defaultValues' => $default_values,
'marker' => Spotmap_Options::get_marker_options(),
'postsFeedNames' => array_values( array_column( $posts_type_feeds, 'name' ) ),
+ 'isLoggedIn' => is_user_logged_in(),
]);
}
diff --git a/src/map-engine/Spotmap.ts b/src/map-engine/Spotmap.ts
index b10413b..ed955e6 100644
--- a/src/map-engine/Spotmap.ts
+++ b/src/map-engine/Spotmap.ts
@@ -51,6 +51,7 @@ export class Spotmap {
private onVisibilityChange: ( () => void ) | null = null;
private reloadBody: AjaxRequestBody | null = null;
private lodManager: LodManager | null = null;
+ private emptyStatePopup: L.Popup | null = null;
constructor( options: SpotmapOptions ) {
this.options = options;
@@ -165,11 +166,6 @@ export class Spotmap {
el as HTMLElement & { _spotmapOptions?: SpotmapOptions }
)._spotmapOptions = this.options;
- // Remove any empty-state overlay left over from a previous render
- el.querySelectorAll( '.spotmap-empty-state' ).forEach( ( n ) =>
- n.remove()
- );
-
if ( ( el as HTMLElement & { _leaflet_id?: number } )._leaflet_id ) {
if (
JSON.stringify( this.options ) === JSON.stringify( oldOptions )
@@ -411,6 +407,10 @@ export class Spotmap {
// during teardown and crashes. Setting text to null first makes
// _textRedraw a no-op for that final render pass.
this.lineManager?.clearArrows();
+ if ( this.emptyStatePopup ) {
+ this.map.closePopup( this.emptyStatePopup );
+ this.emptyStatePopup = null;
+ }
this.map.remove();
}
}
@@ -547,65 +547,50 @@ export class Spotmap {
}
private showEmptyState(): void {
- const container = this.map.getContainer();
-
- // Build a human-readable summary of active filters
- const parts: string[] = [];
-
- let feeds: string[];
- if ( Array.isArray( this.options.feeds ) ) {
- feeds = this.options.feeds;
- } else if ( this.options.feeds ) {
- feeds = String( this.options.feeds )
- .split( ',' )
- .map( ( f ) => f.trim() )
- .filter( Boolean );
- } else {
- feeds = [];
+ if ( this.emptyStatePopup ) {
+ return;
}
- if ( feeds.length > 0 ) {
- parts.push( `Feeds: ${ feeds.join( ', ' ) }` );
- }
+ this.map.setView( [ 0, 0 ], 12, { animate: false } );
- const { from, to } = this.options.dateRange ?? {};
- if ( from || to ) {
- const range = [ from, to ].filter( Boolean ).join( ' – ' );
- parts.push( `Date range: ${ range }` );
- }
+ let detail = '';
+ if ( spotmapjsobj.isLoggedIn ) {
+ const parts: string[] = [];
+ const feeds = this.options.feeds;
- const overlay = document.createElement( 'div' );
- overlay.className = 'spotmap-empty-state';
- overlay.style.cssText = [
- 'position:absolute',
- 'inset:0',
- 'z-index:1000',
- 'display:flex',
- 'flex-direction:column',
- 'align-items:center',
- 'justify-content:center',
- 'background:#f0f0f0',
- 'color:#666',
- 'gap:8px',
- 'text-align:center',
- 'padding:16px',
- 'font-size:14px',
- 'line-height:1.4',
- ].join( ';' );
-
- const title = document.createElement( 'strong' );
- title.textContent = 'No points to display';
- overlay.appendChild( title );
-
- const detail = document.createElement( 'span' );
- detail.textContent =
- parts.length > 0
+ if ( feeds.length > 0 ) {
+ parts.push( `Feeds: ${ feeds.join( ', ' ) }` );
+ }
+
+ const { from, to } = this.options.dateRange ?? {};
+ if ( from || to ) {
+ parts.push( `Date range: ${ [ from, to ].filter( Boolean ).join( ' – ' ) }` );
+ }
+
+ detail = parts.length > 0
? `No tracking data was found for ${ parts.join( ', ' ) }.`
: 'No tracking data has been stored yet.';
- overlay.appendChild( detail );
+ }
- // Leaflet already sets position:relative on the container
- container.appendChild( overlay );
+ const content = `No points to display${
+ detail ? `
${ detail }` : ''
+ }`;
+
+ this.emptyStatePopup = L.popup( {
+ closeButton: false,
+ closeOnClick: false,
+ autoClose: false,
+ } )
+ .setLatLng( [ 0, 0 ] )
+ .setContent( content )
+ .openOn( this.map );
+
+ const tip = this.emptyStatePopup
+ .getElement()
+ ?.querySelector< HTMLElement >( '.leaflet-popup-tip-container' );
+ if ( tip ) {
+ tip.style.display = 'none';
+ }
}
private startAutoReload( body: AjaxRequestBody ): void {
diff --git a/src/map-engine/types.ts b/src/map-engine/types.ts
index 228b5bd..1803777 100644
--- a/src/map-engine/types.ts
+++ b/src/map-engine/types.ts
@@ -7,6 +7,7 @@ export interface SpotmapGlobal {
feeds: string[];
defaultValues: Record< string, unknown >;
marker: Record< string, MarkerTypeConfig >;
+ isLoggedIn: boolean;
}
export interface TileLayerConfig {