Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
86b5823
feat(packages/config): add root property to Section type and schema
zrosenbauer Apr 10, 2026
0886336
feat(packages/core): propagate root property to ResolvedEntry
zrosenbauer Apr 10, 2026
e451706
test(packages/core): add failing tests for buildRootMeta root section…
zrosenbauer Apr 10, 2026
1979bb9
feat(packages/core): promote root section children in buildRootMeta
zrosenbauer Apr 10, 2026
cf1312f
test(packages/core): add failing tests for buildMetaDirectories root …
zrosenbauer Apr 10, 2026
ec04352
feat(packages/core): expand root sections in buildMetaDirectories
zrosenbauer Apr 10, 2026
a2f0ba9
feat(packages/core): treat root sections as standalone in scopes and nav
zrosenbauer Apr 10, 2026
57b28d8
test(packages/core): add nav generation tests for root sections
zrosenbauer Apr 10, 2026
9b59e66
fix(packages/core): replace ternary with filter+map in root meta test
zrosenbauer Apr 10, 2026
76a6075
chore(packages/config): update generated schema.json with root property
zrosenbauer Apr 10, 2026
47df7f1
feat(examples/kitchen-sink): add root section example with API and CL…
zrosenbauer Apr 10, 2026
4274789
fix(packages/core): address PR review feedback for root section meta …
zrosenbauer Apr 20, 2026
f24cf29
Merge branch 'main' into feat/root-section
zrosenbauer Apr 20, 2026
8a7158e
fix(packages/core): filter hidden root sections and use toBeTruthy in…
zrosenbauer Apr 20, 2026
2967698
fix(packages/core): fix lint error and add changeset
zrosenbauer Apr 20, 2026
847b995
fix(packages/core): add return type annotation for flatMap in buildRo…
zrosenbauer Apr 21, 2026
008a67c
fix(packages/config): restrict title to string on Feature, Workspace,…
zrosenbauer Apr 21, 2026
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
5 changes: 5 additions & 0 deletions .changeset/feat-root-section.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@zpress/core': minor
---

feat: support root sections that promote children to top-level sidebar and nav
21 changes: 21 additions & 0 deletions examples/kitchen-sink/docs/references/api/authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: Authentication
---

# Authentication

All API requests require a Bearer token in the `Authorization` header.

## Obtaining a Token

Send a `POST` request to `/auth/token` with your client credentials:

```bash
curl -X POST https://api.acme.com/auth/token \
-H "Content-Type: application/json" \
-d '{"client_id": "...", "client_secret": "..."}'
```

## Token Refresh

Tokens expire after 1 hour. Use the refresh token to obtain a new access token without re-authenticating.
23 changes: 23 additions & 0 deletions examples/kitchen-sink/docs/references/api/endpoints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
title: Endpoints
---

# Endpoints

## Users

| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/users` | List all users |
| `GET` | `/users/:id` | Get user by ID |
| `POST` | `/users` | Create a user |
| `PATCH` | `/users/:id` | Update a user |
| `DELETE` | `/users/:id` | Delete a user |

## Projects

| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/projects` | List all projects |
| `GET` | `/projects/:id` | Get project by ID |
| `POST` | `/projects` | Create a project |
16 changes: 16 additions & 0 deletions examples/kitchen-sink/docs/references/api/errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
title: Error Codes
---

# Error Codes

All errors return a JSON body with `code`, `message`, and optional `details`.

| Code | HTTP Status | Description |
|------|-------------|-------------|
| `auth_required` | 401 | Missing or invalid authentication |
| `forbidden` | 403 | Insufficient permissions |
| `not_found` | 404 | Resource does not exist |
| `validation_error` | 422 | Request body failed validation |
| `rate_limited` | 429 | Too many requests |
| `internal_error` | 500 | Unexpected server error |
29 changes: 29 additions & 0 deletions examples/kitchen-sink/docs/references/cli/commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
title: Commands
---

# Commands

## `acme init`

Initialize a new Acme project in the current directory.

```bash
acme init [--template <name>]
```

## `acme deploy`

Deploy the current project to production.

```bash
acme deploy [--env <environment>] [--dry-run]
```

## `acme status`

Show the current deployment status.

```bash
acme status [--json]
```
27 changes: 27 additions & 0 deletions examples/kitchen-sink/docs/references/cli/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
title: Configuration
---

# Configuration

The CLI reads configuration from `acme.config.ts` in the project root.

```ts
export default {
org: 'acme',
project: 'web',
region: 'us-east-1',
deploy: {
strategy: 'rolling',
timeout: 300,
},
}
```

## Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `ACME_TOKEN` | API authentication token | — |
| `ACME_ORG` | Organization slug | from config |
| `ACME_LOG_LEVEL` | Log verbosity (`debug`, `info`, `warn`, `error`) | `info` |
22 changes: 22 additions & 0 deletions examples/kitchen-sink/docs/references/cli/installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: Installation
---

# Installation

Install the Acme CLI globally:

```bash
npm install -g @acme/cli
```

Verify the installation:

```bash
acme --version
```

## System Requirements

