1
0

vault backup: 2025-12-26 02:09:22
All checks were successful
Deploy Quartz site to GitHub Pages / build (push) Successful in 2m29s

This commit is contained in:
2025-12-26 02:09:22 +01:00
parent 3fddadfe50
commit 50366b9b9c
288 changed files with 58893 additions and 750 deletions

View File

@@ -0,0 +1,130 @@
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();
}

View File

@@ -0,0 +1,2 @@
@import "tailwindcss";
@import 'remixicon/fonts/remixicon.css';