summaryrefslogtreecommitdiff
path: root/templates/profile.html
diff options
context:
space:
mode:
Diffstat (limited to 'templates/profile.html')
-rw-r--r--templates/profile.html292
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>