add multiple news items on homepage and single news item page
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Miniapple8888 2022-01-25 12:42:45 -05:00
parent 84144c10ab
commit 417ad32fba
7 changed files with 246 additions and 11 deletions

View File

@ -0,0 +1,57 @@
.card {
padding: calc(30rem / 16) calc(40rem / 16);
max-width: calc(524rem / 16);
background-color: var(--primary-background);
border-radius: calc(20rem / 16);
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
margin-bottom: 1rem;
}
.fit.card {
max-width: unset;
padding: unset;
border-radius: unset;
}
.date {
font-size: calc(18rem / 16);
margin: 0;
}
.author {
color: var(--secondary-heading);
font-style: normal;
}
.content {
overflow: hidden;
}
.content > *:first-child {
margin-top: 0;
}
@media only screen and (max-width: calc(768rem / 16)) {
.card {
padding: 0;
max-width: unset;
background-color: transparent;
border-radius: 0;
}
.date {
font-weight: 600;
}
.content > *:first-child {
margin-top: 1rem;
}
.content ul,
.content ol {
padding: 0 1rem;
}
}

View File

@ -0,0 +1,42 @@
import React, { ReactNode } from "react";
import { Link } from "./Link";
import styles from "./MiniNewsCard.module.css";
interface MiniNewsCardProps {
date: Date;
author: string;
children: ReactNode;
permalink: string;
fit?: boolean;
}
export const MiniNewsCard: React.FC<MiniNewsCardProps> = ({
date,
author,
children,
permalink,
fit = false,
}) => {
const classes = fit ? [styles.card, styles.fit] : [styles.card];
return (
<article className={classes.join(" ")}>
<h1 className={styles.date}>
<time dateTime={date.toISOString()}>
{date.toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
})}
</time>
</h1>
<address className={styles.author}>{author}</address>
<div className={styles.content}>{children}</div>
<Link href={permalink}>
<span className={styles.mobileLearnMore}>Learn more</span>
</Link>
</article>
);
};

View File

