awcodes / filament-tiptap-editor

用于 Filament Admin/表单的 Tiptap 集成。

资助包维护!
awcodes

安装次数: 251,343

依赖项: 16

建议者: 0

安全: 0

星标: 275

关注者: 6

分支: 74

公开问题: 2

类型:

v3.4.16 2024-09-21 17:01 UTC

This package is auto-updated.

Last update: 2024-09-21 17:03:58 UTC


README

用于 Filament Admin/表单的 Tiptap 集成。

tiptap-editor-og

安装

使用 composer 安装此包

composer require awcodes/filament-tiptap-editor:"^3.0"

为了与 Filament 的主题方法保持一致,您需要使用自定义主题来使用此插件。

注意 如果您尚未设置自定义主题并正在使用面板,请首先按照 Filament 文档 中的说明进行设置。以下内容适用于面板包和独立的表单包。

  1. 将插件样式表和 tippy.js 样式表(如果尚未包含)导入您的主题 CSS 文件中。
@import '<path-to-vendor>/awcodes/filament-tiptap-editor/resources/css/plugin.css';
  1. 将插件的视图添加到您的 tailwind.config.js 文件中。
content: [
    ...
    '<path-to-vendor>/awcodes/filament-tiptap-editor/resources/**/*.blade.php',
]
  1. tailwindcss/nesting 插件添加到您的 postcss.config.js 文件中。
module.exports = {
    plugins: {
        'tailwindcss/nesting': {},
        tailwindcss: {},
        autoprefixer: {},
    },
}
  1. 重新构建您的自定义主题。
npm run build

从 2.x 升级到 3.x

  1. 输出现在使用枚举设置,请更新您的文件,在所有设置输出的地方使用 TiptapOutput,包括配置文件。
  2. barebone 配置文件设置已重命名为 minimal

用法

该编辑器扩展了默认的 Field 类,因此将此类添加到表单时,可以大多数其他方法。

use FilamentTiptapEditor\TiptapEditor;
use FilamentTiptapEditor\Enums\TiptapOutput;

TiptapEditor::make('content')
    ->profile('default|simple|minimal|none|custom')
    ->tools([]) // individual tools to use in the editor, overwrites profile
    ->disk('string') // optional, defaults to config setting
    ->directory('string or Closure returning a string') // optional, defaults to config setting
    ->acceptedFileTypes(['array of file types']) // optional, defaults to config setting
    ->maxSize('integer in KB') // optional, defaults to config setting
    ->output(TiptapOutput::Html) // optional, change the format for saved data, default is html
    ->maxContentWidth('5xl')
    ->required();

在 Blade 文件中渲染内容

如果您将内容存储为 JSON,那么您可能需要将数据解析为 HTML 以在 Blade 文件中输出。为此,有一个名为 tiptap_converter 的辅助函数,可以将数据转换为三种支持的 Tiptap 格式之一。

输出样式完全由您决定。

{!! tiptap_converter()->asHTML($post->content) !!}
{!! tiptap_converter()->asJSON($post->content) !!}
{!! tiptap_converter()->asText($post->content) !!}

目录

如果您在编辑器中使用 heading 工具,您还可以从内容中的标题生成目录。这是通过将内容传递给 asHTML() 方法并设置 toc 选项为 true 来完成的。您还可以传递一个 maxDepth 选项来限制要包含在目录中的标题深度。

<!-- this will generate links for all headings up to h3 -->
{!! tiptap_converter()->asHTML($post->content, toc: true, maxDepth: 3) !!}

<!-- this will generate a table of contents with headings up to h3 -->
{!! tiptap_converter()->asToc($post->content, maxDepth: 3) !!}

或者,您可以使用并扩展 table-of-contents blade 组件来生成目录。

<!-- This will generate the TOC as a nested array, and use it as a parameter in the contents table -->
<x-filament-tiptap-editor::table-of-contents :headings="tiptap_converter()->asTOC($page->body, array: true)" />

配置

插件不需要发布配置即可工作,但如果您需要更改任何默认设置,可以使用以下 Artisan 命令发布配置文件

php artisan vendor:publish --tag="filament-tiptap-editor-config"

配置文件 / 工具

该包默认包含 3 个配置文件(或工具栏)。您还可以使用管道 | 将工具分组。默认配置文件是完整工具集。

