docs: add README, boost skill, and documentation site
This commit is contained in:
15
.gitignore
vendored
15
.gitignore
vendored
@@ -1,5 +1,14 @@
|
|||||||
/vendor
|
.DS_Store
|
||||||
/node_modules
|
.idea
|
||||||
/.phpunit.cache
|
.vscode
|
||||||
|
.claude
|
||||||
|
.phpunit.cache
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
|
build
|
||||||
composer.lock
|
composer.lock
|
||||||
|
coverage
|
||||||
|
node_modules
|
||||||
|
phpunit.xml
|
||||||
|
phpstan.neon
|
||||||
|
testbench.yaml
|
||||||
|
vendor
|
||||||
|
|||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/comments.iml" filepath="$PROJECT_DIR$/.idea/comments.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
175
README.md
Normal file
175
README.md
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
# Comments
|
||||||
|
|
||||||
|
<img src="art/preview.png" alt="Comments System" width="800">
|
||||||
|
|
||||||
|
A full-featured commenting system for Filament panels with threaded replies, @mentions, emoji reactions, and real-time updates.
|
||||||
|
|
||||||
|
[](https://packagist.org/packages/relaticle/comments)
|
||||||
|
[](https://packagist.org/packages/relaticle/comments)
|
||||||
|
[](https://php.net)
|
||||||
|
[](https://laravel.com)
|
||||||
|
[](https://github.com/relaticle/comments/actions)
|
||||||
|
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Threaded Replies** - Nested comment threads with configurable depth limits
|
||||||
|
- **@Mentions** - Autocomplete user mentions with customizable resolver
|
||||||
|
- **Emoji Reactions** - 6 built-in reactions with configurable emoji sets
|
||||||
|
- **File Attachments** - Image and document uploads with validation
|
||||||
|
- **Notifications & Subscriptions** - Database and mail notifications with auto-subscribe
|
||||||
|
- **3 Filament Integrations** - Slide-over action, table action, and infolist entry
|
||||||
|
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- **PHP:** 8.2+
|
||||||
|
- **Laravel:** 12+
|
||||||
|
- **Livewire:** 3.5+ / 4.x
|
||||||
|
- **Filament:** 4.x / 5.x
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer require relaticle/comments
|
||||||
|
```
|
||||||
|
|
||||||
|
Publish and run migrations:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php artisan vendor:publish --tag=comments-migrations
|
||||||
|
php artisan migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Set Up Your Models
|
||||||
|
|
||||||
|
Add the commenting traits to your models:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\Concerns\HasComments;
|
||||||
|
use Relaticle\Comments\Contracts\Commentable;
|
||||||
|
|
||||||
|
class Project extends Model implements Commentable
|
||||||
|
{
|
||||||
|
use HasComments;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the commenter trait to your User model:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\Concerns\IsCommenter;
|
||||||
|
use Relaticle\Comments\Contracts\Commenter;
|
||||||
|
|
||||||
|
class User extends Authenticatable implements Commenter
|
||||||
|
{
|
||||||
|
use IsCommenter;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Register the Filament Plugin
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\CommentsPlugin;
|
||||||
|
|
||||||
|
public function panel(Panel $panel): Panel
|
||||||
|
{
|
||||||
|
return $panel
|
||||||
|
->plugins([
|
||||||
|
CommentsPlugin::make(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add Comments to Your Resources
|
||||||
|
|
||||||
|
Use the slide-over action on view/edit pages:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\Filament\Actions\CommentsAction;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
CommentsAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Or add as a table action:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\Filament\Actions\CommentsTableAction;
|
||||||
|
|
||||||
|
public static function table(Table $table): Table
|
||||||
|
{
|
||||||
|
return $table
|
||||||
|
->actions([
|
||||||
|
CommentsTableAction::make(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Or embed in an infolist:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\Filament\Infolists\Components\CommentsEntry;
|
||||||
|
|
||||||
|
public static function infolist(Infolist $infolist): Infolist
|
||||||
|
{
|
||||||
|
return $infolist->schema([
|
||||||
|
CommentsEntry::make('comments'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**[View Complete Documentation ->](https://relaticle.github.io/comments/)**
|
||||||
|
|
||||||
|
## Our Ecosystem
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top">
|
||||||
|
|
||||||
|
### FilaForms
|
||||||
|
[<img src="https://filaforms.app/img/og-image.png" width="100%" />](https://filaforms.app/)
|
||||||
|
|
||||||
|
Visual form builder for all your public-facing forms.
|
||||||
|
[Learn more ->](https://filaforms.app)
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top">
|
||||||
|
|
||||||
|
### Custom Fields
|
||||||
|
[<img src="https://github.com/Relaticle/custom-fields/raw/2.x/art/preview.png" width="100%" />](https://relaticle.github.io/custom-fields)
|
||||||
|
|
||||||
|
Let users add custom fields to any model without code changes.
|
||||||
|
[Learn more ->](https://relaticle.github.io/custom-fields)
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top">
|
||||||
|
|
||||||
|
### Flowforge
|
||||||
|
[<img src="https://github.com/Relaticle/flowforge/raw/4.x/art/preview.png" width="100%" />](https://relaticle.github.io/flowforge)
|
||||||
|
|
||||||
|
Transform any Laravel model into a drag-and-drop Kanban board.
|
||||||
|
[Learn more ->](https://relaticle.github.io/flowforge)
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT License. See [LICENSE](LICENSE) for details.
|
||||||
BIN
art/preview.png
Normal file
BIN
art/preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 283 KiB |
5
docs/.gitignore
vendored
Normal file
5
docs/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
node_modules
|
||||||
|
.output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
.env
|
||||||
64
docs/app.config.ts
Normal file
64
docs/app.config.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
export default defineAppConfig({
|
||||||
|
docus: {
|
||||||
|
title: 'Comments',
|
||||||
|
description: 'A full-featured commenting system for Filament panels with threaded replies, @mentions, emoji reactions, and real-time updates.',
|
||||||
|
header: {
|
||||||
|
logo: {
|
||||||
|
alt: 'Comments Logo',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
seo: {
|
||||||
|
title: 'Comments',
|
||||||
|
description: 'A full-featured commenting system for Filament panels with threaded replies, @mentions, emoji reactions, and real-time updates.',
|
||||||
|
},
|
||||||
|
github: {
|
||||||
|
repo: 'comments',
|
||||||
|
owner: 'Relaticle',
|
||||||
|
edit: true,
|
||||||
|
rootDir: 'docs'
|
||||||
|
},
|
||||||
|
socials: {
|
||||||
|
discord: 'https://discord.gg/b9WxzUce4Q'
|
||||||
|
},
|
||||||
|
ui: {
|
||||||
|
colors: {
|
||||||
|
primary: 'violet',
|
||||||
|
neutral: 'zinc'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
uiPro: {
|
||||||
|
pageHero: {
|
||||||
|
slots: {
|
||||||
|
container: 'flex flex-col lg:grid py-16 sm:py-20 lg:py-24 gap-16 sm:gap-y-2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toc: {
|
||||||
|
title: 'On this page',
|
||||||
|
bottom: {
|
||||||
|
title: 'Ecosystem',
|
||||||
|
edit: 'https://github.com/Relaticle/comments',
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
icon: 'i-simple-icons-laravel',
|
||||||
|
label: 'FilaForms',
|
||||||
|
to: 'https://filaforms.app',
|
||||||
|
target: '_blank'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-sliders',
|
||||||
|
label: 'Custom Fields',
|
||||||
|
to: 'https://relaticle.github.io/custom-fields',
|
||||||
|
target: '_blank'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'i-lucide-kanban',
|
||||||
|
label: 'Flowforge',
|
||||||
|
to: 'https://relaticle.github.io/flowforge',
|
||||||
|
target: '_blank'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
2
docs/content/1.getting-started/.navigation.yml
Normal file
2
docs/content/1.getting-started/.navigation.yml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
title: Getting Started
|
||||||
|
icon: false
|
||||||
52
docs/content/1.getting-started/1.introduction.md
Normal file
52
docs/content/1.getting-started/1.introduction.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
title: Introduction
|
||||||
|
description: A full-featured commenting system for Filament panels.
|
||||||
|
navigation:
|
||||||
|
icon: i-lucide-home
|
||||||
|
seo:
|
||||||
|
title: Introduction
|
||||||
|
description: Learn about Comments - a full-featured commenting system for Filament panels with threaded replies, @mentions, emoji reactions, and real-time updates.
|
||||||
|
ogImage: /preview.png
|
||||||
|
---
|
||||||
|
|
||||||
|
Welcome to **Comments**, a powerful Laravel package that adds a full-featured commenting system to any Filament panel.
|
||||||
|
|
||||||
|
## What is Comments?
|
||||||
|
|
||||||
|
Comments provides polymorphic commenting on any Eloquent model with deep Filament integration. Add threaded discussions, @mentions, emoji reactions, file attachments, and real-time notifications to your admin panel with minimal setup.
|
||||||
|
|
||||||
|
## Why Choose Comments?
|
||||||
|
|
||||||
|
::card-group
|
||||||
|
:::card
|
||||||
|
---
|
||||||
|
icon: i-lucide-messages-square
|
||||||
|
title: Threaded Discussions
|
||||||
|
---
|
||||||
|
Nested replies with configurable depth limits keep conversations organized and easy to follow.
|
||||||
|
:::
|
||||||
|
|
||||||
|
:::card
|
||||||
|
---
|
||||||
|
icon: i-lucide-clock
|
||||||
|
title: Quick Setup
|
||||||
|
---
|
||||||
|
Add traits to your models, register the plugin, and you have a working comment system in minutes.
|
||||||
|
:::
|
||||||
|
|
||||||
|
:::card
|
||||||
|
---
|
||||||
|
icon: i-lucide-puzzle
|
||||||
|
title: 3 Integration Patterns
|
||||||
|
---
|
||||||
|
Use as a slide-over action, table row action, or inline infolist entry - whatever fits your resource.
|
||||||
|
:::
|
||||||
|
|
||||||
|
:::card
|
||||||
|
---
|
||||||
|
icon: i-lucide-bell
|
||||||
|
title: Built-in Notifications
|
||||||
|
---
|
||||||
|
Database and mail notifications with subscription management and auto-subscribe for authors and mentioned users.
|
||||||
|
:::
|
||||||
|
::
|
||||||
112
docs/content/1.getting-started/2.installation.md
Normal file
112
docs/content/1.getting-started/2.installation.md
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
---
|
||||||
|
title: Installation
|
||||||
|
description: Get started with Comments in minutes.
|
||||||
|
navigation:
|
||||||
|
icon: i-lucide-download
|
||||||
|
seo:
|
||||||
|
description: Install Comments and add commenting to your Filament resources.
|
||||||
|
ogImage: /preview.png
|
||||||
|
---
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- **PHP:** 8.2+
|
||||||
|
- **Laravel:** 12+
|
||||||
|
- **Filament:** 4.x / 5.x
|
||||||
|
- **Livewire:** 3.5+ / 4.x
|
||||||
|
|
||||||
|
## Quick Setup
|
||||||
|
|
||||||
|
::steps
|
||||||
|
### Install Package
|
||||||
|
|
||||||
|
```bash [Terminal]
|
||||||
|
composer require relaticle/comments
|
||||||
|
```
|
||||||
|
|
||||||
|
### Publish and Run Migrations
|
||||||
|
|
||||||
|
```bash [Terminal]
|
||||||
|
php artisan vendor:publish --tag=comments-migrations
|
||||||
|
php artisan migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
### Include CSS Assets
|
||||||
|
|
||||||
|
Prerequisite: You need a custom Filament theme to include the Comments styles.
|
||||||
|
|
||||||
|
::alert{type="warning"}
|
||||||
|
If you haven't set up a custom theme for Filament, follow the [Filament Docs](https://filamentphp.com/docs/5.x/styling/overview#creating-a-custom-theme) first.
|
||||||
|
::
|
||||||
|
|
||||||
|
Add the plugin's views to your theme CSS file:
|
||||||
|
|
||||||
|
```css [resources/css/filament/admin/theme.css]
|
||||||
|
@source "../../../../vendor/relaticle/comments/resources/views/**/*.blade.php";
|
||||||
|
```
|
||||||
|
|
||||||
|
### Register the Plugin
|
||||||
|
|
||||||
|
```php [AdminPanelProvider.php]
|
||||||
|
use Relaticle\Comments\CommentsPlugin;
|
||||||
|
|
||||||
|
public function panel(Panel $panel): Panel
|
||||||
|
{
|
||||||
|
return $panel
|
||||||
|
->plugins([
|
||||||
|
CommentsPlugin::make(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Set Up Your Models
|
||||||
|
|
||||||
|
Add the `HasComments` trait to any model you want to comment on:
|
||||||
|
|
||||||
|
```php [app/Models/Project.php]
|
||||||
|
use Relaticle\Comments\Concerns\HasComments;
|
||||||
|
use Relaticle\Comments\Contracts\Commentable;
|
||||||
|
|
||||||
|
class Project extends Model implements Commentable
|
||||||
|
{
|
||||||
|
use HasComments;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the `IsCommenter` trait to your User model:
|
||||||
|
|
||||||
|
```php [app/Models/User.php]
|
||||||
|
use Relaticle\Comments\Concerns\IsCommenter;
|
||||||
|
use Relaticle\Comments\Contracts\Commenter;
|
||||||
|
|
||||||
|
class User extends Authenticatable implements Commenter
|
||||||
|
{
|
||||||
|
use IsCommenter;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add to Your Resources
|
||||||
|
|
||||||
|
Use the slide-over action on view or edit pages:
|
||||||
|
|
||||||
|
```php [app/Filament/Resources/ProjectResource/Pages/ViewProject.php]
|
||||||
|
use Relaticle\Comments\Filament\Actions\CommentsAction;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
CommentsAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
::
|
||||||
|
|
||||||
|
**Done!** Visit your Filament panel to see comments in action.
|
||||||
|
|
||||||
|
## Optional Configuration
|
||||||
|
|
||||||
|
| Command | Action |
|
||||||
|
|---------|--------|
|
||||||
|
| `php artisan vendor:publish --tag=comments-config` | Publish the configuration file |
|
||||||
|
| `php artisan vendor:publish --tag=comments-views` | Publish the Blade views for customization |
|
||||||
|
| `php artisan vendor:publish --tag=comments-translations` | Publish the translation files |
|
||||||
12
docs/content/1.getting-started/3.upgrading.md
Normal file
12
docs/content/1.getting-started/3.upgrading.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
title: Upgrading
|
||||||
|
description: Upgrade guide for Comments.
|
||||||
|
navigation:
|
||||||
|
icon: i-lucide-arrow-up-circle
|
||||||
|
seo:
|
||||||
|
description: How to upgrade Comments between versions.
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1.x
|
||||||
|
|
||||||
|
This is the initial release of Comments. Future upgrade guides will be documented here as new versions are released.
|
||||||
1
docs/content/2.essentials/.navigation.yml
Normal file
1
docs/content/2.essentials/.navigation.yml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
title: Essentials
|
||||||
189
docs/content/2.essentials/1.configuration.md
Normal file
189
docs/content/2.essentials/1.configuration.md
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
---
|
||||||
|
title: Configuration
|
||||||
|
description: Configure threading, reactions, mentions, attachments, notifications, and more.
|
||||||
|
navigation:
|
||||||
|
icon: i-lucide-settings
|
||||||
|
seo:
|
||||||
|
description: Complete configuration reference for the Comments package.
|
||||||
|
---
|
||||||
|
|
||||||
|
Publish the configuration file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php artisan vendor:publish --tag=comments-config
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates `config/comments.php` with all available options.
|
||||||
|
|
||||||
|
## Table Name
|
||||||
|
|
||||||
|
```php
|
||||||
|
'tables' => [
|
||||||
|
'comments' => 'comments',
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
Change the table name if it conflicts with your application.
|
||||||
|
|
||||||
|
## Models
|
||||||
|
|
||||||
|
```php
|
||||||
|
'models' => [
|
||||||
|
'comment' => \Relaticle\Comments\Comment::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
'commenter' => [
|
||||||
|
'model' => \App\Models\User::class,
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
Override the Comment model to add custom behavior. The commenter model defines which class represents the user who comments.
|
||||||
|
|
||||||
|
## Policy
|
||||||
|
|
||||||
|
```php
|
||||||
|
'policy' => \Relaticle\Comments\Policies\CommentPolicy::class,
|
||||||
|
```
|
||||||
|
|
||||||
|
See the [Authorization](/essentials/authorization) page for customization details.
|
||||||
|
|
||||||
|
## Threading
|
||||||
|
|
||||||
|
```php
|
||||||
|
'threading' => [
|
||||||
|
'max_depth' => 2,
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
Controls how many levels of nested replies are allowed. A depth of `2` means top-level comments and one level of replies. Set to `1` to disable replies entirely.
|
||||||
|
|
||||||
|
## Pagination
|
||||||
|
|
||||||
|
```php
|
||||||
|
'pagination' => [
|
||||||
|
'per_page' => 10,
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
Number of comments loaded initially and per "Load More" click.
|
||||||
|
|
||||||
|
## Reactions
|
||||||
|
|
||||||
|
```php
|
||||||
|
'reactions' => [
|
||||||
|
'emoji_set' => [
|
||||||
|
'thumbs_up' => "\u{1F44D}",
|
||||||
|
'heart' => "\u{2764}\u{FE0F}",
|
||||||
|
'celebrate' => "\u{1F389}",
|
||||||
|
'laugh' => "\u{1F604}",
|
||||||
|
'thinking' => "\u{1F914}",
|
||||||
|
'sad' => "\u{1F622}",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
Customize the available emoji reactions. Keys are used as identifiers in the database, values are the displayed emoji characters.
|
||||||
|
|
||||||
|
## Mentions
|
||||||
|
|
||||||
|
```php
|
||||||
|
'mentions' => [
|
||||||
|
'resolver' => \Relaticle\Comments\Mentions\DefaultMentionResolver::class,
|
||||||
|
'max_results' => 5,
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
The resolver handles searching for users during @mention autocomplete. See the [Mentions](/essentials/mentions) page for creating a custom resolver.
|
||||||
|
|
||||||
|
## Editor Toolbar
|
||||||
|
|
||||||
|
```php
|
||||||
|
'editor' => [
|
||||||
|
'toolbar' => [
|
||||||
|
['bold', 'italic', 'strike', 'link'],
|
||||||
|
['bulletList', 'orderedList'],
|
||||||
|
['codeBlock'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
Defines which formatting buttons appear in the comment editor. Groups create visual separators in the toolbar.
|
||||||
|
|
||||||
|
## Notifications
|
||||||
|
|
||||||
|
```php
|
||||||
|
'notifications' => [
|
||||||
|
'channels' => ['database'],
|
||||||
|
'enabled' => true,
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
Add `'mail'` to the channels array to send email notifications. Set `enabled` to `false` to disable all notifications.
|
||||||
|
|
||||||
|
## Subscriptions
|
||||||
|
|
||||||
|
```php
|
||||||
|
'subscriptions' => [
|
||||||
|
'auto_subscribe' => true,
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
When enabled, users are automatically subscribed to a thread when they create a comment or are mentioned. They receive notifications for subsequent replies.
|
||||||
|
|
||||||
|
## Attachments
|
||||||
|
|
||||||
|
```php
|
||||||
|
'attachments' => [
|
||||||
|
'enabled' => true,
|
||||||
|
'disk' => 'public',
|
||||||
|
'max_size' => 10240, // KB
|
||||||
|
'allowed_types' => [
|
||||||
|
'image/jpeg',
|
||||||
|
'image/png',
|
||||||
|
'image/gif',
|
||||||
|
'image/webp',
|
||||||
|
'application/pdf',
|
||||||
|
'text/plain',
|
||||||
|
'application/msword',
|
||||||
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
Controls file upload behavior. Set `enabled` to `false` to remove the attachment UI entirely. The `max_size` is in kilobytes (default 10 MB).
|
||||||
|
|
||||||
|
## Broadcasting
|
||||||
|
|
||||||
|
```php
|
||||||
|
'broadcasting' => [
|
||||||
|
'enabled' => false,
|
||||||
|
'channel_prefix' => 'comments',
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
When enabled, comment events are broadcast on private channels using the format `{prefix}.{commentable_type}.{commentable_id}`. Requires Laravel Echo and a broadcasting driver.
|
||||||
|
|
||||||
|
## Polling
|
||||||
|
|
||||||
|
```php
|
||||||
|
'polling' => [
|
||||||
|
'interval' => '10s',
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
When broadcasting is disabled, the Livewire component polls for new comments at this interval. Set to `null` to disable polling.
|
||||||
|
|
||||||
|
## Custom User Resolution
|
||||||
|
|
||||||
|
Override how the authenticated user is resolved:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\Config;
|
||||||
|
|
||||||
|
// In AppServiceProvider::boot()
|
||||||
|
Config::resolveAuthenticatedUserUsing(function () {
|
||||||
|
return auth()->user();
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
This is useful for multi-guard applications or custom authentication flows.
|
||||||
74
docs/content/2.essentials/2.authorization.md
Normal file
74
docs/content/2.essentials/2.authorization.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
title: Authorization
|
||||||
|
description: Control who can create, edit, delete, and reply to comments.
|
||||||
|
navigation:
|
||||||
|
icon: i-lucide-shield
|
||||||
|
seo:
|
||||||
|
description: Configure comment authorization policies.
|
||||||
|
---
|
||||||
|
|
||||||
|
## Default Policy
|
||||||
|
|
||||||
|
The built-in `CommentPolicy` provides sensible defaults:
|
||||||
|
|
||||||
|
| Method | Default | Description |
|
||||||
|
|--------|---------|-------------|
|
||||||
|
| `viewAny()` | `true` | Everyone can view comments |
|
||||||
|
| `create()` | `true` | Everyone can create comments |
|
||||||
|
| `update()` | Owner only | Only the comment author can edit |
|
||||||
|
| `delete()` | Owner only | Only the comment author can delete |
|
||||||
|
| `reply()` | Depth check | Can reply if `max_depth` not exceeded |
|
||||||
|
|
||||||
|
## Custom Policy
|
||||||
|
|
||||||
|
Create your own policy to customize authorization:
|
||||||
|
|
||||||
|
```php
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use Relaticle\Comments\Comment;
|
||||||
|
use Relaticle\Comments\Contracts\Commenter;
|
||||||
|
|
||||||
|
class CustomCommentPolicy
|
||||||
|
{
|
||||||
|
public function viewAny(Commenter $user): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(Commenter $user): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Commenter $user, Comment $comment): bool
|
||||||
|
{
|
||||||
|
return $comment->user_id === $user->getKey()
|
||||||
|
&& $comment->user_type === $user->getMorphClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(Commenter $user, Comment $comment): bool
|
||||||
|
{
|
||||||
|
return $comment->user_id === $user->getKey()
|
||||||
|
|| $user->hasRole('admin');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reply(Commenter $user, Comment $comment): bool
|
||||||
|
{
|
||||||
|
return $comment->canReply();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Register it in your config:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// config/comments.php
|
||||||
|
'policy' => App\Policies\CustomCommentPolicy::class,
|
||||||
|
```
|
||||||
|
|
||||||
|
## How Authorization Works
|
||||||
|
|
||||||
|
The Livewire components check the policy before rendering action buttons. Edit and delete buttons only appear for authorized users. Reply buttons are hidden when the thread has reached the configured `max_depth`.
|
||||||
|
|
||||||
|
The policy is registered automatically by the service provider using Laravel's Gate system.
|
||||||
74
docs/content/2.essentials/3.mentions.md
Normal file
74
docs/content/2.essentials/3.mentions.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
title: Mentions
|
||||||
|
description: User @mentions with autocomplete and notification support.
|
||||||
|
navigation:
|
||||||
|
icon: i-lucide-at-sign
|
||||||
|
seo:
|
||||||
|
description: Configure @mention autocomplete and create custom mention resolvers.
|
||||||
|
---
|
||||||
|
|
||||||
|
## How Mentions Work
|
||||||
|
|
||||||
|
Type `@` in the comment editor to trigger user autocomplete. Select a user to insert a mention. When the comment is saved, the `MentionParser` extracts mentions and:
|
||||||
|
|
||||||
|
1. Syncs mention records in the `comment_mentions` table
|
||||||
|
2. Dispatches a `UserMentioned` event for each newly mentioned user
|
||||||
|
3. The `SendUserMentionedNotification` listener sends notifications
|
||||||
|
4. If auto-subscribe is enabled, mentioned users are subscribed to the thread
|
||||||
|
|
||||||
|
## Default Resolver
|
||||||
|
|
||||||
|
The `DefaultMentionResolver` searches the commenter model by name:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// Searches: User::where('name', 'like', "{$query}%")
|
||||||
|
// Limited to: config('comments.mentions.max_results') results
|
||||||
|
```
|
||||||
|
|
||||||
|
## Custom Mention Resolver
|
||||||
|
|
||||||
|
Implement the `MentionResolver` interface to customize user search behavior:
|
||||||
|
|
||||||
|
```php
|
||||||
|
namespace App\Comments;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Relaticle\Comments\Contracts\MentionResolver;
|
||||||
|
|
||||||
|
class TeamMentionResolver implements MentionResolver
|
||||||
|
{
|
||||||
|
public function search(string $query): Collection
|
||||||
|
{
|
||||||
|
return User::query()
|
||||||
|
->where('team_id', auth()->user()->team_id)
|
||||||
|
->where('name', 'like', "{$query}%")
|
||||||
|
->limit(config('comments.mentions.max_results'))
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resolveByNames(array $names): Collection
|
||||||
|
{
|
||||||
|
return User::query()
|
||||||
|
->where('team_id', auth()->user()->team_id)
|
||||||
|
->whereIn('name', $names)
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Register it in your config:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// config/comments.php
|
||||||
|
'mentions' => [
|
||||||
|
'resolver' => App\Comments\TeamMentionResolver::class,
|
||||||
|
'max_results' => 5,
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
| Key | Default | Description |
|
||||||
|
|-----|---------|-------------|
|
||||||
|
| `mentions.resolver` | `DefaultMentionResolver::class` | User search implementation |
|
||||||
|
| `mentions.max_results` | `5` | Maximum autocomplete results |
|
||||||
51
docs/content/2.essentials/4.reactions.md
Normal file
51
docs/content/2.essentials/4.reactions.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
title: Reactions
|
||||||
|
description: Emoji reactions on comments.
|
||||||
|
navigation:
|
||||||
|
icon: i-lucide-smile
|
||||||
|
seo:
|
||||||
|
description: Configure emoji reactions for comments.
|
||||||
|
---
|
||||||
|
|
||||||
|
## Default Reactions
|
||||||
|
|
||||||
|
Six emoji reactions are available out of the box:
|
||||||
|
|
||||||
|
| Key | Emoji | Label |
|
||||||
|
|-----|-------|-------|
|
||||||
|
| `thumbs_up` | :thumbsup: | Like |
|
||||||
|
| `heart` | :heart: | Love |
|
||||||
|
| `celebrate` | :tada: | Celebrate |
|
||||||
|
| `laugh` | :smile: | Laugh |
|
||||||
|
| `thinking` | :thinking: | Thinking |
|
||||||
|
| `sad` | :cry: | Sad |
|
||||||
|
|
||||||
|
## How Reactions Work
|
||||||
|
|
||||||
|
- Each user can add one reaction of each type per comment
|
||||||
|
- Clicking the same reaction again removes it (toggle behavior)
|
||||||
|
- The reaction summary shows which users reacted with each emoji
|
||||||
|
- A `CommentReacted` event is dispatched with `action: 'added'` or `'removed'`
|
||||||
|
|
||||||
|
## Customizing Reactions
|
||||||
|
|
||||||
|
Override the emoji set in your config:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// config/comments.php
|
||||||
|
'reactions' => [
|
||||||
|
'emoji_set' => [
|
||||||
|
'thumbs_up' => "\u{1F44D}",
|
||||||
|
'thumbs_down' => "\u{1F44E}",
|
||||||
|
'heart' => "\u{2764}\u{FE0F}",
|
||||||
|
'fire' => "\u{1F525}",
|
||||||
|
'eyes' => "\u{1F440}",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
Keys are stored in the database. If you change a key, existing reactions with the old key will no longer display.
|
||||||
|
|
||||||
|
## Storage
|
||||||
|
|
||||||
|
Reactions are stored in the `comment_reactions` table with a unique constraint on `(comment_id, user_id, user_type, reaction)`, ensuring one reaction of each type per user per comment.
|
||||||
72
docs/content/2.essentials/5.attachments.md
Normal file
72
docs/content/2.essentials/5.attachments.md
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
---
|
||||||
|
title: Attachments
|
||||||
|
description: File uploads for comments.
|
||||||
|
navigation:
|
||||||
|
icon: i-lucide-paperclip
|
||||||
|
seo:
|
||||||
|
description: Configure file attachments for comments.
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Comments support file attachments for both images and documents. Images are displayed inline within the comment body, while documents appear as downloadable links.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
```php
|
||||||
|
// config/comments.php
|
||||||
|
'attachments' => [
|
||||||
|
'enabled' => true,
|
||||||
|
'disk' => 'public',
|
||||||
|
'max_size' => 10240, // KB (10 MB)
|
||||||
|
'allowed_types' => [
|
||||||
|
'image/jpeg',
|
||||||
|
'image/png',
|
||||||
|
'image/gif',
|
||||||
|
'image/webp',
|
||||||
|
'application/pdf',
|
||||||
|
'text/plain',
|
||||||
|
'application/msword',
|
||||||
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
| Key | Default | Description |
|
||||||
|
|-----|---------|-------------|
|
||||||
|
| `enabled` | `true` | Show/hide the attachment upload UI |
|
||||||
|
| `disk` | `'public'` | Laravel filesystem disk for storage |
|
||||||
|
| `max_size` | `10240` | Maximum file size in kilobytes |
|
||||||
|
| `allowed_types` | images, pdf, text, word | Array of allowed MIME types |
|
||||||
|
|
||||||
|
## Disabling Attachments
|
||||||
|
|
||||||
|
```php
|
||||||
|
'attachments' => [
|
||||||
|
'enabled' => false,
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
This removes the file upload UI from the comment form entirely.
|
||||||
|
|
||||||
|
## Storage
|
||||||
|
|
||||||
|
Attachments are stored via Livewire's file upload mechanism. Each attachment record tracks:
|
||||||
|
|
||||||
|
- `file_path` -- Path on the configured disk
|
||||||
|
- `original_name` -- Original filename for display
|
||||||
|
- `mime_type` -- MIME type for rendering decisions
|
||||||
|
- `size` -- File size in bytes
|
||||||
|
- `disk` -- Storage disk name
|
||||||
|
|
||||||
|
When a comment is deleted, its attachments are cascade deleted from the database. The physical files are removed from the disk.
|
||||||
|
|
||||||
|
## Helper Methods
|
||||||
|
|
||||||
|
The `CommentAttachment` model provides:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$attachment->isImage(); // Check if attachment is an image
|
||||||
|
$attachment->url(); // Get the storage URL
|
||||||
|
$attachment->formattedSize(); // Human-readable size (e.g., "2.5 MB")
|
||||||
|
```
|
||||||
125
docs/content/2.essentials/6.notifications.md
Normal file
125
docs/content/2.essentials/6.notifications.md
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
---
|
||||||
|
title: Notifications
|
||||||
|
description: Comment notifications, subscriptions, and real-time updates.
|
||||||
|
navigation:
|
||||||
|
icon: i-lucide-bell
|
||||||
|
seo:
|
||||||
|
description: Configure comment notifications, subscriptions, broadcasting, and polling.
|
||||||
|
---
|
||||||
|
|
||||||
|
## Notification Types
|
||||||
|
|
||||||
|
Two notification classes are included:
|
||||||
|
|
||||||
|
### CommentRepliedNotification
|
||||||
|
|
||||||
|
Sent to all thread subscribers when a new comment or reply is posted. The comment author is excluded from receiving their own notification.
|
||||||
|
|
||||||
|
### UserMentionedNotification
|
||||||
|
|
||||||
|
Sent to a user when they are @mentioned in a comment. Self-mentions are ignored.
|
||||||
|
|
||||||
|
## Channels
|
||||||
|
|
||||||
|
```php
|
||||||
|
// config/comments.php
|
||||||
|
'notifications' => [
|
||||||
|
'channels' => ['database'],
|
||||||
|
'enabled' => true,
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
Available channels: `'database'` and `'mail'`. Add both to send email notifications alongside database notifications:
|
||||||
|
|
||||||
|
```php
|
||||||
|
'notifications' => [
|
||||||
|
'channels' => ['database', 'mail'],
|
||||||
|
'enabled' => true,
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
## Subscriptions
|
||||||
|
|
||||||
|
Users can subscribe to comment threads on any commentable model. Subscribers receive notifications when new comments are posted.
|
||||||
|
|
||||||
|
### Auto-Subscribe
|
||||||
|
|
||||||
|
```php
|
||||||
|
'subscriptions' => [
|
||||||
|
'auto_subscribe' => true,
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
When enabled:
|
||||||
|
- Users are auto-subscribed when they post a comment
|
||||||
|
- Users are auto-subscribed when they are @mentioned
|
||||||
|
|
||||||
|
### Manual Subscription
|
||||||
|
|
||||||
|
Users can toggle their subscription using the subscribe/unsubscribe button in the comments UI.
|
||||||
|
|
||||||
|
### Programmatic Access
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\CommentSubscription;
|
||||||
|
|
||||||
|
// Check subscription status
|
||||||
|
CommentSubscription::isSubscribed($commentable, $user);
|
||||||
|
|
||||||
|
// Subscribe/unsubscribe
|
||||||
|
CommentSubscription::subscribe($commentable, $user);
|
||||||
|
CommentSubscription::unsubscribe($commentable, $user);
|
||||||
|
|
||||||
|
// Get all subscribers for a commentable
|
||||||
|
$subscribers = CommentSubscription::subscribersFor($commentable);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Events
|
||||||
|
|
||||||
|
| Event | Trigger | Broadcasts |
|
||||||
|
|-------|---------|------------|
|
||||||
|
| `CommentCreated` | New comment or reply | Yes |
|
||||||
|
| `CommentUpdated` | Comment edited | Yes |
|
||||||
|
| `CommentDeleted` | Comment soft-deleted | Yes |
|
||||||
|
| `CommentReacted` | Reaction added/removed | Yes |
|
||||||
|
| `UserMentioned` | User @mentioned | No |
|
||||||
|
|
||||||
|
## Real-time Updates
|
||||||
|
|
||||||
|
### Broadcasting
|
||||||
|
|
||||||
|
Enable broadcasting for instant updates across browser sessions:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// config/comments.php
|
||||||
|
'broadcasting' => [
|
||||||
|
'enabled' => true,
|
||||||
|
'channel_prefix' => 'comments',
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
Events are broadcast on private channels: `{prefix}.{commentable_type}.{commentable_id}`
|
||||||
|
|
||||||
|
This requires Laravel Echo and a broadcasting driver (Pusher, Ably, etc.) configured in your application.
|
||||||
|
|
||||||
|
### Polling Fallback
|
||||||
|
|
||||||
|
When broadcasting is disabled, the Livewire component polls for updates:
|
||||||
|
|
||||||
|
```php
|
||||||
|
'polling' => [
|
||||||
|
'interval' => '10s',
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
Set to `null` to disable polling entirely.
|
||||||
|
|
||||||
|
## Disabling Notifications
|
||||||
|
|
||||||
|
```php
|
||||||
|
'notifications' => [
|
||||||
|
'enabled' => false,
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
This disables all notification dispatching. Subscriptions and events still work, but no notifications are sent.
|
||||||
107
docs/content/2.essentials/7.database-schema.md
Normal file
107
docs/content/2.essentials/7.database-schema.md
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
---
|
||||||
|
title: Database Schema
|
||||||
|
description: Tables, relationships, and indexes used by the Comments package.
|
||||||
|
navigation:
|
||||||
|
icon: i-lucide-database
|
||||||
|
seo:
|
||||||
|
description: Database schema reference for the Comments package.
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tables
|
||||||
|
|
||||||
|
Five tables are created by the package migrations.
|
||||||
|
|
||||||
|
### comments
|
||||||
|
|
||||||
|
The main comments table with polymorphic relationships and threading support.
|
||||||
|
|
||||||
|
| Column | Type | Description |
|
||||||
|
|--------|------|-------------|
|
||||||
|
| `id` | bigint | Primary key |
|
||||||
|
| `commentable_type` | string | Polymorphic model type |
|
||||||
|
| `commentable_id` | bigint | Polymorphic model ID |
|
||||||
|
| `user_type` | string | Commenter model type |
|
||||||
|
| `user_id` | bigint | Commenter model ID |
|
||||||
|
| `parent_id` | bigint (nullable) | Parent comment for replies |
|
||||||
|
| `body` | text | HTML comment content |
|
||||||
|
| `edited_at` | timestamp (nullable) | When the comment was last edited |
|
||||||
|
| `deleted_at` | timestamp (nullable) | Soft delete timestamp |
|
||||||
|
| `created_at` | timestamp | |
|
||||||
|
| `updated_at` | timestamp | |
|
||||||
|
|
||||||
|
**Indexes:** `(commentable_type, commentable_id, parent_id)`
|
||||||
|
|
||||||
|
### comment_reactions
|
||||||
|
|
||||||
|
Tracks emoji reactions per user per comment.
|
||||||
|
|
||||||
|
| Column | Type | Description |
|
||||||
|
|--------|------|-------------|
|
||||||
|
| `id` | bigint | Primary key |
|
||||||
|
| `comment_id` | bigint | Foreign key to comments |
|
||||||
|
| `user_type` | string | Reactor model type |
|
||||||
|
| `user_id` | bigint | Reactor model ID |
|
||||||
|
| `reaction` | string | Reaction key (e.g., `thumbs_up`) |
|
||||||
|
| `created_at` | timestamp | |
|
||||||
|
|
||||||
|
**Unique constraint:** `(comment_id, user_id, user_type, reaction)`
|
||||||
|
|
||||||
|
### comment_mentions
|
||||||
|
|
||||||
|
Tracks @mentioned users per comment.
|
||||||
|
|
||||||
|
| Column | Type | Description |
|
||||||
|
|--------|------|-------------|
|
||||||
|
| `id` | bigint | Primary key |
|
||||||
|
| `comment_id` | bigint | Foreign key to comments |
|
||||||
|
| `user_type` | string | Mentioned user model type |
|
||||||
|
| `user_id` | bigint | Mentioned user model ID |
|
||||||
|
| `created_at` | timestamp | |
|
||||||
|
|
||||||
|
**Unique constraint:** `(comment_id, user_id, user_type)`
|
||||||
|
|
||||||
|
### comment_subscriptions
|
||||||
|
|
||||||
|
Tracks which users are subscribed to comment threads on specific models.
|
||||||
|
|
||||||
|
| Column | Type | Description |
|
||||||
|
|--------|------|-------------|
|
||||||
|
| `id` | bigint | Primary key |
|
||||||
|
| `commentable_type` | string | Subscribed model type |
|
||||||
|
| `commentable_id` | bigint | Subscribed model ID |
|
||||||
|
| `user_type` | string | Subscriber model type |
|
||||||
|
| `user_id` | bigint | Subscriber model ID |
|
||||||
|
| `created_at` | timestamp | |
|
||||||
|
|
||||||
|
**Unique constraint:** `(commentable_type, commentable_id, user_type, user_id)`
|
||||||
|
|
||||||
|
### comment_attachments
|
||||||
|
|
||||||
|
Stores file attachment metadata for comments.
|
||||||
|
|
||||||
|
| Column | Type | Description |
|
||||||
|
|--------|------|-------------|
|
||||||
|
| `id` | bigint | Primary key |
|
||||||
|
| `comment_id` | bigint | Foreign key to comments |
|
||||||
|
| `file_path` | string | Path on the storage disk |
|
||||||
|
| `original_name` | string | Original uploaded filename |
|
||||||
|
| `mime_type` | string | File MIME type |
|
||||||
|
| `size` | bigint | File size in bytes |
|
||||||
|
| `disk` | string | Laravel filesystem disk |
|
||||||
|
| `created_at` | timestamp | |
|
||||||
|
| `updated_at` | timestamp | |
|
||||||
|
|
||||||
|
## Relationships
|
||||||
|
|
||||||
|
```
|
||||||
|
Commentable Model (e.g., Project)
|
||||||
|
└── comments (morphMany)
|
||||||
|
├── user (morphTo → User)
|
||||||
|
├── parent (belongsTo → Comment)
|
||||||
|
├── replies (hasMany → Comment)
|
||||||
|
├── reactions (hasMany → CommentReaction)
|
||||||
|
├── attachments (hasMany → CommentAttachment)
|
||||||
|
└── mentions (morphToMany → User)
|
||||||
|
```
|
||||||
|
|
||||||
|
All relationships are polymorphic, allowing the same comment system to work across any number of models in your application.
|
||||||
1
docs/content/4.community/.navigation.yml
Normal file
1
docs/content/4.community/.navigation.yml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
title: Community
|
||||||
39
docs/content/4.community/1.contributing.md
Normal file
39
docs/content/4.community/1.contributing.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
title: Contributing
|
||||||
|
description: How to contribute to Comments
|
||||||
|
navigation:
|
||||||
|
icon: i-lucide-heart-handshake
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
1. **Fork** the repository
|
||||||
|
2. **Create** a feature branch
|
||||||
|
3. **Make** your changes
|
||||||
|
4. **Run** tests: `composer test`
|
||||||
|
5. **Submit** a pull request
|
||||||
|
|
||||||
|
## Guidelines
|
||||||
|
|
||||||
|
- Follow the existing code style
|
||||||
|
- Add tests for new features
|
||||||
|
- Update documentation as needed
|
||||||
|
- One feature per pull request
|
||||||
|
|
||||||
|
## Development Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run tests
|
||||||
|
composer test
|
||||||
|
|
||||||
|
# Format code
|
||||||
|
composer pint
|
||||||
|
|
||||||
|
# Static analysis
|
||||||
|
composer analyse
|
||||||
|
```
|
||||||
|
|
||||||
|
## Need Help?
|
||||||
|
|
||||||
|
- [Open an issue](https://github.com/relaticle/comments/issues) for bugs or questions
|
||||||
|
- Check [existing issues](https://github.com/relaticle/comments/issues) first
|
||||||
39
docs/content/4.community/2.license.md
Normal file
39
docs/content/4.community/2.license.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
title: License
|
||||||
|
description: MIT License terms and what it means for you
|
||||||
|
navigation:
|
||||||
|
icon: i-lucide-scale
|
||||||
|
---
|
||||||
|
|
||||||
|
## MIT License
|
||||||
|
|
||||||
|
```
|
||||||
|
Copyright (c) Relaticle
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
```
|
||||||
|
|
||||||
|
## What This Means
|
||||||
|
|
||||||
|
You **can** use Comments in commercial projects.
|
||||||
|
You **can** modify and distribute it.
|
||||||
|
You **can** use it in closed source projects.
|
||||||
|
You **can** sell applications that include it.
|
||||||
|
|
||||||
|
Just include the license notice in your copy.
|
||||||
151
docs/content/index.md
Normal file
151
docs/content/index.md
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
---
|
||||||
|
seo:
|
||||||
|
title: Filament Comments System
|
||||||
|
description: A full-featured commenting system for Filament panels with threaded replies, @mentions, emoji reactions, file attachments, and real-time updates.
|
||||||
|
ogImage: /og-image.png
|
||||||
|
---
|
||||||
|
|
||||||
|
::u-page-hero
|
||||||
|
#title
|
||||||
|
Comments
|
||||||
|
|
||||||
|
#description
|
||||||
|
A full-featured commenting system for Filament panels with threaded replies, @mentions, emoji reactions, and real-time updates.
|
||||||
|
|
||||||
|
Drop-in integration with any Filament resource.
|
||||||
|
|
||||||
|
#links
|
||||||
|
:::u-button
|
||||||
|
---
|
||||||
|
color: neutral
|
||||||
|
size: xl
|
||||||
|
to: /getting-started/installation
|
||||||
|
trailing-icon: i-lucide-arrow-right
|
||||||
|
---
|
||||||
|
Get started
|
||||||
|
:::
|
||||||
|
|
||||||
|
:::u-button
|
||||||
|
---
|
||||||
|
color: neutral
|
||||||
|
icon: simple-icons:github
|
||||||
|
size: xl
|
||||||
|
to: https://github.com/relaticle/comments
|
||||||
|
variant: outline
|
||||||
|
---
|
||||||
|
GitHub
|
||||||
|
:::
|
||||||
|
::
|
||||||
|
|
||||||
|
::u-page-section
|
||||||
|
#title
|
||||||
|
Why choose Comments?
|
||||||
|
|
||||||
|
#features
|
||||||
|
:::u-page-feature
|
||||||
|
---
|
||||||
|
icon: i-lucide-messages-square
|
||||||
|
---
|
||||||
|
#title
|
||||||
|
Threaded Replies
|
||||||
|
|
||||||
|
#description
|
||||||
|
Nested comment threads with configurable depth limits. Users can reply to specific comments creating organized discussions.
|
||||||
|
:::
|
||||||
|
|
||||||
|
:::u-page-feature
|
||||||
|
---
|
||||||
|
icon: i-lucide-at-sign
|
||||||
|
---
|
||||||
|
#title
|
||||||
|
@Mentions
|
||||||
|
|
||||||
|
#description
|
||||||
|
Autocomplete user mentions with a customizable resolver interface. Dispatches events for notification handling.
|
||||||
|
:::
|
||||||
|
|
||||||
|
:::u-page-feature
|
||||||
|
---
|
||||||
|
icon: i-lucide-smile
|
||||||
|
---
|
||||||
|
#title
|
||||||
|
Emoji Reactions
|
||||||
|
|
||||||
|
#description
|
||||||
|
Six built-in emoji reactions with a configurable set. Users can react to comments with a single click.
|
||||||
|
:::
|
||||||
|
|
||||||
|
:::u-page-feature
|
||||||
|
---
|
||||||
|
icon: i-lucide-paperclip
|
||||||
|
---
|
||||||
|
#title
|
||||||
|
File Attachments
|
||||||
|
|
||||||
|
#description
|
||||||
|
Upload images and documents to comments with configurable storage, size limits, and MIME type validation.
|
||||||
|
:::
|
||||||
|
|
||||||
|
:::u-page-feature
|
||||||
|
---
|
||||||
|
icon: i-lucide-radio
|
||||||
|
---
|
||||||
|
#title
|
||||||
|
Real-time Updates
|
||||||
|
|
||||||
|
#description
|
||||||
|
Optional broadcasting via private channels with automatic polling fallback. Comments stay in sync across sessions.
|
||||||
|
:::
|
||||||
|
|
||||||
|
:::u-page-feature
|
||||||
|
---
|
||||||
|
icon: i-lucide-puzzle
|
||||||
|
---
|
||||||
|
#title
|
||||||
|
Full Filament Integration
|
||||||
|
|
||||||
|
#description
|
||||||
|
Three integration patterns: slide-over action, table row action, and infolist entry. Works with any Filament resource.
|
||||||
|
:::
|
||||||
|
::
|
||||||
|
|
||||||
|
::u-page-section
|
||||||
|
#title
|
||||||
|
Our Ecosystem
|
||||||
|
|
||||||
|
#description
|
||||||
|
Extend your Laravel applications with our ecosystem of complementary tools
|
||||||
|
|
||||||
|
#default
|
||||||
|
::card-group
|
||||||
|
:::card
|
||||||
|
---
|
||||||
|
title: FilaForms
|
||||||
|
icon: i-simple-icons-laravel
|
||||||
|
to: https://filaforms.app
|
||||||
|
target: _blank
|
||||||
|
---
|
||||||
|
Visual form builder for all your public-facing forms.
|
||||||
|
:::
|
||||||
|
|
||||||
|
:::card
|
||||||
|
---
|
||||||
|
title: Custom Fields
|
||||||
|
icon: i-lucide-sliders
|
||||||
|
to: https://relaticle.github.io/custom-fields
|
||||||
|
target: _blank
|
||||||
|
---
|
||||||
|
Let users add custom fields to any model without code changes.
|
||||||
|
:::
|
||||||
|
|
||||||
|
:::card
|
||||||
|
---
|
||||||
|
title: Flowforge
|
||||||
|
icon: i-lucide-kanban
|
||||||
|
to: https://relaticle.github.io/flowforge
|
||||||
|
target: _blank
|
||||||
|
---
|
||||||
|
Transform any Laravel model into a drag-and-drop Kanban board.
|
||||||
|
:::
|
||||||
|
::
|
||||||
|
::
|
||||||
69
docs/nuxt.config.ts
Normal file
69
docs/nuxt.config.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
|
const baseURL = process.env.NUXT_APP_BASE_URL || '/'
|
||||||
|
const docsVersion = process.env.DOCS_VERSION || '1.x'
|
||||||
|
|
||||||
|
export default defineNuxtConfig({
|
||||||
|
extends: 'docus',
|
||||||
|
modules: ['@nuxt/image', '@nuxt/scripts', 'nuxt-fathom'],
|
||||||
|
fathom: {
|
||||||
|
siteId: process.env.NUXT_PUBLIC_FATHOM_SITE_ID || '',
|
||||||
|
},
|
||||||
|
devtools: { enabled: true },
|
||||||
|
site: {
|
||||||
|
name: 'Comments',
|
||||||
|
},
|
||||||
|
runtimeConfig: {
|
||||||
|
public: {
|
||||||
|
docsVersion,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
appConfig: {
|
||||||
|
docus: {
|
||||||
|
url: `https://relaticle.github.io${baseURL}`,
|
||||||
|
image: `${baseURL}preview.png`,
|
||||||
|
header: {
|
||||||
|
logo: {
|
||||||
|
light: `${baseURL}logo-light.svg`,
|
||||||
|
dark: `${baseURL}logo-dark.svg`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
seo: {
|
||||||
|
ogImage: `${baseURL}preview.png`,
|
||||||
|
},
|
||||||
|
github: {
|
||||||
|
branch: docsVersion,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
app: {
|
||||||
|
baseURL,
|
||||||
|
buildAssetsDir: 'assets',
|
||||||
|
head: {
|
||||||
|
link: [
|
||||||
|
{
|
||||||
|
rel: 'icon',
|
||||||
|
type: 'image/x-icon',
|
||||||
|
href: baseURL + 'favicon.ico',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
provider: 'none',
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
build: {
|
||||||
|
markdown: {
|
||||||
|
highlight: {
|
||||||
|
langs: ['php', 'blade', 'bash', 'json'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
llms: {
|
||||||
|
domain: `https://relaticle.github.io${baseURL.replace(/\/$/, '')}`,
|
||||||
|
},
|
||||||
|
nitro: {
|
||||||
|
preset: 'github_pages',
|
||||||
|
},
|
||||||
|
})
|
||||||
22
docs/package.json
Normal file
22
docs/package.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"name": "comments-docs",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "nuxt dev --extends docus",
|
||||||
|
"build": "nuxt build --extends docus",
|
||||||
|
"generate": "nuxt build --preset github_pages",
|
||||||
|
"preview": "nuxt preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@nuxt/image": "^1.11.0",
|
||||||
|
"@nuxt/scripts": "^0.12.1",
|
||||||
|
"@nuxt/ui": "^4.0.0",
|
||||||
|
"@unhead/vue": "^2.0.17",
|
||||||
|
"better-sqlite3": "^12.4.1",
|
||||||
|
"docus": "latest",
|
||||||
|
"nuxt": "^4.1.2",
|
||||||
|
"typescript": "^5.9.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"nuxt-fathom": "^0.0.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
285
resources/boost/skills/comments-development/SKILL.md
Normal file
285
resources/boost/skills/comments-development/SKILL.md
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
---
|
||||||
|
name: comments-development
|
||||||
|
description: Full-featured commenting system for Filament panels with polymorphic comments, threaded replies, @mentions, emoji reactions, file attachments, and real-time notifications. Use when adding the HasComments trait to models, integrating CommentsAction/CommentsTableAction/CommentsEntry in Filament, configuring threading, reactions, mentions, attachments, notifications, broadcasting, or customizing the CommentPolicy.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Comments Development
|
||||||
|
|
||||||
|
## When to Use This Skill
|
||||||
|
|
||||||
|
Use when:
|
||||||
|
- Adding commenting capability to an Eloquent model
|
||||||
|
- Integrating comments into Filament resources (actions, table actions, infolists)
|
||||||
|
- Configuring threading depth, reactions, mentions, or attachments
|
||||||
|
- Working with comment notifications and subscriptions
|
||||||
|
- Customizing the CommentPolicy for authorization
|
||||||
|
- Implementing real-time updates via broadcasting or polling
|
||||||
|
- Creating a custom MentionResolver
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Add Traits to Models
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\Concerns\HasComments;
|
||||||
|
use Relaticle\Comments\Contracts\Commentable;
|
||||||
|
|
||||||
|
class Project extends Model implements Commentable
|
||||||
|
{
|
||||||
|
use HasComments;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\Concerns\IsCommenter;
|
||||||
|
use Relaticle\Comments\Contracts\Commenter;
|
||||||
|
|
||||||
|
class User extends Authenticatable implements Commenter
|
||||||
|
{
|
||||||
|
use IsCommenter;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Register Plugin in Panel
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\CommentsPlugin;
|
||||||
|
|
||||||
|
public function panel(Panel $panel): Panel
|
||||||
|
{
|
||||||
|
return $panel
|
||||||
|
->plugins([
|
||||||
|
CommentsPlugin::make(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Publish and Run Migrations
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php artisan vendor:publish --tag=comments-migrations
|
||||||
|
php artisan migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
## Filament Integration
|
||||||
|
|
||||||
|
### Slide-Over Action (View/Edit Pages)
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\Filament\Actions\CommentsAction;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
CommentsAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Shows a comment count badge and opens a slide-over modal with the full comment thread.
|
||||||
|
|
||||||
|
### Table Row Action
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\Filament\Actions\CommentsTableAction;
|
||||||
|
|
||||||
|
public static function table(Table $table): Table
|
||||||
|
{
|
||||||
|
return $table
|
||||||
|
->actions([
|
||||||
|
CommentsTableAction::make(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Infolist Entry
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\Filament\Infolists\Components\CommentsEntry;
|
||||||
|
|
||||||
|
public static function infolist(Infolist $infolist): Infolist
|
||||||
|
{
|
||||||
|
return $infolist->schema([
|
||||||
|
CommentsEntry::make('comments'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Embeds the full comment component inline within an infolist.
|
||||||
|
|
||||||
|
## Configuration Reference
|
||||||
|
|
||||||
|
Publish config: `php artisan vendor:publish --tag=comments-config`
|
||||||
|
|
||||||
|
| Key | Default | Purpose |
|
||||||
|
|-----|---------|---------|
|
||||||
|
| `tables.comments` | `'comments'` | Main comments table name |
|
||||||
|
| `models.comment` | `Comment::class` | Comment model class |
|
||||||
|
| `commenter.model` | `User::class` | Commenter (user) model class |
|
||||||
|
| `policy` | `CommentPolicy::class` | Authorization policy class |
|
||||||
|
| `threading.max_depth` | `2` | Maximum reply nesting depth |
|
||||||
|
| `pagination.per_page` | `10` | Comments per page |
|
||||||
|
| `reactions.emoji_set` | 6 emojis | Available reaction emojis |
|
||||||
|
| `mentions.resolver` | `DefaultMentionResolver::class` | User search resolver |
|
||||||
|
| `mentions.max_results` | `5` | Autocomplete results limit |
|
||||||
|
| `editor.toolbar` | bold, italic, strike, link, lists, codeBlock | Rich text toolbar buttons |
|
||||||
|
| `notifications.enabled` | `true` | Enable/disable notifications |
|
||||||
|
| `notifications.channels` | `['database']` | Notification channels |
|
||||||
|
| `subscriptions.auto_subscribe` | `true` | Auto-subscribe on comment/mention |
|
||||||
|
| `attachments.enabled` | `true` | Enable file attachments |
|
||||||
|
| `attachments.disk` | `'public'` | Storage disk |
|
||||||
|
| `attachments.max_size` | `10240` | Max file size (KB) |
|
||||||
|
| `attachments.allowed_types` | images, pdf, text, word | Allowed MIME types |
|
||||||
|
| `broadcasting.enabled` | `false` | Enable real-time broadcasting |
|
||||||
|
| `broadcasting.channel_prefix` | `'comments'` | Private channel prefix |
|
||||||
|
| `polling.interval` | `'10s'` | Livewire polling interval (fallback) |
|
||||||
|
|
||||||
|
### Default Reactions
|
||||||
|
|
||||||
|
```php
|
||||||
|
'reactions' => [
|
||||||
|
'emoji_set' => [
|
||||||
|
'thumbs_up' => ['emoji' => "\u{1F44D}", 'label' => 'Like'],
|
||||||
|
'heart' => ['emoji' => "\u{2764}\u{FE0F}", 'label' => 'Love'],
|
||||||
|
'celebrate' => ['emoji' => "\u{1F389}", 'label' => 'Celebrate'],
|
||||||
|
'laugh' => ['emoji' => "\u{1F602}", 'label' => 'Laugh'],
|
||||||
|
'thinking' => ['emoji' => "\u{1F914}", 'label' => 'Thinking'],
|
||||||
|
'sad' => ['emoji' => "\u{1F622}", 'label' => 'Sad'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
## Events
|
||||||
|
|
||||||
|
| Event | Broadcast | Payload |
|
||||||
|
|-------|-----------|---------|
|
||||||
|
| `CommentCreated` | Yes | `$comment` |
|
||||||
|
| `CommentUpdated` | Yes | `$comment` |
|
||||||
|
| `CommentDeleted` | Yes | `$comment` |
|
||||||
|
| `CommentReacted` | Yes | `$comment`, `$user`, `$reaction`, `$action` (added/removed) |
|
||||||
|
| `UserMentioned` | No | `$comment`, `$mentionedUser` |
|
||||||
|
|
||||||
|
Broadcasting uses private channels: `{prefix}.{commentable_type}.{commentable_id}`
|
||||||
|
|
||||||
|
## Authorization
|
||||||
|
|
||||||
|
Default `CommentPolicy` methods:
|
||||||
|
|
||||||
|
| Method | Default | Description |
|
||||||
|
|--------|---------|-------------|
|
||||||
|
| `viewAny()` | `true` | Everyone can view comments |
|
||||||
|
| `create()` | `true` | Everyone can create comments |
|
||||||
|
| `update()` | Owner only | Only comment author can edit |
|
||||||
|
| `delete()` | Owner only | Only comment author can delete |
|
||||||
|
| `reply()` | Depth check | Can reply if max_depth not exceeded |
|
||||||
|
|
||||||
|
### Custom Policy
|
||||||
|
|
||||||
|
```php
|
||||||
|
// config/comments.php
|
||||||
|
'policy' => App\Policies\CustomCommentPolicy::class,
|
||||||
|
```
|
||||||
|
|
||||||
|
```php
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use Relaticle\Comments\Comment;
|
||||||
|
use Relaticle\Comments\Contracts\Commenter;
|
||||||
|
|
||||||
|
class CustomCommentPolicy
|
||||||
|
{
|
||||||
|
public function delete(Commenter $user, Comment $comment): bool
|
||||||
|
{
|
||||||
|
return $comment->user_id === $user->getKey()
|
||||||
|
|| $user->hasRole('admin');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Patterns
|
||||||
|
|
||||||
|
### Scoped Comments (Multi-tenancy)
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\Config;
|
||||||
|
|
||||||
|
// In AppServiceProvider::boot()
|
||||||
|
Config::resolveAuthenticatedUserUsing(function () {
|
||||||
|
return auth()->user();
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Mention Resolver
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Relaticle\Comments\Contracts\MentionResolver;
|
||||||
|
|
||||||
|
class TeamMentionResolver implements MentionResolver
|
||||||
|
{
|
||||||
|
public function search(string $query): Collection
|
||||||
|
{
|
||||||
|
return User::query()
|
||||||
|
->where('team_id', auth()->user()->team_id)
|
||||||
|
->where('name', 'like', "{$query}%")
|
||||||
|
->limit(config('comments.mentions.max_results'))
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resolveByNames(array $names): Collection
|
||||||
|
{
|
||||||
|
return User::query()
|
||||||
|
->where('team_id', auth()->user()->team_id)
|
||||||
|
->whereIn('name', $names)
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Register in config:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// config/comments.php
|
||||||
|
'mentions' => [
|
||||||
|
'resolver' => App\Comments\TeamMentionResolver::class,
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enable Broadcasting
|
||||||
|
|
||||||
|
```php
|
||||||
|
// config/comments.php
|
||||||
|
'broadcasting' => [
|
||||||
|
'enabled' => true,
|
||||||
|
'channel_prefix' => 'comments',
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
When broadcasting is enabled, the Livewire component listens for real-time events. When disabled, it falls back to polling at the configured interval.
|
||||||
|
|
||||||
|
## Database Schema
|
||||||
|
|
||||||
|
Five tables are created:
|
||||||
|
|
||||||
|
- `comments` -- Polymorphic comments with parent_id for threading, soft deletes
|
||||||
|
- `comment_reactions` -- Unique reactions per user+comment+emoji
|
||||||
|
- `comment_mentions` -- Tracks @mentioned users per comment
|
||||||
|
- `comment_subscriptions` -- Thread subscription tracking per user+commentable
|
||||||
|
- `comment_attachments` -- File metadata (path, name, MIME type, size, disk)
|
||||||
|
|
||||||
|
## Model Relationships
|
||||||
|
|
||||||
|
```php
|
||||||
|
// On any Commentable model
|
||||||
|
$model->comments(); // All comments (morphMany)
|
||||||
|
$model->topLevelComments(); // Top-level only (no parent)
|
||||||
|
$model->commentCount(); // Total count
|
||||||
|
|
||||||
|
// On Comment model
|
||||||
|
$comment->commentable(); // Parent model (morphTo)
|
||||||
|
$comment->user(); // Commenter (morphTo)
|
||||||
|
$comment->parent(); // Parent comment (belongsTo)
|
||||||
|
$comment->replies(); // Child comments (hasMany)
|
||||||
|
$comment->reactions(); // Reactions (hasMany)
|
||||||
|
$comment->attachments(); // File attachments (hasMany)
|
||||||
|
$comment->mentions(); // Mentioned users (morphToMany)
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user