Skip to content

release: publish v0.1.0-alpha.5 - #70

Merged
foxly-it merged 1 commit into
mainfrom
release/v0.1.0-alpha.5
Aug 1, 2026
Merged

release: publish v0.1.0-alpha.5#70
foxly-it merged 1 commit into
mainfrom
release/v0.1.0-alpha.5

Conversation

@foxly-it

@foxly-it foxly-it commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Summary

  • pin the tested Alpha 5 Core, WebApp, Updater, and Unbound multi-architecture manifests
  • publish bilingual installation and website references for Alpha 5
  • document signed Core/WebApp provenance, reproducible Unbound, AdGuard Stable/Beta selection, and upgrade guidance

Verification

  • release workflow 30700196286: tests, Core multiarch build, provenance attestation, published-stack install/DNS/DNSSEC smoke test
  • WebApp build 30699643976: tests, multiarch publish, provenance attestation
  • Updater build 30699641558: tests, real paired update/rollback integration, multiarch publish
  • Unbound build 30699650137: configuration, permissions, recursive DNS/DNSSEC, reproducible multiarch publish
  • independent Core and WebApp GitHub attestation verification
  • docker compose -f compose.alpha.yaml config --quiet
  • jq empty site/project-data.json
  • git diff --check

@foxly-it
foxly-it merged commit d6cc81f into main Aug 1, 2026
3 checks passed
@foxly-it
foxly-it deleted the release/v0.1.0-alpha.5 branch August 1, 2026 12:51
foxly-it added a commit that referenced this pull request Aug 5, 2026
…earlier) (#86)

rootguard-webapp#68 and #70 were already merged but this repo's submodule
pointer and roadmap checkboxes were never updated - an oversight caught
by an explicit audit request rather than during the normal per-PR
workflow. Bumps the submodule, checks both items, and records both in
project-state.md. Also removes a stale "not yet built" note about global
search that was left behind after #64 shipped.
foxly-it added a commit that referenced this pull request Aug 5, 2026
* Initial rootguard-unbound engine (Debian based) + GH Actions

* Fix Dockerfile: remove entrypoint and stabilize build

* Fix: use system user instead of fixed UID

* Fix: use packaged unbound system user

* Add MIT license and README

* Enterprise versioning: automatic Debian Unbound tagging

* Fix Docker tag: sanitize Debian version (+ → -)

* update README.md

* Finalize recursive DNSSEC configuration with persistent trust anchor

* Finalize Debian-based recursive DNSSEC configuration (enterprise commented)

* Run container as root (Debian compliant), let unbound drop privileges internally

* Install dns-root-data package to provide Debian root.key

* Container-optimized recursive DNSSEC configuration with documentation

* Finalize enterprise container-optimized Unbound configuration

* Finalize container-optimized Unbound configuration (no pidfile, no syslog)

* Move DNSSEC trust anchor to /var/lib/unbound (writable runtime path)

* Add runtime entrypoint to fix volume ownership and drop privileges correctly

* Finalize runtime bootstrap: proper trust anchor handling without su

* Enterprise runtime model: root PID1 + internal privilege drop

* Enterprise entrypoint: state init + ownership fix + DNSSEC bootstrap

* Replace unbound-anchor bootstrap with Debian trust anchor copy

* Remove unbound-anchor, use Debian dns-root-data trust anchor

* Finalize immutable runtime model with documented unbound.conf

* Finalize immutable runtime model with documented unbound.conf

* cleanup: remove legacy entrypoint.sh, keep docker-entrypoint.sh

* feat: stable rootguard unbound base image with dnssec, internal bind and production defaults

* fix: install unbound-anchor for automatic dnssec trust anchor generation

* fix: bind unbound to 0.0.0.0 for docker port mapping compatibility

* stable: production-ready rootguard unbound base image

* stable: production-ready rootguard unbound image without anchor hard-fail

* stable: Debian 13 compliant rootguard unbound image using dns-root-data trust anchor

* fix: use writable trust anchor in /var/lib/unbound (Debian 13 compliant)

* final: Debian 13 compliant writable trust anchor under /var/lib/unbound

* fix: explicit IPv4 + IPv6 binding for Docker compatibility

* final: docker-compatible access-control with bridge network support

* phase2: rootguard-ready modular unbound base (unbound.d includes)

* update README.md

* Initial commit

* Add initial backend implementation (health + version endpoints)

* Initial project structure

* Add Apache 2.0 license

* Add NOTICE

* Add professional project README

* ci: add GHCR multi-arch pipeline + improved Dockerfile

* feat: full-stack container integration with stable SPA routing

* feat(ui): professional dashboard layout with status indicator

* feat: stabilize router + SPA fallback, add dashboard API + service endpoint, UI glass layout baseline

* backend: add docker stats engine, system API and dashboard metrics

* feat(service-engine): implement service detection engine

- add /api/services endpoint
- implement binary detection (AdGuard, Unbound)
- implement docker container detection
- filter infrastructure containers
- improve process detection using pgrep exit codes
- integrate detection into router

RootGuard milestone: Service Discovery Engine

* feat(service-control): implement docker container lifecycle control

* feat: introduce rootguard service model

* feat: introduce service registry

* fix: regenerate package-lock for CI build

* fix: extend service model to support detection layer fields

* refactor: remove duplicate service model file

* Build secure RootGuard control plane (#1)

* Connect WebApp to Core and add Unbound settings (#12)

* Connect WebApp to Core and add Unbound settings

* Run WebApp validation on pull requests

* Harden Unbound for RootGuard runtime (#1)

* Harden Unbound for RootGuard runtime

* Validate Unbound changes on pull requests

* Validate Unbound after trust anchor initialization

* Add secure AdGuard bootstrap control (#2)

* Add AdGuard bootstrap interface (#13)

* Add AdGuard bootstrap interface

* Update vulnerable frontend dependencies

* Add versioned Unbound configuration lifecycle (#4)

* Add versioned Unbound configuration lifecycle

* Update Core CI action runtimes

* Add Unbound preview rollback and diagnostics UI (#14)

* Add Unbound preview rollback and diagnostics UI

* Update WebApp CI action runtimes

* Add Unbound presets and advisor (#5)

* Add Unbound advisor and preset interface (#15)

* Add safe Unbound custom configuration (#6)

* Add Unbound expert configuration editor (#16)

* Build AIO control plane and safe updates (#7)

Build the RootGuard AIO control plane, container lifecycle management, live diagnostics, and guarded component updates.

* Adopt AGPL-3.0-or-later (#2)

License the RootGuard Unbound component under AGPL-3.0-or-later and document the licensing terms.

* Add secure AIO management interface (#17)

Add the responsive bilingual RootGuard management interface with login, guided DNS setup, live configuration, diagnostics, and component update controls.

* Prepare RootGuard alpha foundation and documentation (#5)

Establish the RootGuard AIO alpha foundation with secure component updates, guided DNS management, current project documentation, AGPL licensing, and the public Wiki and roadmap.

* Enforce frontend dependency security audit (#18)

Fail WebApp CI when npm reports a high or critical frontend dependency vulnerability.

* Add guided conditional forwarding (#8)

Add typed conditional forwarding, loop-safe validation, expert conflict detection, versioned rendering, and bounded DNS target reachability checks.

* Add guided conditional forwarding interface (#19)

Add the bilingual responsive forwarding wizard, ordered IPv4 and IPv6 targets, reachability checks, fallback guidance, and safe activation through the existing Unbound lifecycle.

* Support unsigned private forward zones (#9)

* Guide unsigned private forward zones (#20)

* Allow private answers per forward zone (#10)

* Guide private answers for forward zones (#21)

* Require authoritative forwarding probes (#11)

Accept conditional-forwarding targets only when the configured zone returns NOERROR with an SOA record.

* Clarify forwarding authority checks (#22)

Describe the SOA-based activation requirement precisely in the German and English conditional-forwarding feedback.

* Stabilize forwarding probe errors (#12)

Return stable, redacted semantic errors for forwarding targets that do not provide a valid zone SOA, and cover NXDOMAIN and malformed responses with regression tests.

* Allow versioned RootGuard image tags (#3)

Let the Unbound component publish its own optional RootGuard release tag while retaining its existing version tags.

* Fix alpha dependency security audit (#23)

* Add secure local password recovery (#24)

* Improve GitHub project discoverability (#13)

* Improve GitHub project discoverability (#25)

* Improve GitHub project discoverability (#4)

* Expose trustworthy service runtime metadata (#15)

* Explain service runtime state in Stack Center (#27)

* Add bounded redacted service diagnostics (#16)

* Add on-demand service diagnostics (#28)

* Add safe update cleanup history (#17)

* Show update and cleanup history (#29)

* Add safe update lifecycle history (#34)

* Prepare standalone updater component (#1)

* Test real paired update and rollback (#3)

* Add typed installation diagnostics (#18)

* Show actionable installation diagnostics (#30)

* Add guided private DNS settings (#19)

* Add guided private DNS controls (#31)

* Add capability-checked resolver modes (#20)

* Add guided resolver protocol modes (#32)

* Distinguish missing container healthchecks (#21)

Report containers without a configured Docker healthcheck separately from genuinely unknown inspection states.

* Explain containers without healthchecks (#33)

Present running containers without a Docker healthcheck as a distinct non-error state with bilingual operator guidance.

* Polish Unbound fields and runtime badge (#34)

Align guided Unbound controls with Setup fields and center the pulsing runtime indicator independently of Safari font baselines.

* Polish management UI (#35)

* Add live dashboard metrics (#22)

* Add bounded Unbound resource profiles (#23)

* Add Unbound resource profile controls (#36)

* Preserve Unbound resource profiles in proxy (#37)

* Upgrade Unbound security baseline to 1.25.2 (#6)

* Upgrade Unbound security baseline to 1.25.2

* Read Unbound version without entrypoint output

* Add guided serve-expired controls (#24)

* Add serve-expired controls to Webapp (#38)

* Add DNSSEC cache controls (#39)

* Add DNSSEC cache controls (#25)

* Add EDNS buffer size control (#26)

* Expose EDNS buffer size control (#40)

* Expose temporary diagnostic logging (#41)

* Add privacy-safe diagnostic logging (#27)

* Enable loopback-only runtime control (#7)

* Bump the actions group across 1 directory with 6 updates (#2)

Bumps the actions group with 6 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [actions/checkout](https://github.com/actions/checkout) | `5` | `7` |
| [docker/metadata-action](https://github.com/docker/metadata-action) | `5` | `6` |
| [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) | `3` | `4` |
| [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) | `3` | `4` |
| [docker/login-action](https://github.com/docker/login-action) | `3` | `4` |
| [docker/build-push-action](https://github.com/docker/build-push-action) | `6` | `7` |



Updates `actions/checkout` from 5 to 7
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v7)

Updates `docker/metadata-action` from 5 to 6
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Commits](docker/metadata-action@v5...v6)

Updates `docker/setup-qemu-action` from 3 to 4
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](docker/setup-qemu-action@v3...v4)

Updates `docker/setup-buildx-action` from 3 to 4
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](docker/setup-buildx-action@v3...v4)

Updates `docker/login-action` from 3 to 4
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](docker/login-action@v3...v4)

Updates `docker/build-push-action` from 6 to 7
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](docker/build-push-action@v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: docker/build-push-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: docker/login-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: docker/metadata-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: docker/setup-buildx-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: docker/setup-qemu-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Add collapsible navigation sidebar (#42)

* Keep Unbound volume identity stable (#8)

* Migrate service volume ownership during updates (#28)

* Show AdGuard filter diagnostics (#43)

* Add AdGuard filter diagnostics and DNS defaults (#29)

* Fix AdGuard DNS baseline status (#30)

* Unify actions and focus AdGuard diagnostics

* Build Unbound reproducibly from verified source (#9)

* Expose stack release metadata (#31)

* Show trusted stack release metadata (#45)

* feat(installer): add AdGuard release channels (#32)

* feat(setup): select AdGuard release channel (#46)

* feat(stack): verify release attestations (#33)

* feat: show cryptographic release provenance (#47)

* feat(stack): show release attestation status

* ci: attest published WebApp images

* fix(stack): explain attestation states consistently

* fix(stack): verify exact SLSA v1 predicate (#34)

* fix(api): preserve service provenance fields (#48)

* fix(deps): bump brace-expansion and postcss to clear high-severity audit gate (#52)

npm audit --audit-level=high fails on main and therefore on every PR:
brace-expansion 5.0.8 (High, GHSA-rgw5-rvv9-x895, DoS via unbounded
intermediate arrays) and postcss <=8.5.22 (Moderate, GHSA-6g55-p6wh-862q,
sourceMappingURL .map read). Both resolve with a patch-level `npm audit fix`,
no breaking changes.

Fixes #51

* fix(overview): derive service KPI total from allowlist instead of hardcoded 2 (#50)

The Services KPI card compared against a hardcoded 2 (from an earlier
version with fewer managed services), so a fully healthy 5-service stack
rendered "5 / 2" instead of "5 / 5". Derive both numerator and denominator
from the actual /api/services allowlist response and update the EN/DE
note copy to name all five services.

Fixes #49

* feat(theme): introduce semantic design tokens with System/Light/Dark support (#54)

Completes the semantic token layer that was already half-referenced across
7 component files (--text, --text-muted, --border, --border-subtle,
--accent, --success, --warning, --surface-soft were used but never defined
at :root), adds a contrast-verified light palette, and wires up a
ThemeProvider (System/Light/Dark, localStorage-persisted, zero-FOUC)
mirroring the existing i18n provider pattern.

Fixes a dead-code bug along the way: a duplicate .sidebar rule in
index.css silently overrode --rg-bg-sidebar with a hardcoded value.

Migrates hardcoded color literals to tokens in the app shell and first
screen (index.css, header, buttons, card, status, layout, motion, glass,
content-modal, login). Page-specific stylesheets (setup/stack/dashboard/
adguard/unbound*) are explicit follow-up work and intentionally keep their
current dark appearance under both themes for now - see the issue for the
full scope boundary and screenshot evidence.

Also removes 4 verified-unused legacy button classes in buttons.css.

Fixes #53

* feat(theme): migrate Dashboard to design tokens (#56)

Replaces the 70 hardcoded hex/rgba literals in dashboard.css with the
semantic tokens introduced in #54, so the Overview/Dashboard page (hero,
KPI tiles, resource tiles, DNS data-flow diagram, service list) now
follows the System/Light/Dark theme toggle. No new tokens needed - all
values mapped onto the existing set.

Fixes #55

* feat(theme): migrate remaining pages to design tokens (#58)

Replaces the ~470 remaining hardcoded hex/rgba literals in Setup, Stack
Center, AdGuard, and the Unbound settings pages (12 files) with the
token set introduced in #54, so the whole app now follows the
System/Light/Dark theme toggle.

Adds a --category-violet token pair for the forwarding/private-DNS
panels' distinct accent, previously unnamed purple literals used
consistently across those two files.

Code/config viewers (Unbound expert editor, live-config viewer, log and
diagnostic <pre> panels) intentionally stay dark regardless of theme,
consistent with the existing content-modal.css precedent.

Fixes #57

* feat(header): rework as a coherent utility bar (#60)

Gives every header control (language, theme, sign-out, GitHub, Docs) the
same height, border, radius, background, icon size, hover, and
focus-visible treatment, per the ROADMAP.md "accessible WebGUI
navigation and appearance" slice.

Fixes an actual bug along the way: GithubIcon/DocsIcon both render at a
raw inline 22x22 SVG size and reference a shared .rg-icon class that had
no CSS rule anywhere, so they were never constrained to the 15-16px used
by the other controls' icons.

The language <select> keeps full native functionality (keyboard,
screen readers) via a transparent-overlay technique rather than a
custom-built dropdown.

Fixes #59

* feat(header): consolidate language, appearance, and sign-out into a user menu (#62)

New UserMenu component: a trigger button (username + chevron, same chip
style as the rest of the utility bar) opens a panel with three explicit
System/Light/Dark options, the language select, and sign-out. GitHub/Docs
stay direct on desktop; on narrow viewports they additionally appear
inside the same menu while the standalone chips hide, so mobile header
clutter consolidates into one trigger, per the ROADMAP.md "accessible
WebGUI navigation and appearance" slice.

Click-outside and Escape close the panel (Escape returns focus to the
trigger), opening auto-focuses the first control.

Fixes #61

* feat(search): add global, local-only search with S / Ctrl+Cmd+K (#64)

New src/search/ module: a hand-curated local index (~45 entries)
covering all pages, the 4 Unbound tabs, and the meaningfully distinct
guided settings/actions across Unbound, Setup, Stack Center, and
AdGuard, each reusing the app's existing bilingual i18n label plus
optional technical-directive keywords (qname-minimisation, prefetch-key,
serve-expired-ttl, local-zone, forward-zone, 90-rootguard-custom.conf,
...).

SearchModal is a self-contained trigger + portal panel (same pattern as
ContentModal/UserMenu): opens from the new header search chip, the "S"
key (ignored while typing in a real field), or Ctrl/Cmd+K (always).
Arrow keys move the highlighted result, Enter selects it, Escape closes
and restores focus to the trigger.

Selecting a result navigates to the matching page; landing on the exact
originating tab/section is the next roadmap item, since Unbound's tab
state isn't currently URL-addressable.

Fixes #63

* fix(theme,header): remove distracting hero circles, fix search placement (#66)

Removes the four decorative bordered-circle pseudo-elements on the
Dashboard/Setup/Unbound/Stack hero cards (purely cosmetic, no content) -
reported as too prominent in light mode and distracting in dark mode.
Also removes the now-unused rg-soft-glow keyframe.

Reorders the header utility bar so vdev precedes the Search/GitHub/Docs/
account button group instead of splitting it, and adds a visible <kbd>S</kbd>
badge to the search trigger so the shortcut is discoverable without
hovering.

Fixes #65

* feat(sidebar): move collapse control to bottom edge, default desktop to collapsed (#68)

Moves the sidebar-toggle button after the nav items (pinned to the
bottom edge via margin-top: auto instead of sitting above the nav list).
New sessions with no stored rootguard.sidebar.collapsed preference now
default to collapsed on desktop widths (>=760px); an existing explicit
preference, in either direction, still always wins. Mobile is unaffected
- the toggle is hidden there and labels always show regardless of the
value.

Fixes #67

* Keep sidebar navigation and collapse control visible while long pages scroll (#70)

* feat(layout): keep sidebar and collapse control visible while pages scroll

Replaces the page-level scroll with a fixed app-shell layout: html/body/
#root at height:100%, a new .app-shell wrapping Header + .layout at
100dvh, .layout as flex:1/min-height:0, and .main scrolling internally
(overflow-y:auto) instead of the whole document. Nav items move into a
new .sidebar-nav wrapper with its own overflow-y:auto so the nav list
can scroll independently if it ever outgrows the viewport, while the
collapse button outside that wrapper always stays at the sidebar's
bottom edge - reachable without scrolling, per the user's explicit
concern before this was implemented.

Mobile's horizontal-scrolling nav row moves from .sidebar to
.sidebar-nav; labels remain unchanged.

Fixes #69

* fix(sidebar): restore collapsed nav tooltips, remove stray scrollbar

The new .sidebar-nav scroll wrapper from the previous commit
inadvertently broke two things, both caused by giving it overflow-y:auto
without an explicit overflow-x: per the CSS overflow spec, one axis
set to a non-visible value while the other stays "visible" forces both
to "auto" - so the collapsed-state tooltip (positioned via
`left: calc(100% + 12px)`, intentionally escaping the sidebar's bounds)
got clipped, and the forced overflow-x:auto rendered a stray horizontal
scrollbar above the collapse button.

Sets overflow-x: hidden explicitly (no more ambiguous coupling), and
replaces the CSS ::after tooltip with a small JS-positioned one rendered
via a document.body portal, so it's never subject to .sidebar-nav's
clipping in the first place regardless of overflow settings.

* Make box-shadow color/intensity theme-aware to fix washed-out light mode (#72)

Every box-shadow was a literal near-black rgba() hand-tuned for the dark
theme; reused unchanged in light mode it reads as a muddy grey halo
instead of a crisp lift, especially combined with light mode's already
low-contrast card borders. Adds --shadow-ink/--shadow-scale tokens
(dark: unchanged; light: cooler ink at ~40% intensity) and rewrites the
15 existing shadow declarations to reference them, preserving each
component's hand-tuned offset/blur/spread exactly.

Fixes #71

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Add fullscreen mode and inline base-config reference to expert editor (#74)

Fullscreen renders via a document.body portal: .unbound-page carries a
permanent `animation: ... both` that leaves a non-none transform applied
after the entrance animation ends, which makes it a containing block for
position:fixed descendants - a plain CSS toggle would size the "fullscreen"
panel against that page div instead of the viewport.

The base config was previously only reachable through a separate
ContentModal popup; it's now an inline, collapsed-by-default disclosure
next to the editor.

Fixes #73

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Remove git submodules ahead of monorepo migration

Part of #92.

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

* Rebuild CI, docs, and workflow tooling for the monorepo

- Replace each component's own nested CI (now inert - GitHub only reads
  the top-level .github/workflows/) with path-filtered workflows here:
  ci-core.yml, ci-webapp.yml, ci-unbound.yml, ci-updater.yml. Each keeps
  its component's test/build/publish behavior, scoped to trigger only on
  changes under its own directory. Dropped the type=semver release-tag
  publish path from webapp/updater (redundant with the unified release
  workflow below); kept :latest/:sha-* dev tags.
- release-alpha.yml: drop submodules: recursive (plain directories now);
  expand the publish matrix from core-only to all four components, so one
  release build produces all four images under one version instead of
  requiring matching version tags pushed to three separate repos first.
  Removed the now-redundant "verify independently published" step in
  smoke-test, since publish covers all four directly.
- ci.yml: drop submodules: recursive from the integration test checkout.
- Consolidate dependabot config (github-actions repo-wide, gomod scoped
  to rootguard-updater/, matching what existed before).
- Remove the now-inert nested .github/ (workflows, issue templates, PR
  template) from each component directory.
- Update AGENTS.md, README.md, CONTRIBUTING.md, docs/project-state.md,
  ROADMAP.md's blockpage entry, and rootguard-core/README.md to describe
  the monorepo layout instead of submodules.

Fixes #92

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

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
foxly-it added a commit that referenced this pull request Aug 6, 2026
… scroll (#70)

* feat(layout): keep sidebar and collapse control visible while pages scroll

Replaces the page-level scroll with a fixed app-shell layout: html/body/
#root at height:100%, a new .app-shell wrapping Header + .layout at
100dvh, .layout as flex:1/min-height:0, and .main scrolling internally
(overflow-y:auto) instead of the whole document. Nav items move into a
new .sidebar-nav wrapper with its own overflow-y:auto so the nav list
can scroll independently if it ever outgrows the viewport, while the
collapse button outside that wrapper always stays at the sidebar's
bottom edge - reachable without scrolling, per the user's explicit
concern before this was implemented.

Mobile's horizontal-scrolling nav row moves from .sidebar to
.sidebar-nav; labels remain unchanged.

Fixes #69

* fix(sidebar): restore collapsed nav tooltips, remove stray scrollbar

The new .sidebar-nav scroll wrapper from the previous commit
inadvertently broke two things, both caused by giving it overflow-y:auto
without an explicit overflow-x: per the CSS overflow spec, one axis
set to a non-visible value while the other stays "visible" forces both
to "auto" - so the collapsed-state tooltip (positioned via
`left: calc(100% + 12px)`, intentionally escaping the sidebar's bounds)
got clipped, and the forced overflow-x:auto rendered a stray horizontal
scrollbar above the collapse button.

Sets overflow-x: hidden explicitly (no more ambiguous coupling), and
replaces the CSS ::after tooltip with a small JS-positioned one rendered
via a document.body portal, so it's never subject to .sidebar-nav's
clipping in the first place regardless of overflow settings.
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