diff options
| author | Tyler Hoang <tyler@tylerhoang.xyz> | 2026-05-06 15:25:36 -0700 |
|---|---|---|
| committer | Tyler Hoang <tyler@tylerhoang.xyz> | 2026-05-06 15:25:36 -0700 |
| commit | 1bdf4ca8c0f51718124ffe5247ac133973d4f251 (patch) | |
| tree | 2904145bdbc5d2a2164cd3cb6c95346e48afd4a5 /templates/profile.html | |
| parent | 051775337251b0c7036959901eacb58471100862 (diff) | |
Add authentication, public profile, and infinite scroll
- Implement session-based auth with argon2 password hashing
- Add login form and logout button in nav
- Create public /tyler profile page with curated stats
- Implement infinite scroll for film lists (load 20 at a time)
- Add lazy loading for poster images
- Fix profile page CSS to use dark theme variables
- Use consistent star character (✦) across all pages
- Add /films/partial endpoint for pagination
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Diffstat (limited to 'templates/profile.html')
| -rw-r--r-- | templates/profile.html | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/templates/profile.html b/templates/profile.html new file mode 100644 index 0000000..9fac27f --- /dev/null +++ b/templates/profile.html @@ -0,0 +1,124 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Tyler's Film Diary - Lumière</title> + <link rel="stylesheet" href="/static/styles.css" /> + </head> + <body> + <div class="shell"> + <header class="topbar"> + <a class="brand" href="/">Lumière</a> + <nav class="nav-actions" aria-label="Primary"> + <a href="/tyler">Profile</a> + </nav> + </header> + + <main> + <div style="max-width: 1200px; margin: 0 auto; padding: 40px 20px;"> + <!-- Hero Section --> + <div style="margin-bottom: 60px; padding-bottom: 40px; border-bottom: 1px solid var(--line);"> + <h1 style="margin: 0 0 8px 0; font-size: 40px; color: var(--text);">Tyler's Film Diary</h1> + <p style="margin: 0; color: var(--muted); font-size: 18px;">A curated collection of films watched and loved</p> + + <!-- Summary Stats --> + <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 24px; margin-top: 32px;"> + <div style="padding: 20px; background: var(--panel); border: 1px solid var(--line); border-radius: 8px;"> + <div style="font-size: 32px; font-weight: bold; color: var(--text);">{{ total_watched }}</div> + <div style="color: var(--muted); margin-top: 4px;">Films Watched</div> + </div> + <div style="padding: 20px; background: var(--panel); border: 1px solid var(--line); border-radius: 8px;"> + <div style="font-size: 32px; font-weight: bold; color: var(--text);"><span class="rating">{% for _ in range(average_stars|int) %}✦{% endfor %}</span> {{ average_stars }}</div> + <div style="color: var(--muted); margin-top: 4px;">Average Rating</div> + </div> + </div> + </div> + + <!-- Top Directors --> + {% if most_watched_directors %} + <div style="margin-bottom: 60px;"> + <h2 style="margin: 0 0 24px 0; font-size: 24px; color: var(--text);">Top Directors</h2> + <div style="display: grid; gap: 12px;"> + {% for item in most_watched_directors %} + <div style="padding: 12px 16px; background: var(--panel); border: 1px solid var(--line); border-radius: 6px; display: flex; justify-content: space-between; align-items: center;"> + <span style="color: var(--text);">{{ item.director }}</span> + <span style="color: var(--muted); font-size: 14px;">{{ item.count }} film{{ 's' if item.count > 1 else '' }}</span> + </div> + {% endfor %} + </div> + </div> + {% endif %} + + <!-- Star Distribution --> + <div style="margin-bottom: 60px;"> + <h2 style="margin: 0 0 24px 0; font-size: 24px; color: var(--text);">Rating Distribution</h2> + <div style="display: grid; gap: 16px;"> + {% for item in star_distribution %} + <div> + <div style="display: flex; justify-content: space-between; margin-bottom: 8px;"> + <span style="color: var(--text);"> + {% if item.stars == 0 %}No rating{% elif item.stars == 1 %}<span class="rating">✦</span>{% elif item.stars == 2 %}<span class="rating">✦✦</span>{% elif item.stars == 3 %}<span class="rating">✦✦✦</span>{% endif %} + </span> + <span style="color: var(--muted);">{{ item.count }}</span> + </div> + <div style="background: var(--panel-soft); height: 24px; border-radius: 4px; overflow: hidden;"> + {% if total_watched > 0 %} + <div style="background: var(--accent); height: 100%; width: {{ (item.count / total_watched * 100) }}%; border-radius: 4px;"></div> + {% endif %} + </div> + </div> + {% endfor %} + </div> + </div> + + <!-- Top Countries --> + {% if films_per_country %} + <div style="margin-bottom: 60px;"> + <h2 style="margin: 0 0 24px 0; font-size: 24px; color: var(--text);">Top Countries</h2> + <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 16px;"> + {% for item in films_per_country %} + <div style="padding: 16px; background: var(--panel); border: 1px solid var(--line); border-radius: 6px; text-align: center;"> + <div style="font-size: 20px; font-weight: bold; color: var(--text);">{{ item.count }}</div> + <div style="color: var(--muted); margin-top: 4px; font-size: 14px;">{{ item.country }}</div> + </div> + {% endfor %} + </div> + </div> + {% endif %} + + <!-- Recent Films --> + {% if recent_films %} + <div> + <h2 style="margin: 0 0 24px 0; font-size: 24px; color: var(--text);">Recently Watched</h2> + <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 24px;"> + {% for film in recent_films %} + <div style="text-align: center;"> + {% if film.poster_url %} + <img src="{{ film.poster_url }}" alt="{{ film.title }}" loading="lazy" style="width: 100%; border-radius: 8px; margin-bottom: 12px; aspect-ratio: 2/3; object-fit: cover;" /> + {% else %} + <div style="width: 100%; aspect-ratio: 2/3; background: var(--panel); border: 1px solid var(--line); border-radius: 8px; margin-bottom: 12px; display: flex; align-items: center; justify-content: center; color: var(--muted);">No poster</div> + {% endif %} + <h3 style="margin: 0; font-size: 14px; line-height: 1.4; color: var(--text);">{{ film.title }}</h3> + {% if film.stars %} + <div style="color: var(--accent); font-size: 12px; margin-top: 4px; font-weight: 800;"> + <span class="rating">{% for i in range(film.stars) %}✦{% endfor %}</span> + </div> + {% endif %} + {% if film.date_watched %} + <div style="color: var(--muted); font-size: 12px; margin-top: 4px;">{{ film.date_watched[:10] }}</div> + {% endif %} + </div> + {% endfor %} + </div> + </div> + {% endif %} + </div> + </main> + + <footer style="text-align: center; padding: 40px 20px; color: var(--muted); font-size: 12px; border-top: 1px solid var(--line); margin-top: 60px;"> + <p style="margin: 0;">Made with <a href="https://github.com/tylerhoang/lumiere" style="color: var(--accent); text-decoration: none;">Lumière</a></p> + </footer> + </div> + </body> +</html> |
