Commit Graph

261 Commits

Author SHA1 Message Date
Julien Calixte
a88d0dbac7 feat(notes): share an always-latest link, not just a snapshot
Some checks failed
CI / verify (push) Has been cancelled
The Share button now offers two links: the pinned snapshot (default) and
an "always latest" link that carries note paths in `?liveNotes` instead of
blob shas. On open they resolve to the current shas against the HEAD file
list and the URL is rewritten to the ordinary pinned form, so freshness,
editing and the snapshot banner keep working unchanged.
2026-07-11 11:11:51 +02:00
Julien Calixte
049ce01ab5 feat(notes): scroll to the last stacked note on page load
All checks were successful
CI / verify (push) Successful in 1m5s
Shared links with stackedNotes landed on the readme, forcing readers to
scroll past every note to reach the one that matters — especially long
on mobile where notes stack vertically.
2026-07-08 00:30:56 +02:00
Julien Calixte
f9906cba30 feat(notes): highlight rust code blocks and .rs file views
All checks were successful
CI / verify (push) Successful in 1m7s
2026-07-08 00:12:17 +02:00
Julien Calixte
1b6c7542d7 feat(notes): render macroplan code blocks as a delivery plan grid
All checks were successful
CI / verify (push) Successful in 2m9s
Follows the tikz pattern: the fence emits a base64 placeholder, then
the post-render hook lazily imports the parser and grid (separate
chunks) and mounts the grid only when a placeholder exists. Mono font
forced on the block because the flag-stacking math assumes Fira Code.
2026-07-08 00:01:21 +02:00
Julien Calixte
5386fa66ea feat(notes): show line numbers on non-markdown file views
All checks were successful
CI / verify (push) Successful in 2m8s
CSS counters on the per-line spans, scoped to .code-file so fenced
blocks inside notes stay untouched. The gutter width adapts to the
file's line count and numbers are excluded from text selection.
2026-07-03 16:57:09 +02:00
Julien Calixte
b8c9d07930 feat(notes): auto-merge non-overlapping edits on conflict
All checks were successful
CI / verify (push) Successful in 1m13s
When a save hits a GitHub conflict, try a three-way merge first: if our
edits and the remote ones don't overlap, commit the result silently with
a tailored toast. Only genuinely overlapping edits open the conflict
modal. Adds an optional successMessage override to updateFile.
2026-06-30 00:27:07 +02:00
Julien Calixte
cb22c755df feat(notes): resolve base and remote sources for merge
resolveMergeSources reads the edited-from snapshot as the merge base
(its own immutable cache entry, never the path pointer) and the current
remote blob, returning the decoded text a three-way merge needs.
2026-06-30 00:27:03 +02:00
Julien Calixte
9d27aa024f feat(notes): banner when viewing an older shared version
All checks were successful
CI / verify (push) Successful in 1m3s
Cache the note path on each snapshot so an old shared sha can find its
current version, and show a calm "older shared version — View latest"
banner. The exact snapshot is shown as-is; the banner only offers a jump
to the latest, never swapping content.
2026-06-29 01:04:51 +02:00
Julien Calixte
2f8d3c24a4 feat(notes): keep old shas as immutable snapshots
All checks were successful
CI / verify (push) Successful in 1m5s
Cache content under its own sha (write-once) with the path key as the
latest pointer, and advance the stack handle to the new sha after an
edit or pull. A shared link keeps showing exactly what was shared, while
the live view follows your changes.
2026-06-29 00:43:56 +02:00
Julien Calixte
a04d169bd8 fix(notes): show raw-text fallback when markdown render fails
All checks were successful
CI / verify (push) Successful in 1m2s
A throwing markdown-it plugin propagated uncaught and left the note
silently blank. Wrap the central render in try/catch and degrade to the
note's escaped raw text with a gentle notice, so content stays readable.
2026-06-29 00:00:20 +02:00
Julien Calixte
0f19482cf2 feat: fullscreen image lightbox on image/diagram click
All checks were successful
CI / verify (push) Successful in 2m2s
Click a note image or a mermaid/tikz diagram to view it fullscreen over
a blurred dim backdrop, with a fade/scale animation and rounded white
frame. Works on desktop and mobile; diagram SVGs are serialized to a
data URL via svgToDataUrl. Closes on click or Escape.
2026-06-18 00:19:51 +02:00
Julien Calixte
72dee337b7 feat(todo): switch /todo view to todo.txt format
Some checks failed
CI / verify (push) Failing after 1m1s
Replace the markdown _todo/todo.md view with a structured todo.txt UI at the
repo root: priority dropdown, inline body edit, project/context/due/rec chips
with Tabler icons, add input as a join-suffix, project/context filter columns
with TransitionGroup animation, priority-sorted list. Drops the now-unused
.todo-notes markdown checkbox styles from app.css.
2026-06-13 21:23:19 +02:00
Julien Calixte
ac3a641b22 fix(markdown): re-render code blocks after Shikiji loads
Some checks failed
CI / verify (push) Failing after 7s
The singleton `md` instance is mutated by `useShikiji()` asynchronously,
but `content` computeds had no reactive dep on that loading, so the
initial render on page reload never picked up syntax highlighting.
Link-click navigation appeared to work only because Shikiji was already
installed in `md` by an earlier render.
2026-06-09 14:38:40 +02:00
Julien Calixte
f8e0bbf9a7 Merge branch 'main' of ssh://git.apoena.dev:22222/remanso-space/remanso
Some checks failed
CI / verify (push) Has been cancelled
2026-06-09 14:34:31 +02:00
Julien Calixte
f2ba56e936 fix: add tsx as lang 2026-06-09 14:34:23 +02:00
Julien Calixte
bb3a4a4dad test: cover post-merge gaps in utils, services, and hooks
All checks were successful
CI / verify (push) Successful in 59s
Adds specs for the files added or modified in the recent merge that
weren't yet covered: oauthReturnPath, withATProtoImages, link,
displayLanguage, and the useGitHubContent / useImageUpload /
useNoteFreshness hooks. Locks in the new pullLatest contract
({raw, failureStatus}) and the fetchLatestSha branch semantics
(ok/unauthorized/offline).
2026-06-06 23:36:17 +02:00
Julien Calixte
9f21cb7882 chore: merge origin/main with local test additions
All checks were successful
CI / verify (push) Successful in 10m1s
Resolves conflict in repo.spec.ts by combining getRepoPermission
tests from main with the getFiles and queryFileContent tests from
the local test pass. Adds getRepoPermission to the userRepo.store
spec mocks so the new permission probe added upstream doesn't break
the store tests.
2026-06-06 22:17:10 +02:00
Julien Calixte
1a2d8f4ebf chore: add tests 2026-06-06 22:13:14 +02:00
Julien Calixte
a09e541fa8 feat(repo): hide write UI for users without push access
Fetch the viewer's push permission via GET /repos/{owner}/{repo} when
entering a repo and gate every write affordance behind it: edit and
image-upload buttons in StackedNote, new-fleeting-note and YouTube
buttons in FleetingNotes, and interactive checkboxes in TodoNotes
(rendered disabled when read-only). Anonymous viewers get the same
treatment because the permissions field is absent without auth, which
collapses to canPush = false.