'profiles' => [
    'default' => [
        'heading', 'bullet-list', 'ordered-list', 'checked-list', 'blockquote', 'hr',
        'bold', 'italic', 'strike', 'underline', 'superscript', 'subscript', 'lead', 'small', 'align-left', 'align-center', 'align-right',
        'link', 'media', 'oembed', 'table', 'grid-builder', 'details',
        'code', 'code-block', 'source',
    ],
    'simple' => [
        'heading', 'hr', 'bullet-list', 'ordered-list', 'checked-list',
        'bold', 'italic', 'lead', 'small',
        'link', 'media',
    ],
    'minimal' => [
        'bold', 'italic', 'link', 'bullet-list', 'ordered-list',
    ],
],

有关修改配置文件以添加/删除编辑器中的按钮或添加自己的按钮的说明,请参阅 filament-tiptap-editor.php 配置文件。

您还可以通过使用 ->tools() 修饰符来按实例添加工具,以覆盖实例设置的配置文件。有关工具的完整列表,请参阅 filament-tiptap-editor.php 配置文件中的默认配置文件设置。

媒体 / 图片

[
    'accepted_file_types' => ['image/jpeg', 'image/png', 'image/webp', 'image/svg+xml', 'application/pdf'],
    'disk' => 'public',
    'directory' => 'images',
    'visibility' => 'public',
    'preserve_file_names' => false,
    'max_file_size' => 2042,
    'image_crop_aspect_ratio' => null,
    'image_resize_target_width' => null,
    'image_resize_target_height' => null,
]

输出格式

Tiptap 有 3 种不同的输出格式。请参阅:https://tiptap.dev/guide/output

如果您想更改存储在数据库中的输出格式,可以更改默认配置或在每个实例中指定。

use FilamentTiptapEditor\Enums\TiptapOutput;

TiptapEditor::make('content')
    ->output(FilamentTiptapEditor\TiptapOutput::Json);

注意 如果您想将编辑器内容存储为数组/JSON,则必须将数据库列设置为 longTextjson 类型,并在模型类中相应地进行转换。

// in your migration
$table->json('content');

// in your model
protected $casts = [
    'content' => 'json' // or 'array'
];

RTL 支持

为了让文本对齐等特性在RTL语言中正常工作,您可以将配置中的direction键切换到'rtl'。

// config/filament-tiptap-editor.php
'direction' => 'rtl'

最大内容宽度

要全局调整编辑器的最大内容宽度,请将配置中的max_content_width键设置为一个Tailwind最大宽度尺寸或full以实现全宽度。这也可以通过->maxContentWidth()方法在实例级别上设置。

'max_content_width' => 'full'
use FilamentTiptapEditor\TiptapEditor;

TiptapEditor::make('content')
    ->maxContentWidth('3xl');

重写

链接和媒体模态是用Filament表单组件动作构建的。这意味着可以用自己的实现替换它们。

链接模态

您可以使用自己的动作来重写默认的链接模态,并将其分配给配置文件中的link_action键。确保您动作的默认名称为filament_tiptap_link

请参阅vendor/awcodes/filament-tiptap-editor/src/Actions/LinkAction.php以获取实现方法。

媒体模态

您可以使用自己的动作来重写默认的媒体模态,并将其分配给配置文件中的media_action键。确保您动作的默认名称为filament_tiptap_media

请参阅vendor/awcodes/filament-tiptap-editor/src/Actions/MediaAction.php以获取实现方法。

编辑器字段初始高度

您可以使用extraInputAttributes()方法向字段添加额外的输入属性。这允许您设置编辑器的初始高度。

TiptapEditor::make('content')
    ->extraInputAttributes(['style' => 'min-height: 12rem;']),

气泡和浮动菜单

默认情况下,编辑器使用气泡和浮动菜单来帮助创建内容,因此无需使用工具栏。如果您不想使用菜单,可以在实例级别或全局配置文件中禁用它们。

TiptapEditor::make('content')
    ->disableFloatingMenus()
    ->disableBubbleMenus();
'disable_floating_menus' => true,
'disable_bubble_menus' => true,

您还可以提供自己的工具用于浮动菜单,默认值可以通过配置文件覆盖。

TiptapEditor::make('content')
    ->floatingMenuTools(['grid-builder', 'media', 'link'])
'floating_menu_tools' => ['media', 'grid-builder', 'details', 'table', 'oembed', 'code-block'],
'bubble_menu_tools' => ['bold', 'italic', 'strike', 'underline', 'superscript', 'subscript', 'lead', 'small', 'link'],

