Add sticky note saving

This commit is contained in:
Idrees Hassan
2025-08-16 17:45:57 -04:00
parent 9f3b36adb7
commit 7412cfd93a
3 changed files with 342 additions and 57 deletions

133
birb.js
View File

@@ -563,6 +563,23 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
super("", () => {}); super("", () => {});
} }
} }
class StickyNote {
/**
* @param {string} id
* @param {string} [site]
* @param {string} [content]
* @param {number} [top]
* @param {number} [left]
*/
constructor(id, site="", content="", top=0, left=0) {
this.id = id;
this.site = site;
this.content = content;
this.top = top;
this.left = left;
}
}
const menuItems = [ const menuItems = [
new MenuItem(`Pet ${birdBirb()}`, pet), new MenuItem(`Pet ${birdBirb()}`, pet),
@@ -579,6 +596,7 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
new DebugMenuItem("Disable Debug", () => { new DebugMenuItem("Disable Debug", () => {
debugMode = false; debugMode = false;
}), }),
new MenuItem("Add Sticky Note", newStickyNote),
new Separator(), new Separator(),
new MenuItem("Settings", () => switchMenuItems(settingsItems), false), new MenuItem("Settings", () => switchMenuItems(settingsItems), false),
]; ];
@@ -657,6 +675,8 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
let unlockedSpecies = [DEFAULT_BIRD]; let unlockedSpecies = [DEFAULT_BIRD];
let visible = true; let visible = true;
let lastPetTimestamp = 0; let lastPetTimestamp = 0;
/** @type {StickyNote[]} */
let stickyNotes = [];
/** /**
* @returns {boolean} Whether the script is running in a userscript extension context * @returns {boolean} Whether the script is running in a userscript extension context
@@ -689,6 +709,15 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
userSettings = saveData.settings ?? {}; userSettings = saveData.settings ?? {};
unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD]; unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD];
currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD; currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD;
stickyNotes = [];
if (saveData.stickyNotes) {
for (let note of saveData.stickyNotes) {
if (note.id) {
stickyNotes.push(new StickyNote(note.id, note.site, note.content, note.top, note.left));
}
}
}
log(stickyNotes.length + " sticky notes loaded");
switchSpecies(currentSpecies); switchSpecies(currentSpecies);
} }
@@ -698,6 +727,15 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
currentSpecies: currentSpecies, currentSpecies: currentSpecies,
settings: userSettings settings: userSettings
}; };
if (stickyNotes.length > 0) {
saveData.stickyNotes = stickyNotes.map(note => ({
id: note.id,
site: note.site,
content: note.content,
top: note.top,
left: note.left
}));
}
if (isUserScript()) { if (isUserScript()) {
log("Saving data to UserScript storage"); log("Saving data to UserScript storage");
// @ts-ignore // @ts-ignore
@@ -739,41 +777,84 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
return settings().birbMode ? "Birb" : "Bird"; return settings().birbMode ? "Birb" : "Bird";
} }
function makeStickyNote(top = 500, left = 500) { function newStickyNote() {
const id = Date.now().toString();
const site = window.location.href;
const stickyNote = new StickyNote(id, site, "");
const element = renderStickyNote(stickyNote);
centerElement(element);
stickyNote.top = parseInt(element.style.top, 10);
stickyNote.left = parseInt(element.style.left, 10);
stickyNotes.push(stickyNote);
save();
}
/**
* @param {StickyNote} stickyNote
* @returns {HTMLElement}
*/
function renderStickyNote(stickyNote) {
let html = ` let html = `
<div class="birb-window-header"> <div class="birb-window-header">
<div class="birb-window-title">Sticky Note</div> <div class="birb-window-title">Sticky Note</div>
<div class="birb-window-close">x</div> <div class="birb-window-close">x</div>
</div> </div>
<div class="birb-window-content"> <div class="birb-window-content">
<textarea class="birb-sticky-note-input" style="width: 150px;" placeholder="Write your notes here and they'll stick to the page..."></textarea> <textarea class="birb-sticky-note-input" style="width: 150px;" placeholder="Write your notes here and they'll stick to the page...">${stickyNote.content}</textarea>
</div>` </div>`
const stickyNote = makeElement("birb-window"); const noteElement = makeElement("birb-window");
stickyNote.classList.add("birb-sticky-note"); noteElement.classList.add("birb-sticky-note");
stickyNote.innerHTML = html; noteElement.innerHTML = html;
stickyNote.style.top = `${top}px`; noteElement.style.top = `${stickyNote.top}px`;
stickyNote.style.left = `${left}px`; noteElement.style.left = `${stickyNote.left}px`;
document.body.appendChild(stickyNote); document.body.appendChild(noteElement);
makeDraggable(stickyNote.querySelector(".birb-window-header")); makeDraggable(noteElement.querySelector(".birb-window-header"), true, (top, left) => {
stickyNote.top = top;
stickyNote.left = left;
save();
});
const closeButton = stickyNote.querySelector(".birb-window-close"); const closeButton = noteElement.querySelector(".birb-window-close");
if (closeButton) { if (closeButton) {
makeClosable(() => { makeClosable(() => {
confirm("Are you sure you want to delete this sticky note?") && stickyNote.remove(); if (confirm("Are you sure you want to delete this sticky note?")) {
deleteStickyNote(stickyNote);
noteElement.remove();
}
}, closeButton); }, closeButton);
} }
centerElement(stickyNote); const textarea = noteElement.querySelector(".birb-sticky-note-input");
if (textarea && textarea instanceof HTMLTextAreaElement) {
let saveTimeout;
// Save after debounce
textarea.addEventListener("input", () => {
stickyNote.content = textarea.value;
clearTimeout(saveTimeout);
saveTimeout = setTimeout(() => {
save();
}, 500);
});
}
// On window resize // On window resize
window.addEventListener("resize", () => { window.addEventListener("resize", () => {
const modTop = `${top - Math.min(window.innerHeight - stickyNote.offsetHeight, top)}px`; const modTop = `${stickyNote.top - Math.min(window.innerHeight - noteElement.offsetHeight, stickyNote.top)}px`;
const modLeft = `${left - Math.min(window.innerWidth - stickyNote.offsetWidth, left)}px`; const modLeft = `${stickyNote.left - Math.min(window.innerWidth - noteElement.offsetWidth, stickyNote.left)}px`;
stickyNote.style.transform = `translate(-${modLeft}, -${modTop})`; noteElement.style.transform = `translate(-${modLeft}, -${modTop})`;
}); });
return noteElement;
}
/**
* @param {StickyNote} stickyNote
*/
function deleteStickyNote(stickyNote) {
stickyNotes = stickyNotes.filter(note => note.id !== stickyNote.id);
save();
} }
function init() { function init() {
@@ -828,7 +909,12 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
} }
}); });
makeStickyNote(); // Render all sticky notes
for (let stickyNote of stickyNotes) {
if (stickyNote.site === window.location.href.split("?")[0]) {
renderStickyNote(stickyNote);
}
}
setInterval(update, 1000 / 60); setInterval(update, 1000 / 60);
} }
@@ -1354,8 +1440,9 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
/** /**
* @param {HTMLElement|null} element The element to detect drag events on * @param {HTMLElement|null} element The element to detect drag events on
* @param {boolean} [parent] Whether to move the parent element when the child is dragged * @param {boolean} [parent] Whether to move the parent element when the child is dragged
* @param {(top: number, left: number) => void} [callback] Callback for when element is moved
*/ */
function makeDraggable(element, parent = true) { function makeDraggable(element, parent = true, callback = () => {}) {
if (!element) { if (!element) {
return; return;
} }
@@ -1384,11 +1471,19 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
e.preventDefault(); e.preventDefault();
}); });
document.addEventListener("mouseup", () => { document.addEventListener("mouseup", (e) => {
if (isMouseDown) {
callback(elementToMove.offsetTop, elementToMove.offsetLeft);
e.preventDefault();
}
isMouseDown = false; isMouseDown = false;
}); });
document.addEventListener("touchend", () => { document.addEventListener("touchend", (e) => {
if (isMouseDown) {
callback(elementToMove.offsetTop, elementToMove.offsetLeft);
e.preventDefault();
}
isMouseDown = false; isMouseDown = false;
}); });

