Skip to content
Open
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
55 changes: 52 additions & 3 deletions packages/backend.ai-docs-toolkit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,23 @@ pnpm build:web

> See the example's [`README.md`](../backend.ai-docs-toolkit-example/README.md#using-the-example-outside-this-monorepo) for the standalone-repo recipe (the `pnpm --filter` build step needs to be replaced).

### Troubleshooting: `docs-toolkit: not found`

`docs-toolkit` is the `bin` of this workspace package. pnpm creates the `node_modules/.bin/docs-toolkit` symlink **at install time**, and only if the toolkit's compiled entrypoint (`dist/cli.js`) already exists. In a fresh clone or new git worktree, `pnpm install` usually runs *before* the toolkit is built, so pnpm skips the symlink. Building the toolkit afterwards (`pnpm --filter backend.ai-docs-toolkit build`) produces `dist/cli.js` but does **not** re-link the bin — so every `docs-toolkit …` invocation (including the `preview:html`, `build:web`, `serve:web` scripts) fails with `docs-toolkit: not found`.

A plain `pnpm install` (even `pnpm install --force`) reports *"Already up to date"* and skips bin-linking, so it does not fix this. Re-link the bin by rebuilding the **consumer** package that depends on the toolkit:

```bash
# from the monorepo root — replace the package name with your docs package
pnpm --filter backend.ai-webui-docs rebuild
```

Verify the command resolves:

```bash
pnpm --filter backend.ai-webui-docs exec docs-toolkit --help
```

## Quick Start

```bash
Expand All @@ -35,6 +52,13 @@ docs-toolkit preview --mode document --lang ko
# Preview (HTML, live-reload)
docs-toolkit preview:html --lang en

# Build a static multi-page website
docs-toolkit build:web --lang all
docs-toolkit build:web --lang en --optimize-images

# Serve the static website (live-reload)
docs-toolkit serve:web --lang en

# Generate Claude AI agent files
docs-toolkit agents
docs-toolkit agents --force # overwrite existing
Expand Down Expand Up @@ -80,26 +104,45 @@ agents:
|---------|-------------|
| `docs-toolkit pdf` | Generate PDF documents |
| `docs-toolkit preview` | PDF preview server with live-reload |
| `docs-toolkit preview:html` | HTML preview server with live-reload |
| `docs-toolkit preview:html` | HTML preview server with live-reload (no PDF) |
| `docs-toolkit build:web` | Generate a static multi-page website |
| `docs-toolkit serve:web` | Static website dev server with live-reload |
| `docs-toolkit init` | Scaffold a new documentation project |
| `docs-toolkit agents` | Generate Claude AI agent files from templates |
| `docs-toolkit help` | Show the CLI help message |

### Common Options

```bash
# PDF generation
docs-toolkit pdf --lang <all|en|ko|...> --theme <name>
docs-toolkit pdf --lang <all|en|ko|...> --theme <name> \
--chapters <comma,separated,names> --note <cover-page note>

# PDF preview
docs-toolkit preview --mode <sample|catalog|document> --lang <lang> --port <port>

# HTML preview
docs-toolkit preview:html --lang <lang> --port <port>
docs-toolkit preview:html --mode <document|catalog> --lang <lang> --port <port>

# Static website build
docs-toolkit build:web --lang <all|en|ko|...> \
--strict|--no-strict --optimize-images --optimize-images-avif

# Static website dev server
docs-toolkit serve:web --lang <lang> --port <port>

# Agent generation
docs-toolkit agents --force # overwrite existing files
```

Notes:

- `pdf --chapters` limits the build to the listed chapter names (default: all chapters).
- `pdf --note` prints a short note on the cover page (e.g. `"Draft — internal review"`).
- `build:web --strict` (default) fails the build on broken links; `--no-strict` downgrades them to warnings.
- `build:web --optimize-images` generates `.webp` variants for PNGs over 50 KB and wraps them in `<picture>`; `--optimize-images-avif` adds `.avif` variants. Both require the optional `sharp` peer dependency.
- Default ports: `preview` → `3456`, `preview:html` → `3457`, `serve:web` → `3458`.

## Agent Template System

The `agents` command generates Claude Code agent files (`.claude/agents/`) and `CLAUDE.md` from Handlebars templates. Templates use variables from the `agents` section of `docs-toolkit.config.yaml`.
Expand Down Expand Up @@ -171,12 +214,18 @@ import {
loadToolkitConfig,
resolveConfig,
generatePdf,
generateWebsite,
startPreviewServer,
startHtmlPreviewServer,
} from 'backend.ai-docs-toolkit';

const config = resolveConfig(loadToolkitConfig(process.cwd()));

// PDF (CLI equivalent: docs-toolkit pdf --lang en)
await generatePdf(config, { lang: 'en' });

// Static website (CLI equivalent: docs-toolkit build:web --lang all)
await generateWebsite(config, { lang: 'all', optimizeImages: true });
```

## Consumer Project Structure
Expand Down
20 changes: 20 additions & 0 deletions packages/backend.ai-docs-toolkit/src/html-builder-web.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,23 @@ test("buildWebDocument — works without config (preview-mode default branding)"
const html = buildWebDocument(sampleChapters, meta);
assert.ok(html.length > 0);
});

test("buildWebDocument — wraps sidebar nav inside .doc-sidebar__scroll (FR-2768 regression guard)", () => {
// FR-2768 made .doc-sidebar a fixed-height, overflow:hidden flex column and
// delegated scrolling to an inner .doc-sidebar__scroll element. If the nav
// is not wrapped in that element, the sidebar can't scroll on overflow.
const html = buildWebDocument(sampleChapters, meta);

const sidebarMatch = html.match(/<aside class="doc-sidebar">[\s\S]*?<\/aside>/);
assert.ok(sidebarMatch, ".doc-sidebar aside not found");
const sidebarHtml = sidebarMatch[0];

const scrollIdx = sidebarHtml.indexOf('class="doc-sidebar__scroll"');
const navIdx = sidebarHtml.indexOf('class="doc-sidebar-nav"');
assert.notStrictEqual(scrollIdx, -1, ".doc-sidebar__scroll wrapper missing from sidebar");
assert.notStrictEqual(navIdx, -1, ".doc-sidebar-nav missing from sidebar");
assert.ok(
scrollIdx < navIdx,
".doc-sidebar-nav must be nested inside the .doc-sidebar__scroll wrapper",
);
});
15 changes: 12 additions & 3 deletions packages/backend.ai-docs-toolkit/src/html-builder-web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,24 @@ function buildSidebarHtml(
})
.join('\n');

// FR-2768 made .doc-sidebar a fixed-height, overflow:hidden flex column
// and delegated scrolling to an inner .doc-sidebar__scroll element (see
// styles-web.ts). website-builder.ts emits that wrapper; this legacy
// single-page preview builder must too, otherwise the nav overflows a
// clipped container with no scrollport and the sidebar can't scroll.
// .doc-sidebar-header is display:none in Phase 2, so leaving it outside
// the scrollport mirrors the pinned version block in website-builder.ts.
return `
<aside class="doc-sidebar">
<div class="doc-sidebar-header">
<h2>${metadata.title}</h2>
<div class="doc-meta">${metadata.version} &middot; ${langLabel}</div>
</div>
<ul class="doc-sidebar-nav">
${navItems}
</ul>
<div class="doc-sidebar__scroll">
<ul class="doc-sidebar-nav">
${navItems}
</ul>
</div>
Comment thread
agatha197 marked this conversation as resolved.
Comment thread
agatha197 marked this conversation as resolved.
</aside>`;
}

Expand Down
Loading