Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add post's read time #8

Merged
merged 3 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion astro.config.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineConfig } from 'astro/config';
import tailwind from "@astrojs/tailwind";
import mdx from "@astrojs/mdx";
import getReadTime from './src/scripts/reading_time';

import vercel from "@astrojs/vercel/serverless";

Expand All @@ -15,5 +16,8 @@ export default defineConfig({
speedInsights: {
enabled: true
}
})
}),
markdown: {
remarkPlugins: [getReadTime]
}
});
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"astro": "^4.0.2",
"astro-icon": "^0.8.2",
"js-sha256": "^0.10.1",
"mdast-util-to-string": "^4.0.0",
"reading-time": "^1.5.0",
"tailwindcss": "^3.3.5",
"typescript": "^5.2.2"
},
Expand Down
7 changes: 6 additions & 1 deletion src/components/PostCard.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import { type CollectionEntry, getEntry } from "astro:content";
import type { AuthorProfile, PostData } from "../scripts/types/post_types";
import PostTypeTag from "./PostTypeBadge.astro";
import { renderPostContent } from "../scripts/content_render";
import PostInfo from "./PostInfo.astro";

interface Props {
post: CollectionEntry<"posts">;
Expand All @@ -11,6 +13,9 @@ const { post } = Astro.props;
const data: PostData = post.data;
const authorEntry = await getEntry("authors", data.author.id);
const author: AuthorProfile = authorEntry.data;
const postContent = await renderPostContent(post)
const { renderPostData } = postContent
const { remarkPluginFrontmatter: remark } = renderPostData

const formatedDate = data.date.toLocaleDateString("pt-br");
---
Expand All @@ -29,7 +34,7 @@ const formatedDate = data.date.toLocaleDateString("pt-br");
<PostTypeTag text={data.postType} />
</span>
</span>
<small>{author.name} ● {formatedDate}</small>
<PostInfo author={author} date={formatedDate} minutesRead={remark.minutesRead} />
<div>
<p class="text-ellipsis overflow-hidden">
{data.description}
Expand Down
20 changes: 20 additions & 0 deletions src/components/PostInfo.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
import type { AuthorProfile } from '../scripts/types/post_types'
import ReadTime from './ReadTime.astro'

interface Props {
author: AuthorProfile
date: string
minutesRead: string
}

const { author, date, minutesRead } = Astro.props
---

<small class="flex flex-row items-center align-middle gap-1">
<span>by {author.name}</span>
<span>●</span>
<span>{date}</span>
<span>●</span>
<ReadTime readTime={minutesRead} />
</small>
17 changes: 17 additions & 0 deletions src/components/ReadTime.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
import Icon from 'astro-icon';

interface Props {
readTime: string
}

const { readTime } = Astro.props

---

<div class="flex flex-row items-center">
<Icon name="time" width="16" height="16"/>
<p class="ml-1">
{readTime}
</p>
</div>
1 change: 1 addition & 0 deletions src/icons/time.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 6 additions & 3 deletions src/layouts/PostLayout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ import PostSideBarLeft from "../components/PostSideBarLeft.astro";
import TagsViewer from "../components/TagsViewer.astro";
import PostTypeTag from "../components/PostTypeBadge.astro";
import PostImageHero from "../components/PostImageHero.astro";
import { imageConfig } from "astro:assets";
import PostInfo from "../components/PostInfo.astro";
import type { RemarkFrontmatter } from "../scripts/types/render_post_data";

interface Props {
id: string;
post: PostData;
remark: RemarkFrontmatter;
author: AuthorProfile;
}

const { post, author } = Astro.props;
const { post, remark, author } = Astro.props;
const { id, title, date, tags, postType, description, image } = post;
const { minutesRead } = remark;
const formatedDate = date.toLocaleDateString("pt-br");
---

Expand All @@ -32,7 +35,7 @@ const formatedDate = date.toLocaleDateString("pt-br");
<PostTypeTag text={postType} />
</span>
</div>
<small>by {author.name} ● {formatedDate}</small>
<PostInfo author={author} date={formatedDate} minutesRead={minutesRead} />
</div>
<TagsViewer tags={tags} />
</header>
Expand Down
11 changes: 9 additions & 2 deletions src/pages/post/[slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
import PostLayout from "../../layouts/PostLayout.astro";
import { type CollectionEntry, getEntry } from "astro:content"
import type { AuthorProfile, PostData } from "../../scripts/types/post_types";
import type { RenderablePostData, RenderPostData } from "../../scripts/types/render_post_data"
import { getPosts } from "../../scripts/content_fetcher";
import { renderPostContent } from "../../scripts/content_render";

export async function getStaticPaths() {
const postCollection = await getPosts();
Expand All @@ -22,11 +24,16 @@ interface Props {

const { post } = Astro.props
const data: PostData = post.data

const authorEntry = await getEntry("authors", data.author.id)
const author: AuthorProfile = authorEntry.data
const { Content } = await post.render()
const postContent = await renderPostContent(post)
const { renderablePost, renderPostData } = postContent

const { Content } = renderablePost
const { remarkPluginFrontmatter: remark } = renderPostData
---

<PostLayout id={post.id} post={data} author={author}>
<PostLayout id={post.id} post={data} remark={remark} author={author}>
<Content/>
</PostLayout>
21 changes: 21 additions & 0 deletions src/scripts/content_render.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { CollectionEntry } from "astro:content";
import type { RenderablePostData, RenderPostData } from "./types/render_post_data";

type PostRender = {
renderablePost: RenderablePostData
renderPostData: RenderPostData
}

export async function renderPostContent(post: CollectionEntry<'posts'>): Promise<PostRender> {
const renderableData: RenderablePostData = await post.render()
const renderData: RenderPostData = {
headings: renderableData.headings,
remarkPluginFrontmatter: {
minutesRead: renderableData.remarkPluginFrontmatter.minutesRead
}
}
return {
renderablePost: renderableData,
renderPostData: renderData
}
}
11 changes: 11 additions & 0 deletions src/scripts/reading_time.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import getReadingTime from 'reading-time';
import { toString } from 'mdast-util-to-string';

export default function getReadTime() {
return function (tree: unknown, { data }: any) {
const textOnPage = toString(tree);
const readingTime = getReadingTime(textOnPage);

data.astro.frontmatter.minutesRead = readingTime.text;
};
}
17 changes: 17 additions & 0 deletions src/scripts/types/render_post_data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { MarkdownHeading } from "astro";
import type { AstroComponentFactory } from "astro/runtime/server/index.js";

export interface RemarkFrontmatter {
minutesRead: string
}

export interface RenderablePostData {
Content: AstroComponentFactory;
headings: MarkdownHeading[];
remarkPluginFrontmatter: Record<string, any>;
}

export interface RenderPostData {
headings: MarkdownHeading[];
remarkPluginFrontmatter: RemarkFrontmatter;
}