From cdd28b6c0a3a6444b9ae79b123fe4fa7401de5ab Mon Sep 17 00:00:00 2001 From: Tyler Hoang Date: Thu, 14 May 2026 01:31:34 -0700 Subject: Refine Lumi layouts and public profile --- main.py | 2 +- routers/profile.py | 25 + static/app.js | 5 +- .../fonts/EBGaramond-Italic-VariableFont_wght.ttf | Bin 0 -> 811012 bytes static/fonts/EBGaramond-VariableFont_wght.ttf | Bin 0 -> 934420 bytes static/fonts/IBMPlexMono-Medium.ttf | Bin 0 -> 134956 bytes static/fonts/IBMPlexMono-Regular.ttf | Bin 0 -> 133796 bytes static/fonts/IBMPlexMono-SemiBold.ttf | Bin 0 -> 138448 bytes .../IBMPlexSans-Italic-VariableFont_wdth,wght.ttf | Bin 0 -> 594116 bytes .../fonts/IBMPlexSans-VariableFont_wdth,wght.ttf | Bin 0 -> 532740 bytes static/styles.css | 1432 +++++++++++++++++--- templates/_feed_partial.html | 12 +- templates/_film_card.html | 112 +- templates/_public_feed_partial.html | 71 + templates/base.html | 66 +- templates/detail.html | 455 ++++--- templates/form.html | 226 +-- templates/index.html | 65 +- templates/profile.html | 298 ++-- 19 files changed, 2092 insertions(+), 677 deletions(-) create mode 100644 static/fonts/EBGaramond-Italic-VariableFont_wght.ttf create mode 100644 static/fonts/EBGaramond-VariableFont_wght.ttf create mode 100644 static/fonts/IBMPlexMono-Medium.ttf create mode 100644 static/fonts/IBMPlexMono-Regular.ttf create mode 100644 static/fonts/IBMPlexMono-SemiBold.ttf create mode 100644 static/fonts/IBMPlexSans-Italic-VariableFont_wdth,wght.ttf create mode 100644 static/fonts/IBMPlexSans-VariableFont_wdth,wght.ttf create mode 100644 templates/_public_feed_partial.html diff --git a/main.py b/main.py index 6b1a06b..16be52f 100644 --- a/main.py +++ b/main.py @@ -16,7 +16,7 @@ load_dotenv() class AuthMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): - public_paths = {"/about", "/login", "/logout", "/tyler", "/films/partial"} + public_paths = {"/about", "/login", "/logout", "/tyler", "/films/partial", "/tyler/films/partial"} path = request.url.path if path.startswith("/static") or path in public_paths: diff --git a/routers/profile.py b/routers/profile.py index 1986257..8e4a081 100644 --- a/routers/profile.py +++ b/routers/profile.py @@ -1,12 +1,15 @@ from fastapi import APIRouter, Depends, Request +from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates from sqlalchemy.orm import Session from database import get_db from models import Film +from services.film_people import split_credit_names router = APIRouter(tags=["profile"]) templates = Jinja2Templates(directory="templates") +templates.env.globals.update(split_credit_names=split_credit_names) def _diary_films(db: Session) -> list[Film]: @@ -72,6 +75,8 @@ def _build_profile_payload(films: list[Film]) -> dict: "id": film.id, "title": film.title, "poster_url": film.poster_url, + "year": film.year, + "director": split_credit_names(film.director)[0] if film.director else None, "date_watched": film.date_watched.isoformat() if film.date_watched else None, "stars": film.stars, } @@ -89,3 +94,23 @@ async def public_profile(request: Request, db: Session = Depends(get_db)): name="profile.html", context={"request": request, **payload}, ) + + +@router.get("/tyler/films/partial") +async def public_profile_films_partial( + request: Request, + offset: int = 0, + limit: int = 20, + db: Session = Depends(get_db), +): + films = _diary_films(db) + page = films[offset : offset + limit] + has_more = (offset + limit) < len(films) + + html = templates.get_template("_public_feed_partial.html").render( + request=request, + films=page, + ) + response = HTMLResponse(html) + response.headers["X-Has-More"] = "true" if has_more else "false" + return response diff --git a/static/app.js b/static/app.js index 04997a0..39f8276 100644 --- a/static/app.js +++ b/static/app.js @@ -365,7 +365,10 @@ document.querySelectorAll(".star-control[data-form-stars]").forEach((control) => const cur = groups[i]; const prev = groups[i - 1]; if (cur.dataset.month === prev.dataset.month) { - cur.querySelectorAll(".film-card").forEach((card) => prev.appendChild(card)); + const prevStack = prev.querySelector(".month-stack"); + const curStack = cur.querySelector(".month-stack"); + if (!prevStack || !curStack) continue; + curStack.querySelectorAll(".film-card").forEach((card) => prevStack.appendChild(card)); cur.remove(); } } diff --git a/static/fonts/EBGaramond-Italic-VariableFont_wght.ttf b/static/fonts/EBGaramond-Italic-VariableFont_wght.ttf new file mode 100644 index 0000000..9cb1376 Binary files /dev/null and b/static/fonts/EBGaramond-Italic-VariableFont_wght.ttf differ diff --git a/static/fonts/EBGaramond-VariableFont_wght.ttf b/static/fonts/EBGaramond-VariableFont_wght.ttf new file mode 100644 index 0000000..baf64b2 Binary files /dev/null and b/static/fonts/EBGaramond-VariableFont_wght.ttf differ diff --git a/static/fonts/IBMPlexMono-Medium.ttf b/static/fonts/IBMPlexMono-Medium.ttf new file mode 100644 index 0000000..8253c5f Binary files /dev/null and b/static/fonts/IBMPlexMono-Medium.ttf differ diff --git a/static/fonts/IBMPlexMono-Regular.ttf b/static/fonts/IBMPlexMono-Regular.ttf new file mode 100644 index 0000000..601ae94 Binary files /dev/null and b/static/fonts/IBMPlexMono-Regular.ttf differ diff --git a/static/fonts/IBMPlexMono-SemiBold.ttf b/static/fonts/IBMPlexMono-SemiBold.ttf new file mode 100644 index 0000000..5e0b41d Binary files /dev/null and b/static/fonts/IBMPlexMono-SemiBold.ttf differ diff --git a/static/fonts/IBMPlexSans-Italic-VariableFont_wdth,wght.ttf b/static/fonts/IBMPlexSans-Italic-VariableFont_wdth,wght.ttf new file mode 100644 index 0000000..6232aaa Binary files /dev/null and b/static/fonts/IBMPlexSans-Italic-VariableFont_wdth,wght.ttf differ diff --git a/static/fonts/IBMPlexSans-VariableFont_wdth,wght.ttf b/static/fonts/IBMPlexSans-VariableFont_wdth,wght.ttf new file mode 100644 index 0000000..9add875 Binary files /dev/null and b/static/fonts/IBMPlexSans-VariableFont_wdth,wght.ttf differ diff --git a/static/styles.css b/static/styles.css index 2a6cd04..637348f 100644 --- a/static/styles.css +++ b/static/styles.css @@ -1,18 +1,94 @@ -@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;1,400;1,500&display=swap'); +@font-face { + font-family: "EB Garamond"; + src: url("/static/fonts/EBGaramond-VariableFont_wght.ttf") format("truetype-variations"), + url("/static/fonts/EBGaramond-VariableFont_wght.ttf") format("truetype"); + font-weight: 400 800; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "EB Garamond"; + src: url("/static/fonts/EBGaramond-Italic-VariableFont_wght.ttf") format("truetype-variations"), + url("/static/fonts/EBGaramond-Italic-VariableFont_wght.ttf") format("truetype"); + font-weight: 400 800; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: "IBM Plex Sans"; + src: url("/static/fonts/IBMPlexSans-VariableFont_wdth,wght.ttf") format("truetype-variations"), + url("/static/fonts/IBMPlexSans-VariableFont_wdth,wght.ttf") format("truetype"); + font-weight: 100 700; + font-stretch: 85% 100%; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "IBM Plex Sans"; + src: url("/static/fonts/IBMPlexSans-Italic-VariableFont_wdth,wght.ttf") format("truetype-variations"), + url("/static/fonts/IBMPlexSans-Italic-VariableFont_wdth,wght.ttf") format("truetype"); + font-weight: 100 700; + font-stretch: 85% 100%; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: "IBM Plex Mono"; + src: url("/static/fonts/IBMPlexMono-Regular.ttf") format("truetype"); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "IBM Plex Mono"; + src: url("/static/fonts/IBMPlexMono-Medium.ttf") format("truetype"); + font-weight: 500; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "IBM Plex Mono"; + src: url("/static/fonts/IBMPlexMono-SemiBold.ttf") format("truetype"); + font-weight: 600; + font-style: normal; + font-display: swap; +} + :root { color-scheme: dark; - --bg: #0b0b0a; - --panel: #171613; - --panel-soft: #201f1b; - --line: #312f28; - --text: #f4efe6; - --muted: #a9a197; - --subtle: #756f66; - --accent: #f0b84d; - --accent-strong: #ffcf73; - --green: #79a889; - --danger: #df6e62; - --shadow: 0 20px 70px rgba(0, 0, 0, 0.35); + --bg: #0b0e13; + --panel: #11151c; + --panel-soft: #181d26; + --panel-raised: #222934; + --line: #232934; + --line-strong: #2e3645; + --text: #f2ecdc; + --muted: #c7c0ae; + --subtle: #8e8676; + --faint: #5e5849; + --accent: #c2aa7a; + --accent-strong: #dcc79e; + --accent-deep: #8f7a50; + --accent-ink: #17120a; + --green: #4f8c5e; + --green-bg: #15241a; + --danger: #b5494b; + --danger-bg: #2a1517; + --warning: #c49545; + --focus-ring: rgba(194, 170, 122, 0.55); + --selection-bg: rgba(194, 170, 122, 0.25); + --font-display: "EB Garamond", "Source Serif Pro", Georgia, serif; + --font-sans: "IBM Plex Sans", "Helvetica Neue", system-ui, sans-serif; + --font-mono: "IBM Plex Mono", "SF Mono", Menlo, monospace; + --shadow: 0 1px 0 rgba(0, 0, 0, 0.4), 0 12px 32px rgba(0, 0, 0, 0.55); + --shadow-soft: 0 1px 0 rgba(0, 0, 0, 0.4), 0 4px 12px rgba(0, 0, 0, 0.45); + --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, 0.04); } * { @@ -22,10 +98,25 @@ body { margin: 0; min-height: 100vh; - background: var(--bg); + background: + radial-gradient(circle at 15% -10%, rgba(194, 170, 122, 0.09), transparent 34rem), + radial-gradient(circle at 88% 10%, rgba(31, 61, 92, 0.2), transparent 30rem), + linear-gradient(180deg, #0b0e13 0%, #080a0e 100%); color: var(--text); - font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + font-family: var(--font-sans); line-height: 1.5; + font-weight: 400; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; +} + +body.modal-open { + overflow: hidden; +} + +::selection { + background: var(--selection-bg); + color: var(--text); } a { @@ -33,6 +124,15 @@ a { text-decoration: none; } +a:focus-visible, +button:focus-visible, +input:focus-visible, +select:focus-visible, +textarea:focus-visible { + outline: 2px solid var(--focus-ring); + outline-offset: 3px; +} + img { display: block; max-width: 100%; @@ -61,8 +161,11 @@ textarea { } .brand { - font-family: 'Cormorant Garamond', Georgia, serif; - font-size: 1.8rem; + font-family: var(--font-display); + font-size: 2rem; + font-weight: 500; + font-style: italic; + letter-spacing: -0.02em; color: var(--accent); } @@ -84,23 +187,32 @@ textarea { color: var(--muted); } +.nav-actions a { + font-size: 0.84rem; + font-weight: 700; + letter-spacing: 0.04em; + text-transform: uppercase; +} + .nav-actions a.is-active { - color: var(--text); + color: var(--accent-strong); } .nav-actions a.button-link { - color: #0e0a04; + color: var(--accent-ink); } .button-link, button { border: 1px solid var(--accent); - border-radius: 6px; + border-radius: 4px; background: var(--accent); - color: #0e0a04; + color: var(--accent-ink); padding: 10px 14px; cursor: pointer; - font-weight: 800; + font-weight: 700; + box-shadow: var(--shadow-inset); + transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease; } .button-link:hover, @@ -124,8 +236,8 @@ button:hover { align-items: center; justify-content: center; border: 1px solid var(--line); - border-radius: 6px; - background: transparent; + border-radius: 4px; + background: rgba(24, 29, 38, 0.58); color: var(--muted); font-weight: 700; } @@ -177,24 +289,29 @@ button:hover { .eyebrow { margin: 0 0 8px; - color: var(--green); + color: var(--subtle); font-size: 0.78rem; - font-weight: 800; + font-weight: 700; + letter-spacing: 0.12em; text-transform: uppercase; } h1 { margin-bottom: 0; - font-family: 'Cormorant Garamond', Georgia, serif; + font-family: var(--font-display); font-size: clamp(2.2rem, 5vw, 4rem); - font-weight: 500; + font-weight: 400; line-height: 1.05; + letter-spacing: -0.02em; } h2 { margin-bottom: 4px; + color: var(--text); + font-family: var(--font-display); font-size: 1.1rem; + font-weight: 500; line-height: 1.2; } @@ -206,7 +323,7 @@ h2 { .inline-link { color: var(--text); text-decoration: underline; - text-decoration-color: rgba(240, 184, 77, 0.45); + text-decoration-color: rgba(194, 170, 122, 0.45); text-underline-offset: 0.14em; } @@ -217,23 +334,23 @@ h2 { .original-title { margin-bottom: 8px; color: var(--subtle); - font-family: Georgia, "Times New Roman", serif; + font-family: var(--font-display); font-style: italic; } .notice { margin-bottom: 20px; - border: 1px solid rgba(121, 168, 137, 0.4); - border-radius: 6px; - background: rgba(121, 168, 137, 0.1); - color: #d5f0dd; + border: 1px solid rgba(79, 140, 94, 0.42); + border-radius: 4px; + background: var(--green-bg); + color: #d7ecd9; padding: 12px 14px; } .notice.error { - border-color: rgba(223, 110, 98, 0.4); - background: rgba(223, 110, 98, 0.1); - color: #ffc7c0; + border-color: rgba(181, 73, 75, 0.44); + background: var(--danger-bg); + color: #f5c3bd; } .diary-feed { @@ -245,8 +362,9 @@ h2 { .month-label { margin: 24px 0 14px; color: var(--subtle); + font-family: var(--font-mono); font-size: 0.78rem; - font-weight: 700; + font-weight: 500; letter-spacing: 0.1em; text-transform: uppercase; } @@ -256,7 +374,7 @@ h2 { grid-template-columns: 92px minmax(0, 1fr); gap: 18px; border-bottom: 1px solid var(--line); - padding: 0 0 18px; + padding: 0 0 20px; } .poster-frame { @@ -265,12 +383,12 @@ h2 { aspect-ratio: 2 / 3; overflow: hidden; border: 1px solid var(--line); - border-radius: 6px; + border-radius: 4px; background: var(--panel); color: var(--accent); - font-family: Georgia, "Times New Roman", serif; + font-family: var(--font-display); font-size: 2rem; - box-shadow: var(--shadow); + box-shadow: var(--shadow-soft); } .poster-frame img { @@ -294,6 +412,7 @@ h2 { .rating { flex: 0 0 auto; color: var(--accent); + font-family: var(--font-mono); font-weight: 800; } @@ -354,6 +473,7 @@ h2 { flex-wrap: wrap; gap: 8px; color: var(--muted); + font-family: var(--font-mono); font-size: 0.92rem; } @@ -375,10 +495,68 @@ h2 { border-radius: 999px; background: var(--panel-soft); color: var(--muted); + font-family: var(--font-mono); padding: 4px 9px; font-size: 0.84rem; } +.ledger-strip { + display: flex; + flex-wrap: wrap; + gap: 0; + margin-top: 8px; + color: var(--muted); + font-family: var(--font-mono); + font-size: 0.92rem; + line-height: 1.65; +} + +.ledger-strip span:not(:last-child)::after { + content: " / "; + color: var(--faint); +} + +.fact-list { + display: grid; + gap: 8px; + margin-top: 10px; +} + +.fact-list-compact { + gap: 6px; +} + +.fact-row { + display: grid; + grid-template-columns: 56px minmax(0, 1fr); + gap: 10px; + align-items: start; +} + +.fact-label { + color: var(--faint); + font-family: var(--font-mono); + font-size: 0.72rem; + font-weight: 500; + letter-spacing: 0.12em; + text-transform: uppercase; + white-space: nowrap; +} + +.fact-value { + color: var(--muted); + font-size: 0.95rem; + line-height: 1.6; +} + +.film-card .fact-value { + font-family: var(--font-sans); +} + +.detail-panel .fact-value { + font-family: var(--font-sans); +} + .inline-actions { display: flex; flex-wrap: wrap; @@ -392,15 +570,16 @@ h2 { .notes-preview { margin: 14px 0 0; - color: #d0c7ba; + color: var(--muted); } .empty-state { margin: 34px 0 64px; border: 1px solid var(--line); - border-radius: 8px; - background: var(--panel); + border-radius: 6px; + background: linear-gradient(180deg, rgba(17, 21, 28, 0.96), rgba(24, 29, 38, 0.76)); padding: 30px; + box-shadow: var(--shadow-soft); } .empty-state p { @@ -417,9 +596,10 @@ h2 { .summary-card, .stats-panel { border: 1px solid var(--line); - border-radius: 8px; - background: var(--panel); + border-radius: 6px; + background: linear-gradient(180deg, rgba(17, 21, 28, 0.98), rgba(17, 21, 28, 0.82)); padding: 18px; + box-shadow: var(--shadow-inset); } .summary-card strong, @@ -427,15 +607,17 @@ h2 { display: block; margin-top: 6px; font-size: clamp(1.8rem, 4vw, 2.6rem); - font-family: 'Cormorant Garamond', Georgia, serif; - font-weight: 600; + font-family: var(--font-display); + font-weight: 500; color: var(--accent); } .summary-label { color: var(--muted); + font-family: var(--font-mono); font-size: 0.82rem; - font-weight: 700; + font-weight: 500; + letter-spacing: 0.1em; text-transform: uppercase; } @@ -460,9 +642,10 @@ h2 { display: grid; gap: 12px; border: 1px solid var(--line); - border-radius: 8px; + border-radius: 6px; background: var(--panel); padding: 16px; + box-shadow: var(--shadow-inset); } .detail-aside-meta strong { @@ -492,10 +675,11 @@ h2 { .detail-panel { border: 1px solid var(--line); - border-radius: 8px; - background: var(--panel); + border-radius: 6px; + background: linear-gradient(180deg, rgba(17, 21, 28, 0.96), rgba(17, 21, 28, 0.78)); padding: 16px; margin-bottom: 20px; + box-shadow: var(--shadow-inset); } .detail-panel .eyebrow { @@ -579,13 +763,14 @@ h2 { .detail-tagline { margin: 0 0 12px; color: var(--accent-strong); - font-family: Georgia, "Times New Roman", serif; + font-family: var(--font-display); + font-style: italic; font-size: 1.08rem; } .detail-overview { margin: 0; - color: #e3dacd; + color: var(--muted); } .detail-cast { @@ -600,9 +785,9 @@ h2 { .notes-body { margin-top: 28px; max-width: 68ch; - color: #e3dacd; + color: var(--muted); white-space: pre-wrap; - font-family: Georgia, "Times New Roman", serif; + font-family: var(--font-display); font-size: 1.14rem; } @@ -642,17 +827,20 @@ h2 { .tmdb-panel { margin-bottom: 24px; border: 1px solid var(--line); - border-radius: 8px; + border-radius: 6px; background: var(--panel); padding: 18px; + box-shadow: var(--shadow-inset); } label { display: block; margin-bottom: 8px; color: var(--muted); + font-family: var(--font-mono); font-size: 0.86rem; - font-weight: 700; + font-weight: 500; + letter-spacing: 0.04em; } input, @@ -660,11 +848,12 @@ select, textarea { width: 100%; border: 1px solid var(--line); - border-radius: 6px; - background: #11100e; + border-radius: 4px; + background: var(--panel); color: var(--text); padding: 11px 12px; outline: none; + box-shadow: var(--shadow-inset); } textarea { @@ -675,6 +864,7 @@ input:focus, select:focus, textarea:focus { border-color: var(--accent); + box-shadow: 0 0 0 3px var(--focus-ring); } .search-row input { @@ -699,7 +889,7 @@ textarea:focus { align-items: center; width: 100%; border-color: var(--line); - background: #11100e; + background: var(--panel); color: var(--text); padding: 8px; text-align: left; @@ -835,8 +1025,8 @@ textarea:focus { gap: 2px; min-width: 120px; border: 1px solid var(--line); - border-radius: 6px; - background: rgba(11, 11, 10, 0.96); + border-radius: 4px; + background: rgba(11, 14, 19, 0.96); color: var(--text); padding: 10px 12px; pointer-events: none; @@ -929,7 +1119,7 @@ textarea:focus { height: 100%; min-width: 8px; border-radius: inherit; - background: linear-gradient(90deg, rgba(240, 184, 77, 0.4), var(--accent)); + background: linear-gradient(90deg, rgba(194, 170, 122, 0.35), var(--accent)); } .stats-overview-row { @@ -985,9 +1175,10 @@ textarea:focus { .review-panel { border: 1px solid var(--line); - border-radius: 8px; - background: var(--panel); + border-radius: 6px; + background: linear-gradient(180deg, rgba(17, 21, 28, 0.96), rgba(17, 21, 28, 0.78)); padding: 18px; + box-shadow: var(--shadow-inset); } .review-panel-wide { @@ -1021,7 +1212,7 @@ textarea:focus { .year-bar-fill { height: 100%; border-radius: inherit; - background: linear-gradient(90deg, rgba(240, 184, 77, 0.35), var(--accent)); + background: linear-gradient(90deg, rgba(194, 170, 122, 0.35), var(--accent)); } .highlight-grid { @@ -1046,124 +1237,1049 @@ textarea:focus { color: var(--subtle); } -@media (max-width: 760px) { - .shell { - width: min(100% - 24px, 1120px); - } +.public-profile-page { + background: + radial-gradient(circle at 12% 0%, rgba(194, 170, 122, 0.08), transparent 28rem), + linear-gradient(180deg, #0b0e13 0%, #080a0e 100%); +} - .topbar { - align-items: center; - flex-direction: row; - } +.public-shell { + width: min(1240px, calc(100% - 40px)); + margin: 0 auto; + padding: 28px 0 48px; +} - .menu-toggle { - display: block !important; - width: 28px; - height: 22px; - margin-left: auto; - background: none; - border: none; - cursor: pointer; - position: relative; - padding: 0; - } +.public-topbar { + display: flex; + align-items: center; + justify-content: space-between; + gap: 20px; + padding-bottom: 22px; + border-bottom: 1px solid var(--line); +} - .menu-toggle::before, - .menu-toggle::after { - content: ""; - position: absolute; - width: 100%; - height: 2px; - background: var(--text); - left: 0; - } +.public-nav { + display: flex; + flex-wrap: wrap; + gap: 18px; +} - .menu-toggle::before { - top: 0; - box-shadow: 0 10px 0 var(--text); - } +.public-nav a { + color: var(--muted); + font-size: 0.84rem; + font-weight: 700; + letter-spacing: 0.04em; + text-transform: uppercase; +} - .menu-toggle::after { - bottom: 0; - } +.public-nav a.is-active, +.public-nav a:hover { + color: var(--accent-strong); +} - .nav-actions { - position: fixed; - top: 73px; - left: 0; - right: 0; - flex-direction: column; - gap: 0; - border-bottom: 1px solid var(--line); - background: var(--bg); - padding: 12px 0; - z-index: 100; - visibility: hidden; - opacity: 0; - transition: opacity 0.3s ease, visibility 0.3s ease; - } +.public-main { + padding-top: 28px; +} - .nav-actions.is-open { - visibility: visible; - opacity: 1; - } +.public-hero { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 24px; + align-items: end; + border: 1px solid var(--line); + border-radius: 10px; + background: + linear-gradient(180deg, rgba(17, 21, 28, 0.96), rgba(11, 14, 19, 0.84)), + radial-gradient(circle at top left, rgba(194, 170, 122, 0.08), transparent 20rem); + padding: 32px; + box-shadow: var(--shadow); +} - .nav-actions a, - .nav-actions button { - padding: 12px 16px; - text-align: left; - border: none; - border-radius: 0; - background: none; - color: var(--muted); - } +.public-hero-copy { + max-width: 50rem; +} - .nav-actions a.is-active, - .nav-actions a:hover, - .nav-actions button:hover { - background: var(--panel); - color: var(--text); - } +.public-hero-text { + margin: 14px 0 0; + color: var(--muted); + font-size: 1rem; + line-height: 1.7; +} - .nav-actions .button-link { - color: #0e0a04; - background: var(--accent); - margin: 8px 16px; - border: none; - } +.public-hero-metrics { + display: grid; + grid-template-columns: repeat(2, minmax(120px, 1fr)); + gap: 16px; +} - .page-heading, - .form-heading { - padding-top: 34px; - } +.public-metric-card { + display: grid; + gap: 6px; + padding: 14px 16px; + border: 1px solid var(--line); + border-radius: 8px; + background: rgba(24, 29, 38, 0.72); +} - .film-card, - .detail-layout, - .form-grid, - .director-summary, - .stats-layout { - grid-template-columns: 1fr; - } +.public-metric-card strong { + color: var(--accent); + font-family: var(--font-display); + font-size: 2rem; + font-weight: 500; +} - .film-card { - grid-template-columns: 72px minmax(0, 1fr); - } +.public-tabs { + display: flex; + gap: 22px; + margin: 24px 0 28px; + border-bottom: 1px solid var(--line); +} + +.public-tab { + border: 0; + border-bottom: 2px solid transparent; + border-radius: 0; + background: none; + box-shadow: none; + color: var(--subtle); + font-size: 0.9rem; + font-weight: 700; + letter-spacing: 0.04em; + padding: 0 0 14px; + text-transform: uppercase; +} + +.public-tab:hover, +.public-tab.is-active { + background: none; + border-bottom-color: var(--accent); + color: var(--text); +} + +.public-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 24px; +} + +.public-section { + display: grid; + gap: 18px; + border: 1px solid var(--line); + border-radius: 8px; + background: linear-gradient(180deg, rgba(17, 21, 28, 0.96), rgba(17, 21, 28, 0.82)); + padding: 24px; + box-shadow: var(--shadow-inset); +} + +.public-section-wide { + grid-column: 1 / -1; +} + +.public-section-head { + display: grid; + gap: 4px; +} + +.public-section-head h2 { + margin: 0; +} + +.public-list, +.public-bars { + display: grid; + gap: 12px; +} + +.public-list-row, +.public-bar-row { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 12px; + align-items: center; +} + +.public-list-row { + padding-bottom: 10px; + border-bottom: 1px solid var(--line); +} + +.public-list-row:last-child { + border-bottom: 0; + padding-bottom: 0; +} + +.public-list-row strong, +.public-bar-row strong, +.public-country-card strong { + color: var(--accent); + font-family: var(--font-display); + font-weight: 500; +} + +.public-bar-row { + grid-template-columns: 92px minmax(0, 1fr) auto; +} + +.public-bar-track { + height: 10px; + overflow: hidden; + border-radius: 999px; + background: var(--panel-soft); +} + +.public-bar-fill { + height: 100%; + min-width: 8px; + border-radius: inherit; + background: linear-gradient(90deg, rgba(194, 170, 122, 0.35), var(--accent)); +} + +.public-country-grid, +.public-poster-grid { + display: grid; + gap: 16px; +} + +.public-country-grid { + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); +} + +.public-country-card { + display: grid; + gap: 6px; + padding: 16px; + border: 1px solid var(--line); + border-radius: 6px; + background: rgba(17, 21, 28, 0.68); +} + +.public-country-card span, +.public-poster-card p, +.public-poster-meta { + color: var(--muted); +} + +.public-poster-grid { + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); +} + +.public-poster-card { + display: grid; + gap: 8px; +} + +.public-poster-frame { + box-shadow: none; +} + +.public-poster-card h3, +.public-film-head h2 { + margin: 0; +} + +.public-poster-card p, +.public-film-head p { + margin: 0; +} + +.public-poster-meta { + font-family: var(--font-mono); + font-size: 0.84rem; +} + +.public-feed { + display: grid; + gap: 0; +} + +.public-film-row { + display: grid; + grid-template-columns: 84px minmax(0, 1fr); + gap: 18px; + padding: 20px 0; + border-top: 1px solid var(--line); +} + +.public-film-row:first-child { + border-top: 0; +} + +.public-film-poster { + box-shadow: none; +} + +.public-film-body { + display: grid; + gap: 8px; +} + +.public-film-head { + display: flex; + align-items: start; + justify-content: space-between; + gap: 16px; +} + +.public-film-head p { + color: var(--muted); +} + +.public-feed-sentinel { + height: 1px; + margin: 20px 0; +} + +.public-footer { + margin-top: 48px; + padding-top: 20px; + border-top: 1px solid var(--line); + color: var(--muted); + font-size: 0.84rem; + text-align: center; +} + +.public-footer p { + margin: 0; +} + +.public-footer a { + color: var(--accent); + border-bottom: 0; +} + +.shell { + width: min(1400px, calc(100% - 40px)); + display: grid; + grid-template-columns: 280px minmax(0, 1fr); + gap: 32px; + padding: 24px 0 40px; +} + +.app-sidebar { + display: block; +} + +.app-sidebar-inner { + position: sticky; + top: 24px; + display: grid; + gap: 24px; + min-height: calc(100vh - 48px); + border-right: 1px solid var(--line); + background: transparent; + padding: 28px 24px; +} + +.sidebar-intro { + margin: -8px 0 0; + max-width: 20ch; + color: var(--subtle); + font-family: var(--font-display); + font-size: 1.15rem; + font-style: italic; + line-height: 1.35; +} + +.sidebar-cta { + display: inline-flex; + align-items: center; + justify-content: center; + width: 100%; + align-self: start; + padding: 12px 14px; +} + +.sidebar-nav { + display: grid; + gap: 24px; +} + +.sidebar-group { + display: grid; + gap: 6px; +} + +.sidebar-label { + margin: 0 0 8px; + color: var(--faint); + font-family: var(--font-mono); + font-size: 0.72rem; + letter-spacing: 0.14em; + text-transform: uppercase; +} + +.sidebar-nav a { + border-left: 1px solid transparent; + color: var(--muted); + font-size: 0.9rem; + font-weight: 600; + letter-spacing: 0.02em; + padding: 11px 0 11px 12px; + transition: border-color 0.15s ease, color 0.15s ease; +} + +.sidebar-nav a:hover, +.sidebar-nav a.is-active { + border-left-color: var(--accent); + color: var(--text); +} + +.sidebar-logout { + margin-top: auto; +} + +.sidebar-logout-button, +.nav-logout-button { + border: 0; + background: none; + box-shadow: none; + color: var(--subtle); + padding: 0; +} + +.sidebar-logout-button:hover, +.nav-logout-button:hover { + background: none; + color: var(--text); +} + +.app-main { + min-width: 0; +} + +.app-content { + min-width: 0; +} + +.topbar { + display: none; +} + +.nav-logout { + display: contents; +} + +.shelf-hero, +.form-hero { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 24px; + align-items: end; + margin-bottom: 20px; + border: 1px solid var(--line); + border-radius: 10px; + background: + linear-gradient(180deg, rgba(17, 21, 28, 0.96), rgba(11, 14, 19, 0.84)), + radial-gradient(circle at top left, rgba(194, 170, 122, 0.08), transparent 22rem); + padding: 32px; + box-shadow: var(--shadow); +} + +.shelf-hero-copy, +.form-heading { + max-width: 46rem; +} + +.form-hero .form-heading, +.shelf-hero-copy { + padding: 0; +} + +.form-hero .form-heading-row { + align-items: flex-start; +} + +.shelf-hero-text, +.form-intro { + margin: 14px 0 0; + color: var(--muted); + font-size: 1rem; + line-height: 1.7; +} + +.shelf-hero-meta { + display: grid; + gap: 16px; + justify-items: end; +} + +.shelf-stat { + display: grid; + gap: 6px; + min-width: 140px; + padding: 14px 16px; + border: 1px solid var(--line); + border-radius: 8px; + background: rgba(24, 29, 38, 0.72); +} + +.shelf-stat strong { + color: var(--accent); + font-family: var(--font-display); + font-size: 2rem; + font-weight: 500; +} + +.feed-toolbar { + position: sticky; + top: 18px; + z-index: 20; + margin-bottom: 28px; + border: 1px solid var(--line); + border-radius: 8px; + background: rgba(11, 14, 19, 0.88); + backdrop-filter: blur(16px); + padding: 14px; +} + +.search-row { + gap: 10px; +} + +.search-row input { + flex: 1 1 360px; +} + +.search-row select { + flex: 0 0 260px; +} + +.diary-feed { + gap: 24px; +} + +.month-group { + display: grid; + grid-template-columns: 132px minmax(0, 1fr); + gap: 18px; + align-items: start; +} + +.month-rail { + position: sticky; + top: 106px; +} + +.month-label { + margin: 0; + padding-top: 10px; +} + +.month-stack { + display: grid; + gap: 0; +} + +.film-card { + grid-template-columns: 72px minmax(0, 1fr); + gap: 16px; + border: 0; + border-top: 1px solid var(--line); + border-radius: 0; + background: transparent; + padding: 18px 0 20px; + box-shadow: none; +} + +.film-card-body { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 18px; + align-items: start; + padding-top: 0; +} + +.film-card-main { + min-width: 0; +} + +.film-card-header { + display: grid; + gap: 4px; +} + +.film-card-header h2 { + margin: 0; + font-size: 1.45rem; +} + +.film-card-header .muted { + margin: 0; +} + +.film-card-side { + display: grid; + justify-items: end; + align-content: start; + gap: 16px; + min-width: 150px; +} + +.star-control { + margin-left: 0; +} + +.inline-actions { + justify-content: end; + margin-top: 0; + opacity: 0; + visibility: hidden; + pointer-events: none; + transition: opacity 0.15s ease; +} + +.film-card:hover .inline-actions, +.film-card:focus-within .inline-actions { + opacity: 1; + visibility: visible; + pointer-events: auto; +} + +.notes-preview { + max-width: 62ch; + line-height: 1.65; +} + +.detail-layout { + grid-template-columns: 280px minmax(0, 1fr); + gap: 32px; +} + +.detail-poster { + position: sticky; + top: 24px; +} + +.detail-poster-button { + width: 100%; +} + +.poster-picker-modal { + position: fixed; + inset: 0; + z-index: 120; + display: grid; + place-items: center; + padding: 32px; +} + +.poster-picker-modal[hidden] { + display: none; +} + +.poster-picker-backdrop { + position: absolute; + inset: 0; + background: rgba(8, 10, 14, 0.82); + backdrop-filter: blur(10px); +} + +.poster-picker-dialog { + position: relative; + z-index: 1; + display: grid; + gap: 18px; + width: min(980px, 100%); + max-height: min(88vh, 900px); + overflow: auto; + border: 1px solid var(--line); + border-radius: 8px; + background: linear-gradient(180deg, rgba(17, 21, 28, 0.98), rgba(11, 14, 19, 0.96)); + padding: 24px; + box-shadow: var(--shadow); +} + +.poster-picker-head { + display: flex; + align-items: start; + justify-content: space-between; + gap: 16px; +} + +.poster-picker-head h2 { + margin: 4px 0 0; +} + +.poster-picker-close { + flex: 0 0 auto; +} + +.poster-picker-status { + margin: 0; + color: var(--muted); + font-size: 0.86rem; +} + +.poster-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); + gap: 12px; +} + +.poster-option { + position: relative; + padding: 0; + border: 2px solid transparent; + border-radius: 4px; + overflow: hidden; + cursor: pointer; + background: none; + box-shadow: none; +} + +.poster-option.is-current, +.poster-option:hover, +.poster-option:focus-visible { + border-color: var(--accent); + background: none; +} + +.poster-option-badge { + position: absolute; + top: 8px; + right: 8px; + padding: 4px 7px; + border: 1px solid rgba(194, 170, 122, 0.5); + border-radius: 999px; + background: rgba(11, 14, 19, 0.86); + color: var(--accent-strong); + font-family: var(--font-mono); + font-size: 0.68rem; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.poster-option img { + width: 100%; + display: block; + aspect-ratio: 2 / 3; + object-fit: cover; +} + +.detail-body { + display: grid; + gap: 24px; +} + +.detail-hero { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 28px; + align-items: start; + border: 1px solid var(--line); + border-radius: 10px; + background: + linear-gradient(180deg, rgba(17, 21, 28, 0.96), rgba(11, 14, 19, 0.84)), + radial-gradient(circle at top left, rgba(194, 170, 122, 0.08), transparent 20rem); + padding: 28px 30px; + box-shadow: var(--shadow); +} + +.detail-hero-copy h1 { + margin-bottom: 8px; +} + +.detail-subtitle { + margin-bottom: 0; +} + +.detail-columns { + display: grid; + grid-template-columns: 280px minmax(0, 1fr); + gap: 24px; + align-items: start; +} + +.detail-sidebar, +.detail-main { + display: grid; + gap: 18px; +} + +.detail-panel { + margin-bottom: 0; +} + +.detail-panel-feature { + padding: 22px; +} + +.detail-actions { + display: flex; + flex-wrap: wrap; + justify-content: end; + align-items: center; + gap: 10px; + margin-top: 0; +} + +.form-shell { + width: min(1080px, 100%); +} + +.form-panel { + display: grid; + gap: 18px; + border: 1px solid var(--line); + border-radius: 8px; + background: linear-gradient(180deg, rgba(17, 21, 28, 0.96), rgba(17, 21, 28, 0.82)); + padding: 24px; + box-shadow: var(--shadow-inset); +} + +.form-panel-head { + display: grid; + gap: 4px; +} + +.form-panel-head h2 { + margin: 0; +} + +.form-grid { + gap: 20px; +} + +.form-grid-archive { + align-items: start; +} + +.poster-preview-field { + grid-column: 1; +} + +.poster-preview { + width: min(220px, 100%); +} + +.notes-field { + grid-column: 2; +} + +@media (max-width: 760px) { + .public-shell { + width: min(100% - 24px, 1240px); + padding-top: 20px; + } + + .public-topbar, + .public-hero, + .public-grid, + .public-hero-metrics, + .public-film-row { + grid-template-columns: 1fr; + } + + .public-topbar { + align-items: flex-start; + flex-direction: column; + } + + .public-nav { + gap: 12px; + } + + .public-hero { + padding: 24px 20px; + } + + .public-tabs { + gap: 16px; + overflow-x: auto; + } + + .public-bar-row { + grid-template-columns: 74px minmax(0, 1fr) auto; + } + + .public-section { + padding: 20px; + } + + .public-film-row { + gap: 14px; + } + + .public-film-poster { + width: min(96px, 100%); + } + + .shell { + width: min(100% - 24px, 1120px); + grid-template-columns: 1fr; + gap: 0; + padding-top: 0; + } + + .app-sidebar { + display: none; + } + + .app-main { + min-width: 0; + } + + .topbar { + display: flex; + align-items: center; + flex-direction: row; + padding: 20px 0; + } + + .menu-toggle { + display: block !important; + width: 28px; + height: 22px; + margin-left: auto; + background: none; + border: none; + cursor: pointer; + position: relative; + padding: 0; + } + + .menu-toggle::before, + .menu-toggle::after { + content: ""; + position: absolute; + width: 100%; + height: 2px; + background: var(--text); + left: 0; + } + + .menu-toggle::before { + top: 0; + box-shadow: 0 10px 0 var(--text); + } + + .menu-toggle::after { + bottom: 0; + } + + .nav-actions { + position: fixed; + top: 73px; + left: 0; + right: 0; + flex-direction: column; + gap: 0; + border-bottom: 1px solid var(--line); + background: rgba(11, 14, 19, 0.98); + padding: 12px 0; + z-index: 100; + visibility: hidden; + opacity: 0; + transition: opacity 0.3s ease, visibility 0.3s ease; + } + + .nav-actions.is-open { + visibility: visible; + opacity: 1; + } + + .nav-actions a, + .nav-actions button { + padding: 12px 16px; + text-align: left; + border: none; + border-radius: 0; + background: none; + color: var(--muted); + } + + .nav-actions a.is-active, + .nav-actions a:hover, + .nav-actions button:hover { + background: var(--panel); + color: var(--text); + } + + .nav-actions .button-link { + color: var(--accent-ink); + background: var(--accent); + margin: 8px 16px; + border: none; + } + + .page-heading, + .form-heading { + padding-top: 34px; + } + + .shelf-hero, + .form-hero, + .detail-hero, + .detail-columns, + .film-card-body, + .month-group { + grid-template-columns: 1fr; + } + + .shelf-hero, + .form-hero, + .detail-hero { + padding: 22px 20px; + } + + .shelf-hero-meta, + .detail-actions, + .film-card-side { + justify-items: start; + justify-content: start; + } + + .feed-toolbar { + top: 10px; + margin-bottom: 20px; + padding: 12px; + } + + .month-rail { + position: static; + } + + .film-card, + .detail-layout, + .form-grid, + .director-summary, + .stats-layout { + grid-template-columns: 1fr; + } + + .film-card { + grid-template-columns: 72px minmax(0, 1fr); + padding: 16px 0 18px; + } .detail-layout { gap: 28px; } + .detail-poster { + position: static; + } + .detail-poster { width: min(220px, 70%); } + .film-card-side, + .inline-actions { + opacity: 1; + visibility: visible; + pointer-events: auto; + } + .poster-preview-field, .notes-field { grid-column: 1; } .search-row, - .form-actions { + .form-actions, + .detail-actions { align-items: stretch; flex-direction: column; } diff --git a/templates/_feed_partial.html b/templates/_feed_partial.html index e22cdde..47800be 100644 --- a/templates/_feed_partial.html +++ b/templates/_feed_partial.html @@ -1,10 +1,14 @@ {% if active_shelf == 'diary' and grouped_films %} {% for group in grouped_films %}
-

