Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 58 additions & 9 deletions app/assets/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@

:root[data-theme='dark'] {
/* background colors */
--bg: oklch(0.145 0 0);
--bg-subtle: oklch(0.178 0 0);
--bg-muted: oklch(0.218 0 0);
--bg-elevated: oklch(0.252 0 0);
--bg: var(--bg-color, oklch(0.145 0 0));
--bg-subtle: var(--bg-subtle-color, oklch(0.178 0 0));
--bg-muted: var(--bg-muted-color, oklch(0.218 0 0));
--bg-elevated: var(--bg-elevated-color, oklch(0.252 0 0));

/* text colors */
--fg: oklch(0.985 0 0);
--fg-muted: oklch(0.709 0 0);
--fg-subtle: oklch(0.633 0 0);

/* border, seperator colors */
/* border, separator colors */
--border: oklch(0.269 0 0);
--border-subtle: oklch(0.239 0 0);
--border-hover: oklch(0.371 0 0);
Expand All @@ -43,11 +43,39 @@
--badge-pink: oklch(0.584 0.189 343);
}

:root[data-theme='dark'][data-bg-theme='slate'] {
--bg: oklch(0.129 0.012 264.695);
--bg-subtle: oklch(0.159 0.022 262.421);
--bg-muted: oklch(0.204 0.033 261.234);
--bg-elevated: oklch(0.259 0.041 260.031);
}

:root[data-theme='dark'][data-bg-theme='zinc'] {
--bg: oklch(0.141 0.005 285.823);
--bg-subtle: oklch(0.168 0.005 285.894);
--bg-muted: oklch(0.209 0.005 285.929);
--bg-elevated: oklch(0.256 0.006 286.033);
}

:root[data-theme='dark'][data-bg-theme='stone'] {
--bg: oklch(0.147 0.004 49.25);
--bg-subtle: oklch(0.178 0.004 49.321);
--bg-muted: oklch(0.218 0.004 49.386);
--bg-elevated: oklch(0.252 0.007 34.298);
}

:root[data-theme='dark'][data-bg-theme='black'] {
--bg: oklch(0 0 0);
--bg-subtle: oklch(0.148 0 0);
--bg-muted: oklch(0.204 0 0);
--bg-elevated: oklch(0.264 0 0);
}

:root[data-theme='light'] {
--bg: oklch(1 0 0);
--bg-subtle: oklch(0.979 0.001 286.375);
--bg-muted: oklch(0.955 0 0);
--bg-elevated: oklch(0.94 0 0);
--bg: var(--bg-color, oklch(1 0 0));
--bg-subtle: var(--bg-subtle-color, oklch(0.979 0.001 286.375));
--bg-muted: var(--bg-muted-color, oklch(0.955 0 0));
--bg-elevated: var(--bg-elevated-color, oklch(0.94 0 0));

--fg: oklch(0.145 0 0);
--fg-muted: oklch(0.439 0 0);
Expand Down Expand Up @@ -75,6 +103,27 @@
--badge-cyan: oklch(0.571 0.181 210);
}

:root[data-theme='light'][data-bg-theme='slate'] {
--bg: oklch(1 0 0);
--bg-subtle: oklch(0.982 0.006 264.62);
--bg-muted: oklch(0.96 0.041 261.234);
--bg-elevated: oklch(0.943 0.013 255.52);
}

:root[data-theme='light'][data-bg-theme='zinc'] {
--bg: oklch(1 0 0);
--bg-subtle: oklch(0.979 0.004 286.53);
--bg-muted: oklch(0.958 0.004 286.39);
--bg-elevated: oklch(0.939 0.004 286.32);
}

:root[data-theme='light'][data-bg-theme='stone'] {
--bg: oklch(1 0 0);
--bg-subtle: oklch(0.979 0.005 48.762);
--bg-muted: oklch(0.958 0.005 48.743);
--bg-elevated: oklch(0.943 0.005 48.731);
}

