redaction component, margin not stacking, other cleanup

This commit is contained in:
2026-08-22 12:18:39 -05:00
parent ce7ed0fd37
commit 5baf764d67
69 changed files with 440 additions and 77 deletions
+30 -8
View File
@@ -1,15 +1,18 @@
export const BODY_FONTS = [
{ id: 'plantin', label: 'Plantin' },
{ id: 'alegreya', label: 'Alegreya' },
{ id: 'redaction', label: 'Redaction' },
{ id: 'redaction-35', label: 'Redaction 35' },
{ id: 'sohne', label: 'Sohne' },
{ id: 'space', label: 'Space Mono' },
{ id: 'georgia', label: 'Georgia' },
{ id: 'palatino', label: 'Palatino' },
{ id: 'iowan', label: 'Iowan' },
{ id: 'redaction', label: 'Redaction' },
// These are to be used by components or other styles
// { id: 'redaction-10', label: 'Redaction 10' },
// { id: 'redaction-20', label: 'Redaction 20' },
// { id: 'redaction-35', label: 'Redaction 35' },
// { id: 'redaction-50', label: 'Redaction 50' },
// { id: 'redaction-70', label: 'Redaction 70' },
// { id: 'redaction-100', label: 'Redaction 100' },
{ id: 'sohne', label: 'Sohne' },
{ id: 'georgia', label: 'Georgia' },
{ id: 'system', label: 'System Sans' },
{ id: 'courier', label: 'Courier' },
{ id: 'space', label: 'Space Mono' },
] as const;
export type BodyFontId = (typeof BODY_FONTS)[number]['id'];
@@ -20,3 +23,22 @@ export const BODY_FONT_STORAGE_KEY = 'body-font';
export function isBodyFontId(value: string | null): value is BodyFontId {
return BODY_FONTS.some((font) => font.id === value);
}
export const REDACTION_STRENGTHS = [0, 10, 20, 35, 50, 70, 100] as const;
export type RedactionStrength = (typeof REDACTION_STRENGTHS)[number];
export function redactionFamily(strength: RedactionStrength): string {
return strength === 0 ? 'Redaction' : `Redaction ${strength}`;
}
export function resolveRedactionStrength(value: unknown): RedactionStrength {
const n = Number(value);
if (REDACTION_STRENGTHS.includes(n as RedactionStrength)) {
return n as RedactionStrength;
}
if (!Number.isFinite(n)) return 35;
return REDACTION_STRENGTHS.reduce((best, grade) =>
Math.abs(grade - n) < Math.abs(best - n) ? grade : best,
);
}
+57
View File
@@ -0,0 +1,57 @@
const WIDE = '(min-width: 1200px)';
const GAP = 8;
export function stackMarginNotes() {
if (!import.meta.client) return;
const notes = Array.from(
document.querySelectorAll<HTMLElement>('.margin-note'),
);
if (!window.matchMedia(WIDE).matches) {
for (const note of notes) note.style.top = '';
return;
}
for (const note of notes) note.style.top = '';
let previousBottom = Number.NEGATIVE_INFINITY;
for (const note of notes) {
const article = note.closest('article');
const mark = note
.closest('.margin-note-root')
?.querySelector<HTMLElement>('.margin-note-mark');
if (!article || !mark) continue;
const articleTop = article.getBoundingClientRect().top;
let top = mark.getBoundingClientRect().top - articleTop;
if (top < previousBottom + GAP) {
top = previousBottom + GAP;
}
note.style.top = `${Math.max(0, top)}px`;
previousBottom = top + note.offsetHeight;
}
}
let listening = false;
export function watchMarginNotes() {
if (!import.meta.client || listening) {
stackMarginNotes();
return;
}
listening = true;
const run = () => stackMarginNotes();
window.addEventListener('resize', run);
document.fonts?.ready.then(run);
new ResizeObserver(run).observe(document.documentElement);
new MutationObserver(run).observe(document.documentElement, {
attributes: true,
attributeFilter: ['class'],
});
run();
}