summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app.rb13
-rw-r--r--public/css/style.css5
-rw-r--r--views/admin/album.erb26
3 files changed, 39 insertions, 5 deletions
diff --git a/app.rb b/app.rb
index 0678c67..af18d44 100644
--- a/app.rb
+++ b/app.rb
@@ -160,7 +160,7 @@ helpers do
cover = data['cover']
return cover if cover && cover != '__random__' && File.exist?(File.join(dir, cover))
candidates = cover_candidates(dir)
- cover == '__random__' ? candidates.sample : candidates.first
+ candidates.sample
end
def cover_candidates(dir)
@@ -413,6 +413,17 @@ post '/admin/edit/*' do
rel = params[:splat].first.chomp('/')
dir = resolve_dir(rel)
+ # Handle file deletions before save so save_edits doesn't re-add them
+ to_delete = (params['file_delete'] || {}).select { |_, v| v == '1' }.keys
+ to_delete.each do |name|
+ full = File.join(dir, name)
+ thumb = File.join(CACHE_ROOT, rel.empty? ? "#{name}.th.jpg" : "#{rel}/#{name}.th.jpg")
+ File.unlink(full) if File.exist?(full)
+ File.unlink(thumb) if File.exist?(thumb)
+ params['file_visible']&.delete(name)
+ params['file_caption']&.delete(name)
+ end
+
unless rel.empty?
new_name = params['folder_name'].to_s.strip
new_name = '' if new_name.include?('/') || new_name.include?("\x00") ||
diff --git a/public/css/style.css b/public/css/style.css
index e6ebff3..41dfd0a 100644
--- a/public/css/style.css
+++ b/public/css/style.css
@@ -379,6 +379,11 @@ legend { padding: 0 8px; color: var(--text-dim); font-size: .85rem; }
.files-table { font-size: .78rem; }
}
+/* ── Admin delete ──────────────────────────────────────────────────────── */
+.delete-cell { text-align: center; }
+.delete-check { accent-color: #c0392b; width: 16px; height: 16px; cursor: pointer; }
+tr.delete-marked td { background: rgba(192,57,43,.08); }
+
/* ── Admin update panel ────────────────────────────────────────────────── */
.admin-update { margin-top: 32px; }
.admin-update h2 { font-size: 1rem; color: var(--text-dim); margin-bottom: 6px; }
diff --git a/views/admin/album.erb b/views/admin/album.erb
index 49ec4ca..f28d515 100644
--- a/views/admin/album.erb
+++ b/views/admin/album.erb
@@ -63,6 +63,7 @@
<th>Caption</th>
<th>Visible</th>
<th>Cover</th>
+ <th>Delete</th>
</tr>
</thead>
<tbody>
@@ -80,6 +81,9 @@
<td class="cover-cell">
<input type="radio" name="album_cover_file" value="<%= name %>" class="cover-radio"<%= ' checked' if @data['cover'] == name %>>
</td>
+ <td class="delete-cell">
+ <input type="checkbox" name="file_delete[<%= name %>]" value="1" class="delete-check">
+ </td>
</tr>
<% end %>
</tbody>
@@ -96,10 +100,24 @@
(function () {
const randomCb = document.getElementById('cover-random');
const radios = () => document.querySelectorAll('.cover-radio');
- if (!randomCb) return;
- radios().forEach(r => r.addEventListener('change', () => { randomCb.checked = false; }));
- randomCb.addEventListener('change', function () {
- if (this.checked) radios().forEach(r => { r.checked = false; });
+ if (randomCb) {
+ radios().forEach(r => r.addEventListener('change', () => { randomCb.checked = false; }));
+ randomCb.addEventListener('change', function () {
+ if (this.checked) radios().forEach(r => { r.checked = false; });
+ });
+ }
+
+ document.querySelectorAll('.delete-check').forEach(cb => {
+ cb.addEventListener('change', function () {
+ this.closest('tr').classList.toggle('delete-marked', this.checked);
+ });
+ });
+
+ document.querySelector('form').addEventListener('submit', function (e) {
+ const count = document.querySelectorAll('.delete-check:checked').length;
+ if (count > 0 && !confirm(`Permanently delete ${count} photo${count !== 1 ? 's' : ''}? This cannot be undone.`)) {
+ e.preventDefault();
+ }
});
})();
</script>