awcodes / filament-tiptap-editor

A Rich Text Editor plugin for Filament Forms.
MIT License
297 stars 86 forks source link

Extending the media modal? #249

Open haleyngonadi opened 11 months ago

haleyngonadi commented 11 months ago

Filament Version

v3.0.97

Plugin Version

v3.2.6

PHP Version

PHP 8.2

Problem description

Following up on this discussion: I'm trying to extend the existing MediaAction to allow for an "align" attribute.

Here's my custom MediaAction (which doesn't work)

<?php
[...]
class MediaAction extends Action
{
    public static function getDefaultName(): ?string
    {
        return 'filament_tiptap_media';
    }

    protected function setUp(): void
    {
        parent::setUp();

        $this
            ->arguments([
                'src' => '',
                'alt' => '',
                'title' => '',
                'align' => '',
                'width' => '',
                'height' => '',
            ])
            ->modalWidth('md')
            ->mountUsing(function (TiptapEditor $component, ComponentContainer $form, array $arguments) {
                $source = $arguments['src'] !== ''
                    ? $component->getDirectory() . Str::of($arguments['src'])
                    ->after($component->getDirectory())
                    : null;

                $form->fill([
                    'src' => $source,
                    'alt' => $arguments['alt'] ?? '',
                    'title' => $arguments['title'] ?? '',
                    'align' => $arguments['align'] ?? '',
                    'width' => $arguments['width'] ?? '',
                    'height' => $arguments['height'] ?? '',
                ]);
            })->modalHeading(function (TiptapEditor $component, array $arguments) {
                $context = blank($arguments['src'] ?? null) ? 'insert' : 'update';

                return __('filament-tiptap-editor::media-modal.heading.' . $context);
            })->form(function (TiptapEditor $component) {
                return [
                    FileUpload::make('src')
                        ->label(__('filament-tiptap-editor::media-modal.labels.file'))
                        ->disk($component->getDisk())
                        ->directory($component->getDirectory())
                        ->visibility(config('filament-tiptap-editor.visibility'))
                        ->preserveFilenames(config('filament-tiptap-editor.preserve_file_names'))
                        ->acceptedFileTypes($component->getAcceptedFileTypes())
                        ->maxFiles(1)
                        ->maxSize($component->getMaxFileSize())
                        ->imageResizeMode(config('filament-tiptap-editor.image_resize_mode'))
                        ->imageCropAspectRatio(config('filament-tiptap-editor.image_crop_aspect_ratio'))
                        ->imageResizeTargetWidth(config('filament-tiptap-editor.image_resize_target_width'))
                        ->imageResizeTargetHeight(config('filament-tiptap-editor.image_resize_target_height'))
                        ->required()
                        ->live()
                        ->afterStateUpdated(function (TemporaryUploadedFile $state, callable $set) {
                            if (Str::contains($state->getMimeType(), 'image')) {
                                $set('type', 'image');
                            } else {
                                $set('type', 'document');
                            }
                        })
                        ->saveUploadedFileUsing(function (BaseFileUpload $component, TemporaryUploadedFile $file, callable $set) {
                            $filename = $component->shouldPreserveFilenames() ? pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME) : Str::uuid();

                            $storeMethod = $component->getVisibility() === 'public' ? 'storePubliclyAs' : 'storeAs';

                            if (Storage::disk($component->getDiskName())->exists(ltrim($component->getDirectory() . '/' . $filename . '.' . $file->getClientOriginalExtension(), '/'))) {
                                $filename = $filename . '-' . time();
                            }

                            if (Str::contains($file->getMimeType(), 'image')) {
                                if (config('filesystems.disks.s3.driver') === 's3') {
                                    $image = Image::make($file->readStream());
                                } else {
                                    $image = Image::make($file->getRealPath());
                                }

                                $set('width', $image->getWidth());
                                $set('height', $image->getHeight());
                            }

                            $upload = $file->{$storeMethod}($component->getDirectory(), $filename . '.' . $file->getClientOriginalExtension(), $component->getDiskName());

                            return Storage::disk($component->getDiskName())->url($upload);
                        }),
                    TextInput::make('link_text')
                        ->label(__('filament-tiptap-editor::media-modal.labels.link_text'))
                        ->required()
                        ->visible(fn (callable $get) => $get('type') == 'document'),
                    TextInput::make('alt')
                        ->label(__('filament-tiptap-editor::media-modal.labels.alt'))
                        ->hidden(fn (callable $get) => $get('type') == 'document')
                        ->hintAction(
                            Action::make('alt_hint_action')
                                ->label('?')
                                ->color('primary')
                                ->url('https://www.w3.org/WAI/tutorials/images/decision-tree', true)
                        ),
                    TextInput::make('title')
                        ->label(__('filament-tiptap-editor::media-modal.labels.title')),
                    Select::make('align')
                        ->label('Alignment')
                        ->options([
                            'left' => 'Left',
                            'center' => 'Center',
                            'right' => 'Right',
                        ]),
                    Hidden::make('width'),
                    Hidden::make('height'),
                    Hidden::make('type')
                        ->default('document'),
                ];
            })->action(function (TiptapEditor $component, $data) {
                if (config('filament-tiptap-editor.use_relative_paths')) {
                    $source = Str::replace(config('app.url'), '', $data['src']);
                } else {
                    $source = str_starts_with($data['src'], 'http')
                        ? $data['src']
                        : Storage::disk(config('filament-tiptap-editor.disk'))->url($data['src']);
                }

                $component->getLivewire()->dispatch(
                    'insert-content',
                    type: 'media',
                    statePath: $component->getStatePath(),
                    media: [
                        'src' => $source,
                        'alt' => $data['alt'] ?? null,
                        'title' => $data['title'],
                        'class' => $data['align'] ? 'align-' . $data['align'] : null,
                        'width' => $data['width'],
                        'height' => $data['height'],
                        'align' => $data['align'],
                        'link_text' => $data['link_text'] ?? null,
                    ],
                );
            });
    }
}

Expected behavior

When you insert an image, the "align" attribute should be added to the img tag, like so tag.

Steps to reproduce

N/A

Reproduction repository

No response

Relevant log output

No response

awcodes commented 11 months ago

According to MDN the 'align' attribute has been deprecated for images. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#align

I recommend inserting the image then using the alignment tools from the toolbar.

haleyngonadi commented 11 months ago

Hi @awcodes, I wasn't trying to use the align attribute per se; I just wanted to be able to add a custom class to the image. Is that something that can be done?

awcodes commented 11 months ago

Ah. ok. i'll reopen then.

rubenlopezgea-at-coodex commented 1 month ago

Many time after this, I'm back. I don't want to open a new issue, as it's the same subject.

It'd be great to be able to add more params. For example, srcset or sizes (as I'm trying to do) I can make the PHP part for it, but as soon as it gets to plugins.js, it removes all attributes not in this list:

filament-tiptap-editor/resources/js/plugin.js:465

.setImage({
    src: src,
    alt: media?.alt,
    title: media?.title,
    width: media?.width,
    height: media?.height,
    lazy: media?.lazy,
})

Here there's a list of all possible attributes: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attributes

and of course, some global attributes as:

and some event handlers:

Adding all those to plugin.js would help us to make any plugin with ease.

awcodes commented 1 month ago

I'm open to PRs. Haven't forgotten about the original issue. Just haven't had the time. Sorry.

rubenlopezgea-at-coodex commented 1 month ago

The plugin is awesome. Let me first of all thank you for it.

I've already made a PR with those properties needed for responsive images coming from spatie/laravel-medialibrary

awcodes commented 1 month ago

I'll look at the PR when I get a chance. Thank you.