-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
47 changed files
with
1,393 additions
and
127 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,112 @@ | ||
@tailwind base; | ||
@tailwind components; | ||
@tailwind utilities; | ||
|
||
/* @view-transition { | ||
navigation: auto; | ||
} */ | ||
|
||
@keyframes count-exit { | ||
from { | ||
opacity: 1; | ||
transform: translateY(0); | ||
} | ||
to { | ||
opacity: 0; | ||
transform: translateY(-100%); | ||
} | ||
} | ||
|
||
@keyframes count-enter { | ||
from { | ||
opacity: 0; | ||
transform: translateY(100%); | ||
} | ||
to { | ||
opacity: 1; | ||
transform: translateY(0); | ||
} | ||
} | ||
|
||
/* Put new transition name on each card to morph each */ | ||
.card-1 { | ||
view-transition-name: card-1; | ||
} | ||
|
||
.card-2 { | ||
view-transition-name: card-2; | ||
} | ||
|
||
.card-3 { | ||
view-transition-name: card-3; | ||
} | ||
|
||
.card-4 { | ||
view-transition-name: card-4; | ||
} | ||
|
||
/* Etc. */ | ||
|
||
.cards { | ||
padding: 0; | ||
display: flex; | ||
justify-content: center; | ||
width: 100%; | ||
gap: 2rem; | ||
max-width: 1000px; | ||
} | ||
|
||
.card { | ||
width: 100%; | ||
aspect-ratio: 2/3; | ||
display: block; | ||
position: relative; | ||
border-radius: 1rem; | ||
max-width: 220px; | ||
} | ||
|
||
.card-1 { | ||
background-color: tan; | ||
} | ||
|
||
.card-2 { | ||
background-color: khaki; | ||
} | ||
|
||
.card-3 { | ||
background-color: thistle; | ||
} | ||
|
||
.card-4 { | ||
background-color: wheat; | ||
} | ||
|
||
.delete-btn { | ||
position: absolute; | ||
bottom: -0.75rem; | ||
right: -0.75rem; | ||
width: 3rem; | ||
height: 3rem; | ||
padding: 0.5rem; | ||
border: 4px solid; | ||
border-radius: 100%; | ||
background: steelblue; | ||
color: white; | ||
|
||
& img { | ||
filter: invert(); | ||
} | ||
} | ||
|
||
.sr-only { | ||
border: 0; | ||
clip: rect(1px, 1px, 1px, 1px); | ||
clip-path: inset(50%); | ||
height: 1px; | ||
margin: -1px; | ||
overflow: hidden; | ||
padding: 0; | ||
position: absolute; | ||
width: 1px; | ||
white-space: nowrap; | ||
} |
38 changes: 38 additions & 0 deletions
38
apps/live-next/app/live-view-transitions/NextLiveTransitions.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
'use client' | ||
|
||
import {useEffect, useState} from 'react' | ||
import {flushSync} from 'react-dom' | ||
|
||
export default function NextLiveTransitions(props: { | ||
children: React.ReactNode | ||
selector?: unknown | ||
}) { | ||
const [[children, selector], setChildren] = useState(() => [props.children, props.selector]) | ||
|
||
useEffect(() => { | ||
if (props.selector !== undefined) { | ||
console.log('we have a selector') | ||
// @ts-ignore | ||
if (props.selector === selector) { | ||
console.log('selector has not changed, skipping') | ||
return | ||
} else { | ||
console.log('selector has changed', props.selector, selector) | ||
} | ||
} | ||
if (props.children !== children) { | ||
console.log('children have changed', props.children, children) | ||
const transition = document.startViewTransition(() => { | ||
flushSync(() => setChildren([props.children, props.selector])) | ||
}) | ||
console.log({transition}) | ||
return () => { | ||
transition.skipTransition() | ||
} | ||
} else { | ||
console.log('children have not changed') | ||
} | ||
}, [children, props.children, props.selector, selector]) | ||
|
||
return <>{children}</> | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
import {cookies} from 'next/headers' | ||
import NextLiveTransitions from './NextLiveTransitions' | ||
|
||
export default async function LiveViewTransitionsPage() { | ||
const cookieStore = await cookies() | ||
const count = cookieStore.get('count')?.value || '0' | ||
const count2 = cookieStore.get('count2')?.value || '0' | ||
async function getVisibleCards() { | ||
'use server' | ||
const cookieStore = await cookies() | ||
return new Set((cookieStore.get('cards')?.value ?? '1,2,3,4').split(',').filter(Boolean)) | ||
} | ||
const visibleCards = await getVisibleCards() | ||
const cards = [ | ||
{id: '1', color: 'tan'}, | ||
{id: '2', color: 'khaki'}, | ||
{id: '3', color: 'thistle'}, | ||
{id: '4', color: 'wheat'}, | ||
] | ||
|
||
async function handleIncrement() { | ||
'use server' | ||
const cookieStore = await cookies() | ||
cookieStore.set('count', (parseInt(cookieStore.get('count')?.value || '0') + 1).toString()) | ||
} | ||
async function handleIncrement2() { | ||
'use server' | ||
const cookieStore = await cookies() | ||
cookieStore.set('count2', (parseInt(cookieStore.get('count2')?.value || '0') + 1).toString()) | ||
} | ||
async function handleDeleteCard(id: string) { | ||
'use server' | ||
const visibleCards = await getVisibleCards() | ||
const cookieStore = await cookies() | ||
visibleCards.delete(id) | ||
cookieStore.set('cards', Array.from(visibleCards).join(',')) | ||
} | ||
async function handleResetCards() { | ||
'use server' | ||
const cookieStore = await cookies() | ||
cookieStore.set('cards', '1,2,3,4') | ||
} | ||
|
||
return ( | ||
<> | ||
<NextLiveTransitions selector={{count}}> | ||
<h1> | ||
Count (transition): <span style={{viewTransitionName: 'count'}}>{count}</span> | ||
</h1> | ||
<h1>Count (real): {count}</h1> | ||
<h1>Count2: {count2}</h1> | ||
</NextLiveTransitions> | ||
<h1>Count (real): {count}</h1> | ||
<form action={handleIncrement}> | ||
<button type="submit">Increment</button> | ||
</form> | ||
<form action={handleIncrement2}> | ||
<button type="submit">Increment 2</button> | ||
</form> | ||
<h1>Count2: {count2}</h1> | ||
<section | ||
style={{ | ||
display: 'grid', | ||
height: '90dvh', | ||
placeItems: 'center', | ||
padding: '2rem', | ||
}} | ||
> | ||
<NextLiveTransitions> | ||
<code style={{viewTransitionName: 'fit-content-test', width: 'fit-content'}}> | ||
{JSON.stringify({visibleCards: Array.from(visibleCards)})} | ||
</code> | ||
<span style={{viewTransitionName: 'vis-label'}}>visibleCards:</span> | ||
<code> | ||
<span style={{viewTransitionName: 'v-card-start'}}>{'['}</span> | ||
{Array.from(visibleCards).map((id, i) => ( | ||
<span key={id} style={{viewTransitionName: `v-card-s-${id}`}}> | ||
{JSON.stringify(id)} | ||
{visibleCards.size - 1 > i ? ',' : null} | ||
</span> | ||
))} | ||
<span style={{viewTransitionName: 'v-card-end'}}>{']'}</span> | ||
</code> | ||
|
||
{visibleCards.size === 0 && ( | ||
<form action={handleResetCards}> | ||
<button className="rounded-md bg-theme-inverse px-4 py-2 text-sm font-semibold text-theme-inverse transition ease-in-out focus:outline-none focus:ring-2 focus:ring-opacity-50 disabled:cursor-not-allowed disabled:opacity-50"> | ||
Reset cards | ||
</button> | ||
</form> | ||
)} | ||
<ul className="cards"> | ||
{cards.map( | ||
({id, color}) => | ||
visibleCards.has(id) && ( | ||
<li | ||
key={id} | ||
className="card" | ||
style={{backgroundColor: color, viewTransitionName: `cards-${id}`}} | ||
> | ||
<form action={handleDeleteCard.bind(null, id)}> | ||
<button type="submit" className="delete-btn"> | ||
<img | ||
src="https://upload.wikimedia.org/wikipedia/commons/7/7d/Trash_font_awesome.svg" | ||
alt="close button" | ||
/> | ||
<span className="sr-only">Delete</span> | ||
</button> | ||
</form> | ||
</li> | ||
), | ||
)} | ||
</ul> | ||
</NextLiveTransitions> | ||
</section> | ||
</> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,57 @@ | ||
import type {MoreStoriesQueryResult} from '@/sanity.types' | ||
import {SanityLiveStream} from '@/sanity/lib/live' | ||
import {moreStoriesQuery} from '@/sanity/lib/queries' | ||
import {TransitionLayoutShift} from 'next-live-transitions' | ||
import Link from 'next/link' | ||
import Avatar from './avatar' | ||
import CoverImage from './cover-image' | ||
import DateComponent from './date' | ||
|
||
export default async function MoreStories(params: {skip: string; limit: number}) { | ||
// export default async function MoreStories(params: {skip: string; limit: number}) { | ||
export default async function MoreStories({data}: {data: MoreStoriesQueryResult}) { | ||
// const {data} = await sanityFetch({query: moreStoriesQuery, params}) | ||
|
||
return ( | ||
<SanityLiveStream query={moreStoriesQuery} params={params}> | ||
{async ({data}: {data: MoreStoriesQueryResult}) => { | ||
'use server' | ||
// return ( | ||
// <SanityLiveStream query={moreStoriesQuery} params={params}> | ||
// {async ({data}: {data: MoreStoriesQueryResult}) => { | ||
// 'use server' | ||
|
||
return ( | ||
<div className="mb-32 grid grid-cols-1 gap-y-20 md:grid-cols-2 md:gap-x-16 md:gap-y-32 lg:gap-x-32"> | ||
{data?.map((post) => { | ||
const {_id, title, slug, coverImage, excerpt, author} = post | ||
return ( | ||
<article key={_id}> | ||
<Link href={`/posts/${slug}`} className="group mb-5 block"> | ||
<CoverImage image={coverImage} priority={false} /> | ||
</Link> | ||
<h3 className="mb-3 text-balance text-3xl leading-snug"> | ||
<Link href={`/posts/${slug}`} className="hover:underline"> | ||
{title} | ||
</Link> | ||
</h3> | ||
<div className="mb-4 text-lg"> | ||
<DateComponent dateString={post.date} /> | ||
</div> | ||
{excerpt && <p className="mb-4 text-pretty text-lg leading-relaxed">{excerpt}</p>} | ||
{author && <Avatar name={author.name} picture={author.picture} />} | ||
</article> | ||
) | ||
})} | ||
</div> | ||
) | ||
}} | ||
</SanityLiveStream> | ||
return ( | ||
<div className="mb-32 grid grid-cols-1 gap-y-20 md:grid-cols-2 md:gap-x-16 md:gap-y-32 lg:gap-x-32"> | ||
<TransitionLayoutShift> | ||
{data?.map((post) => { | ||
const {_id, title, slug, coverImage, excerpt, author} = post | ||
return ( | ||
<article key={_id} style={{viewTransitionName: `post-${_id}`}}> | ||
<Link | ||
href={`/posts/${slug}`} | ||
className="group mb-5 block" | ||
style={{viewTransitionName: `post-${_id}-cover-image`}} | ||
> | ||
<CoverImage image={coverImage} priority={false} /> | ||
</Link> | ||
<h3 | ||
className="mb-3 text-balance text-3xl leading-snug" | ||
style={{viewTransitionName: `post-${_id}-heading`}} | ||
> | ||
<Link href={`/posts/${slug}`} className="hover:underline"> | ||
{title} | ||
</Link> | ||
</h3> | ||
<div className="mb-4 text-lg" style={{viewTransitionName: `post-${_id}-date`}}> | ||
<DateComponent dateString={post.date} /> | ||
</div> | ||
<div style={{viewTransitionName: `post-${_id}-excerpt`}}> | ||
{excerpt && <p className="mb-4 text-pretty text-lg leading-relaxed">{excerpt}</p>} | ||
</div> | ||
<div style={{viewTransitionName: `post-${_id}-author`}}> | ||
{author && <Avatar name={author.name} picture={author.picture} />} | ||
</div> | ||
</article> | ||
) | ||
})} | ||
</TransitionLayoutShift> | ||
</div> | ||
) | ||
// }} | ||
// </SanityLiveStream> | ||
// ) | ||
} |
Oops, something went wrong.