Merge pull request #34 from tlsnotary/blog/do-not-pass-go

blog: do not pass go
This commit is contained in:
sinu.eth
2026-01-02 03:53:04 -08:00
committed by GitHub
15 changed files with 365 additions and 2 deletions

View File

@@ -0,0 +1,9 @@
import styles from './styles.module.css';
export default function Callout({ children }) {
return (
<div className={styles.callout}>
<div className={styles.content}>{children}</div>
</div>
);
}

View File

@@ -0,0 +1,18 @@
.callout {
text-align: center;
margin: 2rem auto;
}
.content {
display: inline-block;
border: 1px solid lightgrey;
border-radius: 4px;
padding: 1rem 2rem;
font-style: italic;
max-width: 80%;
margin: 0 auto;
}
.content > * {
margin: 0;
}

View File

@@ -0,0 +1,65 @@
import React, { useState, useEffect } from 'react';
import styles from './styles.module.css';
export default function Figure({ src, caption, alt, width, children }) {
const [isOpen, setIsOpen] = useState(false);
const isSvgComponent = typeof src === 'function';
const SvgComponent = isSvgComponent ? src : null;
const imgSrc = typeof src === 'string' ? src : (src?.default || null);
useEffect(() => {
const handleEsc = (e) => {
if (e.key === 'Escape') setIsOpen(false);
};
if (isOpen) {
document.addEventListener('keydown', handleEsc);
document.body.style.overflow = 'hidden';
}
return () => {
document.removeEventListener('keydown', handleEsc);
document.body.style.overflow = '';
};
}, [isOpen]);
return (
<>
<figure className={styles.figure}>
<div className={styles.imageWrapper} onClick={() => setIsOpen(true)}>
{isSvgComponent ? (
<SvgComponent style={{ width, height: 'auto' }} />
) : (
<img src={imgSrc} alt={alt || caption} width={width} />
)}
</div>
{(caption || children) && (
<figcaption
className={styles.caption}
{...(!children && caption ? { dangerouslySetInnerHTML: { __html: caption } } : {})}
>
{children}
</figcaption>
)}
</figure>
{isOpen && (
<div className={styles.overlay} onClick={() => setIsOpen(false)}>
<div className={styles.modal} onClick={(e) => e.stopPropagation()}>
{isSvgComponent ? (
<SvgComponent style={{ backgroundColor: 'white', borderRadius: '4px 4px 0 0', margin: 0, display: 'block' }} />
) : (
<img src={imgSrc} alt={alt || caption} />
)}
{(caption || children) && (
<figcaption
className={styles.modalCaption}
{...(!children && caption ? { dangerouslySetInnerHTML: { __html: caption } } : {})}
>
{children}
</figcaption>
)}
</div>
</div>
)}
</>
);
}

View File

@@ -0,0 +1,75 @@
.figure {
text-align: center;
margin: 2rem auto;
}
.imageWrapper {
display: inline-block;
cursor: pointer;
transition: transform 0.2s ease;
}
.imageWrapper img,
.imageWrapper svg {
display: block;
background-color: white;
border-radius: 4px;
margin: 0;
}
.imageWrapper:hover {
transform: scale(1.02);
}
.caption {
color: var(--ifm-color-emphasis-700);
font-size: 1.0rem;
margin-top: 0.5rem;
}
.overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.85);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
cursor: pointer;
}
.modal {
cursor: default;
display: flex;
flex-direction: column;
align-items: center;
width: 1000px;
max-width: 90vw;
gap: 0;
}
.modal img,
.modal svg {
width: 100%;
height: auto;
display: block;
background-color: white;
border-radius: 4px 4px 0 0;
margin: 0;
}
.modalCaption {
color: #333;
font-size: 1.1rem;
padding: 0.5rem 1rem;
text-align: center;
width: 100%;
box-sizing: border-box;
background-color: #f9f9f9;
border: 1px solid lightgrey;
border-radius: 0 0 4px 4px;
margin: 0;
}

View File

@@ -26,6 +26,7 @@
--ifm-link-color: #0056B3;
--ifm-link-hover-color: #003D80;
}
/* Dark mode */
[data-theme='dark'] {
--ifm-color-primary: #4D82BC;
@@ -102,4 +103,4 @@
[data-theme='dark'] .footer {
background-color: var(--ifm-background-surface-color);
}
}