Skip to content

Commit cfb36ce

Browse files
committed
Move dark/light toggle to a button over the map
1 parent cc7b668 commit cfb36ce

2 files changed

Lines changed: 48 additions & 79 deletions

File tree

pcd-website/src/components/MapView.vue

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import { ref, computed, onMounted, onUnmounted } from 'vue';
2+
import { ref, onMounted, onUnmounted } from 'vue';
33
import type { Node } from '../lib/nodes';
44
import { makePopupContent } from '../lib/popup';
55
import NodePanel from './NodePanel.vue';
@@ -21,7 +21,6 @@ interface TileLayerConfig { url: string; options: Record<string, unknown>; }
2121
interface MapStyle { id: string; label: string; layers: TileLayerConfig[]; }
2222
2323
const CARTO_ATTR = '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>';
24-
const ESRI_ATTR = 'Tiles &copy; Esri &mdash; Esri, DeLorme, NAVTEQ, TomTom, Intermap, iPC, USGS, FAO, NPS, NRCAN, GeoBase, Kadaster NL, Ordnance Survey, Esri Japan, METI, Esri China (Hong Kong), and the GIS User Community';
2524
2625
const MAP_STYLES: MapStyle[] = [
2726
{
@@ -52,21 +51,12 @@ const MAP_STYLES: MapStyle[] = [
5251
},
5352
],
5453
},
55-
{
56-
id: 'fun',
57-
label: 'Fun',
58-
layers: [{
59-
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/NatGeo_World_Map/MapServer/tile/{z}/{y}/{x}',
60-
options: { attribution: ESRI_ATTR, maxZoom: 16 },
61-
}],
62-
},
6354
];
6455
6556
const STORAGE_KEY = 'pcd-map-style';
6657
let activeTileLayers: import('leaflet').TileLayer[] = [];
6758
6859
const currentStyle = ref<string>('');
69-
const availableStyles = computed(() => MAP_STYLES.map(s => ({ id: s.id, label: s.label })));
7060
7161
function getInitialStyle(): string {
7262
const stored = localStorage.getItem(STORAGE_KEY);
@@ -89,8 +79,9 @@ function setMapStyle(styleId: string, map: import('leaflet').Map, L: typeof impo
8979
document.documentElement.dataset.theme = styleId === 'dark' ? 'dark' : 'light';
9080
}
9181
92-
function onStyleChange(styleId: string) {
93-
if (mapInstance && leafletRef) setMapStyle(styleId, mapInstance, leafletRef);
82+
function toggleTheme() {
83+
const next = currentStyle.value === 'dark' ? 'light' : 'dark';
84+
if (mapInstance && leafletRef) setMapStyle(next, mapInstance, leafletRef);
9485
}
9586
9687
function setActiveMarker(nodeId: string | null) {
@@ -293,14 +284,25 @@ onUnmounted(() => {
293284
294285
</button>
295286
<NodePanel :node="selectedNode" @close="closePanel" />
287+
<button
288+
id="theme-toggle"
289+
:aria-label="currentStyle === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'"
290+
:title="currentStyle === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'"
291+
@click="toggleTheme"
292+
>
293+
<svg v-if="currentStyle === 'dark'" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
294+
<circle cx="12" cy="12" r="4"/>
295+
<path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/>
296+
</svg>
297+
<svg v-else xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
298+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
299+
</svg>
300+
</button>
296301
<NodeList
297302
:nodes="nodes"
298303
:open="listOpen"
299-
:current-style="currentStyle"
300-
:available-styles="availableStyles"
301304
@close="closeList"
302305
@select="onNodeSelect"
303-
@style-change="onStyleChange"
304306
/>
305307
</template>
306308

@@ -313,6 +315,36 @@ onUnmounted(() => {
313315
height: 100vh;
314316
z-index: 0;
315317
}
318+
319+
#theme-toggle {
320+
position: fixed;
321+
top: 1rem;
322+
right: 1rem;
323+
z-index: var(--z-controls);
324+
width: 40px;
325+
height: 40px;
326+
display: flex;
327+
align-items: center;
328+
justify-content: center;
329+
background: var(--color-bg-popup);
330+
border: 1px solid var(--color-border);
331+
border-radius: 8px;
332+
cursor: pointer;
333+
color: var(--color-text);
334+
transition: background-color 0.12s ease, color 0.12s ease, border-color 0.12s ease;
335+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
336+
}
337+
338+
#theme-toggle:hover {
339+
background: var(--color-primary);
340+
color: #fff;
341+
border-color: var(--color-primary);
342+
}
343+
344+
#theme-toggle:focus-visible {
345+
outline: 2px solid var(--color-focus);
346+
outline-offset: 2px;
347+
}
316348
</style>
317349

318350
<style>

pcd-website/src/components/NodeList.vue

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,14 @@ import { createFocusTrap, type FocusTrap } from 'focus-trap';
44
import type { Node } from '../lib/nodes';
55
import { formatDateRange } from '../lib/format';
66
7-
interface StyleOption { id: string; label: string; }
8-
97
const props = defineProps<{
108
nodes: Node[];
119
open: boolean;
12-
currentStyle: string;
13-
availableStyles: StyleOption[];
1410
}>();
1511
1612
const emit = defineEmits<{
1713
close: [];
1814
select: [node: Node];
19-
'style-change': [styleId: string];
2015
}>();
2116
2217
const containerRef = ref<HTMLElement | null>(null);
@@ -104,20 +99,6 @@ function handleKeydown(e: KeyboardEvent) {
10499
</button>
105100
</div>
106101

107-
<div class="style-selector">
108-
<p class="style-label">Map style</p>
109-
<div class="style-buttons" role="group" aria-label="Map style">
110-
<button
111-
v-for="style in availableStyles"
112-
:key="style.id"
113-
class="style-btn"
114-
:class="{ 'style-btn--active': style.id === currentStyle }"
115-
:aria-pressed="style.id === currentStyle"
116-
@click="emit('style-change', style.id)"
117-
>{{ style.label }}</button>
118-
</div>
119-
</div>
120-
121102
<ul class="list-items">
122103
<li v-for="node in sortedNodes" :key="node.id">
123104
<button
@@ -240,49 +221,5 @@ function handleKeydown(e: KeyboardEvent) {
240221
color: var(--color-text-muted);
241222
}
242223
243-
.style-selector {
244-
padding: 0.75rem 1rem 1.25rem;
245-
border-bottom: 1px solid var(--color-border);
246-
}
247-
248-
.style-label {
249-
margin: 0 0 0.5rem;
250-
font-size: 0.75rem;
251-
font-weight: 600;
252-
color: var(--color-text-muted);
253-
text-transform: uppercase;
254-
letter-spacing: 0.06em;
255-
}
256-
257-
.style-buttons {
258-
display: flex;
259-
flex-wrap: wrap;
260-
gap: 0.375rem;
261-
}
262-
263-
.style-btn {
264-
padding: 0.3125rem 0.625rem;
265-
font-size: 0.8125rem;
266-
font-family: var(--font-family);
267-
background: transparent;
268-
border: 1px solid var(--color-border);
269-
border-radius: 4px;
270-
cursor: pointer;
271-
color: var(--color-text);
272-
transition: background-color 0.1s ease, border-color 0.1s ease;
273-
}
274-
275-
.style-btn:hover {
276-
background: #f5f5f5;
277-
}
278224
279-
.style-btn--active {
280-
background: #5601A4;
281-
border-color: #5601A4;
282-
color: #fff;
283-
}
284-
285-
.style-btn--active:hover {
286-
background: #6a01c8;
287-
}
288225
</style>

0 commit comments

Comments
 (0)