+
+
+```
diff --git a/docs/components/cn-delete-dialog.md b/docs/components/cn-delete-dialog.md
index 6023f96..54f2b5d 100644
--- a/docs/components/cn-delete-dialog.md
+++ b/docs/components/cn-delete-dialog.md
@@ -12,6 +12,33 @@ Two-phase single-item delete confirmation dialog. Shows a warning, waits for API

+## Live demo
+
+```vue
+
+
+
+
+
+
+
+```
+
## Props
| Prop | Type | Default | Description |
@@ -43,7 +70,7 @@ Two-phase single-item delete confirmation dialog. Shows a warning, waits for API
When items don't have a simple name field, use `nameFormatter` to build a display name from any item properties:
-```vue
+```vue {static}
+
+
+
+
+
+
+```
+
## Usage
### Basic (schema-driven)
-```vue
+```vue {static}
```
-```js
+```js {static}
// In setup / data:
const fields = [
{
diff --git a/docs/components/cn-icon.md b/docs/components/cn-icon.md
index f209044..108a0cb 100644
--- a/docs/components/cn-icon.md
+++ b/docs/components/cn-icon.md
@@ -18,7 +18,7 @@ Renders an MDI (Material Design Icons) icon by PascalCase name from an extensibl
## How It Works
-CnIcon maintains an internal `_registry` map of `\{ PascalCaseName: VueComponent \}`. Only `HelpCircleOutline` is pre-registered as the fallback. Apps add their own icons at boot time using `registerIcons()`.
+CnIcon maintains an internal `_registry` map of `{ PascalCaseName: VueComponent }`. Only `HelpCircleOutline` is pre-registered as the fallback. Apps add their own icons at boot time using `registerIcons()`.
## Registering Icons
@@ -37,7 +37,7 @@ registerIcons({ AccountGroupOutline, FileDocumentOutline, Cog })
### Finding Icon Names
-Browse the full MDI icon set at [materialdesignicons.com](https://materialdesignicons.com/). Convert kebab-case to PascalCase:
+Browse the full MDI icon set at [pictogrammers.com/library/mdi/](https://pictogrammers.com/library/mdi/). Convert kebab-case to PascalCase:
| MDI Name | Import Path | Registry Key |
|----------|-------------|--------------|
diff --git a/docs/components/cn-mass-copy-dialog.md b/docs/components/cn-mass-copy-dialog.md
index 5ca33a3..65edd56 100644
--- a/docs/components/cn-mass-copy-dialog.md
+++ b/docs/components/cn-mass-copy-dialog.md
@@ -40,9 +40,36 @@ Two-phase mass copy dialog with naming pattern. Allows users to define a naming
|--------|-------------|
| `setResult(\{ success?, error?, results? \})` | Set result per item |
-## Usage
+## Live demo
```vue
+
+
+
+
+```
+
+## Additional props
+
+### Functional props
+
+| Prop | Default | Description |
+|---|---|---|
+| `dialogTitle` | `''` | Dialog title. Defaults to `'Create {schema.title}'` or `'Edit {schema.title}'` when empty. |
+| `nameField` | `'title'` | Which field is the "name" of the item (used in result messages). |
+| `excludeFields` | `[]` | Array of field keys to exclude from the properties table and form. |
+| `includeFields` | `null` | Array of field keys to include (whitelist mode). Null means all fields. |
+| `fieldOverrides` | `{}` | Per-field override objects passed to `fieldsFromSchema`. |
+| `showPropertiesTable` | `true` | Show or hide the Properties tab. |
+| `showJsonTab` | `true` | Show or hide the Data (JSON) tab. |
+| `showMetadataTab` | `null` | Show or hide the Metadata tab. Defaults to `true` in edit mode, `false` in create mode. |
+| `editablePropertyTypes` | `null` | Array of JSON Schema types for which inline editing is enabled. Defaults to all supported types. |
+| `validationDisplay` | `'indicator'` | How to show property validation state — `'indicator'` or `'none'`. |
+| `jsonEditorDark` | `false` | Enable dark mode in the CodeMirror JSON editor. |
+
+### Slots
+
+| Slot | Description |
+|---|---|
+| `register-schema-selection` | When provided, replaces the default tabbed layout entirely. Useful for a multi-step wizard where register/schema must be chosen before editing. |
+| `tab-properties` | Override the default Properties tab content. Scoped: `{ formData, updateField, objectProperties, selectedProperty, getPropertyDisplayName, getPropertyValidationClass, isPropertyEditable, validationDisplay }`. |
+| `tab-metadata` | Override the default Metadata tab content. Scoped: `{ item, formData }`. |
+| `tab-data` | Override the default Data (JSON) tab content. Scoped: `{ jsonData, updateJson, isValid, formatJson }`. |
+| `form` | Replace the entire dialog form area. Scoped: `{ formData, updateField, objectProperties, jsonData, updateJson, isValidJson }`. |
+
+### Label customization
+
+All user-visible strings have props so they can be pre-translated by the consumer app.
+
+| Prop | Default (English) | Description |
+|---|---|---|
+| `successText` | `'{title} saved successfully.'` | Message shown after a successful save. |
+| `cancelLabel` | `'Cancel'` | Label for the dismiss button before the action is confirmed. |
+| `closeLabel` | `'Close'` | Label for the dismiss button after the result is shown. |
+| `confirmLabel` | `''` | Confirm button label. Defaults to `'Create'` or `'Save'` depending on mode. |
diff --git a/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue b/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue
index 8f6d23a..f54814c 100644
--- a/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue
+++ b/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue
@@ -178,11 +178,11 @@ import {
NcSelect,
NcButton,
NcDateTimePicker,
+ Tooltip,
} from '@nextcloud/vue'
import InformationOutline from 'vue-material-design-icons/InformationOutline.vue'
import Plus from 'vue-material-design-icons/Plus.vue'
import Close from 'vue-material-design-icons/Close.vue'
-import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip.js'
import { formatValue, validateValue } from '../../utils/schema.js'
import CnJsonViewer from '../CnJsonViewer/CnJsonViewer.vue'
import CnColorPicker from '../CnColorPicker/CnColorPicker.vue'
diff --git a/src/components/CnAppLoading/CnAppLoading.md b/src/components/CnAppLoading/CnAppLoading.md
new file mode 100644
index 0000000..22471f2
--- /dev/null
+++ b/src/components/CnAppLoading/CnAppLoading.md
@@ -0,0 +1,47 @@
+Default loading screen — shown while `useAppManifest` fetches the manifest:
+
+```vue
+
+
+
+```
+
+Custom message:
+
+```vue
+
+
+
+```
+
+With logoUrl — shows a branded image above the spinner:
+
+```vue
+
+
+
+```
+
+With logo slot override — render any element above the spinner:
+
+```vue
+
+
+
+
+
+
+
+```
+
+## Additional props and slots
+
+| Prop | Type | Default | Description |
+|------|------|---------|-------------|
+| `logoUrl` | String | `''` | Optional image URL displayed above the spinner. Apps with custom branding can also override the `#logo` slot instead. |
+
+| Slot | Description |
+|------|-------------|
+| `logo` | Replaces the default logo image above the spinner. Use this for custom branding when `logoUrl` alone is not sufficient. |
diff --git a/src/components/CnAppNav/CnAppNav.md b/src/components/CnAppNav/CnAppNav.md
new file mode 100644
index 0000000..c77fb9b
--- /dev/null
+++ b/src/components/CnAppNav/CnAppNav.md
@@ -0,0 +1,57 @@
+CnAppNav renders the Nextcloud app sidebar navigation from a manifest's `menu[]` array. It is normally used inside CnAppRoot which provides the manifest via injection.
+
+Standalone usage with a manifest prop (for use without CnAppRoot):
+
+```vue {static}
+
+
+
+
+
+
+```
+
+Permission filtering — pass a `permissions` array to hide menu items the user does not hold. Items with a `permission` field only render when their permission string appears in the `permissions` prop. When `permissions` is omitted or empty, all items are shown regardless:
+
+```vue {static}
+
+
+
+
+
+
+```
diff --git a/src/components/CnAppRoot/CnAppRoot.md b/src/components/CnAppRoot/CnAppRoot.md
new file mode 100644
index 0000000..e3538c8
--- /dev/null
+++ b/src/components/CnAppRoot/CnAppRoot.md
@@ -0,0 +1,86 @@
+CnAppRoot is the top-level manifest-driven app shell. It orchestrates three phases: loading → dependency check → shell. In a real app it wraps the entire Nextcloud content area.
+
+The component requires a router, Nextcloud globals, and a live capabilities API for dependency checking — it is best demonstrated in a running Nextcloud environment. See `docs/components/cn-app-root.md` and `docs/migrating-to-manifest.md` for full usage.
+
+Minimal conceptual shell (illustrative, not fully runnable in the styleguide):
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+```
+
+With loading state, custom components, translate, permissions, and custom page types:
+
+```vue {static}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Props
+
+| Prop | Type | Required | Default | Description |
+|------|------|----------|---------|-------------|
+| `manifest` | Object | Yes | — | Reactive manifest object from `useAppManifest`. Provides `manifest.dependencies`, `manifest.menu`, and is propagated via provide/inject |
+| `appId` | String | Yes | — | Nextcloud app id. Forwarded to `NcContent` and `CnDependencyMissing` |
+| `isLoading` | Boolean | No | `false` | Whether the manifest is still loading; drives the loading phase |
+| `customComponents` | Object | No | `{}` | Custom-component registry for `type: "custom"` pages and slot overrides in `CnPageRenderer` |
+| `translate` | Function | No | `key => key` | Translate function from the consuming app, typically `(key) => t(appId, key)`. Provided to descendants as `cnTranslate` |
+| `permissions` | Array | No | `[]` | Permission strings for the current user; forwarded to `CnAppNav` for menu filtering |
+| `pageTypes` | Object | No | `null` | Page-type registry map (`type → component`). Falls back to the library's `defaultPageTypes`. Extend with `{ ...defaultPageTypes, report: MyReportPage }` |
+
+## Slots
+
+| Slot | Scope | Description |
+|------|-------|-------------|
+| *(default)* | — | Page content inside `NcAppContent`. Pass `` here in a real app. |
+| `loading` | — | Shown during the loading phase (replaces `CnAppLoading`) |
+| `dependency-missing` | `{ dependencies }` | Shown when required apps are missing (replaces `CnDependencyMissing`) |
+| `menu` | — | Navigation area (replaces `CnAppNav`) |
+| `header-actions` | — | Extra buttons rendered in the app header |
+| `sidebar` | — | Sidebar area rendered alongside `NcAppContent` |
+| `footer` | — | Footer area rendered inside `NcAppContent` |
diff --git a/src/components/CnCard/CnCard.md b/src/components/CnCard/CnCard.md
new file mode 100644
index 0000000..d55ff32
--- /dev/null
+++ b/src/components/CnCard/CnCard.md
@@ -0,0 +1,144 @@
+Basic — title, description, and stats:
+
+```vue
+
+
+
+
+
+```
+
+With icon, iconSize, and titleTooltip:
+
+```vue
+
+
+
+```
+
+With labels and active state:
+
+```vue
+
+
+
+
+
+
+```
+
+With actions slot:
+
+```vue
+
+
+
+
+
+
+
+```
+
+With footer tags and links:
+
+```vue
+
+
+
+```
+
+Controlling description line clamp via descriptionLines:
+
+```vue
+
+```
diff --git a/src/components/CnCellRenderer/CnCellRenderer.vue b/src/components/CnCellRenderer/CnCellRenderer.vue
index c81f53d..0f67fb0 100644
--- a/src/components/CnCellRenderer/CnCellRenderer.vue
+++ b/src/components/CnCellRenderer/CnCellRenderer.vue
@@ -39,8 +39,9 @@ import CheckBold from 'vue-material-design-icons/CheckBold.vue'
* Booleans render as icons, enums as status badges, dates as formatted strings,
* and everything else as truncated text via `formatValue()`.
*
- * @example
+ * ```vue
*
+ * ```
*/
export default {
name: 'CnCellRenderer',
diff --git a/src/components/CnChartWidget/CnChartWidget.md b/src/components/CnChartWidget/CnChartWidget.md
new file mode 100644
index 0000000..0915289
--- /dev/null
+++ b/src/components/CnChartWidget/CnChartWidget.md
@@ -0,0 +1,92 @@
+CnChartWidget wraps ApexCharts for use inside dashboard widget slots. Consuming apps must install `apexcharts` and `vue-apexcharts` as dependencies. The styleguide environment includes these packages, so examples render live.
+
+Area chart — time series data:
+
+```vue
+
+```
+
+Bar chart — category comparison:
+
+```vue
+
+```
+
+Pie chart — distribution:
+
+```vue
+
+```
+
+Donut chart with center label:
+
+```vue
+
+```
+
+Custom `width`, `colors`, `options`, `toolbar`, `legend`, and `unavailableLabel`:
+
+```vue
+
+```
+
+Fallback slot — shown when ApexCharts is not available:
+
+```vue
+
+
+
+ Install apexcharts and vue-apexcharts to see charts.
+
+
+
+```
+
+## Additional props
+
+| Prop | Type | Default | Description |
+|------|------|---------|-------------|
+| `width` | Number\|String | `'100%'` | Chart width (fills container by default) |
+| `options` | Object | `{}` | Custom ApexCharts options deep-merged with the built-in defaults |
+| `colors` | Array | `[]` | Custom color palette (defaults to Nextcloud theme colors) |
+| `toolbar` | Boolean | `false` | Show or hide the ApexCharts toolbar (zoom, download, etc.) |
+| `legend` | Boolean | `true` | Show or hide the chart legend |
+| `unavailableLabel` | String | `'Chart library not available'` | Text shown when ApexCharts cannot be loaded |
+
+## Slots
+
+| Slot | Description |
+|------|-------------|
+| `fallback` | Rendered when the ApexCharts component is not available |
diff --git a/src/components/CnChartWidget/CnChartWidget.vue b/src/components/CnChartWidget/CnChartWidget.vue
index d545043..c81ee35 100644
--- a/src/components/CnChartWidget/CnChartWidget.vue
+++ b/src/components/CnChartWidget/CnChartWidget.vue
@@ -38,25 +38,24 @@ import VueApexCharts from 'vue-apexcharts'
*
* Wraps ApexCharts with sensible defaults for Nextcloud theming.
* Apps must install `apexcharts` and `vue-apexcharts` as dependencies.
- *
- * @example Basic area chart
+ * Basic area chart
+ * ```vue
*
- *
- * @example Pie chart
+ * Pie chart
*
- *
- * @example With custom options
+ * With custom options
*
+ * ```
*/
export default {
name: 'CnChartWidget',
diff --git a/src/components/CnColorPicker/CnColorPicker.md b/src/components/CnColorPicker/CnColorPicker.md
new file mode 100644
index 0000000..abeb4fb
--- /dev/null
+++ b/src/components/CnColorPicker/CnColorPicker.md
@@ -0,0 +1,68 @@
+Basic — click the swatch to open the color picker popover:
+
+```vue
+
+
+
+ {{ color }}
+
+
+
+```
+
+Locked to hex mode — hides the RGB/HSL toggle:
+
+```vue
+
+
+
+ {{ color }}
+
+
+
+```
+
+Disabled state — swatch is not clickable:
+
+```vue
+
+```
+
+Multiple color pickers:
+
+```vue
+
+
+
+
+ {{ item.label }}: {{ item.color }}
+
+
+
+
+```
diff --git a/src/components/CnConfigurationCard/CnConfigurationCard.md b/src/components/CnConfigurationCard/CnConfigurationCard.md
new file mode 100644
index 0000000..8da858b
--- /dev/null
+++ b/src/components/CnConfigurationCard/CnConfigurationCard.md
@@ -0,0 +1,74 @@
+Basic — card with status badge, content, and footer action. The `icon` slot renders before the title in the card header:
+
+```vue
+
+
+
+
+
+
+
+
S3-compatible bucket on us-east-1
+
+```
+
+Cards with content and footer:
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SMTP credentials are required for sending notifications.
+
+
+
+```
+
+With actions:
+
+```vue
+
+
+
+
+
+
+
+
+
+
+ Last tested: 2 hours ago
+
+
+
+
+```
diff --git a/src/components/CnConfigurationCard/CnConfigurationCard.vue b/src/components/CnConfigurationCard/CnConfigurationCard.vue
index 57e8eb7..0a6580f 100644
--- a/src/components/CnConfigurationCard/CnConfigurationCard.vue
+++ b/src/components/CnConfigurationCard/CnConfigurationCard.vue
@@ -35,7 +35,7 @@
* props and slots — no store dependencies. Consumer wraps this and handles
* navigation/store logic.
*
- * @example
+ * ```vue
*
*
* Edit
@@ -45,6 +45,7 @@
*
*
PostgreSQL 15.2 on localhost:5432
*
+ * ```
*/
export default {
name: 'CnConfigurationCard',
diff --git a/src/components/CnContextMenu/CnContextMenu.md b/src/components/CnContextMenu/CnContextMenu.md
new file mode 100644
index 0000000..e66a91d
--- /dev/null
+++ b/src/components/CnContextMenu/CnContextMenu.md
@@ -0,0 +1,57 @@
+CnContextMenu is designed for right-click context menus paired with the `useContextMenu` composable. The menu trigger is hidden by default — it opens programmatically via the `open` prop.
+
+Simulated open state — use `:open.sync` binding in practice:
+
+```vue
+
+
+
+ In real use, right-clicking a row calls openContextMenu(event, row) from useContextMenu().
+ Here we simulate it with a button.
+
+
+
+
+
+
Last action: {{ lastAction || '—' }}
+
+
+
+```
diff --git a/src/components/CnContextMenu/CnContextMenu.vue b/src/components/CnContextMenu/CnContextMenu.vue
index 9c03391..887251c 100644
--- a/src/components/CnContextMenu/CnContextMenu.vue
+++ b/src/components/CnContextMenu/CnContextMenu.vue
@@ -41,15 +41,18 @@ import { NcActions, NcActionButton } from '@nextcloud/vue'
* cursor positioning). The composable handles the DOM attributes; this component
* handles the NcActions template boilerplate.
*
- * @example Dynamic actions (CnIndexPage pattern)
+ * Dynamic actions (CnIndexPage pattern)
+ * ```vue
*
+ * ```
*
- * @example Custom buttons via slot (Doriath pattern)
+ * Custom buttons via slot (Doriath pattern)
+ * ```vue
*
@@ -58,6 +61,7 @@ import { NcActions, NcActionButton } from '@nextcloud/vue'
* Rename
*
*
+ * ```
*/
export default {
name: 'CnContextMenu',
@@ -84,7 +88,7 @@ export default {
* a native tooltip — useful for explaining why an entry is disabled.
* When the entire array is empty (or all entries are filtered out), only
* the default slot content is rendered.
- * @type {Array<{label: string, icon?: object, handler?: Function, disabled?: boolean | Function, visible?: boolean | Function, title?: string | Function, destructive?: boolean}>}
+ * @type {Array<{label: string, icon: object, handler: Function, disabled: boolean | Function, visible: boolean | Function, title: string | Function, destructive: boolean}>}
*/
actions: {
type: Array,
diff --git a/src/components/CnCopyDialog/CnCopyDialog.md b/src/components/CnCopyDialog/CnCopyDialog.md
new file mode 100644
index 0000000..90a717c
--- /dev/null
+++ b/src/components/CnCopyDialog/CnCopyDialog.md
@@ -0,0 +1,118 @@
+Two-phase flow: naming pattern selection → result. Call `setResult()` via ref after the API call:
+
+```vue
+
+
+ Copy item
+
+
+
+
+```
+
+Custom dialog title and name formatter:
+
+```vue
+
+
+ Duplicate Jane Smith
+
+
+
+
+```
+
+Custom patterns — override the naming options shown in the dropdown:
+
+```vue
+
+
+ Copy with custom patterns
+
+
+
+
+```
+
+## Label customization
+
+All user-visible strings have props so they can be pre-translated by the consumer app.
+
+| Prop | Default (English) | Description |
+|---|---|---|
+| `nameFormatter` | `null` | Optional function `(item) => string` to format the displayed item name. Overrides `nameField` when provided. |
+| `dialogTitle` | `'Copy item'` | Dialog title shown in the header. |
+| `patternLabel` | `'Naming pattern'` | Label above the naming pattern dropdown. |
+| `successText` | `'Item successfully copied.'` | Message shown in the success note card after copying. |
+| `cancelLabel` | `'Cancel'` | Label for the dismiss button before the action is confirmed. |
+| `closeLabel` | `'Close'` | Label for the dismiss button after the result is shown. |
+| `confirmLabel` | `'Copy'` | Label for the confirm/copy button. |
diff --git a/src/components/CnCopyDialog/CnCopyDialog.vue b/src/components/CnCopyDialog/CnCopyDialog.vue
index 4190869..856f156 100644
--- a/src/components/CnCopyDialog/CnCopyDialog.vue
+++ b/src/components/CnCopyDialog/CnCopyDialog.vue
@@ -67,13 +67,14 @@ import ContentCopy from 'vue-material-design-icons/ContentCopy.vue'
* and the new name. The parent performs the actual API call and calls
* `setResult()` via a ref.
*
- * @example
+ * ```vue
*
+ * ```
*
* // In methods:
* async onCopyConfirm({ id, newName }) {
diff --git a/src/components/CnDashboardGrid/CnDashboardGrid.md b/src/components/CnDashboardGrid/CnDashboardGrid.md
new file mode 100644
index 0000000..f1c1ad1
--- /dev/null
+++ b/src/components/CnDashboardGrid/CnDashboardGrid.md
@@ -0,0 +1,96 @@
+CnDashboardGrid is the low-level GridStack layout engine. Use `CnDashboardPage` for the full dashboard experience — CnDashboardGrid handles just the drag/drop/resize grid.
+
+Static grid — fixed layout without editing:
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No notes yet.
+
+
+
+
+
+
+
+```
+
+Editable grid with `editable`, `columns`, `cellHeight`, `margin`, `minWidth`, and `minHeight`:
+
+```vue
+
+
` |
+| `cellClass` | Function | `null` | `(row, col) => string` — CSS class(es) applied to each `
` |
+| `scrollable` | Boolean | `false` | Constrain height and make the table vertically scrollable |
+| `loadingText` | String | `'Loading…'` | Text shown below the spinner during loading |
+
+## Slots
+
+| Slot | Scope | Description |
+|------|-------|-------------|
+| `column-{key}` | `{ row, value }` | Override rendering for a specific column cell |
+| `row-actions` | `{ row }` | Action buttons rendered in a trailing actions column |
+| `actions-header` | — | Content shown in the header cell of the actions column |
+| `empty` | — | Custom empty-state content (replaces `emptyText`) |
diff --git a/src/components/CnDataTable/CnDataTable.vue b/src/components/CnDataTable/CnDataTable.vue
index 2991da1..a9ef253 100644
--- a/src/components/CnDataTable/CnDataTable.vue
+++ b/src/components/CnDataTable/CnDataTable.vue
@@ -120,7 +120,8 @@ import { columnsFromSchema } from '../../utils/schema.js'
* (dates, booleans, UUIDs, enums, etc.). Scoped slots still override individual
* columns when needed.
*
- * @example Manual columns (backwards compatible)
+ * Manual columns (backwards compatible)
+ * ```vue
*
+ * ```
*
- * @example Schema-driven (auto columns)
+ * Schema-driven (auto columns)
+ * ```vue
*
+ * ```
*
- * @example Schema with overrides and custom cell
+ * Schema with overrides and custom cell
+ * ```vue
*
*
*
+ * ```
*/
export default {
name: 'CnDataTable',
@@ -156,7 +162,7 @@ export default {
/**
* Column definitions (manual mode).
* Not required when `schema` is provided.
- * @type {Array<{key: string, label: string, sortable?: boolean, width?: string, class?: string, cellClass?: string}>}
+ * @type {Array<{key: string, label: string, sortable: boolean, width: string, class: string, cellClass: string}>}
*/
columns: {
type: Array,
diff --git a/src/components/CnDeleteDialog/CnDeleteDialog.md b/src/components/CnDeleteDialog/CnDeleteDialog.md
new file mode 100644
index 0000000..a334a26
--- /dev/null
+++ b/src/components/CnDeleteDialog/CnDeleteDialog.md
@@ -0,0 +1,113 @@
+Two-phase flow: confirm → result. The parent calls `setResult()` via a ref after the API call:
+
+```vue
+
+
+ Delete item
+
+
+
+
+```
+
+Custom name formatter — override how the item name is resolved:
+
+```vue
+
+
+ Delete Jane Smith
+
+
+
+
+```
+
+Error result — call `setResult({ error: '...' })` on failure:
+
+```vue
+
+
+ Delete (will fail)
+
+
+
+
+```
+
+## Label customization
+
+All user-visible strings have props so they can be pre-translated by the consumer app via `registerTranslations()`.
+
+| Prop | Default (English) | Description |
+|---|---|---|
+| `nameFormatter` | `null` | Optional function `(item) => string` to format the displayed item name. Overrides `nameField` when provided. |
+| `successText` | `'Item successfully deleted.'` | Message shown in the success note card after deletion. |
+| `cancelLabel` | `'Cancel'` | Label for the dismiss button before the action is confirmed. |
+| `closeLabel` | `'Close'` | Label for the dismiss button after the result is shown. |
+| `confirmLabel` | `'Delete'` | Label for the confirm/delete button. |
diff --git a/src/components/CnDeleteDialog/CnDeleteDialog.vue b/src/components/CnDeleteDialog/CnDeleteDialog.vue
index 8994a98..689ac0c 100644
--- a/src/components/CnDeleteDialog/CnDeleteDialog.vue
+++ b/src/components/CnDeleteDialog/CnDeleteDialog.vue
@@ -52,13 +52,14 @@ import TrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'
* itself — it emits a `confirm` event with the item ID. The parent performs
* the actual API call and calls `setResult()` via a ref.
*
- * @example
+ * ```vue
*
+ * ```
*
* // In methods:
* async onDeleteConfirm(id) {
diff --git a/src/components/CnDependencyMissing/CnDependencyMissing.md b/src/components/CnDependencyMissing/CnDependencyMissing.md
new file mode 100644
index 0000000..1c4310f
--- /dev/null
+++ b/src/components/CnDependencyMissing/CnDependencyMissing.md
@@ -0,0 +1,51 @@
+Shown when required apps declared in `manifest.dependencies` are not installed or enabled. CnAppRoot mounts this automatically; apps can override the `#dependency-missing` slot for custom branding.
+
+Not installed:
+
+```vue
+
+
+
+```
+
+App installed but disabled:
+
+```vue
+
+
+
+```
+
+With appName and custom link labels:
+
+```vue
+
+
+
+```
+
+## Additional props
+
+| Prop | Type | Default | Description |
+|------|------|---------|-------------|
+| `appName` | String | `''` | Optional name of the host app included in the default heading |
+| `installLabel` | String | `'Install'` | Label shown on the link for apps that are not yet installed |
+| `enableLabel` | String | `'Enable'` | Label shown on the link for apps that are installed but disabled |
diff --git a/src/components/CnDependencyMissing/CnDependencyMissing.vue b/src/components/CnDependencyMissing/CnDependencyMissing.vue
index 1611a96..2685827 100644
--- a/src/components/CnDependencyMissing/CnDependencyMissing.vue
+++ b/src/components/CnDependencyMissing/CnDependencyMissing.vue
@@ -50,8 +50,7 @@ export default {
* set; otherwise the default Nextcloud apps page is used
* - `enabled` discriminates the link label: `false` means the
* app is installed but disabled; otherwise it's not installed
- *
- * @type {Array<{id: string, name?: string, installUrl?: string, enabled?: boolean}>}
+ * @type {Array<{id: string, name: string, installUrl: string, enabled: boolean}>}
*/
dependencies: {
type: Array,
diff --git a/src/components/CnDetailCard/CnDetailCard.md b/src/components/CnDetailCard/CnDetailCard.md
new file mode 100644
index 0000000..66c9a60
--- /dev/null
+++ b/src/components/CnDetailCard/CnDetailCard.md
@@ -0,0 +1,91 @@
+Basic — card with title and content:
+
+```vue
+
+
+
+```
+
+With icon and actions slot:
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+Collapsible — click header to collapse/expand:
+
+```vue
+
+
+
+
+
+
+
+
+```
+
+Flush — removes padding so tables/lists go edge-to-edge:
+
+```vue
+
+
+
+ Item {{ i }}
+
+
+
+```
+
+With footer slot:
+
+```vue
+
+
Main content goes here.
+
+
+
+
+```
+
+## Additional props and slots
+
+| Prop | Type | Default | Description |
+|------|------|---------|-------------|
+| `icon` | Object\|Function | `null` | Optional MDI icon component rendered in the card header |
+
+| Slot | Description |
+|------|-------------|
+| `icon` | Override the header icon (replaces the `icon` prop rendering) |
+| `footer` | Footer content rendered below the card body (with a top border) |
diff --git a/src/components/CnDetailCard/CnDetailCard.vue b/src/components/CnDetailCard/CnDetailCard.vue
index efab620..9aaa0fb 100644
--- a/src/components/CnDetailCard/CnDetailCard.vue
+++ b/src/components/CnDetailCard/CnDetailCard.vue
@@ -55,23 +55,29 @@ import ChevronDown from 'vue-material-design-icons/ChevronDown.vue'
/**
* CnDetailCard — Card container for detail page sections.
*
- * @example Basic usage
+ * Basic usage
+ * ```vue
*
*
...
*
+ * ```
*
- * @example With icon and actions
+ * With icon and actions
+ * ```vue
*
*
* Edit
*
*
*
+ * ```
*
- * @example Collapsible
+ * Collapsible
+ * ```vue
*
*
*
+ * ```
*/
export default {
name: 'CnDetailCard',
diff --git a/src/components/CnDetailGrid/CnDetailGrid.md b/src/components/CnDetailGrid/CnDetailGrid.md
new file mode 100644
index 0000000..a233eb8
--- /dev/null
+++ b/src/components/CnDetailGrid/CnDetailGrid.md
@@ -0,0 +1,105 @@
+Grid layout (default) — items flow in a responsive auto-fit grid:
+
+```vue
+
+```
+
+Horizontal layout — label on the left, value on the right:
+
+```vue
+
+```
+
+Custom slot content — override a value with a component:
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+Fixed columns — pin to an exact number instead of auto-fit:
+
+```vue
+
+```
+
+Layout tuning — narrow `minItemWidth` for compact grids; wider `labelWidth` for long labels; no accent border:
+
+```vue
+
+```
+
+Empty state — custom message via the `empty` slot when `items` is empty:
+
+```vue
+
+
+
+ No details have been filled in yet.
+
+
+
+```
+
+## Additional props
+
+| Prop | Type | Default | Description |
+|---|---|---|---|
+| `minItemWidth` | `Number` | `250` | Minimum item width (px) for the auto-fit grid. Only applies when `columns` is `0` and `layout` is `'grid'` |
+| `labelWidth` | `Number` | `150` | Minimum label width (px) in horizontal mode |
+| `accent` | `Boolean` | `true` | Show a primary-color left border on each item |
+| `emptyLabel` | `String` | `'No details available'` | Text shown when `items` is empty and the `empty` slot is not used |
+
+## Slots
+
+| Slot | Scope | Description |
+|---|---|---|
+| `empty` | — | Custom empty state, shown when `items` is empty and no default slot content is provided |
+| `item-{index}` | `{ item, index }` | Override the value cell for a specific item |
+| `label-{index}` | `{ item, index }` | Override the label cell for a specific item |
+| `item-actions-{index}` | `{ item, index }` | Add action buttons after the value for a specific item |
+| default | — | Append extra items after the data-driven ones |
diff --git a/src/components/CnDetailGrid/CnDetailGrid.vue b/src/components/CnDetailGrid/CnDetailGrid.vue
index 1d39c4f..564a8e6 100644
--- a/src/components/CnDetailGrid/CnDetailGrid.vue
+++ b/src/components/CnDetailGrid/CnDetailGrid.vue
@@ -57,14 +57,17 @@ import { translate as t } from '@nextcloud/l10n'
/**
* CnDetailGrid — Data-driven label-value grid for detail/info sections.
*
- * @example Simple data-driven grid
+ * Simple data-driven grid
+ * ```vue
*
+ * ```
*
- * @example Grid with custom slot content
+ * Grid with custom slot content
+ * ```vue
*
*
*
+ * ```
*
- * @example Horizontal row layout
+ * Horizontal row layout
+ * ```vue
*
+ * ```
*/
export default {
name: 'CnDetailGrid',
@@ -83,7 +89,7 @@ export default {
props: {
/**
* Array of detail items to render.
- * @type {Array<{ label: string, value?: string|number }>}
+ * @type {Array<{ label: string, value: string|number }>}
*/
items: {
type: Array,
diff --git a/src/components/CnDetailPage/CnDetailPage.md b/src/components/CnDetailPage/CnDetailPage.md
new file mode 100644
index 0000000..e8cc83f
--- /dev/null
+++ b/src/components/CnDetailPage/CnDetailPage.md
@@ -0,0 +1,214 @@
+CnDetailPage is the generic detail/overview page with stats, cards, and flexible content slots.
+
+Full example with header, stats, and data card:
+
+```vue
+
+
+
+
+```
+
+## Additional props
+
+| Prop | Type | Default | Description |
+|------|------|---------|-------------|
+| `icon` | String | `''` | Optional MDI icon name rendered in the header via `CnIcon` |
+| `iconSize` | Number | `28` | Icon size in pixels |
+| `loadingLabel` | String | `'Loading...'` | Message shown below the spinner during loading |
+| `sidebarOpen` | Boolean | `true` | Whether the sidebar starts expanded |
+| `objectType` | String | `''` | Registered object type slug for the sidebar |
+| `objectId` | String\|Number | `''` | Object ID to display in the sidebar |
+| `subtitle` | String | `''` | Subtitle shown in the sidebar header |
+| `sidebarProps` | Object | `{}` | Extra sidebar configuration (`register`, `schema`, `hiddenTabs`, `title`, `subtitle`) |
+| `error` | Boolean | `false` | Whether the page is in an error state |
+| `errorMessage` | String | `'An error occurred'` | Error message shown in the error state |
+| `onRetry` | Function | `null` | Callback for the retry button; when `null` no retry button is shown |
+| `retryLabel` | String | `'Retry'` | Label for the retry button |
+| `empty` | Boolean | `false` | Whether there is no data to show |
+| `emptyLabel` | String | `'No data available'` | Message shown in the empty state |
+| `statsTitle` | String | `''` | Title shown above the statistics table |
+| `statsColumns` | Array | `[]` | Column definitions for the stats table: `{ key, label, align? }` |
+| `statsRows` | Array | `[]` | Row data for the stats table; set `indent: true` for sub-row styling |
+| `maxWidth` | String | `'1200px'` | Maximum width of the page content area |
+
+## Slots
+
+| Slot | Description |
+|------|-------------|
+| `header` | Replace the left header block (icon + title + description). Scope: `{ title, description, icon, iconSize }` |
+| `icon` | Replace the icon inside the default header |
+| `actions` | Action buttons rendered in the right-hand header area |
+| `error` | Custom error state content (replaces default `NcEmptyContent`) |
+| `empty` | Custom empty state content |
+| `stats-header` | Content above the stats table (replaces the default `statsTitle` heading) |
+| `stats-rows` | Custom `
` rows inside the stats table body |
+| `sections` | Additional content below the main content area |
+| `footer` | Footer content rendered below the body |
+| `widget-{widgetId}` | Widget slot in grid layout mode. Scope: `{ item, widget }` |
diff --git a/src/components/CnDetailPage/CnDetailPage.vue b/src/components/CnDetailPage/CnDetailPage.vue
index e7833a8..66779f0 100644
--- a/src/components/CnDetailPage/CnDetailPage.vue
+++ b/src/components/CnDetailPage/CnDetailPage.vue
@@ -185,14 +185,15 @@ import Refresh from 'vue-material-design-icons/Refresh.vue'
* 2. **Grid layout:** When `layout` and `widgets` props are provided, content renders in a
* 12-column CSS grid with `#widget-{widgetId}` scoped slots. Same API as CnDashboardPage.
*
- * @example Basic usage (vertical stacking)
+ * Basic usage (vertical stacking)
*
* A simpler alternative to CnIndexPage for pages that display detail info,
* statistics, charts, or card grids — without multi-object tables or CRUD
* dialogs. Provides a consistent layout with header, loading/error/empty
* states, a statistics table, and flexible content slots.
*
- * @example Basic usage with stats table and content
+ * Basic usage with stats table and content
+ * ```vue
*
*
*
+ * ```
*
- * @example Grid layout mode
+ * Grid layout mode
+ * ```vue
*
*
*
+ * ```
*
- * @example With header actions and error handling
+ * With header actions and error handling
+ * ```vue
*
*
*
+ * ```
*/
export default {
name: 'CnDetailPage',
@@ -360,8 +366,7 @@ export default {
/**
* Column definitions for the statistics table.
* Each column: `{ key: string, label: string, align?: 'left'|'center'|'right' }`
- *
- * @type {Array<{ key: string, label: string, align?: string }>}
+ * @type {Array<{ key: string, label: string, align: string }>}
*/
statsColumns: {
type: Array,
diff --git a/src/components/CnFacetSidebar/CnFacetSidebar.md b/src/components/CnFacetSidebar/CnFacetSidebar.md
new file mode 100644
index 0000000..e12381d
--- /dev/null
+++ b/src/components/CnFacetSidebar/CnFacetSidebar.md
@@ -0,0 +1,139 @@
+Basic — schema-driven facet sidebar with select and checkbox filters:
+
+```vue
+
+
+
+
+
+
+
Active filters: {{ JSON.stringify(activeFilters) }}
+
+
+
+
+```
+
+Loading state:
+
+```vue
+
+```
+
+With live `facetData` from the API — option labels include counts when facet data is provided:
+
+```vue
+
+
+
+
+
+
+
Active: {{ JSON.stringify(activeFilters) }}
+
+
+
+
+```
+
+Admin-only filters — set `userIsAdmin` to `false` to hide schema properties marked `adminOnly: true`:
+
+```vue
+ {}"
+ @clear-all="() => {}" />
+```
+
+## Additional props
+
+| Prop | Type | Default | Description |
+|---|---|---|---|
+| `facetData` | `Object` | `{}` | Live facet data from the API: `{ fieldName: { values: [{ value, count }] } }`. When a field has facet data, its option labels include the count in parentheses. Falls back to the static `enum` values from the schema. |
+| `clearLabel` | `String` | `'Clear all'` | Label for the "Clear all" button shown when any filter is active |
+| `userIsAdmin` | `Boolean` | `true` | When `false`, schema properties with `adminOnly: true` are hidden from the filter list |
diff --git a/src/components/CnFacetSidebar/CnFacetSidebar.vue b/src/components/CnFacetSidebar/CnFacetSidebar.vue
index aab1cd5..020f89e 100644
--- a/src/components/CnFacetSidebar/CnFacetSidebar.vue
+++ b/src/components/CnFacetSidebar/CnFacetSidebar.vue
@@ -70,13 +70,14 @@ import { filtersFromSchema } from '../../utils/schema.js'
* appropriate filter widgets. Accepts live facet data from the API for
* dynamic option values with counts.
*
- * @example
+ * ```vue
*
+ * ```
*/
export default {
name: 'CnFacetSidebar',
@@ -93,7 +94,7 @@ export default {
/** Schema definition — reads facetable properties */
schema: {
type: Object,
- required: true,
+ default: null,
},
/** Live facet data from API: { fieldName: { values: [{value, count}] } } */
facetData: {
diff --git a/src/components/CnFilterBar/CnFilterBar.md b/src/components/CnFilterBar/CnFilterBar.md
new file mode 100644
index 0000000..65dde32
--- /dev/null
+++ b/src/components/CnFilterBar/CnFilterBar.md
@@ -0,0 +1,110 @@
+Search only — just the search input with clear button. The `showClearAll` prop (default `true`) controls whether the "Clear filters" button appears when there are active filters; `clearAllLabel` customises its text:
+
+```vue
+
+
+
+
+```
+
+Hide the clear button — set `showClearAll` to `false` when the parent controls reset itself:
+
+```vue
+
+```
+
+Custom clear label — override the default "Clear filters" text via `clearAllLabel`:
+
+```vue
+
+```
diff --git a/src/components/CnFilterBar/CnFilterBar.vue b/src/components/CnFilterBar/CnFilterBar.vue
index 11c4d99..13f086e 100644
--- a/src/components/CnFilterBar/CnFilterBar.vue
+++ b/src/components/CnFilterBar/CnFilterBar.vue
@@ -74,7 +74,7 @@ import Magnify from 'vue-material-design-icons/Magnify.vue'
* LeadList, RequestList across Pipelinq and Procest. Supports text search,
* select dropdowns, text inputs, and checkbox filters.
*
- * @example
+ * ```vue
*
+ * ```
*/
export default {
name: 'CnFilterBar',
@@ -99,8 +100,9 @@ export default {
props: {
/**
- * Filter definitions.
- * @type {Array<{key: string, label: string, type: 'select'|'text'|'checkbox', options?: Array, value?: *}>}
+ * Filter definitions. Each item has `key`, `label`, `type` ('select'|'text'|'checkbox'),
+ * optional `options` (for select), and optional `value`.
+ * @type {Array<{key: string, label: string, type: 'select'|'text'|'checkbox', options: Array, value: any}>}
*/
filters: {
type: Array,
@@ -144,7 +146,7 @@ export default {
onFilterChange(key, value) {
/**
* @event filter-change Emitted when any filter changes.
- * @type {{ key: string, value: * }}
+ * @type {{ key: string, value: any }}
*/
this.$emit('filter-change', { key, value })
},
diff --git a/src/components/CnFormDialog/CnFormDialog.md b/src/components/CnFormDialog/CnFormDialog.md
new file mode 100644
index 0000000..a4f223b
--- /dev/null
+++ b/src/components/CnFormDialog/CnFormDialog.md
@@ -0,0 +1,125 @@
+Create mode — `item` is null, fields generated from schema:
+
+```vue
+
+
+ Add contact
+
+
+
+
+```
+
+Edit mode — pre-populate form with `item` data:
+
+```vue
+
+
+ Edit contact
+
+
+
+
+```
+
+## Additional props
+
+### Functional props
+
+| Prop | Default | Description |
+|---|---|---|
+| `dialogTitle` | `''` | Dialog title. Defaults to `'Create {schema.title}'` or `'Edit {schema.title}'` when empty. |
+| `excludeFields` | `[]` | Array of field keys to exclude from the auto-generated form. |
+| `includeFields` | `null` | Array of field keys to include (whitelist mode). Null means all fields. |
+| `fieldOverrides` | `{}` | Per-field override objects passed to `fieldsFromSchema`. |
+| `nameField` | `'title'` | Which field is the "name" of the item (used in result messages). |
+| `size` | `'normal'` | NcDialog size — `'small'`, `'normal'`, or `'large'`. |
+
+### Slots
+
+| Slot | Description |
+|---|---|
+| `before-fields` | Rendered before the first auto-generated field (after the `#form` slot check). Useful for adding introductory text or non-schema inputs. |
+| `after-fields` | Rendered after the last auto-generated field. |
+| `form` | Replace the entire auto-generated form. Scoped: `{ fields, formData, errors, updateField }`. |
+| `field-{key}` | Replace a single auto-generated field. Scoped: `{ field, value, error, updateField }`. |
+| `field-{key}-option` | Customize dropdown option rendering for a select/multiselect/tags field. |
+| `field-{key}-selected-option` | Customize selected option display for a select/multiselect/tags field. |
+
+### Label customization
+
+All user-visible strings have props so they can be pre-translated by the consumer app.
+
+| Prop | Default (English) | Description |
+|---|---|---|
+| `successText` | `'{title} saved successfully.'` | Message shown after a successful save. |
+| `cancelLabel` | `'Cancel'` | Label for the dismiss button before the action is confirmed. |
+| `closeLabel` | `'Close'` | Label for the dismiss button after the result is shown. |
+| `confirmLabel` | `''` | Confirm button label. Defaults to `'Create'` or `'Save'` depending on mode. |
diff --git a/src/components/CnFormDialog/CnFormDialog.vue b/src/components/CnFormDialog/CnFormDialog.vue
index 4d7921c..139f3a5 100644
--- a/src/components/CnFormDialog/CnFormDialog.vue
+++ b/src/components/CnFormDialog/CnFormDialog.vue
@@ -354,7 +354,7 @@ import { fieldsFromSchema } from '../../utils/schema.js'
* @event confirm Emitted when the user confirms the form. Payload: formData object (includes `id` in edit mode).
* @event close Emitted when the dialog should be closed (cancel, close button, or auto-close after success).
*
- * @example
+ * ```vue
*
+ * ```
*
* // In methods:
* async onFormConfirm(formData) {
@@ -377,7 +378,8 @@ import { fieldsFromSchema } from '../../utils/schema.js'
* }
* }
*
- * @example
+
+
+```
+
+## Additional props
+
+| Prop | Type | Default | Description |
+|------|------|---------|-------------|
+| `description` | String | `''` | Optional description shown below the title in the page header |
+| `showTitle` | Boolean | `false` | Whether to show the inline page header (title, icon, description) |
+| `icon` | String | `''` | Optional MDI icon name; falls back to `schema.icon` |
+| `columns` | Array | `[]` | Manual column definitions (overrides schema-generated columns) |
+| `selectable` | Boolean | `true` | Whether rows/cards can be selected for mass actions |
+| `selectedIds` | Array | `[]` | Currently selected row IDs (controlled) |
+| `sortKey` | String | `null` | Current sort key |
+| `sortOrder` | String | `'asc'` | Current sort direction (`'asc'` or `'desc'`) |
+| `rowKey` | String | `'id'` | Property name used as the unique row identifier |
+| `excludeColumns` | Array | `[]` | Column keys to hide in schema mode |
+| `includeColumns` | Array | `null` | Column keys to show (whitelist); `null` means all |
+| `columnOverrides` | Object | `{}` | Per-column config overrides in schema mode |
+| `emptyText` | String | `'No items found'` | Text shown in the empty state |
+| `rowClass` | Function | `null` | Callback returning CSS class(es) for a row |
+| `inlineActionCount` | Number | `2` | How many row actions to show inline (rest go in overflow menu) |
+| `showMassImport` | Boolean | `true` | Whether to show the mass Import action |
+| `showMassCopy` | Boolean | `true` | Whether to show the mass Copy action |
+| `massActionNameField` | String | `'title'` | Property name used to display item names in dialogs |
+| `nameFormatter` | Function | `null` | Custom formatter for item names in dialogs; overrides `massActionNameField` |
+| `exportFormats` | Array | `[Excel, CSV]` | Available export formats for the export dialog |
+| `importOptions` | Array | `[]` | Import option definitions for the import dialog |
+| `showFormDialog` | Boolean | `true` | Whether to show the built-in form dialog for Add/Edit |
+| `useAdvancedFormDialog` | Boolean | `false` | Use `CnAdvancedFormDialog` instead of `CnFormDialog` for Add/Edit |
+| `showViewAction` | Boolean | `true` | Whether to add a View row action |
+| `showEditAction` | Boolean | `true` | Whether to add an Edit row action |
+| `showCopyAction` | Boolean | `true` | Whether to add a Copy row action |
+| `showDeleteAction` | Boolean | `true` | Whether to add a Delete row action |
+| `excludeFields` | Array | `[]` | Field keys to exclude from the form dialog |
+| `includeFields` | Array | `null` | Field keys to include in the form dialog (whitelist) |
+| `fieldOverrides` | Object | `{}` | Per-field config overrides passed to `CnFormDialog` |
+| `showViewToggle` | Boolean | `true` | Whether to show the Cards/Table view toggle |
+| `refreshing` | Boolean | `false` | Whether a refresh is currently in progress |
+| `refreshDisabled` | Boolean | `false` | Whether the refresh button is disabled |
+| `addDisabled` | Boolean | `false` | Whether the Add button is disabled |
+| `showAdd` | Boolean | `true` | Whether to show the Add button |
+| `store` | Object | `null` | Store instance for automatic save integration |
+| `objectType` | String | `''` | Object type slug for store integration (e.g. `registerId-schemaId`) |
+
+## Slots
+
+| Slot | Scope | Description |
+|------|-------|-------------|
+| `header` | `{ title, description, icon, showTitle }` | Replace the entire page header |
+| `below-header` | — | Content between the header and the actions bar |
+| `mass-actions` | `{ count, selectedIds }` | Extra mass action buttons shown when items are selected |
+| `action-items` | — | Extra buttons in the action bar |
+| `actions` | — | Extra action bar buttons (alias) |
+| `delete-dialog` | `{ item, close }` | Replace the single-item delete dialog |
+| `copy-dialog` | `{ item, close }` | Replace the single-item copy dialog |
+| `form-dialog` | `{ item, schema, close }` | Replace the create/edit form dialog |
+| `form-fields` | `{ fields, formData, errors, updateField }` | Replace form content inside the built-in `CnFormDialog` |
+| `import-fields` | `{ file }` | Extra fields in the import dialog |
+| `empty` | — | Custom empty state content |
+| `card` | `{ object, selected }` | Custom card template for card view |
+| `row-actions` | `{ row }` | Custom row actions |
+| `column-{key}` | `{ row, value }` | Custom cell renderer for a specific column |
diff --git a/src/components/CnIndexPage/CnIndexPage.vue b/src/components/CnIndexPage/CnIndexPage.vue
index 034ce1f..9b2cf6c 100644
--- a/src/components/CnIndexPage/CnIndexPage.vue
+++ b/src/components/CnIndexPage/CnIndexPage.vue
@@ -307,7 +307,8 @@ import { useContextMenu } from '../../composables/index.js'
*
* Use the `useAdvancedFormDialog` prop to use CnAdvancedFormDialog for create/edit (properties table, JSON tab, optional metadata).
*
- * @example Minimal usage (auto-generated dialogs from schema)
+ * Minimal usage (auto-generated dialogs from schema)
+ * ```vue
*
+ * ```
*
- * @example With custom form dialog
+ * With custom form dialog
+ * ```vue
*
*
*
*
*
+ * ```
*
* @event {void} add — Add button clicked (backward compat, only if listener attached)
* @event {object} create — Form dialog create confirmed. Payload: formData object
@@ -501,7 +505,7 @@ export default {
/** How many action buttons to show inline (rest go in overflow dropdown) */
inlineActionCount: {
type: Number,
- default: 2,
+ default: 0,
},
/** Whether to show the built-in mass Import action */
showMassImport: {
diff --git a/src/components/CnIndexSidebar/CnIndexSidebar.md b/src/components/CnIndexSidebar/CnIndexSidebar.md
new file mode 100644
index 0000000..4f8a73e
--- /dev/null
+++ b/src/components/CnIndexSidebar/CnIndexSidebar.md
@@ -0,0 +1,161 @@
+CnIndexSidebar wraps `NcAppSidebar` — it renders inside the Nextcloud app layout. In the styleguide it displays in a contained box.
+
+Basic — search tab with schema-driven filters:
+
+```vue
+
+
+ {}" />
+
+
+
+```
+
+With icon, visible columns, and column groups:
+
+```vue
+
+
+
+
+```
+
+With live facet data from the API:
+
+```vue
+
+
+
+
+```
+
+With custom tab labels and default tab:
+
+```vue
+
+```
+
+With admin-only filter control:
+
+```vue
+ {}" />
+```
+
+## Additional props
+
+| Prop | Type | Default | Description |
+|------|------|---------|-------------|
+| `icon` | String | `''` | MDI icon name or emoji shown in the sidebar header. Falls back to `schema.icon` |
+| `visibleColumns` | Array | `null` | Currently visible column keys; `null` means all visible |
+| `facetData` | Object | `{}` | Live facet data from the API: `{ fieldName: { values: [{ value, count }] } }` |
+| `columnGroups` | Array | `[]` | Extra column groups beyond schema properties and built-in Metadata. Each: `{ id, label, columns: [{ key, label }], expanded? }` |
+| `showMetadata` | Boolean | `true` | Whether to include the built-in Metadata column group |
+| `searchPlaceholder` | String | `'Type to search...'` | Placeholder text for the search input |
+| `searchTabLabel` | String | `'Search'` | Label for the Search tab |
+| `columnsTabLabel` | String | `'Columns'` | Label for the Columns tab |
+| `searchLabel` | String | `'Search'` | Heading for the search field section |
+| `filtersLabel` | String | `'Filters'` | Heading for the filters section |
+| `columnsHeading` | String | `'Column visibility'` | Heading for the column visibility section |
+| `columnsDescription` | String | `'Select which columns to display in the table'` | Description below the column visibility heading |
+| `propertiesGroupLabel` | String | `''` | Override label for the schema properties group. Falls back to `schema.title` |
+| `defaultTab` | String | `'search-tab'` | Tab id that is active when the sidebar opens. Built-in ids: `'search-tab'`, `'columns-tab'` |
+| `userIsAdmin` | Boolean | `true` | When `false`, schema properties with `adminOnly: true` are hidden from filters |
diff --git a/src/components/CnIndexSidebar/CnIndexSidebar.vue b/src/components/CnIndexSidebar/CnIndexSidebar.vue
index aab34e4..24ee4b1 100644
--- a/src/components/CnIndexSidebar/CnIndexSidebar.vue
+++ b/src/components/CnIndexSidebar/CnIndexSidebar.vue
@@ -185,14 +185,15 @@ import { METADATA_COLUMNS } from '../../constants/metadata.js'
* Must be rendered at the App.vue level as a sibling of NcAppContent.
* Use provide/inject to connect it to page components.
*
- * @example
*
+ * ```vue
*
+ * ```
*
* @slot search-above - Content rendered above the search field in the Search tab (e.g. hints, quick actions).
* @slot search-extra - Content rendered below the search field and filters in the Search tab (e.g. saved searches).
diff --git a/src/components/CnInfoWidget/CnInfoWidget.vue b/src/components/CnInfoWidget/CnInfoWidget.vue
index 611cf72..096bf34 100644
--- a/src/components/CnInfoWidget/CnInfoWidget.vue
+++ b/src/components/CnInfoWidget/CnInfoWidget.vue
@@ -29,14 +29,18 @@
/**
* CnInfoWidget — Renders label-value pairs in a responsive CSS grid.
*
- * @example Manual fields
+ * Manual fields
+ * ```vue
*
+ * ```
*
- * @example Auto-generated from schema
+ * Auto-generated from schema
+ * ```vue
*
+ * ```
*/
export default {
name: 'CnInfoWidget',
diff --git a/src/components/CnItemCard/CnItemCard.vue b/src/components/CnItemCard/CnItemCard.vue
index 74f9f3f..df40d9c 100644
--- a/src/components/CnItemCard/CnItemCard.vue
+++ b/src/components/CnItemCard/CnItemCard.vue
@@ -30,12 +30,15 @@
* a flexible content area. Designed for use in sidebar lists such as
* schema listings, source listings, etc.
*
- * @example Basic usage
+ * Basic usage
+ * ```vue
*
*
Schema content here
*
+ * ```
*
- * @example With actions and stats
+ * With actions and stats
+ * ```vue
*
*
*
@@ -47,6 +50,7 @@
*
*
*
+ * ```
*/
export default {
name: 'CnItemCard',
diff --git a/src/components/CnJsonViewer/CnJsonViewer.md b/src/components/CnJsonViewer/CnJsonViewer.md
new file mode 100644
index 0000000..1e7a18e
--- /dev/null
+++ b/src/components/CnJsonViewer/CnJsonViewer.md
@@ -0,0 +1,88 @@
+Read-only JSON display:
+
+```vue
+
+```
+
+Editable JSON with format button:
+
+```vue
+
+
+
+
+ Type invalid JSON to see the error indicator.
+
+
+
+
+```
+
+XML mode:
+
+```vue
+
+```
+
+Custom error text — use `errorText` to replace the built-in "Invalid JSON format" banner with a caller-controlled message. The banner shows when `errorText` is a non-empty string and hides when it is empty:
+
+```vue
+
+
+
+
+
+
+```
+
+Auto-detect mode — sniffs JSON, XML/HTML, or falls back to plain text:
+
+```vue
+
+
+
+
JSON (auto-detected)
+
+
+
+
Plain text (fallback)
+
+
+
+
+```
diff --git a/src/components/CnJsonViewer/CnJsonViewer.vue b/src/components/CnJsonViewer/CnJsonViewer.vue
index c594d7f..d9871f7 100644
--- a/src/components/CnJsonViewer/CnJsonViewer.vue
+++ b/src/components/CnJsonViewer/CnJsonViewer.vue
@@ -49,17 +49,25 @@ import { getTheme } from '../../utils/getTheme.js'
* Includes syntax highlighting, and optional formatting/validation for JSON.
* Use `readOnly` for display-only mode.
*
- * @example Read-only JSON display (default)
+ * Read-only JSON display (default)
+ * ```vue
*
+ * ```
*
- * @example Auto-detect language from content
+ * Auto-detect language from content
+ * ```vue
*
+ * ```
*
- * @example Explicit XML mode
+ * Explicit XML mode
+ * ```vue
*
+ * ```
*
- * @example Editable JSON with custom height
+ * Editable JSON with custom height
+ * ```vue
*
+ * ```
*/
export default {
name: 'CnJsonViewer',
diff --git a/src/components/CnKpiGrid/CnKpiGrid.md b/src/components/CnKpiGrid/CnKpiGrid.md
new file mode 100644
index 0000000..47bc2b6
--- /dev/null
+++ b/src/components/CnKpiGrid/CnKpiGrid.md
@@ -0,0 +1,38 @@
+4-column dashboard row (default) — responsive, collapses to 2 at 1200px:
+
+```vue
+
+
+
+
+
+
+```
+
+2-column layout:
+
+```vue
+
+
+
+
+```
+
+3-column layout:
+
+```vue
+
+
+
+
+
+```
+
+Custom grid class — use `gridClass` to add an extra CSS class to the grid wrapper for additional spacing or layout tweaks:
+
+```vue
+
+
+
+
+```
diff --git a/src/components/CnKpiGrid/CnKpiGrid.vue b/src/components/CnKpiGrid/CnKpiGrid.vue
index c0b13e2..8fce853 100644
--- a/src/components/CnKpiGrid/CnKpiGrid.vue
+++ b/src/components/CnKpiGrid/CnKpiGrid.vue
@@ -11,19 +11,26 @@
* Wraps CnStatsBlock components in a responsive CSS grid. Supports
* 2, 3, or 4 column layouts that adapt to screen size.
*
- * @example 4-column dashboard (default)
+ * 4-column dashboard (default)
+ *
+ * ```vue
*
*
*
*
*
*
+ * ```
+ *
*
- * @example 2-column layout
+ * 2-column layout
+ * ```vue
*
*
*
*
+ * ```
+ *
*/
export default {
name: 'CnKpiGrid',
diff --git a/src/components/CnMassActionBar/CnMassActionBar.md b/src/components/CnMassActionBar/CnMassActionBar.md
new file mode 100644
index 0000000..0ea7314
--- /dev/null
+++ b/src/components/CnMassActionBar/CnMassActionBar.md
@@ -0,0 +1,112 @@
+CnMassActionBar is only visible when `count > 0`. It renders as a single dropdown button:
+
+```vue
+
+
+
+
+```
+
+Custom button label and action labels — override `menuLabelTemplate` and the individual action labels:
+
+```vue
+ {}"
+ @mass-delete="() => {}"
+ @mass-export="() => {}"
+ @mass-import="() => {}" />
+```
+
+Hiding built-in actions — use `showExport` and `showDelete` to remove actions you don't need:
+
+```vue
+ {}"
+ @mass-import="() => {}" />
+```
+
+## Additional props
+
+| Prop | Type | Default | Description |
+|---|---|---|---|
+| `showExport` | `Boolean` | `true` | Whether to show the built-in Export action |
+| `showDelete` | `Boolean` | `true` | Whether to show the built-in Delete action |
+| `menuLabelTemplate` | `String` | `'Mass actions ({count})'` | Template for the dropdown button label; use `{count}` as a placeholder for the selection count |
+| `importLabel` | `String` | `'Import'` | Label for the Import action item |
+| `exportLabel` | `String` | `'Export'` | Label for the Export action item |
+| `copyLabel` | `String` | `'Copy'` | Label for the Copy action item |
+| `deleteLabel` | `String` | `'Delete'` | Label for the Delete action item |
diff --git a/src/components/CnMassActionBar/CnMassActionBar.vue b/src/components/CnMassActionBar/CnMassActionBar.vue
index 33e2917..a083321 100644
--- a/src/components/CnMassActionBar/CnMassActionBar.vue
+++ b/src/components/CnMassActionBar/CnMassActionBar.vue
@@ -88,7 +88,8 @@ import Export from 'vue-material-design-icons/Export.vue'
*
* ```
*
- * @example Basic usage
+ * Basic usage
+ * ```vue
*
+ * ```
*/
export default {
name: 'CnMassActionBar',
diff --git a/src/components/CnMassCopyDialog/CnMassCopyDialog.md b/src/components/CnMassCopyDialog/CnMassCopyDialog.md
new file mode 100644
index 0000000..d2dcfbc
--- /dev/null
+++ b/src/components/CnMassCopyDialog/CnMassCopyDialog.md
@@ -0,0 +1,51 @@
+Bulk copy with naming pattern selector:
+
+```vue
+
+
+ Copy 2 selected items
+
+
+
+
+```
+
+## Label customization
+
+All user-visible strings have props so they can be pre-translated by the consumer app.
+
+| Prop | Default (English) | Description |
+|---|---|---|
+| `nameFormatter` | `null` | Optional function `(item) => string` to format each item's displayed name. Overrides `nameField` when provided. |
+| `dialogTitle` | `'Copy items'` | Dialog title shown in the header. |
+| `patternLabel` | `'Naming pattern'` | Label above the naming pattern dropdown. |
+| `emptyText` | `'No items selected for copying.'` | Text shown when all items have been removed from the review list. |
+| `successText` | `'Items successfully copied.'` | Message shown in the success note card. |
+| `cancelLabel` | `'Cancel'` | Label for the dismiss button before the action is confirmed. |
+| `closeLabel` | `'Close'` | Label for the dismiss button after the result is shown. |
+| `confirmLabel` | `'Copy'` | Label for the confirm/copy button. |
+| `removeLabel` | `'Remove from list'` | Aria-label for the per-item remove button (the × icon beside each item). |
diff --git a/src/components/CnMassCopyDialog/CnMassCopyDialog.vue b/src/components/CnMassCopyDialog/CnMassCopyDialog.vue
index 4fd106f..6dfff0f 100644
--- a/src/components/CnMassCopyDialog/CnMassCopyDialog.vue
+++ b/src/components/CnMassCopyDialog/CnMassCopyDialog.vue
@@ -88,7 +88,7 @@ import Close from 'vue-material-design-icons/Close.vue'
* with the items and naming function. The parent performs the actual API
* call and calls `setResult()` via a ref.
*
- * @example
+ * ```vue
*
+ * ```
*
* // In methods:
* async onCopyConfirm({ ids, getName }) {
diff --git a/src/components/CnMassDeleteDialog/CnMassDeleteDialog.md b/src/components/CnMassDeleteDialog/CnMassDeleteDialog.md
new file mode 100644
index 0000000..d9b9f34
--- /dev/null
+++ b/src/components/CnMassDeleteDialog/CnMassDeleteDialog.md
@@ -0,0 +1,52 @@
+Bulk delete confirmation — two-phase flow like CnDeleteDialog, but for multiple items:
+
+```vue
+
+
+ Delete 3 selected items
+
+
+
+
+```
+
+## Label customization
+
+All user-visible strings have props so they can be pre-translated by the consumer app.
+
+| Prop | Default (English) | Description |
+|---|---|---|
+| `nameFormatter` | `null` | Optional function `(item) => string` to format each item's displayed name. Overrides `nameField` when provided. |
+| `dialogTitle` | `'Delete items'` | Dialog title shown in the header. |
+| `warningText` | `'The following items will be permanently deleted...'` | Warning text shown above the item list. |
+| `emptyText` | `'No items selected for deletion.'` | Text shown when all items have been removed from the review list. |
+| `successText` | `'Items successfully deleted.'` | Message shown in the success note card. |
+| `cancelLabel` | `'Cancel'` | Label for the dismiss button before the action is confirmed. |
+| `closeLabel` | `'Close'` | Label for the dismiss button after the result is shown. |
+| `confirmLabel` | `'Delete'` | Label for the confirm/delete button. |
+| `removeLabel` | `'Remove from list'` | Aria-label for the per-item remove button (the × icon beside each item). |
diff --git a/src/components/CnMassDeleteDialog/CnMassDeleteDialog.vue b/src/components/CnMassDeleteDialog/CnMassDeleteDialog.vue
index 4a70127..947a785 100644
--- a/src/components/CnMassDeleteDialog/CnMassDeleteDialog.vue
+++ b/src/components/CnMassDeleteDialog/CnMassDeleteDialog.vue
@@ -79,13 +79,14 @@ import Close from 'vue-material-design-icons/Close.vue'
* with the item IDs. The parent component performs the actual API call and
* calls `setResult()` via a ref.
*
- * @example
+ * ```vue
*
+ * ```
*
* // In methods:
* async onDeleteConfirm(ids) {
diff --git a/src/components/CnMassExportDialog/CnMassExportDialog.md b/src/components/CnMassExportDialog/CnMassExportDialog.md
new file mode 100644
index 0000000..9964e06
--- /dev/null
+++ b/src/components/CnMassExportDialog/CnMassExportDialog.md
@@ -0,0 +1,60 @@
+Bulk export with format selection:
+
+```vue
+
+
+ Export 5 items
+
+
+
+
+```
+
+## Additional props
+
+### Functional props
+
+| Prop | Default | Description |
+|---|---|---|
+| `dialogTitle` | `'Export objects'` | Dialog title shown in the header. |
+| `description` | `''` | Optional description text shown above the format selector (e.g., `'Export 42 objects from Cases'`). |
+| `formats` | `[{ id: 'excel', label: 'Excel (.xlsx)' }, { id: 'csv', label: 'CSV (.csv)' }]` | Available export format options. Each entry must have `id` and `label`. |
+| `defaultFormat` | `'excel'` | The `id` of the format that is pre-selected when the dialog opens. |
+
+### Label customization
+
+All user-visible strings have props so they can be pre-translated by the consumer app.
+
+| Prop | Default (English) | Description |
+|---|---|---|
+| `successText` | `'Export completed successfully.'` | Message shown in the success note card. |
+| `formatLabel` | `'Export format'` | Label above the format dropdown. |
+| `cancelLabel` | `'Cancel'` | Label for the dismiss button before the action is confirmed. |
+| `closeLabel` | `'Close'` | Label for the dismiss button after the result is shown. |
+| `confirmLabel` | `'Export'` | Label for the confirm/export button. |
diff --git a/src/components/CnMassExportDialog/CnMassExportDialog.vue b/src/components/CnMassExportDialog/CnMassExportDialog.vue
index bffd7d3..9b5a3e6 100644
--- a/src/components/CnMassExportDialog/CnMassExportDialog.vue
+++ b/src/components/CnMassExportDialog/CnMassExportDialog.vue
@@ -62,13 +62,14 @@ import ExportIcon from 'vue-material-design-icons/Export.vue'
* The parent handles the actual download. Based on the OpenRegister
* ExportRegister pattern.
*
- * @example
+ * ```vue
*
+ * ```
*
* // In methods:
* async onExportConfirm({ format }) {
diff --git a/src/components/CnMassImportDialog/CnMassImportDialog.md b/src/components/CnMassImportDialog/CnMassImportDialog.md
new file mode 100644
index 0000000..592c8a6
--- /dev/null
+++ b/src/components/CnMassImportDialog/CnMassImportDialog.md
@@ -0,0 +1,61 @@
+Bulk import with file upload:
+
+```vue
+
+
+ Import items
+
+
+
+
+```
+
+## Additional props
+
+### Functional props
+
+| Prop | Default | Description |
+|---|---|---|
+| `dialogTitle` | `'Import data'` | Dialog title shown in the header. |
+| `acceptedTypes` | `'.json,.xlsx,.xls,.csv'` | The `accept` attribute passed to the hidden file input. |
+| `options` | `[]` | Import option definitions rendered as toggle switches. Each entry: `{ key, label, description?, default? }`. |
+| `fileTypeHelp` | JSON/Excel/CSV entries | Array of `{ label, description }` explaining the supported file types. Pass an empty array to hide the help section. |
+| `canSubmit` | `true` | Whether the Import button is enabled. Use this when a required slot field (e.g., schema selector) has not yet been filled in. |
+
+### Label customization
+
+All user-visible strings have props so they can be pre-translated by the consumer app.
+
+| Prop | Default (English) | Description |
+|---|---|---|
+| `successText` | `'Import completed successfully!'` | Message when all rows imported without errors. |
+| `partialSuccessText` | `'Import completed with errors. Check the details below.'` | Message when import partially succeeded. |
+| `loadingText` | `'Importing data — this may take a moment for large files...'` | Info card shown while the import is running. |
+| `summaryTitle` | `'Import summary'` | Heading above the results table. |
+| `supportedFormatsLabel` | `'Supported file types:'` | Bold heading inside the file type help block. |
+| `selectFileLabel` | `'Select file'` | Label on the file-picker button. |
+| `cancelLabel` | `'Cancel'` | Label for the dismiss button before the action is confirmed. |
+| `closeLabel` | `'Close'` | Label for the dismiss button after the result is shown. |
+| `confirmLabel` | `'Import'` | Label for the confirm/import button. |
+| `sheetLabel` | `'Sheet'` | Column header in the results summary table. |
+| `foundLabel` | `'Found'` | Column header for the found-rows count. |
+| `createdLabel` | `'Created'` | Column header for the created-rows count. |
+| `updatedLabel` | `'Updated'` | Column header for the updated-rows count. |
+| `unchangedLabel` | `'Unchanged'` | Column header for the unchanged-rows count. |
+| `errorsLabel` | `'Errors'` | Column header for the error-rows count. |
diff --git a/src/components/CnMassImportDialog/CnMassImportDialog.vue b/src/components/CnMassImportDialog/CnMassImportDialog.vue
index f9e3850..6887d64 100644
--- a/src/components/CnMassImportDialog/CnMassImportDialog.vue
+++ b/src/components/CnMassImportDialog/CnMassImportDialog.vue
@@ -180,7 +180,7 @@ import ChevronDown from 'vue-material-design-icons/ChevronDown.vue'
* with the file and options. The parent handles the API call and calls
* `setResult()` via a ref.
*
- * @example
+ * ```vue
*
*
*
+ * ```
*
* // In data:
* importOptions: [
diff --git a/src/components/CnNoteCard/CnNoteCard.md b/src/components/CnNoteCard/CnNoteCard.md
new file mode 100644
index 0000000..2f0da47
--- /dev/null
+++ b/src/components/CnNoteCard/CnNoteCard.md
@@ -0,0 +1,71 @@
+All four note card types:
+
+```vue
+
+
+
+
+
+
+```
+
+With heading:
+
+```vue
+
+
+ Deleting this record will permanently remove all associated data and cannot be undone.
+
+
+ Use the bulk import feature to add multiple records at once.
+
+
+```
+
+Custom content via default slot:
+
+```vue
+
+ Migration required — your schema configuration needs to be updated before continuing.
+ View migration guide →
+
+```
+
+`showAlert` — force the ARIA `alert` role for messages that need immediate user attention (normally only `type="error"` uses the alert role automatically):
+
+```vue
+
+
+
+
+```
+
+Custom icon via `icon` slot — replace the built-in MDI icon with any content:
+
+```vue
+
+
+
+
+ This resource is read-only for your account.
+
+```
+
+## Additional props
+
+| Prop | Type | Default | Description |
+|---|---|---|---|
+| `showAlert` | `Boolean` | `undefined` | When `true`, forces the ARIA `alert` role on the element regardless of `type`. `type="error"` implicitly sets this role even without the prop. Use for warnings that require immediate attention. |
+
+## Slots
+
+| Slot | Description |
+|---|---|
+| `icon` | Replaces the default type-based MDI icon. Use to render a custom icon or component in the leading position. |
+| default | The note card body content. When provided, overrides the `text` prop. |
diff --git a/src/components/CnNotesCard/CnNotesCard.vue b/src/components/CnNotesCard/CnNotesCard.vue
index 36c0236..6a1a79e 100644
--- a/src/components/CnNotesCard/CnNotesCard.vue
+++ b/src/components/CnNotesCard/CnNotesCard.vue
@@ -99,13 +99,16 @@ import { buildHeaders } from '../../utils/index.js'
* Shows up to 5 recent notes with add/delete functionality.
* Integrates CnUserActionMenu on author names for quick communication.
*
- * @example Basic usage
+ * Basic usage
+ * ```vue
*
+ * ```
*
- * @example With sidebar sync
+ * With sidebar sync
+ * ```vue
*
+ * ```
*/
export default {
name: 'CnNotesCard',
diff --git a/src/components/CnObjectCard/CnObjectCard.md b/src/components/CnObjectCard/CnObjectCard.md
new file mode 100644
index 0000000..bb66c19
--- /dev/null
+++ b/src/components/CnObjectCard/CnObjectCard.md
@@ -0,0 +1,143 @@
+Basic — schema-driven card resolves title and description from `schema.configuration`:
+
+```vue
+
+```
+
+With actions slot:
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+```
+
+Selectable — checkbox on the card for mass selections:
+
+```vue
+
+
+
Selected: {{ selected ? item.title : 'none' }}
+
+
+
+
+```
+
+Limiting metadata fields and custom `metadata` slot — `maxMetadata` caps the number of auto-rendered property fields; the `metadata` slot replaces the default rendering:
+
+```vue
+
+
+
+
+
+ {{ field.label }}: {{ field.value }}
+
+
+
+
+
+
+```
+
+## Additional props
+
+| Prop | Type | Default | Description |
+|---|---|---|---|
+| `maxMetadata` | `Number` | `4` | Maximum number of schema properties to show in the metadata section. Properties are sorted by their `order` value before slicing |
+
+## Slots
+
+| Slot | Scope | Description |
+|---|---|---|
+| `metadata` | `{ object, fields }` | Override the metadata section. `fields` is the array of `{ key, label, value, property }` objects (already filtered and limited by `maxMetadata`) |
+| `badges` | `{ object }` | Content rendered below the title/description area (e.g. status badges) |
+| `actions` | `{ object }` | Action buttons rendered on the right side of the card; click events on this area do not bubble to the card's `@click` handler |
diff --git a/src/components/CnObjectCard/CnObjectCard.vue b/src/components/CnObjectCard/CnObjectCard.vue
index 9c7147d..2d4c4cf 100644
--- a/src/components/CnObjectCard/CnObjectCard.vue
+++ b/src/components/CnObjectCard/CnObjectCard.vue
@@ -70,12 +70,13 @@ import { formatValue } from '../../utils/schema.js'
* Uses `schema.configuration` to determine which fields map to the card title,
* description, and image. Remaining visible properties are shown as metadata.
*
- * @example
+ * ```vue
*
*
* Edit
*
*
+ * ```
*/
export default {
name: 'CnObjectCard',
diff --git a/src/components/CnObjectDataWidget/CnObjectDataWidget.md b/src/components/CnObjectDataWidget/CnObjectDataWidget.md
new file mode 100644
index 0000000..581cf18
--- /dev/null
+++ b/src/components/CnObjectDataWidget/CnObjectDataWidget.md
@@ -0,0 +1,130 @@
+Schema-driven editable grid — click any field to edit inline, save when ready:
+
+```vue
+
+
+ Custom notes content for object {{ objectId }}
+
+
+
+
+
+```
+
+With custom tab labels:
+
+```vue
+
+
+
+
+
+
+```
+
+## Props
+
+| Prop | Type | Default | Description |
+|------|------|---------|-------------|
+| `objectType` | String | Required | The entity type slug (e.g. `'pipelinq_lead'`, `'procest_case'`). Used as the sidebar title fallback |
+| `objectId` | String | Required | The UUID of the object to display |
+| `register` | String | `''` | OpenRegister register ID passed to each tab for API calls |
+| `schema` | String | `''` | OpenRegister schema ID passed to each tab for API calls |
+| `apiBase` | String | `'/apps/openregister/api'` | Base API URL for OpenRegister tab endpoints |
+| `open` | Boolean | `true` | Whether the sidebar is visible |
+| `title` | String | `''` | Sidebar header title (defaults to `objectType`) |
+| `subtitle` | String | `''` | Sidebar header subtitle |
+| `subtitleProp` | String | `''` | Deprecated alias for `subtitle`. Use `subtitle` instead |
+| `hiddenTabs` | Array | `[]` | Tab IDs to hide: `'files'`, `'notes'`, `'tags'`, `'tasks'`, `'auditTrail'` |
+| `filesLabel` | String | `'Files'` | Pre-translated label for the Files tab |
+| `notesLabel` | String | `'Notes'` | Pre-translated label for the Notes tab |
+| `tagsLabel` | String | `'Tags'` | Pre-translated label for the Tags tab |
+| `tasksLabel` | String | `'Tasks'` | Pre-translated label for the Tasks tab |
+| `auditTrailLabel` | String | `'Audit trail'` | Pre-translated label for the Audit Trail tab |
diff --git a/src/components/CnObjectSidebar/CnObjectSidebar.vue b/src/components/CnObjectSidebar/CnObjectSidebar.vue
index d914f4c..557728a 100644
--- a/src/components/CnObjectSidebar/CnObjectSidebar.vue
+++ b/src/components/CnObjectSidebar/CnObjectSidebar.vue
@@ -131,25 +131,31 @@ import CnAuditTrailTab from './CnAuditTrailTab.vue'
* Tasks, Audit Trail) that integrate with OpenRegister API endpoints bridging to
* Nextcloud-native APIs. Each tab is a self-contained component.
*
- * @example Basic usage
+ * Basic usage
+ * ```vue
*
+ * ```
*
- * @example Hide specific tabs
+ * Hide specific tabs
+ * ```vue
*
+ * ```
*
- * @example Override a tab
+ * Override a tab
+ * ```vue
*
*
*
*
*
+ * ```
*/
export default {
name: 'CnObjectSidebar',
diff --git a/src/components/CnObjectSidebar/CnTagsTab.vue b/src/components/CnObjectSidebar/CnTagsTab.vue
index 7492422..3d212dd 100644
--- a/src/components/CnObjectSidebar/CnTagsTab.vue
+++ b/src/components/CnObjectSidebar/CnTagsTab.vue
@@ -11,6 +11,7 @@
@focus="showSuggestions = true" />
@@ -121,6 +122,7 @@ export default {
},
async fetchAvailableTags() {
+ if (!this.register || !this.schema) return
try {
const response = await fetch(`${this.apiBase}/tags`, { headers: buildHeaders() })
if (response.ok) {
diff --git a/src/components/CnObjectSidebar/CnTasksTab.vue b/src/components/CnObjectSidebar/CnTasksTab.vue
index b979a28..17d2a9e 100644
--- a/src/components/CnObjectSidebar/CnTasksTab.vue
+++ b/src/components/CnObjectSidebar/CnTasksTab.vue
@@ -10,6 +10,7 @@
@@ -17,6 +18,7 @@
@@ -119,7 +121,7 @@
- {{ loadingMore ? '' : loadMoreLabel }}
+ {{ loadMoreLabel }}
@@ -258,6 +260,7 @@ export default {
},
async fetchUsers() {
+ if (!this.register || !this.schema) return
try {
const response = await fetch('/ocs/v2.php/cloud/users/details?format=json&limit=50', {
headers: buildHeaders(),
diff --git a/src/components/CnPageHeader/CnPageHeader.md b/src/components/CnPageHeader/CnPageHeader.md
new file mode 100644
index 0000000..50a43fd
--- /dev/null
+++ b/src/components/CnPageHeader/CnPageHeader.md
@@ -0,0 +1,43 @@
+Basic — icon, title, and description. Use `iconSize` (default `28`) to adjust the icon pixel size:
+
+```vue
+
+```
+
+Title only (no icon, no description):
+
+```vue
+
+```
+
+Custom icon via slot:
+
+```vue
+
+
+
+
+
+
+
+
+```
+
+With extra content (e.g., a badge or status indicator):
+
+```vue
+
+
+
+
+
+```
diff --git a/src/components/CnPageHeader/CnPageHeader.vue b/src/components/CnPageHeader/CnPageHeader.vue
index 6520007..a60b319 100644
--- a/src/components/CnPageHeader/CnPageHeader.vue
+++ b/src/components/CnPageHeader/CnPageHeader.vue
@@ -23,8 +23,9 @@ import { CnIcon } from '../CnIcon/index.js'
/**
* CnPageHeader — Reusable page header with optional icon, title, and description.
*
- * @example
+ * ```vue
*
+ * ```
*/
export default {
name: 'CnPageHeader',
diff --git a/src/components/CnPageRenderer/CnPageRenderer.md b/src/components/CnPageRenderer/CnPageRenderer.md
new file mode 100644
index 0000000..f7653e2
--- /dev/null
+++ b/src/components/CnPageRenderer/CnPageRenderer.md
@@ -0,0 +1,45 @@
+CnPageRenderer is a type dispatcher mounted inside ``. It matches `$route.name === page.id` and dispatches by `page.type` (`index | detail | dashboard | custom`). It is used automatically inside CnAppRoot and is not intended for standalone use.
+
+In a manifest-driven app, it is mounted as:
+
+```vue
+
+
+
+
+```
+
+The manifest's `pages[]` array drives which component renders for each route:
+
+```json
+{
+ "pages": [
+ { "id": "contacts-index", "route": "/contacts", "type": "index", "config": { "register": "contacts", "schema": "contact" } },
+ { "id": "contacts-detail", "route": "/contacts/:id", "type": "detail", "config": { "register": "contacts", "schema": "contact" } },
+ { "id": "settings", "route": "/settings", "type": "custom", "component": "SettingsPage" }
+ ]
+}
+```
+
+Standalone usage outside of CnAppRoot — pass props explicitly instead of relying on inject:
+
+```vue {static}
+
+
+
+```
+
+See `docs/components/cn-page-renderer.md` for the full config API.
+
+## Props
+
+| Prop | Type | Default | Description |
+|------|------|---------|-------------|
+| `manifest` | Object | `null` | Manifest object. When omitted, falls back to the injected `cnManifest` from a `CnAppRoot` ancestor |
+| `customComponents` | Object | `null` | Custom-component registry. Keys match `page.component` for `type: "custom"` pages. Falls back to injected `cnCustomComponents` |
+| `translate` | Function | `null` | Translate function. Falls back to injected `cnTranslate`. Exposed for symmetry — page components can `inject('cnTranslate')` directly |
+| `pageTypes` | Object | `null` | Page-type registry: map of `pages[].type` → Vue component. Falls back to injected `cnPageTypes` and finally to the library's `defaultPageTypes`. The special `custom` type resolves through `customComponents` instead |
diff --git a/src/components/CnPageRenderer/CnPageRenderer.vue b/src/components/CnPageRenderer/CnPageRenderer.vue
index 1f22407..f385e95 100644
--- a/src/components/CnPageRenderer/CnPageRenderer.vue
+++ b/src/components/CnPageRenderer/CnPageRenderer.vue
@@ -236,11 +236,11 @@ export default {
// for the lifetime of this instance.
if (this.currentPage) {
this.$options.name = `CnPageRenderer:${this.currentPage.id}`
- } else {
- // Warn once at mount time when no page matches the current route.
+ } else if (this.$route) {
+ // Router is present but no page matches — warn so developers notice misconfigured routes.
// eslint-disable-next-line no-console
console.warn(
- `[CnPageRenderer] No page found for $route.name = "${this.$route?.name}". The renderer will mount nothing.`,
+ `[CnPageRenderer] No page found for $route.name = "${this.$route.name}". The renderer will mount nothing.`,
)
}
},
diff --git a/src/components/CnPagination/CnPagination.md b/src/components/CnPagination/CnPagination.md
new file mode 100644
index 0000000..ed71711
--- /dev/null
+++ b/src/components/CnPagination/CnPagination.md
@@ -0,0 +1,102 @@
+Basic — navigate pages with First/Previous/Next/Last buttons and smart ellipsis:
+
+```vue
+
+
+
+
Page {{ page }} · {{ size }} per page
+
+
+
+```
+
+Near the end — shows smart ellipsis at the start:
+
+```vue
+
+
+
+
+```
+
+Small result set — hides pagination when fewer items than threshold (`minItemsToShow`, default 10):
+
+```vue
+
+```
+
+Custom page size options:
+
+```vue
+
+ {}"
+ @page-size-changed="() => {}" />
+
+```
+
+Custom page info format and navigation labels (useful for translated apps or custom wording):
+
+```vue
+ {}"
+ @page-size-changed="() => {}" />
+```
+
+## Additional props
+
+| Prop | Type | Default | Description |
+|---|---|---|---|
+| `minItemsToShow` | `Number` | `10` | Hide the pagination bar when `totalItems` is at or below this threshold |
+| `firstLabel` | `String` | `'First'` | Label for the First page button |
+| `previousLabel` | `String` | `'Previous'` | Label for the Previous page button |
+| `nextLabel` | `String` | `'Next'` | Label for the Next page button |
+| `lastLabel` | `String` | `'Last'` | Label for the Last page button |
+| `itemsPerPageLabel` | `String` | `'Items per page:'` | Label for the page-size selector |
+| `pageInfoFormat` | `String` | `'Page {current} of {total}'` | Format string for the page info text; use `{current}` and `{total}` as placeholders |
diff --git a/src/components/CnPagination/CnPagination.vue b/src/components/CnPagination/CnPagination.vue
index 7560a94..815b2e6 100644
--- a/src/components/CnPagination/CnPagination.vue
+++ b/src/components/CnPagination/CnPagination.vue
@@ -77,7 +77,7 @@ import { NcButton, NcSelect } from '@nextcloud/vue'
* NL Design tokens used:
* - Inherits from cn-pagination CSS class (see css/pagination.css)
*
- * @example
+ * ```vue
*
+ * ```
*/
export default {
name: 'CnPagination',
@@ -160,7 +161,7 @@ export default {
},
/**
* Page info format string. Use {current} and {total} as placeholders.
- * @example "Page {current} of {total}"
+ * "Page {current} of {total}"
*/
pageInfoFormat: {
type: String,
diff --git a/src/components/CnProgressBar/CnProgressBar.md b/src/components/CnProgressBar/CnProgressBar.md
new file mode 100644
index 0000000..2b674f3
--- /dev/null
+++ b/src/components/CnProgressBar/CnProgressBar.md
@@ -0,0 +1,87 @@
+Basic — counts auto-calculate percentages from the total:
+
+```vue
+
+```
+
+Show percentage — display `%` instead of raw count:
+
+```vue
+
+```
+
+Explicit percentages — skip auto-calculation with `item.percentage`:
+
+```vue
+
+```
+
+Dynamic variant — function resolves color based on value:
+
+```vue
+
+```
+
+Rounded corners — enabled by default (`rounded` prop); set to `false` for square-cornered tracks:
+
+```vue
+
+
+
rounded (default)
+
+
+
+
not rounded
+
+
+
+```
+
+Tooltips and custom bar height:
+
+```vue
+
+```
diff --git a/src/components/CnProgressBar/CnProgressBar.vue b/src/components/CnProgressBar/CnProgressBar.vue
index 2db7d31..72067d1 100644
--- a/src/components/CnProgressBar/CnProgressBar.vue
+++ b/src/components/CnProgressBar/CnProgressBar.vue
@@ -49,23 +49,29 @@
* Suitable for distribution visualizations (e.g., query complexity, action breakdown,
* status distribution).
*
- * @example Basic usage
+ * Basic usage
+ * ```vue
*
+ * ```
*
- * @example With explicit percentages
+ * With explicit percentages
+ * ```vue
*
+ * ```
*
- * @example With tooltips
+ * With tooltips
+ * ```vue
*
+ * ```
*/
export default {
name: 'CnProgressBar',
diff --git a/src/components/CnRegisterMapping/CnRegisterMapping.md b/src/components/CnRegisterMapping/CnRegisterMapping.md
new file mode 100644
index 0000000..7ed9e56
--- /dev/null
+++ b/src/components/CnRegisterMapping/CnRegisterMapping.md
@@ -0,0 +1,126 @@
+CnRegisterMapping is a settings component for mapping application entity types to Open Register registers and schemas. It loads available registers from the API and lets admins configure which register/schema each entity type uses.
+
+It is normally placed on an admin settings page:
+
+```vue {static}
+
+
+
+
+```
+
+With `docUrl`, `configuration`, `saving`, `showReimportButton`, `reimporting`, `saveButtonText`, `reimportButtonText`, `autoMatch`, and `labels`:
+
+```vue {static}
+
+
+
+
+```
+
+## Additional props
+
+| Prop | Type | Default | Description |
+|------|------|---------|-------------|
+| `docUrl` | String | `''` | Documentation URL — shows an info icon link next to the section title |
+| `configuration` | Object | `{}` | Current config values: `{ register: '5', contact_schema: '28', … }` |
+| `saving` | Boolean | `false` | Disables the save button and shows a spinner while saving is in progress |
+| `showReimportButton` | Boolean | `false` | Show the re-import button alongside the save button |
+| `reimporting` | Boolean | `false` | Disables the reimport button and shows a spinner while reimport is in progress |
+| `saveButtonText` | String | `'Save configuration'` | Label for the save button |
+| `reimportButtonText` | String | `'Re-import configuration'` | Label for the reimport button |
+| `autoMatch` | Boolean | `true` | Automatically match schema titles to type slugs when a register is selected |
+| `labels` | Object | *(see below)* | UI label overrides for all user-visible strings (register, schema, notConfigured, noSchemas, selectRegister, selectSchema, allConfigured, partiallyConfigured) |
diff --git a/src/components/CnRegisterMapping/CnRegisterMapping.vue b/src/components/CnRegisterMapping/CnRegisterMapping.vue
index 8bcca9c..85b3070 100644
--- a/src/components/CnRegisterMapping/CnRegisterMapping.vue
+++ b/src/components/CnRegisterMapping/CnRegisterMapping.vue
@@ -68,6 +68,7 @@
:value="selectedRegister(groupIdx)"
:options="registerSelectOptions"
:placeholder="labels.selectRegister"
+ :input-label="labels.register"
:loading="registersLoading"
label="label"
track-by="value"
@@ -120,6 +121,7 @@
:value="selectedSchema(groupIdx, type)"
:options="schemaSelectOptions(groupIdx)"
:placeholder="labels.selectSchema"
+ :input-label="labels.schema"
label="label"
track-by="value"
@input="handleSchemaChange(groupIdx, type, $event)" />
@@ -167,7 +169,8 @@ import { buildHeaders } from '../../utils/headers.js'
* Supports multiple register groups (stacked sections) with expandable
* type rows for manual schema override.
*
- * @example Single register (Pipelinq)
+ * Single register (Pipelinq)
+ * ```vue
*
+ * ```
*
- * @example Multi-register (SoftwareCatalog)
+ * Multi-register (SoftwareCatalog)
+ * ```vue
*
+ * ```
*/
export default {
name: 'CnRegisterMapping',
@@ -224,7 +230,7 @@ export default {
},
/**
* Groups of object types that share a register.
- * @type {Array<{ name: string, description?: string, registerConfigKey?: string, types: Array<{ slug: string, label: string, description?: string, configKey?: string }> }>}
+ * @type {Array<{ name: string, description: string, registerConfigKey: string, types: Array<{ slug: string, label: string, description: string, configKey: string }> }>}
*/
groups: {
type: Array,
diff --git a/src/components/CnRowActions/CnRowActions.md b/src/components/CnRowActions/CnRowActions.md
new file mode 100644
index 0000000..d9522b3
--- /dev/null
+++ b/src/components/CnRowActions/CnRowActions.md
@@ -0,0 +1,122 @@
+Basic — actions array with label and handler:
+
+```vue
+
+
+ Row: {{ lastAction || 'no action yet' }}
+
+
+
+
+```
+
+Primary trigger and named menu — use `primary` to apply primary button styling to the trigger, and `menuName` to add a visible label next to the trigger icon:
+
+```vue
+
+
+
+
+
+
+```
+
+Conditional visibility — hide actions based on row state:
+
+```vue
+
+
+
+ {{ item.title }}
+
+
+
+
+
+```
diff --git a/src/components/CnRowActions/CnRowActions.vue b/src/components/CnRowActions/CnRowActions.vue
index d110834..64023e0 100644
--- a/src/components/CnRowActions/CnRowActions.vue
+++ b/src/components/CnRowActions/CnRowActions.vue
@@ -25,13 +25,14 @@ import { NcActions, NcActionButton } from '@nextcloud/vue'
* Wraps NcActions + NcActionButton for consistent row/card action menus.
* Actions are defined as an array of objects with label, icon, handler, etc.
*
- * @example
+ * ```vue
*
+ * ```
*/
export default {
name: 'CnRowActions',
@@ -53,8 +54,7 @@ export default {
* - `visible` (boolean | (row) => boolean) — when `false`, hide the entry from the menu (default: shown)
* - `title` (string | (row) => string) — native tooltip shown on hover (useful to explain why an entry is disabled)
* - `destructive` (boolean) — apply error color styling
- *
- * @type {Array<{label: string, icon?: object, handler: Function, disabled?: boolean | Function, visible?: boolean | Function, title?: string | Function, destructive?: boolean}>}
+ * @type {Array<{label: string, icon: object, handler: Function, disabled: boolean | Function, visible: boolean | Function, title: string | Function, destructive: boolean}>}
*/
actions: {
type: Array,
diff --git a/src/components/CnSchemaFormDialog/CnSchemaFormDialog.md b/src/components/CnSchemaFormDialog/CnSchemaFormDialog.md
new file mode 100644
index 0000000..10f333f
--- /dev/null
+++ b/src/components/CnSchemaFormDialog/CnSchemaFormDialog.md
@@ -0,0 +1,136 @@
+CnSchemaFormDialog is the full-featured JSON Schema editor with Properties, Configuration, and Security tabs.
+
+The **Security tab** has a group permissions table and an **Advanced: Conditional access rules and inheritance** accordion (collapsed by default). The accordion has two sections:
+
+- **Conditional access rules** — property-value-based runtime grants per action (create/read/update/delete)
+- **Inheritance** — "Authenticated users inherit `public` group rights" toggle (default: on). Placed at the bottom because it rarely needs changing; accidental changes would alter RBAC behaviour significantly.
+
+Basic — create a new schema:
+
+```vue
+
+
+
+
+```
+
+## Additional props
+
+### Data and configuration
+
+| Prop | Default | Description |
+|---|---|---|
+| `item` | `null` | Existing schema object for edit mode. Pass `null` for create mode. |
+| `dialogTitle` | `''` | Dialog title. Defaults to `'Create Schema'` or `'Edit Schema'` when empty. |
+| `size` | `'large'` | NcDialog size. |
+| `availableSchemas` | `[]` | Schemas available for composition (allOf/oneOf/anyOf) and property references. Each entry: `{ id, title, description, reference }`. |
+| `availableRegisters` | `[]` | Registers shown in the Configuration tab for field mapping. Each entry: `{ id, label }`. |
+| `userGroups` | `[]` | User groups for RBAC in the Security tab. Each entry: `{ id, displayname }`. |
+| `availableTags` | `[]` | Tags available for file property configuration. |
+| `loadingGroups` | `false` | Whether user groups are still being loaded (shows a loading indicator in the Security tab). |
+| `inheritedProperties` | `{}` | Properties inherited from parent schemas via allOf — shown as locked rows in the Properties tab. |
+| `objectCount` | `0` | Number of objects attached to this schema; controls whether the Delete/Publish buttons are enabled. |
+
+### Optional action buttons (edit mode only)
+
+These buttons appear in the dialog footer when editing an existing schema.
+
+| Prop | Default | Description |
+|---|---|---|
+| `showExtendSchema` | `false` | Show the "Extend schema" button. Emits `extend-schema` on click. |
+| `showAnalyzeProperties` | `false` | Show the "Analyze properties" button. Emits `analyze-properties` on click. |
+| `showValidateObjects` | `false` | Show the "Validate objects" button. Emits `validate-objects` on click. |
+| `showDeleteObjects` | `false` | Show the "Delete objects" button. Disabled when `objectCount === 0`. Emits `delete-objects` on click. |
+| `showPublishObjects` | `false` | Show the "Publish objects" button. Disabled when `objectCount === 0`. Emits `publish-objects` on click. |
+
+### Label customization
+
+All user-visible strings have props so they can be pre-translated by the consumer app.
+
+| Prop | Default (English) | Description |
+|---|---|---|
+| `cancelLabel` | `'Cancel'` | Label for the dismiss button before the action is confirmed. |
+| `closeLabel` | `'Close'` | Label for the dismiss button after the result is shown. |
+| `confirmLabel` | `''` | Confirm button label. Defaults to `'Create'` or `'Save'` depending on mode. |
+| `successText` | `'Schema saved successfully.'` | Message shown after a successful save. |
+| `extendSchemaLabel` | `'Extend schema'` | Label for the Extend Schema action button. |
+| `analyzePropertiesLabel` | `'Analyze properties'` | Label for the Analyze Properties action button. |
+| `validateObjectsLabel` | `'Validate objects'` | Label for the Validate Objects action button. |
+| `deleteObjectsLabel` | `'Delete objects'` | Label for the Delete Objects action button. |
+| `publishObjectsLabel` | `'Publish objects'` | Label for the Publish Objects action button. |
+| `deleteLabel` | `'Delete'` | Label for the Delete (schema) action button. |
+| `deleteObjectsTooltip` | `'Delete all objects in this schema'` | Tooltip shown on the Delete Objects button when objects exist. |
+| `publishObjectsTooltip` | `'Publish all objects in this schema'` | Tooltip shown on the Publish Objects button when objects exist. |
+| `noDeleteObjectsTooltip` | `'No objects to delete'` | Tooltip shown on the Delete Objects button when `objectCount === 0`. |
+| `noPublishObjectsTooltip` | `'No objects to publish'` | Tooltip shown on the Publish Objects button when `objectCount === 0`. |
+| `cannotDeleteTooltip` | `'Cannot delete: objects are still attached'` | Tooltip shown on the Delete button when `objectCount > 0`. |
diff --git a/src/components/CnSchemaFormDialog/CnSchemaSecurityTab.vue b/src/components/CnSchemaFormDialog/CnSchemaSecurityTab.vue
index 84314da..7ec253f 100644
--- a/src/components/CnSchemaFormDialog/CnSchemaSecurityTab.vue
+++ b/src/components/CnSchemaFormDialog/CnSchemaSecurityTab.vue
@@ -82,7 +82,7 @@
-
+
+ {{ t('nextcloud-vue', 'When on (default), logged-in users qualify for any rule that targets the `public` group. Disable to make authenticated access strictly gated by explicit group memberships — anonymous users are unaffected either way.') }}
+
+
@@ -397,11 +411,46 @@ export default {
return total + this.getConditionalRules(action).length
}, 0)
},
+
+ /**
+ * Resolved schema-level value of `inheritFromPublic`.
+ *
+ * The cascade (register / tenant default) lives on the backend; here we
+ * just surface the schema's explicit value, defaulting to `true` (the
+ * pre-change behaviour) when unset.
+ *
+ * @return {boolean}
+ */
+ inheritFromPublic() {
+ const auth = this.schemaItem.authorization || {}
+ if (auth.inheritFromPublic === undefined || auth.inheritFromPublic === null) {
+ return true
+ }
+ return Boolean(auth.inheritFromPublic)
+ },
},
methods: {
t,
capitalize: _.capitalize,
+ /**
+ * Set the schema-level `inheritFromPublic` flag.
+ *
+ * Mutates schemaItem.authorization directly (matches the existing
+ * permission-table pattern). Storing `true` explicitly (rather than
+ * deleting the key) keeps the user's choice visible in the JSON view —
+ * the cascade still treats omitted/null as "unset" if a future operator
+ * removes it manually.
+ *
+ * @param {boolean} value New value for the flag.
+ */
+ setInheritFromPublic(value) {
+ if (!this.schemaItem.authorization) {
+ this.$set(this.schemaItem, 'authorization', {})
+ }
+ this.$set(this.schemaItem.authorization, 'inheritFromPublic', Boolean(value))
+ },
+
availablePropertyOptions(action, ruleIdx) {
const rules = this.getConditionalRules(action)
const currentRule = rules[ruleIdx]
diff --git a/src/components/CnSettingsCard/CnSettingsCard.md b/src/components/CnSettingsCard/CnSettingsCard.md
new file mode 100644
index 0000000..24d515c
--- /dev/null
+++ b/src/components/CnSettingsCard/CnSettingsCard.md
@@ -0,0 +1,30 @@
+Basic — static card with title and icon emoji:
+
+```vue
+
+
+
+```
+
+Collapsible — click header to toggle:
+
+```vue
+
+
+
+
+
+
+
+
+```
diff --git a/src/components/CnSettingsCard/CnSettingsCard.vue b/src/components/CnSettingsCard/CnSettingsCard.vue
index 053af9a..9def13c 100644
--- a/src/components/CnSettingsCard/CnSettingsCard.vue
+++ b/src/components/CnSettingsCard/CnSettingsCard.vue
@@ -37,10 +37,11 @@ import ChevronUp from 'vue-material-design-icons/ChevronUp.vue'
* Extracted from OpenRegister's SettingsCard. Provides a titled card with
* optional collapse/expand animation.
*
- * @example
+ * ```vue
*
*
Content here
*
+ * ```
*/
export default {
name: 'CnSettingsCard',
diff --git a/src/components/CnSettingsSection/CnSettingsSection.md b/src/components/CnSettingsSection/CnSettingsSection.md
new file mode 100644
index 0000000..0b234ec
--- /dev/null
+++ b/src/components/CnSettingsSection/CnSettingsSection.md
@@ -0,0 +1,93 @@
+Basic settings section — wraps NcSettingsSection with actions and loading/error states:
+
+```vue
+
+
+
+```
+
+With action button in the header:
+
+```vue
+
+
+
+ Save changes
+
+
+
+
+
+```
+
+Loading state:
+
+```vue
+
+```
+
+With `detailedDescription`, `docUrl`, `errorMessage`, `onRetry`, `retryButtonText`, `empty`, and `emptyMessage`:
+
+```vue
+
+
+
+
+
+
+```
+
+## Additional props
+
+| Prop | Type | Default | Description |
+|------|------|---------|-------------|
+| `detailedDescription` | String | `''` | Extended description shown in a block below the title (more space than the NcSettingsSection `description`) |
+| `docUrl` | String | `''` | Documentation URL — shows an info icon link next to the section title |
+| `errorMessage` | String | `'An error occurred'` | Message shown when `error` is `true` |
+| `onRetry` | Function | `null` | Callback for the retry button in the error state; button is hidden when `null` |
+| `retryButtonText` | String | `'Retry'` | Label for the retry button |
+| `empty` | Boolean | `false` | Show the empty state instead of the default slot content |
+| `emptyMessage` | String | `'No data available'` | Message shown in the empty state |
diff --git a/src/components/CnSettingsSection/CnSettingsSection.vue b/src/components/CnSettingsSection/CnSettingsSection.vue
index b3549d1..89d1dca 100644
--- a/src/components/CnSettingsSection/CnSettingsSection.vue
+++ b/src/components/CnSettingsSection/CnSettingsSection.vue
@@ -75,15 +75,18 @@ import InformationOutline from 'vue-material-design-icons/InformationOutline.vue
* Extracted from OpenRegister's SettingsSection. Designed for reuse across all
* Conduction Nextcloud apps.
*
- * @example Basic usage
+ * Basic usage
+ * ```vue
*
*
* Clear Cache
*
*
Cache hit rate: 94%
*
+ * ```
*
- * @example With loading and error states
+ * With loading and error states
+ * ```vue
*
*
*
+ * ```
*
- * @example With empty state
+ * With empty state
+ * ```vue
*
*
*
+ * ```
*/
export default {
name: 'CnSettingsSection',
diff --git a/src/components/CnStatsBlock/CnStatsBlock.md b/src/components/CnStatsBlock/CnStatsBlock.md
new file mode 100644
index 0000000..2978fd8
--- /dev/null
+++ b/src/components/CnStatsBlock/CnStatsBlock.md
@@ -0,0 +1,120 @@
+Vertical (default) — centered count and label:
+
+```vue
+
+
+
+
+
+
+```
+
+Horizontal with icon — icon on the left, content on the right:
+
+```vue
+
+