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
424 changes: 0 additions & 424 deletions app/app.vue

Large diffs are not rendered by default.

470 changes: 470 additions & 0 deletions app/assets/main.css

Large diffs are not rendered by default.

41 changes: 32 additions & 9 deletions app/components/PackageWeeklyDownloadStats.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,45 @@ const config = computed(() => ({
style: {
backgroundColor: 'transparent',
animation: { show: false },
area: { color: '#6A6A6A', useGradient: false, opacity: 10 },
dataLabel: { offsetX: -10, fontSize: 28, bold: false, color: '#FAFAFA' },
area: {
color: 'oklch(0.5243 0 0)', // css variable doesn't seem to work here
useGradient: false,
opacity: 10,
},
dataLabel: {
offsetX: -10,
fontSize: 28,
bold: false,
color: 'var(--fg)',
},
line: {
color: '#6A6A6A',
color: 'var(--fg-subtle)',
pulse: {
show: true,
loop: true,
loop: true, // runs only once if false
radius: 2,
color: '#8A8A8A',
color: 'var(--fg-muted)',
easing: 'ease-in-out',
trail: { show: true, length: 6 },
trail: {
show: true,
length: 6,
},
},
},
plot: { radius: 6, stroke: '#FAFAFA' },
title: { text: lastDatapoint.value, fontSize: 12, color: '#8A8A8A', bold: false },
verticalIndicator: { strokeDasharray: 0, color: '#FAFAFA' },
plot: {
radius: 6,
stroke: 'var(--fg)',
},
title: {
text: lastDatapoint.value,
fontSize: 12,
color: 'var(--fg)',
bold: false,
},
verticalIndicator: {
strokeDasharray: 0,
color: 'var(--fg-muted)',
},
},
}))
</script>
Expand Down
41 changes: 35 additions & 6 deletions app/components/SettingsMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { onKeyStroke, onClickOutside } from '@vueuse/core'

const { settings } = useSettings()
const { locale, locales, setLocale } = useI18n()
const colorMode = useColorMode()

