feat: add Tag pages and tags to journal pages

This commit is contained in:
Stefan Imhoff
2023-06-08 19:27:05 +02:00
parent 7384b36e91
commit 277f191114
4 changed files with 87 additions and 14 deletions

View File

@@ -2,20 +2,43 @@ import cx from 'classnames';
import type { ComponentChild, FunctionalComponent } from 'preact'; import type { ComponentChild, FunctionalComponent } from 'preact';
import { Link } from '.';
interface Props { interface Props {
class?: string; active?: boolean;
children: ComponentChild; children: ComponentChild;
class?: string;
href?: string;
} }
export const Tag: FunctionalComponent<Props> = ({ class: className, children, ...props }) => { export const Tag: FunctionalComponent<Props> = ({
active,
class: className,
children,
href,
...props
}) => {
const classes = cx( const classes = cx(
'inline-flex items-center justify-center rounded-25 border-2 border-shibui-350 bg-shibui-200 px-3 py-1 text-1 leading-none text-black mie-1 dark:border-shibui-750 dark:bg-shibui-950 dark:text-white', 'capitalize border-3 relative inline-flex items-center justify-center rounded-25 border-2 border-shibui-350 bg-shibui-200 px-3 py-1 text-1 font-normal leading-none text-black mie-1 pbs-3 dark:border-shibui-750 dark:bg-shibui-950 dark:text-white min-w-[50px]',
{
'!bg-shibui-500 !text-white hover:!bg-shibui-700 dark:!border-shibui-500 dark:!bg-shibui-700 hover:dark:!bg-shibui-400':
href,
'active [&.active]:!border-black/25 !text-white [&.active]:!bg-accent': active,
},
className className
); );
return ( return (
<span class={classes} {...props}> <>
{children} {href ? (
</span> <Link href={href} class={classes} {...props}>
{children}
</Link>
) : (
<span class={classes} {...props}>
{children}
</span>
)}
</>
); );
}; };

View File

