feat: add content CRUD helpers, avatar component, and utility JS classes for devplacepy

This commit is contained in:
2026-05-23 06:41:47 +00:00
parent d7d8314da0
commit 116aeadabf
5 changed files with 138 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
export class Avatar {
static imgHtml(username, size = 24) {
const url = `/avatar/multiavatar/${encodeURIComponent(username)}?size=${size}`;
return `<img src="${url}" class="avatar-img" style="width:${size}px;height:${size}px;border-radius:50%" alt="" loading="lazy">`;
}
}
window.Avatar = Avatar;
+23
View File
@@ -0,0 +1,23 @@
export class Http {
static async getJson(url) {
const response = await fetch(url);
return response.json();
}
static postForm(action, data = {}) {
const form = document.createElement("form");
form.method = "POST";
form.action = action;
for (const [name, value] of Object.entries(data)) {
const input = document.createElement("input");
input.type = "hidden";
input.name = name;
input.value = value;
form.appendChild(input);
}
document.body.appendChild(form);
form.submit();
}
}
window.Http = Http;
+17
View File
@@ -0,0 +1,17 @@
export class TextInput {
static applyValue(element, value, caretPos) {
element.value = value;
element.setSelectionRange(caretPos, caretPos);
element.focus();
element.dispatchEvent(new Event("input", { bubbles: true }));
}
static insertAtCursor(element, text) {
const start = element.selectionStart;
const end = element.selectionEnd;
const value = element.value.substring(0, start) + text + element.value.substring(end);
TextInput.applyValue(element, value, start + text.length);
}
}
window.TextInput = TextInput;
+13
View File
@@ -0,0 +1,13 @@
export class Toast {
static flash(element, message, ms = 2000, revertTo = null) {
const original = revertTo === null ? element.textContent : revertTo;
element.textContent = message;
setTimeout(() => {
if (element.textContent === message) {
element.textContent = original;
}
}, ms);
}
}
window.Toast = Toast;