const availableLocales = computed(() =>
locales.value.map(l => (typeof l === 'string' ? { code: l, name: l } : l)),
Expand Down Expand Up @@ -96,14 +97,16 @@ onKeyStroke(',', e => {
>
<span class="text-sm text-fg select-none">{{ $t('settings.relative_dates') }}</span>
<span
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"
:class="settings.relativeDates ? 'bg-fg' : 'bg-bg-subtle'"
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"
:class="settings.relativeDates ? 'bg-fg' : 'bg-bg'"
aria-hidden="true"
>
<span
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"
:class="
settings.relativeDates ? 'translate-x-4 bg-bg' : 'translate-x-0 bg-fg-muted'
settings.relativeDates
? 'translate-x-4 bg-bg-subtle'
: 'translate-x-0 bg-fg-muted'
"
/>
</span>
Expand All @@ -121,21 +124,47 @@ onKeyStroke(',', e => {
$t('settings.include_types')
}}</span>
<span
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"
:class="settings.includeTypesInInstall ? 'bg-fg' : 'bg-bg-subtle'"
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"
:class="settings.includeTypesInInstall ? 'bg-fg' : 'bg-bg'"
aria-hidden="true"
>
<span
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"
:class="
settings.includeTypesInInstall
? 'translate-x-4 bg-bg'
? 'translate-x-4 bg-bg-subtle'
: 'translate-x-0 bg-fg-muted'
"
/>
</span>
</button>

<!-- Theme selector -->
<div class="pt-2 mt-2 border-t border-border">
<div class="px-2 py-1">
<label for="theme-select" class="text-xs text-fg-subtle uppercase tracking-wider">
{{ $t('settings.theme') }}
</label>
</div>
<div class="px-2 py-1">
<select
id="theme-select"
:value="colorMode.preference"
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"
@change="
colorMode.preference = ($event.target as HTMLSelectElement).value as
| 'light'
| 'dark'
| 'system'
"
>
<option value="system">{{ $t('settings.theme_system') }}</option>
<option value="light">{{ $t('settings.theme_light') }}</option>
<option value="dark">{{ $t('settings.theme_dark') }}</option>
</select>
</div>
</div>

<!-- Language selector -->
<div class="pt-2 mt-2 border-t border-border">
<div class="px-2 py-1">
Expand Down
12 changes: 6 additions & 6 deletions app/composables/useSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,12 @@ export function initAccentOnPrehydrate() {
// Colors must be hardcoded since ACCENT_COLORS can't be referenced.
onPrehydrate(() => {
const colors: Record<AccentColorId, string> = {
rose: '#e9aeba',
amber: '#fbbf24',
emerald: '#34d399',
sky: '#38bdf8',
violet: '#a78bfa',
coral: '#fb7185',
rose: 'oklch(0.797 0.084 11.056)',
amber: 'oklch(0.828 0.165 84.429)',
emerald: 'oklch(0.792 0.153 166.95)',
sky: 'oklch(0.787 0.128 230.318)',
violet: 'oklch(0.714 0.148 286.067)',
coral: 'oklch(0.704 0.177 14.75)',
}
const settings = JSON.parse(localStorage.getItem('npmx-settings') || '{}')
const color = settings.accentColorId ? colors[settings.accentColorId as AccentColorId] : null
Expand Down
16 changes: 8 additions & 8 deletions app/pages/[...package].vue
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ defineOgImageComponent('Package', {
</h2>
<!-- Package manager tabs -->
<div
class="flex items-center gap-1 p-0.5 bg-bg-subtle border border-border rounded-md"
class="flex items-center gap-1 p-0.5 bg-bg-subtle border border-border-subtle rounded-md"
role="tablist"
:aria-label="$t('package.install.pm_label')"
>
Expand All @@ -772,11 +772,11 @@ defineOgImageComponent('Package', {
:key="pm.id"
role="tab"
:aria-selected="selectedPM === pm.id"
class="px-2 py-1 font-mono text-xs rounded transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50"
class="px-2 py-1 font-mono text-xs rounded transition-colors duration-150 border border-solid focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50"
:class="
selectedPM === pm.id
? 'bg-bg-elevated text-fg'
: 'text-fg-subtle hover:text-fg-muted'
? 'bg-bg shadow text-fg border-border'
: 'text-fg-subtle hover:text-fg border-transparent'
"
@click="selectedPM = pm.id"
>
Expand All @@ -797,11 +797,11 @@ defineOgImageComponent('Package', {
</div>
<div class="relative group">
<!-- Terminal-style install command -->
<div class="bg-[#0d0d0d] border border-border rounded-lg overflow-hidden">
<div class="bg-bg-subtle border border-border rounded-lg overflow-hidden">
<div class="flex gap-1.5 px-3 pt-2 sm:px-4 sm:pt-3">
<span class="w-2.5 h-2.5 rounded-full bg-[#333]" />
<span class="w-2.5 h-2.5 rounded-full bg-[#333]" />
<span class="w-2.5 h-2.5 rounded-full bg-[#333]" />
<span class="w-2.5 h-2.5 rounded-full bg-fg-subtle" />
<span class="w-2.5 h-2.5 rounded-full bg-fg-subtle" />
<span class="w-2.5 h-2.5 rounded-full bg-fg-subtle" />
</div>
<div class="space-y-1 px-3 pt-2 pb-3 sm:px-4 sm:pt-3 sm:pb-4">
<!-- Main package install -->
Expand Down
4 changes: 4 additions & 0 deletions i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
"settings": {
"relative_dates": "Relative dates",
"include_types": "Include {'@'}types in install",
"theme": "Theme",
"theme_light": "Light",
"theme_dark": "Dark",
"theme_system": "System",
"language": "Language",
"help_translate": "Help translate npmx"
},
Expand Down
10 changes: 9 additions & 1 deletion nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,17 @@ export default defineNuxtConfig({
'@vite-pwa/nuxt',
'@vueuse/nuxt',
'@nuxtjs/i18n',
'@nuxtjs/color-mode',
],

css: ['vue-data-ui/style.css'],
colorMode: {
preference: 'system',
fallback: 'dark',
dataValue: 'theme',
storageKey: 'npmx-color-mode',
},

css: ['~/assets/main.css', 'vue-data-ui/style.css'],

devtools: { enabled: true },

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@nuxt/a11y": "1.0.0-alpha.1",
"@nuxt/fonts": "^0.13.0",
"@nuxt/scripts": "^0.13.2",
"@nuxtjs/color-mode": "^4.0.0",
"@nuxtjs/html-validator": "^2.1.0",
"@nuxtjs/i18n": "10.2.1",
"@shikijs/langs": "^3.21.0",
Expand Down
19 changes: 18 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions shared/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ export const ERROR_SUGGESTIONS_FETCH_FAILED = 'Failed to fetch suggestions.'

// Theming
export const ACCENT_COLORS = {
rose: '#e9aeba',
amber: '#fbbf24',
emerald: '#34d399',
sky: '#38bdf8',
violet: '#a78bfa',
coral: '#fb7185',
rose: 'oklch(0.797 0.084 11.056)',
amber: 'oklch(0.828 0.165 84.429)',
emerald: 'oklch(0.792 0.153 166.95)',
sky: 'oklch(0.787 0.128 230.318)',
violet: 'oklch(0.714 0.148 286.067)',
coral: 'oklch(0.704 0.177 14.75)',
} as const
34 changes: 17 additions & 17 deletions uno.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,31 +31,31 @@ export default defineConfig({
colors: {
// Minimal black & white palette with subtle grays
bg: {
DEFAULT: '#0a0a0a',
subtle: '#111111',
muted: '#1a1a1a',
elevated: '#222222',
DEFAULT: 'var(--bg)',
subtle: 'var(--bg-subtle)',
muted: 'var(--bg-muted)',
elevated: 'var(--bg-elevated)',
},
fg: {
DEFAULT: '#fafafa',
muted: '#a1a1a1',
subtle: '#8A8A8A',
DEFAULT: 'var(--fg)',
muted: 'var(--fg-muted)',
subtle: 'var(--fg-subtle)',
},
border: {
DEFAULT: '#262626',
subtle: '#1f1f1f',
hover: '#404040',
DEFAULT: 'var(--border)',
subtle: 'var(--border-subtle)',
hover: 'var(--border-hover)',
},
accent: {
DEFAULT: 'var(--accent-color, #666666)',
fallback: '#666666',
DEFAULT: 'var(--accent)',
fallback: 'var(--accent-muted)',
},
// Syntax highlighting colors (inspired by GitHub Dark)
syntax: {
fn: '#b392f0', // function/command - purple
str: '#9ecbff', // string/argument - light blue
kw: '#f97583', // keyword - red/pink
comment: '#6a737d', // comment - gray
fn: 'var(--syntax-fn)',
str: 'var(--syntax-str)',
kw: 'var(--syntax-kw)',
comment: 'var(--syntax-comment)',
},
// Playground provider brand colors
provider: {
Expand Down Expand Up @@ -101,7 +101,7 @@ export default defineConfig({
['container', 'max-w-4xl mx-auto px-4 sm:px-6'],

// Focus states - subtle but accessible
['focus-ring', 'outline-none focus-visible:(ring-2 ring-fg/20 ring-offset-2 ring-offset-bg)'],
['focus-ring', 'outline-none focus-visible:(ring-2 ring-fg/10 ring-offset-2)'],

// Buttons
[
Expand Down