All checks were successful
Deploy Quartz site to GitHub Pages / build (push) Successful in 2m29s
131 lines
4.4 KiB
JavaScript
131 lines
4.4 KiB
JavaScript
import { Editor } from '@tiptap/core';
|
|
import StarterKit from '@tiptap/starter-kit';
|
|
import { Markdown } from 'tiptap-markdown';
|
|
import Placeholder from '@tiptap/extension-placeholder';
|
|
import BubbleMenu from '@tiptap/extension-bubble-menu';
|
|
import './styles.css';
|
|
import 'remixicon/fonts/remixicon.css';
|
|
|
|
// DOM Elements
|
|
const saveBtn = document.getElementById('save-btn');
|
|
const editorContainer = document.getElementById('editor-container');
|
|
const bubbleMenuEl = document.getElementById('bubble-menu');
|
|
|
|
// Editor Instance
|
|
let editor;
|
|
let currentFileId = null;
|
|
|
|
// CSRF Helper
|
|
function getCookie(name) {
|
|
let cookieValue = null;
|
|
if (document.cookie && document.cookie !== '') {
|
|
const cookies = document.cookie.split(';');
|
|
for (let i = 0; i < cookies.length; i++) {
|
|
const cookie = cookies[i].trim();
|
|
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
|
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return cookieValue;
|
|
}
|
|
|
|
// Initialize Editor (only once)
|
|
function initEditor() {
|
|
// Bubble Menu Buttons
|
|
const btnBold = document.getElementById('btn-bold');
|
|
const btnItalic = document.getElementById('btn-italic');
|
|
const btnStrike = document.getElementById('btn-strike');
|
|
const btnCode = document.getElementById('btn-code');
|
|
|
|
editor = new Editor({
|
|
element: document.querySelector('#editor'),
|
|
extensions: [
|
|
StarterKit,
|
|
Markdown,
|
|
Placeholder.configure({
|
|
placeholder: "Type '/' for commands...",
|
|
}),
|
|
BubbleMenu.configure({
|
|
element: bubbleMenuEl,
|
|
tippyOptions: { duration: 100 },
|
|
}),
|
|
],
|
|
content: '',
|
|
editorProps: {
|
|
attributes: {
|
|
class: 'prose prose-sm sm:prose lg:prose-lg max-w-none focus:outline-none',
|
|
},
|
|
},
|
|
onSelectionUpdate({ editor }) {
|
|
btnBold?.classList.toggle('is-active', editor.isActive('bold'));
|
|
btnItalic?.classList.toggle('is-active', editor.isActive('italic'));
|
|
btnStrike?.classList.toggle('is-active', editor.isActive('strike'));
|
|
btnCode?.classList.toggle('is-active', editor.isActive('code'));
|
|
}
|
|
});
|
|
|
|
// Bubble Menu Listeners
|
|
if (btnBold) btnBold.addEventListener('click', () => editor.chain().focus().toggleBold().run());
|
|
if (btnItalic) btnItalic.addEventListener('click', () => editor.chain().focus().toggleItalic().run());
|
|
if (btnStrike) btnStrike.addEventListener('click', () => editor.chain().focus().toggleStrike().run());
|
|
if (btnCode) btnCode.addEventListener('click', () => editor.chain().focus().toggleCode().run());
|
|
|
|
// Container Focus
|
|
if (editorContainer) {
|
|
editorContainer.addEventListener('click', () => {
|
|
if (editor && !editor.isFocused) {
|
|
editor.chain().focus().run();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Expose to global scope for SPA usage
|
|
window.editorInstance = editor;
|
|
window.setEditorFileId = (fileId) => { currentFileId = fileId; };
|
|
}
|
|
|
|
// Save Content
|
|
if (saveBtn) {
|
|
saveBtn.addEventListener('click', async () => {
|
|
if (!editor || !currentFileId) return;
|
|
|
|
saveBtn.disabled = true;
|
|
saveBtn.textContent = 'Saving...';
|
|
|
|
const markdownContent = editor.storage.markdown.getMarkdown();
|
|
const saveUrl = `/file/content/${currentFileId}/save/`;
|
|
|
|
try {
|
|
const response = await fetch(saveUrl, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': getCookie('csrftoken')
|
|
},
|
|
body: JSON.stringify({ content: markdownContent })
|
|
});
|
|
|
|
if (response.ok) {
|
|
saveBtn.textContent = 'Saved!';
|
|
setTimeout(() => {
|
|
saveBtn.textContent = 'Save Changes';
|
|
saveBtn.disabled = false;
|
|
}, 1000);
|
|
} else {
|
|
throw new Error('Save failed');
|
|
}
|
|
} catch (err) {
|
|
alert('Failed to save file');
|
|
saveBtn.textContent = 'Save Changes';
|
|
saveBtn.disabled = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
// Initialize editor on load
|
|
if (document.querySelector('#editor')) {
|
|
initEditor();
|
|
}
|