some basic view transition support

This commit is contained in:
Tony Sullivan 2023-09-18 12:50:14 -05:00
parent 1d9faff6fe
commit 6800e399ed
7 changed files with 84 additions and 43 deletions

View file

@ -1,6 +1,6 @@
--- ---
import ArticleHeader from './ArticleHeader.astro'; import ArticleHeader from './ArticleHeader.astro';
import type { Article, Post } from '../content/config.js'; import type { Article } from '../content/config.js';
export interface Props { export interface Props {
article: Article; article: Article;
@ -13,9 +13,9 @@ const { Content } = await article.render();
<article> <article>
<ArticleHeader {article} class="header" /> <ArticleHeader {article} class="header" />
<div class="e-content"> <div class="e-content">
<Content /> <Content />
</div> </div>
</article> </article>
<style> <style>
@ -24,6 +24,14 @@ const { Content } = await article.render();
flex-direction: column; flex-direction: column;
gap: var(--theme-space-lg); gap: var(--theme-space-lg);
padding-block: var(--theme-space-md); padding-block: var(--theme-space-md);
width: 100%;
max-width: var(--theme-size-content-3);
margin-inline: auto;
}
.e-content {
max-width: var(--theme-size-content-3);
margin-inline: auto;
} }
.e-content > :global(* + *) { .e-content > :global(* + *) {

View file

@ -41,7 +41,7 @@ const { text: readingTime } = await getReadingTime(article.body);
</p> </p>
</div> </div>
<h1 class="p-name">{article.data.title}</h1> <h1 class="p-name">article.data.title}</h1>
{article.data.categories?.length > 0 && <TagList tags={article.data.categories} />} {article.data.categories?.length > 0 && <TagList tags={article.data.categories} />}
</header> </header>
@ -93,7 +93,7 @@ const { text: readingTime } = await getReadingTime(article.body);
@media (min-width: 640px) { @media (min-width: 640px) {
.cover { .cover {
margin-block-end: var(--theme-space-sm); margin-block-end: var(--theme-space-sm);
} }
.p-author { .p-author {

View file

@ -11,14 +11,16 @@ export interface Props extends HTMLAttributes<'article'> {
post: Post; post: Post;
} }
const { post, ...attrs } = Astro.props; const { post, class: className, ...attrs } = Astro.props;
const { pubDate, categories = [] } = post.data; const { pubDate, categories = [] } = post.data;
const cover = 'cover' in post.data && post.data.cover; const cover = 'cover' in post.data && post.data.cover;
const title = 'title' in post.data && post.data.title; const title = 'title' in post.data && post.data.title;
const postUrl = `/post/${post.slug}/`;
--- ---
<article class="h-entry" {...attrs}> <article class:list={['h-entry', className]} transition:name={`card-${post.slug}`} {...attrs}>
<header class="p-author h-card"> <header class="p-author h-card">
<Image {...settings.avatar} width={120} class="u-photo" /> <Image {...settings.avatar} width={120} class="u-photo" />
<strong class="p-name">{settings.name}</strong> <strong class="p-name">{settings.name}</strong>
@ -35,12 +37,24 @@ const title = 'title' in post.data && post.data.title;
isArticle(post) ? ( isArticle(post) ? (
<p class="p-summary">{post.data.description}</p> <p class="p-summary">{post.data.description}</p>
) : ( ) : (
post.render().then(({ Content }) => <div class="e-content"><Content /></div>) post.render().then(({ Content }) => (
<div class="e-content">
<Content />
</div>
))
) )
} }
<footer> <footer>
<a href={`/post/${post.slug}/`} class="u-url">Full {post.collection === 'articles' ? 'article' : 'note'}</a> {
<a href={`javascript: navigator.clipboard.writeText(window.location.href + "post/${post.slug}/");`}> Astro.url.pathname !== postUrl && (
<a href={`/post/${post.slug}/`} class="u-url">
Full {post.collection === 'articles' ? 'article' : 'note'}
</a>
)
}
<a
href={`javascript: navigator.clipboard.writeText(window.location.href + "post/${post.slug}/");`}
>
<Icon icon="share" size="1.5rem" /> <Icon icon="share" size="1.5rem" />
<span class="sr-only">Share this post</span> <span class="sr-only">Share this post</span>
</a> </a>
@ -49,6 +63,7 @@ const title = 'title' in post.data && post.data.title;
<style> <style>
article { article {
max-width: var(--theme-size-content-2);
padding: var(--theme-space-sm) var(--theme-space-sm) var(--theme-space-md); padding: var(--theme-space-sm) var(--theme-space-sm) var(--theme-space-md);
background-color: var(--theme-bg-accent); background-color: var(--theme-bg-accent);
border-radius: var(--theme-radius-xl); border-radius: var(--theme-radius-xl);
@ -65,7 +80,7 @@ const title = 'title' in post.data && post.data.title;
row-gap: var(--theme-space-2xs); row-gap: var(--theme-space-2xs);
column-gap: var(--theme-space-sm); column-gap: var(--theme-space-sm);
} }
.u-photo { .h-card .u-photo {
grid-area: avatar; grid-area: avatar;
width: var(--theme-space-xl); width: var(--theme-space-xl);
height: var(--theme-space-xl); height: var(--theme-space-xl);
@ -95,4 +110,7 @@ const title = 'title' in post.data && post.data.title;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
footer > *:only-child {
margin-inline-start: auto;
}
</style> </style>

View file

@ -16,20 +16,17 @@ const { reverse = false, class: className, ...attrs } = Astro.props;
div { div {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center;
gap: var(--theme-space-lg); gap: var(--theme-space-lg);
margin: 0 auto; margin: 0 auto;
width: 100%; width: 100%;
max-width: var(--theme-content-width); max-width: var(--theme-size-content-3);
} }
@media (min-width: 50em) { @media (min-width: 50em) {
div { div {
display: grid; flex-direction: row;
grid-template-columns: 12rem 1fr; align-items: initial;
}
div.reverse {
grid-template-columns: 1fr 12rem;
} }
} }
</style> </style>

View file

@ -1,4 +1,5 @@
--- ---
import { ViewTransitions } from 'astro:transitions';
import settings from '../settings'; import settings from '../settings';
import '../style/theme.css'; import '../style/theme.css';
import '../style/global.css'; import '../style/global.css';
@ -22,6 +23,7 @@ const { title = settings.name } = Astro.props;
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} /> <meta name="generator" content={Astro.generator} />
<title>{title}</title> <title>{title}</title>
<ViewTransitions />
<!-- Canonical URL --> <!-- Canonical URL -->
<link rel="canonical" href={canonicalURL} /> <link rel="canonical" href={canonicalURL} />
@ -63,23 +65,27 @@ const { title = settings.name } = Astro.props;
<slot /> <slot />
</main> </main>
<Footer /> <Footer />
<style>
html {
scrollbar-gutter: stable;
}
body {
display: flex;
flex-direction: column;
gap: var(--theme-space-lg);
}
.header,
main {
padding-inline: var(--theme-space-sm-lg);
}
main {
width: 100%;
max-width: 55rem;
margin-inline: auto;
}
</style>
</body> </body>
<style>
body {
display: flex;
flex-direction: column;
gap: var(--theme-space-lg);
}
.header, main {
padding-inline: var(--theme-space-sm-lg);
}
main {
width: 100%;
max-width: 55rem;
margin-inline: auto;
}
</style>
</html> </html>

View file

@ -31,7 +31,7 @@ const { title } = isArticle(post) && post.data;
<span>Back to feed</span> <span>Back to feed</span>
</a> </a>
{isArticle(post) ? (<Article article={post} />) : (<div class="card"><Card {post} /></div>)} {isArticle(post) ? <Article article={post} /> : <Card {post} class="card" />}
{ {
(next || prev) && ( (next || prev) && (
@ -45,7 +45,11 @@ const { title } = isArticle(post) && post.data;
{next && ( {next && (
<a href={`/post/${next.slug}`} class="next"> <a href={`/post/${next.slug}`} class="next">
<span>Next post</span> <span>Next post</span>
<Icon icon="arrow-right" size="var(--theme-space-md)" color="var(--theme-accent-dark)" /> <Icon
icon="arrow-right"
size="var(--theme-space-md)"
color="var(--theme-accent-dark)"
/>
</a> </a>
)} )}
</footer> </footer>
@ -68,12 +72,15 @@ const { title } = isArticle(post) && post.data;
.card { .card {
width: 100%; width: 100%;
max-width: 60ch; margin: var(--theme-space-md) auto;
margin-inline: auto;
padding-block: var(--theme-space-md);
} }
.prev, .next { .center {
margin-inline: auto;
}
.prev,
.next {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;

View file

@ -26,6 +26,11 @@
--theme-shadow-md: 2px 2px 10px rgba(0, 0, 0, 0.1); --theme-shadow-md: 2px 2px 10px rgba(0, 0, 0, 0.1);
--theme-shadow-lg: 2px 2px 20px rgba(0, 0, 0, 0.2); --theme-shadow-lg: 2px 2px 20px rgba(0, 0, 0, 0.2);
/* Content Sizes */
--theme-size-content-1: 30ch;
--theme-size-content-2: 45ch;
--theme-size-content-3: 65ch;
/* Type Scale */ /* Type Scale */
/* @link https://utopia.fyi/type/calculator?c=320,16,1.2,1240,20,1.2,5,2,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 */ /* @link https://utopia.fyi/type/calculator?c=320,16,1.2,1240,20,1.2,5,2,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 */
--theme-text-sm: clamp(0.83rem, calc(0.76rem + 0.36vw), 1.04rem); --theme-text-sm: clamp(0.83rem, calc(0.76rem + 0.36vw), 1.04rem);