2.0 - WebUI builder ("Cielight" merge) #9

Merged
Djeex merged 43 commits from beta into main 2025-08-26 10:52:13 +02:00
20 changed files with 786 additions and 38 deletions
Showing only changes of commit 97645b06fa - Show all commits

View File

@ -80,8 +80,6 @@ function renderTags(container, tags, imgIndex) {
// Suggestion dropdown // Suggestion dropdown
const suggestionBox = document.createElement('ul'); const suggestionBox = document.createElement('ul');
suggestionBox.className = 'suggestions'; suggestionBox.className = 'suggestions';
suggestionBox.style.fontStyle = 'italic';
suggestionBox.style.textAlign = 'left';
container.appendChild(suggestionBox); container.appendChild(suggestionBox);
let selectedIndex = -1; let selectedIndex = -1;
@ -90,14 +88,22 @@ function renderTags(container, tags, imgIndex) {
tag = tag.trim(); tag = tag.trim();
if (!tag) return; if (!tag) return;
if (!tags.includes(tag)) tags.push(tag); if (!tags.includes(tag)) tags.push(tag);
updateAllTags(); updateTags(imgIndex, tags); // save to galleryImages and server
updateTags(imgIndex, tags);
renderTags(container, tags, imgIndex); renderTags(container, tags, imgIndex);
}; };
const updateSuggestions = () => { const updateSuggestions = () => {
const value = input.value.toLowerCase(); const value = input.value.toLowerCase();
const suggestions = allTags.filter(t => !tags.includes(t) && t.toLowerCase().startsWith(value));
const allTagsFlat = galleryImages.flatMap(img => img.tags || []);
const tagCount = {};
allTagsFlat.forEach(t => tagCount[t] = (tagCount[t] || 0) + 1);
const allTagsSorted = Object.keys(tagCount)
.sort((a, b) => tagCount[b] - tagCount[a]);
// Show suggestions that start with input (or all if empty)
const suggestions = allTagsSorted.filter(t => t.toLowerCase().startsWith(value) && !tags.includes(t));
suggestionBox.innerHTML = ''; suggestionBox.innerHTML = '';
selectedIndex = -1; selectedIndex = -1;
@ -106,10 +112,21 @@ function renderTags(container, tags, imgIndex) {
suggestionBox.style.display = 'block'; suggestionBox.style.display = 'block';
suggestions.forEach((s, idx) => { suggestions.forEach((s, idx) => {
const li = document.createElement('li'); const li = document.createElement('li');
li.style.fontStyle = 'italic';
li.style.textAlign = 'left';
const boldPart = `<b>${s.substring(0, input.value.length)}</b>`; const boldPart = `<b>${s.substring(0, input.value.length)}</b>`;
const rest = s.substring(input.value.length); const rest = s.substring(input.value.length);
li.innerHTML = boldPart + rest; li.innerHTML = boldPart + rest;
li.onclick = () => addTag(s);
li.addEventListener('mousedown', (e) => {
e.preventDefault();
addTag(s);
input.value = '';
input.focus();
updateSuggestions();
});
li.onmouseover = () => selectedIndex = idx; li.onmouseover = () => selectedIndex = idx;
suggestionBox.appendChild(li); suggestionBox.appendChild(li);
}); });
@ -119,46 +136,50 @@ function renderTags(container, tags, imgIndex) {
}; };
input.addEventListener('input', updateSuggestions); input.addEventListener('input', updateSuggestions);
input.addEventListener('focus', updateSuggestions);
// Keyboard navigation input.addEventListener('focus', updateSuggestions); // Show suggestions on focus
input.addEventListener('keydown', (e) => { input.addEventListener('keydown', (e) => {
const items = suggestionBox.querySelectorAll('li'); const items = suggestionBox.querySelectorAll('li');
if (items.length) {
if (e.key === 'ArrowDown') { if (e.key === 'ArrowDown') {
e.preventDefault(); e.preventDefault();
if (!items.length) return;
selectedIndex = (selectedIndex + 1) % items.length; selectedIndex = (selectedIndex + 1) % items.length;
items.forEach((li, i) => li.classList.toggle('selected', i === selectedIndex)); items.forEach((li, i) => li.classList.toggle('selected', i === selectedIndex));
} else if (e.key === 'ArrowUp') { } else if (e.key === 'ArrowUp') {
e.preventDefault(); e.preventDefault();
if (!items.length) return;
selectedIndex = (selectedIndex - 1 + items.length) % items.length; selectedIndex = (selectedIndex - 1 + items.length) % items.length;
items.forEach((li, i) => li.classList.toggle('selected', i === selectedIndex)); items.forEach((li, i) => li.classList.toggle('selected', i === selectedIndex));
} else if (e.key === 'Enter') { } else if (e.key === 'Enter') {
e.preventDefault(); e.preventDefault();
if (selectedIndex >= 0) addTag(items[selectedIndex].textContent.replace(/×$/,'')); if (selectedIndex >= 0 && items[selectedIndex]) {
else addTag(input.value); addTag(items[selectedIndex].textContent);
} else if (e.key === 'Escape') { } else {
suggestionBox.style.display = 'none'; addTag(input.value);
}
input.value = '';
updateSuggestions();
} else if ([' ', ','].includes(e.key)) { } else if ([' ', ','].includes(e.key)) {
e.preventDefault(); e.preventDefault();
addTag(input.value); addTag(input.value);
} input.value = '';
} else if (['Enter', ' ', ','].includes(e.key)) { updateSuggestions();
e.preventDefault();
addTag(input.value);
} }
}); });
input.addEventListener('blur', () => { input.addEventListener('blur', () => {
setTimeout(() => { setTimeout(() => {
if (input.value.trim()) addTag(input.value);
suggestionBox.style.display = 'none'; suggestionBox.style.display = 'none';
}, 100); input.value = ''; // Clear input without saving
}, 150);
}); });
input.focus(); input.focus();
updateSuggestions(); // show suggestions on render
} }
// --- Update tags in galleryImages array --- // --- Update tags in galleryImages array ---
function updateTags(index, tags) { function updateTags(index, tags) {
galleryImages[index].tags = tags; galleryImages[index].tags = tags;