133
dist/birb.js vendored
View File

@@ -881,6 +881,23 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
super("", () => {}); super("", () => {});
} }
} }
class StickyNote {
/**
* @param {string} id
* @param {string} [site]
* @param {string} [content]
* @param {number} [top]
* @param {number} [left]
*/
constructor(id, site="", content="", top=0, left=0) {
this.id = id;
this.site = site;
this.content = content;
this.top = top;
this.left = left;
}
}
const menuItems = [ const menuItems = [
new MenuItem(`Pet ${birdBirb()}`, pet), new MenuItem(`Pet ${birdBirb()}`, pet),
@@ -897,6 +914,7 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
new DebugMenuItem("Disable Debug", () => { new DebugMenuItem("Disable Debug", () => {
debugMode = false; debugMode = false;
}), }),
new MenuItem("Add Sticky Note", newStickyNote),
new Separator(), new Separator(),
new MenuItem("Settings", () => switchMenuItems(settingsItems), false), new MenuItem("Settings", () => switchMenuItems(settingsItems), false),
]; ];
@@ -975,6 +993,8 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
let unlockedSpecies = [DEFAULT_BIRD]; let unlockedSpecies = [DEFAULT_BIRD];
let visible = true; let visible = true;
let lastPetTimestamp = 0; let lastPetTimestamp = 0;
/** @type {StickyNote[]} */
let stickyNotes = [];
/** /**
* @returns {boolean} Whether the script is running in a userscript extension context * @returns {boolean} Whether the script is running in a userscript extension context
@@ -1007,6 +1027,15 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
userSettings = saveData.settings ?? {}; userSettings = saveData.settings ?? {};
unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD]; unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD];
currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD; currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD;
stickyNotes = [];
if (saveData.stickyNotes) {
for (let note of saveData.stickyNotes) {
if (note.id) {
stickyNotes.push(new StickyNote(note.id, note.site, note.content, note.top, note.left));
}
}
}
log(stickyNotes.length + " sticky notes loaded");
switchSpecies(currentSpecies); switchSpecies(currentSpecies);
} }
@@ -1016,6 +1045,15 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
currentSpecies: currentSpecies, currentSpecies: currentSpecies,
settings: userSettings settings: userSettings
}; };
if (stickyNotes.length > 0) {
saveData.stickyNotes = stickyNotes.map(note => ({
id: note.id,
site: note.site,
content: note.content,
top: note.top,
left: note.left
}));
}
if (isUserScript()) { if (isUserScript()) {
log("Saving data to UserScript storage"); log("Saving data to UserScript storage");
// @ts-ignore // @ts-ignore
@@ -1057,41 +1095,84 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
return settings().birbMode ? "Birb" : "Bird"; return settings().birbMode ? "Birb" : "Bird";
} }
function makeStickyNote(top = 500, left = 500) { function newStickyNote() {
const id = Date.now().toString();
const site = window.location.href;
const stickyNote = new StickyNote(id, site, "");
const element = renderStickyNote(stickyNote);
centerElement(element);
stickyNote.top = parseInt(element.style.top, 10);
stickyNote.left = parseInt(element.style.left, 10);
stickyNotes.push(stickyNote);
save();
}
/**
* @param {StickyNote} stickyNote
* @returns {HTMLElement}
*/
function renderStickyNote(stickyNote) {
let html = ` let html = `
<div class="birb-window-header"> <div class="birb-window-header">
<div class="birb-window-title">Sticky Note</div> <div class="birb-window-title">Sticky Note</div>
<div class="birb-window-close">x</div> <div class="birb-window-close">x</div>
</div> </div>
<div class="birb-window-content"> <div class="birb-window-content">
<textarea class="birb-sticky-note-input" style="width: 150px;" placeholder="Write your notes here and they'll stick to the page..."></textarea> <textarea class="birb-sticky-note-input" style="width: 150px;" placeholder="Write your notes here and they'll stick to the page...">${stickyNote.content}</textarea>
</div>` </div>`
const stickyNote = makeElement("birb-window"); const noteElement = makeElement("birb-window");
stickyNote.classList.add("birb-sticky-note"); noteElement.classList.add("birb-sticky-note");
stickyNote.innerHTML = html; noteElement.innerHTML = html;
stickyNote.style.top = `${top}px`; noteElement.style.top = `${stickyNote.top}px`;
stickyNote.style.left = `${left}px`; noteElement.style.left = `${stickyNote.left}px`;
document.body.appendChild(stickyNote); document.body.appendChild(noteElement);
makeDraggable(stickyNote.querySelector(".birb-window-header")); makeDraggable(noteElement.querySelector(".birb-window-header"), true, (top, left) => {
stickyNote.top = top;
stickyNote.left = left;
save();
});
const closeButton = stickyNote.querySelector(".birb-window-close"); const closeButton = noteElement.querySelector(".birb-window-close");
if (closeButton) { if (closeButton) {
makeClosable(() => { makeClosable(() => {
confirm("Are you sure you want to delete this sticky note?") && stickyNote.remove(); if (confirm("Are you sure you want to delete this sticky note?")) {
deleteStickyNote(stickyNote);
noteElement.remove();
}
}, closeButton); }, closeButton);
} }
centerElement(stickyNote); const textarea = noteElement.querySelector(".birb-sticky-note-input");
if (textarea && textarea instanceof HTMLTextAreaElement) {
let saveTimeout;
// Save after debounce
textarea.addEventListener("input", () => {
stickyNote.content = textarea.value;
clearTimeout(saveTimeout);
saveTimeout = setTimeout(() => {
save();
}, 500);
});
}
// On window resize // On window resize
window.addEventListener("resize", () => { window.addEventListener("resize", () => {
const modTop = `${top - Math.min(window.innerHeight - stickyNote.offsetHeight, top)}px`; const modTop = `${stickyNote.top - Math.min(window.innerHeight - noteElement.offsetHeight, stickyNote.top)}px`;
const modLeft = `${left - Math.min(window.innerWidth - stickyNote.offsetWidth, left)}px`; const modLeft = `${stickyNote.left - Math.min(window.innerWidth - noteElement.offsetWidth, stickyNote.left)}px`;
stickyNote.style.transform = `translate(-${modLeft}, -${modTop})`; noteElement.style.transform = `translate(-${modLeft}, -${modTop})`;
}); });
return noteElement;
}
/**
* @param {StickyNote} stickyNote
*/
function deleteStickyNote(stickyNote) {
stickyNotes = stickyNotes.filter(note => note.id !== stickyNote.id);
save();
} }
function init() { function init() {
@@ -1146,7 +1227,12 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
} }
}); });
makeStickyNote(); // Render all sticky notes
for (let stickyNote of stickyNotes) {
if (stickyNote.site === window.location.href.split("?")[0]) {
renderStickyNote(stickyNote);
}
}
setInterval(update, 1000 / 60); setInterval(update, 1000 / 60);
} }
@@ -1672,8 +1758,9 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
/** /**
* @param {HTMLElement|null} element The element to detect drag events on * @param {HTMLElement|null} element The element to detect drag events on
* @param {boolean} [parent] Whether to move the parent element when the child is dragged * @param {boolean} [parent] Whether to move the parent element when the child is dragged
* @param {(top: number, left: number) => void} [callback] Callback for when element is moved
*/ */
function makeDraggable(element, parent = true) { function makeDraggable(element, parent = true, callback = () => {}) {
if (!element) { if (!element) {
return; return;
} }
@@ -1702,11 +1789,19 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
e.preventDefault(); e.preventDefault();
}); });
document.addEventListener("mouseup", () => { document.addEventListener("mouseup", (e) => {
if (isMouseDown) {
callback(elementToMove.offsetTop, elementToMove.offsetLeft);
e.preventDefault();
}
isMouseDown = false; isMouseDown = false;
}); });
document.addEventListener("touchend", () => { document.addEventListener("touchend", (e) => {
if (isMouseDown) {
callback(elementToMove.offsetTop, elementToMove.offsetLeft);
e.preventDefault();
}
isMouseDown = false; isMouseDown = false;
}); });

