diff --git a/.github/workflows/branch-protection.yml b/.github/workflows/branch-protection.yml index a6d20bb..28065f9 100644 --- a/.github/workflows/branch-protection.yml +++ b/.github/workflows/branch-protection.yml @@ -5,5 +5,5 @@ on: branches: [main, beta] jobs: - check: + branch-protection: uses: ConductionNL/.github/.github/workflows/branch-protection.yml@main diff --git a/.github/workflows/documentation-beta.yml b/.github/workflows/documentation-beta.yml new file mode 100644 index 0000000..658d9ed --- /dev/null +++ b/.github/workflows/documentation-beta.yml @@ -0,0 +1,40 @@ +name: Documentation (Beta) + +on: + push: + branches: + - beta + +jobs: + deploy-beta: + name: Deploy Beta Styleguide + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js 20 + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install and build component styleguide + timeout-minutes: 10 + run: | + cd styleguide + npm ci + npm run build + + - name: Deploy styleguide to /beta/ on GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./styleguide/build + publish_branch: gh-pages + destination_dir: beta/styleguide + user_name: 'github-actions[bot]' + user_email: 'github-actions[bot]@users.noreply.github.com' + keep_files: true diff --git a/.github/workflows/documentation-dev.yml b/.github/workflows/documentation-dev.yml new file mode 100644 index 0000000..8228662 --- /dev/null +++ b/.github/workflows/documentation-dev.yml @@ -0,0 +1,41 @@ +name: Documentation (Dev) + +on: + push: + branches: + - development + +jobs: + deploy-dev: + name: Deploy Dev Styleguide + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js 20 + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install and build component styleguide + timeout-minutes: 10 + run: | + cd styleguide + npm ci + npm run build + + - name: Deploy styleguide to /dev/ on GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./styleguide/build + + publish_branch: gh-pages + destination_dir: dev/styleguide + user_name: 'github-actions[bot]' + user_email: 'github-actions[bot]@users.noreply.github.com' + keep_files: true diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 7a5e2c6..a659273 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -26,6 +26,13 @@ jobs: with: node-version: '20' + - name: Install and build component styleguide + timeout-minutes: 10 + run: | + cd styleguide + npm ci + npm run build + - name: Clear build cache and install dependencies timeout-minutes: 3 run: | @@ -43,6 +50,12 @@ jobs: exit 1 fi + - name: Copy styleguide into Docusaurus build + run: | + mkdir -p docusaurus/build/styleguide + cp -r styleguide/build/. docusaurus/build/styleguide/ + + - name: Create .nojekyll file run: | cd docusaurus/build @@ -58,7 +71,7 @@ jobs: user_email: 'github-actions[bot]@users.noreply.github.com' force_orphan: false allow_empty_commit: true - keep_files: false + keep_files: true - name: Verify deployment run: | diff --git a/.gitignore b/.gitignore index f79db30..3428abd 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,7 @@ dist/ # Docusaurus build output docusaurus/build .docusaurus + +# Styleguide build output +styleguide/build +.styleguide \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 372b5b3..f675313 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,4 +28,7 @@ "[php]": { "editor.defaultFormatter": "DEVSENSE.phptools-vscode" }, + "[markdown]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, } diff --git a/docs/components/cn-advanced-form-dialog.md b/docs/components/cn-advanced-form-dialog.md index 38c830e..1588352 100644 --- a/docs/components/cn-advanced-form-dialog.md +++ b/docs/components/cn-advanced-form-dialog.md @@ -129,11 +129,52 @@ This means the directive is self-contained — it works even if the consuming ap --- +## Live demo + +```vue + + +``` + ## Usage examples ### Standalone (emit confirm, parent saves) -```vue +```vue {static} + +``` + +## Usage + +```vue {static} +
+ + +
+ + +``` + +## Usage + +```vue {static} +
+ + +
+ + +``` + +## Usage + +```vue {static} +
+ + +
+ + +``` + +--- + ## Usage examples ### Basic create/edit (standalone) -```vue +```vue {static} * + * ``` */ export default { name: 'CnCardGrid', diff --git a/src/components/CnCellRenderer/CnCellRenderer.md b/src/components/CnCellRenderer/CnCellRenderer.md new file mode 100644 index 0000000..aed320a --- /dev/null +++ b/src/components/CnCellRenderer/CnCellRenderer.md @@ -0,0 +1,60 @@ +String value — plain text with optional truncation: + +```vue +
+ + +
+``` + +Boolean — renders a check icon for `true`, dash for `false`: + +```vue +
+
+ true + +
+
+ false + +
+
+``` + +Enum — renders as a CnStatusBadge: + +```vue +
+ + + +
+``` + +Array — joined list or dash when empty: + +```vue +
+ + +
+``` + +Date/UUID — formatted with monospace styling: + +```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 + + + +``` + +## 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 + + +``` + +Locked to hex mode — hides the RGB/HSL toggle: + +```vue + + +``` + +Disabled state — swatch is not clickable: + +```vue + +``` + +Multiple color pickers: + +```vue + + +``` 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 + + +``` 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 * * *

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 + + +``` 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 + + +``` + +Custom dialog title and name formatter: + +```vue + + +``` + +Custom patterns — override the naming options shown in the dropdown: + +```vue + + +``` + +## 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 + + +``` + +Editable grid with `editable`, `columns`, `cellHeight`, `margin`, `minWidth`, and `minHeight`: + +```vue + + +``` + +## Additional props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `editable` | Boolean | `false` | Enable drag and resize interactions | +| `columns` | Number | `12` | Number of grid columns | +| `cellHeight` | Number | `80` | Cell height in pixels | +| `margin` | Number | `12` | Gutter between grid items in pixels | +| `minWidth` | Number | `2` | Minimum widget width in grid units | +| `minHeight` | Number | `2` | Minimum widget height in grid units | diff --git a/src/components/CnDashboardGrid/CnDashboardGrid.vue b/src/components/CnDashboardGrid/CnDashboardGrid.vue index 8af46b2..95d9302 100644 --- a/src/components/CnDashboardGrid/CnDashboardGrid.vue +++ b/src/components/CnDashboardGrid/CnDashboardGrid.vue @@ -39,7 +39,7 @@ import 'gridstack/dist/gridstack.min.css' * changes. Does NOT handle widget rendering — that's done by the parent * via the `#widget` scoped slot. * - * @example + * ```vue * * * + * ``` */ export default { name: 'CnDashboardGrid', diff --git a/src/components/CnDashboardPage/CnDashboardPage.md b/src/components/CnDashboardPage/CnDashboardPage.md new file mode 100644 index 0000000..f32d36d --- /dev/null +++ b/src/components/CnDashboardPage/CnDashboardPage.md @@ -0,0 +1,116 @@ +Full dashboard page with custom widgets — each widget gets a scoped slot: + +```vue + + +``` + +With `loading`, `cellHeight`, `gridMargin`, `emptyLabel`, `unavailableLabel`, `header-actions`, and `actions` slots: + +```vue + + +``` + +## Additional props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `loading` | Boolean | `false` | Show a loading spinner instead of the widget grid | +| `cellHeight` | Number | `80` | Grid cell height in pixels (passed to CnDashboardGrid) | +| `gridMargin` | Number | `12` | Grid margin (gutter) in pixels between widgets | +| `emptyLabel` | String | `'No widgets configured'` | Text shown in the empty state when `layout` is empty | +| `unavailableLabel` | String | `'Widget not available'` | Text shown for unknown or unavailable widgets | + +## Slots + +| Slot | Scope | Description | +|------|-------|-------------| +| `header-actions` | — | Extra buttons shown in the page header (right side, before the edit toggle) | +| `actions` | — | Back-compat alias for `header-actions`; prefer `header-actions` in new code | +| `widget-{widgetId}` | `{ item, widget }` | Custom widget content for a widget with the given ID | +| `empty` | — | Custom empty state when no widgets are in the layout | diff --git a/src/components/CnDashboardPage/CnDashboardPage.vue b/src/components/CnDashboardPage/CnDashboardPage.vue index a1d72ed..1c2c7b6 100644 --- a/src/components/CnDashboardPage/CnDashboardPage.vue +++ b/src/components/CnDashboardPage/CnDashboardPage.vue @@ -149,7 +149,8 @@ import CnTileWidget from '../CnTileWidget/CnTileWidget.vue' * 2. **NC Dashboard API** — Widgets with `itemApiVersions` are auto-rendered * 3. **Tile** — Items with `type: 'tile'` render as quick-access tiles * - * @example Basic usage with custom widgets + * Basic usage with custom widgets + * ```vue * * * + * ``` * - * @example With NC Dashboard API widgets + * With NC Dashboard API widgets + * ```vue * + * ``` */ export default { name: 'CnDashboardPage', @@ -203,8 +207,7 @@ export default { * Custom widgets: `{ id: 'my-widget', title: 'My Widget', type: 'custom' }` * NC API widgets: `{ id: 'calendar', title: 'Calendar', itemApiVersions: [1,2], ... }` * Tile widgets: `{ id: 'tile-files', type: 'tile', title: 'Files', icon: 'M12...', iconType: 'svg', backgroundColor: '#0082c9', textColor: '#fff', linkType: 'app', linkValue: 'files' }` - * - * @type {Array<{ id: string, title: string, type?: string, iconUrl?: string, iconClass?: string, buttons?: Array, itemApiVersions?: number[], reloadInterval?: number, [key: string]: any }>} + * @type {Array<{ id: string, title: string, type: string, iconUrl: string, iconClass: string, buttons: Array, itemApiVersions: number[], reloadInterval: number }>} */ widgets: { type: Array, @@ -216,8 +219,7 @@ export default { * Each item: `{ id: 'unique-id', widgetId: 'my-widget', gridX: 0, gridY: 0, gridWidth: 4, gridHeight: 3 }` * * Additional properties (showTitle, styleConfig, tile config) are passed through. - * - * @type {Array<{ id: string|number, widgetId: string, gridX: number, gridY: number, gridWidth: number, gridHeight: number, showTitle?: boolean, styleConfig?: object, [key: string]: any }>} + * @type {Array<{ id: string|number, widgetId: string, gridX: number, gridY: number, gridWidth: number, gridHeight: number, showTitle: boolean, styleConfig: object }>} */ layout: { type: Array, diff --git a/src/components/CnDataTable/CnDataTable.md b/src/components/CnDataTable/CnDataTable.md new file mode 100644 index 0000000..ad4045f --- /dev/null +++ b/src/components/CnDataTable/CnDataTable.md @@ -0,0 +1,202 @@ +Basic table — columns with rows: + +```vue + +``` + +With selection and status badges via custom cell slot: + +```vue + + +``` + +Loading state: + +```vue + +``` + +Empty state: + +```vue + +``` + +Schema-driven — auto-generate columns from a JSON Schema: + +```vue + +``` + +Schema with `columnOverrides`, `excludeColumns`, and `includeColumns`: + +```vue + +``` + +Sorted table — controlled `sortKey` / `sortOrder`, `selectedIds`, `rowClass`, `cellClass`: + +```vue + + +``` + +## Additional props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `schema` | Object | `null` | JSON Schema with `properties` — enables schema-driven column generation | +| `columnOverrides` | Object | `{}` | Per-key column overrides when using `schema` mode: `{ key: { width, label, sortable, … } }` | +| `excludeColumns` | Array | `[]` | Column keys to exclude in schema mode | +| `includeColumns` | Array | `null` | Column keys to include (whitelist) in schema mode | +| `sortKey` | String | `null` | Currently active sort column key (controlled) | +| `sortOrder` | String | `'asc'` | Current sort direction: `'asc'` or `'desc'` | +| `selectedIds` | Array | `[]` | Array of selected row IDs (controlled) | +| `rowClass` | Function | `null` | `(row) => string` — CSS class(es) applied to each `` | +| `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 + + +``` + +Custom name formatter — override how the item name is resolved: + +```vue + + +``` + +Error result — call `setResult({ error: '...' })` on failure: + +```vue + + +``` + +## 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 * * * * + * ``` * - * @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 + + + +``` + +## 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 + + +``` + +With icon, subtitle, and stats table: + +```vue + + +``` + +With error state and retry: + +```vue + + +``` + +With empty state and loading label: + +```vue + + +``` + +With sidebar integration: + +```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 + + +``` + +Loading state: + +```vue + +``` + +With live `facetData` from the API — option labels include counts when facet data is provided: + +```vue + + +``` + +Admin-only filters — set `userIsAdmin` to `false` to hide schema properties marked `adminOnly: true`: + +```vue + +``` + +## 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 + + +``` + +With select and checkbox filters: + +```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 + + +``` + +Edit mode — pre-populate form with `item` data: + +```vue + + +``` + +## 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 Async select with custom option rendering + * Async select with custom option rendering + * ```vue * +``` + +Sizes — the `size` prop controls pixel dimensions (default: `20`): + +```vue +
+ + + + + +
+``` + +Fallback — unregistered names render the fallback icon: + +```vue +
+ Unregistered → fallback: + + Custom fallback: + +
+``` + +Registered icons — call `registerIcons()` in `main.js` before mounting Vue, then use by name: + +```vue + + +``` diff --git a/src/components/CnIcon/CnIcon.vue b/src/components/CnIcon/CnIcon.vue index 0e714fc..8231b71 100644 --- a/src/components/CnIcon/CnIcon.vue +++ b/src/components/CnIcon/CnIcon.vue @@ -12,7 +12,6 @@ import HelpCircleOutline from 'vue-material-design-icons/HelpCircleOutline.vue' * Apps extend this at boot via registerIcons() — import only the * icons you need, keeping bundles small. * - * @example * import { registerIcons } from '@conduction/nextcloud-vue' * import Sword from 'vue-material-design-icons/Sword.vue' * registerIcons({ Sword }) @@ -30,7 +29,6 @@ const _registry = { * * @param {Record} icons - Map of PascalCase icon names to Vue components * - * @example * import { registerIcons } from '@conduction/nextcloud-vue' * import Sword from 'vue-material-design-icons/Sword.vue' * import MagicStaff from 'vue-material-design-icons/MagicStaff.vue' @@ -54,8 +52,9 @@ export const ICON_MAP = _registry * Looks up the name in the shared registry. If not found, renders * the fallback icon (HelpCircleOutline by default). * - * @example + * ```vue * + * ``` * * @see https://pictogrammers.com/library/mdi/ */ diff --git a/src/components/CnIndexPage/CnIndexPage.md b/src/components/CnIndexPage/CnIndexPage.md new file mode 100644 index 0000000..e1cadc6 --- /dev/null +++ b/src/components/CnIndexPage/CnIndexPage.md @@ -0,0 +1,399 @@ +CnIndexPage is the top-level schema-driven index page that combines CnActionsBar, CnDataTable/CnCardGrid, CnPagination, and all single/mass-action dialogs in one component. + +Full example — table view with CRUD actions: + +```vue + + +``` + +With inline header, custom icon, and view toggle: + +```vue + + +``` + +With column and field control: + +```vue + + +``` + +With store integration and action visibility control: + +```vue + + +``` + +With mass-action customisation: + +```vue + + +``` + +With form dialog control: + +```vue + + +``` + +With overridable header slot and below-header slot: + +```vue + + +``` + +## 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 * * *
+ * ``` * * // 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 + + +``` + +Limiting metadata fields and custom `metadata` slot — `maxMetadata` caps the number of auto-rendered property fields; the `metadata` slot replaces the default rendering: + +```vue + + +``` + +## 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 * * * + * ``` */ 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 + + +``` + +Read-only mode — no inline editing: + +```vue +
+ +
+``` + +With `icon`, `objectType`, `store`, `columns`, `overrides`, `exclude`, `include`, and custom labels: + +```vue + + +``` + +## Additional props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `icon` | Object\|Function | `null` | MDI icon component shown in the card header | +| `objectType` | String | `''` | Registered object type slug used by `objectStore.saveObject()` | +| `store` | Object | `null` | Explicit Pinia objectStore instance; auto-detected via Pinia when omitted | +| `overrides` | Object | `{}` | Per-property config: `{ key: { order, gridColumn, gridRow, hidden, editable, label, widget } }` | +| `columns` | Number | `3` | Number of CSS grid columns in the widget | +| `exclude` | Array | `[]` | Property keys to hide | +| `include` | Array | `null` | Property keys to show (whitelist; shows all when `null`) | +| `saveLabel` | String | `'Save'` | Label for the save button | +| `discardLabel` | String | `'Discard'` | Label for the discard button | +| `emptyLabel` | String | `'No data available'` | Label shown when no properties are displayable | diff --git a/src/components/CnObjectDataWidget/CnObjectDataWidget.vue b/src/components/CnObjectDataWidget/CnObjectDataWidget.vue index e0c1972..97c8439 100644 --- a/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +++ b/src/components/CnObjectDataWidget/CnObjectDataWidget.vue @@ -235,7 +235,8 @@ import { fieldsFromSchema, formatValue } from '../../utils/schema.js' * as a label-value cell. Editable cells can be clicked to switch to inline editing. * Uses the objectStore to persist changes. * - * @example Basic usage + * Basic usage + * ```vue * + * ``` * - * @example Read-only mode + * Read-only mode + * ```vue * + * ``` */ export default { name: 'CnObjectDataWidget', @@ -326,8 +330,7 @@ export default { * - `editable` (boolean) — Override editability (default: based on schema readOnly) * - `label` (string) — Override the display label * - `widget` (string) — Override the widget type for editing - * - * @type {{ [key: string]: { order?: number, gridColumn?: number, gridRow?: number, hidden?: boolean, editable?: boolean, label?: string, widget?: string } }} + * @type {object} */ overrides: { type: Object, diff --git a/src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.md b/src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.md new file mode 100644 index 0000000..8c86255 --- /dev/null +++ b/src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.md @@ -0,0 +1,134 @@ +Auto-extracts known system fields (id, uuid, uri, register, schema, created, updated, owner, etc.): + +```vue +
+ +
+``` + +Filtered — show only specific fields: + +```vue +
+ +
+``` + +Horizontal layout with extra items: + +```vue +
+ +
+``` + +Collapsible: + +```vue +
+ +
+``` + +With `icon`, `columns`, `labelWidth`, `exclude`, `emptyLabel`, and the `actions` slot: + +```vue + + +``` + +## Additional props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `icon` | Object\|Function | `null` | MDI icon component shown in the card header | +| `columns` | Number | `0` | Number of grid columns (only relevant for `layout="grid"`; `0` = auto) | +| `labelWidth` | Number | `150` | Minimum label width in pixels for `layout="horizontal"` | +| `exclude` | Array | `[]` | Metadata field keys to hide | +| `emptyLabel` | String | `'No metadata available'` | Text shown when no metadata fields are present | + +## Slots + +| Slot | Description | +|------|-------------| +| `actions` | Action buttons rendered in the card header (e.g. a "Copy UUID" button) | diff --git a/src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue b/src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue index 4001103..66a45a4 100644 --- a/src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue +++ b/src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue @@ -59,10 +59,13 @@ const METADATA_FIELDS = [ * Understands both flat objects (where metadata is at the top level) and * objects with a `@self` metadata block. * - * @example Basic usage + * Basic usage + * ```vue * + * ``` * - * @example With extra items + * With extra items + * ```vue * + * ``` * - * @example Selective display + * Selective display + * ```vue * + * ``` */ export default { name: 'CnObjectMetadataWidget', diff --git a/src/components/CnObjectSidebar/CnAuditTrailTab.vue b/src/components/CnObjectSidebar/CnAuditTrailTab.vue index ea483aa..c248400 100644 --- a/src/components/CnObjectSidebar/CnAuditTrailTab.vue +++ b/src/components/CnObjectSidebar/CnAuditTrailTab.vue @@ -104,7 +104,7 @@ - {{ loadingMore ? '' : loadMoreLabel }} + {{ loadMoreLabel }} diff --git a/src/components/CnObjectSidebar/CnFilesTab.vue b/src/components/CnObjectSidebar/CnFilesTab.vue index baf8928..80feb30 100644 --- a/src/components/CnObjectSidebar/CnFilesTab.vue +++ b/src/components/CnObjectSidebar/CnFilesTab.vue @@ -67,7 +67,7 @@ - {{ loadingMore ? '' : loadMoreLabel }} + {{ loadMoreLabel }} diff --git a/src/components/CnObjectSidebar/CnObjectSidebar.md b/src/components/CnObjectSidebar/CnObjectSidebar.md new file mode 100644 index 0000000..382c7a2 --- /dev/null +++ b/src/components/CnObjectSidebar/CnObjectSidebar.md @@ -0,0 +1,91 @@ +CnObjectSidebar provides a standardized right sidebar with Files, Notes, Tags, Tasks, and Audit Trail tabs for any OpenRegister object. It uses `NcAppSidebar` and integrates with OpenRegister API endpoints. + +It renders within the Nextcloud app layout. In the styleguide, it appears in a constrained container: + +```vue + +``` + +Custom tab content via slot: + +```vue + +``` + +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" />