@ -3,6 +3,7 @@
max-width: calc(524rem / 16);
background-color: var(--primary-background);
border-radius: calc(20rem / 16);
margin-bottom: 1rem;
}
.fit.card {
@ -30,6 +31,7 @@
padding: 0;
max-width: unset;
background-color: transparent;
border-radius: 0;
}
.date {

View File

@ -15,6 +15,7 @@ export const NEWS_PATH = path.join("content", "news");
export interface Metadata {
author: string;
date: string;
permalink: string;
}
export interface News {
@ -40,6 +41,15 @@ export async function getNewsTermsByYear(year: string): Promise<Term[]> {
.sort((a, b) => TERMS.indexOf(a) - TERMS.indexOf(b));
}
export async function getNewsDateByTerm(
year: string,
term: Term
): Promise<string[]> {
return (await getNewsByTerm(year, term)).map(
(news) => news.split("-").slice(0, 3).join("-") // retrieves date from filename
);
}
export async function getNewsByTerm(
year: string,
term: Term
@ -63,6 +73,7 @@ export async function getNewsBySlug(
"utf-8"
);
const { content, data: metadata } = matter(raw);
const slugDate = slug.split("-").slice(0, 3).join("-");
return {
content: await serialize(content),
@ -71,6 +82,7 @@ export async function getNewsBySlug(
date: getLocalDateFromEST(
parse(metadata.date, DATE_FORMAT, new Date())
).toString(),
permalink: `/news/${year}/${term}/${slugDate}`,
} as Metadata,
};
}

View File

@ -8,7 +8,7 @@ import { EmailSignup } from "@/components/EmailSignup";
import { EventDescriptionCard } from "@/components/EventDescriptionCard";
import { Image } from "@/components/Image";
import { Link } from "@/components/Link";
import { NewsCard } from "@/components/NewsCard";
import { MiniNewsCard } from "@/components/MiniNewsCard";
import { GetShapesConfig } from "@/components/ShapesBackground";
import { SocialLinks } from "@/components/SocialLinks";
import { Title } from "@/components/Title";
@ -20,7 +20,7 @@ import styles from "./index.module.css";
interface Props {
moreEvents: boolean; // true if there are more than 2 upcoming events
events: Event[]; // array of 0 - 2 events
news: News;
news: News[]; // array of 3 news items
}
export default function Home(props: Props) {
@ -86,14 +86,17 @@ export default function Home(props: Props) {
See past news <Link href="/news/archive">here</Link>
</p>
<hr className={styles.cardsDividingLine} />
{
<NewsCard
{...props.news.metadata}
date={new Date(props.news.metadata.date)}
>
<MDXRemote {...props.news.content} />
</NewsCard>
}
{props.news.length > 0
? props.news.map((news) => (
<MiniNewsCard
{...news.metadata}
date={new Date(news.metadata.date)}
key={news.metadata.date.toString()}
>
<MDXRemote {...news.content} />
</MiniNewsCard>
))
: null}
</section>
</div>
</div>
@ -116,7 +119,7 @@ export const getStaticProps: GetStaticProps<Props> = async () => {
props: {
moreEvents: upcomingEvents.length > 2,
events: upcomingEvents.slice(0, 2),
news: recentNews[0],
news: recentNews.slice(0, 3),
},
};
};

View File

@ -0,0 +1,8 @@
.page {
padding-bottom: calc(30rem / 16);
}
.page > h1 {
padding-bottom: calc(16rem / 16);
border-bottom: calc(1rem / 16) solid var(--primary-heading);
}

View File

@ -0,0 +1,111 @@
import { ParsedUrlQuery } from "querystring";
import { GetStaticPaths, GetStaticProps } from "next";
import { MDXRemote } from "next-mdx-remote";
import React from "react";
import { NewsCard } from "@/components/NewsCard";
import {
ShapesConfig,
defaultGetShapesConfig,
GetShapesConfig,
} from "@/components/ShapesBackground";
import { Title } from "@/components/Title";
import {
getNewsBySlug,
getNewsByTerm,
getNewsTermsByYear,
getNewsDateByTerm,
getNewsYears,
News,
} from "@/lib/news";
import { Term } from "@/utils";
import styles from "./[date].module.css";
interface Props {
year: string;
term: Term;
news: News[];
}
export default function DateNews({ news }: Props) {
const date = new Date(news[0].metadata.date).toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
});
return (
<div className={styles.page}>
<Title>{["News", `${date}`]}</Title>
<h1>
News: <span>{date}</span>
</h1>
{news.map(({ content, metadata }, idx) => (
<NewsCard
key={idx}
{...metadata}
date={new Date(metadata.date)}
fit={true}
>
<MDXRemote {...content} />
</NewsCard>
))}
</div>
);
}
DateNews.getShapesConfig = ((width, height) => {
return window.innerWidth <= 768
? ({} as ShapesConfig)
: defaultGetShapesConfig(width, height);
}) as GetShapesConfig;
export const getStaticProps: GetStaticProps<Props, Params> = async (
context
) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const { year, term, date } = context.params!;
const slugs = (await getNewsByTerm(year, term)).filter((slug) =>
slug.includes(date)
);
const news = await Promise.all(
slugs.map((slug) => getNewsBySlug(year, term, slug))
);
console.log(slugs);
// Reverse so that we are displaying the most recent news
// of term first
return { props: { year, term, news: news.reverse() } };
};
interface Params extends ParsedUrlQuery {
year: string;
term: Term;
date: string;
}
export const getStaticPaths: GetStaticPaths<Params> = async () => {
const years = await getNewsYears();
const terms = await Promise.all(
years.map(async (year) => {
const termsInYear = await getNewsTermsByYear(year);
return termsInYear.map((term) => ({ year, term }));
})
);
const dates = await Promise.all(
terms.map(async (termInYear) => {
const datesInTerm: Params[] = [];
for (const { year, term } of termInYear) {
const dates = await getNewsDateByTerm(year, term);
dates.map((date) => datesInTerm.push({ year, term, date }));
}
return datesInTerm.flat();
})
);
return {
paths: dates.flat().map((params) => ({ params })),
fallback: false,
};
};