pages: add blog listing, post template

This commit is contained in:
Matilde Park 2022-06-22 13:54:19 -07:00
parent 2ee6cef6eb
commit cdb1658389
10 changed files with 842 additions and 25 deletions

31
components/Meta.js Normal file
View File

@ -0,0 +1,31 @@
export default function Meta(post, disableImage) {
const author = post?.extra?.author || "Urbit";
const title = post?.title ? `${post.title} - ` : "";
const description =
post?.description || "Urbit is a personal server built from scratch.";
const image =
post?.extra?.image || "https://media.urbit.org/logo/urbit-logo-card.png";
return (
<>
<link rel="icon" type="image/png" href="/images/favicon.ico" />
<meta
name="twitter:card"
content="summary_large_image"
key="twitter-card"
/>
<meta name="twitter:site" content="@urbit" key="twitter-site" />
<meta name="twitter:creator" content="@urbit" key="twitter-creator" />
<meta
name="og:title"
content={`${title}developers.urbit.org`}
key="title"
/>
<meta name="og:description" content={description} key="description" />
<meta name="description" content={description} />
<meta name="author" content={author} key="author" />
{!disableImage && (
<meta name="twitter:image" content={image} key="image" />
)}
</>
);
}

50
components/PostPreview.js Normal file
View File

@ -0,0 +1,50 @@
import Link from "next/link";
import { BackgroundImage } from "foundation-design-system";
import { formatDate, generateDisplayDate } from "../lib/lib";
export default function PostPreview(props) {
const section = props?.section ? props.section : "blog";
const date = generateDisplayDate(props.post.date);
return (
<div className={`cursor-pointer ${props.className}`}>
{props.title ? <h3 className="mb-2">{props.title}</h3> : null}
<Link
href={`/${section}/${props.post.slug}`}
key={`post-${props.post.slug}`}
>
<div>
<BackgroundImage
className="aspect-w-5 aspect-h-4 rounded-lg"
src={props.post.extra.image || ""}
/>
<h4 className="mt-2">{props.post.title}</h4>
<div className="flex items-baseline mt-1">
{props.post.extra.author ? (
<div className="type-sub-bold mr-2">
{props.post.extra.author}
</div>
) : null}
{props.post.extra.ship ? (
<Link
href={`https://urbit.org/ids/${props.post.extra.ship}`}
passHref
>
<a className="type-sub-bold text-wall-500 font-mono">
{props.post.extra.ship}
</a>
</Link>
) : null}
</div>
<div className="text-wall-500 type-sub mt-1">{formatDate(date)}</div>
</div>
</Link>
</div>
);
}
PostPreview.defaultProps = {
className: "",
};

View File

