Files
kennethreitz dbdbdea109 Polish: Inter font, glassmorphic nav, hover effects, view transitions
- 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>
2026-04-11 00:21:49 -04:00

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">&larr; Previous</a>{% else %}<span class="btn" style="visibility: hidden;">&larr; 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 &rarr;</a>{% else %}<span class="btn" style="visibility: hidden;">Next &rarr;</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: '&copy; OSM &copy; 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 %}