Skip to content

Commit 2557997

Browse files
committed
Merge branch 'fix-compare-deps' of https://github.com/gameroman/npmx.dev into fix-compare-deps
2 parents 93f3b70 + dda8d69 commit 2557997

File tree

13 files changed

+268
-149
lines changed

13 files changed

+268
-149
lines changed

app/components/Filter/Panel.vue

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -243,17 +243,16 @@ const hasActiveFilters = computed(() => !!filterSummary.value)
243243
role="radiogroup"
244244
:aria-label="$t('filters.weekly_downloads')"
245245
>
246-
<TagClickable
246+
<TagRadioButton
247247
v-for="range in DOWNLOAD_RANGES"
248248
:key="range.value"
249-
type="button"
250-
role="radio"
251-
:aria-checked="filters.downloadRange === range.value"
252-
:status="filters.downloadRange === range.value ? 'active' : 'default'"
253-
@click="emit('update:downloadRange', range.value)"
249+
:model-value="filters.downloadRange"
250+
:value="range.value"
251+
@update:modelValue="emit('update:downloadRange', $event as DownloadRange)"
252+
name="range"
254253
>
255254
{{ $t(getDownloadRangeLabelKey(range.value)) }}
256-
</TagClickable>
255+
</TagRadioButton>
257256
</div>
258257
</fieldset>
259258

@@ -267,17 +266,16 @@ const hasActiveFilters = computed(() => !!filterSummary.value)
267266
role="radiogroup"
268267
:aria-label="$t('filters.updated_within')"
269268
>
270-
<TagClickable
269+
<TagRadioButton
271270
v-for="option in UPDATED_WITHIN_OPTIONS"
272271
:key="option.value"
273-
type="button"
274-
role="radio"
275-
:aria-checked="filters.updatedWithin === option.value"
276-
:status="filters.updatedWithin === option.value ? 'active' : 'default'"
277-
@click="emit('update:updatedWithin', option.value)"
272+
:model-value="filters.updatedWithin"
273+
:value="option.value"
274+
name="updatedWithin"
275+
@update:modelValue="emit('update:updatedWithin', $event as UpdatedWithin)"
278276
>
279277
{{ $t(getUpdatedWithinLabelKey(option.value)) }}
280-
</TagClickable>
278+
</TagRadioButton>
281279
</div>
282280
</fieldset>
283281

@@ -290,17 +288,16 @@ const hasActiveFilters = computed(() => !!filterSummary.value)
290288
</span>
291289
</legend>
292290
<div class="flex flex-wrap gap-2" role="radiogroup" :aria-label="$t('filters.security')">
293-
<TagClickable
291+
<TagRadioButton
294292
v-for="security in SECURITY_FILTER_VALUES"
295293
:key="security"
296-
type="button"
297-
role="radio"
298294
disabled
299-
:aria-checked="filters.security === security"
300-
:status="filters.security === security ? 'active' : 'default'"
295+
:model-value="filters.security"
296+
:value="security"
297+
name="security"
301298
>
302299
{{ $t(getSecurityLabelKey(security)) }}
303-
</TagClickable>
300+
</TagRadioButton>
304301
</div>
305302
</fieldset>
306303

@@ -310,16 +307,14 @@ const hasActiveFilters = computed(() => !!filterSummary.value)
310307
{{ $t('filters.keywords') }}
311308
</legend>
312309
<div class="flex flex-wrap gap-1.5" role="group" :aria-label="$t('filters.keywords')">
313-
<TagClickable
310+
<TagButton
314311
v-for="keyword in displayedKeywords"
315312
:key="keyword"
316-
type="button"
317-
:aria-pressed="filters.keywords.includes(keyword)"
318-
:status="filters.keywords.includes(keyword) ? 'active' : 'default'"
313+
:pressed="filters.keywords.includes(keyword)"
319314
@click="emit('toggleKeyword', keyword)"
320315
>
321316
{{ keyword }}
322-
</TagClickable>
317+
</TagButton>
323318
<button
324319
v-if="hasMoreKeywords"
325320
type="button"

