Add image attachment lightbox
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
{% if item.attachments.all %}
|
||||
<div class="small mt-2">{% trans "Attachments:" %} {% for a in item.attachments.all %}<a href="{{ a.file.url }}">{{ a.file.name }}</a> {% endfor %}</div>
|
||||
<div class="d-flex flex-wrap gap-2 mt-2">
|
||||
{% for a in item.attachments.all %}{% if a.file.name|is_image and not a|is_embedded:item %}<a href="{{ a.file.url }}" target="_blank"><img src="{{ a.file.url }}" class="img-thumbnail" style="max-width:220px;max-height:180px" alt="{{ a.file.name }}"></a>{% endif %}{% endfor %}
|
||||
{% for a in item.attachments.all %}{% if a.file.name|is_image and not a|is_embedded:item %}<button type="button" class="btn p-0 border-0 bg-transparent attachment-image-preview" data-image-url="{{ a.file.url }}" data-image-name="{{ a.file.name }}"><img src="{{ a.file.url }}" class="img-thumbnail" style="max-width:220px;max-height:180px" alt="{{ a.file.name }}"></button>{% endif %}{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
{% block toolbar_filter %}{% endblock %}
|
||||
</div>
|
||||
<main class="container shell py-4">{% for message in messages %}<div class="alert alert-{{ message.tags|default:'info' }}">{{ message }}</div>{% endfor %}{% block content %}{% endblock %}</main>
|
||||
<div id="image-lightbox" class="position-fixed top-0 start-0 w-100 h-100 d-none align-items-center justify-content-center p-3" style="z-index:2000;background:rgba(15,23,42,.72)" role="dialog" aria-modal="true" aria-label="{% trans 'Image preview' %}">
|
||||
<button type="button" class="btn btn-light position-absolute top-0 end-0 m-3" data-lightbox-close aria-label="{% trans 'Close' %}">×</button>
|
||||
<img class="img-fluid bg-white rounded shadow" style="max-height:90vh;max-width:95vw" alt="">
|
||||
</div>
|
||||
{% if user.is_authenticated and request.resolver_match.url_name == 'index' %}<nav class="mobile-bottom-nav gap-1 d-md-none" aria-label="Mobile navigation"><a class="btn btn-primary flex-fill" href="{% url 'new_item' %}?kind=todo">Aufgabe</a><a class="btn btn-secondary flex-fill" href="{% url 'new_item' %}?kind=note">Notiz</a><a class="btn btn-success flex-fill" href="{% url 'new_item' %}?kind=link">Link</a><a class="btn btn-info flex-fill" href="{% url 'new_item' %}?kind=journal">Journal</a></nav>{% endif %}
|
||||
<script>
|
||||
document.body.addEventListener('htmx:configRequest', e => {e.detail.headers['X-CSRFToken']='{{ csrf_token }}'});
|
||||
@@ -63,6 +67,9 @@ async function writeClipboard(text){if(navigator.clipboard&&window.isSecureConte
|
||||
function copyItemText(button,text){writeClipboard(text).then(()=>{button.innerHTML='✓';setTimeout(()=>button.innerHTML='⧉',1200)})}
|
||||
function enhanceCodeBlocks(root=document){root.querySelectorAll('.content pre:not([data-copy])').forEach(pre=>{pre.dataset.copy='1';let btn=document.createElement('button');btn.type='button';btn.className='copy-code btn btn-sm btn-light';btn.title='Kopieren';btn.innerHTML='⧉';btn.addEventListener('click',()=>writeClipboard(pre.querySelector('code')?.innerText || pre.innerText).then(()=>{btn.innerHTML='✓';setTimeout(()=>btn.innerHTML='⧉',1200)}));pre.appendChild(btn)})}
|
||||
document.addEventListener('DOMContentLoaded',()=>enhanceCodeBlocks());document.body.addEventListener('htmx:afterSwap',e=>enhanceCodeBlocks(e.target));
|
||||
function closeImageLightbox(){let box=document.getElementById('image-lightbox');if(box)box.classList.add('d-none')}
|
||||
document.addEventListener('click', event => {let trigger=event.target.closest('.attachment-image-preview');if(trigger){let box=document.getElementById('image-lightbox');let img=box?.querySelector('img');if(box&&img){img.src=trigger.dataset.imageUrl;img.alt=trigger.dataset.imageName||'';box.classList.remove('d-none');box.classList.add('d-flex')}return}let box=event.target.closest('#image-lightbox');if(box&&(event.target===box||event.target.closest('[data-lightbox-close]')))closeImageLightbox()});
|
||||
document.addEventListener('keydown', event => {if(event.key==='Escape')closeImageLightbox()});
|
||||
document.addEventListener('click', event => {let link=event.target.closest('a.tag-filter[data-tag]');if(!link||!(event.ctrlKey||event.metaKey))return;event.preventDefault();let url=new URL(window.location.href);let tag=link.dataset.tag;let tags=url.searchParams.getAll('tag');url.searchParams.delete('tag');if(tags.includes(tag)){tags=tags.filter(t=>t!==tag)}else{tags.push(tag)}tags.forEach(t=>url.searchParams.append('tag',t));window.location.href=url.pathname+(url.searchParams.toString()?'?'+url.searchParams.toString():'')});
|
||||
let deferredPwaPrompt=null;window.addEventListener('beforeinstallprompt',event=>{event.preventDefault();deferredPwaPrompt=event;document.getElementById('pwa-install')?.classList.remove('d-none')});document.addEventListener('click',async event=>{if(event.target?.id==='pwa-install'&&deferredPwaPrompt){deferredPwaPrompt.prompt();await deferredPwaPrompt.userChoice;deferredPwaPrompt=null;event.target.classList.add('d-none')}});
|
||||
if('serviceWorker' in navigator){window.addEventListener('load',()=>navigator.serviceWorker.register('/sw.js').catch(()=>{}));}
|
||||
|
||||
Reference in New Issue
Block a user