Conversation
nixpkgs ships no Chromium derivation for Darwin (its meta.platforms is Linux-only), so referencing pkgs.chromium fails eval on macOS. On Darwin, fall through to chrome-devtools-mcp's built-in browser discovery — Puppeteer locates a user-installed Google Chrome at the standard /Applications path, otherwise downloads chrome-headless-shell into its cache. Linux keeps the pinned nixpkgs chromium so the shell stays fully self-contained.
The default layout now reads as one rounded card with chrome attached on every edge: title strip on top, sidebar on the left, right panel (TOC + backlinks) on the right at lg+, and a backlinks strip on the bottom at smaller widths. Right panel hides one breakpoint earlier than the sidebar so the prose keeps room as the viewport narrows. Backlinks in the right margin show titles only; hovering reveals the context as a flyout to the left of the card. The flyout uses a transparent hover-bridge — outer wrapper extends right up to the link, inner card sits 0.75rem inside — so cursor traversal between link and card never drops the hover. Also lands a one-shot page-load reveal (sidebar fade + main rise), gated on prefers-reduced-motion.
The Stork ES-module PR (#672) accumulated seven follow-up commits across /code-police and /hickey+/lowy. Three patterns recur often enough to warrant a project rule: - one-field options bags (replace with a positional param) - mirror flags shadowing DOM state (query the DOM) - vendor globals from separate <script src> (guard at module load) Plus two calibration examples for built-in rules: silent URL/parse fallbacks must log, and string literals across hot-path methods hit the rule-of-three at exactly three sites.
…alette Color was bleeding everywhere — every internal wikilink rendered as a filled blue pill, the title strip was a saturated banner, and the TOC fought with backlinks for visual weight. Take the page-title strip's treatment as the anchor (bg-primary-50 + text-primary-700 + tracking-tight) and unify everything that links to a note around it: in-prose wikilinks, backlinks (margin / bottom / card), query results, timeline entries, the tasks index. Reading any one of them, you learn the rest at once. Title strip itself goes from text-primary-900 to a brighter text-primary-700 so it sits in the same shade family as the chips it anchors. External links inherit the color + weight but skip the background — underline-on-hover plus the external glyph still keep them distinct from internal note links. TOC drops primary entirely (active item is bg-gray-100 / text-gray-900) since TOC entries map to headings that render in plain text — primary is reserved for "this links to another note". backlink-context flyouts now divide adjacent contexts with a thin top-rule and bump intra-context paragraph spacing from 0.35em → 0.5rem, so multiple referencing snippets no longer read as one continuous block. Drive-bys: standardize on "Linked from" across all three backlinks templates (was "Links to this page" in the card), and fix the no-sidebar branch (e.g. /neuron-layout) so backlinks show again — it was rendering backlinks-bottom which is lg:hidden, so backlinks disappeared entirely at desktop widths. Now uses the full-card backlinks template since there's no right-panel to host the margin variant.
External links no longer share the tracking-tight + font-semibold "tiny title" weight that internal wikilinks use — they're just colored prose with the existing underline-on-hover and external glyph. Reading prose with several externals + internals in the same paragraph, the internal ones now stand out as the destination affordance and external ones recede appropriately. Footnote popup picks up two grounding cues: - A "Footnote N" header in the primary palette (`text-primary-600`, uppercase, tracking-wider) so the popup self-identifies — readers landing in a popup mid-paragraph see what kind of side material they're looking at. - A `border-l-4 border-l-primary-500` rule along the left edge anchors the popup back to the in-prose `<sup>` ref's primary palette without needing a tail/arrow. Typography also tightens to match the backlink-margin flyout (`text-[0.85rem] leading-[1.55]`, `[&_p]:m-0 [&_p+p]:mt-2`) so footnote bodies and backlink contexts feel like the same kind of "side material" rather than two unrelated tooltip flavors.
Mona Sans replaces Space Grotesk for headings, sidebar, TOC, breadcrumbs, and the new chip surfaces (right-panel + backlinks-margin/bottom). It's a variable display+text sans with more character than Inter and less of the "Tailwind starter" feel of Space Grotesk — GitHub uses it as their display face. Self-hosted via the existing update.sh flow (kills the Google Fonts runtime dependency). The sans-font selector in styles.tpl was missing the new chip surfaces (#right-panel, #backlinks-margin, #backlinks-bottom), so wikilink/backlink chips inherited body serif while the title strip + TOC were sans — visible inconsistency in the chip language. Added them so every "title of a note" surface speaks the same UI font. Mona Sans's x-height is taller than Space Grotesk's, so the sidebar tree at the inherited 16px started feeling oversized. Pinning the sidebar to text-sm (14px) brings it back in line with the new typeface without affecting other surfaces.
…scale Theme palette swaps blue → emerald — slate read as blue, and a non-blue primary lets Emanote's UI step out of "AI-app default" territory without straying from a calm, single-hue palette. Note-link chips (wikilinks, backlinks-margin / -bottom / -card, queries, timeline, tasks index, inline tags) drop one fg stop (700 → 600) and gain ~30% transparency on the bg fill (50 → 50/70, hover 100 → 100/80). With the emerald palette already lower saturation than blue, the combination keeps chips as a visible "linked note" affordance without dominating prose. Tag pills (`emanote:inline-tag`) join the same chip language — previously gray-100 + rounded-lg + shadow, now matching the wikilink palette so all "linked note / tag" affordances read as one family. Heading scale tightens to a ~1.20 ratio: h1 4xl 36px (was 5xl 48px) h2 3xl 30px (was 4xl 36px) h3 2xl 24px (was 3xl 30px) h4 xl 20px (was 2xl 24px) h5 lg 18px (was xl 20px) h6 base 16px (was lg 18px) All headings now share font-semibold (was font-bold for h1/h2 only — the split had no semantic basis). h2's section-divider rule drops from `border-b-2 border-gray-200` to `border-b border-gray-100 dark:border-gray-700` so it reads as a thin section break instead of a hard rule competing with the heading itself. Margins tighten one notch at each level (mt-12 → mt-10, mt-10 → mt-8, etc.) so section breaks have ~4em of air rather than ~8em. Letter-spacing -0.02em now scopes to h1-h4 only — at 18px and below in Mona Sans the negative tracking made glyphs touch. Container max-width bumps past Tailwind `container`'s 1536px cap to 100rem (1600px) at 2xl+ so ultra-wide viewports (1920+) don't waste ~200px of horizontal gutter on each side of the card.
Timeline (daily-note backlinks via `<ema:note:backlinks:daily>`) previously rendered as a chip list inside the prose `<main>`, below the article. With the right-panel established as the "side material" hub (TOC + backlinks-margin), timeline belongs there too — and a heatmap conveys the chronological texture better than a flat list. `timeline.tpl` is now a thin section with two children: a hidden `<ul id="timeline-data">` carrying one `<li data-url data-title>` per daily backlink (the screen-reader / no-JS fallback), and a `<div id="timeline-heatmap">` that the new `_emanote-static/js/timeline-heatmap.js` paints into. Per-year layout: 12 month rows × 31 cells. Cells are 4×4px (~5px stride × 31 ≈ 155px) so the heatmap fits the right-panel's narrow ~150px content width at lg, with breathing room at xl. Filled cells are anchors carrying the date + linked-note title via the native `title` attribute; clicking navigates. Empty cells (and trailing non-existent days for short months) are gray placeholders for grid alignment. Years stack newest-first. Dates are parsed from the linked-note title via a YYYY-MM-DD regex — notes without a parseable date are silently skipped; if no entries parse, the section hides itself rather than showing a bare "Timeline" header. Re-renders on `@emanote/morph` so live-server in-app navigation refreshes the cells without a hard reload. Wires through `emanoteJsModuleNames` in JsBundle.hs (one-line addition); cabal's `_emanote-static/js/*.js` glob picks up the new file automatically.
Phase 2's heatmap was right-panel-only (lg+). Below that breakpoint the right-panel is hidden, and pages with daily-note backlinks showed nothing. Fix: render the heatmap a second time inside the bottom-strip aside so narrow viewports see it too — same content, two homes, one shows at lg+ and the other at <lg. Implementation: timeline.tpl now uses classes (`.emanote-timeline`, `.timeline-data`, `.timeline-heatmap`) instead of IDs so two instances are valid HTML. timeline-heatmap.js paints each instance independently via querySelectorAll. Each section's hidden-fallback ul lives next to its own heatmap target — cleanly self-contained. backlinks-bottom.tpl restructures to host both daily and non-daily backlinks: the <aside> now renders unconditionally with a [&:not(:has(*))]:hidden Tailwind guard, and the Heist splices for :daily and :nodaily emit their content (or nothing) inside it. On pages with neither kind of backlink, the aside has zero element children and the guard hides the chrome — so no empty bar appears.
Cells in the heatmap previously only carried a native title attribute
("date — note title"), which is enough to identify the day but not
enough to read why this note was referenced from that daily note.
Each filled cell now hosts a CSS-only group-hover flyout — same
visual language as backlinks-margin's flyout — built from the
rendered backlink context already present inside `.timeline-data`'s
hidden <li>. Header line "YYYY-MM-DD — title" in the primary
palette, followed by the cloned context paragraphs below.
The outer wrapper carries pt-1.5 of transparent padding above the
visible card (positioned `top-full`), forming the same hover-bridge
trick used elsewhere — cursor traversing from the 4px cell down to
the card stays inside the flyout's bounding box, so group-hover
doesn't drop mid-traverse.
Native `title=` is kept as the keyboard / screen-reader fallback and
as a graceful degradation when the visual flyout clips off-screen.
Setting both `title` and the rich hover flyout meant the browser's default gray tooltip layered on top of the styled card. Replace title with aria-label so screen readers still announce the cell while the visual UI is owned by the flyout.
Footer fold-in
Footer now renders as the last child inside #container instead of
floating below it as a centered icon row. New shape: a thin text-link
strip (Home / Index / Tags / Tasks left, Emanote attribution right)
on bg-gray-50 with a top border, matching the sidebar / right-panel
chrome. md:rounded-b-lg so the footer's tinted bg curves with the
container's bottom corners. The previous icon row read as orphaned
mobile bottom-nav and broke the "self-contained card" identity.
E2E selector updates
The chip-language / panel-attachment refactor broke three e2e
scenarios that were locating panels by their old IDs:
- #timeline → .emanote-timeline (class; renders in two homes)
- #backlinks → #backlinks-margin / #backlinks-bottom (#backlinks
kept as a fallback for the legacy card / error
layouts)
panelLinksTo now searches across all matching panel selectors via
querySelectorAll, so the test is structure-independent and won't
break again the next time we add another panel home.
The "every backlink context wrapper has overflow-y visible"
regression guard (#542 follow-up) was anchored to '#backlinks li > div'
— fragile, since context.tpl's wrapper now lives nested inside a
flyout. context.tpl gets a stable class hook (.emanote-backlink-context),
and the test queries by class — robust across whichever panel the
context renders in.
The heatmap was rendering at the same compact 4×4px cell size in both homes, leaving 70% empty space in the wide bottom strip while the right-panel column was tight. Cell sizing is now context-aware: the right-panel home (narrow column) keeps the fixed 4×4 squares; the bottom-strip home gets flex-1 / min-w-[6px] / h-2.5 so cells stretch as horizontal bars to fill the available row width. Detection lives in render(): a section inside #backlinks-bottom is "wide", anything else is "narrow". The cells container also picks up flex-1 in the wide context so its children's flex-1 has a real width to distribute.
The previous structure put #backlinks-bottom on the outer aside that
contained both the timeline and the regular backlinks. The e2e test
'the Backlinks panel does not link to "dailyhost/2025-01-01"' then
saw the timeline's daily-link anchors as if they were in the
backlinks panel, and failed.
Move the ID to the inner regular-backlinks <section>; the outer
aside carries .emanote-bottom-strip (chrome only). #backlinks-bottom
now refers specifically to the non-daily list, matching the
semantics of #backlinks-margin (right-panel) and #backlinks (legacy
card / error layout).
timeline-heatmap.js's wide-context detection updates accordingly:
.closest('.emanote-bottom-strip') instead of .closest('#backlinks-bottom').
…t; tables
Special pages (`/-/all`, `/-/tags`, `/-/tasks`) now render inside the
same rounded card as note pages — title strip on top with a
back-to-Home link in the corner (their only nav since there's no
sidebar), content in the white middle, footer attached at the
bottom. Drop the legacy `bg-gray-200/300` wrappers inside index.tpl,
tagindex.tpl, tasks.tpl that were leaving visible gray rectangles
inside the now-white card.
Tasks index (`/-/tasks`) restructures: heavy `border-2 shadow rounded`
boxes per task become a clean hover-tinted row list, breadcrumbs
move to a thin gray bar with `/` separator instead of the awkward
trailing `\` per crumb, and the note-title link adopts the wikilink
chip language.
In-prose task list alignment: `<li>:has(> svg.--ema-checkbox)` swaps
flex layout for absolute positioning of the checkbox in the marker
slot, so task text shares the same left edge as adjacent regular
bullets — mixed task/non-task lists now read as one column.
Tables: Pandoc emits `<table>` with no class, so style by element
under `main` (header bottom-rule, hover-tinted rows, comfy padding).
Drive-bys
- `.agency/code-police.md`: new `emanote-tailwind-first` rule —
prefer inline Tailwind utility classes over CSS in styles.tpl
unless the rule needs `:has()` / `@keyframes` / vendor-class
hooks Tailwind can't express.
- List markers in `context.tpl` get `marker:text-gray-400` for
consistency with the prose-side BulletList rule.
- `docs/tips/js/{math,mermaid}.md` move out of `js/` (not specific
to JS); `js/` folder removed; `_redirects` updated; orgmode.org
link updated; `docs/architecture.md` deleted (out of date).
…e blocks Cabal version bumps to 2.0.0.0 (still Unreleased). The default-theme overhaul (#699) is a meaningful enough chrome rewrite that 2.0 is warranted: every panel attaches inside one card, the chip language unifies across wikilinks/backlinks/queries/timeline/tags, and the timeline heatmap is a new visualization surface. docs/guide/html-template/ - `toc.md` rewritten to describe the right-panel home, the neutral-gray treatment (TOC entries map to plain-text headings), and the scroll-spy highlight. - New `backlinks.md` covers the daily/non-daily split, the chip+flyout language, and where each variant renders by viewport. - New `right-panel.md` documents the column itself: chrome that mirrors the sidebar, the three surfaces (TOC + timeline + linked from), and the <lg fallback to a bottom-attached strip. Code blocks tighten: - `skylighting.css` `pre` rule moves from hardcoded #f8f8f8 / #1e1e1e to Tailwind design tokens (`var(--color-gray-50)` etc.) so the chrome tracks the rest of the palette and the dark-mode toggle. - `pandoc.tpl` `<CodeBlock>` wrapper drops `py-4 pr-4 rounded-lg overflow-x-auto` — the `<pre>` inside already owns its bg / border / rounded / padding / overflow. The previous double layer of chrome had asymmetric right-only padding that left a visible gap on the right but not the left. Tables: - drop the `tbody tr:last-child { border-bottom: none }` override. Without it the table just trailed off; the consistent 1px border-bottom on every row gives the table a clear bottom edge.
…polish
Syntax highlighting (`skylighting.css`) moves from a hardcoded
GitHub-light circa 2018 palette to design-token colors that
coordinate with the rest of the theme:
primary (theme accent — defaults to emerald, follows index.yaml's
theme: setting): Keyword, ControlFlow, Function, Import, BuiltIn
slate (cool, recedes): String, VerbatimString
orange (warm distinct): Number/Decimal/Float, Char, SpecialChar
amber : Preprocessor, Warning
rose : Constant, Error, Alert
violet (cool-purple) : DataType, Variable, Attribute (distinct
from values without competing with kw)
gray italic : Comment, Documentation, Annotation,
Information
Dark-mode tokens use the lighter -300/-400 stops of each hue family
for legible contrast against the dark code-block background. The
emerald-themed default reads as one design surface; sites that
override `theme:` in index.yaml automatically get a matching
keyword color since `kw` keys off `--color-primary-700`.
Block-level prose images (an `<img>` that's the only content of its
parent paragraph) get a subtle frame in styles.tpl: 1px gray border,
rounded-md, centered with vertical breathing room. Inline images
(emoji, small icons) stay un-framed via the `:only-child` gate so
flowing text isn't disrupted.
Sidebar polish (4 wins):
- Toggle icons swap from filled gray-700 circles to gray-400
chevrons. The eye lands on titles, not toggles.
- Active item picks up the wikilink chip palette (bg-primary-50/70
+ text-primary-600 + font-semibold + tracking-tight) so
"you are here" reads as the same family as "this links to
another note".
- Header shows the site title (`page.siteTitle` from index.yaml)
instead of the hardcoded "Home" string. The literal "Go to Home"
moves into the link's title= tooltip.
- leading-relaxed → leading-snug at text-sm packs ~15% more tree
into the same viewport without crowding.
Backlinks-margin arrow flips: `→` (push) → `←` (pull). Backlinks are
incoming references — "this came from there" — so the arrow
points back at the listed source rather than away from it.
Query listings (default + timeline): drop the `flex-1` full-width
chip (each row was an oversized button). Result chips become
content-sized with a leading `→` arrow on the default variant or a
`tabular-nums` date column on the timeline variant; the whole row
gets a hover-tinted bg so the entire line reads as the click
target. Header collapses to small uppercase tracking-wider gray to
match the chrome label language.
…olved Tailwind v4 only emits CSS variables for palettes whose classes appear in scanned source files. The previous skylighting refresh referenced `var(--color-slate-600)`, `--color-orange-700`, etc. — palettes the templates don't otherwise use — so those tokens fell through to inherit body text colour. The page looked far less coloured than production. Hardcode the non-primary palettes to Tailwind v4 default-palette hex values; keywords / control flow / functions / imports keep `var(--color-primary-*)` since the primary palette IS exposed (it's referenced everywhere via the chip language). Site authors who customize `theme:` still get a matching keyword colour; strings / numbers / types / etc. stay on the curated coordinated palette regardless of theme.
…chip
Each <li> in the bottom-strip Linked-from list previously stacked a
chip + a free-flowing context paragraph with only space-y-3
between rows — at small viewport widths the contexts ran together
and you couldn't tell which paragraph belonged to which chip.
Two changes:
- divide-y between rows (1px gray, dark-mode-safe) so each entry
is visually a separate block.
- The context block gets ml-2 + pl-3 + border-l-2 — indented under
its chip with a thin gray left rule, anchoring it to the chip
above so the pair reads as one unit.
…ard too components/backlinks.tpl is the variant used by the no-sidebar layout (e.g. /neuron-layout) and error.tpl. It still wore the pre-redesign card chrome (p-5 rounded-xl shadow-sm + bg-gray-50 inside the already-rounded parent card) and the same chip-then- free-flowing-context pattern that produced the ball-of-mud on narrow screens. Brings it into line with backlinks-bottom.tpl: divide-y between rows, context indented under its chip with a thin left rule, outer chrome reduced to a top-rule + small heading so the parent container's card chrome carries the visual weight.
Two visual-noise reductions in the sidebar:
- Leaf nodes lost the file/document SVG icon (a 24px outlined
document with content lines for active, plain outline for
inactive). Replaced with a 4px gray dot centered in the same
icon column, so leaves still indent past the toggle column
but don't compete with the title for the eye. Folders keep
their chevron — the chevron's presence/absence already
disambiguates folder vs leaf without needing a leaf glyph.
- Folgezettel depth rails (1px gray-200 left border on each
nested .pl-2 .pl-2) removed. Indent alone is enough to convey
hierarchy, and the user flagged the rails as visible noise.
Comment in styles.tpl notes the previous treatment in case
deep trees become hard to follow without orientation guides.
The two header icons (search, dark-mode-toggle) are still
right-aligned via justify-between on the parent flex; the visual
gap to the sidebar's right edge is just the inner div's px-4
padding (matches the rest of the layout).
heist-extra's Pandoc table renderer (Heist.Extra.Splices.Pandoc.Render) hardcodes `border-r-2 border-l-2 border-gray-300` on every <th>/<td> and `border-b-2 border-t-2 border-gray-300` on every <tr>, producing a spreadsheet look with vertical cell rules. (Upstream TODO note in that file: 'Move tailwind styles to pandoc.tpl'.) Override in styles.tpl with element-selector + !important rules — left and right cell borders zeroed, row top borders zeroed — so only the thead bottom-rule and the per-row 1px bottom separator we set above remain. Editorial GitHub-style table.
The page-footer tag list (rendered by ema:each-tag) was the last
tag surface still on the pre-redesign chrome: gray-100 pill +
gray-700 text + tiny px-1 + plain rounded. Other tag affordances
already moved to the chip language:
- inline tags in prose (emanote:inline-tag rewriteClass) →
bg-primary-50/70 + text-primary-600 + font-semibold tracking-tight
- wikilinks / backlinks / queries / timeline → same palette
Bring metadata tags into the same family: bg-primary-50/70 +
text-primary-600 + px-1.5 py-0.5 rounded-sm + hover bg shift.
font-mono stays (the slashed-path identifier shape reads better in
mono than sans), so metadata tags read as "tag identifier" rather
than "tag link in prose" — same palette, distinct typography.
Spacing tightens: gap-x-2 / gap-y-1.5 instead of space-x-2 + space-y-2
(margin collapses are easier to predict), and mt-8 above the strip
gives breathing room between prose and tags.
Checkbox SVG (checked + unchecked) tightens visually:
- h-4 w-4 fixed → h-[0.9em] w-[0.9em] (scales with surrounding
text instead of being a fixed 16px square)
- stroke-width 3 → 2 on the box outline (refined, not blocky)
- stroke-width 3.5 → 3 on the check path
- rx 3 → 4 (slightly softer corners, matches rounded-sm idiom)
- mt-1 → align-[-0.1em] (sits on the text baseline rather than
pushed-down a fixed amount)
- text-gray-500 → text-gray-400 (less heavy outline)
The styles.tpl marker-slot absolute-positioning rule for in-prose
task lists now scopes to `main ul.list-disc li:has(...)` instead of
any `main li:has(...)`. Previously the rule fired on the special
tasks index page (`/-/tasks`) too, where the <ul> isn't a prose
list-disc — happened to work by accident because <main>'s px-6
padding equalled the rule's -1.5rem offset, but with the lighter
em-sized checkbox the alignment broke. Scoping fixes the special
page without affecting prose task lists.
Drive-by: docs/tips/js.md removed (the js/ folder children moved
out earlier; this stub is no longer needed).
fonts.md
- Space Grotesk → Mona Sans in the "ships with" list (the actual
chrome typeface in default/styles.tpl); link to github/mona-sans.
- Drop "TOC accents" from the theme-colour callout — TOC dropped the
primary palette entirely as part of #699; entries map to plain
headings, not other notes, so they sit in neutral gray.
- Reframe the theme-colour line as "drives the unified chip
language" with cross-references to the chip surfaces (page title,
wikilinks, backlinks, queries, timeline heatmap, tags).
daily-notes.md
- "rendered as a 'timeline' in reverse chronological order" →
year-stacked timeline heatmap, with a link to the backlinks doc's
timeline section.
- "Links to this page" panel → "Linked from" chip list (the panel
label changed in the no-sidebar template; we want the docs to
match what the user sees).
- Demo paragraph names where each surface lives (right-panel at lg+,
bottom strip at narrower widths) so the example is self-locating.
…nner
/-/all (Index): every entry now reads as a "linked note" chip — the
sidebar-tree template gets parameterized via a new tree-link-rest-class
bind that the caller supplies, so:
- sidebar.tpl keeps its original hover-only rest state (chip palette
is reserved for the active item)
- special/index.tpl supplies the full chip palette so every leaf
on /-/all looks like a wikilink chip
The <node:active> shadow inside sidebar-tree.tpl never fires on
/-/all (no current note), so the chip rest class becomes the universal
link style for that page.
/-/tags (Tag Index): rewritten to mirror the established chip
language end-to-end:
- tagcrumbs render as #tag chips with / separators (matching the
tasks.tpl breadcrumb pattern); the trailing crumb gets a slightly
stronger fill so "you are here" stands out without breaking the
family
- subtags render as font-mono #tag chips + (N+M) count
- notes-tagged-here render as the wikilink chip with a leading →
arrow (same shape as query-default.tpl)
Header sections use the same text-xs uppercase tracking-wider micro-
heading as queries / right-panel sections.
text-l → text-lg in pandoc.tpl's <DefinitionList> <dt>: text-l is
not a valid Tailwind class, so DT terms have been rendering at the
default text size since v1. Definitively a typo for text-lg.
text-l → text-sm in index.yaml's emanote:error:yaml rewriteClass:
same typo. The error banner is font-mono, so text-sm reads better
than text-lg here.
Chip rest state on /-/all becomes text-color + bold only; the bg-tint surfaces on hover. The earlier "full chip" rest state stretched a solid primary-50 fill across every row (the link inherits flex-1 from sidebar-tree.tpl), painting the special-page card a wall of blue. The new rest class still reads as the wikilink chip family — same text-primary-600, same font-semibold tracking-tight — just without the resting bg fill. Keeps the "every entry is a linked note" semantic intact while letting the white card breathe.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The default Emanote theme reads as a single self-contained notebook card now — sidebar / prose / right-panel / title strip / backlinks-bottom all stack inside one rounded shadow-bound
#container, so the page UI looks composed instead of assembled. The work started as a marginalia experiment (Tufte-style backlinks in the right margin) and grew through review into a full visual-language pass: every "linked note" surface in the codebase now uses the same chip language, headings tighten to a calmer scale, the timeline becomes a year-stacked heatmap with hover contexts, and the chrome typeface swaps to Mona Sans.Layout — every edge attaches to the main card
<mdmd–lglg+Right panel hides one breakpoint earlier than the sidebar so the prose keeps room as the viewport narrows — the bottom strip carries the same content (backlinks + timeline heatmap) while the sidebar stays visible.
A unified chip language
Every place that renders a "title of a note" now reads as one family — same color, weight, tracking, palette stop:
<Internal>viapandoc.tplquery-default.tpl,query-timeline.tpltimeline.tplspecial/tasks.tplemanote:inline-taginindex.yamlmetadata.tplbg-primary-50/70 text-primary-600 font-semibold tracking-tight px-1 py-0.5 rounded-sm— the same chip rule everywhere, with a small dial-down in saturation (the originalbg-primary-50+text-primary-700read as too prominent against the prose).External links inherit the color but skip the background and the bold weight — they get
text-primary-600+ underline-on-hover + the existing external glyph, so prose still distinguishes "another note" from "another site".Color and chrome
blue→emerald(index.yaml:27).slatewas tried first but reads as blue-gray; emerald gets Emanote off the "AI-app default" baseline at the same calm saturation level.bg-gray-100 text-gray-900) — TOC entries map to headings that render in plain prose, and reserving primary for "linked note" affordances tightens the visual semantics.container1536px cap to100rem(1600px) at2xl+, so ultra-wide viewports don't waste ~300px of horizontal gutter.Typography
Mona Sans's larger x-height makes the sidebar tree feel oversized at the inherited 16px, so
#sidebarpins totext-sm(14px). Self-hosted via the existingfonts/update.shflow — no Google Fonts runtime dependency.Heading scale tightens
All headings now share
font-semibold(the previousfont-boldfor h1+h2 only had no semantic basis). h2's section-divider rule drops fromborder-b-2 border-gray-200toborder-b border-gray-100 dark:border-gray-700— a thin section break instead of a hard rule that competes with the heading. Margins tighten one notch at each level (mt-12 → mt-10,mt-10 → mt-8, etc.), so section breaks have ~4em of air rather than ~8em.letter-spacing: -0.02emnow scopes to h1–h4 only — at 18px and below in Mona Sans the negative tracking made glyphs touch.Timeline → year heatmap
Daily-note backlinks (
<ema:note:backlinks:daily>) used to render as a chip list inside the prose<main>, below the article. With the right-panel established as the side-material hub, timeline belongs there too — and a heatmap reads better than a flat list for chronological texture.Per-year layout: 12 month rows × 31 cells (4×4px each, 5px stride ≈ 155px so it fits the right-panel's narrow content width). Filled cells are anchors — clicking navigates to the daily note, hovering opens a context flyout (header
YYYY-MM-DD — titlein the primary palette, then the rendered backlink context paragraphs, exact same visual language as backlinks-margin's flyout). Empty cells are gray placeholders. Years stack newest-first.Renders in two homes — the right-panel (lg+) and the bottom strip (<lg) — so narrow viewports see the timeline too. Re-renders on
@emanote/morphso live-server in-app navigation refreshes without a hard reload.JS lives in
_emanote-static/js/timeline-heatmap.js, wired throughemanoteJsModuleNamesinJsBundle.hs(one-line addition). Dates are parsed from each backlink's title via aYYYY-MM-DDregex; entries without a parseable date are silently skipped and the section hides itself if zero entries parse.Sidebar polish
page.siteTitle.text-sm leading-snugso Mona Sans's larger x-height doesn't blow the tree out vertically.bg-primary-50/70 text-primary-600 font-semibold tracking-tight.Special pages adopt the card chrome
/-/all,/-/tags,/-/tasks(and any future special page) used to render against a barebg-gray-200/300wrapper that didn't match note pages at all. They now share the no-sidebar branch's card chrome — same title strip, same footer, same rounded shadow.A "← Home" affordance sits absolute-positioned at the left of the title strip (
hidden md:inline-flex) so there's always a one-click way back to/from any special page./-/tasksgot its own restructure: each task-group is rendered as a chip-style note title with/-separated breadcrumbs above its task list, and individual tasks render as hover-tinted rows (rounded-sm hover:bg-gray-50 px-2 py-1).Tables, code blocks, syntax highlighting, images
width:100%,border-collapse: collapse, thead bottom-rule + tbody row separator + row hover. heist-extra hardcodes Tailwind cell-border classes that conflict with the new style — overridden via!importantinstyles.tplfor now (issue filed:srid/heist-extra#18).py-4 pr-4 rounded-lg overflow-x-auto) for a cleanermb-6 text-sm— the surrounding card already gives them visual containment.skylighting.cssrewritten with a coordinated light/dark token palette. Primary tokens follow the theme viavar(--color-primary-*); secondary tokens (slate / orange / rose / violet / amber) use hardcoded hex because Tailwind v4 only emits CSS variables for palettes referenced in scanned classes.main p > img:only-childnow renders framed (rounded-md border) so screenshots and diagrams sit inside a thin chrome instead of bleeding into the prose flow.FOOTNOTE Nheader in the primary palette +border-l-4 border-l-primary-500so the popup self-identifies and visually anchors back to its<sup>ref.Footer rewrite
Folded into the bottom of the card (was a separate sibling of
#container). Renders as a text-link strip — Home / Index / Tags / Tasks on the left, Emanote logo + version on the right — sharing the card'sbg-gray-50chrome andmd:rounded-b-lgso it visually closes the page.Task list polish
In-prose task lists (
- [ ] .../- [x] ...) get a dedicated--ema-checkboxSVG that's em-sized (h-[0.9em] w-[0.9em]) withalign-[-0.1em]so it sits on the text baseline. Strokes lightened (rectstroke-width=2, checkstroke-width=3). The marker-slot rule that hides the bullet when the first child is a checkbox is now scoped tomain ul.list-disc li:has(> svg.--ema-checkbox)— previously it fired on/-/taskswhere there's no list-disc context, mis-rendering tasks there.Backlinks-bottom row layout
The narrow-viewport backlinks card was rendering as one flat block of chips + contexts. Now each row is separated (
divide-y divide-gray-200) with the context indented under its chip via aborder-l-2rule, so multi-backlink pages parse at a glance instead of reading as a single ball of mud. The same row-separated pattern is applied to the no-sidebar full-cardbacklinks.tplfor consistency.Drive-bys
chrome-devtoolsshell evaluates on Darwin.pkgs.chromiumhas Linux-onlymeta.platforms; on macOS the wrapper now omits--executable-pathand lets Puppeteer locate the system Chrome. Linux keeps the pinned nixpkgs chromium so the shell stays self-contained./code-policeproject rules..agency/code-police.mdcaptures four patterns from Stork: drop inline IIFE for an ES module under _emanote-static/js/ #672's follow-ups (one-field options bags, mirror flags shadowing DOM state, vendor globals from separate<script src>, prefer Tailwind utilities overstyles.tplCSS) plus calibration examples for built-in rules./neuron-layoutbacklinks bug fix. No-sidebar branch was renderingbacklinks-bottom(which islg:hidden), so backlinks vanished entirely at desktop widths. Now uses the full-cardbacklinkstemplate since there's no right-panel to host the margin variant.docs/architecture.md(out of date) anddocs/tips/js.mdremoved;docs/tips/js/{math,mermaid}.mdmoved up todocs/tips/{math,mermaid}.mdwith_redirectsentries.Try it locally
nix run github:srid/emanote/noble-cup -- -L $PWD/docs run --port 9010Generated by Claude Code (model
claude-opus-4-7).