From dbdbdea109a6f33cee63d246448bb0ed3f2414b6 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 11 Apr 2026 00:21:49 -0400 Subject: [PATCH] Polish: Inter font, glassmorphic nav, hover effects, view transitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 in base template - Disable hover transforms on mobile Co-Authored-By: Claude Opus 4.6 (1M context) --- static/css/style.css | 97 +++++++++++++++++-------- templates/base.html | 5 +- templates/home.html | 7 +- templates/image_detail.html | 2 +- templates/includes/image_grid_page.html | 2 +- 5 files changed, 75 insertions(+), 38 deletions(-) diff --git a/static/css/style.css b/static/css/style.css index 165d807..cc6f4e4 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -8,24 +8,30 @@ --text-muted: #888; --accent: #e8a820; --accent-hover: #f0be44; - --radius: 6px; + --radius: 8px; --max-width: 1200px; + --transition: 0.2s ease; + --shadow: 0 4px 24px rgba(0,0,0,0.5); } [x-cloak] { display: none !important; } * { margin: 0; padding: 0; box-sizing: border-box; } +html { scroll-behavior: smooth; } +::selection { background: var(--accent); color: #000; } body { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: var(--bg); color: var(--text); - line-height: 1.5; + line-height: 1.6; min-height: 100vh; display: flex; flex-direction: column; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } -a { color: var(--accent); text-decoration: none; } +a { color: var(--accent); text-decoration: none; transition: color var(--transition); } a:hover { color: var(--accent-hover); } /* Nav */ @@ -34,22 +40,24 @@ a:hover { color: var(--accent-hover); } align-items: center; gap: 2rem; padding: 1rem 2rem; - border-bottom: 1px solid var(--border); - background: var(--surface); + border-bottom: 1px solid rgba(255,255,255,0.06); + background: rgba(10, 10, 10, 0.8); + backdrop-filter: blur(20px) saturate(180%); + -webkit-backdrop-filter: blur(20px) saturate(180%); position: sticky; top: 0; z-index: 100; } .nav-brand { - font-size: 1.25rem; + font-size: 1.2rem; font-weight: 700; color: var(--text); - letter-spacing: -0.02em; + letter-spacing: -0.03em; } .nav-links { display: flex; gap: 1.5rem; } -.nav-links a { color: var(--text-muted); font-size: 0.9rem; } +.nav-links a { color: var(--text-muted); font-size: 0.875rem; letter-spacing: -0.01em; transition: color var(--transition); } .nav-links a:hover { color: var(--text); } .nav-auth { margin-left: auto; display: flex; gap: 1rem; align-items: center; } @@ -93,14 +101,15 @@ a:hover { color: var(--accent-hover); } /* Buttons */ .btn { display: inline-block; - padding: 0.4rem 1rem; + padding: 0.45rem 1.1rem; border-radius: var(--radius); - font-size: 0.9rem; + font-size: 0.875rem; + font-weight: 500; border: 1px solid var(--border); background: transparent; color: var(--text); cursor: pointer; - transition: all 0.15s; + transition: all var(--transition); } .btn:hover { border-color: var(--text-muted); color: var(--text); } .btn-primary { background: var(--accent); border-color: var(--accent); color: #000; font-weight: 600; } @@ -110,8 +119,8 @@ a:hover { color: var(--accent-hover); } .container { max-width: var(--max-width); margin: 0 auto; padding: 2rem; flex: 1; } .page-header { margin-bottom: 2rem; } -.page-header h1 { font-size: 1.75rem; font-weight: 700; letter-spacing: -0.02em; } -.page-header p { color: var(--text-muted); margin-top: 0.25rem; } +.page-header h1 { font-size: 1.75rem; font-weight: 700; letter-spacing: -0.03em; } +.page-header p { color: var(--text-muted); margin-top: 0.25rem; font-size: 0.95rem; } /* Image grid */ .image-grid { @@ -128,15 +137,17 @@ a:hover { color: var(--accent-hover); } overflow: hidden; background: var(--surface); cursor: pointer; - transition: transform 0.15s; + transition: transform var(--transition), box-shadow var(--transition); } .image-card img { width: 100%; height: 100%; object-fit: cover; display: block; + transition: transform 0.4s ease; } -.image-card:hover, .image-card-selected, .image-card-focused { transform: scale(1.02); } +.image-card:hover img { transform: scale(1.05); } +.image-card:hover, .image-card-selected, .image-card-focused { transform: scale(1.02); box-shadow: var(--shadow); } .image-card-focused { outline: 2px solid var(--accent); outline-offset: 2px; } .image-card-selected { outline: 2px solid var(--accent); outline-offset: 2px; } .image-card .overlay { @@ -144,13 +155,16 @@ a:hover { color: var(--accent-hover); } bottom: 0; left: 0; right: 0; - padding: 0.5rem 0.6rem; - background: linear-gradient(transparent, rgba(0,0,0,0.8)); - color: rgba(255,255,255,0.75); + padding: 2rem 0.75rem 0.6rem; + background: linear-gradient(to top, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.3) 60%, transparent 100%); + color: rgba(255,255,255,0.85); font-size: 0.75rem; line-height: 1.4; + opacity: 0; + transition: opacity var(--transition); } -.image-card .overlay a.overlay-link { color: rgba(255,255,255,0.85); } +.image-card:hover .overlay { opacity: 1; } +.image-card .overlay a.overlay-link { color: rgba(255,255,255,0.9); } .image-card .overlay a.overlay-link:hover { color: var(--accent); } .image-card-user { display: block; @@ -174,9 +188,9 @@ a:hover { color: var(--accent-hover); } background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); - transition: border-color 0.15s; + transition: border-color var(--transition), box-shadow var(--transition), transform var(--transition); } -.gear-card:hover, .gear-card-focused { border-color: var(--text-muted); } +.gear-card:hover, .gear-card-focused { border-color: var(--text-muted); box-shadow: var(--shadow); transform: translateY(-2px); } .gear-card-focused { outline: 2px solid var(--accent); outline-offset: -2px; } /* Brand filter pills */ @@ -187,8 +201,9 @@ a:hover { color: var(--accent-hover); } padding: 0.3rem 0.75rem; border-radius: 999px; font-size: 0.85rem; + font-weight: 500; cursor: pointer; - transition: all 0.15s; + transition: all var(--transition); } .brand-pill:hover { border-color: var(--text-muted); color: var(--text); } .brand-pill-active { background: var(--accent); border-color: var(--accent); color: #000; font-weight: 600; } @@ -229,9 +244,10 @@ a:hover { color: var(--accent-hover); } display: flex; flex-wrap: wrap; gap: 1.5rem; - padding: 1rem 0; - border-top: 1px solid var(--border); - border-bottom: 1px solid var(--border); + padding: 1rem 1.25rem; + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius); margin: 1rem 0; font-size: 0.85rem; } @@ -260,7 +276,7 @@ a:hover { color: var(--accent-hover); } color: var(--text); font-size: 0.9rem; } -.search-form input:focus, .search-form select:focus { outline: none; border-color: var(--accent); } +.search-form input:focus, .search-form select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(232, 168, 32, 0.1); } /* Auth forms */ .auth-form { @@ -368,9 +384,9 @@ a:hover { color: var(--accent-hover); } border-radius: var(--radius); overflow: hidden; color: inherit; - transition: border-color 0.15s; + transition: border-color var(--transition), box-shadow var(--transition), transform var(--transition); } -.collection-card:hover { border-color: var(--text-muted); color: inherit; } +.collection-card:hover { border-color: var(--text-muted); box-shadow: var(--shadow); transform: translateY(-2px); color: inherit; } .collection-card-image { aspect-ratio: 1; @@ -383,7 +399,9 @@ a:hover { color: var(--accent-hover); } height: 100%; object-fit: cover; display: block; + transition: transform 0.4s ease; } +.collection-card:hover .collection-card-image img { transform: scale(1.05); } .collection-card-count { position: absolute; bottom: 0.5rem; @@ -535,7 +553,7 @@ a:hover { color: var(--accent-hover); } .tag-cloud { display: flex; flex-wrap: wrap; - gap: 0.4rem 0.75rem; + gap: 0.5rem 0.85rem; justify-content: center; align-items: center; padding: 2rem 0; @@ -544,7 +562,7 @@ a:hover { color: var(--accent-hover); } .tag-cloud-item { color: var(--text-muted); - transition: color 0.15s; + transition: color var(--transition); white-space: nowrap; } .tag-cloud-item:hover { color: var(--accent); } @@ -559,7 +577,7 @@ a:hover { color: var(--accent-hover); } border-radius: 999px; color: var(--text); font-size: 0.9rem; - transition: all 0.15s; + transition: all var(--transition); } .tag-pill:hover { border-color: var(--accent); color: var(--accent); } @@ -593,6 +611,19 @@ a:hover { color: var(--accent-hover); } .htmx-indicator { opacity: 0; transition: opacity 0.2s; } .htmx-request .htmx-indicator { opacity: 1; } +@keyframes pulse { 0%, 100% { opacity: 0.4; } 50% { opacity: 1; } } +.loading-pulse { animation: pulse 1.5s ease-in-out infinite; } + +/* Focus */ +:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } + +/* View transitions */ +@view-transition { navigation: auto; } +::view-transition-old(root) { animation: fade-out 0.15s ease; } +::view-transition-new(root) { animation: fade-in 0.15s ease; } +@keyframes fade-out { from { opacity: 1; } to { opacity: 0; } } +@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } + /* Responsive */ @media (max-width: 768px) { .site-nav { flex-wrap: wrap; padding: 0.75rem 1rem; gap: 0.75rem; } @@ -600,5 +631,7 @@ a:hover { color: var(--accent-hover); } .container { padding: 1rem; } .image-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 0.5rem; } .image-card .overlay { display: none; } + .image-card:hover img { transform: none; } .profile-header { flex-direction: column; text-align: center; } + .gear-card:hover, .collection-card:hover { transform: none; } } diff --git a/templates/base.html b/templates/base.html index 7a87335..5361ce5 100644 --- a/templates/base.html +++ b/templates/base.html @@ -21,6 +21,10 @@ {% block twitter_image %}{% endblock %} + + + + {% if analytics_code %}{{ analytics_code|safe }}{% endif %} @@ -38,7 +42,6 @@ {% if has_collections %}Collections{% endif %} Search -
diff --git a/templates/home.html b/templates/home.html index 1b55b6e..56c7756 100644 --- a/templates/home.html +++ b/templates/home.html @@ -4,9 +4,10 @@ {% endblock %} {% block content %} -
-

{{ site_title }}

-
+
+

{{ site_title }}

+ {% if site_tagline %}

{{ site_tagline }}

{% endif %} +
All {% for y in years %} diff --git a/templates/image_detail.html b/templates/image_detail.html index b55b365..cb0ea15 100644 --- a/templates/image_detail.html +++ b/templates/image_detail.html @@ -45,7 +45,7 @@
-
+
{% if prev_image %}← Previous{% else %}{% endif %}
Download diff --git a/templates/includes/image_grid_page.html b/templates/includes/image_grid_page.html index fe50781..06c0f97 100644 --- a/templates/includes/image_grid_page.html +++ b/templates/includes/image_grid_page.html @@ -12,6 +12,6 @@ hx-trigger="revealed" hx-swap="outerHTML" style="grid-column: 1 / -1; text-align: center; padding: 2rem;"> - Loading more... + Loading more…
{% endif %}