Skip to content

Commit

Permalink
Add/blog (#8)
Browse files Browse the repository at this point in the history
* Update to use slugs instead of query params

* Some cleanup

* Spinning up blog core

* Updating the Blog home

* Working on layout

* Adding post preview

* Building new design

* Updating more of the design

* Typescript incident

* Some cleanup

* Blog stuff

* Adding summary

* Adding subtitle

* Blog

* Adding some Footer

* Some cleanup

* Update thumb

* Some cleanup

* Some cleanup

* Fixing some bugs

* Blog CTA more responsive

* Update hop-on-our-soapbox.md

* Update hop-on-our-soapbox.md

* Update hop-on-our-soapbox.md

Co-authored-by: Dean Eigenmann <[email protected]>
  • Loading branch information
mirshko and decanus authored Feb 1, 2021
1 parent 2d98667 commit de72904
Show file tree
Hide file tree
Showing 28 changed files with 1,630 additions and 444 deletions.
15 changes: 15 additions & 0 deletions components/app-store-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { APP_STORE_URL } from "../constants";
import Apple from "../icons/apple";

export default function AppStoreButton() {
return (
<a
className="py-4 px-6 bg-brand text-white rounded-full inline-flex justify-center items-center space-x-3 focus:outline-none focus:ring-4"
href={APP_STORE_URL}
aria-label="Download on the App Store"
>
<Apple size={32} className="-mt-0.5" />
<span className="text-2xl font-medium">App Store</span>
</a>
);
}
46 changes: 18 additions & 28 deletions components/footer.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,38 @@
import Link from "next/link";
import { MEDIA_KIT_URL, TWITTER_URL } from "../constants";

export default function Footer() {
return (
<footer className="max-w-2xl mx-auto w-full p-6 pb-12">
<ul className="flex flex-wrap justify-center -mr-4 -mb-2 text-sm ">
<li className="mr-4 mb-2">
<a
className="text-black opacity-25 focus:outline-none focus:opacity-75 hover:opacity-75"
href="https://twitter.com/intent/user?screen_name=joinsoapbox"
>
<footer className="text-sm text-black px-5 pb-5">
<ul className="w-full flex flex-wrap justify-center -mr-4 -mb-2">
<li className="footer-item">
<a className="footer-item-link" href={TWITTER_URL}>
Twitter
</a>
</li>

<li className="mr-4 mb-2">
<a
className="text-black opacity-25 focus:outline-none focus:opacity-75 hover:opacity-75"
href="https://www.notion.so/Media-Kit-f122893891b84cb5a19a8744b770f847"
>
<li className="footer-item">
<a className="footer-item-link" href={MEDIA_KIT_URL}>
Media Kit
</a>
</li>

<li className="mr-4 mb-2">
<li className="footer-item">
<Link href="/blog">
<a className="footer-item-link">Blog</a>
</Link>
</li>
<li className="footer-item">
<Link href="/support">
<a className="text-black opacity-25 focus:outline-none focus:opacity-75 hover:opacity-75">
Support
</a>
<a className="footer-item-link">Support</a>
</Link>
</li>

<li className="mr-4 mb-2">
<li className="footer-item">
<Link href="/privacy">
<a className="text-black opacity-25 focus:outline-none focus:opacity-75 hover:opacity-75">
Privacy
</a>
<a className="footer-item-link">Privacy</a>
</Link>
</li>

<li className="mr-4 mb-2">
<li className="footer-item">
<Link href="/terms">
<a className="text-black opacity-25 focus:outline-none focus:opacity-75 hover:opacity-75">
Terms
</a>
<a className="footer-item-link">Terms</a>
</Link>
</li>
</ul>
Expand Down
10 changes: 5 additions & 5 deletions components/navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import Link from "next/link";
import { useRouter } from "next/router";

export default function Navigation() {
const router = useRouter();
const { pathname } = useRouter();

const isNavigable = !router.pathname.includes("/report");
const isNavigable = !pathname.includes("/report");

const isHome = router.pathname === "/";
const isHome = pathname === "/";

const icon = (
<img
className="brand-mark"
className="soapbox-mark"
src="/brand.png"
alt="Soapbox"
loading="eager"
Expand All @@ -20,7 +20,7 @@ export default function Navigation() {
if (isHome) return null;

return (
<header className="mt-8">
<header className="mt-5">
<nav className="flex justify-center">
{isNavigable ? (
<Link href="/">
Expand Down
26 changes: 26 additions & 0 deletions components/post-preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Image from "next/image";

export default function PostPreview({ title, date, authors }) {
return (
<div className="room">
<div className="room-title">{title}</div>
<div className="flex items-center justify-between">
<div className="flex -space-x-2">
{authors.map((member, i) => (
<div key={i} className="flex room-head overflow-visible">
<Image
height={50}
width={50}
className="room-head object-cover object-center rounded-full"
draggable="false"
src={member.image}
alt={member.displayName}
/>
</div>
))}
</div>
<div className="no-underline room-button">{date}</div>
</div>
</div>
);
}
2 changes: 1 addition & 1 deletion components/room-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default function RoomPreview({
</div>
<a
href={buttonLink}
className="room-button focus:outline-none focus:ring-4"
className="no-underline room-button focus:outline-none focus:ring-4"
>
{buttonText}
</a>
Expand Down
6 changes: 6 additions & 0 deletions constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ export const CONTACT_URL = "mailto:[email protected]";
export const APP_ID = "1529283270";

export const APP_NAME = "Soapbox: Talk with anyone";

export const TWITTER_URL =
"https://twitter.com/intent/user?screen_name=joinsoapbox";

export const MEDIA_KIT_URL =
"https://www.notion.so/Media-Kit-f122893891b84cb5a19a8744b770f847";
15 changes: 15 additions & 0 deletions icons/twitter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export default function Twitter({ size = 24, className = "" }) {
return (
<svg
className={className}
width={size}
height={size}
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
>
<title>{"Twitter"}</title>
<path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z" />
</svg>
);
}
39 changes: 39 additions & 0 deletions lib.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import fs from "fs";
import matter from "gray-matter";
import renderToString from "next-mdx-remote/render-to-string";
import { join } from "path";

const docsDirectory = join(process.cwd(), "posts");

export async function getPostBySlug(slug: string) {
const fullPath = join(docsDirectory, `${slug}.md`);
const fileContents = fs.readFileSync(fullPath, "utf8");

const { data, content } = matter(fileContents);

const source = await renderToString(content);

return {
slug,
meta: data,
source,
};
}

export function getAllPosts() {
const filenames = fs.readdirSync(docsDirectory);

return filenames.map((file) => ({
slug: file.replace(/\.md$/, ""),
}));
}

export async function getAllPostsWithData() {
const posts = getAllPosts();

const postsWithData = await Promise.all(
posts.map(async (post) => await getPostBySlug(post.slug))
);

return postsWithData;
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
"@mdx-js/loader": "^1.6.22",
"@next/mdx": "^10.0.5",
"@octokit/core": "^3.2.4",
"@tailwindcss/typography": "^0.4.0",
"gray-matter": "^4.0.2",
"next": "^10.0.5",
"next-mdx-remote": "^2.1.3",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-hook-form": "^6.14.1",
Expand Down
8 changes: 6 additions & 2 deletions pages/404.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ import Meta from "../components/meta";

export default function Custom404Page() {
return (
<main className="main">
<main className="p-5">
<Meta title="404: This page could not be found" />

<h1>This page could not be found.</h1>
<div className="max-w-3xl w-full mx-auto px-5 md:px-10 py-24 md:py-32 bg-white rounded-room text-center">
<div className="prose max-w-none">
<h1>This page could not be found</h1>
</div>
</div>
</main>
);
}
5 changes: 3 additions & 2 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import type { AppProps } from "next/app";
import { Fragment } from "react";
import Footer from "../components/footer";
import Navigation from "../components/navigation";
import "../styles/globals.css";

export default function SoapboxApp({ Component, pageProps }: AppProps) {
return (
<div className="flex flex-col min-h-screen">
<Fragment>
<Navigation />

<Component {...pageProps} />

<Footer />
</div>
</Fragment>
);
}
116 changes: 116 additions & 0 deletions pages/blog/[slug].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import type { GetStaticPaths, InferGetStaticPropsType } from "next";
import hydrate from "next-mdx-remote/hydrate";
import Image from "next/image";
import Meta from "../../components/meta";
import { APP_STORE_URL, TWITTER_URL } from "../../constants";
import Apple from "../../icons/apple";
import Twitter from "../../icons/twitter";
import { getAllPosts, getPostBySlug } from "../../lib";

type Props = InferGetStaticPropsType<typeof getStaticProps>;

export default function Post({ slug, meta, source }: Props) {
const content = hydrate(source);

const hasAuthors = meta?.authors?.length > 0;

return (
<main className="p-5">
<Meta
title={meta.title}
description={meta.summary}
url={`https://soapbox.social/blog/${slug}`}
/>

<div className="max-w-2xl w-full mx-auto p-5 md:p-10 bg-white rounded-room">
<div className="space-y-4">
<h1 className="text-4xl font-extrabold leading-none text-prose-primary">
{meta.title}
</h1>

<p className="text-prose-secondary">
<strong>{meta.date}</strong>
</p>

{hasAuthors && (
<div className="flex -space-x-2">
{meta.authors.map((member, i: number) => (
<div key={i} className="flex room-head overflow-visible">
<Image
height={50}
width={50}
className="room-head object-cover object-center rounded-full"
draggable="false"
src={member.image}
alt={member.displayName}
/>
</div>
))}
</div>
)}
</div>

<div className="h-8" />

<div className="prose max-w-none">{content}</div>
</div>

<div className="h-4" />

<div className="max-w-2xl w-full mx-auto p-5 md:p-10 bg-white rounded-room">
<div className="text-center text-prose-secondary">
<p className="text-4xl font-extrabold leading-none text-prose-primary">
Join Soapbox
</p>

<div className="h-4" />

<p>Download Soapbox on iOS and follow us on Twitter.</p>

<div className="h-8" />

<div className="max-w-md mx-auto sm:flex justify-center sm:space-x-2 space-y-4 sm:space-y-0">
<a
className="py-2 px-4 bg-brand text-white rounded-full flex justify-center items-center space-x-2 focus:outline-none focus:ring-4"
href={APP_STORE_URL}
aria-label="Download on the App Store"
>
<Apple size={24} className="-mt-0.5" />
<span className="text-lg font-medium">App Store</span>
</a>

<a
className="py-2 px-4 bg-brand text-white rounded-full flex justify-center items-center space-x-2 focus:outline-none focus:ring-4"
href={TWITTER_URL}
aria-label="Download on the App Store"
>
<Twitter size={24} />
<span className="text-lg font-medium">Twitter</span>
</a>
</div>
</div>
</div>
</main>
);
}

export const getStaticProps = async ({ params }) => {
return {
props: await getPostBySlug(params.slug),
};
};

export const getStaticPaths: GetStaticPaths = async () => {
const posts = getAllPosts();

return {
paths: posts.map((post) => {
return {
params: {
slug: post.slug,
},
};
}),
fallback: false,
};
};
Loading

0 comments on commit de72904

Please sign in to comment.