{{ group.month }}

- {% for film in group.films %} - {% include "_film_card.html" %} - {% endfor %} +
+

{{ group.month }}

+
+
+ {% for film in group.films %} + {% include "_film_card.html" %} + {% endfor %} +
{% endfor %} {% else %} diff --git a/templates/_film_card.html b/templates/_film_card.html index a4e206f..6723821 100644 --- a/templates/_film_card.html +++ b/templates/_film_card.html @@ -7,8 +7,8 @@ {% endif %}
-
-
+
+

{{ film.title }}

{% if film.year %}{{ film.year }}{% endif %} @@ -21,6 +21,55 @@ {% endif %}

+ +
+ {{ film.shelf|title }} + {% if film.date_watched %}{{ film.date_watched }}{% endif %} + {% if film.runtime %}{{ film.runtime }} min{% endif %} + {% if film.rewatch %}Rewatch{% if film.rewatch_count %} #{{ film.rewatch_count }}{% endif %}{% endif %} +
+ + {% if film.language or film.genre or film.context or film.how_found or film.watched_with %} +
+ {% if film.language %} +
+ Lang + {{ film.language }} +
+ {% endif %} + {% if film.genre %} +
+ Genre + {{ film.genre }} +
+ {% endif %} + {% if film.context %} +
+ Context + {{ film.context }} +
+ {% endif %} + {% if film.how_found %} +
+ Found + {{ film.how_found }} +
+ {% endif %} + {% if film.watched_with %} +
+ With + {{ film.watched_with }} +
+ {% endif %} +
+ {% endif %} + + {% if film.notes %} +

