diff --git a/examples/social-feed/src/components/Article.astro b/examples/social-feed/src/components/Article.astro index 2febb34fe..0b0829412 100644 --- a/examples/social-feed/src/components/Article.astro +++ b/examples/social-feed/src/components/Article.astro @@ -1,7 +1,5 @@ --- import ArticleHeader from './ArticleHeader.astro'; -import Icon from './Icon.astro'; -import Prose from './Prose.astro'; import SplitLayout from './SplitLayout.astro'; import type { Article, Post } from '../content/config.js'; @@ -17,7 +15,7 @@ const { Content, headings } = await article.render(); <article> <ArticleHeader {article} class="header" /> <SplitLayout reverse> - <div class="p-content"> + <div class="e-content"> <Content /> </div> @@ -46,11 +44,11 @@ const { Content, headings } = await article.render(); padding-block: var(--theme-space-md); } - .p-content > :global(* + *) { + .e-content > :global(* + *) { margin-block-start: 1em; } - .p-content > :global(p:first-child::first-letter) { + .e-content > :global(p:first-child::first-letter) { float: left; font-size: 3.5rem; padding-inline-end: 0.5rem; @@ -58,7 +56,7 @@ const { Content, headings } = await article.render(); font-weight: bold; } - .p-content :global(img, video, figure) { + .e-content :global(img, video, figure) { margin-inline: auto; } @@ -86,7 +84,7 @@ const { Content, headings } = await article.render(); display: block; } - .p-content > :global(* + *) { + .e-content > :global(* + *) { margin-block-start: 1.5em; } } diff --git a/examples/social-feed/src/components/ArticleHeader.astro b/examples/social-feed/src/components/ArticleHeader.astro index 27ada323e..9830a763e 100644 --- a/examples/social-feed/src/components/ArticleHeader.astro +++ b/examples/social-feed/src/components/ArticleHeader.astro @@ -21,19 +21,19 @@ const { text: readingTime } = await getReadingTime(article.body); <div class="cover"> { article.data.cover && ( - <Image src={article.data.cover.src} alt={article.data.cover.alt} /> + <Image src={article.data.cover.src} alt={article.data.cover.alt} class="u-photo" /> ) } - <div class="author"> - <Image src={settings.avatar.src} alt={settings.avatar.alt} width={80} /> - <p class="u-name">{settings.name}</p> - <p class="u-nickname">{settings.username}</p> + <div class="p-author h-card"> + <Image src={settings.avatar.src} alt={settings.avatar.alt} width={80} class="u-photo" /> + <p class="p-name">{settings.name}</p> + <p class="p-nickname">{settings.username}</p> </div> </div> <div class="meta"> - <FormattedDate date={article.data.pubDate} /> + <FormattedDate date={article.data.pubDate} class="dt-published" /> <span>•</span> <p> <Icon icon="clock" size="1rem" /> @@ -41,7 +41,7 @@ const { text: readingTime } = await getReadingTime(article.body); </p> </div> - <h1>{article.data.title}</h1> + <h1 class="p-name">{article.data.title}</h1> {article.data.categories?.length > 0 && <TagList tags={article.data.categories} />} </header> @@ -73,7 +73,7 @@ const { text: readingTime } = await getReadingTime(article.body); border-radius: inherit; } - .author { + .p-author { grid-column: 1; grid-row: 1; display: flex; @@ -96,23 +96,23 @@ const { text: readingTime } = await getReadingTime(article.body); margin-block-end: var(--theme-space-sm); } - .author { + .p-author { justify-self: end; margin-inline-end: var(--theme-space-xl); } } - .author img { + .p-author img { width: var(--theme-space-lg); height: var(--theme-space-lg); } - .author .u-name { + .p-author .p-name { font-family: var(--font-brand); font-weight: bold; } - .author .u-nickname { + .p-author .p-nickname { color: var(--theme-gray-300); font-size: var(--theme-text-sm); font-weight: 600; diff --git a/examples/social-feed/src/components/Card.astro b/examples/social-feed/src/components/Card.astro index 25e04f095..ab899c3fc 100644 --- a/examples/social-feed/src/components/Card.astro +++ b/examples/social-feed/src/components/Card.astro @@ -18,28 +18,28 @@ const cover = 'cover' in post.data && post.data.cover; const title = 'title' in post.data && post.data.title; --- -<article {...attrs}> - <header> - <Image {...settings.avatar} width={120} class="u-image" /> - <strong class="u-name">{settings.name}</strong> - <div class="u-nickname"> +<article class="h-entry" {...attrs}> + <header class="p-author h-card"> + <Image {...settings.avatar} width={120} class="u-photo" /> + <strong class="p-name">{settings.name}</strong> + <div class="p-nickname"> {settings.username} • - <FormattedDate date={pubDate} /> + <FormattedDate date={pubDate} class="dt-published" /> </div> {categories.length > 0 && <TagList tags={categories} class="tags" />} </header> - {cover && <Image {...cover} width={1060} />} - {title && <h3>{title}</h3>} + {cover && <Image {...cover} width={1060} class="u-photo" />} + {title && <h3 class="p-name">{title}</h3>} { isArticle(post) ? ( - <p>{post.data.description}</p> + <p class="p-summary">{post.data.description}</p> ) : ( - post.render().then(({ Content }) => <Content />) + post.render().then(({ Content }) => <div class="e-content"><Content /></div>) ) } <footer> - <a href={`/post/${post.slug}/`}>Full {post.data.type === 'article' ? 'article' : 'note'}</a> + <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" /> <span class="sr-only">Share this post</span> @@ -65,19 +65,19 @@ const title = 'title' in post.data && post.data.title; row-gap: var(--theme-space-2xs); column-gap: var(--theme-space-sm); } - .u-image { + .u-photo { grid-area: avatar; width: var(--theme-space-xl); height: var(--theme-space-xl); border-radius: var(--theme-radius-full); background-color: var(--theme-shade-subtle); } - .u-name { + .p-name { grid-area: name; font-family: var(--font-brand); font-weight: bold; } - .u-nickname { + .p-nickname { grid-area: nickname; font-size: var(--theme-text-sm); color: var(--theme-gray-300); diff --git a/examples/social-feed/src/components/FormattedDate.astro b/examples/social-feed/src/components/FormattedDate.astro index 1bcce73a2..eac245a13 100644 --- a/examples/social-feed/src/components/FormattedDate.astro +++ b/examples/social-feed/src/components/FormattedDate.astro @@ -1,5 +1,7 @@ --- -interface Props { +import type { HTMLAttributes } from 'astro/types'; + +interface Props extends HTMLAttributes<'time'> { date: Date; } diff --git a/examples/social-feed/src/components/TagList.astro b/examples/social-feed/src/components/TagList.astro index 14b68f82f..bd718f61f 100644 --- a/examples/social-feed/src/components/TagList.astro +++ b/examples/social-feed/src/components/TagList.astro @@ -9,7 +9,11 @@ const { tags, ...attrs } = Astro.props; --- <ul {...attrs}> - {tags.map((tag) => <li>{tag}</li>)} + {tags.map((tag) => ( + <li> + <a href={`/category/${tag}/`} rel="category tag" class="p-category">{tag}</a> + </li> + ))} </ul> <style> diff --git a/examples/social-feed/src/components/UserProfile.astro b/examples/social-feed/src/components/UserProfile.astro index ef264a159..91f0ad23a 100644 --- a/examples/social-feed/src/components/UserProfile.astro +++ b/examples/social-feed/src/components/UserProfile.astro @@ -6,14 +6,14 @@ import Icon from './Icon.astro'; const socialLinks = Object.entries(settings.social); --- -<div class="profile"> +<div class="h-card"> <div> - <div class="avatar"> + <div class="u-photo"> <Image {...settings.avatar} width={220} /> </div> <h1> - {settings.name} - <small>{settings.username}</small> + <span class="p-name">{settings.name}</span> + <small class="p-nickname">{settings.username}</small> </h1> </div> <div class="bio-sections"> @@ -37,7 +37,7 @@ const socialLinks = Object.entries(settings.social); <p> <Icon icon="location-point" color="var(--theme-accent-dark)" size="1.75rem" /> <span class="sr-only">Location</span> - {settings.location} + <span class="p-locality">{settings.location}</span> </p> ) } @@ -46,7 +46,7 @@ const socialLinks = Object.entries(settings.social); <p> <Icon icon="link-h" color="var(--theme-accent-dark)" size="1.75rem" /> <span class="sr-only">Homepage</span> - <a href={settings.homepage}>{settings.homepage.replace(/^https?:\/\/(www\.)?/, '')}</a> + <a href={settings.homepage} class="u-url">{settings.homepage.replace(/^https?:\/\/(www\.)?/, '')}</a> </p> ) } @@ -57,9 +57,10 @@ const socialLinks = Object.entries(settings.social); </div> <ul class="social"> { - socialLinks.map(([key, { url }]) => ( + socialLinks.map(([key, { url, title }]) => ( <li> - <a href={url}> + <a href={url} rel="me"> + <span class="sr-only">{title}</span> <Icon icon={`${key}`} size="1.75rem" /> </a> </li> @@ -70,18 +71,18 @@ const socialLinks = Object.entries(settings.social); </div> <style> - .profile { + .h-card { display: flex; flex-direction: column; gap: var(--theme-space-md); } - .avatar { + .u-photo { display: inline-block; position: relative; } - .avatar::after { + .u-photo::after { border-radius: var(--theme-radius-full); position: absolute; content: ''; @@ -89,7 +90,7 @@ const socialLinks = Object.entries(settings.social); border: 3px solid var(--theme-text); } - .avatar img { + .u-photo img { width: 110px; height: 110px; } diff --git a/examples/social-feed/src/content/config.ts b/examples/social-feed/src/content/config.ts index f17d3814a..1ba864dd4 100644 --- a/examples/social-feed/src/content/config.ts +++ b/examples/social-feed/src/content/config.ts @@ -16,6 +16,7 @@ const articles = defineCollection({ }) .required({ // requiring the description for articles, this will be shown as the short preview text on cards + title: true, description: true }) .strict(), diff --git a/examples/social-feed/src/helpers/getSortedPosts.ts b/examples/social-feed/src/helpers/getSortedPosts.ts index beb364195..3b6389266 100644 --- a/examples/social-feed/src/helpers/getSortedPosts.ts +++ b/examples/social-feed/src/helpers/getSortedPosts.ts @@ -1,4 +1,13 @@ import { getCollection } from 'astro:content'; +import type { Article, Note } from '../content/config'; + +export function sortPosts(order: 'asc' | 'desc' = 'desc') { + return function(a: Article | Note, b: Article | Note) { + return order === 'asc' + ? a.data.pubDate.getTime() - b.data.pubDate.getTime() + : b.data.pubDate.getTime() - a.data.pubDate.getTime() + } +} /** Get everything in your posts collection, sorted by date. */ export async function getSortedPosts(order: 'asc' | 'desc' = 'desc') { @@ -6,8 +15,10 @@ export async function getSortedPosts(order: 'asc' | 'desc' = 'desc') { getCollection('articles'), getCollection('notes'), ]) - .then((collections) => collections.flat()) - posts.sort((a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime()); - if (order === 'asc') posts.reverse(); + .then((collections) => collections + .flat() + .sort(sortPosts(order) + )); + return posts; } diff --git a/examples/social-feed/src/pages/rss.xml.ts b/examples/social-feed/src/pages/rss.xml.ts index 1687e0561..520e5d1dc 100644 --- a/examples/social-feed/src/pages/rss.xml.ts +++ b/examples/social-feed/src/pages/rss.xml.ts @@ -1,12 +1,14 @@ import rss from '@astrojs/rss'; import type { APIContext } from 'astro'; -import { getSortedPosts } from '../helpers/getSortedPosts'; +import { sortPosts } from '../helpers/getSortedPosts'; import settings from '../settings'; +import { getCollection } from 'astro:content'; const { title, description } = settings.rss; -export async function get(context: APIContext) { - const posts = await getSortedPosts(); +export async function GET(context: APIContext) { + const posts = await getCollection('articles'); + return rss({ // `<title>` field in output xml title, @@ -17,7 +19,9 @@ export async function get(context: APIContext) { site: context.site!.href, // Array of `<item>`s in output xml // See "Generating items" section for examples using content collections and glob imports - items: posts.map(({ data, slug }) => ({ ...data, link: `/post/${slug}` })), + items: posts + .sort(sortPosts()) + .map(({ data, slug }) => ({ ...data, link: `/post/${slug}` })), stylesheet: '/rss/styles.xsl', }); }