Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion site/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ export default defineConfig({
Footer: './src/components/starlight/Footer.astro',
MobileMenuFooter: './src/components/starlight/MobileMenuFooter.astro',
PageSidebar: './src/components/starlight/PageSidebar.astro',
MarkdownContent: './src/components/starlight/MarkdownContent.astro',
},
// Split from a single 4,965-line starlight.css into ordered per-pass
// files (see docs/ARCHITECTURE.md). Order matters: several later
Expand Down
61 changes: 0 additions & 61 deletions site/src/components/starlight/MarkdownContent.astro

This file was deleted.

15 changes: 12 additions & 3 deletions site/src/components/starlight/PageSidebar.astro
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
import MobileTableOfContents from 'virtual:starlight/components/MobileTableOfContents';
import TableOfContents from 'virtual:starlight/components/TableOfContents';

const { sidebar: routeSidebar, toc } = Astro.locals.starlightRoute;
const sidebar = routeSidebar as SidebarEntry[];
Expand Down Expand Up @@ -104,9 +105,17 @@ const currentGroupLabel = formatCrumb(currentGroup?.label) || 'Start';
{
toc && (
<>
{/* Narrow screens keep the collapsed dropdown. The wide-screen list
moved to PageTitle.astro so it sits under the hero rather than in
the right-hand rail. */}
{/* Wide screens: the contents list in the right-hand rail, which is
where Starlight puts it and where a reader looks for it. It was
briefly moved under the hero; that came from feedback about the
NARROW list not collapsing, and moving the wide one was not the
fix for it. */}
<div class="right-sidebar-panel sl-hidden lg:sl-block">
<div class="sl-container">
<TableOfContents />
</div>
</div>
{/* Narrow screens keep the collapsed dropdown. */}
<div class="netscli-mobile-toc-wrapper lg:sl-hidden">
<MobileTableOfContents />
</div>
Expand Down
85 changes: 6 additions & 79 deletions site/src/styles/starlight/30-toc-under-hero.css
Original file line number Diff line number Diff line change
@@ -1,85 +1,12 @@
/* Contents list under the hero, instead of in the right-hand rail.
/* Leftovers from the contents-list experiment that moved the ToC out of
* the right-hand rail and under the hero. That is reverted: Starlight puts
* the ToC in the rail on desktop and collapses it to a dropdown below,
* which is what was wanted -- the original complaint was that the MOBILE
* list was not collapsing, and moving the desktop one was not the fix.
*
* The list is rendered by src/components/starlight/MarkdownContent.astro; see
* that file for why it keeps the `.right-sidebar-panel` class. These rules
* undo the parts of that class that only made sense in a fixed 208px rail.
* Only this one unrelated rule is still needed here.
*/

/* Which of the two contents lists shows, and where the switch happens.
*
* 50rem, the width at which the left sidebar stops being a drawer and becomes
* a permanent column. Starlight's own switch for the ToC is 72rem, so the
* 50-72rem band showed the collapsed dropdown beside a fully expanded
* sidebar, with a strip of empty hero above it -- one of the two navigation
* panes collapsed and the other not, at a width with room for both. */
@media (max-width: 49.99rem) {
.docs-toc-under-hero {
display: none !important;
}
}

@media (min-width: 50rem) {
.docs-toc-under-hero {
display: block !important;
}

mobile-starlight-toc {
display: none !important;
}
}

/* The column Starlight reserves for the rail has to collapse, or the article
keeps a dead gutter roughly a sidebar wide. TwoColumnContent.astro sizes
.main-pane by subtracting that width, so both change together. */
@media (min-width: 72rem) {
.right-sidebar-container {
display: none !important;
}

[data-has-sidebar][data-has-toc] .main-pane,
.main-pane {
width: 100% !important;
}
}

/* Full content width, not the rail's 208px -- otherwise the multi-column
rule below can only ever produce one column. */
.docs-toc-under-hero.right-sidebar-panel {
width: 100% !important;
max-width: none !important;
padding: 0 !important;
}

.docs-toc-under-hero .sl-container {
width: auto !important;
max-width: none !important;
}

/* The rail moves from the list onto each link. In the rail layout a single
border on the <ul> was the rail; laid out in columns it would mark only the
first column and leave the other two floating. A border per link gives each
column its own continuous rail, and the active link still lights it green. */
/* These compete with `.right-sidebar-panel ...` rules in
20-docs-shell-closeout.css. An earlier version of this comment claimed the
doubled class was needed because the bundler does not emit these files in
filename order; that was measured and is wrong for this pair -- 30 is
emitted after 20, and the rule it competes with carries no !important, so
these win on either count. (Emission order is not always filename order --
24 is emitted before 23 -- but that is not what was happening here; the
symptom that prompted it was a stale deployed stylesheet.) */
.docs-toc-under-hero :where(nav ul) {
border-inline-start: 0 !important;
}

.docs-toc-under-hero :where(a) {
margin-inline: 0 !important;
border-inline-start: 2px solid var(--sl-color-hairline) !important;
}

.docs-toc-under-hero :where(a[aria-current='true']) {
border-inline-start-color: var(--netscli-accent) !important;
}

/* The search dialog's own failure message, injected by
scripts/docs-search-keys.ts when Pagefind neither answers nor errors.
Sized and coloured like the message it sits under, so it reads as part of
Expand Down
153 changes: 148 additions & 5 deletions ux-walkthrough.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
# UX walkthrough — NetsCLI desktop app
# UX walkthrough

The flow an acceptance pass should walk, step by step, against a running
build. Written from the shipped app; each step below was observed rather
Two surfaces, each with its own journeys: the **desktop app** and the
**website** (`site/`, netscli.com — landing page, docs and changelog).

The flows an acceptance pass should walk, step by step, against a running
build and a served site. Written from the shipped app; each step below was observed rather
than intended. Where a step depends on privileges or the local network, the
condition is stated so a failure can be attributed correctly.

Scope: `apps/netscli-gui`. The CLI, TUI and MCP surfaces have their own
documentation under `docs/`.
The CLI, TUI and MCP surfaces have no walkthrough: they are exercised by
`docs/` and by their own tests, and neither has states a person navigates.

---

# Desktop app

Scope: `apps/netscli-gui`.

## Primary job

Expand Down Expand Up @@ -75,3 +84,137 @@ Recorded so an acceptance pass does not report them as new:
verify interaction findings both ways before believing either.
- The MSI has never been tested on a clean machine without WebView2
preinstalled.

---

# Website

Scope: `site/` — the landing page, the docs, and the changelog, served as a
static build. Written by walking a served production build at 1440px and
375px; the structure below is what is there, not what was intended.

This section did not exist while the site shipped, which is why nothing had
ever walked it. Every journey here is one a person actually performs; a step
that cannot be completed is a finding, not a curiosity.

## Primary job

**Decide whether NetsCLI is worth installing, then install it.**

Everything else on the site serves that or follows from it: the docs explain
what you just installed, and the changelog says whether to update.

Search engines and language models are a second audience for the same
content, which is why the copy has to answer a question rather than describe
a feature. They are not a separate journey — a page that reads well for a
person and states plainly what the tool does serves both.

## Steps

### A. Evaluate — "what is this, and is it for me?"

1. **Land.** The hero states what NetsCLI is in one line, with the current
release, star count and download total beside it. Each of those three is
hidden until GitHub confirms it, so an unauthenticated rate limit shows
nothing rather than something wrong.
2. **Scan the surfaces section** (`#surfaces`) — desktop app, terminal UI,
CLI, MCP server — and recognise which one is yours.
3. **Reach the FAQ** (`#faq`), 13 questions in 4 groups: what it is, install
and updates, interfaces and integrations, network workflows, limits and
dependencies. These carry the comparison questions people actually search
for ("alternative to Angry IP Scanner", "replace nmap").
4. **Leave for the source** if that is the decision — the GitHub link is in
the top nav and in the hero.

### B. Install — "give me the command"

1. **Reach `#install`**, from the nav or the hero CTA.
2. **Pick a platform** — Windows, macOS, Linux tabs. The tab set is the
first choice because a command for the wrong OS is worse than none.
3. **Pick a form** — desktop app or CLI + terminal UI. These are separate
products with separate package names, and the page must not blur them.
4. **Copy a command**, or download an installer directly. Every command has
a copy button; the download links resolve through
`/releases/latest/download/…` so they never name a version that has moved
on.
5. **Verify, if you care** — checksums and signing are stated with a link to
the verification steps.

### C. Learn — "how do I do the thing"

1. **Enter the docs**, from the nav or a search engine landing on a deep
page. Either is a first page, so every page has to stand alone.
2. **Orient**: left sidebar for the section list, right rail for the
contents of this page, breadcrumb for where you are.
3. **Search** (`Ctrl K`, or the button on narrow screens) when the nav does
not have the word you are thinking of.
4. **Follow an anchor** to a heading, and share that link.
5. **Move between pages** with the sidebar, keeping your place.

### D. Check what changed — "should I update?"

1. **Open the changelog**, from the nav or from a version number.
2. **Read the newest release first**; each entry says what changed and why
it matters, with install, compatibility or security notes called out.
3. **Tell released from unreleased.** An entry with no published release
behind it is labelled and is not linked, because a link would 404.

### E. Recover — "that link was wrong"

1. **Hit a 404** and get a page that says so and offers a way back, rather
than a dead end.

### Narrow screens

Each journey above has a narrow variant, and they are where this site has
historically broken:

- The section list collapses behind a menu control; the page contents
collapse into a dropdown under the hero.
- Search becomes a full-screen dialog rather than an inline field.
- The install tabs and command blocks must not overflow horizontally; a
command you cannot read is a command you cannot copy.

## States

| State | What should happen |
| --- | --- |
| **First paint, no JavaScript** | Every page's content is in the HTML, including the changelog entries. Nothing says "Loading". |
| **GitHub unreachable or rate-limited** | Hero metrics stay hidden; the changelog still lists every release from the repo's own file, unlinked and marked not-yet-released. Nothing shows a stale or invented number. |
| **A version in the changelog with no release** | Labelled "Not yet released", and deliberately not linked. |
| **Search index unavailable** | The dialog says so in its own voice, rather than appearing empty or hanging. |
| **Theme: dark, light, or following the system** | All three are selectable and all three are legible; the control shows which is active. |
| **Deep-linked to an anchor** | The target heading is visible and not hidden behind sticky chrome. |
| **Narrow viewport** | No horizontal overflow on any page. Every command block scrolls within itself rather than widening the page. |
| **Print** | Navigation chrome is dropped; the article survives. |

## Known gaps

Recorded so an acceptance pass reports what is new rather than what is
already known. All were measured on a served production build.

- **Page padding is asymmetric.** At 1440px a docs page leaves 29px to the
left of the sidebar and 92px to the right of the contents rail.
- **The two narrow-screen header controls do not match.** Search is
`rgba(17,22,29,0.9)` with a `rgba(140,149,166,0.24)` border; the menu
toggle is `rgba(255,255,255,0.035)` with a `rgba(255,255,255,0.1)` border.
Same size, same radius, different surface.
- **The install section is dense** — 45 copy controls on one page — and the
relative prominence of package manager, script and direct download has not
been decided deliberately.
- **Typography scale is unreviewed** and reads large at desktop widths.
- **The coverage matrix states capabilities as Yes/No** where several rows
are not applicable rather than absent, and it treats the CLI, TUI and MCP
as fully separate when they share one binary and one core.
- **Mobile search layout**: the clear control and the cancel affordance
compete, and the results panel does not extend to the bottom of the
viewport.
- **Anchor links jump the page** rather than moving to the heading quietly.
- **The sidebar's active marker shifts** when a different item is hovered.
- **Breadcrumb separators sit low** relative to their text.
- **The theme control's focus ring is drawn incorrectly**, and its dropdown
is unstyled.

No `design-direction.md` covers this surface: that document scopes itself to
the desktop app. Until one exists, "does this look right" has no written
answer here, and that is the root of most of the list above.