{{ film.notes[:220] }}{% if film.notes|length > 220 %}...{% endif %}

+ {% endif %} +
+ +
{% if film.shelf == 'diary' %}
{% for value in range(1, 4) %} @@ -36,48 +85,27 @@ {% elif film.stars %} {% for _ in range(film.stars) %}✦{% endfor %} {% endif %} -
- -
- {{ film.shelf|title }} - {% if film.date_watched %}{{ film.date_watched }}{% endif %} - {% if film.runtime %}{{ film.runtime }} min{% endif %} - {% if film.language %}{{ film.language }}{% endif %} - {% if film.rewatch %}Rewatch{% if film.rewatch_count %} #{{ film.rewatch_count }}{% endif %}{% endif %} -
- {% if film.genre or film.context or film.how_found or film.watched_with %} -
- {% if film.genre %}{{ film.genre }}{% endif %} - {% if film.context %}{{ film.context }}{% endif %} - {% if film.how_found %}{{ film.how_found }}{% endif %} - {% if film.watched_with %}With {{ film.watched_with }}{% endif %} +
+ {% if film.shelf == 'queue' %} + Mark watched +
+ +
+ {% elif film.shelf == 'diary' %} +
+ +
+
+ +
+ {% else %} + Mark watched +
+ +
+ {% endif %}
- {% endif %} - - {% if film.notes %} -

