@@ -38,19 +38,28 @@ const { user } = useAtproto()
3838const authModal = useModal (' auth-modal' )
3939const compactNumberFormatter = useCompactNumberFormatter ()
4040
41- const { data : likesData } = useFetch <PackageLikes >(() => ` /api/social/likes/${props .packageName } ` , {
42- default : () => ({
43- totalLikes: 0 ,
44- userHasLiked: false ,
45- topLikedRank: null ,
46- }),
47- server: false ,
48- })
41+ const { data : likesData, status : likeStatus } = useFetch <PackageLikes >(
42+ () => ` /api/social/likes/${props .packageName } ` ,
43+ {
44+ default : () => ({
45+ totalLikes: 0 ,
46+ userHasLiked: false ,
47+ topLikedRank: null ,
48+ }),
49+ server: false ,
50+ },
51+ )
52+ const isLoadingLikeData = computed (
53+ () => likeStatus .value === ' pending' || likeStatus .value === ' idle' ,
54+ )
4955const isPackageLiked = computed (() => likesData .value ?.userHasLiked ?? false )
5056const topLikedRank = computed (() => likesData .value ?.topLikedRank ?? null )
5157const likeButtonLabel = computed (() =>
5258 isPackageLiked .value ? $t (' package.likes.unlike' ) : $t (' package.likes.like' ),
5359)
60+ const likeTooltipLabel = computed (() =>
61+ isLoadingLikeData .value ? $t (' common.loading' ) : likeButtonLabel .value ,
62+ )
5463const topLikedBadgeLabel = computed (() =>
5564 topLikedRank .value == null
5665 ? ' '
@@ -105,6 +114,7 @@ const likeAction = async () => {
105114 ? {
106115 ... previousLikesState ,
107116 ... result .data ,
117+ topLikedRank: result .data .topLikedRank ?? previousLikesState .topLikedRank ,
108118 }
109119 : previousLikesState
110120 } catch {
@@ -117,7 +127,7 @@ const likeAction = async () => {
117127
118128<template >
119129 <div class =" relative inline-flex items-center" >
120- <TooltipApp :text =" likeButtonLabel " position =" bottom" class =" items-center" strategy =" fixed" >
130+ <TooltipApp :text =" likeTooltipLabel " position =" bottom" class =" items-center" strategy =" fixed" >
121131 <div class =" relative inline-flex" >
122132 <span v-if =" showLikeFloat" :key =" likeFloatKey" aria-hidden =" true" class =" like-float"
123133 >+1</span
@@ -139,7 +149,12 @@ const likeAction = async () => {
139149 aria-hidden =" true"
140150 class =" inline-block w-4 h-4"
141151 />
142- <span >{{ compactNumberFormatter.format(likesData?.totalLikes ?? 0) }}</span >
152+ <span
153+ v-if =" isLoadingLikeData"
154+ class =" i-svg-spinners:ring-resize w-3 h-3 my-0.5"
155+ aria-hidden =" true"
156+ />
157+ <span v-else >{{ compactNumberFormatter.format(likesData?.totalLikes ?? 0) }}</span >
143158 </ButtonBase >
144159 </div >
145160 </TooltipApp >
@@ -150,13 +165,13 @@ const likeAction = async () => {
150165 position =" left"
151166 :offset =" 8"
152167 strategy =" fixed"
153- class =" absolute [inset-inline-end:-0.5rem] top-[-0.4rem] z-1 "
168+ class =" top-liked-badge-anchor "
154169 >
155170 <NuxtLink
156171 :to =" { name: 'leaderboard-likes' }"
157172 :aria-label =" topLikedBadgeLabel"
158173 data-testid =" top-liked-badge"
159- class =" inline-flex items-center justify-center min-w-5 rounded-full px-1.5 py-0.5 text-2xs font-bold leading-none no-underline text-[var(--bg)] border border-[var(--bg)] bg-[radial-gradient(circle_at_28%_25%,rgb(255_255_255_/_0.34),transparent_38%),linear-gradient(135deg,color-mix(in_oklab,white_10%,var(--accent))_0%,var(--accent)_100%)] shadow-[0_1px_0_rgb(255_255_255_/_0.32)_inset,0_2px_6px_color-mix(in_oklab,var(--accent)_14%,transparent)] transition-shadow duration-[160ms] hover:shadow-[0_1px_0_rgb(255_255_255_/_0.38)_inset,0_4px_10px_color-mix(in_oklab,var(--accent)_18%,transparent)] focus-visible:outline-2 focus-visible:outline-fg focus-visible:outline-offset-2 "
174+ class =" top-liked-badge "
160175 >
161176 <span >{{ $t('package.likes.top_rank_label', { rank: topLikedRank }) }}</span >
162177 </NuxtLink >
@@ -177,6 +192,40 @@ const likeAction = async () => {
177192 animation : float-up 0.75s cubic-bezier (0.25 , 0.46 , 0.45 , 0.94 ) forwards ;
178193}
179194
195+ .top-liked-badge-anchor {
196+ position : absolute ;
197+ inset-inline-end : -0.5rem ;
198+ top : -0.4rem ;
199+ z-index : 1 ;
200+ }
201+
202+ .top-liked-badge {
203+ display : inline-flex ;
204+ align-items : center ;
205+ justify-content : center ;
206+ min-width : 1.25rem ;
207+ padding : 0.125rem 0.375rem ;
208+ border : 1px solid var (--bg );
209+ border-radius : 9999px ;
210+ background : var (--accent );
211+ color : var (--bg );
212+ font-size : 0.6875rem ;
213+ font-weight : 700 ;
214+ line-height : 1 ;
215+ text-decoration : none ;
216+ box-shadow : 0 2px 6px color-mix(in oklab, var (--accent ) 14% , transparent );
217+ transition : box-shadow 160ms ease ;
218+ }
219+
220+ .top-liked-badge :hover {
221+ box-shadow : 0 4px 10px color-mix(in oklab, var (--accent ) 18% , transparent );
222+ }
223+
224+ .top-liked-badge :focus-visible {
225+ outline : 2px solid var (--fg );
226+ outline-offset : 2px ;
227+ }
228+
180229@media (prefers-reduced-motion: reduce) {
181230 .like-float {
182231 display : none ;
0 commit comments