Skip to content

Commit ce0e078

Browse files
Merge pull request #105 from planetscale/heart-hover
fix liked by
2 parents c2ba875 + 2ab9031 commit ce0e078

File tree

4 files changed

+76
-64
lines changed

4 files changed

+76
-64
lines changed

src/app/(default)/post/[id]/page.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export default async function PostPage({ params }: PostPageParams) {
7070
<HtmlView html={post.contentHtml} className="mt-8" />
7171
<div className="flex gap-4 mt-6">
7272
<ReactionButton
73+
likedBy={post.likedBy}
7374
likeCount={post.likedBy.length}
7475
isLikedByCurrentUser={post.isLikedByCurrentUser}
7576
id={post.id}

src/app/_components/like-button.tsx

Lines changed: 56 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,22 @@ import HeartIcon from '../_svg/heart-icon'
88
import { api } from '~/trpc/react'
99
import { useRouter } from 'next/navigation'
1010
import { useState } from 'react'
11+
import { LikedBy } from './liked-by'
12+
import { type RouterOutputs } from '~/trpc/shared'
1113

1214
export const MAX_LIKED_BY_SHOWN = 50
1315

1416
type LikeButtonProps = {
1517
likeCount: number
1618
isLikedByCurrentUser: boolean
19+
likedBy: RouterOutputs['post']['detail']['likedBy']
1720
id: number
1821
}
1922

2023
export const ReactionButton = ({
2124
id,
2225
likeCount,
26+
likedBy,
2327
isLikedByCurrentUser,
2428
}: LikeButtonProps) => {
2529
const [isAnimating, setIsAnimating] = useState(false)
@@ -50,53 +54,58 @@ export const ReactionButton = ({
5054
}
5155

5256
return (
53-
<Button
54-
variant="secondary"
55-
className={classNames(
56-
'transition-colors overflow-hidden [transform:translateZ(0)] space-x-1.5',
57-
{
58-
'border-red-300 !bg-red-100 dark:!bg-red-900 dark:border-red-700':
59-
isLikedByCurrentUser,
60-
'!border-red-600 !bg-red-600 dark:!bg-red-600': isAnimating,
61-
},
62-
)}
63-
onClick={handleReaction}
64-
disabled={like.isLoading}
65-
>
66-
<span className="relative block w-4 h-4 shrink-0">
67-
{isLikedByCurrentUser && !isAnimating ? (
68-
<HeartFilledIcon className="absolute inset-0 text-red scale-1" />
69-
) : (
70-
<>
71-
<HeartIcon
72-
className={classNames(
73-
'absolute inset-0 transition-all text-red fill-transparent transform-gpu',
74-
{ 'scale-[12] fill-red-600': isAnimating },
75-
)}
76-
/>
77-
<span
78-
className={classNames(
79-
'absolute w-4 h-4 top-0 left-[-.5px] rounded-full ring-inset ring-6 ring-gray-50 transition-all duration-300 transform-gpu z-10',
80-
isAnimating ? 'scale-150 !ring-0' : 'scale-0',
81-
)}
82-
></span>
83-
<HeartFilledIcon
84-
className={classNames(
85-
'absolute inset-0 transition-transform delay-200 duration-300 text-gray-50 transform-gpu z-10 ease-spring',
86-
isAnimating ? 'scale-1' : 'scale-0',
87-
)}
88-
/>
89-
</>
90-
)}
91-
</span>
57+
<LikedBy
58+
likedBy={likedBy}
59+
trigger={
60+
<Button
61+
variant="secondary"
62+
className={classNames(
63+
'transition-colors overflow-hidden [transform:translateZ(0)] space-x-1.5',
64+
{
65+
'border-red-300 !bg-red-100 dark:!bg-red-900 dark:border-red-700':
66+
isLikedByCurrentUser,
67+
'!border-red-600 !bg-red-600 dark:!bg-red-600': isAnimating,
68+
},
69+
)}
70+
onClick={handleReaction}
71+
disabled={like.isLoading}
72+
>
73+
<span className="relative block w-4 h-4 shrink-0">
74+
{isLikedByCurrentUser && !isAnimating ? (
75+
<HeartFilledIcon className="absolute inset-0 text-red scale-1" />
76+
) : (
77+
<>
78+
<HeartIcon
79+
className={classNames(
80+
'absolute inset-0 transition-all text-red fill-transparent transform-gpu',
81+
{ 'scale-[12] fill-red-600': isAnimating },
82+
)}
83+
/>
84+
<span
85+
className={classNames(
86+
'absolute w-4 h-4 top-0 left-[-.5px] rounded-full ring-inset ring-6 ring-gray-50 transition-all duration-300 transform-gpu z-10',
87+
isAnimating ? 'scale-150 !ring-0' : 'scale-0',
88+
)}
89+
></span>
90+
<HeartFilledIcon
91+
className={classNames(
92+
'absolute inset-0 transition-transform delay-200 duration-300 text-gray-50 transform-gpu z-10 ease-spring',
93+
isAnimating ? 'scale-1' : 'scale-0',
94+
)}
95+
/>
96+
</>
97+
)}
98+
</span>
9299

93-
<span
94-
className={classNames('relative z-10 tabular-nums', {
95-
'transition-colors duration-100 text-gray-50': like.isLoading,
96-
})}
97-
>
98-
{likeCount}
99-
</span>
100-
</Button>
100+
<span
101+
className={classNames('relative z-10 tabular-nums', {
102+
'transition-colors duration-100 text-gray-50': like.isLoading,
103+
})}
104+
>
105+
{likeCount}
106+
</span>
107+
</Button>
108+
}
109+
/>
101110
)
102111
}

src/app/_components/liked-by.tsx

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,34 @@ import { classNames } from '~/utils/core'
44
import * as Tooltip from '@radix-ui/react-tooltip'
55
import { type RouterOutputs } from '~/trpc/shared'
66
import { MAX_LIKED_BY_SHOWN } from './like-button'
7-
import HeartFilledIcon from '../_svg/heart-filled-icon'
8-
import HeartIcon from '../_svg/heart-icon'
7+
import { type ReactNode } from 'react'
98

109
type LikedByProps = {
10+
trigger: ReactNode
1111
likedBy: RouterOutputs['post']['detail']['likedBy']
12-
isLikedByCurrentUser: RouterOutputs['post']['detail']['isLikedByCurrentUser']
1312
}
1413

15-
export const LikedBy = ({ likedBy, isLikedByCurrentUser }: LikedByProps) => {
14+
export const LikedBy = ({ trigger, likedBy }: LikedByProps) => {
1615
const likeCount = likedBy.length
1716

1817
return (
1918
<Tooltip.TooltipProvider>
2019
<Tooltip.Root delayDuration={300}>
2120
<Tooltip.Trigger
22-
asChild
2321
onClick={(event) => {
2422
event.preventDefault()
2523
}}
2624
onMouseDown={(event) => {
2725
event.preventDefault()
2826
}}
2927
>
30-
<div className="inline-flex items-center gap-1.5">
31-
{isLikedByCurrentUser ? (
32-
<HeartFilledIcon className="w-4 h-4 text-red" />
33-
) : (
34-
<HeartIcon className="w-4 h-4 text-red" />
35-
)}
36-
<span className="text-sm font-semibold tabular-nums">
37-
{likeCount}
38-
</span>
39-
</div>
28+
{trigger}
4029
</Tooltip.Trigger>
4130
<Tooltip.Content
4231
side="bottom"
4332
sideOffset={4}
4433
className={classNames(
45-
'max-w-[260px] px-3 py-1.5 rounded shadow-lg bg-secondary-inverse text-secondary-inverse sm:max-w-sm',
34+
'max-w-[260px] px-3 py-1.5 rounded shadow-lg bg-secondary-inverse text-secondary-inverse sm:max-w-sm z-50',
4635
likeCount === 0 && 'hidden',
4736
)}
4837
>

src/app/_components/post-summary.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import MessageIcon from '~/app/_svg/message-icon'
1111

1212
import { type Session } from 'next-auth'
1313
import { LikedBy } from './liked-by'
14+
import HeartFilledIcon from '../_svg/heart-filled-icon'
15+
import HeartIcon from '../_svg/heart-icon'
1416

1517
export type PostSummaryProps = {
1618
post: RouterOutputs['post']['feed']['posts'][number]
@@ -65,7 +67,18 @@ export const PostSummary = ({ post, hideAuthor }: PostSummaryProps) => {
6567
)}
6668
<div className="ml-auto flex gap-6">
6769
<LikedBy
68-
isLikedByCurrentUser={post.isLikedByCurrentUser}
70+
trigger={
71+
<div className="inline-flex items-center gap-1.5">
72+
{post.isLikedByCurrentUser ? (
73+
<HeartFilledIcon className="w-4 h-4 text-red" />
74+
) : (
75+
<HeartIcon className="w-4 h-4 text-red" />
76+
)}
77+
<span className="text-sm font-semibold tabular-nums">
78+
{post.likedBy.length}
79+
</span>
80+
</div>
81+
}
6982
likedBy={post.likedBy}
7083
/>
7184

0 commit comments

Comments
 (0)