mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2025-09-15 04:25:31 -04:00
<IFrame />
component
This commit is contained in:
@@ -3,13 +3,6 @@
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.content blockquote {
|
||||
margin-left: 0;
|
||||
padding-left: 1.5em;
|
||||
border-left: 3px solid var(--link);
|
||||
color: var(--medium-dark);
|
||||
}
|
||||
|
||||
.content h2,
|
||||
.content h3,
|
||||
.content h4 {
|
||||
@@ -43,6 +36,13 @@
|
||||
padding-left: 0.25em;
|
||||
}
|
||||
|
||||
.content blockquote {
|
||||
margin-left: 0;
|
||||
padding-left: 1.5em;
|
||||
border-left: 3px solid var(--link);
|
||||
color: var(--medium-dark);
|
||||
}
|
||||
|
||||
.content hr {
|
||||
margin: 1.5em auto;
|
||||
height: 2px;
|
||||
@@ -50,33 +50,6 @@
|
||||
background-color: var(--light);
|
||||
}
|
||||
|
||||
.content :global(.image_wrapper) {
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
/* default to centering all images */
|
||||
.content :global(.image_wrapper),
|
||||
.content figure {
|
||||
margin: 1em auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content figure :global(.image_wrapper) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.content figure figcaption {
|
||||
margin-top: 0.75em;
|
||||
font-size: 0.9em;
|
||||
line-height: 1.5;
|
||||
color: var(--medium);
|
||||
}
|
||||
|
||||
/* some figcaptions contain paragraphs, some don't, so reset all of them */
|
||||
.content figure figcaption p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* sub-heading anchor styles */
|
||||
.content :global(.h-anchor) {
|
||||
margin: 0 0.25em;
|
||||
|
15
components/Figure/Figure.module.css
Normal file
15
components/Figure/Figure.module.css
Normal file
@@ -0,0 +1,15 @@
|
||||
.figure {
|
||||
margin: 1em auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.caption {
|
||||
font-size: 0.9em;
|
||||
line-height: 1.5;
|
||||
color: var(--medium);
|
||||
}
|
||||
|
||||
/* some figcaptions contain paragraphs, some don't, so reset all of them */
|
||||
.caption p {
|
||||
margin: 0;
|
||||
}
|
@@ -3,6 +3,8 @@ import innerText from "react-innertext";
|
||||
import type { ReactNode } from "react";
|
||||
import type { ImageProps as NextImageProps } from "next/image";
|
||||
|
||||
import styles from "./Figure.module.css";
|
||||
|
||||
type Props = Omit<NextImageProps, "alt"> & {
|
||||
children: ReactNode; // caption (can be in markdown, yay!!!)
|
||||
alt?: string; // becomes optional -- pulled from plaintext-ified caption if missing
|
||||
@@ -10,9 +12,9 @@ type Props = Omit<NextImageProps, "alt"> & {
|
||||
|
||||
const Figure = ({ children, alt, ...imageProps }: Props) => {
|
||||
return (
|
||||
<figure>
|
||||
<figure className={styles.figure}>
|
||||
<Image alt={alt || innerText(children)} {...imageProps} />
|
||||
<figcaption>{children}</figcaption>
|
||||
<figcaption className={styles.caption}>{children}</figcaption>
|
||||
</figure>
|
||||
);
|
||||
};
|
||||
|
6
components/IFrame/IFrame.module.css
Normal file
6
components/IFrame/IFrame.module.css
Normal file
@@ -0,0 +1,6 @@
|
||||
.frame {
|
||||
width: 100%;
|
||||
display: block;
|
||||
margin: 1em auto;
|
||||
border: 2px solid var(--kinda-light);
|
||||
}
|
28
components/IFrame/IFrame.tsx
Normal file
28
components/IFrame/IFrame.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import styles from "./IFrame.module.css";
|
||||
|
||||
type Props = {
|
||||
src: string;
|
||||
title?: string;
|
||||
height: number;
|
||||
width?: number; // defaults to 100%
|
||||
allowScripts?: boolean;
|
||||
noScroll?: boolean;
|
||||
};
|
||||
|
||||
const IFrame = ({ src, title, height, width, allowScripts, noScroll, ...rest }: Props) => (
|
||||
<iframe
|
||||
className={styles.frame}
|
||||
src={src}
|
||||
title={title}
|
||||
sandbox={allowScripts ? "allow-same-origin allow-scripts allow-popups" : undefined}
|
||||
scrolling={noScroll ? "no" : undefined}
|
||||
loading="lazy"
|
||||
style={{
|
||||
height: `${height}px`,
|
||||
maxWidth: width ? `${width}px` : undefined,
|
||||
}}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
|
||||
export default IFrame;
|
7
components/Image/Image.module.css
Normal file
7
components/Image/Image.module.css
Normal file
@@ -0,0 +1,7 @@
|
||||
.wrapper {
|
||||
line-height: 0;
|
||||
|
||||
/* default to centering all images */
|
||||
margin: 1em auto;
|
||||
text-align: center;
|
||||
}
|
@@ -1,9 +1,11 @@
|
||||
import NextImage from "next/image";
|
||||
import type { ImageProps as NextImageProps } from "next/image";
|
||||
|
||||
import styles from "./Image.module.css";
|
||||
|
||||
const Image = ({ src, width, height, alt, quality, priority }: NextImageProps) => {
|
||||
return (
|
||||
<div className="image_wrapper">
|
||||
<div className={styles.wrapper}>
|
||||
<NextImage
|
||||
src={(src as string).replace(/^\/public/g, "")}
|
||||
layout="intrinsic"
|
||||
|
11
components/OctocatLink/OctocatLink.module.css
Normal file
11
components/OctocatLink/OctocatLink.module.css
Normal file
@@ -0,0 +1,11 @@
|
||||
.link {
|
||||
margin: 0 0.4em;
|
||||
color: var(--text);
|
||||
background: none !important;
|
||||
padding-bottom: 0;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
color: var(--link);
|
||||
}
|
@@ -1,17 +1,13 @@
|
||||
import { OctocatOcticon } from "../Icons";
|
||||
|
||||
import styles from "./OctocatLink.module.css";
|
||||
|
||||
type Props = {
|
||||
repo: string;
|
||||
};
|
||||
|
||||
const OctocatLink = (props: Props) => (
|
||||
<a
|
||||
className="no-underline"
|
||||
href={`https://github.com/${props.repo}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={{ margin: "0 0.4em", color: "var(--text)" }}
|
||||
>
|
||||
<a className={styles.link} href={`https://github.com/${props.repo}`} target="_blank" rel="noopener noreferrer">
|
||||
<OctocatOcticon fill="currentColor" />
|
||||
</a>
|
||||
);
|
||||
|
@@ -8,6 +8,7 @@ export { default as code } from "../components/CodeBlock/CodeBlock";
|
||||
|
||||
// All of these components are technically passed into all posts, but next/dynamic ensures they're loaded only
|
||||
// when they're referenced in the individual mdx files.
|
||||
export const IFrame = dynamic(() => import("../components/IFrame/IFrame"));
|
||||
export const Video = dynamic(() => import("../components/Video/Video"));
|
||||
export const YouTube = dynamic(() => import("../components/YouTubeEmbed/YouTubeEmbed"));
|
||||
export const Tweet = dynamic(() => import("../components/TweetEmbed/TweetEmbed"));
|
||||
|
@@ -19,12 +19,12 @@ Below are the code snippets you can grab and customize to make your own ["waving
|
||||
|
||||
## Demo
|
||||
|
||||
<iframe
|
||||
height="500"
|
||||
width="100%"
|
||||
<IFrame
|
||||
src="https://codepen.io/jakejarvis/embed/pBZWZw/?theme-id=light&default-tab=css,result"
|
||||
scrolling="no"
|
||||
></iframe>
|
||||
height={500}
|
||||
allowScripts
|
||||
noScroll
|
||||
/>
|
||||
|
||||
## CSS
|
||||
|
||||
|
@@ -29,21 +29,14 @@ I've written a simple implementation below, which...
|
||||
|
||||
...meaning that any CSS selectors beginning with `body.dark` or `body.light` will only apply when the respective mode is active. A good place to start is by separating any color rules — your background, text, links, etc. — into a different section of your CSS. Using [SASS or SCSS](https://sass-lang.com/) makes this a whole lot [easier with nesting](https://sass-lang.com/guide#topic-3) but is not required; this was written with a [KISS](https://getyarn.io/yarn-clip/embed/eed08f4f-d1c9-4cc0-b041-f280a5dbf0a5?autoplay=false) mentality.
|
||||
|
||||
<iframe
|
||||
<IFrame
|
||||
src="https://jakejarvis.github.io/dark-mode-example/"
|
||||
title="Dark Mode Example"
|
||||
sandbox="allow-same-origin allow-scripts allow-popups"
|
||||
loading="lazy"
|
||||
style={{
|
||||
height: "190px",
|
||||
width: "100%",
|
||||
maxWidth: "650px",
|
||||
display: "block",
|
||||
boxSizing: "border-box",
|
||||
margin: "0 auto",
|
||||
border: "2px solid var(--kinda-light)",
|
||||
}}
|
||||
></iframe>
|
||||
height={190}
|
||||
width={650}
|
||||
allowScripts
|
||||
/>
|
||||
|
||||
A _very_ barebones example is embedded above ([view the source here](https://github.com/jakejarvis/dark-mode-example), or [open in a new window](https://jakejarvis.github.io/dark-mode-example/) if your browser is blocking the frame) and you can try it out on this site by clicking the 💡 lightbulb in the upper right corner of this page. You'll notice that the dark theme sticks when refreshing this page, navigating between other pages, or if you were to return to this example weeks from now.
|
||||
|
||||
|
@@ -60,7 +60,7 @@ const Note = ({ frontMatter, source }: NoteType) => {
|
||||
</Content>
|
||||
|
||||
{frontMatter.noComments !== true && (
|
||||
<InView rootMargin="140px" triggerOnce={true} fallbackInView={true}>
|
||||
<InView rootMargin="140px" triggerOnce fallbackInView>
|
||||
{({ inView, ref }) => (
|
||||
<div id="comments" ref={ref}>
|
||||
{inView && <Comments title={frontMatter.title} />}
|
||||
|
@@ -2,6 +2,7 @@ import Image from "next/image";
|
||||
import { NextSeo } from "next-seo";
|
||||
import Content from "../components/Content/Content";
|
||||
import PageTitle from "../components/PageTitle/PageTitle";
|
||||
import IFrame from "../components/IFrame/IFrame";
|
||||
import { FloppyIcon, SirenIcon } from "../components/Icons";
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
@@ -75,12 +76,14 @@ const Previously = () => (
|
||||
experience anyway.
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<figure>
|
||||
<iframe
|
||||
className="y2k_frame"
|
||||
<IFrame
|
||||
src="https://jakejarvis.github.io/my-first-website/"
|
||||
title="My Terrible, Horrible, No Good, Very Bad First Website"
|
||||
></iframe>
|
||||
height={500}
|
||||
allowScripts
|
||||
/>
|
||||
<figcaption>
|
||||
November 2001 (
|
||||
<a href="https://github.com/jakejarvis/my-first-website" target="_blank" rel="noopener noreferrer">
|
||||
@@ -236,10 +239,24 @@ const Previously = () => (
|
||||
footer > div {
|
||||
font-size: 0.95em !important;
|
||||
}
|
||||
.y2k_frame {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
border: 2px solid #e3d18c;
|
||||
figure {
|
||||
margin: 1em auto;
|
||||
text-align: center;
|
||||
}
|
||||
figure img {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
figcaption {
|
||||
margin-top: 0.2em;
|
||||
font-size: 0.9em;
|
||||
line-height: 1.5;
|
||||
color: var(--medium);
|
||||
}
|
||||
hr {
|
||||
margin: 1em auto !important;
|
||||
}
|
||||
iframe {
|
||||
margin-bottom: 0.6em !important;
|
||||
}
|
||||
.limegreen {
|
||||
color: #32cd32;
|
||||
|
@@ -3,6 +3,7 @@ import Link from "next/link";
|
||||
import { NextSeo } from "next-seo";
|
||||
import Content from "../components/Content/Content";
|
||||
import PageTitle from "../components/PageTitle/PageTitle";
|
||||
import IFrame from "../components/IFrame/IFrame";
|
||||
import { PrivacyIcon } from "../components/Icons";
|
||||
|
||||
import faunaImg from "../public/static/images/privacy/fauna_hits.png";
|
||||
@@ -24,6 +25,7 @@ const Privacy = () => (
|
||||
<p>Okay, this is an easy one. 😉</p>
|
||||
|
||||
<h2 id="hosting">Hosting</h2>
|
||||
|
||||
<p>
|
||||
Pages and first-party assets on this website are served by{" "}
|
||||
<a href="https://vercel.com/" target="_blank" rel="noopener noreferrer">
|
||||
@@ -35,6 +37,7 @@ const Privacy = () => (
|
||||
</a>{" "}
|
||||
for more information.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For a likely excessive level of privacy and security, this website is also mirrored on the{" "}
|
||||
<a href="https://www.torproject.org/" target="_blank" rel="noopener noreferrer">
|
||||
@@ -42,6 +45,7 @@ const Privacy = () => (
|
||||
</a>{" "}
|
||||
at:
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<p>
|
||||
<a
|
||||
@@ -55,6 +59,7 @@ const Privacy = () => (
|
||||
</blockquote>
|
||||
|
||||
<h2 id="analytics">Analytics</h2>
|
||||
|
||||
<p>
|
||||
A very simple hit counter on each blog post tallies an aggregate number of pageviews (i.e.{" "}
|
||||
<code>hits = hits + 1</code>) in a{" "}
|
||||
@@ -64,6 +69,7 @@ const Privacy = () => (
|
||||
database. Individual views and identifying (or non-identifying) details are{" "}
|
||||
<strong>never stored or logged</strong>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The{" "}
|
||||
<a
|
||||
@@ -87,7 +93,9 @@ const Privacy = () => (
|
||||
</a>{" "}
|
||||
are public.
|
||||
</p>
|
||||
|
||||
<Image src={faunaImg} placeholder="blur" alt="The entire database schema." />
|
||||
|
||||
<p>
|
||||
<a href="https://usefathom.com/ref/ZEYG0O" target="_blank" rel="noopener noreferrer">
|
||||
<strong>Fathom Analytics</strong>
|
||||
@@ -103,15 +111,14 @@ const Privacy = () => (
|
||||
</a>{" "}
|
||||
is completely public, too!)
|
||||
</p>
|
||||
<iframe src="https://app.usefathom.com/share/wbgnqukw/jarv.is" title="Fathom Analytics dashboard">
|
||||
<style jsx>{`
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
border: 2px solid var(--kinda-light);
|
||||
}
|
||||
`}</style>
|
||||
</iframe>
|
||||
|
||||
<IFrame
|
||||
src="https://app.usefathom.com/share/wbgnqukw/jarv.is"
|
||||
title="Fathom Analytics dashboard"
|
||||
height={500}
|
||||
allowScripts
|
||||
/>
|
||||
|
||||
<p>
|
||||
<a href="https://vercel.com/analytics" target="_blank" rel="noopener noreferrer">
|
||||
<strong>Vercel Analytics</strong>
|
||||
@@ -124,10 +131,12 @@ const Privacy = () => (
|
||||
</p>
|
||||
|
||||
<h2 id="third-party">Third-Party Content</h2>
|
||||
|
||||
<p>
|
||||
Occasionally, embedded content from third-party services is included in posts, and some may contain tracking
|
||||
code that is outside of my control. Please refer to their privacy policies for more information:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://blog.codepen.io/documentation/privacy/" target="_blank" rel="noopener noreferrer">
|
||||
@@ -171,6 +180,7 @@ const Privacy = () => (
|
||||
</ul>
|
||||
|
||||
<h2 id="hcaptcha">Fighting Spam</h2>
|
||||
|
||||
<p>
|
||||
Using{" "}
|
||||
<a href="https://www.hcaptcha.com/" target="_blank" rel="noopener noreferrer">
|
||||
@@ -186,6 +196,7 @@ const Privacy = () => (
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can refer to hCaptcha's{" "}
|
||||
<a href="https://www.hcaptcha.com/privacy" target="_blank" rel="noopener noreferrer">
|
||||
@@ -206,6 +217,7 @@ const Privacy = () => (
|
||||
</a>
|
||||
. 🚗
|
||||
</p>
|
||||
|
||||
<p>
|
||||
I also enabled the setting to donate 100% of my{" "}
|
||||
<a href="https://humanprotocol.org/?lng=en-US" target="_blank" rel="noopener noreferrer">
|
||||
|
Reference in New Issue
Block a user