网格布局

使用grid工具时,您可以通过将它们传递给gridLayouts()方法来自定义下拉菜单中可用的布局。

TiptapEditor::make('content')
    ->gridLayouts([
        'two-columns',
        'three-columns',
        'four-columns',
        'five-columns',
        'fixed-two-columns',
        'fixed-three-columns',
        'fixed-four-columns',
        'fixed-five-columns',
        'asymmetric-left-thirds',
        'asymmetric-right-thirds',
        'asymmetric-left-fourths',
        'asymmetric-right-fourths',
    ]);

自定义块

注意 使用自定义块时,必须将内容存储为JSON。

您需要创建3个组件来为Tiptap编辑器创建自定义块。

  • 一个扩展TiptapBlock并定义块设置的块类。
  • 一个'预览'blade文件
  • 一个'rendered'blade文件

创建自定义块

块类

use FilamentTiptapEditor\TiptapBlock;

class BatmanBlock extends TiptapBlock
{
    public string $preview = 'blocks.previews.batman';

    public string $rendered = 'blocks.rendered.batman';

    public function getFormSchema(): array
    {
        return [
            TextInput::make('name'),
            TextInput::make('color'),
            Select::make('side')
                ->options([
                    'Hero' => 'Hero',
                    'Villain' => 'Villain',
                ])
                ->default('Hero')
        ];
    }
}

静态块

如果您只需要一个占位符来输出没有设置的块,您只需不提供getFormSchema方法即可,这样将不会显示模态,块将直接插入到编辑器中。

use FilamentTiptapEditor\TiptapBlock;

class StaticBlock extends TiptapBlock
{
    public string $preview = 'blocks.previews.static';

    public string $rendered = 'blocks.rendered.static';
}

模态宽度、悬停和图标

注意:目前,图标仅在拖放块面板上显示。

class BatmanBlock extends TiptapBlock
{
    public string $width = 'xl';
    
    public bool $slideOver = true;
    
    public ?string $icon = 'heroicon-o-film';
}

预览视图

预览视图只是标准的blade视图。不幸的是,您无法在块预览中使用Livewire组件,因为由于编辑器必须使用wire:ignore,它们将无法正确工作。

resources/views/blocks/previews/batman.blade.php

<div class="flex items-center gap-6">
    <div class="text-5xl">
        @php
            echo match($name) {
                'robin' => '🐤',
                'ivy' => '🥀',
                'joker' => '🤡',
                default => '🦇'
            }
        @endphp
    </div>
    <div>
        <p>Name: {{ $name }}</p>
        <p style="color: {{ $color }};">Color: {{ $color }}</p>
        <p>Side: {{ $side ?? 'Good' }}</p>
    </div>
</div>

渲染视图

渲染视图是正常的blade文件,也可以用来输出带有块数据的Livewire组件。

resources/views/blocks/rendered/batman.blade.php

<div>
    <livewire:batman-block
        :name="$name"
        :color="$color"
        :side="$side"
    />
</div>

将块注册到编辑器

在服务提供者的register方法中,您可以通过configureUsing将您的块添加到编辑器中。

注意 您还需要在tiptap配置中适当位置添加'blocks'键到您的配置文件中的配置文件。

use App\TiptapBlocks\BatmanBlock;
use App\TiptapBlocks\StaticBlock;
use FilamentTiptapEditor\TiptapEditor;

TiptapEditor::configureUsing(function (TiptapEditor $component) {
    $component
        ->blocks([
            BatmanBlock::class,
            StaticBlock::class,
        ]);
});

默认情况下,拖放块面板将在编辑器中打开。如果您想改变这一点,您可以在Editor实例上使用collapseBlocksPanel修饰符或在全局上使用configureUsing

use App\TiptapBlocks\BatmanBlock;
use App\TiptapBlocks\StaticBlock;
use FilamentTiptapEditor\TiptapEditor;

TiptapEditor::configureUsing(function (TiptapEditor $component) {
    $component
        ->collapseBlocksPanel()
        ->blocks([...]);
});

合并标签

合并标签可以与基于JSON的编辑器内容一起使用,以动态内容替换占位符。合并标签在编辑器实例的mergeTags()方法中定义

TiptapEditor::make('content')
    ->mergeTags([
        'first_name',
        'last_name',
    ])

