Skip to content

Commit

Permalink
add hero image and author + enhance style
Browse files Browse the repository at this point in the history
  • Loading branch information
hamidra committed Jul 18, 2024
1 parent 6de8827 commit f32800c
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 32 deletions.
2 changes: 1 addition & 1 deletion next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const nextConfig = {
remotePatterns: [
{
protocol: 'https',
hostname: 'placehold.co',
hostname: '**',
port: '',
pathname: '**',
},
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"format": "prettier --write ."
},
"dependencies": {
"@pondorasti/remark-img-links": "^1.0.8",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-icons": "^1.3.0",
Expand Down
25 changes: 25 additions & 0 deletions pnpm-lock.yaml

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

18 changes: 18 additions & 0 deletions src/app/blog/[slug]/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use client'
import { Button } from '@/components/ui/button'
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
return (
<div className="flex items-center justify-center p-48">
<div className="prose m-auto flex flex-col justify-center lg:prose-lg">
<h2>Something went wrong!</h2>
<Button onClick={() => reset()}>Try again</Button>
</div>
</div>
)
}
45 changes: 38 additions & 7 deletions src/app/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,62 @@
// pages/blog/[slug].js

import Image from 'next/image'
import { siteConfig } from '@/config/site'
import ReactMarkdown from 'react-markdown'
import remarkGFM from 'remark-gfm'
import remarkMath from 'remark-math'
import rehypeKatex from 'rehype-katex'
import { getPostBySlug, getPostsMeta } from '@/lib/posts'
import imgLink from '@pondorasti/remark-img-links'
import { getPostBySlug, getPostsMeta, resolveImage } from '@/lib/posts'
import 'katex/dist/katex.min.css'
import { formatDate } from '@/lib/utils'

export default async function BlogTemplate({ params }) {
let imageBase = siteConfig.links.post_images
let { slug } = params
let { frontmatter, markdownBody } = await getPostBySlug(slug)

let post = await getPostBySlug(slug)
if (!post) throw new Error('No post was found!')

let { frontmatter, markdownBody } = post
let { hero_image, title, author, date } = frontmatter
let resolved_hero_image = await resolveImage(hero_image)
return (
<div>
<article className="prose m-auto lg:prose-xl">
<div className="p-4">
<article className="prose m-auto lg:prose-lg">
<div>
<h1>{frontmatter.title}</h1>
<div className="my-4 text-4xl font-semibold lg:my-8 lg:text-6xl">
{title}
</div>
<div className="flex flex-col">
<div className="text-sm font-semibold lg:text-base">
By: {author}
</div>
<div className="text-xs font-thin text-muted-foreground lg:text-sm">
{formatDate(date)}
</div>
</div>
</div>
<div className="relative my-5 h-96 w-full">
<Image
src={resolved_hero_image}
fill
alt={`${title} hero image`}
className="!m-0 rounded-lg object-cover shadow-md"
/>
</div>
<div>
<ReactMarkdown
remarkPlugins={[remarkGFM, remarkMath]}
remarkPlugins={[
remarkGFM,
remarkMath,
[imgLink, { absolutePath: imageBase }],
]}
rehypePlugins={[rehypeKatex]}
>
{markdownBody}
</ReactMarkdown>
</div>
<h2>Written By: {frontmatter.author}</h2>
</article>
</div>
)
Expand Down
9 changes: 2 additions & 7 deletions src/app/blog/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import { getPostsMeta } from '@/lib/posts'
import PostCard from '@/components/post-card'
export default async function PostsList() {
let postsMeta = await getPostsMeta()
let postsMeta = await getPostsMeta().catch((err) => console.error(err))
return (
<div className="flex flex-row flex-wrap justify-center gap-8 p-2 md:p-16">
{postsMeta.map((meta, id) => (
{postsMeta?.map((meta, id) => (
<>
<PostCard key={id} meta={meta} />
<PostCard key={id} meta={meta} />
<PostCard key={id} meta={meta} />
<PostCard key={id} meta={meta} />
<PostCard key={id} meta={meta} />
<PostCard key={id} meta={meta} />
</>
))}
</div>
Expand Down
8 changes: 4 additions & 4 deletions src/components/post-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import Link from 'next/link'
import { Card, CardHeader, CardContent, CardTitle } from './ui/card'
import Image from 'next/image'
import { cn } from '@/lib/utils'
import { resolveImage } from '@/lib/posts'

export default function PostCard({ meta }) {
export default async function PostCard({ meta }) {
let { author, slug, title, description, hero_image } = meta
hero_image = await resolveImage(hero_image)
return (
<>
<Link href={`/blog/${slug}`}>
Expand All @@ -20,9 +22,7 @@ export default function PostCard({ meta }) {
<div className="gap-2">
<div className="text-xl font-semibold">{title}</div>
<div className="text-l font-light text-muted-foreground">
{
'Warning: Each child in a list should have a unique "key" prop.Warning: Each child in a list should have a unique "key" prop.Warning: Each child in a list should have a unique "key" prop'
}
{description}
</div>
<div className="flex flex-row justify-between text-sm">{`by ${author}`}</div>
</div>
Expand Down
2 changes: 2 additions & 0 deletions src/config/site.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export const siteConfig = {
twitter: 'https://twitter.com/tessernet',
github: 'https://github.com/tesser-labs',
posts: 'https://api.github.com/repos/tesser-labs/blog/contents/posts/',
post_images:
'https://raw.githubusercontent.com/tesser-labs/blog/main/posts/',
},
}

Expand Down
38 changes: 25 additions & 13 deletions src/lib/posts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,48 @@ import matter from 'gray-matter'
import { siteConfig } from '@/config/site'

export async function getPost(path: string) {
const res = await fetch(path)
const post = await res.text()
const post = await fetch(path).then((res) => res.text())
const data = matter(post)

return {
frontmatter: data.data,
markdownBody: data.content,
frontmatter: data?.data,
markdownBody: data?.content,
excerpt: data?.excerpt,
}
}

export async function getPostBySlug(slug: string) {
let base = siteConfig.links.posts
let url = base && slug && new URL(`${slug}.md`, base).href
let res = await (await fetch(url)).json()
let downloadUrl = res.download_url
return getPost(downloadUrl)
let res = url && (await fetch(url).then((res) => res.json()))
let downloadUrl = res?.download_url
return downloadUrl && getPost(downloadUrl)
}

export async function resolveImage(path: string) {
let base = siteConfig.links.post_images
try {
// check of path is absolute or empty
let url = path && new URL(`${path}`).href
return url
} catch {
// if path is relatice resolve it against the base url
let url = path && new URL(`${path}`, base).href
return url
}
}

export async function getPostsUrls(path: string = siteConfig.links.posts) {
const res = await fetch(path)
const posts: Array<{ download_url: string }> = await res.json()
const postUrls = posts
.map((post) => post.download_url)
.filter((post_url) => post_url)
const posts = await fetch(path).then((res) => res.json())
const postUrls =
posts?.map((post) => post.download_url)?.filter((post_url) => post_url) ||
[]
return postUrls
}

export async function getPostsMeta(path: string = siteConfig.links.posts) {
let urls = await getPostsUrls(path)
const pendingMeta = urls.map((url) => getPost(url))
const pendingMeta = urls?.map((url) => getPost(url)) || []
const meta = (await Promise.all(pendingMeta)).map((data) => data.frontmatter)
return meta
}
4 changes: 4 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}

export function formatDate(date: Date) {
return `${date.toDateString().split(' ').slice(1).join(' ')}`
}

0 comments on commit f32800c

Please sign in to comment.