diff --git a/web/e.cash/pages/blog/[slug].js b/web/e.cash/pages/blog/[slug].js new file mode 100644 --- /dev/null +++ b/web/e.cash/pages/blog/[slug].js @@ -0,0 +1,135 @@ +// Copyright (c) 2023 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +import Layout from '/components/layout'; +import Image from 'next/image'; +import H3 from '/components/h3'; +import { Container } from '/components/atoms'; +import { getBlogPosts } from '/data/blog'; +import { + PostCtn, + MainPostImage, + DateText, + NextPostCtn, + Card, + Tag, + CardImage, + TextCtn, + PostBorder, +} from '/styles/pages/blog.js'; +import { formatTimestamp } from '/data/blog.js'; + +const STRAPI_URL = 'https://strapi.fabien.cash'; + +function BlogPost({ post, keepReadingPosts }) { + return ( + + + + + {formatTimestamp( + post.attributes.publish_date + ? post.attributes.publish_date + : post.attributes.publishedAt, + )} + +

+ + + {post.attributes.title} + + +
+ +

+ + {keepReadingPosts.map((post, index) => ( + <> + {post ? ( + + {post.attributes.type} + + {post.attributes.title} + + + + {formatTimestamp( + post.attributes.publish_date + ? post.attributes + .publish_date + : post.attributes + .publishedAt, + )} + +

{post.attributes.title}

+
+
+ ) : null} + + ))} +
+ + + + ); +} + +/** + * Get all blog paths + * This only runs at build time, and the build should fail if the api call fails + * @returns {object} paths - an object with all of the post slugs + */ +export async function getStaticPaths() { + const posts = await getBlogPosts(); + const paths = posts.props.posts.map(item => ({ + params: { slug: item.attributes.slug }, + })); + + return { paths, fallback: false }; +} + +/** + * Get the staticProps for a given slug + * Uses the params object from getStaticPaths to determine the slug for the page + * Gets the data for next and previous posts + * This only runs at build time, and the build should fail if the api call fails + * @returns {object} props - an object with api data for the posts + */ +export async function getStaticProps({ params }) { + const posts = await getBlogPosts(); + const post = + posts.props.posts.find(obj => obj.attributes['slug'] === params.slug) || + null; + const nextPost = + posts.props.posts.find(obj => obj.id === post.id + 1) || null; + const previousPost = + posts.props.posts.find(obj => obj.id === post.id - 1) || null; + const keepReadingPosts = [nextPost, previousPost]; + + return { + props: { + post, + keepReadingPosts, + }, + }; +} + +export default BlogPost; diff --git a/web/e.cash/styles/pages/blog.js b/web/e.cash/styles/pages/blog.js --- a/web/e.cash/styles/pages/blog.js +++ b/web/e.cash/styles/pages/blog.js @@ -171,3 +171,40 @@ font-size: 12px; } `; + +export const PostCtn = styled.div` + padding: 150px 0; +`; + +export const PostBorder = styled.div` + padding: 30px; + border: 1px solid ${props => props.theme.colors.primaryLight}; + box-shadow: 0px 0px 22px 1px ${props => props.theme.colors.primaryLight}68; + margin-bottom: 50px; + + img { + width: 100%; + } +`; + +export const MainPostImage = styled.div` + width: 100%; + padding-bottom: 56.25%; + position: relative; + margin: 30px 0; + img { + object-fit: contain; + } +`; + +export const NextPostCtn = styled.div` + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-template-rows: repeat(1, 1fr); + grid-column-gap: 15px; + grid-row-gap: 15px; + margin-top: 15px; + ${props => props.theme.breakpoint.small} { + grid-template-columns: repeat(1, 1fr); + } +`;