@media (prefers-contrast: more) {
:root[data-theme='dark'] {
/* text colors */
Expand Down
36 changes: 36 additions & 0 deletions app/components/Settings/BgThemePicker.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script setup lang="ts">
const { backgroundThemes, selectedBackgroundTheme, setBackgroundTheme } = useBackgroundTheme()

onPrehydrate(el => {
const settings = JSON.parse(localStorage.getItem('npmx-settings') || '{}')
const id = settings.preferredBackgroundTheme
if (id) {
const input = el.querySelector<HTMLInputElement>(`input[value="${id || 'neutral'}"]`)
if (input) {
input.checked = true
}
}
})
</script>

<template>
<fieldset class="flex items-center gap-4">
<legend class="sr-only">{{ $t('settings.background_themes') }}</legend>
<label
v-for="theme in backgroundThemes"
:key="theme.id"
class="size-6 rounded-full transition-transform duration-150 motion-safe:hover:scale-110 cursor-pointer has-[:checked]:(ring-2 ring-fg ring-offset-2 ring-offset-bg-subtle) has-[:focus-visible]:(ring-2 ring-fg ring-offset-2 ring-offset-bg-subtle)"
:style="{ backgroundColor: theme.value }"
>
<input
type="radio"
name="background-theme"
class="sr-only"
:value="theme.id"
:checked="selectedBackgroundTheme === theme.id"
:aria-label="theme.name"
@change="setBackgroundTheme(theme.id)"
/>
</label>
</fieldset>
</template>
2 changes: 1 addition & 1 deletion app/composables/useColors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export function useCssVariables(
if (options.watchHtmlAttributes && isClientSupported.value) {
useMutationObserver(document.documentElement, () => void colors.value, {
attributes: true,
attributeFilter: ['class', 'style', 'data-theme'],
attributeFilter: ['class', 'style', 'data-theme', 'data-bg-theme'],
})
}

Expand Down
31 changes: 31 additions & 0 deletions app/composables/useSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import type { RemovableRef } from '@vueuse/core'
import { useLocalStorage } from '@vueuse/core'
import { ACCENT_COLORS } from '#shared/utils/constants'
import type { LocaleObject } from '@nuxtjs/i18n'
import { BACKGROUND_THEMES } from '#shared/utils/constants'

type BackgroundThemeId = keyof typeof BACKGROUND_THEMES

type AccentColorId = keyof typeof ACCENT_COLORS

Expand All @@ -15,6 +18,8 @@ export interface AppSettings {
includeTypesInInstall: boolean
/** Accent color theme */
accentColorId: AccentColorId | null
/** Preferred background shade */
preferredBackgroundTheme: BackgroundThemeId | null
/** Hide platform-specific packages (e.g., @scope/pkg-linux-x64) from search results */
hidePlatformPackages: boolean
/** User-selected locale */
Expand All @@ -30,6 +35,7 @@ const DEFAULT_SETTINGS: AppSettings = {
accentColorId: null,
hidePlatformPackages: true,
selectedLocale: null,
preferredBackgroundTheme: null,
sidebar: {
collapsed: [],
},
Expand Down Expand Up @@ -93,3 +99,28 @@ export function useAccentColor() {
setAccentColor,
}
}

export function useBackgroundTheme() {
const backgroundThemes = Object.entries(BACKGROUND_THEMES).map(([id, value]) => ({
id: id as BackgroundThemeId,
name: id,
value,
}))

const { settings } = useSettings()

function setBackgroundTheme(id: BackgroundThemeId | null) {
if (id) {
document.documentElement.dataset.bgTheme = id
} else {
document.documentElement.removeAttribute('data-bg-theme')
}
settings.value.preferredBackgroundTheme = id
}

return {
backgroundThemes,
selectedBackgroundTheme: computed(() => settings.value.preferredBackgroundTheme),
setBackgroundTheme,
}
}
8 changes: 8 additions & 0 deletions app/pages/settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ const setLocale: typeof setNuxti18nLocale = locale => {
</span>
<SettingsAccentColorPicker />
</div>

<!-- Background themes -->
<div class="space-y-3">
<span class="block text-sm text-fg font-medium">
{{ $t('settings.background_themes') }}
</span>
<SettingsBgThemePicker />
</div>
</div>
</section>

Expand Down
6 changes: 6 additions & 0 deletions app/utils/prehydrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ export function initPreferencesOnPrehydrate() {
document.documentElement.style.setProperty('--accent-color', color)
}

// Apply background accent
const preferredBackgroundTheme = settings.preferredBackgroundTheme
if (preferredBackgroundTheme) {
document.documentElement.dataset.bgTheme = preferredBackgroundTheme
}

// Read and apply package manager preference
const storedPM = localStorage.getItem('npmx-pm')
// Parse the stored value (it's stored as a JSON string by useLocalStorage)
Expand Down
3 changes: 2 additions & 1 deletion i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@
"help_translate": "Help translate npmx",
"accent_colors": "Accent colors",
"clear_accent": "Clear accent color",
"translation_progress": "Translation progress"
"translation_progress": "Translation progress",
"background_themes": "Background shade"
},
"i18n": {
"missing_keys": "{count} missing translation | {count} missing translations",
Expand Down
3 changes: 2 additions & 1 deletion lunaria/files/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@
"help_translate": "Help translate npmx",
"accent_colors": "Accent colors",
"clear_accent": "Clear accent color",
"translation_progress": "Translation progress"
"translation_progress": "Translation progress",
"background_themes": "Background shade"
},
"i18n": {
"missing_keys": "{count} missing translation | {count} missing translations",
Expand Down
8 changes: 8 additions & 0 deletions shared/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,11 @@ export const ACCENT_COLORS = {
violet: 'oklch(0.714 0.148 286.067)',
coral: 'oklch(0.704 0.177 14.75)',
} as const

export const BACKGROUND_THEMES = {
neutral: 'oklch(0.555 0 0)',
stone: 'oklch(0.555 0.013 58.123)',
zinc: 'oklch(0.555 0.016 285.931)',
slate: 'oklch(0.555 0.046 257.407)',
black: 'oklch(0.4 0 0)',
} as const
Loading