{{ film.notes[:220] }}{% if film.notes|length > 220 %}...{% endif %}

- {% endif %} - -
- {% if film.shelf == 'queue' %} - Mark watched -
- -
- {% elif film.shelf == 'diary' %} -
- -
-
- -
- {% else %} - Mark watched -
- -
- {% endif %}
diff --git a/templates/_public_feed_partial.html b/templates/_public_feed_partial.html new file mode 100644 index 0000000..ba84c61 --- /dev/null +++ b/templates/_public_feed_partial.html @@ -0,0 +1,71 @@ +{% for film in films %} +
+
+ {% if film.poster_url %} + {{ film.title }} poster + {% else %} + {{ film.title[:1] }} + {% endif %} +
+
+
+
+

{{ film.title }}

+

+ {% if film.year %}{{ film.year }}{% endif %} + {% set directors = split_credit_names(film.director) %} + {% if directors %} + {% if film.year %} · {% endif %} + {{ directors|join(", ") }} + {% endif %} +

+
+ {% if film.stars %} + {% for _ in range(film.stars) %}✦{% endfor %} + {% endif %} +
+ +
+ Diary + {% if film.date_watched %}{{ film.date_watched }}{% endif %} + {% if film.runtime %}{{ film.runtime }} min{% endif %} + {% if film.rewatch %}Rewatch{% if film.rewatch_count %} #{{ film.rewatch_count }}{% endif %}{% endif %} +
+ + {% if film.language or film.genre or film.context or film.how_found or film.watched_with %} +
+ {% if film.language %} +
+ Lang + {{ film.language }} +
+ {% endif %} + {% if film.genre %} +
+ Genre + {{ film.genre }} +
+ {% endif %} + {% if film.context %} +
+ Context + {{ film.context }} +
+ {% endif %} + {% if film.how_found %} +
+ Found + {{ film.how_found }} +
+ {% endif %} + {% if film.watched_with %} +
+ With + {{ film.watched_with }} +
+ {% endif %} +
+ {% endif %} +
+
+{% endfor %} diff --git a/templates/base.html b/templates/base.html index 4e814ad..1b48f06 100644 --- a/templates/base.html +++ b/templates/base.html @@ -10,26 +10,56 @@
-
- Lumière - - -
+
+ + +
+
+ Lumière + + +
-
- {% block content %}{% endblock %} -
+
+ {% block content %}{% endblock %} +
+
{% block scripts %}{% endblock %} diff --git a/templates/detail.html b/templates/detail.html index 9c558f7..f51372d 100644 --- a/templates/detail.html +++ b/templates/detail.html @@ -17,236 +17,335 @@ - - {% endif %} - -
-
- Shelf - {{ film.shelf|title }} -
-
- Watched - {% if film.date_watched %}{{ film.date_watched }}{% else %}Not set{% endif %} -
-
- Stars - {% if film.stars %}{% for _ in range(film.stars) %}✦{% endfor %}{% else %}Unstarred{% endif %} -
-
-

