Skip to content

Commit dfc4d7d

Browse files
committed
rename BasicCard to LikeCard, copy paste like button to card
1 parent c467c3e commit dfc4d7d

3 files changed

Lines changed: 105 additions & 24 deletions

File tree

app/components/Package/BasicCard.vue

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<script setup lang="ts">
2+
const props = defineProps<{
3+
packageUrl: string
4+
}>()
5+
6+
function extractPackageFromRef(ref: string) {
7+
const { pkg } = /https:\/\/npmx.dev\/package\/(?<pkg>.*)/.exec(ref).groups
8+
return pkg
9+
}
10+
11+
const name = computed(() => extractPackageFromRef(props.packageUrl))
12+
13+
const { user } = useAtproto()
14+
15+
const authModal = useModal('auth-modal')
16+
17+
const { data: likesData } = useFetch(() => `/api/social/likes/${name}`, {
18+
default: () => ({ totalLikes: 0, userHasLiked: false }),
19+
server: false,
20+
})
21+
22+
const isLikeActionPending = ref(false)
23+
24+
const likeAction = async () => {
25+
if (user.value?.handle == null) {
26+
authModal.open()
27+
return
28+
}
29+
30+
if (isLikeActionPending.value) return
31+
32+
const currentlyLiked = likesData.value?.userHasLiked ?? false
33+
const currentLikes = likesData.value?.totalLikes ?? 0
34+
35+
// Optimistic update
36+
likesData.value = {
37+
totalLikes: currentlyLiked ? currentLikes - 1 : currentLikes + 1,
38+
userHasLiked: !currentlyLiked,
39+
}
40+
41+
isLikeActionPending.value = true
42+
43+
try {
44+
const result = await togglePackageLike(name, currentlyLiked, user.value?.handle)
45+
46+
isLikeActionPending.value = false
47+
48+
if (result.success) {
49+
// Update with server response
50+
likesData.value = result.data
51+
} else {
52+
// Revert on error
53+
likesData.value = {
54+
totalLikes: currentLikes,
55+
userHasLiked: currentlyLiked,
56+
}
57+
}
58+
} catch {
59+
// Revert on error
60+
likesData.value = {
61+
totalLikes: currentLikes,
62+
userHasLiked: currentlyLiked,
63+
}
64+
isLikeActionPending.value = false
65+
}
66+
}
67+
</script>
68+
69+
<template>
70+
<NuxtLink :to="packageRoute(name)">
71+
<BaseCard class="group font-mono flex justify-between">
72+
{{ name }}
73+
<ClientOnly>
74+
<TooltipApp
75+
:text="likesData?.userHasLiked ? $t('package.likes.unlike') : $t('package.likes.like')"
76+
position="bottom"
77+
>
78+
<button
79+
@click="likeAction"
80+
type="button"
81+
:title="likesData?.userHasLiked ? $t('package.likes.unlike') : $t('package.likes.like')"
82+
class="inline-flex items-center gap-1.5 font-mono text-sm text-fg hover:text-fg-muted transition-colors duration-200"
83+
:aria-label="
84+
likesData?.userHasLiked ? $t('package.likes.unlike') : $t('package.likes.like')
85+
"
86+
>
87+
<span
88+
:class="
89+
likesData?.userHasLiked
90+
? 'i-lucide-heart-minus text-red-500'
91+
: 'i-lucide-heart-plus'
92+
"
93+
class="w-4 h-4"
94+
aria-hidden="true"
95+
/>
96+
<span>{{ formatCompactNumber(likesData?.totalLikes ?? 0, { decimals: 1 }) }}</span>
97+
</button>
98+
</TooltipApp>
99+
</ClientOnly>
100+
<p class="transition-transform duration-150 group-hover:rotate-45">↗</p>
101+
</BaseCard>
102+
</NuxtLink>
103+
</template>

app/pages/profile/[handle]/index.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ defineOgImageComponent('Default', {
6767
<p>Error</p>
6868
</div>
6969
<div v-else class="grid grid-cols-1 lg:grid-cols-3 gap-4">
70-
<PackageBasicCard
70+
<PackageLikeCard
7171
v-if="likesData.likes.records"
7272
v-for="like in likesData.likes.records"
73-
:packageName="like.value.subjectRef"
73+
:packageUrl="like.value.subjectRef"
7474
/>
7575
</div>
7676
</section>

0 commit comments

Comments
 (0)