133
dist/birb.user.js vendored
View File

@@ -894,6 +894,23 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
super("", () => {}); super("", () => {});
} }
} }
class StickyNote {
/**
* @param {string} id
* @param {string} [site]
* @param {string} [content]
* @param {number} [top]
* @param {number} [left]
*/
constructor(id, site="", content="", top=0, left=0) {
this.id = id;
this.site = site;
this.content = content;
this.top = top;
this.left = left;
}
}
const menuItems = [ const menuItems = [
new MenuItem(`Pet ${birdBirb()}`, pet), new MenuItem(`Pet ${birdBirb()}`, pet),
@@ -910,6 +927,7 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
new DebugMenuItem("Disable Debug", () => { new DebugMenuItem("Disable Debug", () => {
debugMode = false; debugMode = false;
}), }),
new MenuItem("Add Sticky Note", newStickyNote),
new Separator(), new Separator(),
new MenuItem("Settings", () => switchMenuItems(settingsItems), false), new MenuItem("Settings", () => switchMenuItems(settingsItems), false),
]; ];
@@ -988,6 +1006,8 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
let unlockedSpecies = [DEFAULT_BIRD]; let unlockedSpecies = [DEFAULT_BIRD];
let visible = true; let visible = true;
let lastPetTimestamp = 0; let lastPetTimestamp = 0;
/** @type {StickyNote[]} */
let stickyNotes = [];
/** /**
* @returns {boolean} Whether the script is running in a userscript extension context * @returns {boolean} Whether the script is running in a userscript extension context
@@ -1020,6 +1040,15 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
userSettings = saveData.settings ?? {}; userSettings = saveData.settings ?? {};
unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD]; unlockedSpecies = saveData.unlockedSpecies ?? [DEFAULT_BIRD];
currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD; currentSpecies = saveData.currentSpecies ?? DEFAULT_BIRD;
stickyNotes = [];
if (saveData.stickyNotes) {
for (let note of saveData.stickyNotes) {
if (note.id) {
stickyNotes.push(new StickyNote(note.id, note.site, note.content, note.top, note.left));
}
}
}
log(stickyNotes.length + " sticky notes loaded");
switchSpecies(currentSpecies); switchSpecies(currentSpecies);
} }
@@ -1029,6 +1058,15 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
currentSpecies: currentSpecies, currentSpecies: currentSpecies,
settings: userSettings settings: userSettings
}; };
if (stickyNotes.length > 0) {
saveData.stickyNotes = stickyNotes.map(note => ({
id: note.id,
site: note.site,
content: note.content,
top: note.top,
left: note.left
}));
}
if (isUserScript()) { if (isUserScript()) {
log("Saving data to UserScript storage"); log("Saving data to UserScript storage");
// @ts-ignore // @ts-ignore
@@ -1070,41 +1108,84 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
return settings().birbMode ? "Birb" : "Bird"; return settings().birbMode ? "Birb" : "Bird";
} }
function makeStickyNote(top = 500, left = 500) { function newStickyNote() {
const id = Date.now().toString();
const site = window.location.href;
const stickyNote = new StickyNote(id, site, "");
const element = renderStickyNote(stickyNote);
centerElement(element);
stickyNote.top = parseInt(element.style.top, 10);
stickyNote.left = parseInt(element.style.left, 10);
stickyNotes.push(stickyNote);
save();
}
/**
* @param {StickyNote} stickyNote
* @returns {HTMLElement}
*/
function renderStickyNote(stickyNote) {
let html = ` let html = `
<div class="birb-window-header"> <div class="birb-window-header">
<div class="birb-window-title">Sticky Note</div> <div class="birb-window-title">Sticky Note</div>
<div class="birb-window-close">x</div> <div class="birb-window-close">x</div>
</div> </div>
<div class="birb-window-content"> <div class="birb-window-content">
<textarea class="birb-sticky-note-input" style="width: 150px;" placeholder="Write your notes here and they'll stick to the page..."></textarea> <textarea class="birb-sticky-note-input" style="width: 150px;" placeholder="Write your notes here and they'll stick to the page...">${stickyNote.content}</textarea>
</div>` </div>`
const stickyNote = makeElement("birb-window"); const noteElement = makeElement("birb-window");
stickyNote.classList.add("birb-sticky-note"); noteElement.classList.add("birb-sticky-note");
stickyNote.innerHTML = html; noteElement.innerHTML = html;
stickyNote.style.top = `${top}px`; noteElement.style.top = `${stickyNote.top}px`;
stickyNote.style.left = `${left}px`; noteElement.style.left = `${stickyNote.left}px`;
document.body.appendChild(stickyNote); document.body.appendChild(noteElement);
makeDraggable(stickyNote.querySelector(".birb-window-header")); makeDraggable(noteElement.querySelector(".birb-window-header"), true, (top, left) => {
stickyNote.top = top;
stickyNote.left = left;
save();
});
const closeButton = stickyNote.querySelector(".birb-window-close"); const closeButton = noteElement.querySelector(".birb-window-close");
if (closeButton) { if (closeButton) {
makeClosable(() => { makeClosable(() => {
confirm("Are you sure you want to delete this sticky note?") && stickyNote.remove(); if (confirm("Are you sure you want to delete this sticky note?")) {
deleteStickyNote(stickyNote);
noteElement.remove();
}
}, closeButton); }, closeButton);
} }
centerElement(stickyNote); const textarea = noteElement.querySelector(".birb-sticky-note-input");
if (textarea && textarea instanceof HTMLTextAreaElement) {
let saveTimeout;
// Save after debounce
textarea.addEventListener("input", () => {
stickyNote.content = textarea.value;
clearTimeout(saveTimeout);
saveTimeout = setTimeout(() => {
save();
}, 500);
});
}
// On window resize // On window resize
window.addEventListener("resize", () => { window.addEventListener("resize", () => {
const modTop = `${top - Math.min(window.innerHeight - stickyNote.offsetHeight, top)}px`; const modTop = `${stickyNote.top - Math.min(window.innerHeight - noteElement.offsetHeight, stickyNote.top)}px`;
const modLeft = `${left - Math.min(window.innerWidth - stickyNote.offsetWidth, left)}px`; const modLeft = `${stickyNote.left - Math.min(window.innerWidth - noteElement.offsetWidth, stickyNote.left)}px`;
stickyNote.style.transform = `translate(-${modLeft}, -${modTop})`; noteElement.style.transform = `translate(-${modLeft}, -${modTop})`;
}); });
return noteElement;
}
/**
* @param {StickyNote} stickyNote
*/
function deleteStickyNote(stickyNote) {
stickyNotes = stickyNotes.filter(note => note.id !== stickyNote.id);
save();
} }
function init() { function init() {
@@ -1159,7 +1240,12 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
} }
}); });
makeStickyNote(); // Render all sticky notes
for (let stickyNote of stickyNotes) {
if (stickyNote.site === window.location.href.split("?")[0]) {
renderStickyNote(stickyNote);
}
}
setInterval(update, 1000 / 60); setInterval(update, 1000 / 60);
} }
@@ -1685,8 +1771,9 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
/** /**
* @param {HTMLElement|null} element The element to detect drag events on * @param {HTMLElement|null} element The element to detect drag events on
* @param {boolean} [parent] Whether to move the parent element when the child is dragged * @param {boolean} [parent] Whether to move the parent element when the child is dragged
* @param {(top: number, left: number) => void} [callback] Callback for when element is moved
*/ */
function makeDraggable(element, parent = true) { function makeDraggable(element, parent = true, callback = () => {}) {
if (!element) { if (!element) {
return; return;
} }
@@ -1715,11 +1802,19 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
e.preventDefault(); e.preventDefault();
}); });
document.addEventListener("mouseup", () => { document.addEventListener("mouseup", (e) => {
if (isMouseDown) {
callback(elementToMove.offsetTop, elementToMove.offsetLeft);
e.preventDefault();
}
isMouseDown = false; isMouseDown = false;
}); });
document.addEventListener("touchend", () => { document.addEventListener("touchend", (e) => {
if (isMouseDown) {
callback(elementToMove.offsetTop, elementToMove.offsetLeft);
e.preventDefault();
}
isMouseDown = false; isMouseDown = false;
}); });