@ -0,0 +1,52 @@
+++
title = "Layer 2 Guides"
date = "2022-02-14"
description = "Urbits Layer 2 system is live and operational."
[extra]
author = "Reid Scoggin"
ship = "~sitful-hatred"
image = "https://media.urbit.org/site/posts/essays/l2-blogpost.png"
+++
Urbits [Layer 2](https://urbit.org/docs/azimuth/l2/layer2) system, naive rollups, allows planets to be spawned at substantially lower cost. This system operates in parallel to Layer 1 Azimuth, but introduces some new concepts and differences that are important to understand. Read on for a high-level survey, and check the star and planet guides linked at the bottom for details and instructions.
After a year of development and testing, **Urbits Layer 2 system is live and operational**. Star and planet operators can now take advantage of subsidized Azimuth operations. If you operate a star, you can distribute planets cheaply or for free; if youve been waiting to buy an ID due to transaction fees, you will find planets are available much more cheaply.
Layer 2 (“L2”) introduces some changes that are important to understand, whether youre new to the network or not. Stars and planet operators that are considering migrating to L2 have different **trade-offs to weigh** before they make a decision.
### Background
Urbit can be broadly divided into two parts: an operating system, Arvo, and the identity layer, Azimuth. These two systems are interlocked. Arvo uses Azimuth to verify that you own an address, which maps to your name on the network. [Azimuth](https://urbit.org/docs/glossary/azimuth) is a public key infrastructure, implemented as contracts on the Ethereum blockchain. Modifications to the ownership or properties of an identitys keys are recorded on Ethereum. Azimuth faithfully serves its purpose as an authoritative, trustless registry of ownership, but it inherits both the strengths and disadvantages of the ETH ecosystem.
Due to ETHs value and popularity, performing transactions directly on the Ethereum blockchain (Layer 1) has become prohibitively expensive for many simple operations. The Ethereum smart contracts that control the logic of Azimuth were developed in a time when ETH was not worth as much. The soaring value of ETH means that the gas fee to spawn or modify a planet routinely costs more than the planet itself. Azimuth is not unique in this regard. All projects built on Ethereum have had to deal with this issue in one form or another. Fortunately, Urbit engineers have come up with a solution for those seeking to get onto the network, albeit with several important trade-offs.
### Naive rollups
Layer 2 refers to technologies built on top of blockchains to enable scaling. [Rollups](https://vitalik.ca/general/2021/01/05/rollup.html) are an Ethereum ecosystem Layer 2 innovation that reduces costs by moving computation off-chain. _Naive rollups_ are a bespoke technology developed for Urbit that augment the original Azimuth contracts. For technical details, you can review the [excellent summary](https://urbit.org/blog/rollups) by `~datnut-pollen`, or the [original proposal](https://groups.google.com/a/urbit.org/g/dev/c/p6rP_WsxLS0) by `~wicdev-wisryt`. In brief: rather than using the Ethereum network to perform the computation associated with PKI modifications (Layer 1), the computation is performed on the Urbit network itself, with the results published to the blockchain by nodes called rollers. Signed data resulting from the combined transactions is posted on a regular basis to the main blockchain by the rollers. Due to this batched, off-chain computation, fees are roughly **65-100x cheaper** than Layer 1 operations.
### What everyone should know
Whether youre new to the network or a longtime participant, you should gain familiarity with the new changes. There are a few things that everyone should know:
- All ships spawned before now have been on Layer 1 those ships have the option of migrating to Layer 2, or remaining on Layer 1.
- **You dont have to do anything**. Migrating is opt-in, and a Layer 1 ship will continue to have full functionality on the network.
- Layer 2 lets you perform **Azimuth transactions cheaply or for free**. If you operate a star, you can spawn planets for free with Tlons roller. Planets can make use of Tlons roller for actions like factory resets and transferring ownership and proxy addresses for free.
- **Migrating is one-way**. If you migrate to Layer 2, there is not currently an option to reverse your decision.
- **Migrating does not change which address owns a point**. After migrating, you will still log into Bridge with the same keys.
### Layer 2 guides
Theres lots more to learn about the new solution. These updates apply to the software on your ship, the Azimuth PKI, and new features and major updates to Bridge. You can learn more in the following guides, with in-depth background and illustrated walkthroughs for common tasks:
[Layer 2 for stars](https://operators.urbit.org/guides/layer-2-for-stars) Its particularly important for star operators to understand the pros and cons of migrating. This guide will explain the technical background, trade-offs, and how to use Layer 2 on Bridge.
- Stars can migrate their spawn proxy to Layer 2 to spawn up to six planets per week for free using Tlons roller.
- Stars can migrate their ownership key to Layer 2 to perform all Azimuth operations on Layer 2, including planet spawning, factory resets, and point adoption.
- Migrating is currently a one-way process and cannot be reversed.
- Layer 2 stars cannot be wrapped as $WSTR tokens, or interact with any other Layer 1 tools or contracts (e.g. MetaMask, OpenSea).
[Layer 2 for planets](https://urbit.org/getting-started/layer-2-for-planets) Just bought a planet and want to know what all of this means for you? Wondering whether you should migrate your Layer 1 planet? Look here for guidance.
- Planets spawned by a Layer 2 star will spawn on Layer 2.
- Migration is one-way; if your planet is on Layer 2, there is no way to migrate it to Layer 1.
- Planets on Layer 2 can take advantage of subsidized, free Azimuth transactions using Tlons roller.
- Planets on Layer 2 cannot currently interact with Layer 1 tools or contracts like MetaMask or OpenSea.

View File

@ -1,3 +1,111 @@
import fs from "fs";
import { join, parse } from "path";
import matter from "gray-matter";
import toml from "@iarna/toml";
import { DateTime } from "luxon";
const options = {
engines: {
toml: toml.parse.bind(toml),
},
language: "toml",
delimiters: "+++",
};
export function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
const directories = (dir) => {
switch (dir) {
case "/":
return join(process.cwd(), "content");
default:
return join(process.cwd(), `content/${dir}`);
}
};
export function formatDate(dateTimeObject) {
return dateTimeObject.toLocaleString(DateTime.DATE_FULL);
}
export function generateDisplayDate(iso8601, zone = "America/Los_Angeles") {
return DateTime.fromISO(iso8601, { zone });
}
export function getPostSlugs(key) {
const dir = fs.existsSync(directories(key))
? fs.readdirSync(directories(key), { withFileTypes: true })
: [];
return dir
.filter((f) => f.isFile() && f.name !== "_index.md")
.map((f) => f.name);
}
export function getPostBySlug(slug, fields = [], key) {
const realSlug = slug.replace(/\.md$/, "");
const fullPath = join(directories(key), `${realSlug}.md`);
const fileContents = fs.readFileSync(fullPath, "utf8");
const { data, content } = matter(fileContents, options);
const items = {};
// Ensure only the minimal needed data is exposed
fields.forEach((field) => {
if (field === "slug") {
items[field] = realSlug;
}
if (field === "content") {
items[field] = content;
}
if (data[field]) {
items[field] = data[field];
}
});
return items;
}
export function getAllPosts(fields = [], key, sort = "") {
const slugs = getPostSlugs(key);
const posts = slugs
.map((slug) => getPostBySlug(slug, fields, key))
// sort posts by date in descending order
.sort((post1, post2) => {
if (sort === "date") {
return DateTime.fromISO(post1.date) > DateTime.fromISO(post2.date)
? -1
: 1;
} else if (sort === "weight") {
return post1.weight > post2.weight ? -1 : 1;
}
});
return posts;
}
export function getNextPost(slug, fields = [], key, sort = "date") {
let resultPost = null;
getAllPosts(fields, key, sort).forEach((post, index, array) => {
if (post.slug === slug) {
if (typeof array[index - 1] !== "undefined") {
resultPost = array[index - 1];
}
}
});
return resultPost;
}
export function getPreviousPost(slug, fields = [], key, sort = "date") {
let resultPost = null;
getAllPosts(fields, key, sort).forEach((post, index, array) => {
if (post.slug === slug) {
if (typeof array[index + 1] !== "undefined") {
resultPost = array[index + 1];
}
}
});
return resultPost;
}

View File

@ -1,6 +1,26 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
}
module.exports = nextConfig
module.exports = {
reactStrictMode: false,
// target: 'serverless',
webpack: (config, { isServer }) => {
// Fixes npm packages that depend on `fs` module
if (!isServer) {
config.resolve.fallback = {
fs: false,
path: "path-browserify",
events: false,
};
}
if (isServer) {
config.externals.push("_http_common");
}
config.resolve.alias.stream = "stream-browserify";
config.resolve.alias.zlib = "browserify-zlib";
// config.externals = {
// ...config.externals,
// canvas: "util",
// bufferutil: "bufferutil",
// "utf-8-validate": "utf-8-validate"
// }
return config;
},
};

346
package-lock.json generated
View File

@ -8,12 +8,18 @@
"name": "developers.urbit.org",
"version": "0.1.0",
"dependencies": {
"@iarna/toml": "^2.2.5",
"browserify-zlib": "^0.2.0",
"classnames": "^2.3.1",
"foundation-design-system": "github:urbit/foundation-design-system#01f35f1ff8775b300508fe334e44d473e4201ba1",
"foundation-design-system": "github:urbit/foundation-design-system",
"gray-matter": "^4.0.3",
"luxon": "^2.4.0",
"next": "12.1.6",
"path-browserify": "^1.0.1",
"react": "^17",
"react-dom": "^17",
"react-swipeable": "^7.0.0"
"react-swipeable": "^7.0.0",
"stream-browserify": "^3.0.0"
},
"devDependencies": {
"eslint": "8.18.0",
@ -85,6 +91,11 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true
},
"node_modules/@iarna/toml": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz",
"integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg=="
},
"node_modules/@markdoc/markdoc": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@markdoc/markdoc/-/markdoc-0.1.2.tgz",
@ -729,6 +740,14 @@
"node": ">=8"
}
},
"node_modules/browserify-zlib": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
"integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
"dependencies": {
"pako": "~1.0.5"
}
},
"node_modules/browserslist": {
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.0.tgz",
@ -1101,9 +1120,9 @@
}
},
"node_modules/electron-to-chromium": {
"version": "1.4.164",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.164.tgz",
"integrity": "sha512-K7iy5y6XyP9Pzh3uaDti0KC4JUNT6T1tLG5RTOmesqq2YgAJpYYYJ32m+anvZYjCV35llPTEh87kvEV/uSsiyQ==",
"version": "1.4.165",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.165.tgz",
"integrity": "sha512-DKQW1lqUSAYQvn9dnpK7mWaDpWbNOXQLXhfCi7Iwx0BKxdZOxkKcCyKw1l3ihWWW5iWSxKKbhEUoNRoHvl/hbA==",
"peer": true
},
"node_modules/emoji-regex": {
@ -1588,6 +1607,18 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/esquery": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
@ -1630,6 +1661,17 @@
"node": ">=0.10.0"
}
},
"node_modules/extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
"dependencies": {
"is-extendable": "^0.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@ -1746,8 +1788,7 @@
},
"node_modules/foundation-design-system": {
"version": "0.0.0",
"resolved": "git+ssh://git@github.com/urbit/foundation-design-system.git#01f35f1ff8775b300508fe334e44d473e4201ba1",
"integrity": "sha512-OmMcLkuYRK8qwiGkbJ+Y/G7nGG9I+HR6sQjZ4t4qVTuFQtF0vEw4HXjHKXdkn+0H5KCNm1qZd8HRg5xd9qJOtA==",
"resolved": "git+ssh://git@github.com/urbit/foundation-design-system.git#f886b6cdb9070ce05644f4b3b3d2e0bcb8ea0a36",
"license": "MIT",
"dependencies": {
"@markdoc/markdoc": "0.1.2",
@ -1951,6 +1992,40 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
},
"node_modules/gray-matter": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
"integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
"dependencies": {
"js-yaml": "^3.13.1",
"kind-of": "^6.0.2",
"section-matter": "^1.0.0",
"strip-bom-string": "^1.0.0"
},
"engines": {
"node": ">=6.0"
}
},
"node_modules/gray-matter/node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dependencies": {
"sprintf-js": "~1.0.2"
}
},
"node_modules/gray-matter/node_modules/js-yaml": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@ -2230,6 +2305,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@ -2432,6 +2515,14 @@
"node": ">=4.0"
}
},
"node_modules/kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/klaw-sync": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz",
@ -2519,6 +2610,14 @@
"node": ">=10"
}
},
"node_modules/luxon": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-2.4.0.tgz",
"integrity": "sha512-w+NAwWOUL5hO0SgwOHsMBAmZ15SoknmQXhSO0hIbJCAmPKSsGeK8MlmhYh2w6Iib38IxN2M+/ooXWLbeis7GuA==",
"engines": {
"node": ">=12"
}
},
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@ -2868,6 +2967,11 @@
"node": ">=4"
}
},
"node_modules/pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
},
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@ -3050,6 +3154,11 @@
"which": "bin/which"
}
},
"node_modules/path-browserify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="
},
"node_modules/path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@ -3371,6 +3480,19 @@
"pify": "^2.3.0"
}
},
"node_modules/readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@ -3489,6 +3611,25 @@
"queue-microtask": "^1.2.2"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/scheduler": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
@ -3498,6 +3639,18 @@
"object-assign": "^4.1.1"
}
},
"node_modules/section-matter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
"integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
"dependencies": {
"extend-shallow": "^2.0.1",
"kind-of": "^6.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/semver": {
"version": "7.3.7",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
@ -3565,6 +3718,28 @@
"node": ">=0.10.0"
}
},
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
},
"node_modules/stream-browserify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz",
"integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==",
"dependencies": {
"inherits": "~2.0.4",
"readable-stream": "^3.5.0"
}
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"dependencies": {
"safe-buffer": "~5.2.0"
}
},
"node_modules/string.prototype.matchall": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz",
@ -3633,6 +3808,14 @@
"node": ">=4"
}
},
"node_modules/strip-bom-string": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
"integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@ -3903,8 +4086,7 @@
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"peer": true
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/v8-compile-cache": {
"version": "2.3.0",
@ -4036,6 +4218,11 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true
},
"@iarna/toml": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz",
"integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg=="
},
"@markdoc/markdoc": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@markdoc/markdoc/-/markdoc-0.1.2.tgz",
@ -4427,6 +4614,14 @@
"fill-range": "^7.0.1"
}
},
"browserify-zlib": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
"integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
"requires": {
"pako": "~1.0.5"
}
},
"browserslist": {
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.0.tgz",
@ -4679,9 +4874,9 @@
}
},
"electron-to-chromium": {
"version": "1.4.164",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.164.tgz",
"integrity": "sha512-K7iy5y6XyP9Pzh3uaDti0KC4JUNT6T1tLG5RTOmesqq2YgAJpYYYJ32m+anvZYjCV35llPTEh87kvEV/uSsiyQ==",
"version": "1.4.165",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.165.tgz",
"integrity": "sha512-DKQW1lqUSAYQvn9dnpK7mWaDpWbNOXQLXhfCi7Iwx0BKxdZOxkKcCyKw1l3ihWWW5iWSxKKbhEUoNRoHvl/hbA==",
"peer": true
},
"emoji-regex": {
@ -5057,6 +5252,11 @@
"eslint-visitor-keys": "^3.3.0"
}
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
},
"esquery": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
@ -5087,6 +5287,14 @@
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
"requires": {
"is-extendable": "^0.1.0"
}
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@ -5186,9 +5394,8 @@
"dev": true
},
"foundation-design-system": {
"version": "git+ssh://git@github.com/urbit/foundation-design-system.git#01f35f1ff8775b300508fe334e44d473e4201ba1",
"integrity": "sha512-OmMcLkuYRK8qwiGkbJ+Y/G7nGG9I+HR6sQjZ4t4qVTuFQtF0vEw4HXjHKXdkn+0H5KCNm1qZd8HRg5xd9qJOtA==",
"from": "foundation-design-system@github:urbit/foundation-design-system#01f35f1ff8775b300508fe334e44d473e4201ba1",
"version": "git+ssh://git@github.com/urbit/foundation-design-system.git#f886b6cdb9070ce05644f4b3b3d2e0bcb8ea0a36",
"from": "foundation-design-system@github:urbit/foundation-design-system",
"requires": {
"@markdoc/markdoc": "0.1.2",
"core-js": "^3.23.1",
@ -5325,6 +5532,36 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
},
"gray-matter": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
"integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
"requires": {
"js-yaml": "^3.13.1",
"kind-of": "^6.0.2",
"section-matter": "^1.0.0",
"strip-bom-string": "^1.0.0"
},
"dependencies": {
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"requires": {
"sprintf-js": "~1.0.2"
}
},
"js-yaml": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
}
}
}
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@ -5516,6 +5753,11 @@
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
"integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="
},
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="
},
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@ -5661,6 +5903,11 @@
"object.assign": "^4.1.2"
}
},
"kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="
},
"klaw-sync": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz",
@ -5733,6 +5980,11 @@
"yallist": "^4.0.0"
}
},
"luxon": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-2.4.0.tgz",
"integrity": "sha512-w+NAwWOUL5hO0SgwOHsMBAmZ15SoknmQXhSO0hIbJCAmPKSsGeK8MlmhYh2w6Iib38IxN2M+/ooXWLbeis7GuA=="
},
"merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@ -5973,6 +6225,11 @@
"integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==",
"dev": true
},
"pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
},
"parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@ -6109,6 +6366,11 @@
}
}
},
"path-browserify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="
},
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
@ -6309,6 +6571,16 @@
"pify": "^2.3.0"
}
},
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@ -6379,6 +6651,11 @@
"queue-microtask": "^1.2.2"
}
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"scheduler": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
@ -6388,6 +6665,15 @@
"object-assign": "^4.1.1"
}
},
"section-matter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
"integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
"requires": {
"extend-shallow": "^2.0.1",
"kind-of": "^6.0.0"
}
},
"semver": {
"version": "7.3.7",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
@ -6434,6 +6720,28 @@
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
},
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
},
"stream-browserify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz",
"integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==",
"requires": {
"inherits": "~2.0.4",
"readable-stream": "^3.5.0"
}
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
}
},
"string.prototype.matchall": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz",
@ -6487,6 +6795,11 @@
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
"dev": true
},
"strip-bom-string": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
"integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g=="
},
"strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@ -6669,8 +6982,7 @@
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"peer": true
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"v8-compile-cache": {
"version": "2.3.0",

View File

@ -9,12 +9,18 @@
"lint": "next lint"
},
"dependencies": {
"@iarna/toml": "^2.2.5",
"browserify-zlib": "^0.2.0",
"classnames": "^2.3.1",
"foundation-design-system": "github:urbit/foundation-design-system#01f35f1ff8775b300508fe334e44d473e4201ba1",
"foundation-design-system": "github:urbit/foundation-design-system",
"gray-matter": "^4.0.3",
"luxon": "^2.4.0",
"next": "12.1.6",
"path-browserify": "^1.0.1",
"react": "^17",
"react-dom": "^17",
"react-swipeable": "^7.0.0"
"react-swipeable": "^7.0.0",
"stream-browserify": "^3.0.0"
},
"devDependencies": {
"eslint": "8.18.0",

27
pages/404.js Normal file
View File

@ -0,0 +1,27 @@
import Head from "next/head";
import Meta from "../components/Meta";
import { Container, SingleColumn, Section } from "foundation-design-system";
import Header from "../components/Header";
import Footer from "../components/Footer";
export default function NotFound(props) {
const post = {
title: "404",
};
return (
<Container>
<Head>
<title>404 developers.urbit.org</title>
{Meta(post)}
</Head>
<Header />
<SingleColumn>
<Section className="pt-48">
<h1>404</h1>
<p className="mt-12">It looks like nothing is here.</p>
</Section>
</SingleColumn>
<Footer />
</Container>
);
}

95
pages/blog.js Normal file
View File

@ -0,0 +1,95 @@
import Head from "next/head";
import Link from "next/link";
import Header from "../components/Header";
import Meta from "../components/Meta";
import {
BackgroundImage,
Container,
SingleColumn,
Section,
} from "foundation-design-system";
import { getAllPosts, formatDate, generateDisplayDate } from "../lib/lib";
import Footer from "../components/Footer";
export default function Blog({ posts }) {
const post = {
title: "Developer Blog",
description: "Technical-oriented posts by Urbit engineers.",
};
return (
<Container>
<Head>
<title>Blog developers.urbit.org</title>
{Meta(post)}
</Head>
<Header />
<SingleColumn>
<Section narrow short>
<h1 className="pb-16">Developer Blog</h1>
</Section>
<Section narrow>
{posts.map((post) => {
const date = generateDisplayDate(post.date);
return (
<div key={post.slug} className="mb-20 cursor-pointer">
<Link href={`/blog/${post.slug}`}>
<div>
{
// Not all blog posts have images
post.extra.image ? (
<BackgroundImage
src={post.extra.image}
className="rounded-lg aspect-w-5 aspect-h-4"
/>
) : null
}
<h3 className="mt-10">{post.title}</h3>
{post?.description && (
<p className="mt-3">{post.description}</p>
)}
<div className="flex items-center justify-between mt-4">
<div className="flex items-baseline">
{post.extra.author ? (
<div className="type-sub-bold mr-2">
{post.extra.author}
</div>
) : null}
{post.extra.ship ? (
<Link
href={`https://urbit.org/ids/${post.extra.ship}`}
passHref
>
<a className="type-sub-bold text-wall-500 font-mono">
{post.extra.ship}
</a>
</Link>
) : null}
</div>
<div className="text-wall-500 type-sub">
{formatDate(date)}
</div>
</div>
</div>
</Link>
</div>
);
})}
</Section>
</SingleColumn>
<Footer />
</Container>
);
}
export async function getStaticProps() {
const posts = getAllPosts(
["title", "slug", "date", "description", "extra"],
"blog",
"date"
);
return {
props: { posts },
};
}

116
pages/blog/[slug].js Normal file
View File

@ -0,0 +1,116 @@
import {
getPostBySlug,
getAllPosts,
getNextPost,
getPreviousPost,
formatDate,
generateDisplayDate,
} from "../../lib/lib";
import { useRouter } from "next/router";
import Head from "next/head";
import Link from "next/link";
import Meta from "../../components/Meta";
import PostPreview from "../../components/PostPreview";
import ErrorPage from "../404";
import Header from "../../components/Header";
import Footer from "../../components/Footer";
import {
Container,
Markdown,
SingleColumn,
Section,
TwoUp,
} from "foundation-design-system";
export default function BlogPost({ post, markdown, nextPost, previousPost }) {
const router = useRouter();
if (!router.isFallback && !post?.slug) {
return <ErrorPage />;
}
const date = generateDisplayDate(post.date);
return (
<Container>
<Head>
<title>{post.title} Blog developers.urbit.org</title>
{Meta(post)}
</Head>
<Header />
<SingleColumn>
<Section short narrow>
<h1>{post.title}</h1>
<h3 className=" mt-6">{post.description}</h3>
<div className="flex items-baseline mt-6">
{post.extra.author ? (
<div className="type-sub-bold mr-2">{post.extra.author}</div>
) : null}
{post.extra.ship ? (
<Link href={`/ids/${post.extra.ship}`} passHref>
<a className="type-sub-bold text-wall-500 font-mono">
{post.extra.ship}
</a>
</Link>
) : null}
</div>
<div className="text-wall-500 type-sub">{formatDate(date)}</div>
</Section>
<Section short narrow className="markdown">
<Markdown.render content={JSON.parse(markdown)} />
</Section>
<Section wide className="flex">
<TwoUp>
{nextPost ? (
<PostPreview title="Next Post" post={nextPost} />
) : null}
{previousPost ? (
<PostPreview title="Previous Post" post={previousPost} />
) : null}
</TwoUp>
</Section>
</SingleColumn>
<Footer />
</Container>
);
}
export async function getStaticProps({ params }) {
const nextPost =
getNextPost(
params.slug,
["title", "slug", "date", "description", "extra"],
"blog"
) || null;
const previousPost =
getPreviousPost(
params.slug,
["title", "slug", "date", "description", "extra"],
"blog"
) || null;
const post = getPostBySlug(
params.slug,
["title", "slug", "date", "description", "content", "extra"],
"blog"
);
const markdown = JSON.stringify(Markdown.parse({ post }));
return {
props: { post, markdown, nextPost, previousPost },
};
}
export async function getStaticPaths() {
const posts = getAllPosts(["slug", "date"], "blog", "date");
return {
paths: posts.map((post) => {
return {
params: {
slug: post.slug,
},
};
}),
fallback: false,
};
}