Skip to content

Commit ec7edb5

Browse files
refactor: move settings to a page
1 parent 38960e2 commit ec7edb5

3 files changed

Lines changed: 149 additions & 208 deletions

File tree

app/components/AppHeader.vue

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ withDefaults(
1111
)
1212
1313
const { isConnected, npmUser } = useConnector()
14+
15+
const router = useRouter()
16+
onKeyStroke(',', e => {
17+
// Don't trigger if user is typing in an input
18+
const target = e.target as HTMLElement
19+
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {
20+
return
21+
}
22+
23+
e.preventDefault()
24+
router.push('/settings')
25+
})
1426
</script>
1527

1628
<template>
@@ -64,9 +76,19 @@ const { isConnected, npmUser } = useConnector()
6476

6577
<!-- Right: User status + GitHub -->
6678
<div class="flex-shrink-0 flex items-center gap-6">
67-
<ClientOnly>
68-
<SettingsMenu />
69-
</ClientOnly>
79+
<NuxtLink
80+
to="/settings"
81+
class="link-subtle font-mono text-sm inline-flex items-center gap-2"
82+
aria-keyshortcuts=","
83+
>
84+
{{ $t('nav.settings') }}
85+
<kbd
86+
class="hidden sm:inline-flex items-center justify-center w-5 h-5 text-xs bg-bg-muted border border-border rounded"
87+
aria-hidden="true"
88+
>
89+
,
90+
</kbd>
91+
</NuxtLink>
7092

7193
<div v-if="showConnector">
7294
<ConnectorStatus />

app/components/SettingsMenu.vue

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

app/pages/settings.vue

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<script setup lang="ts">
2+
const { settings } = useSettings()
3+
const { locale, locales, setLocale } = useI18n()
4+
const colorMode = useColorMode()
5+
6+
const availableLocales = computed(() =>
7+
locales.value.map(l => (typeof l === 'string' ? { code: l, name: l } : l)),
8+
)
9+
</script>
10+
11+
<template>
12+
<main class="container py-8 sm:py-12 w-full">
13+
<div class="space-y-1 p-4 rounded-lg">
14+
<button
15+
type="button"
16+
class="w-full flex items-center justify-between gap-3 px-2 py-2 rounded-md hover:bg-bg-muted transition-[background-color] duration-150 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50"
17+
role="menuitemcheckbox"
18+
:aria-checked="settings.relativeDates"
19+
@click="settings.relativeDates = !settings.relativeDates"
20+
>
21+
<span class="text-sm text-fg select-none">{{ $t('settings.relative_dates') }}</span>
22+
<span
23+
class="relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border-2 border-transparent transition-[background-color] duration-200 ease-in-out motion-reduce:transition-none shadow"
24+
:class="settings.relativeDates ? 'bg-fg' : 'bg-bg'"
25+
aria-hidden="true"
26+
>
27+
<span
28+
class="pointer-events-none inline-block h-4 w-4 rounded-full shadow-sm ring-0 transition-transform duration-200 ease-in-out motion-reduce:transition-none"
29+
:class="
30+
settings.relativeDates ? 'translate-x-4 bg-bg-subtle' : 'translate-x-0 bg-fg-muted'
31+
"
32+
/>
33+
</span>
34+
</button>
35+
36+
<!-- Include @types in install toggle -->
37+
<button
38+
type="button"
39+
class="w-full flex items-center justify-between gap-3 px-2 py-2 rounded-md hover:bg-bg-muted transition-[background-color] duration-150 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50"
40+
role="menuitemcheckbox"
41+
:aria-checked="settings.includeTypesInInstall"
42+
@click="settings.includeTypesInInstall = !settings.includeTypesInInstall"
43+
>
44+
<span class="text-sm text-fg select-none text-left">{{
45+
$t('settings.include_types')
46+
}}</span>
47+
<span
48+
class="relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border-2 border-transparent transition-[background-color] duration-200 ease-in-out motion-reduce:transition-none border border-border shadow"
49+
:class="settings.includeTypesInInstall ? 'bg-fg' : 'bg-bg'"
50+
aria-hidden="true"
51+
>
52+
<span
53+
class="pointer-events-none inline-block h-4 w-4 rounded-full shadow-sm ring-0 transition-transform duration-200 ease-in-out motion-reduce:transition-none"
54+
:class="
55+
settings.includeTypesInInstall
56+
? 'translate-x-4 bg-bg-subtle'
57+
: 'translate-x-0 bg-fg-muted'
58+
"
59+
/>
60+
</span>
61+
</button>
62+
63+
<!-- Theme selector -->
64+
<div class="pt-2 mt-2 border-t border-border">
65+
<div class="px-2 py-1">
66+
<label for="theme-select" class="text-xs text-fg-subtle uppercase tracking-wider">
67+
{{ $t('settings.theme') }}
68+
</label>
69+
</div>
70+
<div class="px-2 py-1">
71+
<select
72+
id="theme-select"
73+
:value="colorMode.preference"
74+
class="w-full bg-bg-muted border border-border rounded-md px-2 py-1.5 text-sm text-fg focus:outline-none focus:ring-2 focus:ring-fg/50 cursor-pointer"
75+
@change="
76+
colorMode.preference = ($event.target as HTMLSelectElement).value as
77+
| 'light'
78+
| 'dark'
79+
| 'system'
80+
"
81+
>
82+
<option value="system">{{ $t('settings.theme_system') }}</option>
83+
<option value="light">{{ $t('settings.theme_light') }}</option>
84+
<option value="dark">{{ $t('settings.theme_dark') }}</option>
85+
</select>
86+
</div>
87+
</div>
88+
89+
<!-- Language selector -->
90+
<div class="pt-2 mt-2 border-t border-border">
91+
<div class="px-2 py-1">
92+
<label for="language-select" class="text-xs text-fg-subtle uppercase tracking-wider">
93+
{{ $t('settings.language') }}
94+
</label>
95+
</div>
96+
<div class="px-2 py-1">
97+
<select
98+
id="language-select"
99+
:value="locale"
100+
class="w-full bg-bg-muted border border-border rounded-md px-2 py-1.5 text-sm text-fg focus:outline-none focus:ring-2 focus:ring-fg/50 cursor-pointer"
101+
@change="setLocale(($event.target as HTMLSelectElement).value as typeof locale)"
102+
>
103+
<option v-for="loc in availableLocales" :key="loc.code" :value="loc.code">
104+
{{ loc.name }}
105+
</option>
106+
</select>
107+
</div>
108+
<a
109+
href="https://github.com/npmx-dev/npmx.dev/tree/main/i18n/locales"
110+
target="_blank"
111+
rel="noopener noreferrer"
112+
class="flex items-center gap-1.5 px-2 py-1.5 text-xs text-fg-muted hover:text-fg transition-colors"
113+
>
114+
<span class="i-carbon-translate w-3.5 h-3.5" aria-hidden="true" />
115+
{{ $t('settings.help_translate') }}
116+
</a>
117+
</div>
118+
119+
<div class="p-3 border-t border-border">
120+
<AccentColorPicker />
121+
</div>
122+
</div>
123+
</main>
124+
</template>

0 commit comments

Comments
 (0)