Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
c3aaa42
fix: invalid link attribute
essenmitsosse Feb 3, 2026
6c271b3
fix: cleanup component
essenmitsosse Feb 4, 2026
59b5c3c
refactor: extract reusable button component
essenmitsosse Feb 4, 2026
a2872d6
refactor: remove uno btn shortcut
essenmitsosse Feb 4, 2026
77c6267
test: add button tests
essenmitsosse Feb 4, 2026
45b86a7
refactor: change search button to new component
essenmitsosse Feb 4, 2026
dfba6b6
fix(style): disabled button
essenmitsosse Feb 4, 2026
05a4cfa
refactor: use button component for connector and social buttons
essenmitsosse Feb 4, 2026
949c0b9
refactor: use button component for modal close button
essenmitsosse Feb 4, 2026
c926dce
style: remove default button and link style
essenmitsosse Feb 4, 2026
2e093db
refactor: move pressed style to css
essenmitsosse Feb 4, 2026
c907c0a
refactor: merge button and tag button
essenmitsosse Feb 4, 2026
a2c3ff4
refactor: merge button and tag link
essenmitsosse Feb 4, 2026
1c0a159
style: improve disabled design
essenmitsosse Feb 4, 2026
585aa63
fix: link
essenmitsosse Feb 4, 2026
83ae495
style: sync links and static tags
essenmitsosse Feb 4, 2026
037638a
chore: move link to own folder
essenmitsosse Feb 4, 2026
15bf1e3
refactor: rename link variants
essenmitsosse Feb 4, 2026
c84a978
Merge remote-tracking branch 'upstream/main' into fix-a11y-extract-bt…
essenmitsosse Feb 5, 2026
205c937
refactor: replace links with component
essenmitsosse Feb 5, 2026
4974d56
fix: remove exclamation mark accidentally added
essenmitsosse Feb 5, 2026
80bcd90
refactor: replace (almost) all links on package page
essenmitsosse Feb 6, 2026
cf33ca9
Merge remote-tracking branch 'upstream/main' into fix-a11y-extract-bt…
essenmitsosse Feb 6, 2026
260be92
feat: unifyied keyshort cut system
essenmitsosse Feb 6, 2026
2278aa1
feat: unifyied icon system
essenmitsosse Feb 6, 2026
886c60e
feat: automatically show external link icon
essenmitsosse Feb 6, 2026
b070507
feat: add button group
essenmitsosse Feb 6, 2026
bf06a1e
feat: automatically open all external links in new window
essenmitsosse Feb 6, 2026
7b860d1
fix: layout
essenmitsosse Feb 6, 2026
1bfa878
refactor: use design components for package sidebar
essenmitsosse Feb 6, 2026
930a25e
refactor: use design components in footer build infos
essenmitsosse Feb 6, 2026
1a8ba38
style: use accent colors for button and links
essenmitsosse Feb 6, 2026
a53e865
style: re-add unified focus style
essenmitsosse Feb 6, 2026
f0cc773
style: improve focus style
essenmitsosse Feb 6, 2026
1a73f88
style: make buttons and links look clickable
essenmitsosse Feb 6, 2026
bc47aee
fix: minor fixes
essenmitsosse Feb 6, 2026
b52eec5
fix: l-to-r
essenmitsosse Feb 6, 2026
9f8f1b8
Merge remote-tracking branch 'upstream/main' into fix-a11y-extract-bt…
essenmitsosse Feb 6, 2026
f65280b
feat: add automatic anchor link design
essenmitsosse Feb 6, 2026
858a8ab
test: update tests
essenmitsosse Feb 6, 2026
314998f
fix: issue with types
essenmitsosse Feb 6, 2026
392797e
fix: remove unnecessary border radius declaration
essenmitsosse Feb 6, 2026
f4cfdee
fix: typo
essenmitsosse Feb 6, 2026
41ed66a
fix: update buton
essenmitsosse Feb 6, 2026
95ef5d7
refactor: update button
essenmitsosse Feb 6, 2026
3654cd4
fix: remove stale reference
essenmitsosse Feb 6, 2026
1d2d1ba
refactor: streamline link props and change how external links are rec…
essenmitsosse Feb 6, 2026
8992ed5
fix: prop name
essenmitsosse Feb 6, 2026
e70ef85
fix: remove unnecessary class
essenmitsosse Feb 6, 2026
ff7a8b6
fix: app header menu on mobile
essenmitsosse Feb 6, 2026
5d23f56
style: move menu to button group
essenmitsosse Feb 6, 2026
50486b5
test: ignore button group for a11y tests
essenmitsosse Feb 6, 2026
45fdd71
fix: wrong element type
essenmitsosse Feb 6, 2026
edc4e21
refactoring
essenmitsosse Feb 6, 2026
e1a4e05
Merge remote-tracking branch 'upstream/main' into fix-a11y-extract-bt…
essenmitsosse Feb 6, 2026
54b044b
style: change package links back to link style
essenmitsosse Feb 6, 2026
e84b59c
test: fix copy-paste error with test props
essenmitsosse Feb 6, 2026
e96ae1a
[autofix.ci] apply automated fixes
autofix-ci[bot] Feb 6, 2026
7ea5e19
fix: footer links
essenmitsosse Feb 6, 2026
952a695
docs: add comment explaining explicit attr
essenmitsosse Feb 6, 2026
042f468
refactor: rename tag variant
essenmitsosse Feb 6, 2026
c8420d2
refactor: change props for buttons and links
essenmitsosse Feb 6, 2026
1fade1e
feat: remove non-working aria-current styling
essenmitsosse Feb 6, 2026
bed8f81
docs: update comment
essenmitsosse Feb 6, 2026
c0967c9
style: remove highlight border from buttons
essenmitsosse Feb 6, 2026
f5689dd
style: remove accent from links and buttons
essenmitsosse Feb 6, 2026
77903fc
fix: firefox bug
essenmitsosse Feb 6, 2026
784b8db
Merge remote-tracking branch 'upstream/main' into fix-a11y-extract-bt…
essenmitsosse Feb 6, 2026
2fce723
refactor: simplify query
essenmitsosse Feb 6, 2026
62c88fc
refactor: change default element for button group
essenmitsosse Feb 6, 2026
3a13fbf
docs: rephrase comment
essenmitsosse Feb 6, 2026
899516f
fix: primary button in light mode
essenmitsosse Feb 6, 2026
917d2d4
fix: wrong element type
essenmitsosse Feb 6, 2026
bf7c69d
Merge remote-tracking branch 'upstream/main' into fix-a11y-extract-bt…
essenmitsosse Feb 6, 2026
a827403
WIP
essenmitsosse Feb 6, 2026
1719728
Merge remote-tracking branch 'upstream/main' into fix-a11y-extract-bt…
essenmitsosse Feb 6, 2026
0bceba2
Revert "WIP"
essenmitsosse Feb 6, 2026
3255a06
[autofix.ci] apply automated fixes
autofix-ci[bot] Feb 6, 2026
bcc1a2d
style: make links mono font again
essenmitsosse Feb 6, 2026
4901f01
style: mute link underline more
essenmitsosse Feb 6, 2026
702bbe9
style: reduce font size in footer
essenmitsosse Feb 6, 2026
0d46806
style: use accent color for link hover
essenmitsosse Feb 6, 2026
07127eb
refactor: use button icon for like button
essenmitsosse Feb 6, 2026
c1352d2
style: remove external link indicator from links that already have an…
essenmitsosse Feb 6, 2026
ea5c9fa
style: make deps info fit on single line
essenmitsosse Feb 6, 2026
a05c470
style: temporarily re-add button cursor pointer, for legacy buttons
essenmitsosse Feb 6, 2026
0f9d174
fix: fix close button for modal
essenmitsosse Feb 6, 2026
06d4847
style: dont hide underline on hover
essenmitsosse Feb 6, 2026
cd95139
style: reduce hover button contrast
essenmitsosse Feb 6, 2026
4bf7b3a
Merge remote-tracking branch 'upstream/main' into fix-a11y-extract-bt…
essenmitsosse Feb 6, 2026
1ae2a62
docs: fix typo
essenmitsosse Feb 7, 2026
e45e548
fix: remove unused import
essenmitsosse Feb 7, 2026
4765ef1
style: add spacing around keyboard shortcut
essenmitsosse Feb 7, 2026
ecc87a3
style: revert menu back to old design while using new components
essenmitsosse Feb 7, 2026
4ceb40e
fix: improve conditional rendering
essenmitsosse Feb 7, 2026
b323b78
fix: replace new button
essenmitsosse Feb 7, 2026
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
14 changes: 3 additions & 11 deletions app/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ if (import.meta.client) {
<template>
<div class="min-h-screen flex flex-col bg-bg text-fg">
<NuxtPwaAssets />
<a href="#main-content" class="skip-link font-mono">{{ $t('common.skip_link') }}</a>
<LinkBase to="#main-content" variant="button-primary" class="skip-link">{{
$t('common.skip_link')
}}</LinkBase>

<AppHeader :show-logo="!isHomepage" />

Expand All @@ -140,19 +142,9 @@ if (import.meta.client) {
.skip-link {
position: fixed;
top: -100%;
inset-inline-start: 0;
padding: 0.5rem 1rem;
background: var(--fg);
color: var(--bg);
font-size: 0.875rem;
z-index: 100;
transition: top 0.2s ease;
}

.skip-link:hover {
color: var(--bg);
text-decoration: underline;
}
.skip-link:focus {
top: 0;
}
Expand Down
41 changes: 9 additions & 32 deletions app/assets/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ html {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
scroll-padding-top: 5rem; /* Offset for fixed header - otherwise anchor headers are cutted */
scroll-padding-top: 5rem;
/* Offset for fixed header - otherwise anchor headers are cutted */
scrollbar-gutter: stable;
}

Expand All @@ -185,26 +186,13 @@ body {
line-height: 1.6;
}

/* Default link styling for accessibility on dark background */
a {
color: var(--fg);
text-decoration: underline;
text-underline-offset: 3px;
text-decoration-color: var(--fg-subtle);
transition:
color 0.2s ease,
text-decoration-color 0.2s ease;
}

a:hover {
color: var(--accent);
text-decoration-color: var(--accent);
}

a:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
border-radius: 4px;
:focus-visible,
:-moz-focusring {
/* weird Firefox behavior makes it necessary to add `!important`
or otherwise the selector would need to be more specific,
which it explicitly should not be. */
outline: 2px solid var(--accent) !important;
outline-offset: 2px !important;
}

/* Reset dd margin (browser default is margin-left: 40px) */
Expand All @@ -214,18 +202,7 @@ dd {

/* Reset button styles */
button {
background: transparent;
border: none;
cursor: pointer;
font: inherit;
padding: 0;
}

button:focus-visible,
select:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
border-radius: 4px;
}

/* Selection */
Expand Down
53 changes: 13 additions & 40 deletions app/components/AppFooter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,52 +14,25 @@ const isHome = computed(() => route.name === 'index')
<BuildEnvironment v-if="!isHome" footer />
</div>
<!-- Desktop: Show all links. Mobile: Links are in MobileMenu -->
<div class="hidden sm:flex items-center gap-6 min-h-11">
<NuxtLink :to="{ name: 'about' }" class="link-subtle font-mono text-xs flex items-center">
<div class="hidden sm:flex items-center gap-6 min-h-11 text-xs">
<LinkBase :to="{ name: 'about' }">
{{ $t('footer.about') }}
</NuxtLink>
<NuxtLink
:to="{ name: 'privacy' }"
class="link-subtle font-mono text-xs flex items-center gap-1"
>
</LinkBase>
<LinkBase :to="{ name: 'privacy' }">
{{ $t('privacy_policy.title') }}
</NuxtLink>
<a
href="https://docs.npmx.dev"
target="_blank"
rel="noopener noreferrer"
class="link-subtle font-mono text-xs flex items-center gap-1"
>
</LinkBase>
<LinkBase to="https://docs.npmx.dev">
{{ $t('footer.docs') }}
<span class="i-carbon:launch rtl-flip w-3 h-3" aria-hidden="true" />
</a>
<a
href="https://repo.npmx.dev"
target="_blank"
rel="noopener noreferrer"
class="link-subtle font-mono text-xs flex items-center gap-1"
>
</LinkBase>
<LinkBase to="https://repo.npmx.dev">
{{ $t('footer.source') }}
<span class="i-carbon:launch rtl-flip w-3 h-3" aria-hidden="true" />
</a>
<a
href="https://social.npmx.dev"
target="_blank"
rel="noopener noreferrer"
class="link-subtle font-mono text-xs flex items-center gap-1"
>
</LinkBase>
<LinkBase to="https://social.npmx.dev">
{{ $t('footer.social') }}
<span class="i-carbon:launch rtl-flip w-3 h-3" aria-hidden="true" />
</a>
<a
href="https://chat.npmx.dev"
target="_blank"
rel="noopener noreferrer"
class="link-subtle font-mono text-xs flex items-center gap-1"
>
</LinkBase>
<LinkBase to="https://chat.npmx.dev">
{{ $t('footer.chat') }}
<span class="i-carbon:launch rtl-flip w-3 h-3" aria-hidden="true" />
</a>
</LinkBase>
</div>
</div>
<p class="text-xs text-fg-muted text-center sm:text-start m-0">
Expand Down
58 changes: 23 additions & 35 deletions app/components/AppHeader.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { LinkBase } from '#components'
import { isEditableElement } from '~/utils/input'

withDefaults(
Expand Down Expand Up @@ -150,52 +151,39 @@ onKeyStroke(
</div>

<!-- End: Desktop nav items + Mobile menu button -->
<div class="flex-shrink-0 flex items-center gap-0.5 sm:gap-2">
<div class="hidden sm:flex flex-shrink-0">
<!-- Desktop: Compare link -->
<NuxtLink
<LinkBase
class="border-none"
variant="button-secondary"
:to="{ name: 'compare' }"
class="hidden sm:inline-flex link-subtle font-mono text-sm items-center gap-2 px-2 py-1.5 hover:bg-bg-subtle focus-visible:outline-accent/70 rounded"
aria-keyshortcuts="c"
keyshortcut="c"
>
{{ $t('nav.compare') }}
<kbd
class="inline-flex items-center justify-center w-5 h-5 text-xs bg-bg-muted border border-border rounded"
aria-hidden="true"
>
c
</kbd>
</NuxtLink>
</LinkBase>

<!-- Desktop: Settings link -->
<NuxtLink
<LinkBase
class="border-none"
variant="button-secondary"
:to="{ name: 'settings' }"
class="hidden sm:inline-flex link-subtle font-mono text-sm items-center gap-2 px-2 py-1.5 hover:bg-bg-subtle focus-visible:outline-accent/70 rounded"
aria-keyshortcuts=","
keyshortcut=","
>
{{ $t('nav.settings') }}
<kbd
class="inline-flex items-center justify-center w-5 h-5 text-xs bg-bg-muted border border-border rounded"
aria-hidden="true"
>
,
</kbd>
</NuxtLink>
</LinkBase>

<!-- Desktop: Account menu -->
<div class="hidden sm:block">
<HeaderAccountMenu />
</div>

<!-- Mobile: Menu button (always visible, click to open menu) -->
<button
type="button"
class="sm:hidden flex items-center p-2 -m-2 text-fg-subtle hover:text-fg transition-colors duration-200 focus-visible:outline-accent/70 rounded"
:aria-label="$t('nav.open_menu')"
@click="showMobileMenu = true"
>
<span class="w-6 h-6 inline-block i-carbon:menu" aria-hidden="true" />
</button>
<HeaderAccountMenu />
</div>

<!-- Mobile: Menu button (always visible, click to open menu) -->
<ButtonBase
type="button"
class="sm:hidden flex"
:aria-label="$t('nav.open_menu')"
:aria-expanded="showMobileMenu"
@click="showMobileMenu = !showMobileMenu"
classicon="i-carbon:menu"
/>
</nav>

<!-- Mobile menu -->
Expand Down
18 changes: 5 additions & 13 deletions app/components/BuildEnvironment.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,19 @@ const buildInfo = useAppConfig().buildInfo
<NuxtTime :datetime="buildInfo.time" :locale="locale" relative />
</i18n-t>
<span>&middot;</span>
<NuxtLink
<LinkBase
v-if="buildInfo.env === 'release'"
external
:href="`https://github.com/npmx-dev/npmx.dev/tag/v${buildInfo.version}`"
target="_blank"
class="hover:text-fg transition-colors"
:to="`https://github.com/npmx-dev/npmx.dev/tag/v${buildInfo.version}`"
>
v{{ buildInfo.version }}
</NuxtLink>
</LinkBase>
<span v-else class="tracking-wider">{{ buildInfo.env }}</span>

<template v-if="buildInfo.commit && buildInfo.branch !== 'release'">
<span>&middot;</span>
<NuxtLink
external
:href="`https://github.com/npmx-dev/npmx.dev/commit/${buildInfo.commit}`"
target="_blank"
class="hover:text-fg transition-colors"
>
<LinkBase :to="`https://github.com/npmx-dev/npmx.dev/commit/${buildInfo.commit}`">
{{ buildInfo.shortCommit }}
</NuxtLink>
</LinkBase>
</template>
</div>
</template>
69 changes: 69 additions & 0 deletions app/components/Button/Base.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<script setup lang="ts">
const props = withDefaults(
defineProps<{
'disabled'?: boolean
'type'?: 'button' | 'submit'
'variant'?: 'primary' | 'secondary'
'size'?: 'small' | 'medium'
'keyshortcut'?: string

/**
* Do not use this directly. Use keyshortcut instead; it generates the correct HTML and displays the shortcut in the UI.
*/
'aria-keyshortcuts'?: never

'classicon'?: string
}>(),
{
type: 'button',
variant: 'secondary',
size: 'medium',
},
)

const el = useTemplateRef('el')

defineExpose({
focus: () => el.value?.focus(),
})
</script>

<template>
<button
ref="el"
class="group cursor-pointer inline-flex gap-x-1 items-center justify-center font-mono border border-border rounded-md transition-all duration-200 disabled:(opacity-40 cursor-not-allowed border-transparent)"
:class="{
'text-sm px-4 py-2': size === 'medium',
'text-xs px-2 py-0.5': size === 'small',
'bg-transparent text-fg hover:enabled:(bg-fg/10) focus-visible:enabled:(bg-fg/10) aria-pressed:(bg-fg text-bg border-fg hover:enabled:(bg-fg text-bg/50))':
variant === 'secondary',
'text-bg bg-fg hover:enabled:(bg-fg/50) focus-visible:enabled:(bg-fg/50) aria-pressed:(bg-fg text-bg border-fg hover:enabled:(text-bg/50))':
variant === 'primary',
}"
:type="props.type"
:disabled="
/**
* Unfortunately Vue _sometimes_ doesn't handle `disabled` correct,
* resulting in an invalid `disabled=false` attribute in the final HTML.
*
* This fixes this.
*/
disabled ? true : undefined
"
:aria-keyshortcuts="keyshortcut"
>
<span
v-if="classicon"
:class="[size === 'small' ? 'size-3' : 'size-4', classicon]"
aria-hidden="true"
/>
<slot />
<kbd
v-if="keyshortcut"
class="ms-2 inline-flex items-center justify-center w-4 h-4 text-xs text-fg bg-bg-muted border border-border rounded no-underline"
aria-hidden="true"
>
{{ keyshortcut }}
</kbd>
</button>
</template>
14 changes: 14 additions & 0 deletions app/components/Button/Group.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script setup lang="ts">
const props = defineProps<{
as?: string | Component
}>()
</script>

<template>
<component
:is="props.as || 'div'"
class="flex items-center shrink-0 ms-auto [&>*:not(:first-child)]:rounded-s-none [&>*:not(:first-child)]:border-s-0 [&>*:not(:last-child)]:rounded-e-none"
>
<slot />
</component>
</template>
18 changes: 6 additions & 12 deletions app/components/ColumnPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,16 @@ function handleReset() {

<template>
<div class="relative">
<button
<ButtonBase
ref="buttonRef"
type="button"
class="btn-ghost inline-flex items-center gap-1.5 px-3 py-1.5 border border-border rounded-md hover:border-border-hover focus-visible:ring-2 focus-visible:ring-fg focus-visible:ring-offset-2 focus-visible:ring-offset-bg"
:aria-expanded="isOpen"
aria-haspopup="true"
:aria-controls="menuId"
@click.stop="isOpen = !isOpen"
classicon="i-carbon-column"
>
<span class="i-carbon-column w-4 h-4" aria-hidden="true" />
<span class="font-mono text-sm">{{ $t('filters.columns.title') }}</span>
</button>
{{ $t('filters.columns.title') }}
</ButtonBase>

<Transition name="dropdown">
<div
Expand Down Expand Up @@ -136,13 +134,9 @@ function handleReset() {
</div>

<div class="border-t border-border py-1">
<button
type="button"
class="w-full px-3 py-2 text-start text-sm font-mono text-fg-muted hover:bg-bg-muted hover:text-fg transition-colors duration-200 focus-visible:ring-2 focus-visible:ring-fg focus-visible:ring-inset"
@click="handleReset"
>
<ButtonBase @click="handleReset">
{{ $t('filters.columns.reset') }}
</button>
</ButtonBase>
</div>
</div>
</div>
Expand Down
Loading
Loading