chore: update

This commit is contained in:
enscribe 2024-09-10 17:51:46 -07:00
parent 8fe228e243
commit 43e35a3f8b
No known key found for this signature in database
GPG key ID: 9BBD5C4114E25322
54 changed files with 1013 additions and 496 deletions

View file

@ -2,18 +2,18 @@
import Layout from '@layouts/Layout.astro'
import Container from '@components/Container.astro'
import Link from '@components/Link.astro'
import BackToPrevious from '@components/BackToPrevious.astro'
import { SITE } from '@consts'
import { Button } from '@/components/ui/button'
---
<Layout title="404" description={SITE.DESCRIPTION}>
<Container>
<div class="mt-16 grid place-items-center gap-3">
<h4 class="text-2xl font-semibold">
404: Page not found
</h4>
<h4 class="text-2xl font-semibold">404: Page not found</h4>
<span>
<BackToPrevious href="/">Go to home page</BackToPrevious>
<a href="/">
<Button variant="outline"> Go to home page </Button>
</a>
</span>
</div>
</Container>

View file

@ -1,62 +1,35 @@
---
import { getCollection } from 'astro:content'
import Layout from '@layouts/Layout.astro'
import Container from '@components/Container.astro'
import { Image } from 'astro:assets'
import Link from '@components/Link.astro'
import { SITE } from '@consts'
---
<Layout title="About" description="About">
<Layout title="About" description={SITE.DESCRIPTION}>
<Container>
<div class="space-y-10">
<div class="font-semibold">About</div>
<section class="not-prose flex flex-col gap-4 text-justify">
<p class="text-justify">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolores porro
hic minima incidunt explicabo obcaecati consectetur consequuntur at
quisquam commodi.
</p>
<article class="prose max-w-none dark:prose-invert">
<h1 class="mb-8 text-3xl font-bold">About Us</h1>
<p class="mb-4">
Welcome to {SITE.TITLE}, a platform dedicated to sharing insights,
knowledge, and experiences in the world of technology and beyond. Our
mission is to provide valuable content that informs, inspires, and
engages our readers.
</p>
<p class="mb-8">
Founded in 2023, we've grown into a community of passionate writers and
tech enthusiasts. Our team brings diverse expertise to the table,
covering topics ranging from software development and artificial
intelligence to digital culture and tech ethics.
</p>
<p class="text-justify">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolores porro
hic minima incidunt explicabo obcaecati consectetur consequuntur at
quisquam commodi.
</p>
</section>
<div class="flex flex-col justify-center md:flex-row">
<div class="my-10 text-center">
<div
class="h-[250px] w-[350px] -rotate-6 overflow-hidden rounded-xl object-cover"
>
<Image
src={'/astro-nano.png'}
alt={'life2'}
width={350}
height={250}
class="h-[250px] w-[350px] overflow-hidden rounded-xl object-cover"
/>
</div>
<p class="mt-4 text-sm">
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
</p>
</div>
<div class="mx-10 my-10 text-center">
<div
class="mx-auto h-[250px] w-[150px] rotate-6 rounded-xl object-cover sm:ml-auto"
>
<Image
src={'/astro-micro.jpg'}
alt={'life2'}
width={150}
height={250}
class="h-[250px] w-[150px] rounded-xl object-cover"
/>
</div>
<p class="mt-4 text-sm">
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
</p>
</div>
</div>
</div>
<h2 class="mb-4 text-2xl font-semibold">Get in Touch</h2>
<p class="mb-4">
We love hearing from our readers! Whether you have a question,
suggestion, or just want to say hello, don't hesitate to reach out.
</p>
<p>
<Link href="/contact" class="font-semibold">Contact Us</Link>
</p>
</article>
</Container>
</Layout>

View file

