tags
This commit is contained in:
1 parent
a9603aa0e8
commit
719f9d51ff
13 files changed
+625
-70
No files matched your search
@@ -1,7 +1,7 @@
|
||||
// ── Detail view ──
|
||||
|
||||
import { $, esc, api, fuzzyMatch } from './util.js';
|
||||
import { state, getChildren, getGroupCards, getRecent, markRecent } from './state.js';
|
||||
import { state, parseTags, tagChipHtml, getChildren, getGroupCards, getRecent, markRecent } from './state.js';
|
||||
import { renderMd, stripMd, firstImage, addCodeCopyButtons } from './markdown.js';
|
||||
import { pushCardDelete, pushCardEdit, snapshotCard } from './undo.js';
|
||||
import { showDialog } from './dialog.js';
|
||||
@@ -87,6 +87,9 @@ function clearMorphGhost() {
|
||||
}
|
||||
}
|
||||
|
||||
let galleryImages = [];
|
||||
let galleryIndex = 0;
|
||||
|
||||
function ensureImageFullscreenOverlay() {
|
||||
if (imageFsOverlay) return imageFsOverlay;
|
||||
|
||||
@@ -96,6 +99,9 @@ function ensureImageFullscreenOverlay() {
|
||||
<button type="button" class="detail-image-fs-close" aria-label="close image">
|
||||
<i class="ph ph-x text-xl"></i>
|
||||
</button>
|
||||
<button type="button" class="detail-image-fs-nav detail-image-fs-prev" aria-label="previous"><i class="ph ph-caret-left"></i></button>
|
||||
<button type="button" class="detail-image-fs-nav detail-image-fs-next" aria-label="next"><i class="ph ph-caret-right"></i></button>
|
||||
<div class="detail-image-fs-counter"></div>
|
||||
<div class="detail-image-fs-stage">
|
||||
<img class="detail-image-fs-img" alt="">
|
||||
</div>
|
||||
@@ -104,6 +110,8 @@ function ensureImageFullscreenOverlay() {
|
||||
if (e.target === overlay) closeImageFullscreen();
|
||||
});
|
||||
overlay.querySelector('.detail-image-fs-close')?.addEventListener('click', closeImageFullscreen);
|
||||
overlay.querySelector('.detail-image-fs-prev')?.addEventListener('click', e => { e.stopPropagation(); navigateGallery(-1); });
|
||||
overlay.querySelector('.detail-image-fs-next')?.addEventListener('click', e => { e.stopPropagation(); navigateGallery(1); });
|
||||
|
||||
document.body.appendChild(overlay);
|
||||
imageFsOverlay = overlay;
|
||||
@@ -118,6 +126,26 @@ function ensureImageFullscreenOverlay() {
|
||||
return overlay;
|
||||
}
|
||||
|
||||
function updateGalleryNav() {
|
||||
if (!imageFsOverlay) return;
|
||||
const hasGallery = galleryImages.length > 1;
|
||||
imageFsOverlay.querySelector('.detail-image-fs-prev').style.display = hasGallery ? '' : 'none';
|
||||
imageFsOverlay.querySelector('.detail-image-fs-next').style.display = hasGallery ? '' : 'none';
|
||||
const counter = imageFsOverlay.querySelector('.detail-image-fs-counter');
|
||||
counter.style.display = hasGallery ? '' : 'none';
|
||||
if (hasGallery) counter.textContent = `${galleryIndex + 1} / ${galleryImages.length}`;
|
||||
}
|
||||
|
||||
function navigateGallery(dir) {
|
||||
if (galleryImages.length < 2) return;
|
||||
galleryIndex = (galleryIndex + dir + galleryImages.length) % galleryImages.length;
|
||||
resetImageFsTransform();
|
||||
if (imageFsImg) {
|
||||
imageFsImg.src = galleryImages[galleryIndex];
|
||||
}
|
||||
updateGalleryNav();
|
||||
}
|
||||
|
||||
function applyImageFsTransform() {
|
||||
if (!imageFsImg) return;
|
||||
imageFsImg.style.transform = `translate(${fsTx}px, ${fsTy}px) scale(${fsScale})`;
|
||||
@@ -178,14 +206,18 @@ function onImageFsMouseUp() {
|
||||
imageFsOverlay?.classList.remove('dragging');
|
||||
}
|
||||
|
||||
function openImageFullscreen(src, alt = '') {
|
||||
function openImageFullscreen(src, alt = '', gallery = []) {
|
||||
if (!src) return;
|
||||
const overlay = ensureImageFullscreenOverlay();
|
||||
resetImageFsTransform();
|
||||
galleryImages = gallery.length > 1 ? gallery : [];
|
||||
galleryIndex = galleryImages.indexOf(src);
|
||||
if (galleryIndex < 0) galleryIndex = 0;
|
||||
if (imageFsImg) {
|
||||
imageFsImg.src = src;
|
||||
imageFsImg.alt = alt || 'image';
|
||||
}
|
||||
updateGalleryNav();
|
||||
overlay.classList.add('open');
|
||||
document.body.classList.add('detail-image-fs-open');
|
||||
}
|
||||
@@ -433,6 +465,32 @@ function showContent(card) {
|
||||
(card.bucket_name ? ' | bucket: ' + card.bucket_name : '');
|
||||
applyZoom();
|
||||
|
||||
// Tags
|
||||
const tags = parseTags(card);
|
||||
const tagEl = $('detail-tags');
|
||||
if (tagEl) {
|
||||
if (tags.length) {
|
||||
tagEl.classList.remove('hidden');
|
||||
tagEl.innerHTML = tags.map(t => tagChipHtml(t)).join('');
|
||||
tagEl.querySelectorAll('.tag-seg[data-tag]').forEach(seg => {
|
||||
seg.addEventListener('click', e => {
|
||||
const tag = seg.dataset.tag;
|
||||
if (e.ctrlKey || e.metaKey) {
|
||||
const idx = state.activeTags.indexOf(tag);
|
||||
if (idx >= 0) state.activeTags.splice(idx, 1);
|
||||
else state.activeTags.push(tag);
|
||||
} else {
|
||||
state.activeTags = [tag];
|
||||
}
|
||||
window._renderTagBar?.();
|
||||
window._renderBoard();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
tagEl.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
// Backlinks
|
||||
const pattern = `[[${card.title}]]`.toLowerCase();
|
||||
const backlinks = state.cards.filter(c => c.id != card.id && (c.body || '').toLowerCase().includes(pattern));
|
||||
@@ -505,7 +563,24 @@ function applyReadingResizeHandles(root) {
|
||||
|
||||
function bindDetailImageFullscreen(root) {
|
||||
if (!root) return;
|
||||
|
||||
// Gallery grids: single click, with prev/next
|
||||
root.querySelectorAll('.md-gallery').forEach(gallery => {
|
||||
const srcs = Array.from(gallery.querySelectorAll('img')).map(i => i.getAttribute('src'));
|
||||
gallery.querySelectorAll('.md-gallery-item').forEach(item => {
|
||||
const img = item.querySelector('img');
|
||||
if (!img) return;
|
||||
item.addEventListener('click', e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
openImageFullscreen(img.getAttribute('src'), img.getAttribute('alt') || 'image', srcs);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Regular images: double-click, no gallery nav
|
||||
root.querySelectorAll('img').forEach(img => {
|
||||
if (img.closest('.md-gallery')) return;
|
||||
img.title = 'double-click to open fullscreen';
|
||||
img.addEventListener('dblclick', e => {
|
||||
e.preventDefault();
|
||||
@@ -526,8 +601,10 @@ detail.addEventListener('click', e => {
|
||||
$('detail-close')?.addEventListener('click', closeDetail);
|
||||
|
||||
document.addEventListener('keydown', e => {
|
||||
if (e.key !== 'Escape') return;
|
||||
if (!imageFsOverlay?.classList.contains('open')) return;
|
||||
if (e.key === 'ArrowLeft') { navigateGallery(-1); e.preventDefault(); return; }
|
||||
if (e.key === 'ArrowRight') { navigateGallery(1); e.preventDefault(); return; }
|
||||
if (e.key !== 'Escape') return;
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
closeImageFullscreen();
|
||||
|
||||
Reference in new issue
Block a user