add kirby-loop plugin with French translations
All checks were successful
Deploy / Deploy to Production (push) Successful in 6s
All checks were successful
Deploy / Deploy to Production (push) Successful in 6s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8ea5f0c462
commit
ab7fd8b2ea
74 changed files with 16423 additions and 2 deletions
90
site/plugins/loop/docs/01-installation.md
Normal file
90
site/plugins/loop/docs/01-installation.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
---
|
||||
title: Installation
|
||||
---
|
||||
|
||||
This guide covers all installation methods for the Kirby Loop plugin.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before installing the plugin, ensure your system meets these requirements:
|
||||
|
||||
- **Kirby CMS**: Version 4.0 or higher
|
||||
- **PHP**: Version 8.3 or higher
|
||||
- **SQLite**: Support enabled (usually included by default in PHP)
|
||||
|
||||
## Installation Methods
|
||||
|
||||
### Method 1: Composer (Recommended)
|
||||
|
||||
Composer is the preferred installation method
|
||||
|
||||
```bash
|
||||
composer require moinframe/kirby-loop
|
||||
```
|
||||
|
||||
### Method 2: Manual Installation
|
||||
|
||||
For environments where Composer isn't available or preferred:
|
||||
|
||||
1. **Download the plugin**
|
||||
- Visit the [GitHub releases page](https://github.com/moinframe/kirby-loop/releases)
|
||||
- Download the latest version as a ZIP file
|
||||
|
||||
2. **Extract and place**
|
||||
- Unzip the downloaded archive
|
||||
- Rename the folder to `loop` (remove version numbers)
|
||||
- Move the folder to `/site/plugins/loop`
|
||||
|
||||
3. **Verify installation**
|
||||
- The plugin folder should contain `index.php` and other plugin files
|
||||
- Your final structure should be: `/site/plugins/loop/index.php`
|
||||
|
||||
### Method 3: Git Submodule
|
||||
|
||||
For projects using Git version control, submodules provide a clean way to include the plugin:
|
||||
|
||||
```bash
|
||||
git submodule add https://github.com/moinframe/kirby-loop.git site/plugins/loop
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
After successful installation:
|
||||
|
||||
1. **Configuration**: See [Configuration Guide](https://moinfra.me/docs/moinframe-loop/02-configuration) for customization options
|
||||
2. **Multi-language**: If using multiple languages, review [Multi-language Setup](https://moinfra.me/docs/moinframe-loop/03-multi-language)
|
||||
3. **API Integration**: For custom implementations, check the [API Reference](https://moinfra.me/docs/moinframe-loop/05-api)
|
||||
|
||||
## Updating
|
||||
|
||||
### Composer Updates
|
||||
```bash
|
||||
composer update moinframe/kirby-loop
|
||||
```
|
||||
|
||||
### Manual Updates
|
||||
1. Download the new version
|
||||
2. Replace the plugin folder (backup first!)
|
||||
3. Clear any caches
|
||||
|
||||
### Git Submodule Updates
|
||||
```bash
|
||||
git submodule update --remote site/plugins/loop
|
||||
git add site/plugins/loop
|
||||
git commit -m "Update loop plugin"
|
||||
```
|
||||
|
||||
## Uninstallation
|
||||
|
||||
To remove the plugin:
|
||||
|
||||
1. **Remove plugin files**:
|
||||
- Composer: `composer remove moinframe/kirby-loop`
|
||||
- Manual: Delete `/site/plugins/loop/` folder
|
||||
- Git submodule: `git submodule deinit site/plugins/loop`
|
||||
|
||||
2. **Clean up data** (optional):
|
||||
- Delete `/site/logs/loop/` directory to remove all comments
|
||||
- Remove configuration from `site/config/config.php`
|
||||
|
||||
3. **Clear caches**: Clear any site caches to ensure complete removal
|
||||
252
site/plugins/loop/docs/02-configuration.md
Normal file
252
site/plugins/loop/docs/02-configuration.md
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
---
|
||||
title: Configuration
|
||||
---
|
||||
|
||||
You can customize the plugin's look and behavior by adding configuration options.
|
||||
Add configuration options to your `site/config/config.php` file:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
return [
|
||||
// Your existing Kirby configuration...
|
||||
|
||||
// Loop Configuration
|
||||
'moinframe.loop' => [
|
||||
'auto-inject' => true,
|
||||
...
|
||||
]
|
||||
];
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Enable/Disable Tool
|
||||
|
||||
**Option**: `moinframe.loop.enabled`
|
||||
**Type**: `boolean|callable`
|
||||
**Default**: `true`
|
||||
|
||||
Controls whether loop is enabled globally or conditionally.
|
||||
|
||||
```php
|
||||
// Simple boolean enable/disable
|
||||
'moinframe.loop.enabled' => false, // Disables globally
|
||||
|
||||
// Use a callback for dynamic control
|
||||
'moinframe.loop.enabled' => function($page) {
|
||||
// Only enable for specific templates
|
||||
return in_array($page->template()->name(), ['article', 'blog']);
|
||||
},
|
||||
|
||||
// Filter by page status
|
||||
'moinframe.loop.enabled' => function($page) {
|
||||
return $page->status() === 'published';
|
||||
},
|
||||
|
||||
// Complex conditions
|
||||
'moinframe.loop.enabled' => function($page) {
|
||||
return $page->template()->name() === 'article'
|
||||
&& $page->status() === 'published'
|
||||
&& !$page->archived()->toBool();
|
||||
}
|
||||
```
|
||||
|
||||
**Callback function receives:**
|
||||
- `$page` - The current Kirby page object
|
||||
|
||||
**Common use cases:**
|
||||
- Disable feedback on specific page templates
|
||||
- Enable only for published content
|
||||
- Conditional enabling based on page fields or metadata
|
||||
|
||||
**Note**: This option is checked both during auto-injection and manual snippet usage.
|
||||
|
||||
### Auto-Injection
|
||||
|
||||
**Option**: `moinframe.loop.auto-inject`
|
||||
**Type**: `boolean`
|
||||
**Default**: `true`
|
||||
|
||||
Controls whether loop is automatically injected into all pages.
|
||||
|
||||
```php
|
||||
// Disable auto-injection (requires manual snippet placement)
|
||||
'moinframe.loop.auto-inject' => false,
|
||||
```
|
||||
|
||||
When disabled, you must manually add the snippet to your templates:
|
||||
|
||||
```php
|
||||
<?php snippet('loop/app') ?>
|
||||
```
|
||||
|
||||
**Use cases for disabling auto-injection:**
|
||||
- Custom page templates where you want precise control
|
||||
- JavaScript-based routing (Swup, Taxi.js) that needs manual initialization
|
||||
- Conditional loading based on user roles or page types
|
||||
|
||||
### Position
|
||||
|
||||
**Option**: `moinframe.loop.position`
|
||||
**Type**: `string`
|
||||
**Default**: `'top'`
|
||||
**Values**: `'top'` | `'bottom'`
|
||||
|
||||
Sets the position of loop header on the page.
|
||||
|
||||
```php
|
||||
// Position header at bottom of page
|
||||
'moinframe.loop.position' => 'bottom',
|
||||
```
|
||||
|
||||
### Database Path
|
||||
|
||||
**Option**: `moinframe.loop.database`
|
||||
**Type**: `string|null`
|
||||
**Default**: `null` (uses `site/logs/loop/comments.sqlite`)
|
||||
|
||||
Customize the SQLite database location.
|
||||
|
||||
```php
|
||||
// Custom database path
|
||||
'moinframe.loop.database' => '/custom/path/comments.sqlite',
|
||||
|
||||
// Alternative locations
|
||||
'moinframe.loop.database' => kirby()->root('content') . '/feedback.sqlite',
|
||||
'moinframe.loop.database' => '/var/www/data/feedback.sqlite',
|
||||
```
|
||||
|
||||
**Important considerations:**
|
||||
- Path must be absolute
|
||||
- Directory must exist and be writable
|
||||
- Consider backup strategies for custom locations
|
||||
- Ensure path is outside web root for security
|
||||
|
||||
### Public Access
|
||||
|
||||
**Option**: `moinframe.loop.public`
|
||||
**Type**: `boolean`
|
||||
**Default**: `false`
|
||||
|
||||
Controls whether loop requires authentication.
|
||||
|
||||
```php
|
||||
// Allow public access (no authentication required)
|
||||
'moinframe.loop.public' => true,
|
||||
```
|
||||
|
||||
**Security implications:**
|
||||
- `false` (default): Only authenticated panel users can see/use the tool
|
||||
- `true`: Anyone can add comments
|
||||
|
||||
**Recommended for public access:**
|
||||
- Internal staging environments
|
||||
- Client review sites with controlled access
|
||||
- Public beta feedback collection
|
||||
|
||||
### Language Override
|
||||
|
||||
**Option**: `moinframe.loop.language`
|
||||
**Type**: `string|null`
|
||||
**Default**: `null` (auto-detect from Kirby)
|
||||
|
||||
Force a specific UI language regardless of the current page language.
|
||||
|
||||
```php
|
||||
// Force German UI
|
||||
'moinframe.loop.language' => 'de',
|
||||
|
||||
// Force English UI
|
||||
'moinframe.loop.language' => 'en',
|
||||
```
|
||||
|
||||
**When to use:**
|
||||
- Single-language sites with non-English content but English-speaking editors
|
||||
- Multi-language sites where editors prefer consistent UI language
|
||||
|
||||
### Theme
|
||||
|
||||
**Option**: `moinframe.loop.theme`
|
||||
**Type**: `string`
|
||||
**Default**: `'default'`
|
||||
**Values**: `'default'` | `'dark'` | custom theme name
|
||||
|
||||
Sets the visual theme for the loop interface.
|
||||
|
||||
```php
|
||||
// Use dark theme
|
||||
'moinframe.loop.theme' => 'dark',
|
||||
|
||||
// Use custom theme
|
||||
'moinframe.loop.theme' => 'custom',
|
||||
```
|
||||
|
||||
**Available themes:**
|
||||
- `'default'` - Light theme with clean, bright interface
|
||||
- `'dark'` - Dark theme for low-light environments
|
||||
- Custom theme names - See [Theming Guide](https://moinfra.me/docs/moinframe-loop/04-theming) for creating custom themes
|
||||
|
||||
### Welcome Dialog
|
||||
|
||||
The welcome dialog introduces new users to loop functionality.
|
||||
|
||||
#### Enable/Disable Welcome Dialog
|
||||
|
||||
**Option**: `moinframe.loop.welcome.enabled`
|
||||
**Type**: `boolean`
|
||||
**Default**: `true`
|
||||
|
||||
```php
|
||||
// Disable welcome dialog
|
||||
'moinframe.loop.welcome.enabled' => false,
|
||||
```
|
||||
|
||||
#### Custom Welcome Headline
|
||||
|
||||
**Option**: `moinframe.loop.welcome.headline`
|
||||
**Type**: `string|null`
|
||||
**Default**: `null` (uses default translation)
|
||||
|
||||
```php
|
||||
// Custom welcome headline
|
||||
'moinframe.loop.welcome.headline' => 'Welcome to Our Review Tool!',
|
||||
```
|
||||
|
||||
#### Custom Welcome Text
|
||||
|
||||
**Option**: `moinframe.loop.welcome.text`
|
||||
**Type**: `string|null`
|
||||
**Default**: `null` (uses default translation)
|
||||
|
||||
```php
|
||||
// Custom welcome message
|
||||
'moinframe.loop.welcome.text' => 'Click anywhere on the page to leave feedback. Use the toggle button to switch between navigation and comment modes.',
|
||||
```
|
||||
|
||||
## Manual Snippet Usage
|
||||
|
||||
When auto-injection is disabled, you have full control over when and where loop appears.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```php
|
||||
<?php snippet('loop/app') ?>
|
||||
```
|
||||
|
||||
### Conditional Loading
|
||||
|
||||
```php
|
||||
<?php if ($kirby->user() && $kirby->user()->role()->isAdmin()): ?>
|
||||
<?php snippet('loop/app') ?>
|
||||
<?php endif ?>
|
||||
```
|
||||
|
||||
> [!TIPP]
|
||||
> Manual snippets also respect the `enabled` configuration option. If you've set up conditional enabling via the `enabled` option, you don't need to duplicate that logic in your template - the snippet will automatically check the enabled status.
|
||||
|
||||
|
||||
## Caching Behavior
|
||||
|
||||
> [!WARNING]
|
||||
> Pages with loop automatically have Kirby's page **cache** **disabled**. This is necessary for CSRF token validation and User authentication checks.
|
||||
94
site/plugins/loop/docs/03-multi-language.md
Normal file
94
site/plugins/loop/docs/03-multi-language.md
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
---
|
||||
title: Multi-Language
|
||||
---
|
||||
|
||||
Kirby Loop provides comprehensive support for multi-language Kirby sites, including automatic language detection and customizable UI translations.
|
||||
|
||||
## How Multi-Language Support Works
|
||||
|
||||
The plugin automatically detects and adapts to your Kirby site's language configuration. No additional configuration is required - the plugin works automatically with Kirby's multi-language setup.
|
||||
|
||||
- **Single-language sites**: Uses the en translations
|
||||
- **Multi-language sites**: Detects the current page language and adapts accordingly
|
||||
|
||||
|
||||
|
||||
## UI Language Override
|
||||
|
||||
### Forcing a Specific UI Language
|
||||
|
||||
By default, loop UI adapts to the current page language. You can override this behavior:
|
||||
|
||||
```php
|
||||
// Always show German UI regardless of page language
|
||||
'moinframe.loop.language' => 'de',
|
||||
|
||||
// Always show English UI regardless of page language
|
||||
'moinframe.loop.language' => 'en',
|
||||
```
|
||||
|
||||
### Use Cases for Language Override
|
||||
|
||||
**Consistent Editor Experience:**
|
||||
```php
|
||||
// Editors prefer English UI even on German pages
|
||||
'moinframe.loop.language' => 'en',
|
||||
```
|
||||
|
||||
**Single-Language website with non english content:**
|
||||
```php
|
||||
// German content site with German-speaking editors
|
||||
'moinframe.loop.language' => 'de',
|
||||
```
|
||||
|
||||
|
||||
## Built-in Translations
|
||||
|
||||
The plugin includes complete translations for:
|
||||
- English (en) - Default
|
||||
- German (de)
|
||||
|
||||
## Custom Translations
|
||||
|
||||
### Adding New Languages
|
||||
|
||||
To add support for additional languages, create or extend your Kirby language files:
|
||||
|
||||
```php
|
||||
// site/languages/fr.php
|
||||
<?php
|
||||
|
||||
return [
|
||||
'code' => 'fr',
|
||||
'default' => false,
|
||||
'direction' => 'ltr',
|
||||
'locale' => 'fr_FR',
|
||||
'name' => 'Français',
|
||||
'translations' => [
|
||||
// UI Elements
|
||||
'moinframe.loop.ui.header.title' => 'Commentaires',
|
||||
...
|
||||
]
|
||||
];
|
||||
```
|
||||
|
||||
### Overriding Existing Translations
|
||||
|
||||
Customize existing translations by adding them to your language files:
|
||||
|
||||
```php
|
||||
// site/languages/en.php - Override English defaults
|
||||
return [
|
||||
'code' => 'en',
|
||||
'default' => true,
|
||||
'translations' => [
|
||||
'moinframe.loop.ui.header.title' => 'Page Feedback',
|
||||
'moinframe.loop.ui.comment.placeholder' => 'What needs attention?',
|
||||
'moinframe.loop.ui.welcome.headline' => 'Welcome to Our Review Tool',
|
||||
]
|
||||
];
|
||||
```
|
||||
|
||||
### Translation Key Reference
|
||||
|
||||
For a complete list of available translation keys, see the [plugin's index file](https://github.com/moinframe/kirby-loop/blob/main/index.php).
|
||||
110
site/plugins/loop/docs/04-theming.md
Normal file
110
site/plugins/loop/docs/04-theming.md
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
---
|
||||
title: Theming
|
||||
---
|
||||
|
||||
Kirby Loop comes with built-in theming support, allowing you to customize the visual appearance to match your brand or provide different user experiences. The plugin includes a default (light) theme and a dark theme, with support for creating custom themes.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Setting a Theme
|
||||
|
||||
Configure the theme in your `site/config/config.php`:
|
||||
|
||||
```php
|
||||
return [
|
||||
// Set theme: 'default', 'dark', or custom theme name
|
||||
'moinframe.loop.theme' => 'dark',
|
||||
];
|
||||
```
|
||||
|
||||
**Available options:**
|
||||
- `'default'` - Light theme (default)
|
||||
- `'dark'` - Dark theme
|
||||
- Custom theme name
|
||||
|
||||
## Creating Custom Themes
|
||||
|
||||
Custom themes are CSS files that override the default color and styling tokens. The theming system uses CSS custom properties (variables) for easy customization.
|
||||
|
||||
|
||||
### Basic Custom Theme
|
||||
|
||||
Here's a minimal custom theme example:
|
||||
|
||||
```css
|
||||
/* frontend/src/styles/theme-custom.css */
|
||||
kirby-loop[theme="custom"] {
|
||||
/* Accent color */
|
||||
--color-accent-l: 0.6;
|
||||
--color-accent-c: 0.15;
|
||||
--color-accent-h: 280; /* Purple accent */
|
||||
|
||||
/* Neutral color lightness values */
|
||||
--color-neutral-l-0: 0.98;
|
||||
--color-neutral-l-100: 0.92;
|
||||
--color-neutral-l-200: 0.86;
|
||||
--color-neutral-l-300: 0.7;
|
||||
--color-neutral-l-400: 0.6;
|
||||
--color-neutral-l-500: 0.5;
|
||||
--color-neutral-l-600: 0.4;
|
||||
--color-neutral-l-700: 0.3;
|
||||
--color-neutral-l-800: 0.15;
|
||||
--color-neutral-l-900: 0.05;
|
||||
--color-neutral-l-1000: 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Configure Your Custom Theme
|
||||
|
||||
Set your custom theme in the configuration:
|
||||
|
||||
```php
|
||||
// site/config/config.php
|
||||
return [
|
||||
'moinframe.loop.theme' => 'custom',
|
||||
];
|
||||
```
|
||||
|
||||
## Theme Architecture
|
||||
|
||||
### Color System
|
||||
|
||||
The theming system uses OKLCH color space for consistent, perceptually uniform colors:
|
||||
|
||||
```css
|
||||
/* Accent colors */
|
||||
--color-accent-l: 0.7; /* Lightness (0-1) */
|
||||
--color-accent-c: 0.12; /* Chroma/saturation (0-0.4) */
|
||||
--color-accent-h: 220; /* Hue (0-360) */
|
||||
|
||||
/* Neutral colors */
|
||||
--color-neutral-l-0: 1; /* Lightest */
|
||||
--color-neutral-l-100: 0.95;
|
||||
--color-neutral-l-200: 0.9;
|
||||
/* ... */
|
||||
--color-neutral-l-900: 0.05;
|
||||
--color-neutral-l-1000: 0; /* Darkest */
|
||||
```
|
||||
|
||||
### Advanced Customization
|
||||
|
||||
You can override any design token in your custom theme:
|
||||
|
||||
```css
|
||||
kirby-loop[theme="custom"] {
|
||||
/* Colors */
|
||||
--color-accent-l: 0.65;
|
||||
--color-accent-c: 0.18;
|
||||
--color-accent-h: 15; /* Orange accent */
|
||||
|
||||
/* Shadows with custom opacity */
|
||||
--shadow-s: 0 0.1em 0.25em oklch(var(--color-neutral-l-900) var(--color-neutral-c) var(--color-neutral-h) / 0.15);
|
||||
|
||||
/* Custom border radius */
|
||||
--border-radius: 0.5rem;
|
||||
--border-radius-rounded: 1rem;
|
||||
|
||||
/* Custom fonts */
|
||||
--font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
}
|
||||
```
|
||||
325
site/plugins/loop/docs/05-api.md
Normal file
325
site/plugins/loop/docs/05-api.md
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
---
|
||||
title: API Reference
|
||||
---
|
||||
|
||||
Kirby Loop provides a RESTful API for managing comments and feedback. All endpoints include CSRF protection.
|
||||
|
||||
## Authentication
|
||||
|
||||
All API endpoints require authentication, controlled by the `moinframe.loop.public` configuration option:
|
||||
|
||||
- **Default (private)**: Only authenticated Kirby users can access the API
|
||||
- **Public mode**: Anyone can access the API
|
||||
|
||||
## CSRF Protection
|
||||
|
||||
All API requests must include a valid CSRF token in the request header:
|
||||
|
||||
```javascript
|
||||
fetch('/loop/comments/page-id', {
|
||||
headers: {
|
||||
'X-CSRF-Token': '<csrf-token>'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Base URL Structure
|
||||
|
||||
### Single Language Sites
|
||||
```
|
||||
/loop/comments/{pageId}
|
||||
/loop/comment/new
|
||||
/loop/comment/reply
|
||||
/loop/comment/resolve
|
||||
/loop/comment/unresolve
|
||||
/loop/guest/name
|
||||
```
|
||||
|
||||
### Multi-Language Sites
|
||||
```
|
||||
/{language}/loop/comments/{pageId}
|
||||
/{language}/loop/comment/new
|
||||
/{language}/loop/comment/reply
|
||||
/{language}/loop/comment/resolve
|
||||
/{language}/loop/comment/unresolve
|
||||
/{language}/loop/guest/name
|
||||
```
|
||||
|
||||
Where `{language}` is the language code (e.g., `en`, `de`).
|
||||
|
||||
## Endpoints
|
||||
|
||||
### GET /loop/comments/{pageId}
|
||||
|
||||
Retrieve all comments for a specific page.
|
||||
|
||||
**Parameters:**
|
||||
- `pageId` (string): The page ID or 'home' for the homepage
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"comments": [
|
||||
{
|
||||
"id": 1,
|
||||
"author": "John Doe",
|
||||
"url": "https://example.com/page",
|
||||
"page": "page-uuid",
|
||||
"comment": "This needs to be updated",
|
||||
"selector": ".header h1",
|
||||
"selectorOffsetX": 10,
|
||||
"selectorOffsetY": 20,
|
||||
"pagePositionX": 150,
|
||||
"pagePositionY": 300,
|
||||
"timestamp": 1640995200,
|
||||
"lang": "en",
|
||||
"status": "OPEN",
|
||||
"replies": [
|
||||
{
|
||||
"id": 1,
|
||||
"author": "jane.smith",
|
||||
"comment": "I'll fix this",
|
||||
"parentId": 1,
|
||||
"timestamp": 1640995800
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
- `400`: Page not found
|
||||
- `401`: Unauthorized (if authentication required)
|
||||
- `403`: CSRF token invalid
|
||||
|
||||
### POST /loop/comment/new
|
||||
|
||||
Create a new comment on a page.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"comment": "This section needs clarification",
|
||||
"url": "https://example.com/page",
|
||||
"selector": ".content p:nth-child(3)",
|
||||
"selectorOffsetX": 15,
|
||||
"selectorOffsetY": 25,
|
||||
"pagePositionX": 200,
|
||||
"pagePositionY": 450,
|
||||
"pageId": "projects/project-alpha"
|
||||
}
|
||||
```
|
||||
|
||||
**Required Fields:**
|
||||
- `comment` (string): The comment text (HTML stripped and sanitized)
|
||||
- `url` (string): The full URL where the comment was made
|
||||
- `selector` (string): CSS selector for the commented element
|
||||
- `selectorOffsetX` (number): X offset within the selected element
|
||||
- `selectorOffsetY` (number): Y offset within the selected element
|
||||
- `pagePositionX` (number): X position on the page
|
||||
- `pagePositionY` (number): Y position on the page
|
||||
- `pageId` (string): Kirby page ID or 'home'
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"comment": {
|
||||
"id": 15,
|
||||
"author": "John Doe",
|
||||
"url": "https://example.com/page",
|
||||
"page": "page-uuid",
|
||||
"comment": "This section needs clarification",
|
||||
"selector": ".content p:nth-child(3)",
|
||||
"selectorOffsetX": 15,
|
||||
"selectorOffsetY": 25,
|
||||
"pagePositionX": 200,
|
||||
"pagePositionY": 450,
|
||||
"timestamp": 1640995200,
|
||||
"lang": "en",
|
||||
"status": "OPEN",
|
||||
"replies": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
- `400`: Missing required fields, invalid selector format, or invalid data
|
||||
- `401`: Unauthorized
|
||||
- `403`: CSRF token invalid or disabled
|
||||
- `404`: Page not found
|
||||
|
||||
### POST /loop/comment/reply
|
||||
|
||||
Add a reply to an existing comment.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"comment": "I'll handle this update",
|
||||
"parentId": 15
|
||||
}
|
||||
```
|
||||
|
||||
**Required Fields:**
|
||||
- `comment` (string): The reply text (HTML stripped and sanitized)
|
||||
- `parentId` (number): ID of the parent comment
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"reply": {
|
||||
"id": 3,
|
||||
"author": "John Doe",
|
||||
"comment": "I'll handle this update",
|
||||
"parentId": 15,
|
||||
"timestamp": 1640995800
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
- `400`: Missing required fields
|
||||
- `401`: Unauthorized
|
||||
- `403`: CSRF token invalid or disabled
|
||||
|
||||
### POST /loop/comment/resolve
|
||||
|
||||
Mark a comment as resolved.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"id": 15
|
||||
}
|
||||
```
|
||||
|
||||
**Required Fields:**
|
||||
- `id` (number): The comment ID to resolve
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
- `400`: Missing comment ID
|
||||
- `401`: Unauthorized
|
||||
- `403`: CSRF token invalid or disabled
|
||||
|
||||
### POST /loop/comment/unresolve
|
||||
|
||||
Mark a resolved comment as unresolved.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"id": 15
|
||||
}
|
||||
```
|
||||
|
||||
**Required Fields:**
|
||||
- `id` (number): The comment ID to unresolve
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
- `400`: Missing comment ID
|
||||
- `401`: Unauthorized
|
||||
- `403`: CSRF token invalid or disabled
|
||||
|
||||
### POST /loop/guest/name
|
||||
|
||||
Set a guest name for non-authenticated users (when public mode is enabled).
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"name": "John Doe"
|
||||
}
|
||||
```
|
||||
|
||||
**Required Fields:**
|
||||
- `name` (string): The guest user's name
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"name": "John Doe"
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
- `400`: Missing or empty name
|
||||
- `401`: Unauthorized
|
||||
- `403`: CSRF token invalid or disabled
|
||||
|
||||
## Data Models
|
||||
|
||||
### Comment Object
|
||||
|
||||
```typescript
|
||||
interface Comment {
|
||||
id: number;
|
||||
author: string; // Resolved display name (user name, email prefix, or guest name)
|
||||
url: string; // Full URL where comment was made
|
||||
page: string; // Page UUID
|
||||
comment: string; // Sanitized comment text
|
||||
selector: string; // CSS selector for target element
|
||||
selectorOffsetX: number; // X offset within element (float)
|
||||
selectorOffsetY: number; // Y offset within element (float)
|
||||
pagePositionX: number; // X position on page (float)
|
||||
pagePositionY: number; // Y position on page (float)
|
||||
timestamp: number; // Unix timestamp
|
||||
lang: string; // Language code
|
||||
status: string; // Status: OPEN, RESOLVED
|
||||
replies: Reply[]; // Array of replies
|
||||
}
|
||||
```
|
||||
|
||||
### Reply Object
|
||||
|
||||
```typescript
|
||||
interface Reply {
|
||||
id: number;
|
||||
author: string; // Resolved display name (user name, email prefix, or guest name)
|
||||
comment: string; // Sanitized reply text
|
||||
parentId: number; // Parent comment ID
|
||||
timestamp: number; // Unix timestamp
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
The api endpoints return consistent error responses. For more details, switch on the debug mode in your Kirby Installation.
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "error",
|
||||
"message": "Human-readable error message",
|
||||
"code": "ERROR_CODE" // Optional error code
|
||||
}
|
||||
```
|
||||
|
||||
### Common Error Codes
|
||||
|
||||
- `CSRF_INVALID`: CSRF token is missing or invalid
|
||||
- `PAGE_NOT_FOUND`: Specified page doesn't exist
|
||||
- `FIELD_REQUIRED`: Required field is missing
|
||||
- `UNAUTHORIZED`: Authentication required but not provided
|
||||
- `INVALID_SELECTOR`: Invalid selector format
|
||||
- `INVALID_NAME`: Invalid guest name
|
||||
- `DISABLED`: Tool is disabled
|
||||
Loading…
Add table
Add a link
Reference in a new issue