Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
4 changes: 2 additions & 2 deletions app/components/Filter/Chips.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const emit = defineEmits<{
<template>
<div v-if="chips.length > 0" class="flex flex-wrap items-center gap-2">
<TransitionGroup name="chip">
<span v-for="chip in chips" :key="chip.id" class="tag gap-1">
<TagStatic v-for="chip in chips" :key="chip.id" class="gap-1">
<span class="text-fg-subtle text-xs">{{ chip.label }}:</span>
<span class="max-w-32 truncate">{{
Array.isArray(chip.value) ? chip.value.join(', ') : chip.value
Expand All @@ -27,7 +27,7 @@ const emit = defineEmits<{
>
<span class="i-carbon-close w-3 h-3" aria-hidden="true" />
</button>
</span>
</TagStatic>
</TransitionGroup>

<button
Expand Down
40 changes: 12 additions & 28 deletions app/components/Filter/Panel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -243,22 +243,17 @@ const hasActiveFilters = computed(() => !!filterSummary.value)
role="radiogroup"
:aria-label="$t('filters.weekly_downloads')"
>
<button
<TagClickable
v-for="range in DOWNLOAD_RANGES"
:key="range.value"
type="button"
role="radio"
:aria-checked="filters.downloadRange === range.value"
class="tag transition-colors duration-200 focus-visible:ring-2 focus-visible:ring-fg focus-visible:ring-offset-1"
:class="
filters.downloadRange === range.value
? 'bg-fg text-bg border-fg hover:text-bg/50'
: ''
"
:status="filters.downloadRange === range.value ? 'active' : 'default'"
@click="emit('update:downloadRange', range.value)"
>
{{ $t(getDownloadRangeLabelKey(range.value)) }}
</button>
</TagClickable>
</div>
</fieldset>

Expand All @@ -272,22 +267,17 @@ const hasActiveFilters = computed(() => !!filterSummary.value)
role="radiogroup"
:aria-label="$t('filters.updated_within')"
>
<button
<TagClickable
v-for="option in UPDATED_WITHIN_OPTIONS"
:key="option.value"
type="button"
role="radio"
:aria-checked="filters.updatedWithin === option.value"
class="tag transition-colors duration-200 focus-visible:ring-2 focus-visible:ring-fg focus-visible:ring-offset-1"
:class="
filters.updatedWithin === option.value
? 'bg-fg text-bg border-fg hover:text-bg/70'
: ''
"
:status="filters.updatedWithin === option.value ? 'active' : 'default'"
@click="emit('update:updatedWithin', option.value)"
>
{{ $t(getUpdatedWithinLabelKey(option.value)) }}
</button>
</TagClickable>
</div>
</fieldset>

Expand All @@ -300,20 +290,17 @@ const hasActiveFilters = computed(() => !!filterSummary.value)
</span>
</legend>
<div class="flex flex-wrap gap-2" role="radiogroup" :aria-label="$t('filters.security')">
<button
<TagClickable
v-for="option in SECURITY_FILTER_OPTIONS"
:key="option.value"
type="button"
role="radio"
disabled
:aria-checked="filters.security === option.value"
class="tag transition-colors duration-200 opacity-50 cursor-not-allowed focus-visible:ring-2 focus-visible:ring-fg focus-visible:ring-offset-1"
:class="
filters.security === option.value ? 'bg-fg text-bg border-fg hover:text-bg/70' : ''
"
:status="filters.security === option.value ? 'active' : 'default'"
>
{{ $t(getSecurityLabelKey(option.value)) }}
</button>
</TagClickable>
</div>
</fieldset>

Expand All @@ -323,19 +310,16 @@ const hasActiveFilters = computed(() => !!filterSummary.value)
{{ $t('filters.keywords') }}
</legend>
<div class="flex flex-wrap gap-1.5" role="group" :aria-label="$t('filters.keywords')">
<button
<TagClickable
v-for="keyword in displayedKeywords"
:key="keyword"
type="button"
:aria-pressed="filters.keywords.includes(keyword)"
class="tag text-xs transition-colors duration-200 focus-visible:ring-2 focus-visible:ring-fg focus-visible:ring-offset-1"
:class="
filters.keywords.includes(keyword) ? 'bg-fg text-bg border-fg hover:text-bg/70' : ''
"
:status="filters.keywords.includes(keyword) ? 'active' : 'default'"
@click="emit('toggleKeyword', keyword)"
>
{{ keyword }}
</button>
</TagClickable>
<button
v-if="hasMoreKeywords"
type="button"
Expand Down
4 changes: 2 additions & 2 deletions app/components/Package/Card.vue
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ const pkgDescription = useMarkdown(() => ({
:aria-label="$t('package.card.keywords')"
class="relative z-10 flex flex-wrap gap-1.5 mt-3 pt-3 border-t border-border list-none m-0 p-0"
>
<li v-for="keyword in result.package.keywords.slice(0, 5)" :key="keyword" class="tag">
<TagStatic as="li" v-for="keyword in result.package.keywords.slice(0, 5)" :key="keyword">
{{ keyword }}
</li>
</TagStatic>
</ul>
</BaseCard>
</template>
5 changes: 2 additions & 3 deletions app/components/Package/TableRow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -118,16 +118,15 @@ const allMaintainersText = computed(() => {
<!-- Keywords -->
<td v-if="isColumnVisible('keywords')" class="py-2 px-3">
<div v-if="pkg.keywords?.length" class="flex flex-wrap gap-1">
<button
<TagClickable
v-for="keyword in pkg.keywords.slice(0, 3)"
:key="keyword"
type="button"
class="tag text-xs hover:bg-fg hover:text-bg hover:border-fg transition-colors duration-200 focus-visible:ring-2 focus-visible:ring-fg focus-visible:ring-offset-1"
:title="`Filter by ${keyword}`"
@click.stop="emit('clickKeyword', keyword)"
>
{{ keyword }}
</button>
</TagClickable>
<span v-if="pkg.keywords.length > 3" class="text-fg-subtle text-xs">
+{{ pkg.keywords.length - 3 }}
</span>
Expand Down
25 changes: 25 additions & 0 deletions app/components/Tag/Clickable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<script setup lang="ts">
const props = withDefaults(
defineProps<{ as?: string | Component; status?: 'default' | 'active'; disabled?: boolean }>(),
{
status: 'default',
as: 'button',
},
)
</script>

<template>
<component
:is="props.as"
class="inline-flex items-center px-2 py-0.5 text-xs font-mono border rounded transition-colors duration-200 focus-visible:ring-2 focus-visible:ring-fg focus-visible:ring-offset-1"
:class="{
'bg-bg-muted text-fg-muted border-border hover:(text-fg border-border-hover)':
props.status === 'default',
'bg-fg text-bg border-fg hover:(text-text-bg/50)': props.status === 'active',
'opacity-50 cursor-not-allowed': props.disabled,
}"
:disabled="props.disabled"
Comment thread
danielroe marked this conversation as resolved.
Outdated
>
<slot />
</component>
</template>
12 changes: 12 additions & 0 deletions app/components/Tag/Static.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script setup lang="ts">
const props = withDefaults(defineProps<{ as?: string | Component }>(), { as: 'span' })
</script>

<template>
<component
:is="props.as"
Comment thread
danielroe marked this conversation as resolved.
Outdated
class="inline-flex items-center px-2 py-0.5 text-xs font-mono text-fg-muted bg-bg-muted border border-border rounded"
>
<slot />
</component>
</template>
8 changes: 6 additions & 2 deletions app/pages/package/[...package].vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { joinURL } from 'ufo'
import { areUrlsEquivalent } from '#shared/utils/url'
import { isEditableElement } from '~/utils/input'
import { formatBytes } from '~/utils/formatters'
import { NuxtLink } from '#components'

definePageMeta({
name: 'package',
Expand Down Expand Up @@ -1005,9 +1006,12 @@ defineOgImageComponent('Package', {
</h2>
<ul class="flex flex-wrap gap-1.5 list-none m-0 p-0">
<li v-for="keyword in displayVersion.keywords.slice(0, 15)" :key="keyword">
<NuxtLink :to="{ name: 'search', query: { q: `keywords:${keyword}` } }" class="tag">
<TagClickable
:as="NuxtLink"
:to="{ name: 'search', query: { q: `keywords:${keyword}` } }"
>
{{ keyword }}
</NuxtLink>
</TagClickable>
</li>
</ul>
</section>
Expand Down
40 changes: 40 additions & 0 deletions test/nuxt/a11y.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ import {
SettingsAccentColorPicker,
SettingsBgThemePicker,
SettingsToggle,
TagStatic,
TagClickable,
TerminalExecute,
TerminalInstall,
TooltipAnnounce,
Expand Down Expand Up @@ -232,6 +234,44 @@ describe('component accessibility audits', () => {
})
})

describe('TagStatic', () => {
it('should have no accessibility violations', async () => {
const component = await mountSuspended(TagStatic, {
slots: { default: 'Tag content' },
})
const results = await runAxe(component)
expect(results.violations).toEqual([])
})
})

describe('TagClickable', () => {
it('should have no accessibility violations', async () => {
const component = await mountSuspended(TagClickable, {
slots: { default: 'Tag content' },
})
const results = await runAxe(component)
expect(results.violations).toEqual([])
})

it('should have no accessibility violationst for active state', async () => {
const component = await mountSuspended(TagClickable, {
props: { status: 'active' },
slots: { default: 'Tag content' },
})
const results = await runAxe(component)
expect(results.violations).toEqual([])
})

it('should have no accessibility violationst for disabled state', async () => {
const component = await mountSuspended(TagClickable, {
props: { disabled: true },
slots: { default: 'Tag content' },
})
const results = await runAxe(component)
expect(results.violations).toEqual([])
})
})

describe('TooltipApp', () => {
it('should have no accessibility violations', async () => {
const component = await mountSuspended(TooltipApp, {
Expand Down
6 changes: 1 addition & 5 deletions uno.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,7 @@ export default defineConfig({
],
['link-subtle', 'text-fg-muted hover:text-fg transition-colors duration-200 focus-ring'],

// Tags/badges
[
'tag',
'inline-flex items-center px-2 py-0.5 text-xs font-mono text-fg-muted bg-bg-muted border border-border rounded transition-colors duration-200 hover:(text-fg border-border-hover)',
],
// badges
['badge-orange', 'bg-badge-orange/10 text-badge-orange'],
['badge-yellow', 'bg-badge-yellow/10 text-badge-yellow'],
['badge-green', 'bg-badge-green/10 text-badge-green'],
Expand Down
Loading