Skip to content

Commit 688240b

Browse files
committed
now we're talking
1 parent 116579b commit 688240b

7 files changed

+60
-56
lines changed

.prettierignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pnpm-lock.yaml
2+
pnpm-workspace.yaml

next-canary/sanity.types.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,10 @@ export type AllSanitySchemaTypes =
190190
export declare const internalGroqTypeReferenceTo: unique symbol
191191
// Source: ./src/app/Reactions.tsx
192192
// Variable: REACTION_QUERY
193-
// Query: *[_type == "reaction" && _id == $id][0]{emoji,reactions,"fetchedAt":now()}
193+
// Query: *[_type == "reaction" && _id == $id][0]{emoji,reactions}
194194
export type REACTION_QUERYResult = {
195195
emoji: string | null
196196
reactions: number | null
197-
fetchedAt: string
198197
} | null
199198

200199
// Source: ./src/app/layout.tsx
@@ -235,7 +234,7 @@ export type DYNAMIC_DEMO_QUERYResult = {
235234

236235
declare module '@sanity/client' {
237236
interface SanityQueries {
238-
'*[_type == "reaction" && _id == $id][0]{emoji,reactions,"fetchedAt":now()}': REACTION_QUERYResult
237+
'*[_type == "reaction" && _id == $id][0]{emoji,reactions}': REACTION_QUERYResult
239238
'*[_id == "theme"][0]{background,text,"fetchedAt":now()}': THEME_QUERYResult
240239
'*[_type == "demo" && slug.current == $slug][0]{title,reactions[0..4]{_key,_ref},"fetchedAt":now()}': DEMO_QUERYResult
241240
'*[_type == "demo" && slug.current == $slug][0]{title,"fetchedAt":now()}': DYNAMIC_DEMO_QUERYResult

next-canary/src/app/ReactionButton.tsx

+31-21
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
'use client'
22

33
import {AnimatePresence, motion} from 'framer-motion'
4-
import {startTransition, useEffect, useOptimistic, useState} from 'react'
5-
import {Square} from './Square'
4+
import {startTransition, use, useEffect, useOptimistic, useState} from 'react'
5+
import {ReactionFallback, Square} from './ReactionPrimitives'
66

77
interface Emoji {
88
key: string
@@ -22,7 +22,33 @@ function insert(emojis: Emoji[], delay: number) {
2222
return [...emojis, createEmoji(delay)]
2323
}
2424

25-
export function ReactionButton(props: {onClick: () => void; emoji: string; reactions: number}) {
25+
function insertMany(emojis: Emoji[], needed: number) {
26+
const stagger = 5_000 / needed
27+
const nextEmojis = [...emojis]
28+
for (let i = 0; i < needed; i++) {
29+
nextEmojis.push(createEmoji(i * stagger))
30+
}
31+
return nextEmojis
32+
}
33+
34+
export function ReactionButton(props: {
35+
onClick: () => void
36+
data: Promise<{
37+
emoji: string | null
38+
reactions: number | null
39+
} | null>
40+
}) {
41+
const {onClick} = props
42+
const data = use(props.data)
43+
44+
if (!data?.emoji || typeof data.reactions !== 'number') {
45+
return <ReactionFallback />
46+
}
47+
48+
return <EmojiReactionButton onClick={onClick} emoji={data.emoji} reactions={data.reactions} />
49+
}
50+
51+
function EmojiReactionButton(props: {onClick: () => void; emoji: string; reactions: number}) {
2652
const {onClick, emoji, reactions} = props
2753
const [initialReactions] = useState(reactions)
2854

@@ -36,22 +62,12 @@ export function ReactionButton(props: {onClick: () => void; emoji: string; react
3662
useEffect(() => {
3763
if (nextReactions > emojis.length) {
3864
const needed = nextReactions - emojis.length
39-
startTransition(() =>
40-
setEmojis((emojis) => {
41-
const nextEmojis = [...emojis]
42-
for (let i = 0; i < needed; i++) {
43-
nextEmojis.push(createEmoji(i * 60))
44-
}
45-
return nextEmojis
46-
}),
47-
)
65+
startTransition(() => setEmojis((emojis) => insertMany(emojis, needed)))
4866
}
4967
}, [nextReactions, emojis.length])
5068

5169
const pendingEmojis = emojis.filter(({done}) => !done)
5270

53-
// focus-within:ring-(--theme-text) focus-within:ring-offset-(--theme-background) focus-within:ring-2 focus-within:ring-offset-2 focus-within:duration-0
54-
5571
return (
5672
<div className="bg-(--theme-text)/40 focus-within:ring-(--theme-text) focus-within:ring-offset-(--theme-background) relative aspect-square rounded-lg transition duration-1000 ease-in-out focus-within:ring-2 focus-within:ring-offset-2 focus-within:duration-0">
5773
<motion.button
@@ -69,13 +85,7 @@ export function ReactionButton(props: {onClick: () => void; emoji: string; react
6985
</motion.button>
7086
<AnimatePresence>
7187
{pendingEmojis.map(({key, delay}) => (
72-
<FloatingEmoji
73-
key={key}
74-
_key={key}
75-
emoji={props.emoji}
76-
delay={delay}
77-
setEmojis={setEmojis}
78-
/>
88+
<FloatingEmoji key={key} _key={key} emoji={emoji} delay={delay} setEmojis={setEmojis} />
7989
))}
8090
</AnimatePresence>
8191
</div>
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export function ReactionFallback() {
2+
return (
3+
<ButtonContainer>
4+
<button
5+
disabled
6+
className="bg-(--theme-text)/40 flex animate-pulse rounded-lg transition-colors duration-1000 ease-in-out"
7+
>
8+
<Square> </Square>
9+
</button>
10+
</ButtonContainer>
11+
)
12+
}
13+
14+
export function Square({children}: {children: React.ReactNode}) {
15+
return (
16+
<div className="inline-flex aspect-square size-12 items-center justify-center">{children}</div>
17+
)
18+
}
19+
20+
function ButtonContainer({children}: {children: React.ReactNode}) {
21+
return <div className="relative aspect-square">{children}</div>
22+
}

next-canary/src/app/Reactions.tsx

+3-21
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {sanityFetch} from '@/sanity/fetch'
22
import {defineQuery} from 'groq'
33
import {Suspense} from 'react'
44
import {ReactionButton} from './ReactionButton'
5-
import {ButtonContainer, Square} from './Square'
5+
import {ReactionFallback} from './ReactionPrimitives'
66

77
interface Props {
88
data: {
@@ -30,11 +30,7 @@ const REACTION_QUERY = defineQuery(`*[_type == "reaction" && _id == $id][0]{emoj
3030
export async function Reaction(props: {_ref: string}) {
3131
const {_ref} = props
3232

33-
const {data} = await sanityFetch({query: REACTION_QUERY, params: {id: _ref}})
34-
35-
if (!data?.emoji || typeof data.reactions !== 'number') {
36-
return <ReactionFallback />
37-
}
33+
const data = sanityFetch({query: REACTION_QUERY, params: {id: _ref}}).then(({data}) => data)
3834

3935
return (
4036
<ReactionButton
@@ -48,8 +44,7 @@ export async function Reaction(props: {_ref: string}) {
4844
body: formData,
4945
})
5046
}}
51-
emoji={data.emoji}
52-
reactions={data.reactions}
47+
data={data}
5348
/>
5449
)
5550
}
@@ -65,19 +60,6 @@ export function ReactionsFallback(props: Props) {
6560
)
6661
}
6762

68-
function ReactionFallback() {
69-
return (
70-
<ButtonContainer>
71-
<button
72-
disabled
73-
className="bg-(--theme-text)/40 flex animate-pulse rounded-lg transition-colors duration-1000 ease-in-out"
74-
>
75-
<Square> </Square>
76-
</button>
77-
</ButtonContainer>
78-
)
79-
}
80-
8163
function Wrapper({children}: {children: React.ReactNode}) {
8264
return (
8365
<aside className="bg-(--theme-text)/30 fixed bottom-2 left-[50%] grid -translate-x-[50%] grid-flow-col grid-rows-1 gap-2 rounded-2xl p-2 transition-colors duration-1000 ease-in-out">

next-canary/src/app/SanityLive.tsx

-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@ export function SanityLive() {
1616
console.info('Sanity is live with automatic revalidation of published content')
1717
break
1818
case 'message':
19-
console.log('Sanity Live message:', event)
2019
expireTags(event.tags)
2120
break
2221
case 'reconnect':
2322
case 'restart':
24-
console.info('Sanity Live connection was lost, reconnecting...', event)
2523
router.refresh()
2624
break
2725
}

next-canary/src/app/Square.tsx

-9
This file was deleted.

0 commit comments

Comments
 (0)