Skip to content

feat: in-app documentation viewer#1677

Open
mohnjiles wants to merge 8 commits into
mainfrom
feat/in-app-docs-viewer
Open

feat: in-app documentation viewer#1677
mohnjiles wants to merge 8 commits into
mainfrom
feat/in-app-docs-viewer

Conversation

@mohnjiles

@mohnjiles mohnjiles commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Adds a "Documentation" page to the footer nav (above Settings): master-detail docs browser rendering the repo''s docs/ tree in-app.

How it works

  • Nav tree: GitHub git/trees API on docs/ (Refit, matching sibling API clients), sections humanized from folder names, README.md as the landing page, images//.gitkeep excluded.
  • Content: raw.githubusercontent.com fetch with a 1-day disk cache (Cache/Docs), serve-from-cache on network failure, friendly error + Retry, and a dedicated "docs not available yet" state (docs/ isn''t on main until the upstream docs PR lands — the page degrades gracefully until then).
  • Rendering: the app''s existing BetterMarkdownScrollViewer (Markdown.Avalonia), with HyperlinkCommand interception — relative .md links navigate in-app, external links open the browser — and relative image URLs rewritten to raw URLs.
  • Config: owner/repo/branch are single consts in DocumentationConstants.cs (currently LykosAI/StabilityMatrix@main).
  • Link/path resolution is pure and unit-tested (18 MSTest cases, all passing). dotnet build: 0 errors, 0 new warnings. Husky formatting applied.

Needs before undraft

  1. Docs content merged to main (now up as Feat: Initial Documentation #1685), else the page shows the "not available yet" state.
  2. Human GUI smoke test: sidebar selection, markdown fidelity, in-app link nav, external links, images. (Data/URL layer verified against live GitHub already.)

Smoke-test round (2367c1d)

From the first GUI pass: sidebar is now a TreeView (CheckpointsPage pattern — expandable sections, root README hoisted to a top-level leaf, selection synced with link navigation); sections/pages ordered to match the docs site nav (overview-first) instead of alphabetical; the footer entry moved above Support Us so the heart/Discord/Activity/Settings cluster keeps its muscle-memory positions; and ToC #anchor links now scroll to their heading — GitHub-style slugs matched against the rendered heading blocks (no library API needed after all), including cross-page page.md#anchor links (navigate, then scroll after load). 31 unit tests pass.

Round 2 (7306974): browser-style content zoom (50–200%, persisted in settings, compact overlay control bottom-right — scales the document via a LayoutTransformControl inside the internal scroll viewer, so the scrollbar doesn't scale); 18px right inset so the overlay scrollbar no longer covers the rightmost text; and a fence-aware preprocessing pass fixing links with inline-code text (the docs breadcrumbs, e.g. Home) which Markdown.Avalonia otherwise renders as literal text. 35 unit tests pass.

v1 scope cuts

Image loading synchronous via the library default; flat-file cache rather than LiteDB.

Follow-up idea (roadmap): contextual ? icons in settings/env-var/data-dir UI deep-linking into this page.

🤖 Generated with Claude Code

Adds a Documentation footer page that fetches the docs/ folder from the
repository, renders markdown with the existing Markdown.Avalonia control,
and handles internal navigation, external links, and relative images.

- Fetch docs tree via new Refit IGitHubContentApi (GitHub git/trees)
- DocumentationService groups pages into humanized sections (README first),
  caches the tree listing and page markdown to disk (1 day TTL) and serves
  from cache on network failure
- DocumentationPathResolver: pure helpers for humanizing names and resolving
  relative .md links / image URLs (unit tested)
- DocumentationMarkdownViewer routes hyperlink clicks through a command
  (relative .md navigates in-app, http(s) opens in the browser) and rewrites
  relative image paths to raw URLs
- Loading, offline/error (with Retry), and "docs not available yet" states

Owner/repo/branch live as consts in DocumentationConstants (branch "main").

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an in-app documentation viewer feature, adding a new Avalonia DocumentationPage view and DocumentationViewModel, a custom DocumentationMarkdownViewer control, and a DocumentationService that fetches and caches markdown content from GitHub. The review feedback focuses on improving robustness, performance, and preventing race conditions. Key recommendations include handling potential race conditions during rapid page selection, wrapping cache-writing operations in try-catch blocks to prevent network-success paths from failing on disk errors, replacing inefficient string-splitting allocations with LastIndexOf, and adding exception handling around file system checks and reads to prevent crashes.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread StabilityMatrix.Avalonia/Controls/DocumentationMarkdownViewer.cs
Comment thread StabilityMatrix.Avalonia/ViewModels/DocumentationViewModel.cs Outdated
Comment thread StabilityMatrix.Core/Services/DocumentationService.cs
Comment thread StabilityMatrix.Core/Services/DocumentationService.cs Outdated
Comment thread StabilityMatrix.Core/Services/DocumentationService.cs Outdated
Comment thread StabilityMatrix.Core/Services/DocumentationService.cs Outdated
Comment thread StabilityMatrix.Core/Services/DocumentationService.cs
Comment thread StabilityMatrix.Core/Services/DocumentationService.cs
- Replace pageCts synchronously before any await so rapid page selections
  can't leak a stale load that overwrites newer content
- Cache write failures after a successful fetch no longer fail the operation
  (nested try-catch, logged as warnings)
- Unreadable/corrupt cached tree listing now falls back to network instead
  of throwing
- Match Engine as IMarkdownEngine2 (the getter's actual type; upgraded
  wrappers don't implement IMarkdownEngine)
- Avoid Split('/') allocations in hot-ish path helpers

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mohnjiles and others added 3 commits July 13, 2026 19:42
The app already ships Octokit; Git.Tree.GetRecursive covers what the
hand-rolled IGitHubContentApi + GitHubTreeResponse did, so both are
removed along with their Refit registration. Page markdown still comes
from raw.githubusercontent.com, which is not subject to the anonymous
API rate limit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mohnjiles mohnjiles marked this pull request as ready for review July 14, 2026 04:14
mohnjiles and others added 3 commits July 13, 2026 22:35
…olling

From GUI smoke-test feedback:
- Sidebar is now a TreeView (CheckpointsPage pattern): sections as
  expandable parent nodes (expanded by default), pages as leaves, root
  README hoisted to a top-level leaf; selection stays synced with
  link-driven navigation
- Sections and pages ordered to match the docs site nav (preferred
  section order, overview-first within sections) instead of alphabetical
- Documentation footer entry moved above Support Us so the pre-existing
  footer cluster keeps its muscle-memory positions; navigates by type
  since it left FooterPages
- In-page ToC anchor links now scroll to their heading: GitHub-style
  slugs matched against rendered Heading1-6 blocks, measurement deferred
  to a layout pass; cross-page page.md#anchor links navigate then scroll
- New-style partial observable property on the shared nav-node base

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Browser-style zoom (50-200%, persisted in settings): the document
  wrapper is re-parented into a LayoutTransformControl inside the
  internal scroll viewer, so content scales but the scrollbar doesn't;
  compact zoom overlay in the bottom-right corner
- 18px right inset between content and the overlay scrollbar
- Links whose text is inline code (the docs breadcrumbs, e.g.
  [`Home`](../README.md)) rendered as literal text — Markdown.Avalonia
  can't parse code spans inside link text, so strip the backticks in a
  fence-aware preprocessing pass before rendering

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
FluentIcons SymbolIcon measures greedily when given only FontSize, so
the zoom in/out buttons expanded to the full height of the content
pane. Constrain the icons with explicit Width/Height (the pattern used
elsewhere in the app). Verified with a headless render of the page.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant