mirror of
https://github.com/kennethreitz/photos.kennethreitz.org.git
synced 2026-06-21 15:10:56 +00:00
dbdbdea109
- Add Inter font via Google Fonts with proper preconnect - Nav: backdrop-filter blur with semi-transparent background - Image cards: hover-reveal overlay, inner zoom, shadow on hover - Gear/collection cards: hover lift with shadow - EXIF bar: rounded card style instead of bordered lines - Search inputs: accent focus glow ring - Homepage: display site tagline, more generous hero spacing - View Transitions API for smooth cross-page fades (Chrome 126+) - Animated loading pulse for infinite scroll - Global: smooth scroll, accent selection color, focus-visible - Radius 6px→8px, font smoothing, CSS custom properties - Fix stray </div> in base template - Disable hover transforms on mobile Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
159 lines
9.3 KiB
HTML
159 lines
9.3 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}{% if image.ai_title %}{{ image.ai_title }}{% if image.exif and image.exif.camera %} | {{ image.exif.camera.display_name }}{% endif %} — {{ site_title }}{% endif %}{% endblock %}
|
|
{% block meta_description %}{% if image.ai_description %}{{ image.ai_description }}{% else %}{{ site_tagline }}{% endif %}{% endblock %}
|
|
{% block og_title %}{% if image.ai_title %}{{ image.ai_title }}{% else %}Photo{% endif %}{% endblock %}
|
|
{% block og_description %}{% if image.ai_description %}{{ image.ai_description }}{% elif image.exif and image.exif.camera %}Shot on {{ image.exif.camera.display_name }}{% endif %}{% endblock %}
|
|
{% block og_type %}article{% endblock %}
|
|
{% block og_image %}{% if image.thumbnail_large %}<meta property="og:image" content="{{ image.thumbnail_large.url }}"><meta property="og:image:width" content="1600">{% elif image.thumbnail_medium %}<meta property="og:image" content="{{ image.thumbnail_medium.url }}">{% endif %}{% endblock %}
|
|
{% block twitter_card %}summary_large_image{% endblock %}
|
|
{% block twitter_title %}{% if image.ai_title %}{{ image.ai_title }}{% else %}Photo{% endif %}{% endblock %}
|
|
{% block twitter_description %}{% if image.ai_description %}{{ image.ai_description }}{% elif image.exif and image.exif.camera %}Shot on {{ image.exif.camera.display_name }}{% endif %}{% endblock %}
|
|
{% block twitter_image %}{% if image.thumbnail_large %}<meta name="twitter:image" content="{{ image.thumbnail_large.url }}">{% elif image.thumbnail_medium %}<meta name="twitter:image" content="{{ image.thumbnail_medium.url }}">{% endif %}{% endblock %}
|
|
{% block head %}
|
|
<link rel="alternate" type="application/json+oembed" href="https://photos.kennethreitz.org/oembed?url=https://photos.kennethreitz.org/images/{{ image.id }}/&format=json" title="{{ image.ai_title|default:'Photo' }}">
|
|
{% if image.tags.all %}<meta name="keywords" content="{% for tag in image.tags.all %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %}{% if image.exif and image.exif.camera %}, {{ image.exif.camera.display_name }}{% endif %}{% if image.exif and image.exif.lens %}, {{ image.exif.lens.display_name }}{% endif %}">{% endif %}
|
|
{% if image.exif and image.exif.gps_latitude and image.exif.gps_longitude %}
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
|
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
{% endif %}
|
|
<script type="application/ld+json">
|
|
{
|
|
"@context": "https://schema.org",
|
|
"@type": "ImageObject",
|
|
{% if image.ai_title %}"name": "{{ image.ai_title|escapejs }}",{% endif %}
|
|
{% if image.ai_description %}"description": "{{ image.ai_description|escapejs }}",{% endif %}
|
|
{% if image.thumbnail_large %}"contentUrl": "{{ image.thumbnail_large.url }}",
|
|
"thumbnailUrl": "{{ image.thumbnail_small.url }}",{% endif %}
|
|
{% if image.exif and image.exif.date_taken %}"dateCreated": "{{ image.exif.date_taken|date:'c' }}",{% endif %}
|
|
"author": {
|
|
"@type": "Person",
|
|
"name": "{{ site_title }}"
|
|
}{% if image.exif and image.exif.camera %},
|
|
"exifData": [
|
|
{% if image.exif.camera %}{"@type": "PropertyValue", "name": "camera", "value": "{{ image.exif.camera.display_name|escapejs }}"}{% endif %}{% if image.exif.lens %},{"@type": "PropertyValue", "name": "lens", "value": "{{ image.exif.lens.display_name|escapejs }}"}{% endif %}{% if image.exif.focal_length %},{"@type": "PropertyValue", "name": "focalLength", "value": "{{ image.exif.focal_length }}mm"}{% endif %}{% if image.exif.aperture %},{"@type": "PropertyValue", "name": "fNumber", "value": "f/{{ image.exif.aperture }}"}{% endif %}{% if image.exif.iso %},{"@type": "PropertyValue", "name": "isoSpeed", "value": "{{ image.exif.iso }}"}{% endif %}
|
|
]{% endif %}
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
{% block content %}
|
|
<div>
|
|
<!-- Image -->
|
|
<div style="margin-bottom: 1rem;">
|
|
{% if image.thumbnail_large %}<img src="{{ image.thumbnail_large.url }}" alt="{{ image.ai_title|default:image.title }}" style="max-width: 100%; border-radius: var(--radius);">
|
|
{% elif image.thumbnail_medium %}<img src="{{ image.thumbnail_medium.url }}" alt="{{ image.ai_title|default:image.title }}" style="max-width: 100%; border-radius: var(--radius);">
|
|
{% elif image.thumbnail_small %}<img src="{{ image.thumbnail_small.url }}" alt="{{ image.ai_title|default:image.title }}" style="max-width: 100%; border-radius: var(--radius);">{% endif %}
|
|
</div>
|
|
|
|
<!-- Prev / Download / Next -->
|
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.25rem; padding: 0.6rem 0; border-bottom: 1px solid var(--border);">
|
|
{% if prev_image %}<a href="/images/{{ prev_image.id }}/" class="btn" id="prev-link">← Previous</a>{% else %}<span class="btn" style="visibility: hidden;">← Previous</span>{% endif %}
|
|
<details style="position: relative;">
|
|
<summary class="btn">Download</summary>
|
|
<div class="dropdown-menu" style="left: 50%; transform: translateX(-50%); min-width: 180px; margin-top: 0.25rem;">
|
|
{% if image.thumbnail_small %}<a href="{{ image.thumbnail_small.url }}" download><strong>S</strong> <span style="color: var(--text-muted);">Small (300px)</span></a>{% endif %}
|
|
{% if image.thumbnail_medium %}<a href="{{ image.thumbnail_medium.url }}" download><strong>M</strong> <span style="color: var(--text-muted);">Medium (800px)</span></a>{% endif %}
|
|
{% if image.thumbnail_large %}<a href="{{ image.thumbnail_large.url }}" download><strong>L</strong> <span style="color: var(--text-muted);">Large (1600px)</span></a>{% endif %}
|
|
<hr>
|
|
{% if image.original %}<a href="{{ image.original.url }}" download><strong>O</strong> <span style="color: var(--text-muted);">Original</span></a>{% endif %}
|
|
</div>
|
|
</details>
|
|
{% if next_image %}<a href="/images/{{ next_image.id }}/" class="btn" id="next-link">Next →</a>{% else %}<span class="btn" style="visibility: hidden;">Next →</span>{% endif %}
|
|
</div>
|
|
|
|
<!-- Title & Description -->
|
|
{% if image.ai_title %}<h1 style="font-size: 1.5rem; font-weight: 700; margin-bottom: 0.25rem;">{{ image.ai_title }}</h1>{% endif %}
|
|
{% if image.ai_description %}<p style="margin-bottom: 1rem;">{{ image.ai_description }}</p>{% endif %}
|
|
|
|
<!-- EXIF bar -->
|
|
{% if image.exif %}
|
|
<div class="exif-bar">
|
|
<div style="display: flex; flex-wrap: wrap; gap: 1rem 1.5rem;">
|
|
{% if image.exif.camera %}
|
|
<div class="exif-item">
|
|
<span class="exif-label">Camera</span>
|
|
<a href="/cameras/{{ image.exif.camera.slug }}/">{{ image.exif.camera.display_name }}</a>
|
|
</div>
|
|
{% endif %}
|
|
{% if image.exif.lens %}
|
|
<div class="exif-item">
|
|
<span class="exif-label">Lens</span>
|
|
<a href="/lenses/{{ image.exif.lens.slug }}/">{{ image.exif.lens.display_name }}</a>
|
|
</div>
|
|
{% endif %}
|
|
{% if image.exif.focal_length %}
|
|
<div class="exif-item">
|
|
<span class="exif-label">Focal Length</span>
|
|
<span>{{ image.exif.focal_length }}mm</span>
|
|
</div>
|
|
{% endif %}
|
|
{% if image.exif.aperture %}
|
|
<div class="exif-item">
|
|
<span class="exif-label">Aperture</span>
|
|
<span>f/{{ image.exif.aperture }}</span>
|
|
</div>
|
|
{% endif %}
|
|
{% if image.exif.shutter_speed %}
|
|
<div class="exif-item">
|
|
<span class="exif-label">Shutter Speed</span>
|
|
<span>{{ image.exif.shutter_speed }}s</span>
|
|
</div>
|
|
{% endif %}
|
|
{% if image.exif.iso %}
|
|
<div class="exif-item">
|
|
<span class="exif-label">ISO</span>
|
|
<span>{{ image.exif.iso }}</span>
|
|
</div>
|
|
{% endif %}
|
|
{% if image.exif.date_taken %}
|
|
<div class="exif-item">
|
|
<span class="exif-label">Date Taken</span>
|
|
<span>{{ image.exif.date_taken|date:"N j, Y" }}</span>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Tags & views -->
|
|
<div style="margin-top: 0.75rem;">
|
|
{% if image.tags.all %}
|
|
<div style="display: flex; flex-wrap: wrap; gap: 0.3rem; margin-bottom: 0.5rem;">
|
|
{% for tag in image.tags.all %}
|
|
<a href="/tags/{{ tag.slug }}/" class="tag-pill" style="font-size: 0.8rem; padding: 0.2rem 0.6rem;">{{ tag.name }}</a>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
<p style="color: var(--text-muted); font-size: 0.85rem;">{{ image.view_count }} views</p>
|
|
</div>
|
|
|
|
{% if image.exif and image.exif.gps_latitude and image.exif.gps_longitude %}
|
|
<div id="map" style="height: 250px; border-radius: var(--radius); margin: 1rem 0;"></div>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
var map = L.map('map').setView([{{ image.exif.gps_latitude }}, {{ image.exif.gps_longitude }}], 5);
|
|
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
|
|
attribution: '© OSM © CARTO', maxZoom: 19,
|
|
}).addTo(map);
|
|
L.marker([{{ image.exif.gps_latitude }}, {{ image.exif.gps_longitude }}]).addTo(map);
|
|
});
|
|
</script>
|
|
{% endif %}
|
|
</div>
|
|
{% endblock %}
|
|
{% block scripts %}
|
|
<script>
|
|
document.addEventListener('keydown', function(e) {
|
|
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
|
|
if (e.key === 'ArrowLeft') {
|
|
var prev = document.getElementById('prev-link');
|
|
if (prev) prev.click();
|
|
} else if (e.key === 'ArrowRight') {
|
|
var next = document.getElementById('next-link');
|
|
if (next) next.click();
|
|
} else if (e.key === 'o' || e.key === 'O') {
|
|
{% if image.original %}window.location.href = '{{ image.original.url }}';{% endif %}
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|