2.0 - WebUI builder ("Cielight" merge) #9
@ -2,4 +2,3 @@ hero:
|
||||
images: []
|
||||
gallery:
|
||||
images: []
|
||||
|
||||
|
@ -75,5 +75,17 @@
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/upload.js') }}"></script>
|
||||
</div>
|
||||
<!-- Delete confirmation modal -->
|
||||
<div id="delete-modal" class="modal" style="display:none;">
|
||||
<div class="modal-content">
|
||||
<span id="delete-modal-close" class="modal-close">×</span>
|
||||
<h3>Confirm Deletion</h3>
|
||||
<p id="delete-modal-text">Are you sure you want to delete this image?</p>
|
||||
<div class="modal-actions">
|
||||
<button id="delete-modal-confirm" class="modal-btn danger">Delete</button>
|
||||
<button id="delete-modal-cancel" class="modal-btn">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -44,7 +44,7 @@ function renderGallery() {
|
||||
<div class="tags-display" data-index="${i}"></div>
|
||||
<div class="flex-item flex-full">
|
||||
<div class="flex-item flex-end">
|
||||
<button onclick="deleteGalleryImage(${i})">🗑 Delete</button>
|
||||
<button onclick="showDeleteModal('gallery', ${i})">🗑 Delete</button>
|
||||
</div>
|
||||
<div class="tag-input" data-index="${i}"></div>
|
||||
</div>
|
||||
@ -208,56 +208,13 @@ function renderHero() {
|
||||
</div>
|
||||
<div class="flex-item flex-full">
|
||||
<div class="flex-item flex-end">
|
||||
<button onclick="deleteHeroImage(${i})">🗑 Delete</button>
|
||||
<button onclick="showDeleteModal('hero', ${i})">🗑 Delete</button>
|
||||
</div>
|
||||
`;
|
||||
container.appendChild(div);
|
||||
});
|
||||
}
|
||||
|
||||
// --- Delete gallery image ---
|
||||
async function deleteGalleryImage(index) {
|
||||
const img = galleryImages[index];
|
||||
try {
|
||||
const res = await fetch('/api/gallery/delete', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({ src: img.src.split('/').pop() })
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.ok) {
|
||||
galleryImages.splice(index, 1);
|
||||
renderGallery();
|
||||
await saveGallery();
|
||||
showToast("✅ Gallery image deleted!", "success");
|
||||
} else showToast("Error: " + data.error, "error");
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
showToast("Server error!", "error");
|
||||
}
|
||||
}
|
||||
|
||||
// --- Delete hero image ---
|
||||
async function deleteHeroImage(index) {
|
||||
const img = heroImages[index];
|
||||
try {
|
||||
const res = await fetch('/api/hero/delete', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({ src: img.src.split('/').pop() })
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.ok) {
|
||||
heroImages.splice(index, 1);
|
||||
renderHero();
|
||||
await saveHero();
|
||||
showToast("✅ Hero image deleted!", "success");
|
||||
} else showToast("Error: " + data.error, "error");
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
showToast("Server error!", "error");
|
||||
}
|
||||
}
|
||||
|
||||
// --- Save gallery to server ---
|
||||
async function saveGallery() {
|
||||
@ -316,5 +273,90 @@ function showToast(message, type = "success", duration = 3000) {
|
||||
}, duration);
|
||||
}
|
||||
|
||||
let pendingDelete = null; // { type: 'gallery'|'hero', index: number }
|
||||
|
||||
// --- Show delete confirmation modal ---
|
||||
function showDeleteModal(type, index) {
|
||||
pendingDelete = { type, index };
|
||||
document.getElementById('delete-modal').style.display = 'flex';
|
||||
}
|
||||
|
||||
// --- Hide modal ---
|
||||
function hideDeleteModal() {
|
||||
document.getElementById('delete-modal').style.display = 'none';
|
||||
pendingDelete = null;
|
||||
}
|
||||
|
||||
// --- Confirm deletion ---
|
||||
async function confirmDelete() {
|
||||
if (!pendingDelete) return;
|
||||
if (pendingDelete.type === 'gallery') {
|
||||
await actuallyDeleteGalleryImage(pendingDelete.index);
|
||||
} else if (pendingDelete.type === 'hero') {
|
||||
await actuallyDeleteHeroImage(pendingDelete.index);
|
||||
}
|
||||
hideDeleteModal();
|
||||
}
|
||||
|
||||
|
||||
// --- Modal event listeners ---
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
document.getElementById('delete-modal-close').onclick = hideDeleteModal;
|
||||
document.getElementById('delete-modal-cancel').onclick = hideDeleteModal;
|
||||
document.getElementById('delete-modal-confirm').onclick = confirmDelete;
|
||||
});
|
||||
|
||||
// --- Actual delete functions ---
|
||||
async function actuallyDeleteGalleryImage(index) {
|
||||
const img = galleryImages[index];
|
||||
try {
|
||||
const res = await fetch('/api/gallery/delete', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({ src: img.src.split('/').pop() })
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.ok) {
|
||||
galleryImages.splice(index, 1);
|
||||
renderGallery();
|
||||
await saveGallery();
|
||||
showToast("✅ Gallery image deleted!", "success");
|
||||
} else showToast("Error: " + data.error, "error");
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
showToast("Server error!", "error");
|
||||
}
|
||||
}
|
||||
|
||||
async function actuallyDeleteHeroImage(index) {
|
||||
const img = heroImages[index];
|
||||
try {
|
||||
const res = await fetch('/api/hero/delete', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({ src: img.src.split('/').pop() })
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.ok) {
|
||||
heroImages.splice(index, 1);
|
||||
renderHero();
|
||||
await saveHero();
|
||||
showToast("✅ Hero image deleted!", "success");
|
||||
} else showToast("Error: " + data.error, "error");
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
showToast("Server error!", "error");
|
||||
}
|
||||
}
|
||||
|
||||
// --- Modal event listeners ---
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
document.getElementById('delete-modal-close').onclick = hideDeleteModal;
|
||||
document.getElementById('delete-modal-cancel').onclick = hideDeleteModal;
|
||||
document.getElementById('delete-modal-confirm').onclick = confirmDelete;
|
||||
});
|
||||
|
||||
|
||||
|
||||
// --- Initialize ---
|
||||
loadData();
|
||||
|
@ -51,7 +51,7 @@ h1, h2 {
|
||||
}
|
||||
|
||||
.photo {
|
||||
background-color: rgba(58, 62, 65, 0.26);
|
||||
background-color: rgb(67 67 67 / 26%);
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
@ -163,6 +163,7 @@ h1, h2 {
|
||||
border-radius: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.tag .remove-tag {
|
||||
@ -273,7 +274,7 @@ h1, h2 {
|
||||
.nav > .nav-links {
|
||||
display: inline;
|
||||
float: right;
|
||||
font-size: 12px;
|
||||
font-size: 14px;
|
||||
height: 100%;
|
||||
line-height: 70px;
|
||||
}
|
||||
@ -367,3 +368,61 @@ h1, h2 {
|
||||
.custom-upload-btn:hover {
|
||||
background: #55c3ec;
|
||||
}
|
||||
|
||||
/* Modal styles */
|
||||
.modal {
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
z-index: 10000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
.modal-content {
|
||||
background: #ffffff29;
|
||||
color: #fff;
|
||||
padding: 2rem 2.5rem;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 24px rgba(0,0,0,0.25);
|
||||
min-width: 300px;
|
||||
max-width: 90vw;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
backdrop-filter: blur(20px);
|
||||
}
|
||||
.modal-close {
|
||||
position: absolute;
|
||||
top: 12px; right: 18px;
|
||||
font-size: 1.5rem;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.modal-close:hover { opacity: 1; }
|
||||
.modal-actions {
|
||||
margin-top: 2rem;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
}
|
||||
.modal-btn {
|
||||
padding: 0.5em 1.5em;
|
||||
border-radius: 30px;
|
||||
border: none;
|
||||
background: #09A0C1;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.modal-btn.danger {
|
||||
background: #c62828;
|
||||
}
|
||||
.modal-btn:hover {
|
||||
background: #55c3ec;
|
||||
}
|
||||
.modal-btn.danger:hover {
|
||||
background: #d32f2f;
|
||||
}
|
Reference in New Issue
Block a user