Skip to content

Commit d624813

Browse files
committed
feat(navbar): move unit selection into a settings menu
Replace the inline °C/°F + mm/in toggle with a gear-icon dropdown so the navbar has room to breathe. Switch the header to a 3-column grid (logo · search · settings) so the search bar can use more horizontal space while staying centered. Assisted-by: Claude:claude-sonnet-4-5
1 parent e2fc23c commit d624813

3 files changed

Lines changed: 100 additions & 29 deletions

File tree

src/components/LocationBar.vue

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { ref, watch } from "vue";
55
import { searchLocations, formatLocation, type GeocodingResult } from "@/api/geocoding";
66
import { useLocation, type Location } from "@/composables/useLocation";
77
8-
import UnitsToggle from "./UnitsToggle.vue";
8+
import SettingsMenu from "./SettingsMenu.vue";
99
1010
const { favourites, recent, setLocation } = useLocation();
1111
@@ -105,12 +105,12 @@ function geolocate(): void {
105105

106106
<template>
107107
<header ref="root" class="sticky top-0 z-30 border-b border-slate-800 bg-slate-950/90 backdrop-blur">
108-
<div class="mx-auto flex max-w-4xl items-center gap-3 px-4 py-3 sm:px-6">
109-
<div class="flex flex-shrink-0 items-baseline gap-2">
108+
<div class="mx-auto grid max-w-4xl grid-cols-[1fr_minmax(0,36rem)_1fr] items-center gap-3 px-4 py-3 sm:px-6">
109+
<div class="flex items-baseline justify-self-start">
110110
<span class="text-lg font-semibold tracking-tight sm:text-xl">MeteoCompare</span>
111111
</div>
112112

113-
<div class="relative max-w-md flex-1">
113+
<div class="relative w-full">
114114
<input
115115
v-model="query"
116116
type="search"
@@ -194,7 +194,9 @@ function geolocate(): void {
194194
</div>
195195
</div>
196196

197-
<UnitsToggle />
197+
<div class="flex justify-self-end">
198+
<SettingsMenu />
199+
</div>
198200
</div>
199201
</header>
200202
</template>

src/components/SettingsMenu.vue

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<script setup lang="ts">
2+
import { onClickOutside } from "@vueuse/core";
3+
import { ref } from "vue";
4+
5+
import { useUnits, type PrecipitationUnit, type TemperatureUnit } from "@/composables/useUnits";
6+
7+
const { temp, precip } = useUnits();
8+
9+
const isOpen = ref(false);
10+
const root = ref<HTMLElement | null>(null);
11+
12+
onClickOutside(root, () => (isOpen.value = false));
13+
14+
const tempOptions: { value: TemperatureUnit; label: string }[] = [
15+
{ value: "c", label: "°C" },
16+
{ value: "f", label: "°F" },
17+
];
18+
const precipOptions: { value: PrecipitationUnit; label: string }[] = [
19+
{ value: "mm", label: "mm" },
20+
{ value: "in", label: "in" },
21+
];
22+
</script>
23+
24+
<template>
25+
<div ref="root" class="relative">
26+
<button
27+
type="button"
28+
class="flex items-center justify-center rounded-md border border-slate-800 p-2 text-slate-300 transition-colors hover:border-slate-600 hover:text-sky-300"
29+
:aria-expanded="isOpen"
30+
aria-haspopup="true"
31+
title="Settings"
32+
@click="isOpen = !isOpen"
33+
>
34+
<svg
35+
xmlns="http://www.w3.org/2000/svg"
36+
viewBox="0 0 24 24"
37+
fill="none"
38+
stroke="currentColor"
39+
stroke-width="2"
40+
stroke-linecap="round"
41+
stroke-linejoin="round"
42+
class="size-4"
43+
aria-hidden="true"
44+
>
45+
<circle cx="12" cy="12" r="3" />
46+
<path
47+
d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33h0a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51h0a1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82v0a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"
48+
/>
49+
</svg>
50+
<span class="sr-only">Settings</span>
51+
</button>
52+
53+
<div v-if="isOpen" class="absolute right-0 z-40 mt-1 w-56 overflow-hidden rounded-lg border border-slate-800 bg-slate-900 shadow-xl" role="menu">
54+
<div class="px-3 pt-2 pb-1 text-[10px] tracking-wider text-slate-500 uppercase">Units</div>
55+
56+
<div class="flex items-center justify-between px-3 py-2 text-sm">
57+
<span class="text-slate-300">Temperature</span>
58+
<div class="flex gap-1" role="radiogroup" aria-label="Temperature unit">
59+
<button
60+
v-for="opt in tempOptions"
61+
:key="opt.value"
62+
type="button"
63+
role="radio"
64+
:aria-checked="temp === opt.value"
65+
class="rounded-md border px-2 py-1 text-xs tabular-nums transition-colors"
66+
:class="temp === opt.value ? 'border-sky-600 bg-sky-600/20 text-sky-200' : 'border-slate-800 text-slate-300 hover:border-slate-600'"
67+
@click="temp = opt.value"
68+
>
69+
{{ opt.label }}
70+
</button>
71+
</div>
72+
</div>
73+
74+
<div class="flex items-center justify-between px-3 pt-1 pb-3 text-sm">
75+
<span class="text-slate-300">Precipitation</span>
76+
<div class="flex gap-1" role="radiogroup" aria-label="Precipitation unit">
77+
<button
78+
v-for="opt in precipOptions"
79+
:key="opt.value"
80+
type="button"
81+
role="radio"
82+
:aria-checked="precip === opt.value"
83+
class="rounded-md border px-2 py-1 text-xs transition-colors"
84+
:class="precip === opt.value ? 'border-sky-600 bg-sky-600/20 text-sky-200' : 'border-slate-800 text-slate-300 hover:border-slate-600'"
85+
@click="precip = opt.value"
86+
>
87+
{{ opt.label }}
88+
</button>
89+
</div>
90+
</div>
91+
</div>
92+
</div>
93+
</template>

src/components/UnitsToggle.vue

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)