Skip to content

[draft][work-in-progress] add event map#757

Draft
bubelov wants to merge 1 commit intomainfrom
event-map
Draft

[draft][work-in-progress] add event map#757
bubelov wants to merge 1 commit intomainfrom
event-map

Conversation

@bubelov
Copy link
Collaborator

@bubelov bubelov commented Feb 26, 2026

Summary by CodeRabbit

  • New Features
    • Added Event Map feature accessible from the maps dropdown navigation menu
    • Interactive map displays event locations with full event details, dates, and website links
    • Dark mode theming and responsive design for optimal viewing across devices
    • Geolocation, scale indicator, multiple map layers, and "locate me" controls for seamless navigation

@netlify
Copy link

netlify bot commented Feb 26, 2026

Deploy Preview for btcmap ready!

Name Link
🔨 Latest commit 9d0f876
🔍 Latest deploy log https://app.netlify.com/projects/btcmap/deploys/69a02179cf26a30008a0444e
😎 Deploy Preview https://deploy-preview-757--btcmap.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 56 (🔴 down 25 from production)
Accessibility: 97 (no change from production)
Best Practices: 92 (🔴 down 8 from production)
SEO: 99 (no change from production)
PWA: 90 (no change from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@escapedcat escapedcat marked this pull request as draft February 26, 2026 10:34
@coderabbitai
Copy link

coderabbitai bot commented Feb 26, 2026

📝 Walkthrough

Walkthrough

A new Event Map feature is introduced with navigation UI entry, supporting type definitions, layout routing configuration, and an interactive Leaflet-based map page displaying geolocated events with popups, controls, and dark mode support.

Changes

Cohort / File(s) Summary
Navigation & UI
src/components/layout/Header.svelte, src/lib/i18n/locales/en.json, src/routes/+layout.svelte
Added Event Map dropdown entry in header with i18n key, and configured minimal layout rendering for /events/map route.
Type Definitions
src/lib/types.ts
Introduced EventMapEvent type with geolocation and event details fields; expanded ProgressUpdate interface with item counts and status tracking.
Event Map Page
src/routes/events/map/+page.svelte
New interactive map component with async event API loading, Leaflet initialization, event marker creation with popups, map controls (geolocation, scale, layers, home marker), hash-based view persistence, dark mode support, and lifecycle cleanup.

Sequence Diagram

sequenceDiagram
    participant User as User/Client
    participant Page as +page.svelte
    participant API as External API
    participant Map as Leaflet Map
    participant DOM as DOM/UI

    User->>Page: Mount component
    Page->>Page: onMount triggered
    Page->>API: Fetch events data
    API-->>Page: Event array returned
    Page->>Map: Load Leaflet dependencies
    Map-->>Page: Dependencies loaded
    Page->>Map: Initialize map instance
    Page->>Map: Configure base layers & controls
    Page->>Map: Add attribution, scale, geolocation
    Page->>Page: Check if mapLoaded && events exist
    Page->>Map: Create markers for each event
    Map->>DOM: Render markers with popups
    Map->>DOM: Apply dark mode styling
    DOM-->>User: Interactive map displayed
    User->>Map: Interact with map (pan/zoom)
    Page->>Page: Update URL hash with view state
    User->>Page: Unmount component
    Page->>Map: onDestroy - remove markers
    Page->>Map: Destroy map instance
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~35 minutes

Possibly related PRs

  • PR #677: Introduces i18n-backed navigation header structure that this PR's Event Map dropdown entry depends on.
  • PR #711: Modifies src/routes/+layout.svelte to alter layout rendering, intersecting with this PR's minimal layout route configuration.

Suggested labels

Review effort 4/5

Suggested reviewers

  • dadofsambonzuki
  • escapedcat

Poem

Across digital meadows the markers now hop, 🗺️
Where events and locations shall never stop,
Leaflet leaves trace each gathering place,
Dark themes embrace with elegant grace,
The map comes alive—a rabbit's delight! 🐰✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning No pull request description was provided by the author, and the required template sections (issue reference, change description, screenshots, context) are entirely missing. Add a comprehensive pull request description following the template: explain which issue this addresses, describe the proposed changes, include relevant screenshots, and provide additional context about the implementation.
Title check ❓ Inconclusive The title '[draft][work-in-progress] add event map' is vague and uses non-descriptive markers that don't convey meaningful information about the changeset beyond indicating incomplete work. Provide a more descriptive title that explains the specific changes, such as 'Add interactive event map page with Leaflet integration' or similar, once the work is ready for review.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch event-map

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/routes/events/map/`+page.svelte:
- Line 92: The reactive guard currently checks events?.length which prevents
initializeEvents() from running when events is an empty array or error result;
update the reactive statement so it triggers when events is defined (e.g.,
events != null or typeof events !== "undefined") along with mapLoaded &&
!eventsLoaded, so initializeEvents() always runs even for empty results and
allows mapLoading to finish; update the reactive line referencing events,
mapLoaded, eventsLoaded, and initializeEvents accordingly.
- Around line 44-71: The popup uses innerHTML with unescaped interpolations
(popupContainer.innerHTML) of untrusted fields event.name and event.website,
enabling DOM XSS; to fix, stop injecting raw HTML: build the popup DOM using
safe methods (createElement, textContent, setAttribute) or sanitize/validate
inputs before inserting, ensure links use safe hrefs (reject or strip
javascript: schemes) when creating the anchor for event.website, and keep
theme-related style insertion controlled (use a CSS class toggle using
currentMapTheme instead of injecting <style> with string interpolation).
Reference popupContainer, event.name, event.website and currentMapTheme to
locate and replace the innerHTML assignment with DOM-safe construction.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fddd69a and 9d0f876.

📒 Files selected for processing (5)
  • src/components/layout/Header.svelte
  • src/lib/i18n/locales/en.json
  • src/lib/types.ts
  • src/routes/+layout.svelte
  • src/routes/events/map/+page.svelte

Comment on lines +44 to +71
popupContainer.innerHTML = `
<div class='text-center space-y-2'>
<span class='text-primary dark:text-white font-semibold text-xl' title='Event name'>${event.name}</span>

${
event.website
? `<a href="${event.website}" target="_blank" rel="noopener noreferrer" class='block mt-4 bg-link hover:bg-hover !text-white text-center font-semibold py-3 rounded-xl transition-colors' title='Event website'>Visit Website</a>`
: ""
}
</div>

${
currentMapTheme === "dark"
? `
<style>
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
background-color: #06171C;
border: 1px solid #e5e7eb
}

.leaflet-popup-close-button {
font-size: 24px !important;
top: 4px !important;
right: 4px !important;
}
</style>`
: ""
}`;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Prevent DOM XSS in popup rendering.

Untrusted API fields (event.name, event.website) are interpolated into innerHTML. That enables script/attribute injection (including unsafe javascript: URLs).

🔐 Suggested fix
+const safeExternalUrl = (value: string): string | null => {
+	try {
+		const parsed = new URL(value);
+		return parsed.protocol === "https:" || parsed.protocol === "http:"
+			? parsed.toString()
+			: null;
+	} catch {
+		return null;
+	}
+};

 events.forEach((event: EventMapEvent) => {
-	const popupContainer = leaflet.DomUtil.create("div");
-	popupContainer.innerHTML = `
-		<div class='text-center space-y-2'>
-			<span class='text-primary dark:text-white font-semibold text-xl' title='Event name'>${event.name}</span>
-			${event.website ? `<a href="${event.website}" ...>Visit Website</a>` : ""}
-		</div>
-		...`;
+	const popupContainer = leaflet.DomUtil.create("div", "text-center space-y-2");
+	const title = leaflet.DomUtil.create(
+		"span",
+		"text-primary dark:text-white font-semibold text-xl",
+		popupContainer,
+	);
+	title.title = "Event name";
+	title.textContent = event.name;
+
+	const website = event.website ? safeExternalUrl(event.website) : null;
+	if (website) {
+		const link = leaflet.DomUtil.create(
+			"a",
+			"block mt-4 bg-link hover:bg-hover !text-white text-center font-semibold py-3 rounded-xl transition-colors",
+			popupContainer,
+		) as HTMLAnchorElement;
+		link.href = website;
+		link.target = "_blank";
+		link.rel = "noopener noreferrer";
+		link.title = "Event website";
+		link.textContent = "Visit Website";
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/routes/events/map/`+page.svelte around lines 44 - 71, The popup uses
innerHTML with unescaped interpolations (popupContainer.innerHTML) of untrusted
fields event.name and event.website, enabling DOM XSS; to fix, stop injecting
raw HTML: build the popup DOM using safe methods (createElement, textContent,
setAttribute) or sanitize/validate inputs before inserting, ensure links use
safe hrefs (reject or strip javascript: schemes) when creating the anchor for
event.website, and keep theme-related style insertion controlled (use a CSS
class toggle using currentMapTheme instead of injecting <style> with string
interpolation). Reference popupContainer, event.name, event.website and
currentMapTheme to locate and replace the innerHTML assignment with DOM-safe
construction.

eventsLoaded = true;
};