要插入合并标签,用户可以键入{{来打开自动完成菜单,或者从“块面板”中将合并标签拖动到编辑器中。您可以使用showMergeTagsInBlocksPanel(false)从块面板中删除标签

TiptapEditor::make('content')
    ->mergeTags([...])
    ->showMergeTagsInBlocksPanel(false)

渲染合并标签

虽然您可以完全控制合并标签内容的替换方式,但您可以使用tiptap_converter辅助程序的mergeTagsMap()方法用提供的数据替换标签

{!! tiptap_converter()->mergeTagsMap(['first_name' => 'John', 'last_name' => 'Doe'])->asHTML($content) !!}

在独立表单包中的使用

如果您正在使用任何需要模态框的工具(例如插入媒体、插入视频等),请确保在自定义表单后添加{{ $this->modal }}到您的视图

<form wire:submit.prevent="submit">
    {{ $this->form }}

    <button type="submit">
        Save
    </button>
</form>

{{ $this->modal }}

自定义扩展

您可以通过创建必要的文件并将它们添加到配置文件扩展数组中,将自定义扩展添加到编辑器中。

这仅支持CSS和JS与Vite。

您可以在https://tiptap.dev/guide/custom-extensions上阅读有关自定义扩展的更多信息。

JS

首先,在resources/js/tiptap下创建您自定义扩展的目录,并添加您的扩展文件。

import { Node, mergeAttributes } from "@tiptap/core";

const Hero = Node.create({
    name: "hero",
    ...
})

export default Hero

接下来,在resources/js/tiptap/extensions.js中创建一个文件,并添加以下代码。

请注意,当将扩展添加到数组时,您必须以键:数组的形式注册它们。

import Hero from "./hero.js";

window.TiptapEditorExtensions = {
    hero: [Hero]
}

CSS

为您的自定义扩展在resources/css/tiptap/extensions.css中创建一个CSS文件。所有样式都应限制在.tiptap-content的父类中。

.tiptap-content {
    .hero-block {
        ...
    }
}

Vite配置

现在您需要将这些添加到您的vite.config.js文件中,并运行构建以生成文件。

export default defineConfig({
    plugins: [
        laravel({
            input: [
                ...
                'resources/js/tiptap/extensions.js',
                'resources/css/tiptap/extensions.css',
            ],
            refresh: true,
        }),
    ],
});

PHP解析器

您还需要创建您扩展的PHP版本,以便从数据库中读取内容并在编辑器或前端显示中渲染。您可以在应用程序的任何位置创建此版本,例如在app/TiptapExtensions/YourExtenion.php中。

您可以在https://github.com/ueberdosis/tiptap-php上阅读有关PHP解析器的更多信息。

namespace App\TiptapExtensions;

use Tiptap\Core\Node;

class Hero extends Node
{
    public static $name = 'hero';
    ...
}

工具栏按钮

您还需要为工具栏按钮创建一个专用视图。此视图应放置在应用程序的resources/views/components目录中的某个位置。您可以根据自己的需要编写按钮代码,但建议使用插件的视图组件以保持一致性。

<x-filament-tiptap-editor::button
    label="Hero"
    active="hero"
    action="editor().commands.toggleHero()"
>
    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"><path fill="currentColor" d="M5 21q-.825 0-1.413-.588T3 19V5q0-.825.588-1.413T5 3h14q.825 0 1.413.588T21 5v14q0 .825-.588 1.413T19 21H5Zm0-2h14v-5H5v5Z"/></svg>
    
    <span class="sr-only">{{ $label }}</span>
</x-filament-tiptap-editor::button>

注册扩展

最后,您需要在配置文件中注册您的扩展,并将新的扩展添加到适当的profile中。

'profiles' => [
    'minimal' => [
        ..., 
        'hero',
    ],
],
'extensions_script' => 'resources/js/tiptap/extensions.js',
'extensions_styles' => 'resources/css/tiptap/extensions.css',
'extensions' => [
    [
        'id' => 'hero',
        'name' => 'Hero',
        'button' => 'tools.hero',
        'parser' => \App\TiptapExtensions\Hero::class,
    ],
],

版本控制

此项目遵循语义版本控制指南。

许可协议

版权所有(c)2022 Adam Weston和贡献者

在MIT许可协议下发布,有关详细信息,请参阅LICENSE.md