Store media:ID in article bodies instead of CDN URLs, and keep sablog attach tokens as a fallback. Co-authored-by: Cursor <cursoragent@cursor.com>
157 lines
6.8 KiB
PHP
157 lines
6.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Filament\Resources\Articles\Schemas;
|
|
|
|
use App\Domain\Blog\ContentFormat;
|
|
use App\Domain\Media\MarkdownMediaEmbed;
|
|
use App\Domain\Plugin\Hook;
|
|
use App\Settings\GeneralSettings;
|
|
use Filament\Actions\Action;
|
|
use Filament\Forms\Components\DateTimePicker;
|
|
use Filament\Forms\Components\Select;
|
|
use Filament\Forms\Components\Textarea;
|
|
use Filament\Forms\Components\TextInput;
|
|
use Filament\Forms\Components\Toggle;
|
|
use Filament\Notifications\Notification;
|
|
use Filament\Schemas\Components\Actions;
|
|
use Filament\Schemas\Components\Utilities\Get;
|
|
use Filament\Schemas\Components\Utilities\Set;
|
|
use Filament\Schemas\Schema;
|
|
use Xpier\FilamentMediaLibrary\Components\MediaPicker;
|
|
use Xpier\FilamentMediaLibrary\Models\MediaLibrary;
|
|
|
|
class ArticleForm
|
|
{
|
|
public static function configure(Schema $schema): Schema
|
|
{
|
|
$defaultFormat = ContentFormat::MARKDOWN;
|
|
try {
|
|
$defaultFormat = ContentFormat::normalize(app(GeneralSettings::class)->default_content_format, ContentFormat::MARKDOWN);
|
|
} catch (\Throwable) {
|
|
//
|
|
}
|
|
|
|
return $schema
|
|
->components([
|
|
Select::make('category_id')
|
|
->label(__('admin.fields.category'))
|
|
->relationship('category', 'name')
|
|
->required(),
|
|
Select::make('user_id')
|
|
->label(__('admin.fields.author'))
|
|
->relationship('user', 'name')
|
|
->required(),
|
|
TextInput::make('title')
|
|
->label(__('admin.fields.title'))
|
|
->required()
|
|
->columnSpanFull(),
|
|
Select::make('content_format')
|
|
->label(__('admin.fields.content_format'))
|
|
->options([
|
|
ContentFormat::MARKDOWN => __('admin.options.markdown_recommended'),
|
|
ContentFormat::HTML => __('admin.options.html_legacy'),
|
|
])
|
|
->default($defaultFormat)
|
|
->required()
|
|
->live()
|
|
->helperText(__('admin.helpers.article_content')),
|
|
Textarea::make('content')
|
|
->label(fn (Get $get): string => $get('content_format') === ContentFormat::MARKDOWN
|
|
? __('admin.fields.content_markdown')
|
|
: __('admin.fields.content_html'))
|
|
->required()
|
|
->rows(18)
|
|
->columnSpanFull(),
|
|
MediaPicker::make('insert_media_id')
|
|
->label(__('admin.fields.insert_media'))
|
|
->module('articles')
|
|
->mediaType(null)
|
|
->dehydrated(false)
|
|
->helperText(__('admin.helpers.insert_media'))
|
|
->columnSpanFull(),
|
|
Actions::make([
|
|
Action::make('insertSelectedMedia')
|
|
->label(__('admin.actions.insert_media_into_content'))
|
|
->action(function (Get $get, Set $set): void {
|
|
$mediaId = $get('insert_media_id');
|
|
$media = is_numeric($mediaId)
|
|
? MediaLibrary::query()->find((int) $mediaId)
|
|
: null;
|
|
|
|
if (! $media instanceof MediaLibrary) {
|
|
Notification::make()->title(__('admin.notifications.pick_media_first'))->warning()->send();
|
|
|
|
return;
|
|
}
|
|
|
|
$snippet = app(MarkdownMediaEmbed::class)->snippet(
|
|
$media,
|
|
(string) ($get('content_format') ?: ContentFormat::MARKDOWN)
|
|
);
|
|
$set('content', rtrim((string) $get('content'))."\n\n".$snippet."\n");
|
|
$set('insert_media_id', null);
|
|
Notification::make()->title(__('admin.notifications.media_inserted'))->success()->send();
|
|
}),
|
|
])->columnSpanFull(),
|
|
TextInput::make('description')
|
|
->label(__('admin.fields.description')),
|
|
TextInput::make('keywords')
|
|
->label(__('admin.fields.keywords')),
|
|
TextInput::make('slug')
|
|
->label(__('admin.fields.slug')),
|
|
DateTimePicker::make('published_at')
|
|
->label(__('admin.fields.published_at'))
|
|
->default(now()),
|
|
Toggle::make('stick')
|
|
->label(__('admin.fields.stick'))
|
|
->default(false),
|
|
Toggle::make('visible')
|
|
->label(__('admin.fields.visible'))
|
|
->default(true),
|
|
Toggle::make('close_comment')
|
|
->label(__('admin.fields.close_comment'))
|
|
->default(false),
|
|
TextInput::make('read_password')
|
|
->label(__('admin.fields.read_password'))
|
|
->password(),
|
|
TextInput::make('cover_path')
|
|
->label(__('admin.fields.cover_path'))
|
|
->helperText(__('admin.helpers.cover_path'))
|
|
->columnSpanFull(),
|
|
MediaPicker::make('cover_media_id')
|
|
->label(__('admin.fields.cover_media'))
|
|
->module('articles')
|
|
->mediaType('image')
|
|
->relationship('coverMedia')
|
|
->columnSpanFull(),
|
|
TextInput::make('cover_source')
|
|
->label(__('admin.fields.cover_source'))
|
|
->disabled()
|
|
->dehydrated(false),
|
|
TextInput::make('cover_status')
|
|
->label(__('admin.fields.cover_status'))
|
|
->disabled()
|
|
->dehydrated(false),
|
|
Textarea::make('ai_summary')
|
|
->label(__('admin.fields.ai_summary'))
|
|
->rows(3)
|
|
->columnSpanFull(),
|
|
Textarea::make('ai_polished_content')
|
|
->label(__('admin.fields.ai_polished_content'))
|
|
->helperText(__('admin.helpers.ai_polished_content'))
|
|
->rows(12)
|
|
->columnSpanFull(),
|
|
Textarea::make('ai_suggestions_text')
|
|
->label(__('admin.fields.ai_suggestions'))
|
|
->helperText(__('admin.helpers.ai_suggestions'))
|
|
->rows(4)
|
|
->disabled()
|
|
->dehydrated(false)
|
|
->columnSpanFull(),
|
|
...Hook::collect('filament.article.form'),
|
|
]);
|
|
}
|
|
}
|