feat: introduce new components for improved structure and functionality
This commit is contained in:
parent
2e511b5e00
commit
c5e26d83c1
10 changed files with 101 additions and 62 deletions
|
|
@ -1,4 +1,6 @@
|
|||
---
|
||||
import Tag from "@/components/Tag.astro";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
|
|
@ -41,11 +43,7 @@ const { title, description, date, tags } = Astro.props;
|
|||
{
|
||||
tags?.map((tag) => (
|
||||
<li>
|
||||
<a href={`/tags/${tag}`}>
|
||||
<span class="text-sm text-zinc-400 font-semibold rounded-md bg-zinc-800 px-2 py-2 hover:bg-zinc-700">
|
||||
#{tag}
|
||||
</span>
|
||||
</a>
|
||||
<Tag name={tag} />
|
||||
</li>
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,9 @@ interface Props {
|
|||
date: Date;
|
||||
title: string;
|
||||
description: string;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
const { id, date, title, description, tags } = Astro.props;
|
||||
const { id, date, title, description } = Astro.props;
|
||||
---
|
||||
|
||||
<a href={`/posts/${id}`}>
|
||||
|
|
@ -22,13 +21,6 @@ const { id, date, title, description, tags } = Astro.props;
|
|||
}
|
||||
</div>
|
||||
<h2 class="text-2xl font-semibold mb-1">{title}</h2>
|
||||
<p class="text-sm mb-3">{description}</p>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{
|
||||
tags?.map((tag) => (
|
||||
<span class="text-xs text-zinc-400 font-semibold">#{tag}</span>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<p class="text-base text-zinc-400">{description}</p>
|
||||
</div>
|
||||
</a>
|
||||
|
|
|
|||
9
src/components/EmptyState.astro
Normal file
9
src/components/EmptyState.astro
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
interface Props {
|
||||
message: string;
|
||||
}
|
||||
|
||||
const { message } = Astro.props;
|
||||
---
|
||||
|
||||
<p class="text-lg text-zinc-400">{message}</p>
|
||||
|
|
@ -6,6 +6,7 @@ import socialFacebook from "@/assets/images/social-facebook.svg";
|
|||
import socialGithub from "@/assets/images/social-github.svg";
|
||||
import socialLinkedIn from "@/assets/images/social-linkedin.svg";
|
||||
import socialX from "@/assets/images/social-x.svg";
|
||||
import SocialLink from "@/components/SocialLink.astro";
|
||||
---
|
||||
|
||||
<div class="flex flex-col min-h-full items-center justify-center">
|
||||
|
|
@ -18,44 +19,36 @@ import socialX from "@/assets/images/social-x.svg";
|
|||
<h1 class="text-5xl font-bold mt-4">Dhemas Nurjaya</h1>
|
||||
<h2 class="text-xl mt-2">Passionate Software Engineer</h2>
|
||||
<div class="flex flex-row gap-8 mt-8" aria-label="social links">
|
||||
<a
|
||||
<SocialLink
|
||||
href="https://www.linkedin.com/in/dhemas-nurjaya-030890bb"
|
||||
aria-label="Linkedin"
|
||||
>
|
||||
<Image
|
||||
src={socialLinkedIn}
|
||||
alt="LinkedIn"
|
||||
loading="eager"
|
||||
class="w-6 h-6 invert"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://github.com/dhemasnurjaya" aria-label="Github">
|
||||
<Image
|
||||
src={socialGithub}
|
||||
alt="Github"
|
||||
loading="eager"
|
||||
class="w-6 h-6 invert"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://x.com/dhemaseka" aria-label="X">
|
||||
<Image src={socialX} alt="X" loading="eager" class="w-6 h-6 invert" />
|
||||
</a>
|
||||
<a href="https://www.facebook.com/Dhemas" aria-label="Facebook">
|
||||
<Image
|
||||
src={socialFacebook}
|
||||
alt="Facebook"
|
||||
loading="eager"
|
||||
class="w-6 h-6 invert"
|
||||
/>
|
||||
</a>
|
||||
<a href="mailto:dhemasnurjaya@gmail.com" aria-label="Email">
|
||||
<Image
|
||||
src={socialEmail}
|
||||
alt="Email"
|
||||
loading="eager"
|
||||
class="w-6 h-6 invert"
|
||||
/>
|
||||
</a>
|
||||
label="Linkedin"
|
||||
icon={socialLinkedIn}
|
||||
alt="LinkedIn"
|
||||
/>
|
||||
<SocialLink
|
||||
href="https://github.com/dhemasnurjaya"
|
||||
label="Github"
|
||||
icon={socialGithub}
|
||||
alt="Github"
|
||||
/>
|
||||
<SocialLink
|
||||
href="https://x.com/dhemaseka"
|
||||
label="X"
|
||||
icon={socialX}
|
||||
alt="X"
|
||||
/>
|
||||
<SocialLink
|
||||
href="https://www.facebook.com/Dhemas"
|
||||
label="Facebook"
|
||||
icon={socialFacebook}
|
||||
alt="Facebook"
|
||||
/>
|
||||
<SocialLink
|
||||
href="mailto:dhemasnurjaya@gmail.com"
|
||||
label="Email"
|
||||
icon={socialEmail}
|
||||
alt="Email"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-24"></div>
|
||||
</div>
|
||||
|
|
|
|||
9
src/components/PageTitle.astro
Normal file
9
src/components/PageTitle.astro
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
interface Props {
|
||||
title: string;
|
||||
}
|
||||
|
||||
const { title } = Astro.props;
|
||||
---
|
||||
|
||||
<h1 class="text-4xl font-bold mb-8">{title}</h1>
|
||||
17
src/components/SocialLink.astro
Normal file
17
src/components/SocialLink.astro
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
import { Image } from "astro:assets";
|
||||
import type { ImageMetadata } from "astro";
|
||||
|
||||
interface Props {
|
||||
href: string;
|
||||
label: string;
|
||||
icon: ImageMetadata;
|
||||
alt: string;
|
||||
}
|
||||
|
||||
const { href, label, icon, alt } = Astro.props;
|
||||
---
|
||||
|
||||
<a href={href} aria-label={label}>
|
||||
<Image src={icon} alt={alt} loading="eager" class="w-6 h-6 invert" />
|
||||
</a>
|
||||
21
src/components/Tag.astro
Normal file
21
src/components/Tag.astro
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
interface Props {
|
||||
name: string;
|
||||
count?: number;
|
||||
href?: string;
|
||||
variant?: "default" | "small";
|
||||
}
|
||||
|
||||
const { name, count, href, variant = "default" } = Astro.props;
|
||||
const linkHref = href || `/tags/${name}`;
|
||||
const isSmall = variant === "small";
|
||||
const textSize = isSmall ? "text-xs" : "text-sm";
|
||||
---
|
||||
|
||||
<a href={linkHref}>
|
||||
<span
|
||||
class={`${textSize} text-zinc-400 font-semibold rounded-md bg-zinc-800 px-2 py-2 hover:bg-zinc-700`}
|
||||
>
|
||||
#{name}{count !== undefined && <sup>{count}</sup>}
|
||||
</span>
|
||||
</a>
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
import { getCollection } from "astro:content";
|
||||
import Layout from "@/layouts/Layout.astro";
|
||||
import BlogPostCard from "@/components/BlogPostCard.astro";
|
||||
import PageTitle from "@/components/PageTitle.astro";
|
||||
|
||||
const posts = await getCollection("blog");
|
||||
posts.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
|
||||
|
|
@ -11,7 +12,7 @@ posts.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
|
|||
title="Posts - Dhemas Nurjaya"
|
||||
description="Read the latest blog posts by Dhemas Nurjaya"
|
||||
>
|
||||
<h1 class="text-4xl font-bold mb-8">Posts</h1>
|
||||
<PageTitle title="Posts" />
|
||||
<ul class="space-y-4">
|
||||
{
|
||||
posts.map((post) => (
|
||||
|
|
@ -21,7 +22,6 @@ posts.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
|
|||
title={post.data.title}
|
||||
date={post.data.date}
|
||||
description={post.data.description}
|
||||
tags={post.data.tags}
|
||||
/>
|
||||
</li>
|
||||
))
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
import { getCollection, type CollectionEntry } from "astro:content";
|
||||
import BlogPostCard from "@/components/BlogPostCard.astro";
|
||||
import Layout from "@/layouts/Layout.astro";
|
||||
import PageTitle from "@/components/PageTitle.astro";
|
||||
import EmptyState from "@/components/EmptyState.astro";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection("blog");
|
||||
|
|
@ -36,7 +38,7 @@ const { filteredPosts } = Astro.props;
|
|||
title={`Posts tagged with "${name}" - Dhemas Nurjaya`}
|
||||
description={`Browse blog posts tagged with "${name}" by Dhemas Nurjaya`}
|
||||
>
|
||||
<h1 class="text-4xl font-bold mb-8">Posts tagged with "{name}"</h1>
|
||||
<PageTitle title={`Posts tagged with "${name}"`} />
|
||||
{
|
||||
filteredPosts.length > 0 ? (
|
||||
<ul class="space-y-4">
|
||||
|
|
@ -53,7 +55,7 @@ const { filteredPosts } = Astro.props;
|
|||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<p class="text-lg text-zinc-400">No posts found with the tag "{name}".</p>
|
||||
<EmptyState message={`No posts found with the tag "${name}".`} />
|
||||
)
|
||||
}
|
||||
</Layout>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
---
|
||||
import { getCollection } from "astro:content";
|
||||
import Layout from "@/layouts/Layout.astro";
|
||||
import PageTitle from "@/components/PageTitle.astro";
|
||||
import Tag from "@/components/Tag.astro";
|
||||
|
||||
const posts = await getCollection("blog");
|
||||
const tagsMap = new Map<string, number>();
|
||||
|
|
@ -16,16 +18,12 @@ const tags = Array.from(tagsMap.entries()).sort((a, b) =>
|
|||
---
|
||||
|
||||
<Layout title="Tags - Dhemas Nurjaya" description="Browse blog posts by tags">
|
||||
<h1 class="text-4xl font-bold mb-8">Tags</h1>
|
||||
<PageTitle title="Tags" />
|
||||
<ul class="flex flex-wrap gap-4">
|
||||
{
|
||||
tags?.map(([tag, count]) => (
|
||||
<li class="mb-4">
|
||||
<a href={`/tags/${tag}`}>
|
||||
<span class="text-lg text-zinc-400 font-semibold rounded-md bg-zinc-800 px-2 py-2 hover:bg-zinc-700">
|
||||
{tag} <sup>{count}</sup>
|
||||
</span>
|
||||
</a>
|
||||
<Tag name={tag} count={count} />
|
||||
</li>
|
||||
))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue