AI slop
All checks were successful
Build and Deploy Nuxt / build (push) Successful in 1m20s

This commit is contained in:
2026-06-08 00:28:29 +02:00
parent 94e2b8bd47
commit 0fb4f01892
22 changed files with 1474 additions and 346 deletions

View File

@@ -15,9 +15,15 @@ const sourceText = ref(''); // Original markdown source, used for editing
const displayText = ref(''); // Compiled HTML from markdown
const editingMode = ref(false);
const editableTitle = ref(null);
const title = ref(props.title);
const displayTitle = ref('');
const isDirty = ref(false);
const showClose = ref(false);
let savedState = { text: '', title: '' };
function markDirty() {
isDirty.value = sourceText.value !== savedState.text || title.value !== savedState.title;
}
function closeNote(){
emitter.emit('delete-note', props.noteKey);
@@ -48,20 +54,29 @@ function update(){
}, 0);
}
watch(sourceText, (newText) => {
// update();
});
watch(sourceText, markDirty);
watch(title, markDirty);
onMounted(() => {
sourceText.value = props.text;
title.value = props.title;
displayTitle.value = props.title;
savedState = { text: props.text, title: props.title };
emitter.on('title-updated', handleTitleUpdate);
// window.addEventListener('keydown', handleKeydown);
setTimeout(() => setupCallout(), 0);
update();
});
function handleTitleUpdate(data) {
if (data.key !== props.noteKey) return;
title.value = data.title;
savedState.title = data.title;
}
onUnmounted(() => {
emitter.off('title-updated', handleTitleUpdate);
// window.removeEventListener('keydown', handleKeydown);
});
@@ -92,12 +107,11 @@ function SaveNote(){
title: title.value,
}).then((response) => {
if(response.data.status !== 'ok'){
// Handle error (e.g., show a notification)
return;
}
// DisplayToast('green', "Note saved successfully.", 500);
savedState = { text: sourceText.value, title: title.value };
isDirty.value = false;
}).catch((error) => {
// Handle error (e.g., show a notification)
});
}
@@ -147,16 +161,18 @@ function setupCallout() {
}
const editTitle = (e) => {
title.value = e.target.innerText;
}
</script>
<template>
<div class="note" @keydown="handleKeydown" tabindex="0">
<div class="note-stunt">
<div class="close-button" v-on:click="closeNote">
<div class="unsaved-wrapper" v-if="isDirty">
<div class="unsaved-dot"></div>
<div class="close-button close-hidden" v-on:click="closeNote">
<img class="icon" src="/icons/Pixelarticons/white/close.svg" alt="My Happy SVG"/>
</div>
</div>
<div class="close-button" v-else v-on:click="closeNote">
<img class="icon" src="/icons/Pixelarticons/white/close.svg" alt="My Happy SVG"/>
</div>
<span>{{ title }}</span>
@@ -164,7 +180,7 @@ const editTitle = (e) => {
<div class="note-content-container">
<textarea v-model="sourceText" class="full-editor" v-if="editingMode"></textarea>
<div v-else class="note-content" ref="noteContent">
<h1 contenteditable="true" ref="editableTitle" @input="editTitle">{{ displayTitle }}</h1>
<h1>{{ title }}</h1>
<div ref="noteContent" v-html="displayText"></div>
</div>
@@ -184,6 +200,46 @@ const editTitle = (e) => {
user-select: none;
}
.unsaved-wrapper {
position: relative;
margin-bottom: 5px;
width: 20px;
height: 20px;
}
.unsaved-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #ffffff;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
}
.close-hidden {
opacity: 0;
visibility: hidden;
position: absolute;
top: 0;
left: 0;
width: 20px;
height: 20px;
margin-bottom: 0;
transition: opacity 0.15s ease, visibility 0.15s ease;
}
.unsaved-wrapper:hover .close-hidden {
opacity: 1;
visibility: visible;
}
.unsaved-wrapper:hover .unsaved-dot {
opacity: 0;
}
.full-editor {
width: 100%;
height: 100%;