feat(kb): KB UI/UX overhaul - rendered markdown, three-pane reading view, tree nav #71

Merged
vas2000-work merged 22 commits from feat/kb-ui-overhaul into main 2026-06-05 23:09:49 +02:00
Owner

Summary

Rebuilds the KB reading and authoring experience (design + plan in dev-docs/kb-ui-overhaul-design.md / -plan.md).

Reading view (three panes)

  • Collapsible category/article tree nav (left), built from the KbCategory parent_id hierarchy; current article highlighted. Also on the article list page.
  • Article rendered as real Markdown directly on the page (no Card, no <pre>), via pulldown-cmark sanitized with ammonia.
  • Consolidated header: breadcrumb (resolved over the category hierarchy), title, inline thumbs-up/thumbs-down rating with counts, status + visibility badges, Edit, density toggle, and a fullscreen read-mode toggle. Secondary header items collapse into an overflow dropdown when the row is too narrow.
  • Right rail slimmed to just the version history.
  • Both rails collapse via directional chevrons; collapse, density, and read-mode preferences persist per user in localStorage. On narrow screens rails become one-at-a-time overlays.

Authoring form

  • Slug auto-generates from the title as you type, stopping once the slug is edited by hand (edit mode never clobbers an existing slug).
  • Body editor gains Write / Preview tabs; Preview renders the same sanitized Markdown.

New modules

  • src/utils/markdown.rs (render + sanitize), src/utils/prefs.rs (localStorage), src/components/collapsible_rail.rs, src/components/overflow_actions.rs. Adds the ammonia dependency.

Tests / gates

Unit tests cover markdown rendering + sanitization (script/onerror/javascript: stripped), breadcrumb path resolution, the tree builder, and the slug-touched behavior. Locally green: cargo check --target wasm32-unknown-unknown, cargo clippy --all-targets -- -D warnings, cargo test --lib (58 passed), cargo fmt --all --check.

Known minor follow-ups (not blocking)

  • OverflowActions / CollapsibleRail render their children in both an inline and an overlay slot, so a stateful child (the rating widget) keeps independent state across a resize. Edge case.
  • Narrow-screen rails switch (one open at a time) rather than strictly blocking the second until the first is dismissed.
