vault backup: 2025-04-20 01:56:43
This commit is contained in:
8
.obsidian/workspace.json
vendored
8
.obsidian/workspace.json
vendored
@@ -41,12 +41,12 @@
|
|||||||
"state": {
|
"state": {
|
||||||
"type": "markdown",
|
"type": "markdown",
|
||||||
"state": {
|
"state": {
|
||||||
"file": "PERSONAL PROJECTS/PS1 DOCS/PS1 Gamepad.md",
|
"file": "WORK & PROJECTS/Mol/Code Chunks/TipTap Plugin.md",
|
||||||
"mode": "source",
|
"mode": "source",
|
||||||
"source": false
|
"source": false
|
||||||
},
|
},
|
||||||
"icon": "lucide-file",
|
"icon": "lucide-file",
|
||||||
"title": "PS1 Gamepad"
|
"title": "TipTap Plugin"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -207,6 +207,8 @@
|
|||||||
},
|
},
|
||||||
"active": "dd912cc876184c4f",
|
"active": "dd912cc876184c4f",
|
||||||
"lastOpenFiles": [
|
"lastOpenFiles": [
|
||||||
|
"PERSONAL PROJECTS/PS1 DOCS/PS1 Gamepad.md",
|
||||||
|
"WORK & PROJECTS/Mol/Code Chunks/TipTap Plugin.md",
|
||||||
"PERSONAL PROJECTS/P2EP/pseudoCode/FUN_800453e0 SystemEventManager.md",
|
"PERSONAL PROJECTS/P2EP/pseudoCode/FUN_800453e0 SystemEventManager.md",
|
||||||
"PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80015674 Update Entity Stats.md",
|
"PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80015674 Update Entity Stats.md",
|
||||||
"PERSONAL PROJECTS/P2EP/pseudoCode/MakeSmallChar.md",
|
"PERSONAL PROJECTS/P2EP/pseudoCode/MakeSmallChar.md",
|
||||||
@@ -216,7 +218,6 @@
|
|||||||
"PERSONAL PROJECTS/P2EP/pseudoCode",
|
"PERSONAL PROJECTS/P2EP/pseudoCode",
|
||||||
"PERSONAL PROJECTS/PS1 DOCS/Untitled",
|
"PERSONAL PROJECTS/PS1 DOCS/Untitled",
|
||||||
"PERSONAL PROJECTS/PS1 DOCS/fade calculation.md",
|
"PERSONAL PROJECTS/PS1 DOCS/fade calculation.md",
|
||||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 Gamepad.md",
|
|
||||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 Gpu-DMA.md",
|
"PERSONAL PROJECTS/PS1 DOCS/PS1 Gpu-DMA.md",
|
||||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 Ordering table.md",
|
"PERSONAL PROJECTS/PS1 DOCS/PS1 Ordering table.md",
|
||||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 DMA.md",
|
"PERSONAL PROJECTS/PS1 DOCS/PS1 DMA.md",
|
||||||
@@ -239,7 +240,6 @@
|
|||||||
"WORK & PROJECTS/Mol/Планы и диаграммы/Разработка - ЭПИКИ.md",
|
"WORK & PROJECTS/Mol/Планы и диаграммы/Разработка - ЭПИКИ.md",
|
||||||
"WORK & PROJECTS/Mol/Планы и диаграммы/00001_Редактор_форм/Таблицы нумератора и документов.canvas",
|
"WORK & PROJECTS/Mol/Планы и диаграммы/00001_Редактор_форм/Таблицы нумератора и документов.canvas",
|
||||||
"WORK & PROJECTS/Mol/Планы и диаграммы/Схема связей юрлиц и адресов.canvas",
|
"WORK & PROJECTS/Mol/Планы и диаграммы/Схема связей юрлиц и адресов.canvas",
|
||||||
"WORK & PROJECTS/Mol/Разработка - ЭПИКИ.md",
|
|
||||||
"WORK & PROJECTS/Mol/Планы и диаграммы/00001_Редактор_форм/Архитектура редактора и генератора (Alfa + Mol).canvas",
|
"WORK & PROJECTS/Mol/Планы и диаграммы/00001_Редактор_форм/Архитектура редактора и генератора (Alfa + Mol).canvas",
|
||||||
"WORK & PROJECTS/Mol/Планы и диаграммы/Alfa Cloud/Alfa cloud prod.canvas",
|
"WORK & PROJECTS/Mol/Планы и диаграммы/Alfa Cloud/Alfa cloud prod.canvas",
|
||||||
"WORK & PROJECTS/Mol/Планы и диаграммы/00001_Быстрый старт/Быстрый старт.canvas",
|
"WORK & PROJECTS/Mol/Планы и диаграммы/00001_Быстрый старт/Быстрый старт.canvas",
|
||||||
|
|||||||
183
WORK & PROJECTS/Mol/Code Chunks/TipTap Plugin.md
Normal file
183
WORK & PROJECTS/Mol/Code Chunks/TipTap Plugin.md
Normal 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).
|
||||||
|
- **Готовые команды** для управления колонтитулами.
|
||||||
Reference in New Issue
Block a user