vault backup: 2025-04-20 01:56:43

This commit is contained in:
sShemet
2025-04-20 01:56:43 +05:00
parent 9913ce8b27
commit b1ff190a4a
2 changed files with 187 additions and 4 deletions

View File

@@ -0,0 +1,183 @@
Хорошо! Давайте создадим плагин для **Tiptap** во **Vue 3 (Composition API)**, который добавляет **колонтитул (footer)** как отдельный узел (`Node`), сохраняемый и загружаемый вместе с документом.
---
## **1. Создаём плагин для колонтитула (`FooterNode`)**
Сначала опишем сам узел (`Node`), который будет представлять колонтитул.
### **`FooterExtension.ts`**
```typescript
import { Node } from '@tiptap/core';
export const FooterExtension = Node.create({
name: 'footer', // Уникальное имя узла
group: 'block', // Группа (block, inline и т. д.)
content: 'inline*', // Разрешённый контент внутри (текст, ссылки и т. п.)
// Парсинг HTML → ProseMirror-узел
parseHTML() {
return [
{
tag: 'footer', // Будет парсить `<footer>` в документе
},
];
},
// Как узел будет отрендерен в HTML
renderHTML({ HTMLAttributes }) {
return ['footer', HTMLAttributes, 0]; // <footer>...</footer>
},
// Добавляем команды для работы с колонтитулом
addCommands() {
return {
setFooter:
(content) =>
({ commands }) => {
return commands.insertContent({
type: this.name,
content: [
{
type: 'text',
text: content || 'Текст колонтитула',
},
],
});
},
};
},
});
```
---
## **2. Подключаем плагин в редактор (Vue 3 Composition API)**
Теперь создадим компонент редактора с использованием **Vue 3 + Tiptap**.
### **`TiptapEditor.vue`**
```vue
<script setup lang="ts">
import { useEditor, EditorContent } from '@tiptap/vue-3';
import StarterKit from '@tiptap/starter-kit';
import { FooterExtension } from './FooterExtension';
const editor = useEditor({
extensions: [
StarterKit,
FooterExtension, // Подключаем наш плагин
],
content: `
<p>Основной контент документа...</p>
<footer>Колонтитул (подвал)</footer>
`,
});
// Функция для добавления колонтитула
const insertFooter = () => {
editor.value?.commands.setFooter('Новый текст колонтитула');
};
// Сохранение документа (например, в JSON)
const saveContent = () => {
const json = editor.value?.getJSON();
console.log(json);
// Можно отправить на сервер или сохранить в localStorage
};
</script>
<template>
<div class="editor">
<div v-if="editor" class="menu-bar">
<button @click="insertFooter">Добавить колонтитул</button>
<button @click="saveContent">Сохранить</button>
</div>
<EditorContent :editor="editor" />
</div>
</template>
<style>
.editor {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.menu-bar {
margin-bottom: 10px;
}
footer {
margin-top: 2rem;
padding: 1rem;
background: #f5f5f5;
border-top: 1px solid #ddd;
}
</style>
```
---
## **3. Как это работает?**
- **`FooterExtension`** определяет новый тип узла `<footer>`, который:
- Может содержать текст (`inline*`).
- Сохраняется в JSON при вызове `editor.getJSON()`.
- Загружается обратно при установке `editor.content`.
- **Команда `setFooter`** позволяет программно вставлять колонтитул.
- **Сохранение и загрузка** работают автоматически благодаря Tiptap.
---
## **4. Дополнительные улучшения**
### **Добавление атрибутов (например, даты в колонтитул)**
Можно расширить плагин, чтобы он поддерживал атрибуты:
```typescript
// В FooterExtension.ts
addAttributes() {
return {
date: {
default: new Date().toLocaleDateString(),
renderHTML: (attrs) => ({ 'data-date': attrs.date }),
},
};
},
```
Теперь при рендеринге будет:
```html
<footer data-date="2024-04-20">Текст колонтитула</footer>
```
### **Валидация структуры документа**
Если колонтитул должен быть **только в конце документа**, можно добавить проверку в `addCommands`:
```typescript
setFooter:
(content) =>
({ commands, state }) => {
const { doc } = state;
const lastNode = doc.lastChild;
// Если последний элемент уже footer — заменяем его
if (lastNode?.type.name === 'footer') {
return commands.insertContentAt(
doc.content.size - 1,
{
type: this.name,
content: [{ type: 'text', text: content }],
}
);
}
// Иначе добавляем в конец
return commands.insertContentAt(
doc.content.size,
{
type: this.name,
content: [{ type: 'text', text: content }],
}
);
},
```
---
## **Итог**
- **Кастомный узел `<footer>`**, который сохраняется и загружается с документом.
- **Интеграция с Vue 3** (Composition API).
- **Готовые команды** для управления колонтитулами.