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:
5
src/avif_compact.sh
Executable file
5
src/avif_compact.sh
Executable 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"
|
@@ -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"
|
||||
|
47
src/index.js
47
src/index.js
@@ -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
|
||||
}
|
||||
|
@@ -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 = () => {
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user