@@ -10,7 +10,7 @@ import GridLayout from '../layouts/GridLayout.astro';
import PageTitle from '../components/PageTitle.astro'; import PageTitle from '../components/PageTitle.astro';
import Pagination from '../components/Pagination.astro'; import Pagination from '../components/Pagination.astro';
import Picture from '../components/Picture.astro'; import Picture from '../components/Picture.astro';
import { Banner, ListItem, OrderedList, TextLink } from '../components'; import { Banner, ListItem, OrderedList, Tag, TextLink } from '../components';
import { mapping } from '../mdx-components'; import { mapping } from '../mdx-components';
@@ -52,14 +52,13 @@ const description = '…';
<PageTitle slot="title" class="!text-6"> <PageTitle slot="title" class="!text-6">
{entry.data.title} {entry.data.title}
</PageTitle> </PageTitle>
{ {
entry.data.cover && ( entry.data.cover && (
<Picture <Picture
alt={entry.data.title} alt={entry.data.title}
aspect={1.6} aspect={1.6}
breakpoints={[300, 500, 700, 1000, 1300, 1500, 1800, 2000]} breakpoints={[300, 500, 700, 1000, 1300, 1500, 1800, 2000]}
class="col-span-full h-auto !mbe-0 xl:col-start-1 xl:col-end-14 3xl:col-end-13 [&_img]:!w-full [&_img]:!max-w-none [&_picture]:!w-full [&_picture]:!max-w-none" class="col-span-full aspect-video h-auto !mbe-0 xl:col-start-1 xl:col-end-14 3xl:col-end-13 [&_img]:!w-full [&_img]:!max-w-none [&_picture]:!w-full [&_picture]:!max-w-none"
format={['webp', 'avif']} format={['webp', 'avif']}
src={entry.data.cover} src={entry.data.cover}
/> />
@@ -79,11 +78,14 @@ const description = '…';
<div class="leading-tight"> <div class="leading-tight">
<time datetime={dateToISO(entry.data.date)}>{dateToFormat(entry.data.date)}</time> <time datetime={dateToISO(entry.data.date)}>{dateToFormat(entry.data.date)}</time>
</div> </div>
<div class="leading-none"> <div class="leading-none mbe-6">
{wordCount(entry.body)} {wordCount(entry.body)}
<span class="italic">words</span> • {minutesRead} <span class="italic">words</span> • {minutesRead}
<span class="italic">read</span> <span class="italic">read</span>
</div> </div>
<div class="flex flex-wrap gap-y-3">
{entry.data.tags.map((t) => <Tag href={`/tag/${t}/`}>{t}</Tag>)}
</div>
</aside> </aside>
<div <div
class="journal-post col-start-2 col-end-18 md:col-start-5 md:col-end-15 xl:col-start-6 xl:col-end-14 3xl:col-start-7 3xl:col-end-13" class="journal-post col-start-2 col-end-18 md:col-start-5 md:col-end-15 xl:col-start-6 xl:col-end-14 3xl:col-start-7 3xl:col-end-13"

32
src/pages/tag.astro Normal file
View File

@@ -0,0 +1,32 @@
---
import { getCollection } from 'astro:content';
import { sortByDate } from '../utils';
import GridLayout from '../layouts/GridLayout.astro';
import PageTitle from '../components/PageTitle.astro';
import { Tag } from '../components';
const allJournal = await getCollection('journal');
allJournal.sort(sortByDate);
const uniqueTags = [...new Set(allJournal.map((entry) => entry.data.tags).flat())];
uniqueTags.sort((a, b) => a.localeCompare(b));
const title = 'Tags';
const description = '…';
---
<GridLayout
backLink="/journal/"
class="grid"
description={description}
grid="wide"
innerGrid
title={title}
>
<PageTitle grid="wide" innerGrid>Tags</PageTitle>
<aside class="col-start-1 col-end-18 flex flex-wrap gap-y-3">
{uniqueTags.map((t) => <Tag href={`/tag/${t}/`}>{t}</Tag>)}
</aside>
</GridLayout>

View File

@@ -6,14 +6,20 @@ import { sortByDate } from '../../utils';
import GridLayout from '../../layouts/GridLayout.astro'; import GridLayout from '../../layouts/GridLayout.astro';
import PageTitle from '../../components/PageTitle.astro'; import PageTitle from '../../components/PageTitle.astro';
import JournalList from '../../components/JournalList.astro'; import JournalList from '../../components/JournalList.astro';
import { Tag } from '../../components';
console.log('test'); import type { CollectionEntry } from 'astro:content';
interface Props {
entries: CollectionEntry<'journal'>[];
uniqueTags: string[];
}
export async function getStaticPaths() { export async function getStaticPaths() {
const journalEntries = await getCollection('journal'); const journalEntries = await getCollection('journal');
journalEntries.sort(sortByDate); journalEntries.sort(sortByDate);
const uniqueTags = [...new Set(journalEntries.map((entry) => entry.data.tags).flat())]; const uniqueTags = [...new Set(journalEntries.map((entry) => entry.data.tags).flat())];
uniqueTags.sort((a, b) => a.localeCompare(b));
return uniqueTags.map((tag) => { return uniqueTags.map((tag) => {
const filteredEntries = journalEntries.filter((entry) => entry.data.tags.includes(tag)); const filteredEntries = journalEntries.filter((entry) => entry.data.tags.includes(tag));
@@ -21,13 +27,14 @@ export async function getStaticPaths() {
params: { tag }, params: { tag },
props: { props: {
entries: filteredEntries, entries: filteredEntries,
uniqueTags: uniqueTags,
}, },
}; };
}); });
} }
const { tag } = Astro.params; const { tag } = Astro.params;
const { entries } = Astro.props; const { entries, uniqueTags } = Astro.props;
const title = 'Journal'; const title = 'Journal';
const description = '…'; const description = '…';
@@ -41,8 +48,17 @@ const description = '…';
innerGrid innerGrid
backLink="/journal/" backLink="/journal/"
> >
<PageTitle slot="title"> <PageTitle slot="title" class="capitalize">
Tag: {tag} {tag}
</PageTitle> </PageTitle>
<aside class="col-start-1 col-end-18 flex flex-wrap gap-y-3">
{
uniqueTags.map((uTag) => (
<Tag active={uTag === tag} href={`/tag/${uTag}/`}>
{uTag}
</Tag>
))
}
</aside>
<JournalList entries={entries} /> <JournalList entries={entries} />
</GridLayout> </GridLayout>