{{ film.shelf|title }} Entry

-

{{ film.title }}

- {% if film.original_title %} -

{{ film.original_title }}

- {% endif %} -
-

- {% if film.year %}{{ film.year }}{% endif %} - {% set directors = split_credit_names(film.director) %} - {% if directors %} - {% if film.year %} · {% endif %} - {% for director in directors %} - {{ director }}{% if not loop.last %}, {% endif %} - {% endfor %} +

+
+

{{ film.shelf|title }} Entry

+

{{ film.title }}

+ {% if film.original_title %} +

{{ film.original_title }}

{% endif %} -

- {% if ratings %} -
- {% if ratings.imdb %} - - IMDb - {{ ratings.imdb }} - - {% endif %} - {% if ratings.rt %} - - Rotten Tomatoes - {{ ratings.rt }} - - {% endif %} - {% if ratings.metacritic %} - - Metacritic - {{ ratings.metacritic }} - +
+

+ {% if film.year %}{{ film.year }}{% endif %} + {% set directors = split_credit_names(film.director) %} + {% if directors %} + {% if film.year %} · {% endif %} + {% for director in directors %} + {{ director }}{% if not loop.last %}, {% endif %} + {% endfor %} + {% endif %} +

+ {% if ratings %} +
+ {% if ratings.imdb %} + + IMDb + {{ ratings.imdb }} + + {% endif %} + {% if ratings.rt %} + + Rotten Tomatoes + {{ ratings.rt }} + + {% endif %} + {% if ratings.metacritic %} + + Metacritic + {{ ratings.metacritic }} + + {% endif %} +
+ {% endif %} +
+
+ +
+ Edit + {% if film.shelf == 'queue' %} + Mark watched +
+ +
+ {% elif film.shelf == 'diary' %} +
+ +
+
+ +
+ {% else %} + Mark watched +
+ +
{% endif %} +
+ +
- {% endif %} -
+
-
-
-

