-
Notifications
You must be signed in to change notification settings - Fork 48
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
Port /blog
to App router; add blog preview cards [#134]
#1059
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import { Metadata } from "next"; | ||
import { redirect } from "next/navigation"; | ||
import React from "react"; | ||
|
||
import { BigSpacer } from "../../../components/spacers"; | ||
import { | ||
siteLogo, | ||
siteTitle, | ||
siteTitleAlt, | ||
siteUrl, | ||
} from "../../../data/BaseConfig"; | ||
|
||
import { getBlogPosts, markdownToHtml } from "../utils"; | ||
|
||
import styles from "./styles.module.css"; | ||
|
||
// just to avoid having to repeat this in a couple method sigs... | ||
interface BlogPostParams { | ||
id: string; | ||
} | ||
|
||
// return a list of params that will get handed to this page at build | ||
// time, to statically build out all the blog posts | ||
export function generateStaticParams(): BlogPostParams[] { | ||
return getBlogPosts().map((post) => { | ||
return { id: post.blogUrlName }; | ||
}); | ||
} | ||
|
||
// generate opengraph and other metadata tags | ||
export async function generateMetadata({ | ||
params, | ||
}: { | ||
params: BlogPostParams; | ||
}): Promise<Metadata> { | ||
const { id } = params; | ||
|
||
// set up some defaults that are independent of the specific blog post | ||
const baseUrl = new URL(siteUrl); | ||
const metadata: Metadata = { | ||
metadataBase: baseUrl, | ||
openGraph: { | ||
description: siteTitleAlt, | ||
images: [ | ||
{ | ||
url: `${siteUrl}${siteLogo}`, | ||
}, | ||
], | ||
siteName: siteTitle, | ||
title: siteTitle, | ||
type: "website", | ||
url: baseUrl, | ||
}, | ||
}; | ||
|
||
// this is the specific post we're rendering | ||
const blogPost = getBlogPosts().find((post) => post.blogUrlName === id); | ||
|
||
if (blogPost) { | ||
const description = `Nextstrain blog post from ${blogPost.date}; author(s): ${blogPost.author}`; | ||
|
||
metadata.title = blogPost.title; | ||
metadata.description = description; | ||
metadata.openGraph!.description = description; | ||
metadata.openGraph!.title = `${siteTitle}: ${blogPost.title}`; | ||
metadata.openGraph!.url = `/blog/${blogPost.blogUrlName}`; | ||
} | ||
|
||
return metadata; | ||
genehack marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
export default async function BlogPost({ | ||
params, | ||
}: { | ||
params: BlogPostParams; | ||
}): Promise<React.ReactElement> { | ||
const { id } = params; | ||
|
||
// we need this list to build the archive list in the sidebar | ||
const allBlogPosts = getBlogPosts(); | ||
|
||
// and then this is the specific post we're rendering | ||
const blogPost = allBlogPosts.find((post) => post.blogUrlName === id); | ||
|
||
// if for some reason we didn't find the post, 404 on out | ||
if (!blogPost) { | ||
redirect("/404"); | ||
} | ||
|
||
const html = await markdownToHtml(blogPost.mdstring); | ||
|
||
return ( | ||
<> | ||
<BigSpacer count={2} /> | ||
|
||
<article className="container"> | ||
<div className="row"> | ||
<div className="col-lg-8"> | ||
<time className={styles.blogPostDate} dateTime={blogPost.date}> | ||
{blogPost.date} | ||
</time> | ||
<h1 className={styles.blogPostTitle}>{blogPost.title}</h1> | ||
<h2 className={styles.blogPostAuthor}>{blogPost.author}</h2> | ||
<div | ||
className={styles.blogPostBody} | ||
dangerouslySetInnerHTML={{ | ||
__html: html, | ||
}} | ||
/> | ||
</div> | ||
<div className="col-lg-1" /> | ||
<div className={`${styles.blogSidebar} col-lg-3`}> | ||
<h2>Blog Archives</h2> | ||
<ul> | ||
{allBlogPosts.map((p) => ( | ||
<li key={p.blogUrlName}> | ||
<a href={p.blogUrlName}>{p.sidebarTitle}</a> ({p.date}) | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
</div> | ||
</article> | ||
</> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
.blogPostTitle { | ||
clear: both; /* this is to let the title fall under the floated date, not under it */ | ||
color: black; | ||
font-size: 3.5rem; | ||
font-weight: 400; | ||
line-height: 40px; | ||
text-align: left; | ||
width: 100%; | ||
} | ||
|
||
.blogPostAuthor { | ||
color: black; | ||
font-size: 2rem; | ||
font-weight: 300; | ||
margin: 1rem 0 2rem; | ||
} | ||
|
||
.blogPostDate { | ||
color: black; | ||
float: right; | ||
font-size: 1.4rem; | ||
font-weight: 300; | ||
min-height: 2rem; | ||
} | ||
|
||
.blogPostBody { | ||
color: black; | ||
font-size: 1.6rem; | ||
font-weight: 300; | ||
line-height: var(--niceLineHeight); | ||
margin-top: 0px; | ||
padding-bottom: 25px; | ||
width: 100%; | ||
} | ||
|
||
.blogPostBody img { | ||
max-width: 100%; | ||
} | ||
|
||
.blogPostBody h1 { | ||
color: black; | ||
font-size: 3rem; | ||
margin-top: 20px; | ||
text-align: left; | ||
} | ||
.blogPostBody h2 { | ||
font-size: 2.4rem; | ||
font-weight: 300; | ||
margin-top: 10px; | ||
} | ||
.blogPostBody h3 { | ||
font-size: 1.8rem; | ||
font-weight: 300; | ||
margin-top: 10px; | ||
} | ||
.blogPostBody p { | ||
margin-top: 10px; | ||
} | ||
.blogPostBody li { | ||
margin-left: 3rem; | ||
} | ||
|
||
.blogSidebar { | ||
font-size: 14px; | ||
} | ||
.blogSidebar ul { | ||
list-style: none; | ||
} | ||
.blogSidebar ul li { | ||
margin: 1.2rem 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { redirect } from "next/navigation"; | ||
|
||
import { getBlogPosts } from "./utils"; | ||
|
||
export default function Index(): void { | ||
const mostRecentPost = getBlogPosts()[0]; | ||
|
||
// _technically_ getBlogPosts() could return an empty array and then | ||
// mostRecentPost would be undefined -- to make the type checker | ||
// happy, if for some reason mostRecentPost is undefined, we will | ||
// detect that and redirect to the 404 page | ||
const redirectTo = mostRecentPost | ||
? `/blog/${mostRecentPost.blogUrlName}` | ||
: `/404`; | ||
|
||
redirect(redirectTo); | ||
Comment on lines
+12
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The images of the most recent blog fail to load when going to /blog, but load fine at /blog/2024-10-22-oropouche-analysis-and-resources There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, i see that. seems to be because the image URLs are relative to oddly, it works fine on localhost... I will dig into the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, yeah, this is because of how the I think I'm going to take this as the push from the universe to move ahead with converting the front page to be the five most recent blog posts, which will require some additional refactoring in this PR. |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit
What an upgrade! I'm sure there was a reason for this but it's hard to tell from the commit message. Was there a function that wasn't available in the older version?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The primary reason was I needed to update it off 0.7 to get typing support, and so I figured I might as well update it to "current".
FWIW, 0.7 is "only" five years old — the package versions fairly aggressively, for whatever reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since I need to rework other stuff in this PR, I have gone back and updated the commit message to include this information.