Skip to content

Commit

Permalink
chore: squash everything
Browse files Browse the repository at this point in the history
  • Loading branch information
stipsan committed Oct 21, 2024
1 parent 19cc6c9 commit 3ba37eb
Show file tree
Hide file tree
Showing 47 changed files with 1,393 additions and 127 deletions.
109 changes: 109 additions & 0 deletions apps/live-next/app/globals.css
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 apps/live-next/app/live-view-transitions/NextLiveTransitions.tsx
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.
118 changes: 118 additions & 0 deletions apps/live-next/app/live-view-transitions/page.tsx
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>
</>
)
}
79 changes: 46 additions & 33 deletions apps/live-next/app/more-stories.tsx
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>
// )
}
Loading

0 comments on commit 3ba37eb

Please sign in to comment.