Watch log

-
- {% if film.date_watched %}{{ film.date_watched }}{% endif %} - {% if film.runtime %}{{ film.runtime }} min{% endif %} - {% if film.rewatch %}Rewatch{% if film.rewatch_count %} #{{ film.rewatch_count }}{% endif %}{% endif %} - {% if film.watched_with %}With {{ film.watched_with }}{% endif %} - {% if film.context %}{{ film.context }}{% endif %} - {% if film.how_found %}{{ film.how_found }}{% endif %} +
+
-
-

Production

-
- {% if film.genre %}{{ film.genre }}{% endif %} - {% if film.country %}{{ film.country }}{% endif %} - {% if film.language %}{{ film.language }}{% endif %} - {% if film.year %}{{ film.year }}{% endif %} - {% if film.tmdb_id %}TMDB {{ film.tmdb_id }}{% endif %} -
-
-
+
+

Watch log

+
+ {% if film.date_watched %} +
+ Watched + {{ film.date_watched }} +
+ {% endif %} + {% if film.runtime %} +
+ Runtime + {{ film.runtime }} min +
+ {% endif %} + {% if film.rewatch %} +
+ Rewatch + Yes{% if film.rewatch_count %} · #{{ film.rewatch_count }}{% endif %} +
+ {% endif %} + {% if film.watched_with %} +
+ With + {{ film.watched_with }} +
+ {% endif %} + {% if film.context %} +
+ Context + {{ film.context }} +
+ {% endif %} + {% if film.how_found %} +
+ Found + {{ film.how_found }} +
+ {% endif %} +
+
- {% if rewatch_history|length > 1 %} -
-