Previously every write button was visible regardless of role, so
read-role collaborators and anonymous viewers could enter edit mode and
type before the save failed with 401/403.
2026-05-29 15:24:12 +02:00
Julien Calixte
b87836782b fix(notes): persist uploaded image to cache so it survives reload 2026-05-25 21:29:51 +02:00
Julien Calixte
54c52feeba refactor(notes): return failure status from pullLatest
Callers had to read back the side-effected status ref to know why a
pull failed, which also broke TS narrowing on the freshness badge
handler. Return { raw, failureStatus } so the reason flows through
the return value.
2026-05-25 21:25:54 +02:00
Julien Calixte
6a0f0d08d2 feat(notes): add image upload button when editing a markdown note 2026-05-25 21:17:46 +02:00
Julien Calixte
01bb4b8c70 refactor(github): extract putRaw and add uploadBinaryFile 2026-05-25 21:17:38 +02:00
Julien Calixte
151a4d9137 fix(github): auto-retry GitHub calls on 401 and expose unauthorized state
fetchLatestSha and queryFileContent were silently catching every error
(including expired-token 401s) and returning null, so the freshness
badge could stay on "offline" with no UI hint that re-auth was needed.
Wrap both calls in runWithAuthRetry to recover from refreshable tokens
transparently, and switch fetchLatestSha to a tagged result so the
freshness hook can distinguish auth failure from network failure.
2026-05-17 21:10:20 +02:00
Julien Calixte
7a2ccc1bd1 fix(github): silence contents endpoint deprecation warnings
Use RFC 6570 reserved expansion ({+path}) so slashes stay literal in
the request URL, and pin the contents call to API version 2026-03-10
to clear the Sunset: 2028-03-10 header on the deprecated 2022-11-28
version. The only breaking change in 2026-03-10 (submodule type in
directory listings) doesn't affect us — fetchLatestSha is per-file
and the array branch already short-circuits.
2026-05-17 00:34:03 +02:00
Julien Calixte
2994839ee5 feat(offline): track structured failure details during caching
Replace the failure counter with a list of typed failures (fetch,
build, save, readme, unknown) carrying path, sha, message, and
affected doc ids so callers can surface diagnostics instead of just
a count.
2026-05-17 00:07:13 +02:00
Julien Calixte
0a2445a06d fix(repo): paginate repo list alphabetically server-side
Switch from /search/repositories (best-match order) to /user/repos
with sort=full_name so infinite scroll appends in A–Z order instead
of injecting new pages into earlier letters.
2026-05-16 23:59:04 +02:00
Julien Calixte
f3ed5e063f perf(offline): parallelise note caching with batched writes
Fetch blobs with a concurrency of 8 instead of one at a time, batch
PouchDB writes via bulkUpdate, filter already-cached files up front,
and run the README fetch in parallel with the worker loop.
2026-05-16 23:48:06 +02:00
Julien Calixte
0ad747b69f fix(offline): pre-cache home README under its synthetic key
The home page reads README via getCachedMainReadme, which uses
Note-{owner}-{repo}-README, not the blob SHA. Cache-all only wrote
SHA-keyed entries, so the homepage README was empty offline.
2026-05-16 23:31:58 +02:00
Julien Calixte
c5236b2587 fix(offline): don't abort cache loop on a single fetch failure
A single null from queryFileContent silently exited cacheAllNotes,
leaving every later note uncached while the success toast still fired.
Skip the failing file, count failures, and surface them via errorMessage.
2026-05-16 23:31:42 +02:00
Julien Calixte
de7ac8d096 fix(freshness): hold checking state for 400ms minimum
Cached GitHub responses resolved so fast that the spinner state was
overwritten before Vue could render it, so clicking the badge from
"Not checked" looked like nothing happened.
2026-05-16 18:38:59 +02:00
Julien Calixte
9d1b6552cb feat(markdown): add hover download buttons on rendered SVGs
Attach SVG and PNG (×2) download buttons to every rendered SVG (TikZ,
Mermaid, …) once post-render finishes. Exports always use the original
colors with a white background baked in, regardless of theme.
2026-05-16 12:17:04 +02:00
Julien Calixte
572a05962c fix(markdown): load TikZ font stylesheet to keep text aligned
The obsidian-tikzjax bundle emits SVG referencing Computer Modern font
families like cmbx7 but ships the @font-face declarations in a separate
styles.css. Without it the browser substitutes a default font whose
glyph widths don't match TeX's, leaving visible gaps between each
kerned text run. Lazy-load the stylesheet alongside the engine on
first TikZ render so cache hits and misses both see correct fonts.
2026-05-15 16:25:55 +02:00
Julien Calixte
33285d723a refactor(markdown): extract post-render effects into composable
Four components duplicated the watch -> nextTick -> listenToClick -> runTikz
shape. Collapse to useMarkdownPostRender, which also accepts optional flags
for Mermaid, Shikiji and image hydration so StackedNote no longer needs its
own inline conditional chain.
2026-05-15 15:48:12 +02:00
Julien Calixte
813f16655c Merge branch 'main' of ssh://git.apoena.dev:22222/remanso-space/remanso 2026-05-15 15:40:21 +02:00
Julien Calixte
bf19e982fe feat(markdown): render TikZ fenced blocks to SVG
Adds a markdown-it extractor for ```tikz blocks that emits a sanitized
placeholder, plus a runTikz() that lazy-loads the obsidian-tikzjax 0.5.2
bundle from jsdelivr on first encounter, sanitizes the produced SVG with
DOMPurify, and caches it in PouchDB keyed by sha256(source) so repeat
views are instant and offline-capable.
2026-05-15 15:38:48 +02:00
Julien Calixte
816c3687d8 fix(auth): clear stale credential error after github re-auth
The 401 flag and cached repo list were module-level and only reset
after a 20-min stale window, so re-authenticating left the
"credentials are invalid or expired" message pinned on. Watch the
access token: reset state and refetch on change. Also await
saveCredentials before redirecting so refs are settled.
2026-05-14 13:04:44 +02:00
Julien Calixte
aad07184fd fix(freshness): surface silent failures when pulling latest
queryFileContent threw on octokit errors (stale SHA 404, expired token,
network blip) and the rejection bubbled up unhandled through pullLatest
and onBadgeClick, leaving the badge stuck on "Outdated" with no log or
toast. Wrap the octokit call, log on failure, clear the cached SHA so
the next click re-resolves it, and show an error toast.

Also fix a dead `if (!user || !repo) { null }` that did nothing.
2026-05-06 22:02:50 +02:00
Julien Calixte
e425be5c96 refactor(freshness): drop time-based stale-known status
The 2-minute timer + tick ref decayed verified to stale-known and rendered
a clock icon, but the user can always click the badge to re-check. Removing
the timer simplifies the hook and the badge has one fewer visual state.
2026-05-04 23:53:48 +02:00
Julien Calixte
84803c45dd refactor(scroll): clean up debug overlay and pass anchor by param
Removes the temporary on-screen scroll diagnosis panel and the global
window.__scrollAtClick stash. The anchor scrollTop is now captured
synchronously at addStackedNote entry and threaded through
scrollToFocusedNote and scrollToNoteElement to scrollToElement, so no
state survives across calls — nothing to reset on repo or page change.
2026-05-04 23:02:12 +02:00
Julien Calixte
a526a9f6af fix(scroll): snap to click-time scrollTop before smooth scroll
Capture mainApp.scrollTop synchronously when addStackedNote runs and
snap the scroll back to that value before scrollIntoView fires, so
the smooth scroll begins from where the user actually tapped rather
than from a position drifted by momentum or async work.
2026-05-04 19:57:00 +02:00
Julien Calixte
c88340d5f1 chore(debug): add temporary scroll overlay for mobile diagnosis 2026-05-04 19:02:35 +02:00
Julien Calixte
2f05b93f51 fix(stacked-note): size mobile notes with svh to stabilize scroll target
Dynamic viewport units rescale every note when the mobile address bar
grows or shrinks, shifting the scroll target by the address-bar height
mid-flight. Small viewport units stay constant across address-bar
transitions so the smooth scroll lands where it was aimed.
2026-05-04 18:45:45 +02:00
Julien Calixte
cc266eac7c refactor(scroll): delegate note scroll to scrollIntoView
Native scrollIntoView reads the element position at scroll time and
picks the right scrollable ancestor itself, sidestepping iOS Safari
quirks with scrollTo on overflow containers and visual-viewport shifts.
2026-05-04 18:29:05 +02:00
Julien Calixte
be006f08b4 fix(stacked-note): align mobile scroll target to element rect
Replace the (index + 1) * clientHeight math and 80ms setTimeout with a
scrollToElement helper that reads getBoundingClientRect inside rAF, so
the smooth scroll starts from the user's actual position even when the
note is freshly mounted.
2026-05-04 18:15:10 +02:00
Julien Calixte
efe9c01e63 chore(github-content): pin api version on fetchLatestSha request
Silences the @octokit/request deprecation warning that prints whenever
the unversioned /repos/{owner}/{repo}/contents/{path} call fires.
2026-05-03 23:37:24 +02:00
Julien Calixte
d31c774ace feat(stacked-note): surface note freshness and guard saves on conflict
Adds a Tabler-icon badge in the stacked-note action bar showing whether
the loaded copy still matches GitHub HEAD (verified / outdated / offline
/ checking / unknown / stale-known). The save flow now re-checks before
the PUT and opens a conflict modal when GitHub has moved on, with three
explicit choices: discard local edits and pull, overwrite anyway, or
cancel. Race-condition 409s from the PUT itself are routed through the
same modal.
2026-05-03 23:32:54 +02:00
Julien Calixte
d8a59467a0 refactor(github-content): expose conflict info and add latest-sha lookup
updateFile/createFile now return { sha, conflict } so 409/422 from GitHub
can drive a UI flow instead of being swallowed as a generic save error.
Also adds fetchLatestSha(path) for cheap freshness checks against HEAD.
2026-05-03 23:32:37 +02:00
Julien Calixte
e715fb02d3 fix(markdown): cache Shikiji init promise to avoid race on parallel callers
The boolean guard flipped synchronously before the async plugin load
resolved, so concurrent callers (e.g. multiple stacked non-markdown
notes mounting on reload) returned early and rendered before
markdown-it-shikiji was attached to the shared md instance. Cache the
in-flight promise instead so all callers await the same resolution.
2026-04-30 11:03:29 +02:00
Julien Calixte
7b4c7947aa fix: remove bottom padding 2026-04-29 22:06:58 +02:00