mirror of
https://github.com/kogakure/website-astro-stefanimhoff.de.git
synced 2026-02-03 20:15:27 +00:00
feat: add Journal index page
This commit is contained in:
52
src/components/JournalList.astro
Normal file
52
src/components/JournalList.astro
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
import { Picture } from 'astro-imagetools/components';
|
||||||
|
|
||||||
|
import type { CollectionEntry } from 'astro:content';
|
||||||
|
interface Props {
|
||||||
|
entries: CollectionEntry<'journal'>[];
|
||||||
|
}
|
||||||
|
|
||||||
|
import { pickTwoRandomColors } from '../utils';
|
||||||
|
import { Link, Subsubheadline } from '../components';
|
||||||
|
|
||||||
|
const { entries } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<nav class="col-start-1 col-end-18" aria-label="Journal">
|
||||||
|
<ul
|
||||||
|
class="grid auto-rows-[50px] grid-cols-[repeat(auto-fit,_minmax(100px,_1fr))] grid-rows-[50px] gap-[max(25px,_2vw)]"
|
||||||
|
>
|
||||||
|
{
|
||||||
|
entries.map(({ slug, data }) => (
|
||||||
|
<li class="journal-card image-shadow group">
|
||||||
|
<Link title={data.title} href={`/${slug}/`} class="block h-full w-full">
|
||||||
|
<div class="absolute z-10 flex h-full w-full flex-col items-center justify-center p-10 text-center leading-tight text-white">
|
||||||
|
<Subsubheadline class="!m-0 leading-tight">{data.title}</Subsubheadline>
|
||||||
|
</div>
|
||||||
|
{data.cover ? (
|
||||||
|
<>
|
||||||
|
{data.cover.endsWith('.svg') ? (
|
||||||
|
<img src={data.cover} alt={data.title} />
|
||||||
|
) : (
|
||||||
|
<Picture
|
||||||
|
src={data.cover}
|
||||||
|
alt={data.title}
|
||||||
|
aspect={0.6}
|
||||||
|
breakpoints={[300, 512, 768, 1024]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
class="h-full w-full scale-105 bg-gray-800 blur-sm brightness-[50%] filter transition duration-300 ease-in-out group-hover:brightness-[90%]"
|
||||||
|
style={`background-image: linear-gradient(to bottom left, ${
|
||||||
|
pickTwoRandomColors()[0]
|
||||||
|
} 0%, ${pickTwoRandomColors()[1]} 100%)`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
@@ -5,14 +5,19 @@ 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 { Tag } from '../components';
|
||||||
|
|
||||||
import { Content as Intro } from '../text/journal/intro.mdx';
|
import { Content as Intro } from '../text/journal/intro.mdx';
|
||||||
import { Link } from '../components';
|
|
||||||
|
|
||||||
import { mapping } from '../mdx-components';
|
import { mapping } from '../mdx-components';
|
||||||
|
|
||||||
const allJournal = await getCollection('journal');
|
const allJournal = await getCollection('journal');
|
||||||
allJournal.sort(sortByDate);
|
allJournal.sort(sortByDate);
|
||||||
|
|
||||||
|
const uniqueTags = [...new Set(allJournal.map((entry) => entry.data.tags).flat())];
|
||||||
|
uniqueTags.sort((a, b) => a.localeCompare(b));
|
||||||
|
|
||||||
const title = 'Journal';
|
const title = 'Journal';
|
||||||
const description = '…';
|
const description = '…';
|
||||||
---
|
---
|
||||||
@@ -25,18 +30,8 @@ const description = '…';
|
|||||||
>
|
>
|
||||||
<Intro components={mapping} />
|
<Intro components={mapping} />
|
||||||
</article>
|
</article>
|
||||||
|
<aside class="col-start-1 col-end-18 flex flex-wrap gap-y-3">
|
||||||
<nav class="md:col-start-1 md:col-end-16" aria-label="Journal">
|
{uniqueTags.map((tag) => <Tag href={`/tag/${tag}/`}>{tag}</Tag>)}
|
||||||
<ol>
|
</aside>
|
||||||
{
|
<JournalList entries={allJournal} />
|
||||||
allJournal.map(({ slug, data }) => (
|
|
||||||
<li>
|
|
||||||
<Link title={data.title} href={`/${slug}/`}>
|
|
||||||
{data.title}
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
|
|||||||
48
src/pages/tags/[tag].astro
Normal file
48
src/pages/tags/[tag].astro
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
import { getCollection } from 'astro:content';
|
||||||
|
|
||||||
|
import { sortByDate } from '../../utils';
|
||||||
|
|
||||||
|
import GridLayout from '../../layouts/GridLayout.astro';
|
||||||
|
import PageTitle from '../../components/PageTitle.astro';
|
||||||
|
import JournalList from '../../components/JournalList.astro';
|
||||||
|
|
||||||
|
console.log('test');
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const journalEntries = await getCollection('journal');
|
||||||
|
journalEntries.sort(sortByDate);
|
||||||
|
|
||||||
|
const uniqueTags = [...new Set(journalEntries.map((entry) => entry.data.tags).flat())];
|
||||||
|
|
||||||
|
return uniqueTags.map((tag) => {
|
||||||
|
const filteredEntries = journalEntries.filter((entry) => entry.data.tags.includes(tag));
|
||||||
|
return {
|
||||||
|
params: { tag },
|
||||||
|
props: {
|
||||||
|
entries: filteredEntries,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { tag } = Astro.params;
|
||||||
|
const { entries } = Astro.props;
|
||||||
|
|
||||||
|
const title = 'Journal';
|
||||||
|
const description = '…';
|
||||||
|
---
|
||||||
|
|
||||||
|
<GridLayout
|
||||||
|
title={title}
|
||||||
|
description={description}
|
||||||
|
grid="wide"
|
||||||
|
class="grid"
|
||||||
|
innerGrid
|
||||||
|
backLink="/journal/"
|
||||||
|
>
|
||||||
|
<PageTitle slot="title">
|
||||||
|
Tag: {tag}
|
||||||
|
</PageTitle>
|
||||||
|
<JournalList entries={entries} />
|
||||||
|
</GridLayout>
|
||||||
@@ -13,24 +13,17 @@ export const journal = defineCollection({
|
|||||||
z.enum([
|
z.enum([
|
||||||
'book',
|
'book',
|
||||||
'code',
|
'code',
|
||||||
'decentralization',
|
|
||||||
'design',
|
'design',
|
||||||
'download',
|
'download',
|
||||||
'film',
|
'film',
|
||||||
'health',
|
|
||||||
'minimalism',
|
|
||||||
'note-taking',
|
|
||||||
'personal',
|
|
||||||
'philosophy',
|
'philosophy',
|
||||||
'poetry',
|
'poetry',
|
||||||
'politics',
|
'politics',
|
||||||
'productivity',
|
'productivity',
|
||||||
'publication',
|
'recommendation',
|
||||||
'self-improvement',
|
'self-improvement',
|
||||||
'software',
|
'software',
|
||||||
'survival',
|
'technology',
|
||||||
'tip',
|
|
||||||
'typography',
|
|
||||||
'writing',
|
'writing',
|
||||||
])
|
])
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -182,4 +182,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.journal-card {
|
||||||
|
@apply relative col-span-2 row-span-3 inline-block overflow-hidden rounded-4 border-1 border-black/25 hover:scale-105 dark:border-white/25 md:row-span-5;
|
||||||
|
|
||||||
|
& img,
|
||||||
|
& picture {
|
||||||
|
@apply !h-full w-full object-cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
& img {
|
||||||
|
@apply !h-full scale-100 blur-0 brightness-[50%] filter transition duration-300 ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover img {
|
||||||
|
@apply scale-105 blur-sm brightness-[70%];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Writing is a passion for me. I’ve written a huge collection of essays about [Ninja & Ninjutsu](https://www.kogakure.de/) that I later converted into a book. The online publishing platform <cite>Medium</cite> selected [one of my essays](/attention/) as a recommendation of the day.
|
Writing is my passion. I've compiled a large collection of essays on [Ninja & Ninjutsu](https://www.kogakure.de/en/) which I later turned into a book. The online publishing platform <cite>Medium</cite> chose [one of my essays](/attention/) as their recommendation of the day. Additionally, I write [Haiku](/haiku/) poems.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from './date';
|
export * from './date';
|
||||||
|
export * from './pick-two-random-colors';
|
||||||
export * from './remark-reading-time';
|
export * from './remark-reading-time';
|
||||||
export * from './sort-by-date';
|
export * from './sort-by-date';
|
||||||
export * from './sort-by-sortkey';
|
export * from './sort-by-sortkey';
|
||||||
|
|||||||
18
src/utils/pick-two-random-colors.ts
Normal file
18
src/utils/pick-two-random-colors.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import colorsJson from '../data/colors-japan.json';
|
||||||
|
|
||||||
|
interface Color {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
color: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const pickTwoRandomColors = (): [string, string] => {
|
||||||
|
const colors: Color[] = colorsJson;
|
||||||
|
const randomIndex1 = Math.floor(Math.random() * colors.length);
|
||||||
|
let randomIndex2 = Math.floor(Math.random() * colors.length);
|
||||||
|
while (randomIndex2 === randomIndex1) {
|
||||||
|
randomIndex2 = Math.floor(Math.random() * colors.length);
|
||||||
|
}
|
||||||
|
return [colors[randomIndex1].color, colors[randomIndex2].color];
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user