fix: view transitions

This commit is contained in:
jake committed 2026-01-28 11:18:56 -05:00
1 parent b80768cab6
commit 928ec66cf6
5 files changed
+40 -32

No files matched your search

+21 -23
View File
@@ -195,7 +195,7 @@
} }
} }
/* View Transitions */ /* View Transitions - uses tw-animate-css's `enter` and `exit` keyframes */
@layer base { @layer base {
@media (prefers-reduced-motion: reduce) { @media (prefers-reduced-motion: reduce) {
::view-transition-group(*), ::view-transition-group(*),
@@ -205,33 +205,31 @@
} }
} }
::view-transition-group(*) {
animation-duration: 250ms;
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
::view-transition-old(*) {
--tw-exit-opacity: 0;
animation: 150ms ease-in both exit;
}
::view-transition-new(*) {
--tw-enter-opacity: 0;
animation: 200ms ease-out both enter;
}
/* Main content: fade + slide */
main { main {
view-transition-name: main-content; view-transition-name: main-content;
} }
::view-transition-old(main-content) { ::view-transition-old(main-content) {
animation: fade-out 120ms ease-out; --tw-exit-opacity: 0;
--tw-exit-translate-y: -8px;
animation: 150ms ease-in forwards exit;
} }
::view-transition-new(main-content) { ::view-transition-new(main-content) {
animation: fade-in 120ms ease-in 40ms; --tw-enter-opacity: 0;
} --tw-enter-translate-y: 12px;
animation: 200ms ease-out forwards enter;
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
} }
} }
+4 -1
View File
@@ -1,3 +1,4 @@
import { ViewTransition } from "react";
import { env } from "@/lib/env"; import { env } from "@/lib/env";
import { JsonLd } from "react-schemaorg"; import { JsonLd } from "react-schemaorg";
import Providers from "@/components/providers"; import Providers from "@/components/providers";
@@ -64,7 +65,9 @@ const RootLayout = ({ children }: Readonly<{ children: React.ReactNode }>) => {
<Providers> <Providers>
<Header /> <Header />
<div className="mx-auto mt-4 w-full max-w-4xl px-5"> <div className="mx-auto mt-4 w-full max-w-4xl px-5">
<main>{children}</main> <main>
<ViewTransition>{children}</ViewTransition>
</main>
</div> </div>
<Footer /> <Footer />
+4 -1
View File
@@ -147,7 +147,10 @@ const Page = async ({ params }: { params: Promise<{ slug: string }> }) => {
</div> </div>
</div> </div>
<h1 className="my-5 text-4xl font-semibold tracking-tight sm:text-3xl"> <h1
className="my-5 text-3xl font-semibold tracking-tight"
style={{ viewTransitionName: `note-title-${frontmatter!.slug}` }}
>
<Link <Link
href={`/${POSTS_DIR}/${frontmatter!.slug}`} href={`/${POSTS_DIR}/${frontmatter!.slug}`}
dangerouslySetInnerHTML={{ __html: frontmatter!.htmlTitle || frontmatter!.title }} dangerouslySetInnerHTML={{ __html: frontmatter!.htmlTitle || frontmatter!.title }}
+9 -2
View File
@@ -2,6 +2,7 @@ import { env } from "@/lib/env";
import { cacheLife } from "next/cache"; import { cacheLife } from "next/cache";
import { EyeIcon, MessagesSquareIcon } from "lucide-react"; import { EyeIcon, MessagesSquareIcon } from "lucide-react";
import Link from "@/components/link"; import Link from "@/components/link";
import PageTitle from "@/components/layout/page-title";
import { getFrontMatter, POSTS_DIR, type FrontMatter } from "@/lib/posts"; import { getFrontMatter, POSTS_DIR, type FrontMatter } from "@/lib/posts";
import { createMetadata } from "@/lib/metadata"; import { createMetadata } from "@/lib/metadata";
import { formatDate, formatDateISO } from "@/lib/date"; import { formatDate, formatDateISO } from "@/lib/date";
@@ -97,7 +98,7 @@ const PostsList = async () => {
Object.entries(postsByYear).forEach(([year, posts]) => { Object.entries(postsByYear).forEach(([year, posts]) => {
sections.push( sections.push(
<section className="my-8 first-of-type:mt-0 last-of-type:mb-0" key={year}> <section className="my-8 first-of-type:mt-0 last-of-type:mb-0" key={year}>
<h2 id={year} className="mt-0 mb-4 text-4xl font-semibold tracking-tight sm:text-3xl"> <h2 id={year} className="mt-0 mb-4 text-2xl font-semibold tracking-tight">
{year} {year}
</h2> </h2>
<ul className="space-y-4"> <ul className="space-y-4">
@@ -115,6 +116,7 @@ const PostsList = async () => {
prefetch={false} prefetch={false}
dangerouslySetInnerHTML={{ __html: htmlTitle || title }} dangerouslySetInnerHTML={{ __html: htmlTitle || title }}
className="underline-offset-4 hover:underline" className="underline-offset-4 hover:underline"
style={{ viewTransitionName: `note-title-${slug}` }}
/> />
<PostStats slug={slug} views={views} comments={comments} /> <PostStats slug={slug} views={views} comments={comments} />
@@ -131,7 +133,12 @@ const PostsList = async () => {
}; };
const Page = async () => { const Page = async () => {
return <PostsList />; return (
<>
<PageTitle canonical="/notes">Notes</PageTitle>
<PostsList />
</>
);
}; };
export default Page; export default Page;
+2 -5
View File
@@ -10,13 +10,10 @@ const PageTitle = ({
canonical: string; canonical: string;
}) => { }) => {
return ( return (
<h1 <h1 className={cn("mt-0 mb-6 text-left text-3xl font-semibold tracking-tight lowercase", className)} {...rest}>
className={cn("mt-0 mb-6 text-left text-4xl font-semibold tracking-tight lowercase sm:text-3xl", className)}
{...rest}
>
<Link <Link
href={canonical} href={canonical}
className="before:text-muted-foreground no-underline before:-mr-1 before:tracking-wider before:content-['\002E\002F']" className="before:text-muted-foreground no-underline before:mr-[-3px] before:tracking-wider before:content-['\002E\002F']"
> >
{children} {children}
</Link> </Link>