[READ-ONLY] Mirror of https://github.com/flo-bit/blog-template. minimalistic astro blog template flo-bit.dev/blog-template/
astro blog template
0

Configure Feed

Select the types of activity you want to include in your feed.

add bluesky comments

+286 -192
src/assets/comments.png

This is a binary file and will not be displayed.

src/assets/likes.png

This is a binary file and will not be displayed.

+42
src/components/BigBlogEntry.astro
··· 1 + --- 2 + import { BASE } from "../config.json"; 3 + import FormattedDate from "./FormattedDate.astro"; 4 + import Tag from "./Tag.astro"; 5 + import HeroImage from "./HeroImage.astro"; 6 + 7 + const { title, description, pubDate, slug, heroImage, tags } = Astro.props; 8 + --- 9 + 10 + <article 11 + class="relative isolate flex flex-col gap-8 lg:flex-row group md:grid md:grid-cols-2 mt-8" 12 + > 13 + <div class="relative aspect-[16/9] lg:w-full lg:shrink-0"> 14 + <HeroImage image={heroImage} /> 15 + </div> 16 + <div class="h-full flex flex-col justify-center"> 17 + <div class="flex items-center gap-x-4 text-xs"> 18 + <time datetime="2020-03-16" class="text-base-500"> 19 + <FormattedDate date={pubDate} /> 20 + </time> 21 + {tags?.map((tag: string) => <Tag {tag} />)} 22 + </div> 23 + <div class="max-w-xl"> 24 + <div 25 + class="mt-3 text-xl md:text-2xl font-bold leading-6 text-base-900 dark:text-base-50" 26 + > 27 + <a href={BASE + `/posts/${slug}/`}> 28 + <span class="absolute inset-0"></span> 29 + {title} 30 + </a> 31 + 32 + <div 33 + class="absolute -inset-2 md:-inset-4 rounded-2xl opacity-0 group-hover:opacity-100 scale-95 group-hover:scale-100 bg-base-200/50 dark:bg-base-800/50 -z-10 transition-all duration-150" 34 + > 35 + </div> 36 + </div> 37 + <p class="mt-5 text-sm leading-6 text-base-600 dark:text-base-400"> 38 + {description} 39 + </p> 40 + </div> 41 + </div> 42 + </article>
+2 -23
src/components/BlogEntry.astro
··· 1 1 --- 2 2 import { BASE } from "../config.json"; 3 3 import FormattedDate from "./FormattedDate.astro"; 4 - import { Image } from "astro:assets"; 5 - import type { ImageMetadata } from "astro"; 6 4 import Tag from "./Tag.astro"; 5 + import HeroImage from "./HeroImage.astro"; 7 6 8 7 const { title, description, pubDate, slug, heroImage, tags } = Astro.props; 9 - 10 - const images = import.meta.glob<{ default: ImageMetadata }>( 11 - "/src/assets/*.{jpeg,jpg,png,gif}" 12 - ); 13 - 14 - // replace ../.. with src in heroImage 15 - let replacedHero = heroImage.replace("../..", "/src"); 16 - 17 - if (!images[replacedHero]) 18 - throw new Error( 19 - `"${replacedHero}" does not exist in glob: "src/assets/*.{jpeg,jpg,png,gif}"` 20 - ); 21 8 --- 22 9 23 10 <article class="relative isolate flex flex-col gap-8 lg:flex-row group"> 24 11 <div class="relative aspect-[16/9] lg:w-64 lg:shrink-0"> 25 - <Image 26 - src={images[replacedHero]()} 27 - alt="" 28 - class="absolute inset-0 h-full w-full rounded-2xl bg-base-50 dark:bg-base-900 object-cover" 29 - /> 30 - <div 31 - class="absolute inset-0 rounded-2xl ring-1 ring-inset ring-base-900/10 dark:ring-base-100/10" 32 - > 33 - </div> 12 + <HeroImage image={heroImage} /> 34 13 </div> 35 14 <div> 36 15 <div class="flex items-center gap-x-4 text-xs">
+27
src/components/HeroImage.astro
··· 1 + --- 2 + import { Image } from "astro:assets"; 3 + 4 + const { image } = Astro.props; 5 + const images = import.meta.glob<{ default: ImageMetadata }>( 6 + "/src/assets/*.{jpeg,jpg,png,gif}" 7 + ); 8 + 9 + // replace ../.. with src in image 10 + let replacedImage = image.replace("../..", "/src"); 11 + 12 + if (!images[replacedImage]) 13 + throw new Error( 14 + `"${replacedImage}" does not exist in glob: "src/assets/*.{jpeg,jpg,png,gif}"` 15 + ); 16 + --- 17 + 18 + <Image 19 + src={images[replacedImage]()} 20 + alt="" 21 + class="absolute inset-0 h-full w-full rounded-2xl bg-base-50 dark:bg-base-900 object-cover" 22 + /> 23 + 24 + <div 25 + class="absolute inset-0 rounded-2xl ring-1 ring-inset ring-base-900/10 dark:ring-base-100/10" 26 + > 27 + </div>
+2 -2
src/components/bluesky/Comment.svelte
··· 12 12 const { comment, depth = 0 } = $props(); 13 13 </script> 14 14 15 - <div class="border-l dark:border-base-800 border-base-300 pl-6"> 15 + <div class="border-l dark:border-base-800 border-base-300 pl-3"> 16 16 <div class="mt-2 pb-2"> 17 17 <div 18 - class="text-sm text-base-600 dark:text-base-500 flex items-center -ml-9" 18 + class="text-sm text-base-600 dark:text-base-500 flex items-center -ml-6" 19 19 > 20 20 <Avatar 21 21 src={comment.post.author.avatar}
+40 -37
src/components/bluesky/Comments.svelte
··· 1 1 <script lang="ts"> 2 - import { onMount } from "svelte"; 3 - import { atUriToPostUri, getUserPosts, getLikes, getPost, getComments } from "./utils"; 4 - import { cn } from "src/utils"; 5 - import Comment from "./Comment.svelte"; 6 - 7 - let { uri, likesCount, likesData, user, comments } = $props(); 8 - 9 - let postUri = $state(uri); 10 - 11 - onMount(async () => { 12 - if (!uri && user) { 13 - let posts = await getUserPosts(user); 14 - 15 - const url = window.location.href; 16 - 17 - // @ts-expect-error: weird type fuckery 18 - const post = posts.find((post) => post.post.embed?.external?.uri === url); 19 - 20 - if (post) { 21 - postUri = post.post.uri; 22 - comments = await getComments(post.post.uri); 23 - } 24 - } else if (uri) { 25 - comments = await getComments(uri); 26 - } 2 + import { onMount } from "svelte"; 3 + import { getUserPosts, getComments, getCommentCount } from "./utils"; 4 + import Comment from "./Comment.svelte"; 5 + 6 + let { uri, user, comments } = $props(); 7 + 8 + let postUri = $state(uri); 9 + 10 + onMount(async () => { 11 + if (!uri && user) { 12 + let posts = await getUserPosts(user); 13 + 14 + const url = window.location.href; 15 + 16 + // @ts-expect-error: weird type fuckery 17 + const post = posts.find((post) => post.post.embed?.external?.uri === url); 18 + 19 + if (post) { 20 + postUri = post.post.uri; 21 + comments = await getComments(post.post.uri); 22 + } 23 + } else if (uri) { 24 + comments = await getComments(uri); 25 + } 26 + 27 + console.log(comments); 28 + }); 29 + </script> 27 30 28 - console.log(comments); 29 - }); 30 - </script> 31 - 32 - <div class="not-prose mt-8"> 33 - 31 + <div class="not-prose mt-8"> 34 32 {#if comments.length > 0} 35 - <div> 36 - {#each comments as comment} 37 - <Comment comment={comment} /> 38 - {/each} 39 - </div> 33 + <div class="text-sm text-base-950 dark:text-base-100 font-semibold"> 34 + {getCommentCount(comments)} comments, sorted by newest first 35 + </div> 40 36 {/if} 41 37 42 - </div> 38 + {#if comments.length > 0} 39 + <div class="pt-4"> 40 + {#each comments as comment} 41 + <Comment {comment} /> 42 + {/each} 43 + </div> 44 + {/if} 45 + </div>
+2 -3
src/components/bluesky/Likes.svelte
··· 7 7 8 8 let postUri = $state(uri); 9 9 let postLikesCount = $state(likesCount); 10 - let postLikesData = $state(likesData.filter((like) => like.actor.avatar)); 10 + let postLikesData = $state(likesData.filter((like: any) => like.actor.avatar)); 11 11 12 12 onMount(async () => { 13 13 if (!uri && user) { ··· 41 41 42 42 {#if postUri} 43 43 <div class="not-prose flex flex-col mt-8 gap-4"> 44 - 45 44 <div class="text-sm text-base-950 dark:text-base-100 font-semibold"> 46 - {postLikesCount} like{postLikesCount === 1 ? "" : "s"} on bluesky 45 + {postLikesCount} like{postLikesCount === 1 ? "" : "s"} 47 46 </div> 48 47 49 48 <div class="isolate flex -space-x-2 overflow-hidden px-4 flex-wrap">
+12 -1
src/components/bluesky/utils.ts
··· 215 215 return `${Math.floor(number / 1000)}k`; 216 216 } 217 217 return `${Math.floor(number / 1000000)}m`; 218 - } 218 + } 219 + 220 + export function getCommentCount(comments: { replies?: any}[]) { 221 + // recursively check for replies and add them up 222 + let count = comments.length; 223 + for(const comment of comments) { 224 + if(comment.replies?.length) { 225 + count += getCommentCount(comment.replies); 226 + } 227 + } 228 + return count; 229 + }
-1
src/config.json
··· 21 21 "BLUESKY_URL": "https://bsky.app/profile/flo-bit.dev" 22 22 }, 23 23 "BLUESKY_IDENTIFIER": "flo-bit.dev", 24 - "MANUAL_SITE_BASE": true, 25 24 "SITE": "https://flo-bit.dev", 26 25 "BASE": "/blog-template" 27 26 }
src/content/blog/adding-content.md src/content/blog/adding-content.mdx
+34
src/content/blog/comments-via-bluesky.mdx
··· 1 + --- 2 + title: "Showing comments using Bluesky" 3 + description: "showing comments on your blog posts using bluesky" 4 + pubDate: "Dec 02 2024" 5 + published: true 6 + heroImage: "/src/assets/blog-placeholder-1.jpg" 7 + tags: ["setup"] 8 + --- 9 + 10 + You can also show comments on your blog posts using bluesky. 11 + 12 + ## How it works 13 + 14 + Set the `BLUESKY_IDENTIFIER` in your `src/config.json` file to your bluesky handle (without the `@`). 15 + 16 + Then just post a link to your blog post on bluesky and comments will be shown on your blog posts, looking something like this: 17 + 18 + <div class="max-w-md rounded-xl overflow-hidden border border-base-200 dark:border-base-800 shadow-lg not-prose"> 19 + ![showing comments]($assets/comments.png) 20 + </div> 21 + 22 + Note that no "add comment" link is shown if there is no post on bluesky linking to your blog post. 23 + 24 + Comments are both server-side rendered on build and updated on the client when you navigate to the page 25 + (so they work without javascript, but might be a bit outdated). 26 + 27 + If you post a link to your blog post on bluesky, likes will also be shown (see [likes via bluesky](../likes-via-bluesky)). 28 + If you don't want to show likes, you can disable them using the `disableLikes` option in your post options. 29 + 30 + ```yml 31 + disableLikes: true 32 + ``` 33 + 34 + See a live example below:
+17 -15
src/content/blog/configuring-the-blog.md src/content/blog/configuring-the-blog.mdx
··· 7 7 tags: ["setup"] 8 8 --- 9 9 10 - Editing the code: Change the values in `src/config.json` to configure the blog to your liking, see below for more information. 10 + Change the values in `src/config.json` to configure the blog to your liking, see below for more information. 11 + 12 + ## SITE 11 13 12 - Editing using [pagecms](https://next.pagescms.org): After having logged in and opened your repository, click on "Website Configuration" and fill out the form, changing the values to your liking. Click "Save" to apply the changes (takes about 1 minute to deploy). 14 + - set this to your blog url, e.g. `https://flo-bit.dev` 15 + 16 + ## BASE 17 + 18 + - set this to the base path of your blog, e.g. `/blog-template` 13 19 14 20 ## SITE_TITLE 15 21 16 22 - will be shown in the title and meta tags and og image 23 + 24 + ## SITE_NAME 25 + 26 + - will be shown in the header, leave blank to hide 17 27 18 28 ## SITE_DESCRIPTION 19 29 ··· 51 61 one of 'red', 'orange', 'amber', 'yellow', 'lime', 'green', 'emerald', 'teal', 52 62 'cyan', 'sky', 'blue', 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose' 53 63 64 + ## BLUESKY_IDENTIFIER 65 + 66 + - set this to your bluesky handle, e.g. `flo-bit.dev` (without the `@`) will be used to show likes and comments on your blog posts from bluesky 67 + 54 68 ## SOCIAL MEDIA LINKS 55 69 56 70 - set any of these to '' to hide the respective icon in the footer ··· 62 76 - LINKEDIN_URL 63 77 - YOUTUBE_URL 64 78 - SUBSTACK_URL 79 + - BLUESKY_URL 65 80 - EMAIL 66 - 67 - ## MANUAL_SITE_BASE 68 - 69 - - set this to true if you want to manually set the site and base url 70 - (e.g. when not deploying to github pages) 71 - 72 - ## SITE 73 - 74 - - will be set automatically when deploying to github pages 75 - 76 - ## BASE 77 - 78 - - will be set automatically when deploying to github pages
+1 -1
src/content/blog/features.md src/content/blog/features.mdx
··· 20 20 - ✅ Tag your posts 21 21 - ✅ Super easy to deploy as a static site 22 22 - ✅ Includes some prebuilt components for you to use 23 - - ✅ Easy to edit using [pagecms](https://pagescms.org) (see [how to use](posts/how-to-use)) 23 + - ✅ Likes and comments via bluesky
-37
src/content/blog/how-to-use.md
··· 1 - --- 2 - title: "Minimal setup with github pages" 3 - description: "Learn how to use this blog template with github pages (for free, with no coding required)" 4 - pubDate: "Oct 26 2024" 5 - published: true 6 - heroImage: "/src/assets/blog-placeholder-2.jpg" 7 - tags: ["setup"] 8 - --- 9 - 10 - 1. Fork [the repository of this blog](https://github.com/flo-bit/blog-template) (note: this repository per default uses github actions which are only free for public repositories) 11 - 12 - 2. In your repository settings, set up github pages to deploy using github actions (*SETTINGS* -> *PAGES* -> *SOURCE*: **Github Actions**) 13 - 14 - 3. Your blog should be live in about 1 minute at `https://<your-github-username>.github.io/<your-repo-name>` 15 - 16 - For editing the blog you can either edit the code directly or use the preconfigured [pagescms](https://next.pagescms.org). 17 - 18 - ### Editing with pagescms 19 - 20 - 4. Go to [pagescms](https://next.pagescms.org) and log in with your github account and authorize the app. 21 - 22 - 5. Add your repository to pagescms and open it. 23 - 24 - 6. Now you can edit your website configuration, about page, description and blog posts directly in the browser. 25 - 26 - 7. Your changes will be automatically pushed to your repository and deployed to github pages in about 1 minute everytime you hit save. 27 - 28 - ### Editing the code 29 - 30 - 4. Set up your blog info in `src/config.json` (leaving SITE, BASE, and MANUAL_SITE_BASE, as they are). 31 - 32 - 5. Add your blog posts in `src/content/blog/` 33 - 34 - 6. Add your info in `src/content/info/`: 35 - 36 - - `description.md` is used for the homepage description 37 - - `about.md` is used for the about page
+22
src/content/blog/how-to-use.mdx
··· 1 + --- 2 + title: "Minimal setup with github pages" 3 + description: "Learn how to use this blog template with github pages (for free, with no coding required)" 4 + pubDate: "Oct 26 2024" 5 + published: true 6 + heroImage: "/src/assets/blog-placeholder-2.jpg" 7 + tags: ["setup"] 8 + --- 9 + 10 + 1. Fork [the repository of this blog](https://github.com/flo-bit/blog-template) (note: this repository per default uses github actions which are only free for public repositories) 11 + 12 + 2. In your repository settings, set up github pages to deploy using github actions (*SETTINGS* -> *PAGES* -> *SOURCE*: **Github Actions**) 13 + 14 + 3. Set up your blog info in `src/config.json` (see [all options](../configuring-the-blog)) 15 + 16 + 4. Your blog should be live in about 1 minute at `https://<your-github-username>.github.io/<your-repo-name>` 17 + 18 + 5. Add your blog posts in `src/content/blog/` 19 + 20 + 6. Add your info in `src/content/info/`: 21 + 22 + - `about.mdx` is used for the about page
-26
src/content/blog/likes-via-bluesky.md
··· 1 - --- 2 - title: "Showing Likes using Bluesky" 3 - description: "how to show likes on your blog posts using bluesky" 4 - pubDate: "Nov 22 2024" 5 - published: true 6 - heroImage: "/src/assets/blog-placeholder-3.jpg" 7 - tags: ["setup"] 8 - disableComments: true 9 - --- 10 - 11 - You can show likes on your blog posts using bluesky. 12 - 13 - ## How it works 14 - 15 - Set the `BLUESKY_IDENTIFIER` in your `src/config.json` file to your bluesky handle (without the `@`). 16 - 17 - Then just post a link to your blog post on bluesky and likes will be shown on your blog posts, looking something like this: 18 - 19 - ![likes]($assets/likes.png) 20 - 21 - Note that no like button is shown if there is no post on bluesky linking to your blog post. 22 - 23 - Likes are both server-side rendered on build and updated on the client when you navigate to the page 24 - (so they work without javascript, but might be a bit outdated). 25 - 26 - See a live example below:
+35
src/content/blog/likes-via-bluesky.mdx
··· 1 + --- 2 + title: "Showing Likes using Bluesky" 3 + description: "how to show likes on your blog posts using bluesky" 4 + pubDate: "Nov 22 2024" 5 + published: true 6 + heroImage: "/src/assets/blog-placeholder-3.jpg" 7 + tags: ["setup"] 8 + disableComments: false 9 + --- 10 + 11 + You can show likes on your blog posts using bluesky. 12 + 13 + ## How it works 14 + 15 + Set the `BLUESKY_IDENTIFIER` in your `src/config.json` file to your bluesky handle (without the `@`). 16 + 17 + Then just post a link to your blog post on bluesky and likes will be shown on your blog posts, looking something like this: 18 + 19 + <div class="max-w-md rounded-xl overflow-hidden border border-base-200 dark:border-base-800 shadow-lg not-prose"> 20 + ![showing likes]($assets/likes.png) 21 + </div> 22 + 23 + Note that no like link is shown if there is no post on bluesky linking to your blog post. 24 + 25 + Likes are both server-side rendered on build and updated on the client when you navigate to the page 26 + (so they work without javascript, but might be a bit outdated). 27 + 28 + If you post a link to your blog post on bluesky, comments will also be shown (see [comments via bluesky](../comments-via-bluesky)). 29 + If you don't want to show comments, you can disable them using the `disableComments` option in your post options. 30 + 31 + ```yml 32 + disableComments: true 33 + ``` 34 + 35 + See a live example below:
+1 -1
src/content/blog/markdown-style-guide.md src/content/blog/markdown-style-guide.mdx
··· 80 80 81 81 #### Output 82 82 83 - > Don't communicate by sharing memory, share memory by communicating.<br> 83 + > Don't communicate by sharing memory, share memory by communicating.<br /> 84 84 > — <cite>Rob Pike[^1]</cite> 85 85 86 86 [^1]: The above quote is excerpted from Rob Pike's [talk](https://www.youtube.com/watch?v=PAAkCSZUG1c) during Gopherfest, November 18, 2015.
+16 -2
src/content/blog/post-options.md src/content/blog/post-options.mdx
··· 7 7 tags: ["setup"] 8 8 --- 9 9 10 - > You only need this when you edit the markdown files directly. When you use [pagecms](https://next.pagescms.org) you can configure the post directly in the browser and don't need to worry about this. 11 - 12 10 here are all options you can use in the frontmatter of a blog post: 13 11 14 12 ### title: string (required) ··· 90 88 ```yml 91 89 noTextInOGImage: false 92 90 ``` 91 + 92 + ### disable comments (optional) 93 + 94 + - whether to disable comments, default: false 95 + 96 + ```yml 97 + disableComments: false 98 + ``` 99 + 100 + ### disable likes (optional) 101 + 102 + - whether to disable likes, default: false 103 + 104 + ```yml 105 + disableLikes: false 106 + ```
-21
src/content/info/about.md
··· 1 - # Hello world! 🌎 2 - 3 - Here you can write something about yourself, who are you, why are you writing this blog, what are you going to write about, etc. 4 - 5 - You can also add some images or links like this: 6 - 7 - ### Image 8 - 9 - ```markdown 10 - ![earth](../../assets/earth.jpg) 11 - ``` 12 - 13 - ![earth](../../assets/earth.jpg) 14 - 15 - ### Link 16 - 17 - ```markdown 18 - here is a [post about how to use this template](posts/how-to-use) 19 - ``` 20 - 21 - here is a [post about how to use this template](posts/how-to-use)
-2
src/content/info/description.md src/content/info/about.mdx
··· 1 1 # Blog template 2 2 3 - > This description will be shown on the main page of your blog above your most recent posts. It could be a short summary of what your blog is about, and what readers can expect. 4 - 5 3 Minimalistic but opinionated blog template using [astro](https://astro.build/) and [svelte](https://svelte.dev/). aims to be super easy to deploy and use, with a focus on performance and SEO, ease-of-use and design (see all [features here](posts/features)). 6 4 7 5 This blog doubles as a tutorial on how to use this template, start by [setting up your github repo](posts/how-to-use), then [add some content](posts/adding-content). For more information read about [supported markdown features here](posts/markdown-style-guide).
+19 -4
src/layouts/PostList.astro
··· 1 1 --- 2 - import { SITE_TITLE, SITE_DESCRIPTION } from "../config.json"; 2 + import { SITE_TITLE, SITE_DESCRIPTION, BASE } from "../config.json"; 3 3 4 4 import Footer from "$components/Footer.astro"; 5 5 import Header from "$components/Header.astro"; ··· 8 8 9 9 import Pagination from "$components/Pagination.astro"; 10 10 import ProseWrapper from "./ProseWrapper.astro"; 11 + import HeroImage from "$components/HeroImage.astro"; 12 + import BigBlogEntry from "$components/BigBlogEntry.astro"; 11 13 12 14 type Props = { 13 15 posts: Array<any>; 14 16 totalPages: number; 15 17 currentPage: number; 16 18 tag?: string; 19 + showFeatured?: boolean; 17 20 }; 18 21 19 - const { posts, totalPages, currentPage, tag } = Astro.props; 22 + const { posts, totalPages, currentPage, tag, showFeatured } = Astro.props; 20 23 --- 21 24 22 25 <BaseLayout title={SITE_TITLE} description={SITE_DESCRIPTION}> 23 26 <Header active="blog" /> 24 - <main class="max-w-2xl lg:max-w-3xl mx-auto mt-16 px-4"> 27 + <main class="max-w-2xl lg:max-w-3xl mx-auto mt-8 px-4"> 25 28 <ProseWrapper> 26 29 <slot /> 27 30 </ProseWrapper> 31 + 32 + { 33 + showFeatured ? ( 34 + <BigBlogEntry {...posts[0].data} slug={posts[0].slug} /> 35 + ) : null 36 + } 28 37 <div class="my-14 space-y-16 max-w-3xl"> 29 - {posts.map((post: any) => <BlogEntry {...post.data} slug={post.slug} />)} 38 + { 39 + posts.map((post: any, index: number) => 40 + index > 0 || !showFeatured ? ( 41 + <BlogEntry {...post.data} slug={post.slug} /> 42 + ) : null 43 + ) 44 + } 30 45 </div> 31 46 32 47 {
+2 -2
src/pages/about/index.astro
··· 5 5 import Header from "$components/Header.astro"; 6 6 import BaseLayout from "$layouts/BaseLayout.astro"; 7 7 import BlogPost from "$layouts/BlogPost.astro"; 8 - import { Content } from "$content/info/about.md"; 8 + import { Content } from "$content/info/about.mdx"; 9 9 --- 10 10 11 11 <BaseLayout title={SITE_TITLE} description={SITE_DESCRIPTION}> 12 12 <Header active="about" /> 13 13 14 - <main class="max-w-2xl lg:max-w-3xl mx-auto mt-16 px-4"> 14 + <main class="max-w-2xl lg:max-w-3xl mx-auto mt-8 px-4"> 15 15 <BlogPost> 16 16 <Content /> 17 17 </BlogPost>
+2 -2
src/pages/index.astro
··· 10 10 const total = Math.ceil((await getBlogPosts()).length / POSTS_PER_PAGE); 11 11 --- 12 12 13 - <PostList {posts} totalPages={total} currentPage={1}> 14 - <Content /> 13 + <PostList {posts} totalPages={total} currentPage={1} showFeatured> 14 + <h1>Latest blog posts</h1> 15 15 </PostList>
+6 -1
src/pages/pages/[...index].astro
··· 22 22 const total = Math.ceil((await getBlogPosts()).length / POSTS_PER_PAGE); 23 23 --- 24 24 25 - <PostList {posts} totalPages={total} currentPage={index}> 25 + <PostList 26 + {posts} 27 + totalPages={total} 28 + currentPage={index} 29 + showFeatured={index === 1} 30 + > 26 31 <h1>All blog posts</h1> 27 32 </PostList>
+3 -11
src/pages/posts/[...slug].astro
··· 9 9 import { BASE } from "../../config.json"; 10 10 import { getBlogPosts } from "src/utils"; 11 11 import BlueskyLikes from "$components/bluesky/BlueskyLikes.astro"; 12 + import Tag from "$components/Tag.astro"; 12 13 13 14 export async function getStaticPaths() { 14 15 const posts = await getBlogPosts(); ··· 41 42 <Image 42 43 src={images[replacedHero]()} 43 44 alt="" 44 - class="w-full h-80 object-cover rounded-xl shadow" 45 + class="w-full h-80 object-cover rounded-xl shadow border border-base-400 dark:border-base-700" 45 46 /> 46 47 ) : null 47 48 } ··· 49 50 <div class="flex mt-8 items-center gap-x-4 text-xs"> 50 51 <FormattedDate date={post.data.pubDate} /> 51 52 <div class="flex gap-x-2"> 52 - { 53 - post.data.tags?.map((tag: string) => ( 54 - <a 55 - href={BASE + "/tags/" + tag} 56 - class="relative z-10 rounded-full bg-base-100 px-3 py-1.5 font-medium text-base-700 hover:bg-base-200 dark:bg-base-800 dark:hover:bg-base-700 dark:text-base-300 border border-base-200 dark:border-base-700" 57 - > 58 - {tag} 59 - </a> 60 - )) 61 - } 53 + {post.data.tags?.map((tag: string) => <Tag {tag} />)} 62 54 </div> 63 55 </div> 64 56
+1
todo.md
··· 1 + - allow custom icons for favicons and header