- Node.js 18 or later
- macOS, Linux, or Windows (WSL)
20 changes: 20 additions & 0 deletions examples/kitchen-sink/zpress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,26 @@ export default defineConfig({
},
],
},
{
title: 'Reference',
icon: 'pixelarticons:book-open',
path: '/references',
root: true,
items: [
{
title: 'API',
path: '/references/api',
include: 'docs/references/api/*.md',
sort: 'alpha',
},
{
title: 'CLI',
path: '/references/cli',
include: 'docs/references/cli/*.md',
sort: 'alpha',
},
],
},
],
sidebar: {
above: [
Expand Down
57 changes: 30 additions & 27 deletions packages/config/schemas/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,30 +98,7 @@
"type": "object",
"properties": {
"title": {
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"from": {
"type": "string",
"enum": [
"auto",
"filename",
"heading",
"frontmatter"
]
},
"transform": {}
},
"required": [
"from"
],
"additionalProperties": false
}
]
"type": "string"
},
"icon": {
"anyOf": [
Expand Down Expand Up @@ -193,7 +170,30 @@
"type": "object",
"properties": {
"title": {
"$ref": "#/definitions/ZpressConfig/properties/apps/items/properties/title"
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"from": {
"type": "string",
"enum": [
"auto",
"filename",
"heading",
"frontmatter"
]
},
"transform": {}
},
"required": [
"from"
],
"additionalProperties": false
}
]
},
"description": {
"type": "string"
Expand Down Expand Up @@ -392,6 +392,9 @@
},
"standalone": {
"type": "boolean"
},
"root": {
"type": "boolean"
}
},
"required": [
Expand Down Expand Up @@ -478,7 +481,7 @@
"type": "object",
"properties": {
"title": {
"$ref": "#/definitions/ZpressConfig/properties/apps/items/properties/title"
"type": "string"
},
"description": {
"type": "string"
Expand Down Expand Up @@ -511,7 +514,7 @@
"type": "object",
"properties": {
"title": {
"$ref": "#/definitions/ZpressConfig/properties/apps/items/properties/title"
"type": "string"
},
"description": {
"type": "string"
Expand Down
7 changes: 4 additions & 3 deletions packages/config/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ const entrySchema: z.ZodType<Section> = z.lazy(() =>
icon: iconConfigSchema.optional(),
card: cardConfigSchema.optional(),
standalone: z.boolean().optional(),
root: z.boolean().optional(),
})
.strict()
)
Expand All @@ -131,7 +132,7 @@ const openapiConfigSchema = z

const workspaceItemSchema = z
.object({
title: titleConfigSchema,
title: z.string(),
icon: iconConfigSchema.optional(),
description: z.string(),
tags: z.array(z.string()).optional(),
Expand All @@ -150,7 +151,7 @@ const workspaceItemSchema = z

const workspaceGroupSchema = z
.object({
title: titleConfigSchema,
title: z.string(),
description: z.string().optional(),
icon: iconIdSchema,
items: z.array(workspaceItemSchema).min(1),
Expand All @@ -160,7 +161,7 @@ const workspaceGroupSchema = z

const featureSchema = z
.object({
title: titleConfigSchema,
title: z.string(),
description: z.string(),
link: z.string().optional(),
icon: iconConfigSchema.optional(),
Expand Down
7 changes: 4 additions & 3 deletions packages/config/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ export interface Section {
readonly icon?: IconConfig
readonly card?: CardConfig
readonly standalone?: boolean
readonly root?: boolean
}

/**
Expand All @@ -285,7 +286,7 @@ export interface Section {
* ```
*/
export interface Workspace {
readonly title: TitleConfig
readonly title: string
readonly icon?: IconConfig
readonly description: string
readonly tags?: readonly string[]
Expand Down Expand Up @@ -324,7 +325,7 @@ export interface Workspace {
* ```
*/
export interface WorkspaceCategory {
readonly title: TitleConfig
readonly title: string
readonly description?: string
readonly icon: IconId
readonly items: readonly Workspace[]
Expand Down Expand Up @@ -395,7 +396,7 @@ export interface OpenAPIConfig {
* ```
*/
export interface Feature {
readonly title: TitleConfig
readonly title: string
readonly description: string
readonly link?: string
readonly icon?: IconConfig
Expand Down
28 changes: 0 additions & 28 deletions packages/core/src/define-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,16 +139,6 @@ function validateWorkspaces(items: readonly Workspace[]): ConfigResult<true> {
}
}

if (typeof item.title !== 'string') {
return {
error: configError(
'invalid_field',
`Workspace "${String(item.title)}": "title" must be a string (TitleConfig not supported on Workspace)`
),
seen: acc.seen,
}
}

if (!item.description) {
return {
error: configError(
Expand Down Expand Up @@ -209,13 +199,6 @@ function validateWorkspaceCategories(categories: readonly WorkspaceCategory[]):
return configError('missing_field', 'WorkspaceCategory: "title" is required')
}

if (typeof category.title !== 'string') {
return configError(
'invalid_field',
`WorkspaceCategory: "title" must be a string (TitleConfig not supported on WorkspaceCategory)`
)
}

if (!category.icon) {
return configError(
'missing_field',
Expand Down Expand Up @@ -393,17 +376,6 @@ function validateFeature(feature: Feature): ConfigError | null {
return configError('missing_field', 'Feature: "title" is required')
}

const titleStr = match(feature.title)
.with(P.string, (t) => t)
.otherwise(() => 'Feature')

if (typeof feature.title !== 'string') {
return configError(
'invalid_field',
`Feature "${titleStr}": "title" must be a string (TitleConfig not supported on Feature)`
)
}

if (!feature.description) {
return configError('missing_field', `Feature "${feature.title}": "description" is required`)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/sync/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ function concatPage(pages: readonly PageData[], page: PageData | undefined): Pag
* @returns Array of standalone scope path strings
*/
function collectStandaloneScopePaths(entries: readonly ResolvedEntry[]): readonly string[] {
return entries.filter((e) => e.standalone && e.link).map((e) => e.link as string)
return entries.filter((e) => (e.standalone || e.root) && e.link).map((e) => e.link as string)
}

/**
Expand Down
Loading
Loading