## Summary Rebuilds the KB reading and authoring experience (design + plan in `dev-docs/kb-ui-overhaul-design.md` / `-plan.md`). ## Reading view (three panes) - Collapsible category/article tree nav (left), built from the `KbCategory` parent_id hierarchy; current article highlighted. Also on the article list page. - Article rendered as real Markdown directly on the page (no Card, no `<pre>`), via pulldown-cmark sanitized with ammonia. - Consolidated header: breadcrumb (resolved over the category hierarchy), title, inline `thumbs-up`/`thumbs-down` rating with counts, status + visibility badges, Edit, density toggle, and a fullscreen read-mode toggle. Secondary header items collapse into an overflow dropdown when the row is too narrow. - Right rail slimmed to just the version history. - Both rails collapse via directional chevrons; collapse, density, and read-mode preferences persist per user in localStorage. On narrow screens rails become one-at-a-time overlays. ## Authoring form - Slug auto-generates from the title as you type, stopping once the slug is edited by hand (edit mode never clobbers an existing slug). - Body editor gains Write / Preview tabs; Preview renders the same sanitized Markdown. ## New modules - `src/utils/markdown.rs` (render + sanitize), `src/utils/prefs.rs` (localStorage), `src/components/collapsible_rail.rs`, `src/components/overflow_actions.rs`. Adds the `ammonia` dependency. ## Tests / gates Unit tests cover markdown rendering + sanitization (script/onerror/javascript: stripped), breadcrumb path resolution, the tree builder, and the slug-touched behavior. Locally green: `cargo check --target wasm32-unknown-unknown`, `cargo clippy --all-targets -- -D warnings`, `cargo test --lib` (58 passed), `cargo fmt --all --check`. ## Known minor follow-ups (not blocking) - OverflowActions / CollapsibleRail render their children in both an inline and an overlay slot, so a stateful child (the rating widget) keeps independent state across a resize. Edge case. - Narrow-screen rails switch (one open at a time) rather than strictly blocking the second until the first is dismissed.
Captures the agreed design: three-pane reading view (collapsible category/article tree nav left, article-only center with breadcrumb and rendered markdown, metadata + rating + tiny version history right rail), a per-user reader density toggle, client-side markdown rendering via pulldown-cmark sanitized with ammonia, breadcrumb resolution over the category parent_id hierarchy, live slug generation on the authoring form, and Write/Preview tabs on the body editor. Tree nav scoped to the detail and list pages. Includes components affected, alternatives, testing, and acceptance criteria.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both side rails get a directional chevron toggle (< / >) and are collapsible: on wide screens the user can hide either rail (state persisted per user), and on narrow screens both auto-collapse into overlays that open one at a time. Factor this into a reusable CollapsibleRail component. Also specify the article body renders directly on the page (no Card, no <pre>), and update acceptance criteria accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A fullscreen icon button at the top-right of the center article pane (right-aligned on the breadcrumb row) collapses both rails in one click for distraction-free reading and restores their prior state on exit. It acts as a master toggle over the per-rail chevrons, persists per user, and swaps its glyph between enter and exit. Updated the mockup and acceptance criteria.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move everything that can sit with the title onto the article header: inline rating (thumbs up/down + counts), status and visibility badges, the Edit action, and an "Updated" sub-line. The right rail is reduced to just the tiny version-history list, so the center pane is the article and the rail is only versions. Header items stay visible under rail collapse and read mode. Updated mockup and acceptance criteria.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When the article title row cannot fit the secondary header items (rating, status/visibility badges, Edit) inline without overflowing, they collapse into a single overflow dropdown (kebab trigger) instead of bleeding out of the container; the title stays inline and widening restores them. Factor as a reusable OverflowActions piece. Updated acceptance criteria.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Task-by-task plan (TDD for the pure logic: markdown render+sanitize, breadcrumb path resolution, category/article tree builder, slug-touched behavior; manual verification for the Dioxus components). Covers the new ammonia dep, prefs/localStorage helper, CollapsibleRail and OverflowActions components, the three-pane reading view, the consolidated header, tree rail on the list page, and the live-slug + Write/Preview authoring form. Maps every spec acceptance criterion to a task.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Render KB article Markdown to sanitized HTML via pulldown-cmark plus ammonia, for direct injection on the reading view and the authoring preview. Unit tests cover heading/list/code rendering and that script tags, event-handler attributes, and javascript: URLs are scrubbed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Typed get_bool/set_bool over localStorage (values "1"/"0"), degrading to the provided default off-web or on storage error, for persisting the KB density, rail-collapse, and read-mode preferences per user.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
resolve_category_path walks an article category_id up the parent_id chain to build the root-first breadcrumb trail, with a visited-set cycle guard and empty result for missing or dangling categories. Unit tested for nested, none, and dangling cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
build_kb_tree assembles the nav forest: root categories with recursively nested children (ordered by sort_order then name) and their articles (ordered by title), plus a separate uncategorized bucket for articles whose category is absent or unknown. Unit tested for nesting and the orphan bucket.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
KbBreadcrumb renders the resolved root-first category trail to the article title. KbTreeNav/KbTreeCategory/KbTreeArticle render the build_kb_tree forest as a collapsible category tree with nested articles and an uncategorized bucket, highlighting the current article. Not yet mounted into the pages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A reusable side rail: on wide screens it shows inline with a directional chevron that toggles a parent-owned collapsed signal; on narrow screens it becomes an edge handle that opens an overlay, with the parent owning open_overlay so only one rail overlay is open at a time.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Shows its children inline at the sm breakpoint and up; below sm it collapses them into a dropdown behind an overflow button so a narrow header row never overflows its container.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
RatingBar renders thumbs-up/down with live counts, reusing the existing helpful/not_helpful feedback endpoints. DensityToggle flips a comfortable/compact signal persisted under kb_density. ReadModeButton collapses both rails at once (remembering and restoring their prior state) persisted under kb_read_mode. Not yet mounted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the KBArticleDetailPage grid with a three-pane layout: a collapsible category/article tree rail (left), the article rendered as sanitized markdown directly on the page with a header carrying the breadcrumb, title, inline rating, status/visibility badges, Edit, density toggle, overflow dropdown, and a fullscreen read-mode toggle (center), and a slim version-history rail (right). Rail collapse, density, and read-mode persist per user. Removes the old preformatted body, the helpful card, and the right info card.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The three-pane rewrite moved the title and Edit action into an in-pane header, leaving the AppLayout PageHeader rendering a duplicate title and Edit button on the loaded article view. Remove the redundant PageHeader (keeping the AppLayout wrapper) so the detail page shows a single header.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wrap the KB article list in a two-pane shell with the shared collapsible KbTreeNav on the left (collapse state persisted under kb_left_rail, shared with the detail view) and the existing search + table as the main pane.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The slug now fills from the title as you type via next_slug, stopping once the slug is edited by hand (edit mode starts touched so an existing slug is never clobbered). The body editor gains Write/Preview tabs, with Preview rendering the same sanitized markdown as the reading view. Unit test covers the slug-touched behavior.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The #[component] macro destructures collapsed and open_overlay into immutable bindings, but the onclick closures call Signal::set (which takes &mut self), so the component did not compile. Rebind both to mut (signals are Copy, so each move closure captures a mutable copy), matching the DensityToggle/ReadModeButton convention.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
style(kb): apply rustfmt line wrapping
All checks were successful
Check / clippy + fmt + tests (pull_request) Successful in 55s
e0f2d107e7
cargo fmt --check flagged two long lines: the overlay_pos if-expression in CollapsibleRail and the active-article class format! in KbTreeArticle. Wrap both per rustfmt so cargo fmt --all --check passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix(kb): share rating state across the duplicated header slots
All checks were successful
Check / clippy + fmt + tests (pull_request) Successful in 43s
f9933a586d
OverflowActions renders the header (including RatingBar) in both an inline and a dropdown slot. RatingBar owned its counts internally, so a vote in one slot did not reflect in the other after a resize. Lift the counts to a parent-owned signal passed into RatingBar so both rendered copies stay in sync.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Merge branch 'main' into feat/kb-ui-overhaul
All checks were successful
Create release / Create release from merged PR (pull_request) Has been skipped
Check / clippy + fmt + tests (pull_request) Successful in 3m23s
cb43bb6ec9
vas2000-work deleted branch feat/kb-ui-overhaul 2026-06-05 23:09:49 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/mokosh-apps!71
No description provided.