frontend/src/lib/components/Markdown.svelte
2024-05-26 16:07:01 +02:00

239 lines
5.5 KiB
Svelte

<script lang="ts">
import { onDestroy, onMount } from 'svelte';
import { markdownValue, markdownClicked } from '$lib/store';
import showdown from 'showdown';
export let id;
export let outputCounter;
export let name;
const converter = new showdown.Converter();
const toolbarOptions = {
container: [
['bold'],
['italic'],
['link'],
['image'],
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
],
}
let quill;
let html;
let value;
async function initializeQuillEditor()
{
const container = document.getElementById(id);
try {
const { default: Quill } = await import('quill');
quill = new Quill(container, {
modules: {
toolbar: toolbarOptions,
},
theme: 'snow',
placeholder: 'Markdown your code here...',
keepFocus: true,
});
}
catch(e)
{
console.log(e)
}
quill.on('editor-change', function() {
const editor = quill.root;
// Add text-4xl class to all h1 elements
editor.querySelectorAll('h1').forEach((h1) => {
h1.classList.add('text-4xl');
});
editor.querySelectorAll('h2').forEach((h2) => {
h2.classList.add('text-3xl');
});
editor.querySelectorAll('h3').forEach((h3) => {
h3.classList.add('text-xl');
});
editor.querySelectorAll('h4').forEach((h4) => {
h4.classList.add('text-md');
});
editor.querySelectorAll('h5').forEach((h5) => {
h5.classList.add('text-sm');
});
editor.querySelectorAll('h6').forEach((h6) => {
h6.classList.add('text-xs');
});
editor.querySelectorAll('a').forEach((a) => {
a.classList.add('text-blue-400', 'hover:text-white','underline');
});
editor.querySelectorAll('ol').forEach((ol) => {
ol.classList.add('list-decimal','ml-10','mt-3');
});
editor.querySelectorAll('ul').forEach((ul) => {
ul.classList.add('list-disc','ml-10','mt-3');
});
$: value = editor.innerHTML;
const contents = editor.innerHTML;
markdownValue.update((value) => [
...value.filter((item) => item.id !== id),
{ id: id , name: name, input: contents},
]);
console.log($markdownValue)
// Force Svelte to update the DOM
$: {}
});
// Convert the markdown value to HTML and set it as the content of the Quill editor
html = converter.makeHtml($markdownValue[id]?.input || '');
quill.setContents(quill.clipboard.convert(html));
};
onMount(async () => {
await initializeQuillEditor()
});
onDestroy(() => {
if (quill) {
quill.off('text-change');
quill = null;
}
});
/** Dispatch event on click outside of node */
function clickOutside(node) {
const handleClick = event => {
if (node && !node.contains(event.target) && !event.defaultPrevented) {
node.dispatchEvent(
new CustomEvent('click_outside', node)
)
}
}
document.addEventListener('click', handleClick, true);
return {
destroy() {
document.removeEventListener('click', handleClick, true);
}
}
}
function handleClickOutside(event) {
$markdownClicked[id] = false;
}
function handleClick() {
$markdownClicked[id] = true;
}
function hasContent(html) {
const el = document.createElement('div');
el.innerHTML = html;
let content = el.firstChild.innerHTML.trim();
// Remove <br> tags
content = content.replace(/<br\s*\/?>/gi, '');
return content !== '';
}
function keyCombination(event) {
if (event.key === "Enter" && event.shiftKey) {
$markdownClicked[id] = false;
event.preventDefault();
}
}
$: {
if($markdownClicked)
{
console.log($markdownClicked)
}
}
</script>
<div on:keydown={keyCombination} on:click={handleClick} use:clickOutside on:click_outside={handleClickOutside} class="text-gray-100 w-full sm:w-3/4 max-w-2xl mt-3 rounded-lg ">
<div class="{$markdownClicked[id] === false ? 'hidden' : '' } text-gray-100 w-full sm:w-3/4 max-w-2xl mb-4 rounded-lg ">
<textarea bind:value={value} id ={id} class="bg-[#1A1A27] min-h-12 w-full" />
</div>
<div class="{$markdownClicked[id] === true ? 'hidden' : '' } text-white mt-3 cursor-pointer w-full sm:w-3/4 max-w-2xl text-sm p-2">
{#each $markdownValue as mk}
{#if mk?.id === id}
<div class="flex flex-col">
<span class="text-gray-400 mb-4">[{outputCounter}] : </span>
<div class="border-b border-slate-800 rounded-md ">
{#if hasContent(value)}
{@html value}
{:else}
<p class="italic text-gray-400">Markdown your code here...</p>
{/if}
</div>
</div>
{/if}
{/each}
</div >
</div>
<style>
@import '/src/lib/assets/style_quill.css';
</style>