add badges

This commit is contained in:
2025-12-09 03:33:27 +03:00
parent 1539486456
commit dbf0150a5e
43 changed files with 913 additions and 111 deletions

View File

@@ -1,4 +1,5 @@
const bookmarkMenuHrefTemplate = '/hyperapi/bookmarks-dropdown';
const badgeEditorEndpoint = '/hyperapi/badge-editor';
const previewEndpoint = '/api/babycode-preview';
const userEndpoint = '/api/current-user';
@@ -277,3 +278,200 @@ export default class {
}
}
}
export class BadgeEditorForm {
#badgeTemplate = undefined;
async loadBadgeEditor(ev, el) {
const badges = await this.api.getHTML(badgeEditorEndpoint);
if (!badges.value) {
return;
}
if (this.#badgeTemplate === undefined){
const badge = await this.api.getHTML(`${badgeEditorEndpoint}/template`)
if (!badge.value){
return;
}
this.#badgeTemplate= badge.value;
}
el.replaceChildren();
const addButton = `<button data-disable-if-max="1" data-receive="updateBadgeCount" DISABLE_IF_MAX type="button" data-send="addBadge">Add badge</button>`;
const submitButton = `<input data-receive="updateBadgeCount" type="submit" value="Save badges">`;
const controls = `<span>${addButton} ${submitButton} <span data-count="1" data-receive="updateBadgeCount">BADGECOUNT/10</span></span>`
const badgeCount = badges.value.querySelectorAll('.settings-badge-container').length;
const subs = [
['BADGECOUNT', badgeCount],
['DISABLE_IF_MAX', badgeCount === 10 ? 'disabled' : ''],
];
el.appendChild(this.api.makeHTML(controls, subs));
el.appendChild(badges.value);
}
addBadge(ev, el) {
if (this.#badgeTemplate === undefined) {
return;
}
const badge = this.#badgeTemplate.cloneNode(true);
el.appendChild(badge);
this.api.localTrigger('updateBadgeCount');
}
deleteBadge(ev, el) {
if (!el.contains(el.sender)) {
return;
}
el.remove();
this.api.localTrigger('updateBadgeCount');
}
updateBadgeCount(_ev, el) {
const badgeCount = el.parentNode.parentNode.querySelectorAll('.settings-badge-container').length;
if (el.dsInt('disableIfMax') === 1) {
el.disabled = badgeCount === 10;
} else if (el.dsInt('count') === 1) {
el.textContent = `${badgeCount}/10`;
}
}
badgeEditorPrepareSubmit(ev, el) {
if (ev.type !== 'submit') {
return;
}
ev.preventDefault();
const badges = el.querySelectorAll('.settings-badge-container').length;
const noUploads = el.querySelectorAll('.settings-badge-file-picker.hidden input[type=file]');
noUploads.forEach(e => {
e.value = null;
})
// console.log(noUploads);
el.submit();
// console.log('would submit now');
}
}
const validateBase64Img = dataURL => new Promise(resolve => {
const img = new Image();
img.onload = () => {
resolve(img.width === 88 && img.height === 31);
};
img.src = dataURL;
});
export class BadgeEditorBadge {
#badgeCustomImageData = null;
badgeUpdatePreview(ev, el) {
if (ev.type !== 'change') {
return;
}
// TODO: el.sender doesn't have a bittyParentBittyId
const selectBittyParent = el.sender.closest('bitty-7-0');
if (el.bittyParentBittyId !== selectBittyParent.dataset.bittyid) {
return;
}
if (ev.val === 'custom') {
if (this.#badgeCustomImageData) {
el.src = this.#badgeCustomImageData;
} else {
el.removeAttribute('src');
}
return;
}
const option = el.sender.selectedOptions[0];
el.src = option.dataset.filePath;
}
async badgeUpdatePreviewCustom(ev, el) {
if (ev.type !== 'change') {
return;
}
if (el.bittyParentBittyId !== el.sender.bittyParentBittyId) {
return;
}
const file = ev.target.files[0];
if (file.size >= 1000 * 500) {
this.api.trigger('badgeErrorSize');
this.#badgeCustomImageData = null;
el.removeAttribute('src');
return;
}
const reader = new FileReader();
reader.onload = async e => {
const dimsValid = await validateBase64Img(e.target.result);
if (!dimsValid) {
this.api.trigger('badgeErrorDim');
this.#badgeCustomImageData = null;
el.removeAttribute('src');
return;
}
this.#badgeCustomImageData = e.target.result;
el.src = this.#badgeCustomImageData;
this.api.trigger('badgeHideErrors');
}
reader.readAsDataURL(file);
}
badgeToggleFilePicker(ev, el) {
if (ev.type !== 'change') {
return;
}
// TODO: el.sender doesn't have a bittyParentBittyId
const selectBittyParent = el.sender.closest('bitty-7-0');
if (el.bittyParentBittyId !== selectBittyParent.dataset.bittyid) {
return;
}
const filePicker = el.querySelector('input[type=file]');
if (ev.val === 'custom') {
el.classList.remove('hidden');
if (filePicker.dataset.validity) {
filePicker.setCustomValidity(filePicker.dataset.validity);
}
filePicker.required = true;
} else {
el.classList.add('hidden');
filePicker.setCustomValidity('');
filePicker.required = false;
}
}
openBadgeFilePicker(ev, el) {
// TODO: el.sender doesn't have a bittyParentBittyId
if (el.sender.parentNode !== el.parentNode) {
return;
}
el.click();
}
badgeErrorSize(_ev, el) {
if (el.sender !== el.bittyParent) {
return;
}
const validity = "Image can't be over 500KB."
el.dataset.validity = validity;
el.setCustomValidity(validity);
el.reportValidity();
}
badgeErrorDim(_ev, el) {
if (el.sender !== el.bittyParent) {
return;
}
const validity = "Image must be exactly 88x31 pixels."
el.dataset.validity = validity;
el.setCustomValidity(validity);
el.reportValidity();
}
badgeHideErrors(_ev, el) {
if (el.sender !== el.bittyParent) {
return;
}
delete el.dataset.validity;
el.setCustomValidity('');
}
}