Compare commits

...

3 commits

Author SHA1 Message Date
51208f43b3 Live times 2024-12-01 08:06:23 -08:00
a66207cb9b Note 2024-12-01 07:15:09 -08:00
47ec8dce7b Note 2024-12-01 07:09:44 -08:00
4 changed files with 81 additions and 15 deletions

View file

@ -21,6 +21,8 @@ events.addEventListener("redirect", (e) => {
window.location = e.data; window.location = e.data;
}); });
// NOTE: This was designed for a refresh redesign but I haven't the heart to do
// it yet.
events.addEventListener("progress", (e) => { events.addEventListener("progress", (e) => {
// Grab the progress element being referred to. // Grab the progress element being referred to.
const parameters = JSON.parse(e.data); const parameters = JSON.parse(e.data);

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
@ -188,6 +195,7 @@ def status_view() -> tags.html:
return document return document
# NOTE: Not in use yet.
def refresh_view(feeds: list[feed.Feed]) -> tags.html: def refresh_view(feeds: list[feed.Feed]) -> tags.html:
document = tags.html( document = tags.html(
_standard_header("Refreshing Feeds..."), _standard_header("Refreshing Feeds..."),

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):