merge in new changes
This commit is contained in:
182
src/pages/categories/index.astro
Normal file
182
src/pages/categories/index.astro
Normal file
@@ -0,0 +1,182 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import { readItems, readSingleton } from '@directus/sdk';
|
||||
|
||||
import type { Post } from '@lib/directusTypes';
|
||||
|
||||
import directus from '@lib/directus';
|
||||
import BaseLayout from '@layouts/BaseLayout.astro';
|
||||
import BlogCategoryCard from '@components/blog/BlogCategoryCard.astro';
|
||||
import HeroSection from '@components/ui/sections/HeroSection.astro';
|
||||
import { timeago } from '@support/time';
|
||||
import categoryImg from '@images/autumn_bench.png';
|
||||
|
||||
const global = await directus.request(readSingleton('site_global'));
|
||||
const posts = await directus.request(
|
||||
readItems('posts', {
|
||||
fields: ['*'],
|
||||
sort: ['-published_date'],
|
||||
})
|
||||
);
|
||||
|
||||
const postMap: Map<string, Post[]> = posts
|
||||
.sort((a: Post, b: Post) => b.published_date.valueOf() - a.published_date.valueOf())
|
||||
.reduce((acc, obj) => {
|
||||
let posts = acc.get(obj.category);
|
||||
if (!posts) {
|
||||
posts = [];
|
||||
}
|
||||
posts.push(obj);
|
||||
|
||||
acc.set(obj.category, posts);
|
||||
|
||||
return acc;
|
||||
}, new Map<string, Post[]>());
|
||||
|
||||
const layoutPattern = [
|
||||
{ col: 2, row: 2 },
|
||||
{ col: 2, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
{ col: 1, row: 2 },
|
||||
{ col: 2, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
{ col: 1, row: 1 },
|
||||
];
|
||||
|
||||
const categories = (await getCollection('categories'))
|
||||
.sort((a, b) => {
|
||||
const aCount = postMap.get(a.slug)?.length ?? 0;
|
||||
const bCount = postMap.get(b.slug)?.length ?? 0;
|
||||
return bCount - aCount;
|
||||
})
|
||||
.map((c, index) => {
|
||||
const posts = postMap.get(c.slug);
|
||||
const pattern = layoutPattern[index % layoutPattern.length];
|
||||
const smColSpan = Math.min(pattern.col, 2);
|
||||
const mdColSpan = Math.min(pattern.col, 4);
|
||||
const rowSpan = pattern.row;
|
||||
const rowSpanClass = rowSpan > 1 ? `row-span-${rowSpan}` : 'row-span-1';
|
||||
const gridItemClass = `col-span-${smColSpan} md:col-span-${mdColSpan} ${rowSpanClass} smooth-reveal-cards rounded-xl transition-all duration-300 shadow-xs hover:shadow-md dark:shadow-md dark:hover:shadow-lg border border-stone-200/50 dark:border-stone-700/50`;
|
||||
return {
|
||||
...c,
|
||||
posts,
|
||||
gridItemClass,
|
||||
layoutPattern: {
|
||||
smCol: smColSpan,
|
||||
mdCol: mdColSpan,
|
||||
row: rowSpan,
|
||||
index,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const description =
|
||||
'Here are some categories that I am interested in, including Laravel, Golang, and my life.';
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title="All Categories"
|
||||
description={description}
|
||||
structuredData={{
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'WebPage',
|
||||
inLanguage: 'en-US',
|
||||
'@id': Astro.url.href,
|
||||
url: Astro.url.href,
|
||||
name: `All Categories | ${global.name}`,
|
||||
description: description,
|
||||
isPartOf: {
|
||||
'@type': 'WebSite',
|
||||
url: global.site_url,
|
||||
name: global.name,
|
||||
description: global.about,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<HeroSection
|
||||
title="Categories"
|
||||
subTitle={description}
|
||||
src={categoryImg}
|
||||
alt={global.categories_image_alt}
|
||||
/>
|
||||
|
||||
<section class="mx-auto px-4 py-10 sm:px-6 lg:px-8 lg:py-14 lg:pt-10 2xl:max-w-full">
|
||||
<div class="grid grid-flow-row-dense grid-cols-2 gap-4 md:grid-cols-4">
|
||||
{
|
||||
categories.map((category) => {
|
||||
return (
|
||||
<div
|
||||
class={category.gridItemClass}
|
||||
style={category.layoutPattern.row > 1 ? 'grid-row: span 2 / span 2;' : ''}
|
||||
>
|
||||
<BlogCategoryCard
|
||||
slug={category.slug}
|
||||
title={category.data.title}
|
||||
description={category.data.description}
|
||||
count={postMap.get(category.slug)?.length ?? 0}
|
||||
publishDate={timeago(postMap.get(category.slug)?.[0]?.published_date)}
|
||||
layoutPattern={category.layoutPattern}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
</BaseLayout>
|
||||
|
||||
<script>
|
||||
// Add smooth reveal animations for content after loading
|
||||
document.addEventListener('astro:page-load', () => {
|
||||
const animateContent = () => {
|
||||
// Animate group 1
|
||||
const smoothReveal = document.querySelectorAll('.smooth-reveal');
|
||||
smoothReveal.forEach((el, index) => {
|
||||
setTimeout(
|
||||
() => {
|
||||
el.classList.add('animate-reveal');
|
||||
},
|
||||
50 + index * 100
|
||||
);
|
||||
});
|
||||
|
||||
// Animate group 2
|
||||
const smoothReveal2 = document.querySelectorAll('.smooth-reveal-2');
|
||||
smoothReveal2.forEach((el, index) => {
|
||||
setTimeout(
|
||||
() => {
|
||||
el.classList.add('animate-reveal');
|
||||
},
|
||||
200 + index * 150
|
||||
);
|
||||
});
|
||||
|
||||
// Animate topic cards with staggered delay
|
||||
const smoothRevealCards = document.querySelectorAll('.smooth-reveal-cards');
|
||||
smoothRevealCards.forEach((el, index) => {
|
||||
setTimeout(
|
||||
() => {
|
||||
el.classList.add('animate-reveal');
|
||||
},
|
||||
500 + index * 100
|
||||
);
|
||||
});
|
||||
|
||||
// Animate with just fade in with staggered delay
|
||||
const smoothRevealFade = document.querySelectorAll('.smooth-reveal-fade');
|
||||
smoothRevealFade.forEach((el, index) => {
|
||||
setTimeout(
|
||||
() => {
|
||||
el.classList.add('animate-reveal-fade');
|
||||
},
|
||||
100 + index * 250
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
animateContent();
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user