app/components/Package/Card.vue

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,16 @@ const pkgDescription = useMarkdown(() => ({
162162
:aria-label="$t('package.card.keywords')"
163163
class="relative z-10 flex flex-wrap gap-1.5 mt-3 pt-3 border-t border-border list-none m-0 p-0 pointer-events-none"
164164
>
165-
<TagClickable
165+
<TagButton
166166
v-for="keyword in result.package.keywords.slice(0, 5)"
167-
:key="keyword"
168-
type="button"
169167
class="pointer-events-auto"
170-
:status="props.filters?.keywords.includes(keyword) ? 'active' : 'default'"
168+
:key="keyword"
169+
:pressed="props.filters?.keywords.includes(keyword)"
171170
:title="`Filter by ${keyword}`"
172171
@click.stop="emit('clickKeyword', keyword)"
173172
>
174173
{{ keyword }}
175-
</TagClickable>
174+
</TagButton>
176175
<span
177176
v-if="result.package.keywords.length > 5"
178177
class="text-fg-subtle text-xs pointer-events-auto"

app/components/Package/Keywords.vue

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
<script setup lang="ts">
2-
import { NuxtLink } from '#components'
3-
42
defineProps<{
53
keywords?: string[]
64
}>()
@@ -9,9 +7,9 @@ defineProps<{
97
<CollapsibleSection v-if="keywords?.length" :title="$t('package.keywords_title')" id="keywords">
108
<ul class="flex flex-wrap gap-1.5 list-none m-0 p-0">
119
<li v-for="keyword in keywords.slice(0, 15)" :key="keyword">
12-
<TagClickable :as="NuxtLink" :to="{ name: 'search', query: { q: `keywords:${keyword}` } }">
10+
<TagLink :to="{ name: 'search', query: { q: `keywords:${keyword}` } }">
1311
{{ keyword }}
14-
</TagClickable>
12+
</TagLink>
1513
</li>
1614
</ul>
1715
</CollapsibleSection>

app/components/Package/TableRow.vue

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,17 +126,16 @@ const allMaintainersText = computed(() => {
126126
class="flex flex-wrap gap-1 justify-end"
127127
:aria-label="$t('package.card.keywords')"
128128
>
129-
<TagClickable
129+
<TagButton
130130
v-for="keyword in pkg.keywords.slice(0, 3)"
131131
:key="keyword"
132-
type="button"
133-
:status="props.filters?.keywords.includes(keyword) ? 'active' : 'default'"
132+
:pressed="props.filters?.keywords.includes(keyword)"
134133
:title="`Filter by ${keyword}`"
135134
@click.stop="emit('clickKeyword', keyword)"
136135
:class="{ 'group-hover:bg-bg-elevated': !props.filters?.keywords.includes(keyword) }"
137136
>
138137
{{ keyword }}
139-
</TagClickable>
138+
</TagButton>
140139
<span
141140
v-if="pkg.keywords.length > 3"
142141
class="text-fg-subtle text-xs"

app/components/Tag/Button.vue

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<script setup lang="ts">
2+
const props = defineProps<{
3+
disabled?: boolean
4+
/**
5+
* type should never be used, because this will always be a button.
6+
*
7+
* If you want a link use `TagLink` instead.
8+
* */
9+
type?: never
10+
pressed?: boolean
11+
}>()
12+
</script>
13+
14+
<template>
15+
<button
16+
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"
17+
:class="[
18+
pressed
19+
? 'bg-fg text-bg border-fg hover:(text-text-bg/50)'
20+
: 'bg-bg-muted text-fg-muted border-border hover:(text-fg border-border-hover)',
21+
{
22+
'opacity-50 cursor-not-allowed': disabled,
23+
},
24+
]"
25+
type="button"
26+
:disabled="disabled ? true : undefined"
27+
:aria-pressed="pressed"
28+
>
29+
<slot />
30+
</button>
31+
</template>

app/components/Tag/Clickable.vue

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

app/components/Tag/Link.vue

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<script setup lang="ts">
2+
import type { NuxtLinkProps } from '#app'
3+
4+
const { current, ...props } = defineProps<
5+
{
6+
/** Disabled links will be displayed as plain text */
7+
disabled?: boolean
8+
/**
9+
* `type` should never be used, because this will always be a link.
10+
*
11+
* If you want a button use `TagButton` instead.
12+
* */
13+
type?: never
14+
current?: boolean
15+
} &
16+
/** This makes sure the link always has either `to` or `href` */
17+
(Required<Pick<NuxtLinkProps, 'to'>> | Required<Pick<NuxtLinkProps, 'href'>>) &
18+
NuxtLinkProps
19+
>()
20+
</script>
21+
22+
<template>
23+
<!-- This is only a placeholder implementation yet. It will probably need some additional styling, but note: A disabled link is just text. -->
24+
<span v-if="disabled" class="opacity-50"><slot /></span>
25+
<NuxtLink
26+
v-else
27+
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"
28+
:class="{
29+
'bg-bg-muted text-fg-muted border-border hover:(text-fg border-border-hover)': !current,
30+
'bg-fg text-bg border-fg hover:(text-text-bg/50)': current,
31+
'opacity-50 cursor-not-allowed': disabled,
32+
}"
33+
v-bind="props"
34+
>
35+
<slot />
36+
</NuxtLink>
37+
</template>

app/components/Tag/RadioButton.vue

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<script setup lang="ts">
2+
const model = defineModel<string>()
3+
4+
const props = defineProps<{
5+
disabled?: boolean
6+
/**
7+
* type should never be used, because this will always be a radio button.
8+
*
9+
* If you want a link use `TagLink` instead.
10+
* */
11+
type?: never
12+
13+
/** Shouldn't try to set `checked` explicitly, is handled internally */
14+
checked?: never
15+
value: string
16+
}>()
17+
18+
const uid = useId()
19+
const internalId = `${model.value}-${uid}`
20+
const checked = computed(() => model.value === props.value)
21+
/** Todo: This shouldn't be necessary, but using v-model on `input type=radio` doesn't work as expected in Vue */
22+
const onChange = () => {
23+
model.value = props.value
24+
}
25+
</script>
26+
27+
<template>
28+
<div>
29+
<input
30+
type="radio"
31+
:id="internalId"
32+
:value="props.value"
33+
:checked="checked"
34+
:disabled="props.disabled ? true : undefined"
35+
@change="onChange"
36+
class="peer sr-only"
37+
/>
38+
<label
39+
class="bg-bg-muted text-fg-muted border-border hover:(text-fg border-border-hover) inline-flex items-center px-2 py-0.5 text-xs font-mono border rounded transition-colors duration-200 peer-focus:ring-2 peer-focus:ring-fg border-none peer-checked:(bg-fg text-bg border-fg hover:(text-text-bg/50)) peer-disabled:(opacity-50 pointer-events-none)"
40+
:htmlFor="internalId"
41+
>
42+
<slot />
43+
</label>
44+
</div>
45+
</template>

docs/content/2.guide/1.features.md

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -93,38 +93,42 @@ Quick access to online development environments detected from package READMEs:
9393
### Custom badges
9494

9595
You can add custom npmx badges to your markdown files using the following syntax:
96-
`[![Open on npmx.dev](https://npmx.dev/api/registry/badge/TYPE/YOUR_PACKAGE)](https://npmx.dev/package/YOUR_PACKAGE)`
9796

98-
> [!IMPORTANT]
99-
> Make sure to replace `TYPE` with one of the options listed below and `YOUR_PACKAGE` with the actual package name (e.g., `vue`, `lodash`, or `@nuxt/kit`).
97+
```md
98+
[![Open on npmx.dev](https://npmx.dev/api/registry/badge/TYPE/YOUR_PACKAGE)](https://npmx.dev/package/YOUR_PACKAGE)
99+
```
100+
101+
::tip
102+
Make sure to replace `TYPE` with one of the options listed below and `YOUR_PACKAGE` with the actual package name (e.g., `vue`, `lodash`, or `@nuxt/kit`).
103+
::
100104

101105
#### Available Badge Types
102106

103-
- **version**: Shows the latest or specific version of the package. ![](https://img.shields.io/badge/%233b82f6-3b82f6)
104-
- **license**: Displays the package license (e.g., MIT, Apache-2.0). ![](https://img.shields.io/badge/%2322c55e-22c55e)
105-
- **size**: Shows the install size (via Bundlephobia) or unpacked size. ![](https://img.shields.io/badge/%23a855f7-a855f7)
106-
- **downloads**: Displays monthly download statistics. ![](https://img.shields.io/badge/%23f97316-f97316)
107-
- **downloads-day**: Displays daily download statistics. ![](https://img.shields.io/badge/%23f97316-f97316)
108-
- **downloads-week**: Displays weekly download statistics. ![](https://img.shields.io/badge/%23f97316-f97316)
109-
- **downloads-month**: Alias for monthly download statistics. ![](https://img.shields.io/badge/%23f97316-f97316)
110-
- **downloads-year**: Displays yearly download statistics. ![](https://img.shields.io/badge/%23f97316-f97316)
111-
- **vulnerabilities**: Shows the number of vulnerabilities found via OSV. ![](https://img.shields.io/badge/%2322c55e-22c55e) / ![](https://img.shields.io/badge/%23ef4444-ef4444)
112-
- **dependencies**: Lists the total count of package dependencies. ![](https://img.shields.io/badge/%2306b6d4-06b6d4)
113-
- **created**: Displays the date the package was first published. ![](https://img.shields.io/badge/%2364748b-64748b)
114-
- **updated**: Displays the date of the most recent modification. ![](https://img.shields.io/badge/%2364748b-64748b)
115-
- **engines**: Shows the supported Node.js version range. ![](https://img.shields.io/badge/%23eab308-eab308)
116-
- **types**: Indicates if TypeScript types are included. ![](https://img.shields.io/badge/%233b82f6-3b82f6) / ![](https://img.shields.io/badge/%2364748b-64748b)
117-
- **maintainers**: Displays the total count of package maintainers. ![](https://img.shields.io/badge/%2306b6d4-06b6d4)
118-
- **deprecated**: Shows if the package is active or deprecated. ![](https://img.shields.io/badge/%2322c55e-22c55e) / ![](https://img.shields.io/badge/%23ef4444-ef4444)
119-
- **quality**: NPMS.io quality score based on linting and tests. ![](https://img.shields.io/badge/%23a855f7-a855f7)
120-
- **popularity**: NPMS.io popularity score based on downloads and stars. ![](https://img.shields.io/badge/%2306b6d4-06b6d4)
121-
- **maintenance**: NPMS.io maintenance score based on activity. ![](https://img.shields.io/badge/%23eab308-eab308)
122-
- **score**: The overall NPMS.io combined score. ![](https://img.shields.io/badge/%233b82f6-3b82f6)
123-
- **name**: Simple badge displaying the package name. ![](https://img.shields.io/badge/%2364748b-64748b)
107+
- **version**: Shows the latest or specific version of the package. :img{src="https://img.shields.io/badge/%233b82f6-3b82f6" class="inline align-middle h-5 w-14"}
108+
- **license**: Displays the package license (e.g., MIT, Apache-2.0). :img{src="https://img.shields.io/badge/%2322c55e-22c55e" class="inline align-middle h-5 w-14"}
109+
- **size**: Shows the install size (via Bundlephobia) or unpacked size. :img{src="https://img.shields.io/badge/%23a855f7-a855f7" class="inline align-middle h-5 w-14"}
110+
- **downloads**: Displays monthly download statistics. :img{src="https://img.shields.io/badge/%23f97316-f97316" class="inline align-middle h-5 w-14"}
111+
- **downloads-day**: Displays daily download statistics. :img{src="https://img.shields.io/badge/%23f97316-f97316" class="inline align-middle h-5 w-14"}
112+
- **downloads-week**: Displays weekly download statistics. :img{src="https://img.shields.io/badge/%23f97316-f97316" class="inline align-middle h-5 w-14"}
113+
- **downloads-month**: Alias for monthly download statistics. :img{src="https://img.shields.io/badge/%23f97316-f97316" class="inline align-middle h-5 w-14"}
114+
- **downloads-year**: Displays yearly download statistics. :img{src="https://img.shields.io/badge/%23f97316-f97316" class="inline align-middle h-5 w-14"}
115+
- **vulnerabilities**: Shows the number of vulnerabilities found via OSV. :img{src="https://img.shields.io/badge/%2322c55e-22c55e" class="inline align-middle h-5 w-14"} / :img{src="https://img.shields.io/badge/%23ef4444-ef4444" class="inline align-middle h-5 w-14"}
116+
- **dependencies**: Lists the total count of package dependencies. :img{src="https://img.shields.io/badge/%2306b6d4-06b6d4" class="inline align-middle h-5 w-14"}
117+
- **created**: Displays the date the package was first published. :img{src="https://img.shields.io/badge/%2364748b-64748b" class="inline align-middle h-5 w-14"}
118+
- **updated**: Displays the date of the most recent modification. :img{src="https://img.shields.io/badge/%2364748b-64748b" class="inline align-middle h-5 w-14"}
119+
- **engines**: Shows the supported Node.js version range. :img{src="https://img.shields.io/badge/%23eab308-eab308" class="inline align-middle h-5 w-14"}
120+
- **types**: Indicates if TypeScript types are included. :img{src="https://img.shields.io/badge/%233b82f6-3b82f6" class="inline align-middle h-5 w-14"} / :img{src="https://img.shields.io/badge/%2364748b-64748b" class="inline align-middle h-5 w-14"}
121+
- **maintainers**: Displays the total count of package maintainers. :img{src="https://img.shields.io/badge/%2306b6d4-06b6d4" class="inline align-middle h-5 w-14"}
122+
- **deprecated**: Shows if the package is active or deprecated. :img{src="https://img.shields.io/badge/%2322c55e-22c55e" class="inline align-middle h-5 w-14"} / :img{src="https://img.shields.io/badge/%23ef4444-ef4444" class="inline align-middle h-5 w-14"}
123+
- **quality**: NPMS.io quality score based on linting and tests. :img{src="https://img.shields.io/badge/%23a855f7-a855f7" class="inline align-middle h-5 w-14"}
124+
- **popularity**: NPMS.io popularity score based on downloads and stars. :img{src="https://img.shields.io/badge/%2306b6d4-06b6d4" class="inline align-middle h-5 w-14"}
125+
- **maintenance**: NPMS.io maintenance score based on activity. :img{src="https://img.shields.io/badge/%23eab308-eab308" class="inline align-middle h-5 w-14"}
126+
- **score**: The overall NPMS.io combined score. :img{src="https://img.shields.io/badge/%233b82f6-3b82f6" class="inline align-middle h-5 w-14"}
127+
- **name**: Simple badge displaying the package name. :img{src="https://img.shields.io/badge/%2364748b-64748b" class="inline align-middle h-5 w-14"}
124128

125129
#### Examples
126130

127-
```markdown
131+
```md
128132
# Version Badge
129133

130134
[![Open on npmx.dev](https://npmx.dev/api/registry/badge/version/nuxt)](https://npmx.dev/package/nuxt)

0 commit comments

Comments
 (0)