$: events?.length && mapLoaded && !eventsLoaded && initializeEvents();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Loading can get stuck at 40% when no events are returned.

The reactive guard requires events.length, so initializeEvents() never runs for empty/error results, and mapLoading never reaches completion.

✅ Suggested fix
-$: events?.length && mapLoaded && !eventsLoaded && initializeEvents();
+$: if (mapLoaded && !eventsLoaded) {
+	initializeEvents();
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$: events?.length && mapLoaded && !eventsLoaded && initializeEvents();
$: if (mapLoaded && !eventsLoaded) {
initializeEvents();
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/routes/events/map/`+page.svelte at line 92, The reactive guard currently
checks events?.length which prevents initializeEvents() from running when events
is an empty array or error result; update the reactive statement so it triggers
when events is defined (e.g., events != null or typeof events !== "undefined")
along with mapLoaded && !eventsLoaded, so initializeEvents() always runs even
for empty results and allows mapLoading to finish; update the reactive line
referencing events, mapLoaded, eventsLoaded, and initializeEvents accordingly.

@bubelov
Copy link
Collaborator Author

bubelov commented Mar 5, 2026

This PR is deliberately non-invasive, so the chances to affect the main map are minimal. Merging with the main map can be considered in the future, but I think it makes sense to have a separate sandbox until we know what we want and until we see more public interest and a core of active maintainers.

Any feedback for the first version? Clustering would be an overkill with the current number of events, and we don't have any extra fields to display at the moment, so I guess translations is the only thing missing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant