1
mirror of https://github.com/jakejarvis/jarv.is.git synced 2025-04-26 13:18:26 -04:00

next-mdx-remote -> mdx-bundler (#729)

This commit is contained in:
Jake Jarvis 2022-01-09 13:45:38 -05:00 committed by GitHub
parent b7313985db
commit 65416fcc1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 1624 additions and 821 deletions

View File

@ -0,0 +1,3 @@
import Gist from "react-gist";
export default Gist;

View File

@ -0,0 +1,28 @@
const Octocat = (props: { repo: string }) => {
return (
<a
className="no-underline"
href={`https://github.com/${props.repo}`}
target="_blank"
rel="noopener noreferrer"
style={{ margin: "0 0.3em", color: "var(--text)" }}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="1em"
height="1em"
aria-hidden="true"
className="icon"
fill="currentColor"
>
<path
fillRule="evenodd"
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"
></path>
</svg>
</a>
);
};
export default Octocat;

View File

@ -0,0 +1,13 @@
import TweetEmbed from "react-tweet-embed";
const Tweet = (props: { id: string }) => (
<TweetEmbed
id={props.id}
options={{
dnt: true,
align: "center",
}}
/>
);
export default Tweet;

View File

@ -0,0 +1,9 @@
import ReactPlayer, { ReactPlayerProps } from "react-player/lazy";
const Video = (props: ReactPlayerProps) => (
<div style={{ position: "relative", paddingTop: "56.25%" }}>
<ReactPlayer width="100%" height="100%" style={{ position: "absolute", top: 0, left: 0 }} {...props} />
</div>
);
export default Video;

View File

@ -1,3 +1,5 @@
import { memo } from "react";
type Props = {
boxes?: number;
timing?: number;
@ -54,4 +56,4 @@ const Loading = ({ boxes = 3, timing = 0.1, width }: Props) => {
);
};
export default Loading;
export default memo(Loading);

View File

@ -1,13 +1,11 @@
import dynamic from "next/dynamic";
import Link from "next/link";
import Image from "next/image";
import { useTheme } from "next-themes";
import type { LinkProps } from "next/link";
import type { ImageProps } from "next/image";
// The following components are all passed into <MDXProvider /> as replacement HTML tags or drop-in React components
// available in .mdx files containing post content, since they're not directly aware of the components in this folder.
// The following components are all passed into <MDXComponent /> in [slug].tsx as replacements for vanilla HTML tags.
type CustomLinkProps = LinkProps & {
target?: string;
@ -23,7 +21,10 @@ const CustomLink = ({ href, target, rel, className, children }: CustomLinkProps)
</Link>
);
const CustomImg = (props: ImageProps) => (
type CustomImgProps = ImageProps & {
caption?: unknown;
};
const CustomImg = (props: CustomImgProps) => (
// the required height and width are part of the props, so they get automatically passed here with {...props}
<div className={props.className}>
{/* eslint-disable-next-line jsx-a11y/alt-text */}
@ -56,55 +57,11 @@ const CustomCode = (props: any) => {
}
};
const CustomTweet = (props: { id: string }) => {
const TweetEmbed = dynamic(() => import("react-tweet-embed"));
const { resolvedTheme } = useTheme();
return (
<TweetEmbed
id={props.id}
options={{
dnt: true,
align: "center",
theme: resolvedTheme === "dark" ? "dark" : "light",
}}
/>
);
};
const CustomGist = dynamic(() => import("react-gist"));
const CustomVideo = dynamic(() => import("./video/Video"));
const CustomGitHubLink = (props: { repo: string }) => {
const OctocatOcticon: any = dynamic(() => import("./icons/octicons").then((mod) => mod.OctocatOcticon));
return (
<a className="no-underline" href={`https://github.com/${props.repo}`} target="_blank" rel="noopener noreferrer">
<OctocatOcticon className="icon" fill="currentColor" />
<style jsx>{`
a {
margin: 0 0.3em;
color: var(--text);
}
a:hover {
color: var(--link);
}
`}</style>
</a>
);
};
// These are the actual tags referenced in mdx files:
const mdxComponents = {
a: CustomLink,
img: CustomImg,
code: CustomCode,
video: CustomVideo,
tweet: CustomTweet,
gist: CustomGist,
octocat: CustomGitHubLink,
};
export default mdxComponents;

View File

@ -1,5 +0,0 @@
.wrapper {
margin-top: 2em;
padding-top: 1em;
border-top: 2px solid var(--light);
}

View File

@ -3,9 +3,11 @@ import Head from "next/head";
import { useTheme } from "next-themes";
import { githubRepo } from "../../lib/config";
import styles from "./Comments.module.css";
type Props = {
slug: string;
};
const Comments = ({ slug }) => {
const Comments = (props: Props) => {
const [injected, setInjected] = useState(false);
const scriptRef = useRef<HTMLDivElement>(null);
const { resolvedTheme } = useTheme();
@ -25,7 +27,7 @@ const Comments = ({ slug }) => {
// https://utteranc.es/
utterances.setAttribute("repo", githubRepo);
utterances.setAttribute("issue-term", `notes/${slug}`);
utterances.setAttribute("issue-term", `notes/${props.slug}`);
utterances.setAttribute("theme", resolvedTheme === "dark" ? "github-dark" : "github-light");
utterances.setAttribute("label", "💬 comments");
@ -43,7 +45,15 @@ const Comments = ({ slug }) => {
<link rel="preload" href="https://utteranc.es/client.js" as="script" crossOrigin="anonymous" />
</Head>
<div ref={scriptRef} id="comments" className={styles.wrapper} />
<div ref={scriptRef} id="comments" />
<style jsx>{`
div {
margin-top: 2em;
padding-top: 1em;
border-top: 2px solid var(--light);
}
`}</style>
</>
);
};

View File

@ -16,52 +16,52 @@ type Props = {
updatedAt: string;
};
const RepoCard = ({ name, url, description, language, stars, forks, updatedAt }: Props) => (
const RepoCard = (props: Props) => (
<div className={styles.card}>
<a className={styles.name} href={url} target="_blank" rel="noopener noreferrer">
{name}
<a className={styles.name} href={props.url} target="_blank" rel="noopener noreferrer">
{props.name}
</a>
{description && <p className={styles.description}>{description}</p>}
{props.description && <p className={styles.description}>{props.description}</p>}
<div className={styles.meta}>
{language && (
{props.language && (
<div className={styles.meta_item}>
<span className={styles.language_color}>
<style jsx>{`
span {
background-color: ${language.color};
background-color: ${props.language.color};
}
`}</style>
</span>
<span>{language.name}</span>
<span>{props.language.name}</span>
</div>
)}
{stars > 0 && (
{props.stars > 0 && (
<div className={styles.meta_item}>
<a
href={`${url}/stargazers`}
title={`${stars.toLocaleString("en-US")} ${stars === 1 ? "star" : "stars"}`}
href={`${props.url}/stargazers`}
title={`${props.stars.toLocaleString("en-US")} ${props.stars === 1 ? "star" : "stars"}`}
target="_blank"
rel="noopener noreferrer"
>
<StarOcticon fill="currentColor" className={styles.octicon} />
<span>{stars.toLocaleString("en-US")}</span>
<span>{props.stars.toLocaleString("en-US")}</span>
</a>
</div>
)}
{forks > 0 && (
{props.forks > 0 && (
<div className={styles.meta_item}>
<a
href={`${url}/network/members`}
title={`${forks.toLocaleString("en-US")} ${forks === 1 ? "fork" : "forks"}`}
href={`${props.url}/network/members`}
title={`${props.forks.toLocaleString("en-US")} ${props.forks === 1 ? "fork" : "forks"}`}
target="_blank"
rel="noopener noreferrer"
>
<ForkOcticon fill="currentColor" className={styles.octicon} />
<span>{forks.toLocaleString("en-US")}</span>
<span>{props.forks.toLocaleString("en-US")}</span>
</a>
</div>
)}
@ -69,7 +69,7 @@ const RepoCard = ({ name, url, description, language, stars, forks, updatedAt }:
<div
className={styles.meta_item}
title={intlFormat(
new Date(updatedAt),
new Date(props.updatedAt),
{
year: "numeric",
month: "short",
@ -83,7 +83,7 @@ const RepoCard = ({ name, url, description, language, stars, forks, updatedAt }:
}
)}
>
<span>Updated {formatDistanceToNowStrict(new Date(updatedAt), { addSuffix: true })}</span>
<span>Updated {formatDistanceToNowStrict(new Date(props.updatedAt), { addSuffix: true })}</span>
</div>
</div>
</div>

View File

@ -1,10 +0,0 @@
.wrapper {
position: relative;
padding-top: 56.25%; /* 100 / (1280 / 720) */
}
.react_player {
position: absolute;
top: 0;
left: 0;
}

View File

@ -1,14 +0,0 @@
import dynamic from "next/dynamic";
import type { ReactPlayerProps } from "react-player";
import styles from "./Video.module.css";
const ReactPlayer = dynamic(() => import("react-player/lazy"));
const Video = (props: ReactPlayerProps) => (
<div className={styles.wrapper}>
<ReactPlayer className={styles.react_player} width="100%" height="100%" {...props} />
</div>
);
export default Video;

View File

@ -1,8 +1,24 @@
import fs from "fs";
import path from "path";
import matter from "gray-matter";
import { bundleMDX } from "mdx-bundler";
import readingTime from "reading-time";
import { NOTES_DIR, baseUrl } from "./config";
// remark/rehype markdown plugins
import remarkGfm from "remark-gfm";
import rehypeExternalLinks from "rehype-external-links";
import rehypeSlug from "rehype-slug";
import rehypeAutolinkHeadings from "rehype-autolink-headings";
import rehypeHighlight from "rehype-highlight";
// returns all .mdx files in NOTES_DIR (without .mdx extension)
export const getNoteSlugs = () =>
fs
.readdirSync(path.join(process.cwd(), NOTES_DIR))
.filter((file) => /\.mdx$/.test(file))
.map((noteFile) => noteFile.replace(/\.mdx$/, ""));
// returns front matter and/or *raw* markdown contents of a given slug
export const getNoteData = (slug: string) => {
const fullPath = path.join(process.cwd(), NOTES_DIR, `${slug}.mdx`);
@ -15,17 +31,58 @@ export const getNoteData = (slug: string) => {
slug,
permalink: `${baseUrl}/notes/${slug}/`,
date: new Date(data.date).toISOString(), // validate/normalize the date string provided from front matter
readingTime: readingTime(content).minutes,
},
content,
};
};
// returns all .mdx files in NOTES_DIR (without .mdx extension)
export const getNoteSlugs = () =>
fs
.readdirSync(path.join(process.cwd(), NOTES_DIR))
.filter((file) => /\.mdx$/.test(file))
.map((noteFile) => noteFile.replace(/\.mdx$/, ""));
export const getNote = async (slug: string) => {
// https://github.com/kentcdodds/mdx-bundler#nextjs-esbuild-enoent
if (process.platform === "win32") {
process.env.ESBUILD_BINARY_PATH = path.join(process.cwd(), "node_modules", "esbuild", "esbuild.exe");
} else {
process.env.ESBUILD_BINARY_PATH = path.join(process.cwd(), "node_modules", "esbuild", "bin", "esbuild");
}
const { frontMatter, content } = getNoteData(slug);
const { code: mdxSource } = await bundleMDX({
source: content,
cwd: process.cwd(),
// cwd: path.join("/Users/jake/source/jarv.is", "components"),
xdmOptions: (options) => {
options.remarkPlugins = [...(options.remarkPlugins ?? []), [remarkGfm, { singleTilde: false }]];
options.rehypePlugins = [
...(options.rehypePlugins ?? []),
[rehypeExternalLinks, { target: "_blank", rel: ["noopener", "noreferrer"] }],
[rehypeSlug, {}],
[
rehypeAutolinkHeadings,
{ behavior: "append", properties: { className: "h-anchor" }, content: [], test: ["h2", "h3"] },
],
[rehypeHighlight, {}],
];
return options;
},
esbuildOptions: (options) => {
options.minify = true;
options.target = ["es2018"];
options.loader = {
...options.loader,
".js": "jsx",
".ts": "tsx",
};
return options;
},
});
return {
frontMatter,
mdxSource,
};
};
// returns the front matter of ALL notes, sorted reverse chronologically
export const getAllNotes = () =>

View File

@ -11,6 +11,8 @@ tags:
image: "/static/images/notes/bernie-sanders-bern-app-data/sad-bernie.jpg"
---
import Video from "./components/embeds/Video";
The team behind Bernie Sanders' 2020 campaign [released a new web app](https://www.nbcnews.com/politics/2020-election/bernie-sanders-2020-campaign-unveils-app-increase-its-voter-database-n999206) last month named [BERN](https://app.berniesanders.com/). The goal of BERN is simple: to gather as much information as they can on as many voters in the United States as they can, and make their grassroots army of enthusiastic supporters do the work. It's undoubtedly a smart strategy, but also a concerning one for myself and other privacy advocates.
<img src="/static/images/notes/bernie-sanders-bern-app-data/sad-bernie.jpg" width="865" height="433" alt="Sad Bernie" />
@ -40,7 +42,7 @@ Using either feature, a volunteer starts with a search of the database for the v
Here's one of the instructional videos provided internally to volunteers:
<video
<Video
url={[
{ src: "/static/images/notes/bernie-sanders-bern-app-data/friend-to-friend.webm", type: "video/webm" },
{ src: "/static/images/notes/bernie-sanders-bern-app-data/friend-to-friend.mp4", type: "video/mp4" },

View File

@ -11,6 +11,8 @@ tags:
image: "/static/images/notes/cloudflare-dns-archive-is-blocked/archive-is.png"
---
import Tweet from "./components/embeds/Tweet";
**tl;dr:** No. Quite the opposite, actually — [Archive.is](https://archive.is/)'s owner is intentionally blocking 1.1.1.1 users.
<img
@ -28,7 +30,7 @@ A [recent post on Hacker News](https://news.ycombinator.com/item?id=19828317) po
In other words, Archive.is's nameservers throw a hissy fit and return a bogus IP when Cloudflare **doesn't** leak your geolocation info to them via the optional [EDNS client subnet feature](https://tools.ietf.org/html/rfc7871). The owner of Archive.is has plainly admitted this with [a questionable claim](https://twitter.com/archiveis/status/1018691421182791680) (in my opinion) about the lack of EDNS information causing him "so many troubles."
<tweet id="1018691421182791680" />
<Tweet id="1018691421182791680" />
He's even gone as far as [replying to support requests](https://community.cloudflare.com/t/archive-is-error-1001/18227/7) by telling people to switch to Google's DNS, which — surprise! — offers your location to nameservers [with pleasure](https://developers.google.com/speed/public-dns/docs/ecs).

View File

@ -11,18 +11,21 @@ tags:
image: "/static/images/notes/coronavirus-open-source/covid19dashboards.png"
---
import Octocat from "./components/embeds/Octocat";
import Video from "./components/embeds/Video";
We're all quickly learning that worldwide pandemics can bring out both [the best](https://www.vox.com/culture/2020/3/13/21179293/coronavirus-italy-covid19-music-balconies-sing) and [the worst](https://twitter.com/9NewsAUS/status/1236088663093608448) of humanity. But one thing has become readily apparent to me — outside of the large teams of medical professionals risking their lives right this minute, the open source community stands alone in its ability to rapidly organize in the midst of chaos to give back to the world and, in this case, make it safer for all of us.
These are just a few incredible open source projects that didn't exist a few months ago, but rapidly formed teams of dozens of contributors to fill both big needs and small niches in the fight to defeat the novel coronavirus, aka [**COVID-19**](https://www.cdc.gov/coronavirus/2019-nCoV/index.html).
## [The COVID Tracking Project](https://covidtracking.com/) <octocat repo="COVID19Tracking/website" />
## [The COVID Tracking Project](https://covidtracking.com/) <Octocat repo="COVID19Tracking/website" />
Now that Americans are _finally_ starting to get tested for the coronavirus, information and statistics about the results are being released state-by-state, which has led to a scattering of primary sources across the web, each releasing [different figures in different forms](https://docs.google.com/document/d/1OyN6_1UeDePwPwKi6UKZB8GwNC7-kSf1-BO2af8kqVA/edit). The [COVID Tracking Project](https://covidtracking.com/) collects as much information as possible from each local health authority's website and puts everything together in [easy-to-digest tables](https://covidtracking.com/data/), as well as [spreadsheets](https://docs.google.com/spreadsheets/u/2/d/e/2PACX-1vRwAqp96T9sYYq2-i7Tj0pvTf6XVHjDSMIKBdZHXiCGGdNC0ypEU9NbngS8mxea55JuCFuua1MUeOj5/pubhtml) and a [public API](https://covidtracking.com/api/).
The maintainers are also [fully transparent](https://covidtracking.com/about-tracker/) about their process and take great care to annotate individual figures with the methodology used to arrive at each, which has earned them the [trust](https://covidtracking.com/#press) of even the largest national news organizations reporting on COVID-19.
<figure>
<a class="no-underline" href="https://covidtracking.com/" target="_blank" rel="noopener noreferrer">
<a className="no-underline" href="https://covidtracking.com/" target="_blank" rel="noopener noreferrer">
<img
className="center"
src="/static/images/notes/coronavirus-open-source/covidtracking.png"
@ -33,14 +36,14 @@ The maintainers are also [fully transparent](https://covidtracking.com/about-tra
</a>
</figure>
## [#findthemasks](https://findthemasks.com/) <octocat repo="r-pop/findthemasks" />
## [#findthemasks](https://findthemasks.com/) <Octocat repo="r-pop/findthemasks" />
This one might be my favorite, simply because of its laser-like focus on solving a very specific (yet catastrophic) problem. The United States is [already running out](https://www.nytimes.com/2020/03/19/health/coronavirus-masks-shortage.html) of [personal protective equipment (PPE)](https://www.fda.gov/medical-devices/general-hospital-devices-and-supplies/personal-protective-equipment-infection-control) for the healthcare professionals on the front lines of this crisis. [#findthemasks.com](https://findthemasks.com/) has gathered specific donation requests and points of contact from hospitals around the country in desperate need of basic supplies.
_Please_ look up your local hospitals on [#findthemasks](https://findthemasks.com/#sites) and follow their instructions to donate anything you have hoarded — it's likely the single most impactful thing you can do at this point. If you don't see your local hospital, or don't feel comfortable shipping equipment to any hospital listed, you can also visit [PPE Link](https://ppelink.org/ppe-donations/) and they will connect you with hospitals in your area.
<figure>
<a class="no-underline" href="https://findthemasks.com/" target="_blank" rel="noopener noreferrer">
<a className="no-underline" href="https://findthemasks.com/" target="_blank" rel="noopener noreferrer">
<img
className="center"
src="/static/images/notes/coronavirus-open-source/findthemasks.png"
@ -51,14 +54,14 @@ _Please_ look up your local hospitals on [#findthemasks](https://findthemasks.co
</a>
</figure>
## [#StayTheFuckHome](https://staythefuckhome.com/) <octocat repo="flore2003/staythefuckhome" />
## [#StayTheFuckHome](https://staythefuckhome.com/) <Octocat repo="flore2003/staythefuckhome" />
I figured I'd throw in this cheeky website broadcasting a simple but serious message: **STAY THE FUCK HOME!!!** If you're _still_ not convinced of the importance of this "suggestion," give their ["Self-Quarantine Manifesto"](https://staythefuckhome.com/) a quick read. Now.
The [GitHub community](https://github.com/flore2003/staythefuckhome/pulls?q=is%3Apr) has translated the instructional essay into over a dozen different languages — including a [safe-for-work version](https://staythefuckhome.com/sfw/), if that helps — and they're [looking for more translators](https://github.com/flore2003/staythefuckhome#contributing) if you're multilingual and need something besides Netflix to fill your time with while you **_stay the fuck home!_** 😉
<figure>
<a class="no-underline" href="https://staythefuckhome.com/" target="_blank" rel="noopener noreferrer">
<a className="no-underline" href="https://staythefuckhome.com/" target="_blank" rel="noopener noreferrer">
<img
className="center"
src="/static/images/notes/coronavirus-open-source/staythefuckhome.png"
@ -69,12 +72,12 @@ The [GitHub community](https://github.com/flore2003/staythefuckhome/pulls?q=is%3
</a>
</figure>
## [COVID-19 Dashboards](https://covid19dashboards.com/) <octocat repo="github/covid19-dashboard" />
## [COVID-19 Dashboards](https://covid19dashboards.com/) <Octocat repo="github/covid19-dashboard" />
This collection of various visualizations is fascinating (and sobering) to look at. If you're smarter than I am and have experience in data analysis, their team (led by a [GitHub engineer](https://github.com/hamelsmu)) would be more than happy to [add your contribution](https://github.com/github/covid19-dashboard/blob/master/CONTRIBUTING.md) to the site — they're using [Jupyter Notebooks](https://jupyter.org/) and [fastpages](https://github.com/fastai/fastpages).
<figure>
<a class="no-underline" href="https://covid19dashboards.com/" target="_blank" rel="noopener noreferrer">
<a className="no-underline" href="https://covid19dashboards.com/" target="_blank" rel="noopener noreferrer">
<img
className="center"
src="/static/images/notes/coronavirus-open-source/covid19dashboards.png"
@ -85,12 +88,12 @@ This collection of various visualizations is fascinating (and sobering) to look
</a>
</figure>
## [CoronaTracker](https://coronatracker.samabox.com/) <octocat repo="MhdHejazi/CoronaTracker" />
## [CoronaTracker](https://coronatracker.samabox.com/) <Octocat repo="MhdHejazi/CoronaTracker" />
CoronaTracker is a _beautiful_ cross-platform app for iOS and macOS with intuitive maps and charts fed by reputable live data. Apple is [being justifiably picky](https://developer.apple.com/news/?id=03142020a) about "non-official" Coronavirus apps in their App Store ([so is Google](https://blog.google/inside-google/company-announcements/coronavirus-covid19-response/), by the way) but you can still [download the macOS app directly](https://coronatracker.samabox.com/) or [compile the iOS source code](https://github.com/MhdHejazi/CoronaTracker#1-ios-app) yourself using Xcode if you wish.
<figure>
<a class="no-underline" href="https://coronatracker.samabox.com/" target="_blank" rel="noopener noreferrer">
<a className="no-underline" href="https://coronatracker.samabox.com/" target="_blank" rel="noopener noreferrer">
<img
src="/static/images/notes/coronavirus-open-source/coronatracker.png"
width="865"
@ -100,12 +103,12 @@ CoronaTracker is a _beautiful_ cross-platform app for iOS and macOS with intuiti
</a>
</figure>
## [Staying Home Club](https://stayinghome.club/) <octocat repo="phildini/stayinghomeclub" />
## [Staying Home Club](https://stayinghome.club/) <Octocat repo="phildini/stayinghomeclub" />
A bit more family-friendly than [#StayTheFuckHome](https://staythefuckhome.com/), the [Staying Home Club](https://stayinghome.club/) is maintaining a running list of over a thousand companies and universities mandating that employees and students work from home, as well as events that have been canceled or moved online. Quarantining yourself might feel lonely, but here's solid proof that you're far from alone right now.
<figure>
<a class="no-underline" href="https://stayinghome.club/" target="_blank" rel="noopener noreferrer">
<a className="no-underline" href="https://stayinghome.club/" target="_blank" rel="noopener noreferrer">
<img
className="center"
src="/static/images/notes/coronavirus-open-source/stayinghome.png"
@ -116,12 +119,12 @@ A bit more family-friendly than [#StayTheFuckHome](https://staythefuckhome.com/)
</a>
</figure>
## [Nextstrain for nCoV](https://nextstrain.org/ncov) <octocat repo="nextstrain/ncov" />
## [Nextstrain for nCoV](https://nextstrain.org/ncov) <Octocat repo="nextstrain/ncov" />
This one is a bit over my head, but apparently [Nextstrain](https://nextstrain.org/) is a pretty impressive open-source service targeted at genome data analysis and visualization of different pathogens. Their [COVID-19 page](https://nextstrain.org/ncov) is still awe-inspiring to look at for a layman like me, but probably a thousand times more so if you're an actual scientist — in which case, the [genome data they've open-sourced](https://github.com/nextstrain/ncov) might be of interest to you.
<figure>
<a class="no-underline" href="https://nextstrain.org/ncov" target="_blank" rel="noopener noreferrer">
<a className="no-underline" href="https://nextstrain.org/ncov" target="_blank" rel="noopener noreferrer">
<img
src="/static/images/notes/coronavirus-open-source/nextstrain.png"
width="865"
@ -131,13 +134,13 @@ This one is a bit over my head, but apparently [Nextstrain](https://nextstrain.o
</a>
</figure>
## [Johns Hopkins 2019-nCoV Data](https://systems.jhu.edu/research/public-health/ncov/) <octocat repo="CSSEGISandData/COVID-19" />
## [Johns Hopkins 2019-nCoV Data](https://systems.jhu.edu/research/public-health/ncov/) <Octocat repo="CSSEGISandData/COVID-19" />
Johns Hopkins University's [visual COVID-19 global dashboard](https://www.arcgis.com/apps/opsdashboard/index.html#/bda7594740fd40299423467b48e9ecf6) has been bookmarked as my go-to source of information since the beginning of this crisis earlier this year. Now, JHU's [Center for Systems Science and Engineering](https://systems.jhu.edu/) has open-sourced [their data and analysis](https://github.com/CSSEGISandData/COVID-19) for anybody to use.
<figure>
<a
class="no-underline"
className="no-underline"
href="https://systems.jhu.edu/research/public-health/ncov/"
target="_blank"
rel="noopener noreferrer"
@ -151,14 +154,14 @@ Johns Hopkins University's [visual COVID-19 global dashboard](https://www.arcgis
</a>
</figure>
## [COVID-19 Scenarios](https://neherlab.org/covid19/) <octocat repo="neherlab/covid19_scenarios" />
## [COVID-19 Scenarios](https://neherlab.org/covid19/) <Octocat repo="neherlab/covid19_scenarios" />
COVID-19 Scenarios will probably hit everyone in a different way, depending on your levels of optimism and/or pessimism right now. It uses [advanced scientific models](https://neherlab.org/covid19/about) to predict the future of the virus based on past data and future variables and assumptions you can tinker with yourself.
The maintainers at the [Neher Lab in Basel, Switzerland](https://neherlab.org/) even have a [discussion thread](https://github.com/neherlab/covid19_scenarios/issues/18) and an [open chatroom](https://spectrum.chat/covid19-scenarios/general/questions-discussions~8d49f461-a890-4beb-84f7-2d6ed0ae503a) set up for both scientists and non-scientists to ask questions and post ideas, which I find really nice of them!
<figure>
<a class="no-underline" href="https://neherlab.org/covid19/" target="_blank" rel="noopener noreferrer">
<a className="no-underline" href="https://neherlab.org/covid19/" target="_blank" rel="noopener noreferrer">
<img
className="center"
src="/static/images/notes/coronavirus-open-source/scenarios.png"
@ -169,12 +172,12 @@ The maintainers at the [Neher Lab in Basel, Switzerland](https://neherlab.org/)
</a>
</figure>
## [Corona Data Scraper](https://coronadatascraper.com/#home) <octocat repo="lazd/coronadatascraper" />
## [Corona Data Scraper](https://coronadatascraper.com/#home) <Octocat repo="lazd/coronadatascraper" />
Similar to the [COVID Tracking Project](https://covidtracking.com/) above, the [Corona Data Scraper](https://coronadatascraper.com/#home) has set up an automated process to scrape verified data from across the web to form massive CSV spreadsheets and JSON objects. They even [rate the quality](https://github.com/lazd/coronadatascraper#source-rating) of each source to prioritize data accordingly.
<figure>
<a class="no-underline" href="https://coronadatascraper.com/#home" target="_blank" rel="noopener noreferrer">
<a className="no-underline" href="https://coronadatascraper.com/#home" target="_blank" rel="noopener noreferrer">
<img
className="center"
src="/static/images/notes/coronavirus-open-source/coronadatascraper.png"
@ -185,7 +188,7 @@ Similar to the [COVID Tracking Project](https://covidtracking.com/) above, the [
</a>
</figure>
## [Folding@home](https://foldingathome.org/covid19/) <octocat repo="FoldingAtHome/coronavirus" />
## [Folding@home](https://foldingathome.org/covid19/) <Octocat repo="FoldingAtHome/coronavirus" />
[Folding@home](https://foldingathome.org/) has been around [_forever_](https://en.wikipedia.org/wiki/Folding@home). I remember installing it on my family's home computer as a curious kid and making my father infuriated over how slow it got. But they [switched gears this month](https://foldingathome.org/2020/03/15/coronavirus-what-were-doing-and-how-you-can-help-in-simple-terms/) from using our computers to crunch various proteins and molecules in the background, and all of their power is now going towards discovering unknown "folds" in the coronavirus, which might be able to lead scientists to find better cures and potential vaccines.
@ -193,15 +196,15 @@ You can [download their software here](https://foldingathome.org/start-folding/)
**Fun fact:** The team behind Folding@home has seen a [**huge** spike in computational power](https://www.reddit.com/r/pcmasterrace/comments/flgm7q/ama_with_the_team_behind_foldinghome_coronavirus/) this month after cryptominers started mining coronavirus proteins instead of boring, old Ethereum with their insanely overpowered GPUs! 👏
<video url="https://www.youtube-nocookie.com/watch?v=NTLU1anxe8c" controls />
<Video url="https://www.youtube-nocookie.com/watch?v=NTLU1anxe8c" controls />
## [Coronavirus Tracker API](https://coronavirus-tracker-api.herokuapp.com/v2/locations) <octocat repo="ExpDev07/coronavirus-tracker-api" />
## [Coronavirus Tracker API](https://coronavirus-tracker-api.herokuapp.com/v2/locations) <Octocat repo="ExpDev07/coronavirus-tracker-api" />
To wrap this list up, I thought I'd include [yet another API](https://github.com/ExpDev07/coronavirus-tracker-api) fed by multiple data sources that you can use to create your own open-source project if any of these inspired you. This one is incredibly flexible in terms of [query parameters and endpoints](https://github.com/ExpDev07/coronavirus-tracker-api#api-endpoints) but they all return simple JSON responses like we all know and love.
<figure>
<a
class="no-underline"
className="no-underline"
href="https://coronavirus-tracker-api.herokuapp.com/v2/locations"
target="_blank"
rel="noopener noreferrer"

View File

@ -28,7 +28,7 @@ Below are the code snippets you can grab and customize to make your own ["waving
## CSS
<!-- prettier-ignore -->
{/* prettier-ignore */}
```css
.wave {
animation-name: wave-animation; /* Refers to the name of your @keyframes element below */

View File

@ -91,7 +91,7 @@ The [example HTML and CSS below](#html-css) is still helpful for reference.
### [Minified JS](https://raw.githubusercontent.com/jakejarvis/dark-mode-example/gh-pages/dark-mode.min.js) (410 bytes gzipped! 📦):
<!-- prettier-ignore -->
{/* prettier-ignore */}
```js
/*! Dark mode switcheroo | MIT License | jrvs.io/darkmode */
(function(){var e=window,t=e.document,i=t.body.classList,a=localStorage,c="dark_mode_pref",d=a.getItem(c),n="dark",o="light",r=o,s=t.querySelector(".dark-mode-toggle"),m=r===n,l=function(e){i.remove(n,o);i.add(e);m=e===n};d===n&&l(n);d===o&&l(o);if(!d){var f=function(e){return"(prefers-color-scheme: "+e+")"};e.matchMedia(f(n)).matches?l(n):e.matchMedia(f(o)).matches?l(o):l(r);e.matchMedia(f(n)).addListener((function(e){e.matches&&l(n)}));e.matchMedia(f(o)).addListener((function(e){e.matches&&l(o)}))}if(s){s.style.visibility="visible";s.addEventListener("click",(function(){if(m){l(o);a.setItem(c,o)}else{l(n);a.setItem(c,n)}}),!0)}})();
@ -99,7 +99,7 @@ The [example HTML and CSS below](#html-css) is still helpful for reference.
### Full JS:
<!-- prettier-ignore -->
{/* prettier-ignore */}
```js
/*! Dark mode switcheroo | MIT License | jrvs.io/darkmode */
@ -182,7 +182,7 @@ The [example HTML and CSS below](#html-css) is still helpful for reference.
### HTML & CSS Example:
<!-- prettier-ignore -->
{/* prettier-ignore */}
```html
<!doctype html>
<html>

View File

@ -11,7 +11,10 @@ tags:
image: "/static/images/notes/dropping-dropbox/email.png"
---
I've been a loyal Dropbox user since its inception as a [Y Combinator startup](https://www.ycombinator.com/apply/dropbox/) ten years ago. Having a folder on all of my devices that instantly synchronized with each other was a game-changer for me, and I grew dependent on it more and more as they gave out free storage like candy — 48 GB for having a Samsung Chromebook, 1 GB for "Posting <3 to Twitter," and so on — until I needed to upgrade to Dropbox Pro. But this month I canceled my Pro subscription after a few too many strikes.
import Tweet from "./components/embeds/Tweet";
import Video from "./components/embeds/Video";
I've been a loyal Dropbox user since its inception as a [Y Combinator startup](https://www.ycombinator.com/apply/dropbox/) ten years ago. Having a folder on all of my devices that instantly synchronized with each other was a game-changer for me, and I grew dependent on it more and more as they gave out free storage like candy — 48 GB for having a Samsung Chromebook, 1 GB for "Posting \<3 to Twitter," and so on — until I needed to upgrade to Dropbox Pro. But this month I canceled my Pro subscription after a few too many strikes.
<figure>
<img
@ -31,12 +34,12 @@ Decisions made by the top folks at Dropbox gave me an increasingly sour taste in
- Adding a [3-device limit](https://help.dropbox.com/account/computer-limit) for free accounts, triggering another hostage negotiation resulting in me upgrading to Pro.
- Continuously forcing [bloated updates](https://www.theverge.com/2019/6/11/18661673/new-dropbox-desktop-app-google-docs-slack-atlassian) to their once-simple macOS app down users' throats, to the point where ["the new Dropbox"](https://blog.dropbox.com/topics/product-tips/new-dropbox) was consistently eating up _over a gigabyte of RAM_ and a non-negligible chunk of CPU usage thanks to an entire web browser being embedded into it:
<tweet id="1138686582859239425" />
<Tweet id="1138686582859239425" />
- Explicitly [dropping support for symlinking](https://news.ycombinator.com/item?id=20844363) (aka making aliases to) files outside of the literal `~/Dropbox` folder, which was incredibly helpful for nerds — once their main audience and biggest cheerleaders — with things like [dotfiles](https://github.com/jakejarvis/dotfiles) and Git repositories.
- ...and as a bonus, making the process of canceling Dropbox Pro incredibly convoluted, annoying, and sketchy. Here's a video demonstration via [Justin Dunham](https://twitter.com/jwyattd):
<video
<Video
url={[
{ src: "/static/images/notes/dropping-dropbox/cancel.webm", type: "video/webm" },
{ src: "/static/images/notes/dropping-dropbox/cancel.mp4", type: "video/mp4" },

View File

@ -11,6 +11,8 @@ tags:
image: "/static/images/notes/github-actions/actions-flow.png"
---
import Gist from "./components/embeds/Gist";
<img
className="center"
src="/static/images/notes/github-actions/actions-flow.png"
@ -51,15 +53,15 @@ Here are the actions I've made so far, sorted by popularity as of this posting:
As an example of an _extremely_ simple (and almost completely unnecessary) action, the [Wait action](https://github.com/jakejarvis/wait-action) takes one input — a unit of time — and has the pipeline sleep for that amount of time. The [`Dockerfile`](https://github.com/jakejarvis/wait-action/blob/master/Dockerfile) is as simple as this:
<gist id="6a0830c7c3e514980b30fdf86b4931c5" file="Dockerfile" />
<Gist id="6a0830c7c3e514980b30fdf86b4931c5" file="Dockerfile" />
...with a super-short [`entrypoint.sh`](https://github.com/jakejarvis/wait-action/blob/master/entrypoint.sh):
<gist id="6a0830c7c3e514980b30fdf86b4931c5" file="entrypoint.sh" />
<Gist id="6a0830c7c3e514980b30fdf86b4931c5" file="entrypoint.sh" />
Using an action is also surprisingly simple, and more intuitive than [Travis CI](https://travis-ci.com/) or [CircleCI](https://circleci.com/), in my humble opinion. Pipelines in GitHub Actions are called ["workflows,"](https://help.github.com/en/github/automating-your-workflow-with-github-actions/configuring-a-workflow) and live in a file with [YAML syntax](https://help.github.com/en/github/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions) in `.github/workflows`. An example of a `workflow.yml` file that uses the above action to wait 10 seconds (on both pushes and pull requests) would look something like:
<gist id="6a0830c7c3e514980b30fdf86b4931c5" file="workflow.yml" />
<Gist id="6a0830c7c3e514980b30fdf86b4931c5" file="workflow.yml" />
---

View File

@ -12,13 +12,15 @@ tags:
image: "/static/images/notes/github-rename-master/github-default.png"
---
import Tweet from "./components/embeds/Tweet";
<img src="/static/images/notes/github-rename-master/blm-topic.png" width="865" height="162" alt="Black lives matter." />
In the midst of this year's long-overdue support of the [**Black Lives Matter**](https://blacklivesmatters.carrd.co/) movement and calls to action in the US and around the world, a [new spotlight](https://mail.gnome.org/archives/desktop-devel-list/2019-May/msg00066.html) has been placed on unchecked invocations of racially charged language in the computer science world, no matter how big or small — like the long-standing and, until recently, widely accepted terms ["master" and "slave"](https://tools.ietf.org/id/draft-knodel-terminology-00.html#master-slave) as an oppressive metaphor for ownership/importance.
When somebody pointed out the negative connotations of Git projects being created with a branch named `master` by default, and the possibility of this making minorities feel even more unwelcome in an industry already [lacking diversity](https://www.informationisbeautiful.net/visualizations/diversity-in-tech/), GitHub CEO [Nat Friedman](https://github.com/nat) quietly [announced a plan](https://twitter.com/natfriedman/status/1271253144442253312) to change this on Twitter (ignore the replies for your sanity):
<tweet id="1271253144442253312" />
<Tweet id="1271253144442253312" />
I think many people misunderstood this tweet to mean GitHub will forcefully rename the `master` branch of all existing projects, which would break _millions_ of programmers' workflows. If anything, it's more likely a name such as `main` will replace `master` as **the default when creating a new repository**, but that change hasn't been made yet. [GitLab is also discussing](https://gitlab.com/gitlab-org/gitlab/-/issues/221164) a similar switch to `main` as the default name. (Ideally, these changes would be made in tandem with the actual Git codebase, too. [~~But this doesn't seem likely.~~](https://lore.kernel.org/git/CAOAHyQwyXC1Z3v7BZAC+Bq6JBaM7FvBenA-1fcqeDV==apdWDg@mail.gmail.com/t/))

View File

@ -12,6 +12,8 @@ tags:
image: "/static/images/notes/how-to-backup-linux-server/apocalypse.png"
---
import Tweet from "./components/embeds/Tweet";
<figure>
<img
src="/static/images/notes/how-to-backup-linux-server/apocalypse.png"
@ -26,7 +28,7 @@ image: "/static/images/notes/how-to-backup-linux-server/apocalypse.png"
Last month, the founder of [a small startup](https://raisup.com/) got quite a bit of [attention on Twitter](https://twitter.com/w3Nicolas/status/1134529316904153089) (and [Hacker News](https://news.ycombinator.com/item?id=20064169)) when he called out [DigitalOcean](https://www.digitalocean.com/) who, in his words, "killed" his company. Long story short: DigitalOcean's automated abuse system flagged the startup's account after they spun up about ten powerful droplets for some CPU-intensive jobs and deleted them shortly after — which is literally **the biggest selling point** of a "servers by the hour" company like DigitalOcean, by the way — and, after replying to the support ticket, an unsympathetic customer support agent [declined to reactivate](https://twitter.com/w3Nicolas/status/1134529372172509184) the account without explanation. [Nicolas](https://twitter.com/w3Nicolas) had no way of even accessing his data, turning the inconvenient but trivial task of migrating servers into a potentially fatal situation for his company.
<tweet id="1134529316904153089" />
<Tweet id="1134529316904153089" />
Predictably, there were [a](https://twitter.com/kolaente/status/1134897543643615238) [lot](https://twitter.com/hwkfr/status/1135164281731911681) [of](https://twitter.com/joestarstuff/status/1135406188114276352) [Monday](https://twitter.com/FearbySoftware/status/1134717875351052288)-[morning](https://twitter.com/mkozak/status/1134557954785587200) [quarterbacks](https://twitter.com/MichMich/status/1134547174447026181) who weighed in, scolding him for not having backups ([he did](https://twitter.com/w3Nicolas/status/1134529374676500482), but they were also stored on DigitalOcean) and not paying a boatload of non-existent money for expensive load balancers pointing to multiple cloud providers. Hindsight is always 20/20, of course, but if we're talking about a small side project that exploded into a full-fledged startup with Fortune 500 clients seemingly overnight, I _completely_ understand Nicolas' thought process. _"Let's just take advantage of cloud computing's #1 selling point: press a few buttons to make our servers [harder, better, faster, stronger](https://www.youtube.com/watch?v=x84m3YyO2oU) and get back to coding!"_

View File

@ -10,6 +10,9 @@ tags:
image: "/static/images/notes/millenial-with-hillary-clinton/24707394571_0818d4ab83_o-1-copy.jpg"
---
import Video from "./components/embeds/Video";
{/* prettier-ignore */}
<figure>
<img
src="/static/images/notes/millenial-with-hillary-clinton/24707394571_0818d4ab83_o-1-copy.jpg"
@ -18,18 +21,7 @@ image: "/static/images/notes/millenial-with-hillary-clinton/24707394571_0818d4ab
alt="Hillary for New Hampshire Winter Fellows with Hillary Clinton in Derry, NH (February 3, 2016)"
/>
<figcaption>
<a href="https://medium.com/@HillaryForNH" target="_blank" rel="noopener noreferrer">
Hillary for New Hampshire
</a>{" "}
Winter Fellows with{" "}
<a href="https://medium.com/@HillaryClinton" target="_blank" rel="noopener noreferrer">
Hillary Clinton
</a>{" "}
in Derry, NH (
<a href="https://www.flickr.com/photos/hillaryclinton/24707394571/" target="_blank" rel="noopener noreferrer">
February 3, 2016
</a>
)
<a href="https://medium.com/@HillaryForNH" target="_blank" rel="noopener noreferrer">Hillary for New Hampshire</a> Winter Fellows with <a href="https://medium.com/@HillaryClinton" target="_blank" rel="noopener noreferrer">Hillary Clinton</a> in Derry, NH (<a href="https://www.flickr.com/photos/hillaryclinton/24707394571/" target="_blank" rel="noopener noreferrer">February 3, 2016</a>)
</figcaption>
</figure>
@ -65,13 +57,13 @@ I'm aware of the street cred young Democrats collect by claiming they hated Hill
As [Bill Maher](https://medium.com/u/cdc04a9799f6) (an avid Bernie supporter) [said this weekend](https://www.youtube.com/watch?v=rd1gpjkjcfc), some in our party need to "learn the difference between an imperfect friend and a deadly enemy." I don't agree with everything Hillary has said or done. I don't unconditionally defend every single chapter in her public record over the past 30 years (and [neither does she](https://www.washingtonpost.com/blogs/post-partisan/wp/2016/02/25/hillary-clinton-responds-to-activist-who-demanded-apology-for-superpredator-remarks/), by the way). I don't think that's possible for any voter to find in a politician. But if you identify as a Democrat, she is the farthest thing from your enemy. Plain and simple. Like you and Bernie, she wants to prevent a Republican from winning in November and reversing so much of the progress we've made over the past seven years on their first day in office. That is our number one goal right now. And whether it gets accomplished by a President Clinton or a President Sanders, I am 100% on board either way. Let's stop fighting each other and start fighting together.
<video url="https://www.youtube-nocookie.com/watch?v=TqrwDMTByNM" controls />
<Video url="https://www.youtube-nocookie.com/watch?v=TqrwDMTByNM" controls />
---
**Update:** The campaign has included my snowy New Hampshire interaction with her in one of the DNC convention videos! See a few short seconds of my joy at 1:24.
<video
<Video
url={[
{ src: "/static/images/hillary/convention-720p.webm", type: "video/webm" },
{ src: "/static/images/hillary/convention-720p.mp4", type: "video/mp4" },

View File

@ -35,7 +35,7 @@ Hopefully we can all look back at our first projects and be proud of how far we'
---
<figure>
<a class="no-underline" href="https://github.com/jakejarvis/jbb" target="_blank" rel="noopener noreferrer">
<a className="no-underline" href="https://github.com/jakejarvis/jbb" target="_blank" rel="noopener noreferrer">
<img src="/static/images/notes/my-first-code/jbb-logo.png" width="640" height="80" alt="Jake's Bulletin Board" />
</a>
<figcaption>

View File

@ -11,14 +11,11 @@ tags:
image: "/static/images/notes/no-homo-still-raps-motto/1_b41ztscbaxqi60snwsswfw.jpg"
---
{/* prettier-ignore */}
<figure>
<img src="/static/images/notes/no-homo-still-raps-motto/1_b41ztscbaxqi60snwsswfw.jpg" width="865" height="364" />
<figcaption>
This essay was written for Professor David Valdes-Greenwood's "Love & Sexuality" class at{" "}
<a href="https://www.tufts.edu/" target="_blank" rel="noopener noreferrer">
Tufts University
</a>{" "}
in April 2012.
This essay was written for Professor David Valdes-Greenwood's "Love & Sexuality" class at <a href="https://www.tufts.edu/" target="_blank" rel="noopener noreferrer"> Tufts University </a> in April 2012.
</figcaption>
</figure>

View File

@ -10,6 +10,8 @@ tags:
image: "/static/images/notes/presidential-candidates-404-pages/obama-laughing.jpg"
---
import Video from "./components/embeds/Video";
<figure>
<img
src="/static/images/notes/presidential-candidates-404-pages/obama-laughing.jpg"
@ -39,7 +41,7 @@ I'm a _huge_ sucker for Kate McKinnon's spot-on impression of Warren on Saturday
Although the designer who selected this GIF likely had _thousands_ of choices when searching "[Bernie finger wagging GIF](https://www.google.com/search?q=Bernie+finger+wagging+GIF&tbm=isch&tbs=itp:animated)," the text beside it is well-written and funny — even though we both know putting a page at [berniesanders.com/zxcliaosid](https://berniesanders.com/zxcliaosid/) probably won't be a top priority of a President Sanders.
<video
<Video
url={[
{ src: "/static/images/notes/presidential-candidates-404-pages/sanders.webm", type: "video/webm" },
{ src: "/static/images/notes/presidential-candidates-404-pages/sanders.mp4", type: "video/mp4" },
@ -67,7 +69,7 @@ Uncle Joe has a nice and simple 404 page. I like it, along with the Ray-Bans and
A ballsy move, considering Beto's infamous [DUI arrest](https://www.politifact.com/texas/statements/2019/mar/14/club-growth/beto-orourke-arrested-dwi-flee-scene/) in the '90s — but still a clever ask for a donation and a great use of a GIF, even if it's left over from his Senate campaign.
<video
<Video
url={[
{ src: "/static/images/notes/presidential-candidates-404-pages/orourke.webm", type: "video/webm" },
{ src: "/static/images/notes/presidential-candidates-404-pages/orourke.mp4", type: "video/mp4" },
@ -89,7 +91,7 @@ A ballsy move, considering Beto's infamous [DUI arrest](https://www.politifact.c
Another clean and simple page with a top-notch GIF. It injected some emotion into visiting [kamalaharris.com/alskdjf](https://kamalaharris.com/alskdjf).
<video
<Video
url={[
{ src: "/static/images/notes/presidential-candidates-404-pages/harris.webm", type: "video/webm" },
{ src: "/static/images/notes/presidential-candidates-404-pages/harris.mp4", type: "video/mp4" },

View File

@ -11,6 +11,7 @@ tags:
image: "/static/images/notes/security-headers-cloudflare-workers/security-headers.png"
---
{/* prettier-ignore */}
<figure>
<img
src="/static/images/notes/security-headers-cloudflare-workers/security-headers.png"
@ -19,11 +20,7 @@ image: "/static/images/notes/security-headers-cloudflare-workers/security-header
alt="An A+ security grade for this website!"
/>
<figcaption>
An{" "}
<a href="https://securityheaders.com/?q=jarv.is&amp;followRedirects=on" target="_blank" rel="noopener noreferrer">
A+ security grade
</a>{" "}
for this website!
An <a href="https://securityheaders.com/?q=jarv.is&amp;followRedirects=on" target="_blank" rel="noopener noreferrer">A+ security grade</a> for this website!
</figcaption>
</figure>

View File

@ -14,7 +14,7 @@ image: "/static/images/notes/shodan-search-queries/shodan.png"
Over time, I've collected an assortment of interesting, funny, and depressing search queries to plug into [Shodan](https://www.shodan.io/), the ([literal](https://www.vice.com/en_uk/article/9bvxmd/shodan-exposes-the-dark-side-of-the-net)) internet search engine. Some return facepalm-inducing results, while others return serious and/or ancient vulnerabilities in the wild.
<figure>
<a class="no-underline" href="https://account.shodan.io/register" target="_blank" rel="noopener noreferrer">
<a className="no-underline" href="https://account.shodan.io/register" target="_blank" rel="noopener noreferrer">
<img
src="/static/images/notes/shodan-search-queries/shodan.png"
width="865"

View File

@ -15,7 +15,7 @@ A few months ago, I stumbled upon [my first website ever](https://jakejarvis.git
Introducing the [**Y2K Sandbox**](https://y2k.app/) — with fully-featured, fully-isolated, on-demand [**Windows Millennium Edition®**](https://www.youtube.com/watch?v=CaNDeyYP98A) virtual machines, simply to experience my first website in its natural Internet Explorer 5 habitat. And maybe play some [3D Pinball: Space Cadet](https://en.wikipedia.org/wiki/Full_Tilt!_Pinball#3D_Pinball_for_Windows_%E2%80%93_Space_Cadet). Oh, and [Microsoft Bob](https://en.wikipedia.org/wiki/Microsoft_Bob) is there too if you want to say hello and catch up. 🤓
<figure>
<a class="no-underline" href="https://y2k.app/" target="_blank" rel="noopener noreferrer">
<a className="no-underline" href="https://y2k.app/" target="_blank" rel="noopener noreferrer">
<img
src="/static/images/notes/y2k-sandbox/screenshot.png"
width="865"

View File

@ -27,8 +27,6 @@
"@fontsource/inter": "4.5.1",
"@fontsource/roboto-mono": "4.5.0",
"@hcaptcha/react-hcaptcha": "^1.0.0",
"@mdx-js/loader": "^1.6.22",
"@mdx-js/react": "^1.6.22",
"@next/bundle-analyzer": "^12.0.7",
"@octokit/graphql": "^4.8.0",
"@primer/octicons-react": "^16.2.0",
@ -46,10 +44,10 @@
"is-absolute-url": "^4.0.1",
"is-email-like": "^2.0.0",
"markdown-to-jsx": "^7.1.5",
"mdx-bundler": "^8.0.1",
"modern-normalize": "github:sindresorhus/modern-normalize#1fc6b5a86676b7ac8abc62d04d6080f92debc70f",
"next": "v12.0.8-canary.19",
"next-compose-plugins": "^2.2.1",
"next-mdx-remote": "^3.0.8",
"next-seo": "^4.28.1",
"next-themes": "^0.0.15",
"node-fetch": "^3.1.0",
@ -63,10 +61,12 @@
"react-is": "^17.0.2",
"react-player": "^2.9.0",
"react-tweet-embed": "^1.3.1",
"reading-time": "^1.5.0",
"rehype-autolink-headings": "^6.1.1",
"rehype-external-links": "^1.0.1",
"rehype-highlight": "^5.0.2",
"rehype-slug": "^5.0.1",
"remark-gfm": "^3.0.1",
"styled-jsx": "^4.0.1",
"swr": "^1.1.2"
},
@ -80,6 +80,7 @@
"@types/react-is": "^17.0.3",
"autoprefixer": "^10.4.2",
"cross-env": "^7.0.3",
"esbuild": "^0.14.11",
"eslint": "~8.6.0",
"eslint-config-next": "~12.0.7",
"eslint-config-prettier": "~8.3.0",

View File

@ -1,7 +1,7 @@
import { NextSeo } from "next-seo";
import Content from "../components/Content";
import PageTitle from "../components/page/PageTitle";
import Video from "../components/video/Video";
import Video from "../components/embeds/Video";
import { TapeIcon } from "../components/icons";
import thumbnail from "../public/static/images/birthday/thumb.png";

View File

@ -1,7 +1,7 @@
import { NextSeo } from "next-seo";
import Content from "../components/Content";
import PageTitle from "../components/page/PageTitle";
import Video from "../components/video/Video";
import Video from "../components/embeds/Video";
import thumbnail from "../public/static/images/hillary/thumb.png";

View File

@ -1,7 +1,7 @@
import { NextSeo } from "next-seo";
import Content from "../components/Content";
import PageTitle from "../components/page/PageTitle";
import Video from "../components/video/Video";
import Video from "../components/embeds/Video";
import thumbnail from "../public/static/images/leo/thumb.png";

View File

@ -1,90 +1,76 @@
import { MDXRemote } from "next-mdx-remote";
import { serialize } from "next-mdx-remote/serialize";
import { useMemo } from "react";
import dynamic from "next/dynamic";
import { NextSeo, ArticleJsonLd } from "next-seo";
import { escape } from "html-escaper";
import { getMDXComponent } from "mdx-bundler/client";
import Content from "../../components/Content";
import Meta from "../../components/notes/Meta";
import Comments from "../../components/notes/Comments";
import mdxComponents from "../../components/mdxComponents";
import { getNoteData, getNoteSlugs } from "../../lib/parse-notes";
import { getNote, getNoteSlugs } from "../../lib/parse-notes";
import * as config from "../../lib/config";
import type { GetStaticProps, GetStaticPaths } from "next";
// mdx plugins
import rehypeHighlight from "rehype-highlight";
import rehypeExternalLinks from "rehype-external-links";
import rehypeSlug from "rehype-slug";
import rehypeAutolinkHeadings from "rehype-autolink-headings";
const Comments = dynamic(() => import("../../components/notes/Comments"), { ssr: false });
const Note = ({ frontMatter, source }) => (
<>
<NextSeo
title={frontMatter.title}
description={frontMatter.description}
canonical={frontMatter.permalink}
openGraph={{
title: frontMatter.title,
url: frontMatter.permalink,
type: "article",
article: {
authors: [config.authorName],
tags: frontMatter.tags,
publishedTime: frontMatter.date,
modifiedTime: frontMatter.date,
},
images: frontMatter.image && [
{
url: `${config.baseUrl}${frontMatter.image}`,
alt: frontMatter.title,
const Note = ({ frontMatter, mdxSource }) => {
const MDXComponent = useMemo(() => getMDXComponent(mdxSource, { process }), [mdxSource]);
return (
<>
<NextSeo
title={frontMatter.title}
description={frontMatter.description}
canonical={frontMatter.permalink}
openGraph={{
title: frontMatter.title,
url: frontMatter.permalink,
type: "article",
article: {
authors: [config.authorName],
tags: frontMatter.tags,
publishedTime: frontMatter.date,
modifiedTime: frontMatter.date,
},
],
}}
twitter={{
cardType: "summary_large_image",
}}
/>
<ArticleJsonLd
url={frontMatter.permalink}
title={escape(frontMatter.title)}
description={escape(frontMatter.description)}
datePublished={frontMatter.date}
dateModified={frontMatter.date}
images={frontMatter.image && [`${config.baseUrl}${frontMatter.image}`]}
authorName={[config.authorName]}
publisherName={config.siteName}
publisherLogo={`${config.baseUrl}/static/images/me.jpg`}
/>
images: frontMatter.image && [
{
url: `${config.baseUrl}${frontMatter.image}`,
alt: frontMatter.title,
},
],
}}
twitter={{
cardType: "summary_large_image",
}}
/>
<ArticleJsonLd
url={frontMatter.permalink}
title={escape(frontMatter.title)}
description={escape(frontMatter.description)}
datePublished={frontMatter.date}
dateModified={frontMatter.date}
images={frontMatter.image && [`${config.baseUrl}${frontMatter.image}`]}
authorName={[config.authorName]}
publisherName={config.siteName}
publisherLogo={`${config.baseUrl}/static/images/me.jpg`}
/>
<Meta {...frontMatter} />
<Content>
<MDXRemote {...source} components={mdxComponents} />
</Content>
<Comments slug={frontMatter.slug} />
</>
);
<Meta {...frontMatter} />
<Content>
{/* @ts-ignore */}
<MDXComponent components={mdxComponents} />
</Content>
<Comments slug={frontMatter.slug} />
</>
);
};
export const getStaticProps: GetStaticProps = async ({ params }) => {
const { frontMatter, content } = getNoteData(params.slug as string);
const source = await serialize(content, {
mdxOptions: {
// remarkPlugins: [],
rehypePlugins: [
[rehypeExternalLinks, { target: "_blank", rel: ["noopener", "noreferrer"] }],
[rehypeSlug, {}],
[
rehypeAutolinkHeadings,
{ behavior: "append", properties: { className: "h-anchor" }, content: [], test: ["h2", "h3"] },
],
[rehypeHighlight, {}],
],
},
});
const { frontMatter, mdxSource } = await getNote(params.slug as string);
return {
props: {
frontMatter,
source,
mdxSource,
},
};
};

View File

@ -58,6 +58,7 @@ pre code {
}
.center {
display: block;
text-align: center;
margin-left: auto;
margin-right: auto;

1905
yarn.lock

File diff suppressed because it is too large Load Diff