Skip to content

Commit 7c6a138

Browse files
authored
Merge branch 'main' into main
2 parents a44570c + f5a7c14 commit 7c6a138

File tree

47 files changed

+1271
-225
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1271
-225
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/Header/AccountMenu.client.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script setup lang="ts">
2+
import { useAtproto } from '~/composables/atproto/useAtproto'
23
import { useModal } from '~/composables/useModal'
34
45
const {

app/components/Header/AuthModal.client.vue

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,22 @@
11
<script setup lang="ts">
2+
import { useAtproto } from '~/composables/atproto/useAtproto'
3+
import { authRedirect } from '~/utils/atproto/helpers'
4+
25
const handleInput = shallowRef('')
36
47
const { user, logout } = useAtproto()
58
69
async function handleBlueskySignIn() {
7-
await navigateTo(
8-
{
9-
path: '/api/auth/atproto',
10-
query: { handle: 'https://bsky.social' },
11-
},
12-
{ external: true },
13-
)
10+
await authRedirect('https://bsky.social')
1411
}
1512
1613
async function handleCreateAccount() {
17-
await navigateTo(
18-
{
19-
path: '/api/auth/atproto',
20-
query: { handle: 'https://npmx.social', create: 'true' },
21-
},
22-
{ external: true },
23-
)
14+
await authRedirect('https://npmx.social', true)
2415
}
2516
2617
async function handleLogin() {
2718
if (handleInput.value) {
28-
await navigateTo(
29-
{
30-
path: '/api/auth/atproto',
31-
query: { handle: handleInput.value },
32-
},
33-
{ external: true },
34-
)
19+
await authRedirect(handleInput.value)
3520
}
3621
}
3722
</script>

app/components/Header/MobileMenu.client.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
import { useFocusTrap } from '@vueuse/integrations/useFocusTrap'
3+
import { useAtproto } from '~/composables/atproto/useAtproto'
34
45
const isOpen = defineModel<boolean>('open', { default: false })
56

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>

0 commit comments

Comments
 (0)