Live times

This commit is contained in:
John Doty 2024-12-01 08:06:08 -08:00
parent a66207cb9b
commit 51208f43b3
3 changed files with 78 additions and 15 deletions

60
cry/static/index.js Normal file
View file

@ -0,0 +1,60 @@
console.log("Hello world!");
function time_ago(time) {
// Much like the python in feed.py
const now = Date.now();
const seconds = Math.round((now - time) / 1000);
// If you *must* have live output (for debugging or something) just
// uncomment here.
// return `${seconds}s`;
if (seconds < 90) {
return `${seconds}s`;
}
const minutes = Math.round(seconds / 60);
if (minutes < 90) {
return `${minutes}m`;
}
const hours = Math.round(minutes / 60);
if (hours < 24) {
return `${hours}h`;
}
const days = Math.round(hours / 24);
if (days <= 7) {
return `${days}d`;
}
const weeks = Math.round(days / 7);
if (weeks < 52) {
return `${weeks}w`;
}
const years = Math.round(weeks / 52);
return `{years}y`
}
function timeAgoTick(selector, format) {
const tags = document.querySelectorAll(selector);
for (const tag of tags) {
const then = Date.parse(tag.getAttribute("datetime"));
const when = time_ago(then);
const formatted = format(when);
// NOTE: I'm being a real dork about this because I am super nervous
// about leaking memory/making the page heaver than it needs to be,
// with a callback every second and all.
const text = tag.firstChild;
if (text.data != formatted) {
text.data = formatted;
}
}
}
function registerTimeCallback() {
setInterval(() => {
timeAgoTick(".time-ago-bare", (a) => a);
timeAgoTick(".time-ago-paren", (a) => `(${a})`);
}, 1000);
}
addEventListener("DOMContentLoaded", () => registerTimeCallback());

View file

@ -41,7 +41,10 @@ def _feed_summary(f: feed.Feed) -> tags.li:
{"class": "feed-summary-timestamp"}, {"class": "feed-summary-timestamp"},
tags.i( tags.i(
f"Posted ", f"Posted ",
time_(entry.time_ago(), datetime=entry.posted_time_iso()), time_(
{"class": "time-ago-bare", "datetime": entry.posted_time_iso()},
entry.time_ago(),
),
" ago", " ago",
), ),
), ),
@ -116,8 +119,11 @@ def feed_view(feeds: list[feed.Feed]) -> tags.html:
), ),
" ", " ",
time_( time_(
{
"class": "time-ago-paren",
"datetime": entry.posted_time_iso(),
},
f"({entry.time_ago()})", f"({entry.time_ago()})",
datetime=entry.posted_time_iso(),
), ),
) )
for entry in f.entries for entry in f.entries
@ -131,6 +137,7 @@ def feed_view(feeds: list[feed.Feed]) -> tags.html:
), ),
), ),
), ),
tags.script({"src": "/index.js"}),
) )
assert isinstance(document, tags.html) assert isinstance(document, tags.html)
return document return document

View file

@ -1,10 +1,8 @@
import asyncio import asyncio
import contextlib import contextlib
import dataclasses import dataclasses
import dominate.tags as tags
import functools import functools
import http.server import http.server
import io
import pathlib import pathlib
import time import time
import traceback import traceback
@ -17,6 +15,7 @@ from . import database
from . import feed from . import feed
from . import views from . import views
class DeadlineCondition: class DeadlineCondition:
"""A condition variable that allows you to wait with a timeout.""" """A condition variable that allows you to wait with a timeout."""
@ -296,6 +295,7 @@ def refresh_feeds(sink: EventChannel):
REFRESH_TASK: BackgroundTask | None = None REFRESH_TASK: BackgroundTask | None = None
@background_task @background_task
def subscribe(sink: EventChannel, url: str): def subscribe(sink: EventChannel, url: str):
"""Subscribe to a feed.""" """Subscribe to a feed."""
@ -338,9 +338,11 @@ class Handler(http.server.BaseHTTPRequestHandler):
if self.path == "/": if self.path == "/":
return self.serve_feeds() return self.serve_feeds()
elif self.path == "/style.css": elif self.path == "/style.css":
return self.serve_style() return self.serve_static("style.css", "text/css")
elif self.path == "/event.js": elif self.path == "/event.js":
return self.serve_event_js() return self.serve_static("event.js", "text/javascript")
elif self.path == "/index.js":
return self.serve_static("index.js", "text/javascript")
elif self.path == "/refresh-status": elif self.path == "/refresh-status":
return self.serve_status() return self.serve_status()
elif self.path == "/subscribe-status": elif self.path == "/subscribe-status":
@ -478,16 +480,10 @@ class Handler(http.server.BaseHTTPRequestHandler):
self.end_headers() self.end_headers()
self.wfile.write(response) self.wfile.write(response)
def serve_event_js(self): def serve_static(self, name: str, content_type: str):
self.write_file( self.write_file(
pathlib.Path(__file__).parent / "static" / "event.js", pathlib.Path(__file__).parent / "static" / name,
content_type="text/javascript", content_type=content_type,
)
def serve_style(self):
self.write_file(
pathlib.Path(__file__).parent / "static" / "style.css",
content_type="text/css",
) )
def write_file(self, path: pathlib.Path, content_type: str): def write_file(self, path: pathlib.Path, content_type: str):