384 lines
No EOL
26 KiB
PHP
384 lines
No EOL
26 KiB
PHP
<div x-data="blockEditor(@js($publication->blocks))"
|
||
x-init="init()"
|
||
class="space-y-3 transition-all duration-300">
|
||
|
||
|
||
|
||
<template x-for="(block, index) in blocks" :key="block._key">
|
||
<div class="block-card group relative bg-white border border-gray-200 rounded-lg transition-all duration-300"
|
||
@dragover.prevent="onDragOver(index, $event)"
|
||
@drop="onDrop(index, $event)"
|
||
:class="{
|
||
'ring-2 ring-indigo-400 shadow-lg z-10': isFocused(block._key),
|
||
'opacity-50': focusedBlockKey && !isFocused(block._key),
|
||
'border-indigo-400 border-dashed bg-indigo-50/30': dragIndex !== null && dragIndex !== index,
|
||
'opacity-40': dragIndex === index,
|
||
}"
|
||
:data-block-key="block._key">
|
||
|
||
{{-- Hover-reveal block handle and delete --}}
|
||
<div class="block-handle absolute -left-1 top-3 -translate-x-full opacity-0 group-hover:opacity-100 transition-opacity flex flex-col items-center gap-1 z-20"
|
||
:class="{ 'opacity-100': isFocused(block._key) }">
|
||
<span class="text-gray-400 hover:text-gray-500 cursor-grab text-xs leading-none select-none"
|
||
draggable="true"
|
||
@dragstart="onDragStart(index, $event)"
|
||
@dragend="onDragEnd()"
|
||
title="Drag to reorder">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
||
<path d="M0 0h24v24H0z" fill="none" />
|
||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M5.7 9.3L3 12m0 0l2.7 2.7M3 12h18M9.3 5.7L12 3m0 0l2.7 2.7M12 3v18m2.7-2.7L12 21m0 0l-2.7-2.7m9-9L21 12m0 0l-2.7 2.7" />
|
||
</svg>
|
||
</span>
|
||
<span class="text-[10px] text-gray-400 uppercase tracking-wider font-medium rotate-180"
|
||
style="writing-mode: vertical-rl;"
|
||
x-text="block.type === 'rich_text' ? 'Text' : block.type.replace(/_/g, ' ')"></span>
|
||
</div>
|
||
|
||
<div class="block-handle absolute right-24 -bottom-4 translate-x-full opacity-0 group-hover:opacity-100 transition-opacity z-20"
|
||
:class="{ 'opacity-100': isFocused(block._key) }">
|
||
<button type="button" class="group/remove flex items-center gap-1" @click="removeBlock(index)">
|
||
<span class="text-gray-300 group-hover/remove:text-red-700 group-hover/remove:cursor-pointer text-sm leading-none select-none"
|
||
title="Delete block">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
||
<path d="M0 0h24v24H0z" fill="none" />
|
||
<path fill="currentColor" d="M7 21q-.825 0-1.412-.587T5 19V6H4V4h5V3h6v1h5v2h-1v13q0 .825-.587 1.413T17 21zM17 6H7v13h10zM9 17h2V8H9zm4 0h2V8h-2zM7 6v13z" />
|
||
</svg>
|
||
</span>
|
||
<span class="text-[10px] text-gray-300 group-hover/remove:text-red-700 group-hover/remove:cursor-pointer tracking-wider font-medium rotate-360"
|
||
>
|
||
Remove block
|
||
</span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="p-1">
|
||
|
||
{{-- ============ RICH TEXT ============ --}}
|
||
<div x-show="block.type === 'rich_text'" class="space-y-0">
|
||
|
||
{{-- Slim toolbar (single row) --}}
|
||
<div class="slim-toolbar flex items-center gap-0.5 pb-2 mb-2 border-b border-gray-100 flex-wrap"
|
||
@mousedown.prevent>
|
||
|
||
{{-- Undo / Redo --}}
|
||
<button type="button" @click="editorAction(block._key, 'undo')"
|
||
:disabled="!editorState(block._key).canUndo"
|
||
class="tbtn" title="Undo (Ctrl+Z)">↶</button>
|
||
<button type="button" @click="editorAction(block._key, 'redo')"
|
||
:disabled="!editorState(block._key).canRedo"
|
||
class="tbtn" title="Redo (Ctrl+Y)">↷</button>
|
||
|
||
<span class="tdiv"></span>
|
||
|
||
{{-- Inline formatting --}}
|
||
<button type="button" @click="editorAction(block._key, 'bold')"
|
||
:class="{ 'tbtn-active': editorState(block._key).bold }"
|
||
class="tbtn font-bold" title="Bold (Ctrl+B)">B</button>
|
||
<button type="button" @click="editorAction(block._key, 'italic')"
|
||
:class="{ 'tbtn-active': editorState(block._key).italic }"
|
||
class="tbtn italic" title="Italic (Ctrl+I)">I</button>
|
||
<button type="button" @click="editorAction(block._key, 'strike')"
|
||
:class="{ 'tbtn-active': editorState(block._key).strike }"
|
||
class="tbtn line-through" title="Strikethrough">S</button>
|
||
<button type="button" @click="editorAction(block._key, 'code')"
|
||
:class="{ 'tbtn-active': editorState(block._key).code }"
|
||
class="tbtn font-mono text-xs" title="Inline code"></></button>
|
||
|
||
<span class="tdiv"></span>
|
||
|
||
{{-- Block type --}}
|
||
<button type="button"
|
||
:class="{ 'tbtn-active': editorState(block._key).paragraph && !editorState(block._key).activeHeadingLevel }"
|
||
@click="editorAction(block._key, 'paragraph')"
|
||
class="tbtn text-xs" title="Paragraph">¶</button>
|
||
<button type="button"
|
||
:class="{ 'tbtn-active': editorState(block._key).h2 }"
|
||
@click="editorAction(block._key, 'h2')"
|
||
class="tbtn text-xs font-bold" title="Heading 2">H2</button>
|
||
<button type="button"
|
||
:class="{ 'tbtn-active': editorState(block._key).h3 }"
|
||
@click="editorAction(block._key, 'h3')"
|
||
class="tbtn text-xs font-semibold" title="Heading 3">H3</button>
|
||
|
||
<span class="tdiv"></span>
|
||
|
||
{{-- Lists --}}
|
||
<button type="button"
|
||
:class="{ 'tbtn-active': editorState(block._key).bulletList }"
|
||
@click="editorAction(block._key, 'bullet')"
|
||
class="tbtn" title="Bullet list">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
||
<path d="M0 0h24v24H0z" fill="none" />
|
||
<path fill="currentColor" d="M2 5h3v3H2zm0 6h3v3H2zm0 6h3v3H2zm6 1h14v1H8zM8 6h14v1H8zm0 6h14v1H8z" />
|
||
</svg>
|
||
</button>
|
||
<button type="button"
|
||
:class="{ 'tbtn-active': editorState(block._key).orderedList }"
|
||
@click="editorAction(block._key, 'ordered')"
|
||
class="tbtn text-xs" title="Numbered list">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 32 32">
|
||
<path d="M0 0h32v32H0z" fill="none" />
|
||
<path fill="currentColor" d="M16 22h14v2H16zm0-14h14v2H16zm-8 4V4H6v1H4v2h2v5H4v2h6v-2zm2 16H4v-4a2 2 0 0 1 2-2h2v-2H4v-2h4a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H6v2h4Z" />
|
||
</svg>
|
||
</button>
|
||
|
||
<span class="tdiv"></span>
|
||
|
||
{{-- Block elements --}}
|
||
<button type="button"
|
||
:class="{ 'tbtn-active': editorState(block._key).blockquote }"
|
||
@click="editorAction(block._key, 'blockquote')"
|
||
class="tbtn" title="Blockquote">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
||
<path d="M0 0h24v24H0z" fill="none" />
|
||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 15h15m0 4H6m9-8h6m0-4h-6M9 9h1a1 1 0 1 1-1 1V7.5a2 2 0 0 1 2-2M3 9h1a1 1 0 1 1-1 1V7.5a2 2 0 0 1 2-2" />
|
||
</svg>
|
||
</button>
|
||
<button type="button"
|
||
:class="{ 'tbtn-active': editorState(block._key).codeBlock }"
|
||
@click="editorAction(block._key, 'codeBlock')"
|
||
class="tbtn font-mono text-xs" title="Code block">{ }</button>
|
||
|
||
<span class="tdiv"></span>
|
||
|
||
{{-- Media --}}
|
||
<button type="button"
|
||
:class="{ 'tbtn-active': editorState(block._key).link }"
|
||
@click="setLink(block._key)"
|
||
class="tbtn" title="Add link">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
||
<path d="M0 0h24v24H0z" fill="none" />
|
||
<path fill="none" stroke="currentColor" stroke-dasharray="28" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 6l2 -2c1 -1 3 -1 4 0l1 1c1 1 1 3 0 4l-5 5c-1 1 -3 1 -4 0M11 18l-2 2c-1 1 -3 1 -4 0l-1 -1c-1 -1 -1 -3 0 -4l5 -5c1 -1 3 -1 4 0">
|
||
<animate fill="freeze" attributeName="stroke-dashoffset" dur="0.6s" values="28;0" />
|
||
</path>
|
||
</svg>
|
||
</button>
|
||
<button type="button"
|
||
@click="insertImage(block._key)"
|
||
class="tbtn" title="Insert image">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
||
<path d="M0 0h24v24H0z" fill="none" />
|
||
<path fill="currentColor" d="M5 21q-.825 0-1.412-.587T3 19V5q0-.825.588-1.412T5 3h14q.825 0 1.413.588T21 5v14q0 .825-.587 1.413T19 21zm0-2h14V5H5zm0 0V5zm2-2h10q.3 0 .45-.275t-.05-.525l-2.75-3.675q-.15-.2-.4-.2t-.4.2L11.25 16L9.4 13.525q-.15-.2-.4-.2t-.4.2l-2 2.675q-.2.25-.05.525T7 17" />
|
||
</svg>
|
||
</button>
|
||
|
||
<span class="tdiv"></span>
|
||
|
||
{{-- Table --}}
|
||
<button type="button"
|
||
:class="{ 'tbtn-active': editorState(block._key).table }"
|
||
@click="editorState(block._key).table
|
||
? getEditor(block._key)?.chain().deleteTable().run()
|
||
: getEditor(block._key)?.chain().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()"
|
||
class="tbtn" title="Toggle table">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
||
<path d="M0 0h24v24H0z" fill="none" />
|
||
<path fill="currentColor" d="M6 5h11a3 3 0 0 1 3 3v9a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V8a3 3 0 0 1 3-3M4 17a2 2 0 0 0 2 2h5v-3H4zm7-5H4v3h7zm6 7a2 2 0 0 0 2-2v-1h-7v3zm2-7h-7v3h7zM4 11h7V8H4zm8 0h7V8h-7z" />
|
||
</svg>
|
||
</button>
|
||
|
||
<span class="tdiv"></span>
|
||
|
||
{{-- Clear marks --}}
|
||
<button type="button" @click="editorAction(block._key, 'clearMarks')"
|
||
class="tbtn text-[10px] text-gray-400" title="Clear formatting">
|
||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 16 16">
|
||
<path d="M0 0h16v16H0z" fill="none" />
|
||
<path fill="currentColor" d="M2.958 2a.75.75 0 0 0-.727.568l-.236.945a.75.75 0 0 0 1.455.363l.094-.376h2.024l-1.225 7h-.388a.75.75 0 0 0 0 1.5h2.067a5.6 5.6 0 0 1 .068-1.499l-.044-.001h-.18l1.224-7h2.227l-.003.013a.75.75 0 0 0 1.455.363l.236-.944A.75.75 0 0 0 10.278 2zM1.75 12.5h4.34A5.5 5.5 0 0 0 6.6 14H1.75a.75.75 0 0 1 0-1.5m14.25-1a4.5 4.5 0 1 1-9 0a4.5 4.5 0 0 1 9 0m-2.646-1.146a.5.5 0 0 0-.708-.708L11.5 10.793l-1.146-1.147a.5.5 0 0 0-.708.708l1.147 1.146l-1.147 1.146a.5.5 0 0 0 .708.708l1.146-1.147l1.146 1.147a.5.5 0 0 0 .708-.708L12.207 11.5z" />
|
||
</svg>
|
||
</button>
|
||
|
||
</div>
|
||
|
||
{{-- Editor area --}}
|
||
<div class="tiptap-editor-wrapper relative">
|
||
<div class="tiptap-editor min-h-48 text-sm prose max-w-none"
|
||
:class="{ 'min-h-96': isFocused(block._key) }"
|
||
x-init="mountTiptap($el, block)"></div>
|
||
|
||
</div>
|
||
|
||
{{-- Table helpers (shown when table is active) --}}
|
||
<div x-show="editorState(block._key).table" x-cloak
|
||
class="flex flex-wrap items-center gap-1 pt-2 border-t border-gray-100 mt-2">
|
||
<button type="button" @click="getEditor(block._key)?.chain().addColumnBefore().run()"
|
||
class="tbtn text-[10px]" title="Add column before">+←</button>
|
||
<button type="button" @click="getEditor(block._key)?.chain().addColumnAfter().run()"
|
||
class="tbtn text-[10px]" title="Add column after">+→</button>
|
||
<button type="button" @click="getEditor(block._key)?.chain().deleteColumn().run()"
|
||
class="tbtn text-[10px]" title="Delete column">−Col</button>
|
||
<button type="button" @click="getEditor(block._key)?.chain().addRowBefore().run()"
|
||
class="tbtn text-[10px]" title="Add row before">+↑</button>
|
||
<button type="button" @click="getEditor(block._key)?.chain().addRowAfter().run()"
|
||
class="tbtn text-[10px]" title="Add row after">+↓</button>
|
||
<button type="button" @click="getEditor(block._key)?.chain().deleteRow().run()"
|
||
class="tbtn text-[10px]" title="Delete row">−Row</button>
|
||
<button type="button" @click="getEditor(block._key)?.chain().mergeCells().run()"
|
||
class="tbtn text-[10px]">Merge</button>
|
||
<button type="button" @click="getEditor(block._key)?.chain().splitCell().run()"
|
||
class="tbtn text-[10px]">Split</button>
|
||
</div>
|
||
|
||
{{-- Image size controls (shown when image is selected) --}}
|
||
<div x-show="editorState(block._key).image" x-cloak
|
||
class="flex items-center gap-1 pt-2 border-t border-gray-100 mt-2">
|
||
<span class="text-[10px] text-gray-400 mr-1">Size:</span>
|
||
<button type="button" @click="setImageSize(block._key, 'img-xs')"
|
||
:class="{ 'tbtn-active': editorState(block._key).currentImageSize === 'img-xs' }"
|
||
class="tbtn text-[10px]">XS</button>
|
||
<button type="button" @click="setImageSize(block._key, 'img-sm')"
|
||
:class="{ 'tbtn-active': editorState(block._key).currentImageSize === 'img-sm' }"
|
||
class="tbtn text-[10px]">SM</button>
|
||
<button type="button" @click="setImageSize(block._key, 'img-md')"
|
||
:class="{ 'tbtn-active': editorState(block._key).currentImageSize === 'img-md' }"
|
||
class="tbtn text-[10px]">MD</button>
|
||
<button type="button" @click="setImageSize(block._key, 'img-lg')"
|
||
:class="{ 'tbtn-active': editorState(block._key).currentImageSize === 'img-lg' }"
|
||
class="tbtn text-[10px]">LG</button>
|
||
<button type="button" @click="setImageSize(block._key, 'img-full')"
|
||
:class="{ 'tbtn-active': editorState(block._key).currentImageSize === 'img-full' }"
|
||
class="tbtn text-[10px]">Full</button>
|
||
<span class="tdiv"></span>
|
||
<button type="button" @click="removeImage(block._key)"
|
||
class="tbtn text-[10px] text-red-400">✕ Remove</button>
|
||
</div>
|
||
|
||
<input type="hidden" :name="`blocks[${index}][content][content]`" x-model="block.content.content">
|
||
</div>
|
||
|
||
{{-- ============ IMAGE ============ --}}
|
||
<div x-show="block.type === 'image'" class="space-y-2">
|
||
<input type="text" :name="`blocks[${index}][content][url]`" x-model="block.content.url"
|
||
placeholder="Image URL"
|
||
class="w-full border border-gray-300 rounded px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
|
||
<div class="grid grid-cols-2 gap-2">
|
||
<input type="text" :name="`blocks[${index}][content][alt]`" x-model="block.content.alt"
|
||
placeholder="Alt text"
|
||
class="border border-gray-300 rounded px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
|
||
<input type="text" :name="`blocks[${index}][content][caption]`" x-model="block.content.caption"
|
||
placeholder="Caption"
|
||
class="border border-gray-300 rounded px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
|
||
</div>
|
||
<select :name="`blocks[${index}][content][style]`" x-model="block.content.style"
|
||
class="border border-gray-300 rounded px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
|
||
<option value="full">Full width</option>
|
||
<option value="contained">Contained</option>
|
||
<option value="float-left">Float left</option>
|
||
<option value="float-right">Float right</option>
|
||
</select>
|
||
</div>
|
||
|
||
{{-- ============ VIDEO ============ --}}
|
||
<div x-show="block.type === 'video'" class="space-y-2">
|
||
<input type="text" :name="`blocks[${index}][content][url]`" x-model="block.content.url"
|
||
placeholder="Video URL"
|
||
class="w-full border border-gray-300 rounded px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
|
||
<div class="grid grid-cols-2 gap-2">
|
||
<input type="text" :name="`blocks[${index}][content][title]`" x-model="block.content.title"
|
||
placeholder="Title"
|
||
class="border border-gray-300 rounded px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
|
||
<input type="text" :name="`blocks[${index}][content][caption]`" x-model="block.content.caption"
|
||
placeholder="Caption"
|
||
class="border border-gray-300 rounded px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ============ TAXONOMY LIST ============ --}}
|
||
<div x-show="block.type === 'taxonomy_list'" class="space-y-2">
|
||
<select :name="`blocks[${index}][content][taxonomy_term_id]`"
|
||
x-model="block.content.taxonomy_term_id"
|
||
class="w-full border border-gray-300 rounded px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
|
||
<option value="">— Select term —</option>
|
||
@foreach($channelTerms as $term)
|
||
<option value="{{ $term->id }}">{{ $term->title }}</option>
|
||
@endforeach
|
||
</select>
|
||
<div class="flex items-center gap-2">
|
||
<label class="text-xs text-gray-500">Limit</label>
|
||
<input type="number" :name="`blocks[${index}][content][limit]`" x-model="block.content.limit"
|
||
min="1" max="50"
|
||
class="w-20 border border-gray-300 rounded px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ============ POSTS CAROUSEL ============ --}}
|
||
<div x-show="block.type === 'posts_carousel'" class="space-y-2">
|
||
<input type="text" :name="`blocks[${index}][content][title]`" x-model="block.content.title"
|
||
placeholder="Section title"
|
||
class="w-full border border-gray-300 rounded px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
|
||
<div class="flex items-center gap-2">
|
||
<label class="text-xs text-gray-500">Limit</label>
|
||
<input type="number" :name="`blocks[${index}][content][limit]`" x-model="block.content.limit"
|
||
min="1" max="20"
|
||
class="w-20 border border-gray-300 rounded px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
{{-- Hidden control inputs --}}
|
||
<input type="hidden" :name="`blocks[${index}][type]`" x-model="block.type">
|
||
<input type="hidden" :name="`blocks[${index}][order]`" :value="index">
|
||
<input type="hidden" :name="`blocks[${index}][id]`" x-model="block.id">
|
||
</div>
|
||
</template>
|
||
|
||
{{-- Add block strip --}}
|
||
<div class="flex flex-wrap gap-2 pt-1">
|
||
<button type="button" @click="addBlock('rich_text')"
|
||
class="px-3 py-1.5 text-xs border border-dashed border-gray-300 rounded-lg hover:border-indigo-400 text-gray-500 hover:text-indigo-700 transition-colors">
|
||
+ Text
|
||
</button>
|
||
<button type="button" @click="addBlock('image')"
|
||
class="px-3 py-1.5 text-xs border border-dashed border-gray-300 rounded-lg hover:border-emerald-400 text-gray-500 hover:text-emerald-700 transition-colors">
|
||
+ Image
|
||
</button>
|
||
<button type="button" @click="addBlock('video')"
|
||
class="px-3 py-1.5 text-xs border border-dashed border-gray-300 rounded-lg hover:border-amber-400 text-gray-500 hover:text-amber-700 transition-colors">
|
||
+ Video
|
||
</button>
|
||
<button type="button" @click="addBlock('taxonomy_list')"
|
||
class="px-3 py-1.5 text-xs border border-dashed border-gray-300 rounded-lg hover:border-cyan-400 text-gray-500 hover:text-cyan-700 transition-colors">
|
||
+ Taxonomy list
|
||
</button>
|
||
<button type="button" @click="addBlock('posts_carousel')"
|
||
class="px-3 py-1.5 text-xs border border-dashed border-gray-300 rounded-lg hover:border-pink-400 text-gray-500 hover:text-pink-700 transition-colors">
|
||
+ Posts carousel
|
||
</button>
|
||
</div>
|
||
|
||
{{-- Focus mode hint --}}
|
||
<div x-show="focusedBlockKey" x-cloak
|
||
class="fixed bottom-4 right-4 bg-gray-900 text-white text-xs px-3 py-1.5 rounded-full shadow-lg z-50 opacity-80 pointer-events-none">
|
||
Press <kbd class="font-mono bg-white/20 px-1 rounded">Esc</kbd> to exit focus mode
|
||
</div>
|
||
|
||
{{-- Delete confirmation modal --}}
|
||
<div x-show="confirmDelete !== null" x-cloak
|
||
x-transition.opacity
|
||
@keydown.escape.window="cancelRemoveBlock()"
|
||
class="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
|
||
<div class="bg-white rounded-xl shadow-2xl p-6 w-full max-w-sm mx-4"
|
||
@click.outside="cancelRemoveBlock()">
|
||
<h3 class="text-lg font-semibold text-gray-900 mb-2">Delete block?</h3>
|
||
<p class="text-sm text-gray-500 mb-6">
|
||
This will permanently remove block
|
||
<span class="font-medium text-gray-700"
|
||
x-text="confirmDelete !== null ? blocks[confirmDelete].type.replace(/_/g, ' ') : ''"></span>
|
||
at position
|
||
<span class="font-medium text-gray-700" x-text="confirmDelete !== null ? confirmDelete + 1 : ''"></span>.
|
||
This action cannot be undone.
|
||
</p>
|
||
<div class="flex justify-end gap-3">
|
||
<button type="button" @click="cancelRemoveBlock()"
|
||
class="px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 rounded-lg hover:bg-gray-200 transition-colors">
|
||
Cancel
|
||
</button>
|
||
<button type="button" @click="confirmRemoveBlock()"
|
||
class="px-4 py-2 text-sm font-medium text-white bg-red-600 rounded-lg hover:bg-red-700 transition-colors">
|
||
Delete
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div> |