2024-09-27 16:59:29 +02:00
|
|
|
<script lang="ts">
|
|
|
|
|
import { deserialize, applyAction } from "$app/forms";
|
|
|
|
|
import { textareaScrollTop, previewContent } from "$lib/runes.svelte";
|
2024-10-19 17:55:02 +02:00
|
|
|
import LoadingSpinner from "$lib/components/LoadingSpinner.svelte";
|
|
|
|
|
import { LOADING_DELAY } from "$lib/utils";
|
2024-09-27 16:59:29 +02:00
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
apiPrefix,
|
|
|
|
|
label,
|
|
|
|
|
name,
|
|
|
|
|
content
|
|
|
|
|
}: { apiPrefix: string; label: string; name: string; content: string } = $props();
|
|
|
|
|
|
|
|
|
|
let mainContentTextarea: HTMLTextAreaElement;
|
2024-10-19 17:55:02 +02:00
|
|
|
let loadingDelay: number;
|
|
|
|
|
let pasting = $state(false);
|
2024-09-27 16:59:29 +02:00
|
|
|
|
|
|
|
|
const updateScrollPercentage = () => {
|
|
|
|
|
const { scrollTop, scrollHeight, clientHeight } = mainContentTextarea;
|
|
|
|
|
textareaScrollTop.value = (scrollTop / (scrollHeight - clientHeight)) * 100;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleImagePaste = async (event: ClipboardEvent) => {
|
|
|
|
|
const clipboardItems = Array.from(event.clipboardData?.items ?? []);
|
|
|
|
|
const file = clipboardItems.find((item) => item.type.startsWith("image/"));
|
|
|
|
|
|
|
|
|
|
if (!file) return null;
|
|
|
|
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
|
|
const fileObject = file.getAsFile();
|
|
|
|
|
|
|
|
|
|
if (!fileObject) return;
|
|
|
|
|
|
2024-10-19 17:55:02 +02:00
|
|
|
loadingDelay = window.setTimeout(() => (pasting = true), LOADING_DELAY);
|
|
|
|
|
|
2024-09-27 16:59:29 +02:00
|
|
|
const formData = new FormData();
|
|
|
|
|
formData.append("file", fileObject);
|
|
|
|
|
|
|
|
|
|
const request = await fetch("?/pasteImage", {
|
|
|
|
|
method: "POST",
|
|
|
|
|
body: formData
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const result = deserialize(await request.clone().text());
|
|
|
|
|
applyAction(result);
|
|
|
|
|
|
|
|
|
|
const response = await request.json();
|
|
|
|
|
|
|
|
|
|
if (JSON.parse(response.data)[1]) {
|
|
|
|
|
const fileId = JSON.parse(response.data)[4];
|
|
|
|
|
const fileUrl = `${apiPrefix}/rpc/retrieve_file?id=${fileId}`;
|
|
|
|
|
|
|
|
|
|
const target = event.target as HTMLTextAreaElement;
|
2024-10-08 21:20:44 +02:00
|
|
|
const markdownToInsert = ``;
|
|
|
|
|
const cursorPosition = target.selectionStart;
|
2024-10-19 17:55:02 +02:00
|
|
|
const newContent =
|
|
|
|
|
target.value.slice(0, cursorPosition) +
|
|
|
|
|
markdownToInsert +
|
|
|
|
|
target.value.slice(cursorPosition);
|
2024-09-27 16:59:29 +02:00
|
|
|
|
2024-10-19 17:55:02 +02:00
|
|
|
target.value = newContent;
|
2024-09-27 16:59:29 +02:00
|
|
|
previewContent.value = newContent;
|
2024-10-08 21:20:44 +02:00
|
|
|
|
|
|
|
|
const newCursorPosition = cursorPosition + markdownToInsert.length;
|
|
|
|
|
target.setSelectionRange(newCursorPosition, newCursorPosition);
|
|
|
|
|
target.focus();
|
2024-09-27 16:59:29 +02:00
|
|
|
}
|
2024-10-19 17:55:02 +02:00
|
|
|
|
|
|
|
|
window.clearTimeout(loadingDelay);
|
|
|
|
|
pasting = false;
|
|
|
|
|
return;
|
2024-09-27 16:59:29 +02:00
|
|
|
};
|
|
|
|
|
</script>
|
|
|
|
|
|
2024-10-19 17:55:02 +02:00
|
|
|
{#if pasting}
|
|
|
|
|
<LoadingSpinner />
|
|
|
|
|
{/if}
|
|
|
|
|
|
2024-09-27 16:59:29 +02:00
|
|
|
<label>
|
|
|
|
|
{label}:
|
|
|
|
|
<textarea
|
|
|
|
|
{name}
|
|
|
|
|
rows="20"
|
2024-10-06 02:01:15 +02:00
|
|
|
maxlength="200000"
|
2024-09-27 16:59:29 +02:00
|
|
|
bind:value={previewContent.value}
|
|
|
|
|
bind:this={mainContentTextarea}
|
|
|
|
|
onscroll={updateScrollPercentage}
|
|
|
|
|
onpaste={handleImagePaste}
|
|
|
|
|
required>{content}</textarea
|
|
|
|
|
>
|
|
|
|
|
</label>
|