From c16fdde19a5fc3b76f7b6903a95aae922f9a3ba3 Mon Sep 17 00:00:00 2001 From: John Doty Date: Sat, 23 Nov 2024 16:55:16 -0800 Subject: [PATCH] Two very bad columns --- cry/static/style.css | 62 ++++++++++++++++++++++++++++++++ cry/views.py | 86 ++++++++++++++++++++++++++++++++------------ cry/web.py | 4 +-- 3 files changed, 127 insertions(+), 25 deletions(-) diff --git a/cry/static/style.css b/cry/static/style.css index a6d1d8c..3c4a809 100644 --- a/cry/static/style.css +++ b/cry/static/style.css @@ -41,3 +41,65 @@ li.entry:before { content: '\2022'; padding-right: 0.5rem; } + +/* Feed summaries */ +ul.feed-summary-list { + list-style-type: none; + margin: 0; + padding: 0 1rem 0 0; + + flex-basis: 10%; + flex: 1; + width: 100%; + + height: auto; + overflow-y: auto; +} + +li.feed-summary { + margin-bottom: 0.5rem; + flex: 1; + + overflow: hidden; +} +li.feed-summary h2 { + margin: 0; + font-size: 100%; + flex: 1; +} +li.feed-summary p { + margin: 0; +} +p.feed-title-summary { + height: 1.5rem; + + overflow: hidden; + text-overflow: ellipsis; +} + +/* The feed container */ +div.feed-container { + flex: 1; + flex-basis: 40%; + + height: 100%; + overflow-y: auto; +} + +/* Group it all */ +div.main-container { + margin-top: 1rem; + flex: 1; + + display: flex; + flex-direction: row; + margin-left: auto; + margin-right: auto; + overflow-y: scroll; /*...but we don't scroll because our columns do first!*/ +} + +/* Uh */ +body.feed-view { + display: flex; + flex-direction: column; +} diff --git a/cry/views.py b/cry/views.py index c53833d..c0ac176 100644 --- a/cry/views.py +++ b/cry/views.py @@ -1,9 +1,11 @@ import typing +import dominate import dominate.tags as tags from . import feed + def _standard_header(title: str) -> tags.head: head = tags.head( tags.meta(charset="utf8"), @@ -13,11 +15,33 @@ def _standard_header(title: str) -> tags.head: assert isinstance(head, tags.head) return head + +def _feed_summary(f: feed.Feed) -> tags.li: + if len(f.entries) == 0: + last_entry = tags.p(tags.i("Never posted")) + else: + entry = f.entries[0] + last_entry = [ + tags.p(tags.i(f"Posted {entry.time_ago()} ago")), + tags.p({"class": "feed-title-summary"}, entry.title), + ] + + result = tags.li( + {"class": "feed-summary"}, + # TODO: Image! + tags.h2(f.title), + last_entry, + ) + assert isinstance(result, tags.li) + return result + + def feed_view(feeds: list[feed.Feed]) -> tags.html: document = tags.html( _standard_header("Subscribed Feeds"), - tags.h1("Feeds"), - tags.div( + tags.body( + {"class": "feed-view"}, + tags.h1("Feeds"), tags.form( {"method": "post", "action": "/refresh"}, tags.input_(type="submit", value="Refresh"), @@ -28,33 +52,45 @@ def feed_view(feeds: list[feed.Feed]) -> tags.html: tags.input_(type="url", name="url"), tags.input_(type="submit", value="Subscribe"), ), - ( + tags.div( + {"class": "main-container"}, + tags.ul( + {"class": "feed-summary-list"}, (_feed_summary(f) for f in feeds) + ), tags.div( - {"class": "feed"}, - tags.h2(tags.a(f.title, href=f.link, target="_blank")), + {"class": "feed-container"}, ( - tags.ul( - tags.li( - {"class": "entry"}, - tags.a( - entry.title, href=entry.link, target="_blank" - ), - f" ({entry.time_ago()})", - ) - for entry in f.entries + tags.div( + {"class": "feed"}, + tags.h2(tags.a(f.title, href=f.link, target="_blank")), + ( + tags.ul( + tags.li( + {"class": "entry"}, + tags.a( + entry.title, + href=entry.link, + target="_blank", + ), + f" ({entry.time_ago()})", + ) + for entry in f.entries + ) + if len(f.entries) > 0 + else tags.i("No entries...") + ), ) - if len(f.entries) > 0 - else tags.i("No entries...") + for f in feeds ), - ) - for f in feeds + ), ), ), ) assert isinstance(document, tags.html) return document -def subscribe_choose_view(candidates: typing.Iterable[tuple[str,str]]) -> tags.html: + +def subscribe_choose_view(candidates: typing.Iterable[tuple[str, str]]) -> tags.html: document = tags.html( _standard_header("Choose Feed"), tags.h1("Choose Feed"), @@ -64,11 +100,15 @@ def subscribe_choose_view(candidates: typing.Iterable[tuple[str,str]]) -> tags.h tags.thead(tags.tr(tags.th("Title"), tags.th("URL"), tags.th())), tags.tbody( tags.form( - {"action": "/subscribe", "method":"post"}, + {"action": "/subscribe", "method": "post"}, tags.tr( - tags.td(title), tags.td(url), tags.td( - tags.input_({"type":"hidden", "name":"url", "value":url}), - tags.input_({"type":"submit", "value":"Subscribe"}), + tags.td(title), + tags.td(url), + tags.td( + tags.input_( + {"type": "hidden", "name": "url", "value": url} + ), + tags.input_({"type": "submit", "value": "Subscribe"}), ), ), ) diff --git a/cry/web.py b/cry/web.py index b8fd033..b1c4b7c 100644 --- a/cry/web.py +++ b/cry/web.py @@ -497,7 +497,7 @@ class Handler(http.server.BaseHTTPRequestHandler): feeds.sort(key=feed.sort_key, reverse=True) document = views.feed_view(feeds) - self.write_html(document.render()) + self.write_html("\n" + document.render()) def serve_subscribe_choose(self): try: @@ -512,7 +512,7 @@ class Handler(http.server.BaseHTTPRequestHandler): return document = views.subscribe_choose_view(candidates) - self.write_html(document.render()) + self.write_html("\n" + document.render()) def write_html(self, html: str): response = html.encode("utf-8")