You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
278 lines
9.0 KiB
278 lines
9.0 KiB
<script setup> |
|
import { ref, onMounted, onBeforeUnmount, defineProps, defineEmits } from 'vue' |
|
import { Editor, EditorContent } from '@tiptap/vue-3' |
|
import StarterKit from '@tiptap/starter-kit' |
|
import TextAlign from '@tiptap/extension-text-align' |
|
import Underline from '@tiptap/extension-underline' |
|
import Highlight from '@tiptap/extension-highlight' |
|
import TextStyle from '@tiptap/extension-text-style' |
|
import Mention from '@tiptap/extension-mention' |
|
import Color from '@tiptap/extension-color' |
|
import Link from '@tiptap/extension-link' |
|
import Placeholder from '@tiptap/extension-placeholder' |
|
import Typography from '@tiptap/extension-typography' |
|
import CharacterCount from '@tiptap/extension-character-count' |
|
import Image from '@tiptap/extension-image' |
|
import TaskList from '@tiptap/extension-task-list' |
|
import TaskItem from '@tiptap/extension-task-item' |
|
import Table from '@tiptap/extension-table' |
|
import TableRow from '@tiptap/extension-table-row' |
|
import TableCell from '@tiptap/extension-table-cell' |
|
import TableHeader from '@tiptap/extension-table-header' |
|
|
|
import Tabs from './Tabs.vue' |
|
import TextTab from './Tabs/TextTab.vue' |
|
import BlockTab from './Tabs/BlockTab.vue' |
|
import ListTab from './Tabs/ListTab.vue' |
|
import MediaTab from './Tabs/MediaTab.vue' |
|
import TableTab from './Tabs/TableTab.vue' |
|
import HistoryTab from './Tabs/HistoryTab.vue' |
|
import BubbleMenu from './BubbleMenu.vue' |
|
import FloatingMenu from './FloatingMenu.vue' |
|
|
|
const props = defineProps({ |
|
content: { |
|
type: Object || String, |
|
default: ` |
|
<h2 style="text-align: left">Bienvenue dans l'éditeur de page ✨</h2> |
|
<p style="text-align: left">Voici les fonctionnalités disponibles :</p> |
|
<h3 style="text-align: left">1. Mise en forme de texte</h3> |
|
<p style="text-align: left">Essayez les boutons de la barre d'outils pour :</p> |
|
<ul> |
|
<li><p style="text-align: left"><strong>Gras</strong> (Ctrl+B)</p></li> |
|
<li><p style="text-align: left"><em>Italique</em> (Ctrl+I)</p></li> |
|
<li><p style="text-align: left"><s>Barré</s></p></li> |
|
<li><p style="text-align: left">et plein d'autre</p></li> |
|
</ul> |
|
<h3 style="text-align: left">2. Titres et hiérarchie</h3> |
|
<p style="text-align: left">Utilisez le menu déroulant pour choisir parmi 4 niveaux de titres</p> |
|
<h1 style="text-align: left">Titre 1</h1> |
|
<h2 style="text-align: left">Titre 2</h2> |
|
<h3 style="text-align: left">Titre 3</h3> |
|
<h4 style="text-align: left">Titre 4</h4> |
|
<h3 style="text-align: left">3. Listes</h3> |
|
<ul> |
|
<li><p style="text-align: left">Liste à puces</p></li> |
|
<li> |
|
<p style="text-align: left">Structurez votre contenu</p> |
|
<ul> |
|
<li><p style="text-align: left">Liste dans une liste </p></li> |
|
</ul> |
|
</li> |
|
</ul> |
|
<ol> |
|
<li><p style="text-align: left">Liste numérotée</p></li> |
|
<li><p style="text-align: left">Étapes séquentielles</p></li> |
|
</ol> |
|
<h3 style="text-align: left">4. Element (Conteneur)</h3> |
|
<p style="text-align: left">Les <em>conteneurs </em>structurent les éléments visuels de manière <strong>isolée</strong> et <strong>cohérente</strong>.</p> |
|
<p style="text-align: left">Quelques examples :</p> |
|
<blockquote> |
|
<p style="text-align: left">Voici une citation</p> |
|
<p style="text-align: left">- Vinayak Ambigapathy 2025</p> |
|
</blockquote> |
|
<p style="text-align: left"><br class="ProseMirror-trailingBreak"></p> |
|
<pre> |
|
<code>Voici une note </code> |
|
</pre> |
|
<p style="text-align: left">D’autre element arriverons bientot pour vous permettre de faire des page manifique.</p> |
|
<h3>5. Tableaux structurés</h3> |
|
<p>Créez des tableaux :</p> |
|
<table class="demo-table"> |
|
<thead> |
|
<tr> |
|
<th>Fonctionnalité</th> |
|
<th>Raccourci</th> |
|
<th>Exemple</th> |
|
</tr> |
|
</thead> |
|
<tbody> |
|
<tr> |
|
<td>Ligne horizontale</td> |
|
<td>Ctrl+Shift+H</td> |
|
<td><hr></td> |
|
</tr> |
|
<tr> |
|
<td>Cellule de titre</td> |
|
<td>Toujour en gras et au bord du tableau avec la cellule grisé</td> |
|
<th>Titre</th> |
|
</tr> |
|
<tr> |
|
<td>Cellule standard</td> |
|
<td>La classique</td> |
|
<td>Contenu</td> |
|
</tr> |
|
</tbody> |
|
<tfoot> |
|
<tr> |
|
<td colspan="3">Astuce : Utilisez Tab pour naviguer entre les cellules</td> |
|
</tr> |
|
</tfoot> |
|
</table> |
|
|
|
<p>Fonctionnalités disponibles :</p> |
|
<ul> |
|
<li>Insertion/suppression de lignes/colonnes</li> |
|
<li>Fusion/séparation de cellules</li> |
|
<li>Alignement du contenu</li> |
|
</ul> |
|
<p>Certaines de ces fonctionnalité ne fonctionne pas encore au mieux mais cela devrait changer bientot.</p> |
|
<h3 style="text-align: left">6. Raccourcis clavier</h3> |
|
<p style="text-align: left">Voici quelque racourci clavier. Essayez ces combinaisons :</p> |
|
<ul> |
|
<li><p style="text-align: left">Ctrl+Z → Annuler</p></li> |
|
<li><p style="text-align: left">Ctrl+Shift+Z → Rétablir</p></li> |
|
<li><p style="text-align: left">Ctrl+Shift+8 → Liste à puces</p></li> |
|
<li><p style="text-align: left">Ctrl+Shift+7 → Liste numérotée</p></li> |
|
</ul> |
|
` |
|
}, |
|
editable: { |
|
type: Boolean, |
|
default: true, |
|
} |
|
}) |
|
|
|
const emit = defineEmits(['update']) |
|
const editor = ref(null) |
|
const edit = ref(props.editable); |
|
const activeTab = ref('text') |
|
|
|
defineExpose({ |
|
editable: (flag) => { |
|
edit.value = flag; |
|
editor.value.setEditable(flag) |
|
} |
|
}); |
|
|
|
const ImageAlign = Image.extend({ |
|
addAttributes() { |
|
return { |
|
...this.parent?.(), |
|
alignment: { |
|
default: 'left', |
|
renderHTML: attributes => { |
|
return { |
|
class: `image-align-${attributes.alignment}`, |
|
} |
|
}, |
|
}, |
|
} |
|
}, |
|
}) |
|
|
|
// Initialize editor |
|
onMounted(() => { |
|
editor.value = new Editor({ |
|
content: props.content, |
|
editorProps: { |
|
attributes: { |
|
class: 'tiptap-editor', |
|
}, |
|
}, |
|
extensions: [ |
|
StarterKit.configure({ |
|
heading: { levels: [1, 2, 3, 4] } |
|
}), |
|
Underline, |
|
Mention.configure({ |
|
HTMLAttributes: { |
|
class: 'mention', |
|
}, |
|
suggestion: { |
|
items: ({ query }) => { |
|
return [ |
|
"Tax", "Padda", "Example" |
|
] |
|
} |
|
}, |
|
}), |
|
Highlight.configure({ |
|
multicolor: true |
|
}), |
|
TextStyle, |
|
TextAlign.configure({ |
|
types: ['heading', 'paragraph'], |
|
alignments: ['left', 'center', 'right', 'justify'], |
|
defaultAlignment: 'left', |
|
}), |
|
Color, |
|
CharacterCount, |
|
//Gapcursor, |
|
Link.configure({ |
|
openOnClick: false, |
|
autolink: true |
|
}), |
|
Placeholder.configure({ |
|
placeholder: 'Texte...' |
|
}), |
|
Typography, |
|
ImageAlign.configure({ |
|
inline: true, |
|
allowBase64: true |
|
}), |
|
TaskList, |
|
TaskItem.configure({ |
|
nested: true |
|
}), |
|
Table.configure({ |
|
resizable: true |
|
}), |
|
TableRow, |
|
TableCell, |
|
TableHeader |
|
], |
|
onUpdate: ({ editor }) => { |
|
emit('update', { |
|
html: editor.getHTML(), |
|
json: editor.getJSON() |
|
}) |
|
} |
|
}); |
|
editor.value.setEditable(edit); |
|
emit('update', { |
|
html: editor.value.getHTML(), |
|
json: editor.value.getJSON() |
|
}) |
|
}) |
|
|
|
// Clean up |
|
onBeforeUnmount(() => { |
|
if (editor.value) { |
|
editor.value.destroy() |
|
} |
|
}) |
|
</script> |
|
<template> |
|
<div v-if="editor" class="notion-editor-container"> |
|
<!-- Toolbar based on active tab --> |
|
<div v-show="edit" class="sticky top-0 pt-16 right-0 left-0 z-10 bg-white border-b border-gray-200 py-2 flex space-x-2 flex-wrap"> |
|
<Tabs @active="(tab) => activeTab = tab"/> |
|
<TextTab v-show="activeTab == 'text'" :editor="editor" /> |
|
<BlockTab v-show="activeTab == 'blocks'" :editor="editor"/> |
|
<ListTab v-show="activeTab == 'lists'" :editor="editor"/> |
|
<MediaTab v-show="activeTab == 'media'" :editor="editor"/> |
|
<TableTab v-show="activeTab == 'tables'" :editor="editor"/> |
|
<HistoryTab v-show="activeTab == 'history'" :editor="editor"/> |
|
</div> |
|
<BubbleMenu v-show="edit" :editor="editor" /> |
|
<!-- Floating Menu for Block Types --> |
|
<FloatingMenu v-show="edit" :editor="editor" /> |
|
<!-- Editor Content --> |
|
<editor-content |
|
:editor="editor" |
|
:class="'tiptap-editor min-h-[500px] h-full bg-white shadow-md'" |
|
/> |
|
<div class="sticky bottom-0 right-0 left-0 z-10 |
|
bg-white border-t border-gray-200 p-2 flex space-x-2 |
|
text-sm text-gray-700"> |
|
<p>{{ editor.storage.characterCount.words() }} words</p> |
|
<p>|</p> |
|
<p>{{ editor.storage.characterCount.characters() }} characters</p> |
|
</div> |
|
</div> |
|
</template> |
|
|
|
|
|
<style> |
|
</style> |