@ -1,29 +1,32 @@
---
import { type CollectionEntry, getCollection, getEntry } from 'astro:content'
import { type CollectionEntry, getCollection } from 'astro:content'
import Layout from '@layouts/Layout.astro'
import MemberCard from '@components/MemberCard.astro'
import Container from '@components/Container.astro'
import AuthorCard from '@components/AuthorCard.astro'
import BlogCard from '@components/BlogCard.astro'
import { Button } from '@/components/ui/button'
export async function getStaticPaths() {
const authors = await getCollection('authors')
return authors.map((member) => ({
params: { slug: member.slug },
props: { member },
return authors.map((author) => ({
params: { slug: author.slug },
props: { author },
}))
}
type Props = {
member: CollectionEntry<'authors'>
author: CollectionEntry<'authors'>
}
const { member } = Astro.props
const { author } = Astro.props
const allPosts = await getCollection('blog')
const memberPosts = allPosts
const authorPosts = allPosts
.filter((post) => {
if (typeof post.data.author === 'string') {
return post.data.author === member.data.name && !post.data.draft
return post.data.author === author.data.name && !post.data.draft
} else if (post.data.author && 'slug' in post.data.author) {
return post.data.author.slug === member.slug && !post.data.draft
return post.data.author.slug === author.slug && !post.data.draft
}
return false
})
@ -31,10 +34,35 @@ const memberPosts = allPosts
---
<Layout
title={`${member.data.name} - Team Member`}
description={member.data.bio || `Profile of ${member.data.name}`}
title={`${author.data.name} - Author`}
description={author.data.bio || `Profile of ${author.data.name}`}
>
<section class="mx-auto flex max-w-screen-xl flex-col gap-4">
<MemberCard member={member} />
</section>
<Container>
<a href="/authors">
<Button variant="ghost" className="mb-8">&larr; Back to authors</Button>
</a>
<div class="space-y-10">
<section>
<AuthorCard author={author} />
</section>
<section class="space-y-4">
<h2 class="text-2xl font-semibold">Posts by {author.data.name}</h2>
{
authorPosts.length > 0 ? (
<ul class="not-prose flex flex-col gap-4">
{authorPosts.map((post) => (
<li>
<BlogCard entry={post} />
</li>
))}
</ul>
) : (
<p class="text-muted-foreground">
No posts available from this author.
</p>
)
}
</section>
</div>
</Container>
</Layout>

View file

@ -1,21 +1,25 @@
---
import { getCollection } from 'astro:content'
import Layout from '@layouts/Layout.astro'
import MemberCard from '@components/MemberCard.astro'
import Container from '@components/Container.astro'
import AuthorCard from '@components/AuthorCard.astro'
const authors = await getCollection('authors')
---
<Layout title="authors" description="authors">
<section>
<ul class="not-prose grid grid-cols-1 gap-4 lg:grid-cols-2 xl:grid-cols-3">
{
authors.map((member) => (
<li>
<MemberCard member={member} />
</li>
))
}
</ul>
</section>
<Layout title="Authors" description="Authors">
<Container>
<div class="space-y-10">
<h1 class="text-3xl font-semibold">Authors</h1>
<ul class="not-prose flex flex-col gap-4">
{
authors.map((author) => (
<li>
<AuthorCard author={author} />
</li>
))
}
</ul>
</div>
</Container>
</Layout>

View file

@ -1,12 +1,14 @@
---
import { type CollectionEntry, getCollection } from 'astro:content'
import { type CollectionEntry, getCollection, getEntry } from 'astro:content'
import Layout from '@layouts/Layout.astro'
import Container from '@components/Container.astro'
import FormattedDate from '@components/FormattedDate.astro'
import { readingTime } from '@lib/utils'
import BackToPrevious from '@components/BackToPrevious.astro'
import PostNavigation from '@components/PostNavigation.astro'
import TableOfContents from '@components/TableOfContents.astro'
import { Image } from 'astro:assets'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
export async function getStaticPaths() {
const posts = (await getCollection('blog'))
@ -45,47 +47,112 @@ const prevPost = getPrevPost(currentPostSlug)
const post = Astro.props
const { Content, headings } = await post.render()
let author = null
if (
post.data.author &&
typeof post.data.author === 'object' &&
'collection' in post.data.author
) {
author = await getEntry(post.data.author)
} else if (typeof post.data.author === 'string') {
author = {
data: {
name: post.data.author,
avatar: '/favicons/android-chrome-512x512.png',
},
}
}
---
<Layout title={post.data.title} description={post.data.description}>
<Container>
<div class="animate">
<BackToPrevious href="/blog">Back to blog</BackToPrevious>
</div>
<div class="my-10 space-y-4">
<div class="flex items-center gap-1.5">
<div class="font-base text-sm">
<FormattedDate date={post.data.date} />
</div>
&bull;
<div class="font-base text-sm">
{readingTime(post.body)}
<a href="/blog">
<Button variant="ghost" className="mb-8">&larr; Back to blog</Button>
</a>
{
post.data.image && (
<div class="mb-8 flex justify-center">
<Image
src={post.data.image}
alt={post.data.title}
width={1200}
height={630}
class="rounded-lg object-cover shadow-lg"
/>
</div>
)
}
<div class="mb-8 flex flex-col items-center gap-y-4">
<div class="flex items-center gap-3 text-sm text-muted-foreground">
<FormattedDate date={post.data.date} />
<span>&bull;</span>
<span>{readingTime(post.body)}</span>
</div>
<h1 class="text-4xl font-semibold">
<h1 class="text-4xl font-bold leading-tight sm:text-5xl">
{post.data.title}
</h1>
<div class="font-base text-sm">
<div class="flex flex-wrap gap-2">
{
post.data.tags && post.data.tags.length > 0 ? (
post.data.tags.map((tag) => (
<div class="my-1 inline-block">
<a
href={`/tags/${tag}`}
class="mx-1 rounded-full px-2 py-1 transition-colors duration-300 ease-in-out"
>
#{tag}
<Button variant="outline" asChild>
<a href={`/tags/${tag}`}>
<Badge variant="outline">{tag}</Badge>
</a>
</div>
</Button>
))
) : (
<span>No tags available</span>
<span class="text-sm text-muted-foreground">No tags available</span>
)
}
</div>
{
author && (
<div>
{typeof post.data.author === 'object' &&
'collection' in post.data.author ? (
<Button variant="ghost" asChild>
<a
class="group flex items-center gap-3 rounded-xl p-2 transition-colors duration-300 ease-in-out hover:bg-secondary"
href={`/authors/${post.data.author.slug}`}
>
<Image
src={author.data.avatar}
alt={`Avatar of ${author.data.name}`}
width={48}
height={48}
class="rounded-full"
/>
<div>
<span class="font-medium group-hover:text-primary">
{author.data.name}
</span>
<p class="text-sm text-muted-foreground">Author</p>
</div>
</a>
</Button>
) : (
<div class="flex items-center gap-3 rounded-xl p-2">
<Image
src={author.data.avatar || '/default-avatar.png'}
alt={`Avatar of ${author.data.name}`}
width={48}
height={48}
class="rounded-full"
/>
<div>
<span class="font-medium">{author.data.name}</span>
<p class="text-sm text-muted-foreground">Author</p>
</div>
</div>
)}
</div>
)
}
</div>
{headings.length > 0 && <TableOfContents headings={headings} />}
<article class="prose prose-neutral max-w-full dark:prose-invert prose-img:mx-auto prose-img:my-auto">
<article class="max-w-full">
<Content />
<div class="mt-24">
<PostNavigation prevPost={prevPost} nextPost={nextPost} />

View file

@ -2,7 +2,7 @@
import { type CollectionEntry, getCollection } from 'astro:content'
import Layout from '@layouts/Layout.astro'
import Container from '@components/Container.astro'
import ArrowCard from '@components/ArrowCard.astro'
import BlogCard from '@components/BlogCard.astro'
const data = (await getCollection('blog'))
.filter((post) => !post.data.draft)
@ -36,7 +36,7 @@ const years = Object.keys(posts).sort((a, b) => parseInt(b) - parseInt(a))
<ul class="not-prose flex flex-col gap-4">
{posts[year].map((post) => (
<li>
<ArrowCard entry={post} />
<BlogCard entry={post} />
</li>
))}
</ul>

View file

@ -2,7 +2,7 @@
import Layout from '@layouts/Layout.astro'
import Container from '@components/Container.astro'
import { SITE } from '@consts'
import ArrowCard from '@components/ArrowCard.astro'
import BlogCard from '@components/BlogCard.astro'
import Link from '@components/Link.astro'
import { getCollection } from 'astro:content'
@ -14,7 +14,7 @@ const blog = (await getCollection('blog'))
<Layout title="Home" description="Home">
<Container>
<section class="space-y-6">
<section class="space-y-4">
<div class="flex flex-wrap items-center justify-between gap-y-2">
<h2 class="font-semibold">Latest posts</h2>
<Link href="/blog"> See all posts </Link>
@ -23,7 +23,7 @@ const blog = (await getCollection('blog'))
{
blog.map((post) => (
<li>
<ArrowCard entry={post} />
<BlogCard entry={post} />
</li>
))
}

View file

@ -2,7 +2,7 @@
import { type CollectionEntry, getCollection } from 'astro:content'
import Layout from '@layouts/Layout.astro'
import Container from '@components/Container.astro'
import ArrowCard from '@components/ArrowCard.astro'
import BlogCard from '@components/BlogCard.astro'
type BlogPost = CollectionEntry<'blog'>
@ -36,11 +36,11 @@ export async function getStaticPaths() {
>
<Container>
<div class="space-y-10">
<div class="font-semibold">
Tag: <span
class="mx-2 rounded-full px-3 py-2 transition-colors duration-300 ease-in-out"
>#{tag}</span
>
<div class="flex items-center gap-2">
<h1 class="text-3xl font-semibold">Posts tagged with</h1>
<span class="rounded-full bg-secondary px-4 py-2 text-2xl font-medium">
{tag}
</span>
</div>
<div class="space-y-4">
{
@ -49,7 +49,7 @@ export async function getStaticPaths() {
<div>
<ul class="not-prose flex flex-col gap-4">
<li>
<ArrowCard entry={post} />
<BlogCard entry={post} />
</li>
</ul>
</div>

View file

@ -2,7 +2,7 @@
import { getCollection } from 'astro:content'
import Layout from '@layouts/Layout.astro'
import Container from '@components/Container.astro'
import Image from 'astro/components/Image.astro'
import { Badge } from '@/components/ui/badge'
const blog = (await getCollection('blog')).filter((post) => !post.data.draft)
@ -14,21 +14,18 @@ const tags = blog
<Layout title="Tags" description="Tags">
<Container>
<div class="space-y-10">
<div class="font-semibold">Tags</div>
<ul class="flex flex-wrap">
<h1 class="text-3xl font-semibold">Tags</h1>
<div class="flex flex-wrap gap-2">
{
tags.map((tag) => (
<li class="my-3">
<a
href={`/tags/${tag}`}
class="mx-2 rounded-full px-3 py-2 transition-colors duration-300 ease-in-out"
>
<a href={`/tags/${tag}`}>
<Badge variant="secondary" className="hover:bg-secondary/80">
#{tag}
</a>
</li>
</Badge>
</a>
))
}
</ul>
</div>
</div>
</Container>
</Layout>