Rewatches

-
- {% for entry in rewatch_history %} -
-
-

{{ entry.date_watched }}

-

- {% for _ in range(entry.stars) %}✦{% endfor %} - {% if entry.watched_with %}with {{ entry.watched_with }}{% endif %} -

+
+

Production

+
+ {% if film.genre %} +
+ Genre + {{ film.genre }} +
+ {% endif %} + {% if film.country %} +
+ Country + {{ film.country }} +
+ {% endif %} + {% if film.language %} +
+ Lang + {{ film.language }} +
+ {% endif %} + {% if film.year %} +
+ Year + {{ film.year }} +
+ {% endif %} + {% if film.tmdb_id %} +
+ TMDB + {{ film.tmdb_id }} +
+ {% endif %}
- {% if not loop.first %} - - {% set prev_entry = rewatch_history[loop.index - 2] %} - {% if prev_entry.date_watched %} - {% set days = (entry.date_watched - prev_entry.date_watched).days %} - {{ days }}d - {% if entry.stars != prev_entry.stars %} - ({{ prev_entry.stars }}→{{ entry.stars }}) +
+ + +
+ {% if tmdb_context %} +
+

Summary

+ {% if tmdb_context.tagline %} +

{{ tmdb_context.tagline }}

+ {% endif %} + {% if tmdb_context.overview %} +

