diff options
Diffstat (limited to 'templates/profile.html')
| -rw-r--r-- | templates/profile.html | 292 |
1 files changed, 139 insertions, 153 deletions
diff --git a/templates/profile.html b/templates/profile.html index 7c847f4..bbf70a2 100644 --- a/templates/profile.html +++ b/templates/profile.html @@ -3,199 +3,175 @@ <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Tyler's Film Diary - Lumière</title> + <title>Tyler's Film Diary · Lumière</title> <link rel="icon" href="/static/favicon.svg" type="image/svg+xml"> <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> + <body class="public-profile-page"> + <div class="public-shell"> + <header class="public-topbar"> + <a class="brand" href="/tyler">Lumière</a> + <nav class="public-nav" aria-label="Primary"> + <a class="is-active" href="/tyler">Profile</a> <a href="/about">About</a> + <a href="/login">Private Log In</a> </nav> </header> - <main> - <div style="max-width: 1200px; margin: 0 auto; padding: 40px 20px;"> - <!-- Hero Section --> - <div style="margin-bottom: 40px; padding-bottom: 24px; 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 0 24px 0; color: var(--muted); font-size: 18px;">A curated collection of films watched and loved</p> - - <!-- Tabs --> - <div style="display: flex; gap: 24px; border-bottom: 1px solid var(--line); padding-bottom: 16px;"> - <button id="tab-overview" class="profile-tab is-active" data-tab="overview" style="background: none; border: none; color: var(--text); cursor: pointer; font-size: 16px; padding: 0; border-bottom: 2px solid var(--accent);">Overview</button> - <button id="tab-films" class="profile-tab" data-tab="films" style="background: none; border: none; color: var(--muted); cursor: pointer; font-size: 16px; padding: 0; border-bottom: 2px solid transparent;">All Films</button> + <main class="public-main"> + <section class="public-hero"> + <div class="public-hero-copy"> + <p class="eyebrow">Public Ledger</p> + <h1>Tyler's Film Diary</h1> + <p class="public-hero-text">A public cut of the diary: recent watches, recurring directors, and the films that keep returning.</p> + </div> + <div class="public-hero-metrics"> + <div class="public-metric-card"> + <span class="summary-label">Watched</span> + <strong>{{ total_watched }}</strong> + </div> + <div class="public-metric-card"> + <span class="summary-label">Average</span> + <strong>{{ average_stars }}</strong> </div> </div> + </section> - <!-- Overview Tab --> - <div id="panel-overview" class="tab-panel is-active" style="display: block;"> - <!-- Hero Section Stats --> - <div style="margin-bottom: 60px;"> + <section class="public-tabs"> + <button id="tab-overview" class="public-tab is-active" data-tab="overview" type="button">Overview</button> + <button id="tab-films" class="public-tab" data-tab="films" type="button">All Films</button> + </section> - - <!-- 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> + <section id="panel-overview" class="public-panel is-active"> + <div class="public-grid"> + <section class="public-section"> + <div class="public-section-head"> + <p class="eyebrow">Rotation</p> + <h2>Most watched directors</h2> </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 class="public-list"> + {% for item in most_watched_directors %} + <div class="public-list-row"> + <span>{{ item.director }}</span> + <strong>{{ item.count }}</strong> + </div> + {% endfor %} </div> - </div> - </div> + </section> - <!-- 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> + <section class="public-section"> + <div class="public-section-head"> + <p class="eyebrow">Distribution</p> + <h2>Ratings</h2> </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 %} + <div class="public-bars"> + {% for item in star_distribution %} + <div class="public-bar-row"> + <span> + {% if item.stars == 0 %}Unrated{% else %}{% for _ in range(item.stars) %}✦{% endfor %}{% 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 class="public-bar-track"> + {% if total_watched > 0 %} + <div class="public-bar-fill" style="width: {{ (item.count / total_watched * 100) }}%;"></div> + {% endif %} + </div> + <strong>{{ item.count }}</strong> </div> + {% endfor %} </div> - {% endfor %} - </div> - </div> + </section> - <!-- 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> + {% if films_per_country %} + <section class="public-section public-section-wide"> + <div class="public-section-head"> + <p class="eyebrow">Geography</p> + <h2>Most watched countries</h2> </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 class="public-country-grid"> + {% for item in films_per_country %} + <div class="public-country-card"> + <strong>{{ item.count }}</strong> + <span>{{ item.country }}</span> </div> - {% endif %} - {% if film.date_watched %} - <div style="color: var(--muted); font-size: 12px; margin-top: 4px;">{{ film.date_watched[:10] }}</div> - {% endif %} + {% endfor %} </div> - {% endfor %} - </div> - </div> - {% endif %} - </div> - <!-- End Overview Tab --> + </section> + {% endif %} - <!-- All Films Tab --> - <div id="panel-films" class="tab-panel" style="display: none;"> - <div id="films-feed" style="display: grid; gap: 20px;"> - <!-- Films will be loaded here via infinite scroll --> - </div> - <div id="films-sentinel" data-shelf="diary" data-offset="0" data-total="{{ total_watched }}" style="height: 1px; margin: 20px 0;"></div> + {% if recent_films %} + <section class="public-section public-section-wide"> + <div class="public-section-head"> + <p class="eyebrow">Recent</p> + <h2>Recently watched</h2> + </div> + <div class="public-poster-grid"> + {% for film in recent_films %} + <article class="public-poster-card"> + <div class="poster-frame public-poster-frame"> + {% if film.poster_url %} + <img src="{{ film.poster_url }}" alt="{{ film.title }} poster" loading="lazy"> + {% else %} + <span>{{ film.title[:1] }}</span> + {% endif %} + </div> + <h3>{{ film.title }}</h3> + <p>{{ film.year }}{% if film.director %} · {{ film.director }}{% endif %}</p> + {% if film.date_watched %} + <span class="public-poster-meta">{{ film.date_watched[:10] }}</span> + {% endif %} + </article> + {% endfor %} + </div> + </section> + {% endif %} </div> - <!-- End All Films Tab --> - </div> + </section> + + <section id="panel-films" class="public-panel" hidden> + <div id="public-films-feed" class="public-feed"></div> + <div id="public-films-sentinel" data-offset="0" data-total="{{ total_watched }}" class="public-feed-sentinel"></div> + </section> </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://git.tylerhoang.xyz/lumi.git" style="color: var(--accent); text-decoration: none;">Lumière</a></p> + <footer class="public-footer"> + <p>Made with <a href="https://git.tylerhoang.xyz/lumi.git">Lumière</a></p> </footer> </div> <script> - // Tab switching - document.querySelectorAll(".profile-tab").forEach((tab) => { - tab.addEventListener("click", () => { - const tabName = tab.dataset.tab; - - // Update tab buttons - document.querySelectorAll(".profile-tab").forEach((t) => { - t.classList.remove("is-active"); - t.style.color = "var(--muted)"; - t.style.borderBottomColor = "transparent"; - }); - tab.classList.add("is-active"); - tab.style.color = "var(--text)"; - tab.style.borderBottomColor = "var(--accent)"; + const tabs = document.querySelectorAll(".public-tab"); + const panels = document.querySelectorAll(".public-panel"); + let filmsLoaded = false; - // Update panels - document.querySelectorAll(".tab-panel").forEach((panel) => { - panel.style.display = "none"; - }); - document.getElementById(`panel-${tabName}`).style.display = "block"; - - // Load films if switching to all films tab - if (tabName === "films" && !tab.dataset.loaded) { - loadInitialFilms(); - tab.dataset.loaded = "true"; - } + function setActiveTab(tabName) { + tabs.forEach((tab) => { + const active = tab.dataset.tab === tabName; + tab.classList.toggle("is-active", active); }); - }); + panels.forEach((panel) => { + const active = panel.id === `panel-${tabName}`; + panel.hidden = !active; + }); + } - // Load all films with infinite scroll - function loadInitialFilms() { - const sentinel = document.querySelector("#films-sentinel"); - const feed = document.querySelector("#films-feed"); + async function loadPublicFilms() { + if (filmsLoaded) return; + filmsLoaded = true; + + const sentinel = document.querySelector("#public-films-sentinel"); + const feed = document.querySelector("#public-films-feed"); let loading = false; const loadMore = async () => { if (loading) return; loading = true; - - const offset = Number(sentinel.dataset.offset); - const total = Number(sentinel.dataset.total); + const offset = Number(sentinel.dataset.offset || 0); try { - const response = await fetch(`/films/partial?shelf=diary&offset=${offset}&limit=20`); + const response = await fetch(`/tyler/films/partial?offset=${offset}&limit=20`); if (!response.ok) return; - - const hasMore = response.headers.get("X-Has-More") === "true"; const html = await response.text(); + const hasMore = response.headers.get("X-Has-More") === "true"; if (html.trim()) { feed.insertAdjacentHTML("beforeend", html); @@ -208,7 +184,7 @@ sentinel.dataset.offset = String(offset + 20); } } catch (error) { - console.error("Failed to load films", error); + console.error("Failed to load public films", error); } finally { loading = false; } @@ -223,8 +199,18 @@ }, { rootMargin: "100px" }); observer.observe(sentinel); - loadMore(); // Load first batch immediately + loadMore(); } + + tabs.forEach((tab) => { + tab.addEventListener("click", () => { + const tabName = tab.dataset.tab; + setActiveTab(tabName); + if (tabName === "films") { + loadPublicFilms(); + } + }); + }); </script> </body> </html> |
