A click on a child of an <a> (e.g. nested <strong>, <em>, <code>, icon)
made event.target a non-anchor, so getAttribute('href') returned null
and the handler bailed without preventDefault. The browser then
performed the native navigation, which for relative links like
'../note.md' resolved against the current /:user/:repo URL and the SPA
re-routed treating the destination as a new repo.
The page width from .remanso.json was only applied after an async
PouchDB + network fetch, so notes briefly rendered at the default
500px before snapping to the configured value. Persist pageWidth
alongside the existing font cache (key renamed to remanso:layout:*),
so it is read synchronously during setUserRepo and applied before
the first render. Also always reset --note-width with a default
fallback to prevent stale values leaking across repo navigation.
Pure-fragment links (#heading) used to fall through to the browser's
default jump. Handle them in the click listener and scope the lookup
to the same stacked note so identical heading ids in other notes
don't win, with smooth scroll behavior to match cross-note anchors
into already-stacked notes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Smooth-scroll for the anchor jump when the target note is already
stacked, instant otherwise. While threading the new flag, the four
positional params got hard to read, so collapse them into
{ noteId, notes, hash, smoothHash } and update all call sites.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Links like `path/to/note.md#heading` previously errored with "Note not
found" because the full href (including `#hash`) was matched against
file paths. Split the fragment off in the link handler, plumb it through
the event bus, and scroll the matching heading into view once the
target note is in place. Headings now get GitHub-style ids via
markdown-it-anchor + github-slugger so the anchors actually exist.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Restore explicit overflow-y:auto on #main-app for mobile (removed in
63f5d64) — implicit coercion from overflow-x:auto is not reliable in
all Safari/WebKit versions.
- Override position:sticky on .readme to position:relative on mobile.
The desktop sticky (left:0) is correct for horizontal scroll, but on
mobile vertical scroll it pinned the 100dvh-tall readme across the
entire viewport, hiding all stacked notes behind it.
body/html have overflow:hidden so scrollTop is a no-op on them.
#main-app is the actual scroll container; use overflow-y:auto on
mobile and target it directly in scrollToNote and the scroll listener.
Three layered fixes for mobile note scrolling:
1. app.css / App.vue: on mobile, override overflow:hidden on html/body
and overflow:visible on #main-app so content from useResizeContainer
(which sets the note-container height to (n+1)*100vh) propagates to
the document and document.body.scrollTop works again.
2. FluxNote.vue: give each .note an explicit height:100dvh on mobile so
the percentage-based height:100% does not resolve against the
inflated container height set by useResizeContainer.
3. StackedNote / StackedPublicNote: replace overflow-y:hidden with
overflow-y:clip on the section. Unlike hidden, clip does not create a
scroll container, so touch events fall through to the page scroll and
the section never feels "draggable" when content fits within the note.
Add left offset to each stacked note so position: sticky activates
during horizontal scroll, pinning notes progressively to the right
of the readme column at calc((index + 1) * var(--note-width)).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contain horizontal overflow within #main-app instead of leaking to the
document, which caused a horizontal scrollbar to consume viewport height
and trigger an unwanted vertical scrollbar. Also fix note pane height
to use 100% instead of 100vh, and switch useResizeContainer to minWidth
so the flex container can grow when the window is wider than the notes.
Add a window resize listener to keep the value accurate on resize.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Allows repo owners to configure note column width via `"pageWidth": "700px"` in .remanso.json. Applies the value to the --note-width CSS variable and invalidates the cached width so resize/overlay hooks pick it up.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wrap inputs in <label class="input"> (DaisyUI v5 compound input pattern).
Form uses flex fill so inputs auto-size and the button stays on the right
on a single line regardless of container width.
Replace the minimal centered layout with a full literary/academic
homepage: logged-out users see an editorial hero, manifesto, demo
notes, and ZK primer; logged-in users see a personal launchpad
(greeting, repo tiles, last visited, review queue) followed by the
same editorial content below.
Uses DaisyUI CSS variables throughout (color-mix) so it adapts to
any theme change without hardcoded overrides.
Setting overflow-x: auto forces overflow-y off 'visible' per CSS spec,
which caused an unwanted vertical scrollbar in stacked note sections.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace <a> (no href) with <button> so both elements receive tab focus.
BackButton gets text-base-content to preserve icon color; LinkedNotes
uses btn class="link" to keep the inline text-link appearance.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
<button> gets color:ButtonText from the browser UA stylesheet, making
SVG stroke="currentColor" render black. Add text-base-content to
inherit the DaisyUI theme color like the <a>-based router-links do.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
<button> defaults to color: ButtonText (black) in browsers, unlike <a>
which inherits. Adding color: inherit restores the theme color for the
SVG stroke (which uses currentColor).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace <a> with <button> for the typography icon in HeaderNote so it
receives tab focus — <a> without href is excluded from the tab order.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dark theme was set to "dim" in theme.config.ts while app.css registered
"sunset" as the prefersdark theme. The script's regex required a trailing
comma that didn't exist on the last property, causing silent failures.
chosen* fields are per-browser preferences — localStorage is the correct
and sufficient store for them. Removing data.update from font setters and
stripping chosen* from the GitHub fetch PouchDB write prevents stale PouchDB
data from conflicting with localStorage on reload.
- Use v-model with writable computeds instead of :value+@change so selects
re-sync when the options list changes asynchronously
- Always include currently chosen fonts in sortedFontFamilies so a selected
font not present in .remanso.json fontFamilies still shows in the select
- Initialize userSettings instead of returning early in font setters so
changes made before async GitHub fetch completes are not silently dropped
- Back font choices with localStorage so they survive hard reloads even when
PouchDB/IndexedDB fails silently in the web worker
- Install missing comlink (was in lockfile but not node_modules)
- Add @ts-rest/core and @ts-rest/vue-query (imported but not declared as deps)
- Add declare module '*.vue' shim to shims-vue.d.ts
- Replace arktype validators in ts-rest contract with contract.type<T>() since @ts-rest expects Zod schemas