{{ tmdb_context.overview }}

{% endif %} + {% if tmdb_context.cast %} +
+ Cast +

{{ tmdb_context.cast|join(", ") }}

+
{% endif %} - +
+ {% endif %} + +
+

Notes

+ {% if film.notes %} +
{{ film.notes }}
+ {% else %} +

No notes saved.

{% endif %} -
- {% endfor %} -
-
- {% endif %} +
- {% if tmdb_context %} -
-

Summary

- {% if tmdb_context.tagline %} -

{{ tmdb_context.tagline }}

- {% endif %} - {% if tmdb_context.overview %} -

{{ tmdb_context.overview }}

- {% endif %} - {% if tmdb_context.cast %} -
- Cast -

{{ tmdb_context.cast|join(", ") }}

+ {% if rewatch_history|length > 1 %} +
+

Rewatches

+
+ {% for entry in rewatch_history %} +
+
+

{{ entry.date_watched }}

+

+ {% for _ in range(entry.stars) %}✦{% endfor %} + {% if entry.watched_with %}with {{ entry.watched_with }}{% endif %} +

+
+ {% if not loop.first %} + + {% set prev_entry = rewatch_history[loop.index - 2] %} + {% if prev_entry.date_watched %} + {% set days = (entry.date_watched - prev_entry.date_watched).days %} + {{ days }}d + {% if entry.stars != prev_entry.stars %} + ({{ prev_entry.stars }}→{{ entry.stars }}) + {% endif %} + {% endif %} + + {% endif %} +
+ {% endfor %}
+
{% endif %} -
- {% endif %} - -
-

Notes

- {% if film.notes %} -
{{ film.notes }}
- {% else %} -

No notes saved.

- {% endif %} +
- -
- Edit - {% if film.shelf == 'queue' %} - Mark watched -
- -
- {% elif film.shelf == 'diary' %} -
- -
-
- -
- {% else %} - Mark watched -
- -
- {% endif %} -
- -
-
+ {% if film.tmdb_id %} + + {% endif %} + {% if film.tmdb_id %} {% endif %} diff --git a/templates/form.html b/templates/form.html index cd29e67..f7bbbf1 100644 --- a/templates/form.html +++ b/templates/form.html @@ -13,138 +13,168 @@ {% set current_stars = film.stars if film and film.stars else 0 %} -
-

Diary Entry

-
-

{{ page_title }}

-
- {% for value in range(1, 4) %} - - {% endfor %} +
+
+

Diary Entry

+
+
+

{{ page_title }}

+

Search TMDB first, then tune the entry like a ledger instead of filling a blank spreadsheet.

+
+
+ {% for value in range(1, 4) %} + + {% endfor %} +
-
+ -
- +
+
+

Lookup

+

TMDB title search

+
-
+ -
-
- - +
+
+

Identity

+

Core film record

+
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - +
+ + +
+
-
- - +
+
+

Log

+

Watch context

+
+
+ + +
-
- - {% set current_shelf = shelf_override if shelf_override else (film.shelf if film and film.shelf else 'diary') %} - -
+
+ + {% set current_shelf = shelf_override if shelf_override else (film.shelf if film and film.shelf else 'diary') %} + +
-
- -
+
+ +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - -
+
+ + +
-
- - +
+ + +
+
-
- - +
+
+

Archive

+

Poster and notes

+
+
+ + +
-
-
- {% if film and film.poster_url %} - Poster preview - {% else %} - Poster preview - {% endif %} +
+
+ {% if film and film.poster_url %} + Poster preview + {% else %} + Poster preview + {% endif %} +
-
-
- - +
+ + +
-
+
Cancel diff --git a/templates/index.html b/templates/index.html index dc76e5d..7e74c07 100644 --- a/templates/index.html +++ b/templates/index.html @@ -3,35 +3,44 @@ {% block title %}{{ shelf_meta.title }} · Lumière{% endblock %} {% block content %} -
-

{{ shelf_meta.eyebrow }}

-
+
+
+

{{ shelf_meta.eyebrow }}

{{ shelf_meta.title }}

+

{{ shelf_meta.empty_text }}

+
+
+
+ Entries + {{ total_films or 0 }} +
{% if active_shelf == 'queue' %} Surprise me {% endif %}
-
- - -
+
+
+ + +
+
{% if imported is not none %}
{{ imported }} entries imported.
@@ -62,10 +71,14 @@ {% if active_shelf == 'diary' and grouped_films %} {% for group in grouped_films %}
-

{{ group.month }}

- {% for film in group.films %} - {% include "_film_card.html" %} - {% endfor %} +
+

{{ group.month }}

+
+
+ {% for film in group.films %} + {% include "_film_card.html" %} + {% endfor %} +
{% endfor %} {% else %} 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 @@ - Tyler's Film Diary - Lumière + Tyler's Film Diary · Lumière - -
-
- Lumière -
- - {% if films_per_country %} -
-

Top Countries

-
- {% for item in films_per_country %} -
-
{{ item.count }}
-
{{ item.country }}
+ {% if films_per_country %} +
+
+

Geography

+

Most watched countries

- {% endfor %} -
-
- {% endif %} - - - {% if recent_films %} -
-

Recently Watched

-
- {% for film in recent_films %} -
- {% if film.poster_url %} - {{ film.title }} - {% else %} -
No poster
- {% endif %} -

{{ film.title }}

- {% if film.stars %} -
- {% for i in range(film.stars) %}✦{% endfor %} +
+ {% for item in films_per_country %} +
+ {{ item.count }} + {{ item.country }}
- {% endif %} - {% if film.date_watched %} -
{{ film.date_watched[:10] }}
- {% endif %} + {% endfor %}
- {% endfor %} -
-
- {% endif %} + + {% endif %} + + {% if recent_films %} +
+
+

Recent

+

Recently watched

+
+
+ {% for film in recent_films %} +
+
+ {% if film.poster_url %} + {{ film.title }} poster + {% else %} + {{ film.title[:1] }} + {% endif %} +
+

{{ film.title }}

+

{{ film.year }}{% if film.director %} · {{ film.director }}{% endif %}

+ {% if film.date_watched %} + {{ film.date_watched[:10] }} + {% endif %} +
+ {% endfor %} +
+
+ {% endif %}
- + - - - -
+ -
-- cgit v1.3-2-g0d8e