mirror of
https://github.com/kogakure/website-astro-stefanimhoff.de.git
synced 2026-02-03 20:15:27 +00:00
feat: add Tag pages and tags to journal pages
This commit is contained in:
@@ -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>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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
32
src/pages/tag.astro
Normal 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>
|
||||||
@@ -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>
|
||||||
Reference in New Issue
Block a user