diff options
Diffstat (limited to 'templates')
| -rw-r--r-- | templates/profile.html | 108 |
1 files changed, 106 insertions, 2 deletions
diff --git a/templates/profile.html b/templates/profile.html index f697efe..745ed32 100644 --- a/templates/profile.html +++ b/templates/profile.html @@ -19,9 +19,22 @@ <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);"> + <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; color: var(--muted); font-size: 18px;">A curated collection of films watched and loved</p> + <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> + </div> + </div> + + <!-- Overview Tab --> + <div id="panel-overview" class="tab-panel is-active" style="display: block;"> + <!-- Hero Section Stats --> + <div style="margin-bottom: 60px;"> + <!-- Summary Stats --> <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 24px; margin-top: 32px;"> @@ -114,6 +127,17 @@ </div> </div> {% endif %} + </div> + <!-- End Overview Tab --> + + <!-- 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> + </div> + <!-- End All Films Tab --> </div> </main> @@ -121,5 +145,85 @@ <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> + + <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)"; + + // 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"; + } + }); + }); + + // Load all films with infinite scroll + function loadInitialFilms() { + const sentinel = document.querySelector("#films-sentinel"); + const feed = document.querySelector("#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); + + try { + const response = await fetch(`/films/partial?shelf=diary&offset=${offset}&limit=20`); + if (!response.ok) return; + + const hasMore = response.headers.get("X-Has-More") === "true"; + const html = await response.text(); + + if (html.trim()) { + feed.insertAdjacentHTML("beforeend", html); + } + + if (!hasMore) { + observer.disconnect(); + sentinel.remove(); + } else { + sentinel.dataset.offset = String(offset + 20); + } + } catch (error) { + console.error("Failed to load films", error); + } finally { + loading = false; + } + }; + + const observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + loadMore(); + } + }); + }, { rootMargin: "100px" }); + + observer.observe(sentinel); + loadMore(); // Load first batch immediately + } + </script> </body> </html> |
