1
0
mirror of https://github.com/osmarks/website synced 2025-09-06 12:27:56 +00:00

New blog post and redesigned iconography

This commit is contained in:
2024-03-28 00:48:30 +00:00
parent cc4fa56faa
commit 0ad753e377
96 changed files with 289 additions and 124 deletions

5
src/avif_compact.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/sh
file=$(mktemp /tmp/tmp.XXXXXXXXXX.png)
convert "$1" -resize 25% "$file"
avifenc -s 0 -q 50 "$file" $2
rm "$file"

View File

@@ -30,7 +30,7 @@
"https://www.rtl-sdr.com/feed/",
"https://astralcodexten.substack.com/feed",
"https://www.rifters.com/crawl/?feed=rss2",
"https://drewdevault.com/feed.xml",
"https://drewdevault.com/blog/index.xml",
"https://qntm.org/rss.php",
"https://aphyr.com/posts.atom",
"https://os.phil-opp.com/rss.xml"

View File

@@ -76,9 +76,42 @@ globalData.hashBG = hashBG
const removeExtension = x => x.replace(/\.[^/.]+$/, "")
const mdutils = MarkdownIt().utils
const renderContainer = (tokens, idx) => {
let opening = true
if (tokens[idx].type === "container__close") {
let nesting = 0
for (; tokens[idx].type !== "container__open" && nesting !== 1; idx--) {
nesting += tokens[idx].nesting
}
opening = false
}
const m = tokens[idx].info.trim().split(" ");
const blockType = m[0]
const options = {}
for (const arg of m.slice(1)) {
const [k, v] = arg.split("=", 2)
options[k] = v ?? true
}
if (opening) {
if (blockType === "captioned") {
const link = `<a href="${md.utils.escapeHtml(options.src)}">`
return `<div class="${options.wide ? "caption wider" : "caption"}">${options.link ? link : ""}<img src="${md.utils.escapeHtml(options.src)}">${options.link ? "</a>" : ""}`
}
} else {
if (blockType === "captioned") {
return `</div>`
}
}
throw new Error(`unrecognized blockType ${blockType}`)
}
const readFile = path => fsp.readFile(path, { encoding: "utf8" })
const anchor = require("markdown-it-anchor")
const md = new MarkdownIt({ html: true })
.use(require("markdown-it-container"), "", { render: renderContainer, validate: params => true })
.use(require("markdown-it-footnote"))
.use(anchor, {
permalink: anchor.permalink["headerLink"]({
@@ -332,10 +365,9 @@ const doImages = async () => {
(await fse.readdir(path.join(assetsDir, "images"), { encoding: "utf-8" })).map(async image => {
if (image.endsWith(".original")) { // generate alternative formats
const stripped = image.replace(/\.original$/).split(".").slice(0, -1).join(".")
globalData.images[stripped] = {}
const fullPath = path.join(assetsDir, "images", image)
const stat = await fse.stat(fullPath)
const writeFormat = async (name, ext, mime, cmd, supplementaryArgs) => {
const writeFormat = async (name, ext, cmd, supplementaryArgs, suffix="") => {
let bytes = readCache(`images/${stripped}/${name}`, null, stat.mtimeMs)
const destFilename = stripped + ext
const destPath = path.join(outAssets, "images", destFilename)
@@ -350,10 +382,15 @@ const doImages = async () => {
await fsp.writeFile(destPath, bytes)
}
globalData.images[stripped][mime] = "/assets/images/" + destFilename
return "/assets/images/" + destFilename
}
await writeFormat("avif", ".avif", "image/avif", "avifenc", ["-s", "0", "-q", "20"])
await writeFormat("jpeg-scaled", ".jpg", "_fallback", "convert", ["-resize", "25%", "-format", "jpeg"])
const avif = await writeFormat("avif", ".avif", "avifenc", ["-s", "0", "-q", "20"], " 2x")
const avifc = await writeFormat("avif-compact", ".c.avif", path.join(srcDir, "avif_compact.sh"), [])
const jpeg = await writeFormat("jpeg-scaled", ".jpg", "_fallback", "convert", ["-resize", "25%", "-format", "jpeg"])
globalData.images[stripped] = [
["image/avif", `${avifc}, ${avif} 2x`],
["_fallback", jpeg]
]
} else {
globalData.images[image.split(".").slice(0, -1).join(".")] = "/assets/images/" + image
}

View File

@@ -417,7 +417,7 @@ if (sidenotes && footnotes) {
const linkRect = link.getBoundingClientRect()
item.style.position = "absolute"
item.style.left = getComputedStyle(sidenotes).paddingLeft
item.style.paddingBottom = item.style.paddingTop = `${BORDER / 2}px`
item.style.paddingBottom = item.style.paddingTop = item.style.paddingRight = `${BORDER / 2}px`
const itemRect = item.getBoundingClientRect()
notes.push({
item,
@@ -427,7 +427,7 @@ if (sidenotes && footnotes) {
}
// preliminary placement: place in valid regions going down
for (const note of notes) {
const index = Math.max(inclusions.findLastIndex(inc => (inc.start + note.height) < note.target), 0)
const index = Math.max(inclusions.findLastIndex(inc => inc.start < note.target), 0)
const next = inclusions.slice(index)
.findIndex(inc => (sum(inc.contents.map(x => x.height)) + note.height) < (inc.end - inc.start))
inclusions[index + next].contents.push(note)
@@ -510,6 +510,11 @@ if (sidenotes && footnotes) {
})
})
window.relayout = relayout
document.querySelectorAll("img").forEach(x => {
x.addEventListener("load", () => {
setTimeout(() => relayout(true), 0)
})
})
}
const fixDetailsSummary = () => {

View File

@@ -3,6 +3,9 @@ $content-margin: 1rem
$content-width: 40rem
$navbar-width: 20rem
*
box-sizing: border-box
:root
--autocol-lightness: 80%
--autocol-saturation: 100%
@@ -167,7 +170,6 @@ button, select, input, textarea, .textarea
display: flex
img, picture
padding-right: 1em
height: 8em
width: 8em
.title
@@ -175,13 +177,15 @@ button, select, input, textarea, .textarea
font-weight: 600
.caption
width: calc(100% - 3em)
background: lightgray
border: 1px solid black
padding: 1em
margin: 0.5em
margin-bottom: 0.5em
margin-top: 0.5em
img, picture
width: 100%
p
margin: 0
blockquote
padding-left: 0.4rem
@@ -216,6 +220,7 @@ blockquote
.footnotes-list
text-align: justify
@media (max-width: calc(2 * $content-margin + $content-width + $sidenotes-width))
// minwidth 1-pane layout
.sidenotes
min-width: auto
width: auto
@@ -229,6 +234,7 @@ blockquote
display: block
@media (min-width: calc(2 * $content-margin + $content-width + $sidenotes-width + $navbar-width))
// fullwidth 3-pane layout
body
display: flex
.nav-container