1
0
mirror of https://github.com/osmarks/website synced 2025-04-21 10:13:21 +00:00

inline footnotes prototype

This commit is contained in:
osmarks 2025-03-30 23:02:21 +01:00
parent a9c4072283
commit ebcee20c5b
2 changed files with 76 additions and 31 deletions

View File

@ -413,6 +413,37 @@ const inCollapsedDetails = el => {
const footnotes = document.querySelector(".footnotes")
const sidenotes = document.querySelector(".sidenotes")
var sidenotesAtSide = () => false
let previousHighlight
const fixDetailsSummary = elt => {
if (!(elt instanceof HTMLElement) && !window.location.hash.slice(1)) return
const el = elt instanceof HTMLElement ? elt : document.getElementById(window.location.hash.slice(1))
var parent = el
if (!el) return
if (el.classList.contains("footnote-item")) {
if (previousHighlight) {
previousHighlight.classList.remove("hl1")
}
el.classList.add("hl1")
previousHighlight = el
}
if (el.classList.contains("footnote-backref")) {
// close footnote
if (previousHighlight) {
previousHighlight.classList.remove("hl1")
previousHighlight.classList.remove("hl3")
}
}
while (parent.parentElement) {
if (parent.nodeName === "DETAILS") {
parent.setAttribute("open", true)
}
parent = parent.parentElement
}
if (sidenotesAtSide()) el.scrollIntoView()
}
if (sidenotes && footnotes) {
const codeblocks = Array.from(document.querySelectorAll(".wider")).concat(Array.from(document.querySelectorAll(".content pre")))
const article = document.querySelector(".content")
@ -424,7 +455,7 @@ if (sidenotes && footnotes) {
const sum = xs => xs.reduce((a, b) => a + b, 0)
const arrayOf = (n, x) => new Array(n).fill(x)
const BORDER = 16
const sidenotesAtSide = () => getComputedStyle(sidenotes).paddingLeft !== "0px"
sidenotesAtSide = () => getComputedStyle(sidenotes).paddingLeft !== "0px"
let rendered = false
const relayout = forceRedraw => {
// sidenote column width is static: no need to redo positioning on resize unless no positions applied
@ -447,13 +478,14 @@ if (sidenotes && footnotes) {
inclusions.push({ start: end - snRect.top, contents: [] })
}
inclusions[inclusions.length - 1].end = Infinity
console.log(inclusions, exclusions)
const notes = []
// read off sidenotes to place
for (const item of footnoteItems) {
const link = article.querySelector(`#${item.id.replace(/^fn/, "fnref")}`)
const linkRect = link.getBoundingClientRect()
item.style.position = "absolute"
item.style.display = "list-item"
item.style.width = null
item.style.left = getComputedStyle(sidenotes).paddingLeft
item.style.paddingBottom = item.style.paddingTop = item.style.paddingRight = `${BORDER / 2}px`
const itemRect = item.getBoundingClientRect()
@ -470,7 +502,6 @@ if (sidenotes && footnotes) {
.findIndex(inc => (sum(inc.contents.map(x => x.height)) + note.height) < (inc.end - inc.start))
inclusions[index + next].contents.push(note)
}
console.log(inclusions)
// TODO: try simple moves between regions? might be useful sometimes
// place within region and apply styles
for (const inc of inclusions) {
@ -525,7 +556,7 @@ if (sidenotes && footnotes) {
}
const solutionVars = new Map(solution.variables)
let position = 0
console.log(solutionVars, model)
console.log("Layout solution found")
regionNotes.forEach((note, i) => {
position += solutionVars.get(`gap_${i}`) || 0
note.item.style.top = position + "px"
@ -535,8 +566,17 @@ if (sidenotes && footnotes) {
}
rendered = true
} else {
const articleRect = article.getBoundingClientRect()
const pad = parseFloat(getComputedStyle(sidenotes).paddingLeft)
for (const item of sidenotes.querySelectorAll(".footnote-item")) {
item.style.position = "static"
//item.style.position = "static"
const link = article.querySelector(`#${item.id.replace(/^fn/, "fnref")}`)
const linkRect = link.getBoundingClientRect()
item.style.position = "absolute"
item.style.left = (articleRect.left + pad) + "px"
item.style.width = (articleRect.right - articleRect.left - pad * 2) + "px"
item.style.top = linkRect.bottom + "px"
item.style.display = "none"
}
rendered = false
}
@ -549,6 +589,12 @@ if (sidenotes && footnotes) {
link.addEventListener("mouseleave", () => {
item.classList.remove("hl2")
})
item.addEventListener("mouseover", () => {
if (!sidenotesAtSide()) item.classList.add("hl3")
})
item.addEventListener("mouseleave", () => {
item.classList.remove("hl3")
})
}
}
@ -565,28 +611,18 @@ if (sidenotes && footnotes) {
setTimeout(() => relayout(true), 0)
})
})
}
let previousHighlight
const fixDetailsSummary = () => {
if (!window.location.hash.slice(1)) return
const el = document.getElementById(window.location.hash.slice(1))
var parent = el
if (!el) return
if (el.classList.contains("footnote-item")) {
if (previousHighlight) {
previousHighlight.classList.remove("hl1")
}
el.classList.add("hl1")
previousHighlight = el
}
while (parent.parentElement) {
if (parent.nodeName === "DETAILS") {
parent.setAttribute("open", true)
}
parent = parent.parentElement
}
el.scrollIntoView()
document.querySelectorAll("a").forEach(x => {
const isBackref = x.classList.contains("footnote-backref")
const isRef = x.parentElement.classList.contains("footnote-ref")
if (!isBackref && !isRef) return
x.addEventListener("click", ev => {
if (!sidenotesAtSide()) {
ev.preventDefault()
if (isRef) fixDetailsSummary(document.getElementById(x.getAttribute("href").slice(1)))
else fixDetailsSummary(x)
}
})
})
}
window.addEventListener("hashchange", fixDetailsSummary)

View File

@ -102,7 +102,7 @@ h1, h2, h3, h4, h5, h6
font-family: $headers
text-align: left
a
color: inherit
color: inherit !important
text-decoration: none !important
summary h1, summary h2
@ -222,9 +222,12 @@ blockquote
min-width: $sidenotes-width
padding-left: 1.5rem
position: relative
box-sizing: border-box
p
margin: 0
.footnotes-list
margin: 0
.footnotes-sep
display: none
.footnotes-list
@ -236,16 +239,22 @@ blockquote
width: auto
max-width: $content-width
padding: 0
position: static
margin-left: $content-margin
margin-right: $content-margin
.footnotes-sep
display: block
.sidenotes-container
display: block
table
display: block
overflow-x: scroll
.footnote-item.hl1, .footnote-item.hl2, .footnote-item.hl3
background: hsl(0, 0%, var(--autocol-lightness))
padding: 0.5em
box-sizing: border-box
list-style-type: none
display: block !important
@media (min-width: calc(4 * $content-margin + $content-width + $sidenotes-width + $navbar-width))
// fullwidth 3-pane layout
body
@ -278,7 +287,7 @@ blockquote
min-width: calc(40rem - 2 * $content-margin - $navbar-width)
$hl-border: 3px
.footnote-item.hl1, .footnote-item.hl2
.footnote-item.hl1, .footnote-item.hl2, .footnote-item.hl3
border-top: solid $hl-border orange
border-bottom: solid $hl-border orange
margin-top: -$hl-border