summaryrefslogtreecommitdiffstats
path: root/views/person.erb
diff options
context:
space:
mode:
Diffstat (limited to 'views/person.erb')
-rw-r--r--views/person.erb129
1 files changed, 122 insertions, 7 deletions
diff --git a/views/person.erb b/views/person.erb
index 1bb25e2..b64dcbd 100644
--- a/views/person.erb
+++ b/views/person.erb
@@ -1,3 +1,57 @@
+<% if admin? %>
+<div class="person-page-wrap">
+ <aside class="bulk-panel" id="bulk-panel">
+ <h2 class="bulk-panel-title">Selection</h2>
+ <p class="bulk-panel-hint" id="bulk-hint">Click photos to select them.</p>
+ <p class="bulk-selected-count" id="bulk-count" style="display:none">
+ <strong id="bulk-n">0</strong> selected
+ &nbsp;<a href="#" id="bulk-clear" style="font-size:.8rem">Clear</a>
+ </p>
+
+ <div id="bulk-actions" style="display:none">
+ <hr class="bulk-sep">
+
+ <% unless @named_people.empty? %>
+ <form id="reassign-form" method="post"
+ action="/admin/people/<%= ERB::Util.url_encode(@person_slug) %>/bulk_reassign">
+ <label class="bulk-label">Reassign to person</label>
+ <select name="to_uuid" class="bulk-select" required>
+ <option value="">— Select person —</option>
+ <% @named_people.each do |p| %>
+ <option value="<%= ERB::Util.html_escape(p[:uuid]) %>"><%= ERB::Util.html_escape(p[:name]) %></option>
+ <% end %>
+ </select>
+ <div id="reassign-rels"></div>
+ <button type="submit" class="btn btn-sm bulk-action-btn"
+ onclick="return populateRels('reassign-rels') && confirm('Reassign ' + selectedRels.size + ' photo(s)?')">
+ Reassign
+ </button>
+ </form>
+ <% end %>
+
+ <form id="move-form" method="post" action="/admin/photos/move_album"
+ style="margin-top:16px">
+ <input type="hidden" name="return_to" value="/people/<%= ERB::Util.url_encode(@person_slug) %>">
+ <label class="bulk-label">Move to album</label>
+ <input type="text" name="dst_rel" list="album-dirs" class="bulk-input"
+ placeholder="album/path" autocomplete="off">
+ <datalist id="album-dirs">
+ <% (@album_dirs || []).each do |d| %>
+ <option value="<%= ERB::Util.html_escape(d) %>">
+ <% end %>
+ </datalist>
+ <div id="move-rels"></div>
+ <button type="submit" class="btn btn-sm bulk-action-btn"
+ onclick="return populateRels('move-rels') && confirm('Move ' + selectedRels.size + ' photo(s) to this album?')">
+ Move
+ </button>
+ </form>
+ </div>
+ </aside>
+
+ <div class="person-page-main">
+<% end %>
+
<div class="album-header">
<div class="breadcrumbs">
<a href="/people">People</a>
@@ -11,16 +65,77 @@
<% if @photos.empty? %>
<p class="empty-album">No photos found.</p>
<% else %>
- <div class="grid">
+ <div class="grid" id="photo-grid">
<% @photos.each do |photo| %>
<% album_url = photo[:dir_rel].empty? ? '/browse/' : "/browse/#{ERB::Util.html_escape(photo[:dir_rel])}" %>
- <a href="<%= album_url %>?photo=<%= ERB::Util.url_encode(photo[:filename]) %>"
- class="card" style="text-decoration:none">
- <div class="thumb-wrap">
- <img src="/thumb/<%= ERB::Util.html_escape(photo[:rel]) %>"
- loading="lazy" alt="<%= ERB::Util.html_escape(photo[:filename]) %>">
+ <% if admin? %>
+ <div class="card selectable-card" data-rel="<%= ERB::Util.html_escape(photo[:rel]) %>"
+ data-href="<%= album_url %>?photo=<%= ERB::Util.url_encode(photo[:filename]) %>">
+ <div class="thumb-wrap">
+ <img src="/thumb/<%= ERB::Util.html_escape(photo[:rel]) %>"
+ loading="lazy" alt="<%= ERB::Util.html_escape(photo[:filename]) %>">
+ <span class="select-checkbox" aria-hidden="true"></span>
+ </div>
</div>
- </a>
+ <% else %>
+ <a href="<%= album_url %>?photo=<%= ERB::Util.url_encode(photo[:filename]) %>"
+ class="card" style="text-decoration:none">
+ <div class="thumb-wrap">
+ <img src="/thumb/<%= ERB::Util.html_escape(photo[:rel]) %>"
+ loading="lazy" alt="<%= ERB::Util.html_escape(photo[:filename]) %>">
+ </div>
+ </a>
+ <% end %>
<% end %>
</div>
<% end %>
+
+<% if admin? %>
+ </div><%# .person-page-main %>
+</div><%# .person-page-wrap %>
+
+<script>
+var selectedRels = new Set();
+
+function updatePanel() {
+ var n = selectedRels.size;
+ document.getElementById('bulk-n').textContent = n;
+ document.getElementById('bulk-count').style.display = n ? '' : 'none';
+ document.getElementById('bulk-hint').style.display = n ? 'none' : '';
+ document.getElementById('bulk-actions').style.display = n ? '' : 'none';
+}
+
+function populateRels(containerId) {
+ if (!selectedRels.size) { alert('No photos selected.'); return false; }
+ var c = document.getElementById(containerId);
+ c.innerHTML = '';
+ selectedRels.forEach(function(rel) {
+ var inp = document.createElement('input');
+ inp.type = 'hidden'; inp.name = 'rels[]'; inp.value = rel;
+ c.appendChild(inp);
+ });
+ return true;
+}
+
+document.querySelectorAll('.selectable-card').forEach(function(card) {
+ card.addEventListener('click', function(e) {
+ if (e.target.closest('.select-checkbox') || e.shiftKey || e.ctrlKey || e.metaKey) {
+ e.preventDefault();
+ var rel = card.dataset.rel;
+ if (selectedRels.has(rel)) { selectedRels.delete(rel); card.classList.remove('selected'); }
+ else { selectedRels.add(rel); card.classList.add('selected'); }
+ updatePanel();
+ } else {
+ window.open(card.dataset.href, '_blank');
+ }
+ });
+});
+
+document.getElementById('bulk-clear').addEventListener('click', function(e) {
+ e.preventDefault();
+ selectedRels.clear();
+ document.querySelectorAll('.selectable-card.selected').forEach(function(c) { c.classList.remove('selected'); });
+ updatePanel();
+});
+</script>
+<% end %>