diff --git a/telnet/server.py b/telnet/server.py index 3df6c23..8434a07 100644 --- a/telnet/server.py +++ b/telnet/server.py @@ -58,7 +58,7 @@ async def prompt( ) -> str: """Handle prompt + inactivity timeouts safely.""" await write(writer, label) - try: + try: data = await asyncio.wait_for(reader.readline(), timeout=READ_TIMEOUT) except asyncio.TimeoutError: await write(writer, "\r\n Connection inactive.\r\n") @@ -68,6 +68,7 @@ async def prompt( text = data.decode(errors="ignore").strip() return re.sub(r"[^\x20-\x7e]", "", text) + async def show_bbs(writer, bbs): await write(writer, f"\r\n {bbs.site.name}\r\n") await write(writer, f" {bbs.site.description}\r\n") @@ -87,6 +88,7 @@ async def show_bbs(writer, bbs): await write(writer, "[#] open board [n] news [q] quit\r\n") + async def show_board(writer, board, threads, has_next): await write(writer, f"\r\n {board.name}\r\n") await write(writer, f" {board.description}\r\n\r\n") @@ -96,7 +98,9 @@ async def show_board(writer, board, threads, has_next): else: for i, t in enumerate(threads, 1): date = format_datetime_utc(t.created_at) - await write(writer, f" {i}. {t.title} · {t.author.handle} · {date}\r\n") + await write( + writer, f" {i}. {t.title} · {t.author.handle} · {date}\r\n" + ) cmds = ["[#] open thread"] if has_next: diff --git a/tui/screens/thread.py b/tui/screens/thread.py index 3f746a2..e3b1659 100644 --- a/tui/screens/thread.py +++ b/tui/screens/thread.py @@ -120,13 +120,16 @@ class ThreadScreen(Screen): # Fetch any quoted replies not already known missing = [ - r.quote for r in result.replies + r.quote + for r in result.replies if r.quote and r.quote not in self._replies_map ] for uri in missing: try: parsed = AtUri.parse(uri) - rec = await get_record(client, parsed.did, parsed.collection, parsed.rkey) + rec = await get_record( + client, parsed.did, parsed.collection, parsed.rkey + ) author = await resolve_identity(client, parsed.did) self._replies_map[uri] = reply_from_record(rec, author) except Exception: diff --git a/web/src/components/HandleInput.tsx b/web/src/components/HandleInput.tsx index 9619556..5ae7ea9 100644 --- a/web/src/components/HandleInput.tsx +++ b/web/src/components/HandleInput.tsx @@ -13,8 +13,10 @@ const PLACEHOLDERS = [ // Props for HandleInput. Extends standard props so callers can // pass things like `required`, `disabled`, `id`, etc. -interface HandleInputProps - extends Omit, "onChange" | "value"> { +interface HandleInputProps extends Omit< + InputHTMLAttributes, + "onChange" | "value" +> { value: string; onChange: (v: string) => void; } diff --git a/web/src/components/ReplyCard.tsx b/web/src/components/ReplyCard.tsx index 6d4ab37..891e74f 100644 --- a/web/src/components/ReplyCard.tsx +++ b/web/src/components/ReplyCard.tsx @@ -40,7 +40,10 @@ export default function ReplyCard({ const isSysop = userDid === sysopDid; return ( -
+
{reply.handle} diff --git a/web/src/hooks/useThreadReplies.ts b/web/src/hooks/useThreadReplies.ts index d3fe0b2..1556aac 100644 --- a/web/src/hooks/useThreadReplies.ts +++ b/web/src/hooks/useThreadReplies.ts @@ -35,7 +35,6 @@ function pageForReply( return index >= 0 ? Math.floor(index / REPLIES_PER_PAGE) + 1 : null; } - function rkeyFromHash(): string | null { const h = typeof window !== "undefined" ? window.location.hash : ""; return h.startsWith("#reply-") ? h.slice(7) : null; @@ -118,7 +117,8 @@ export function useThreadReplies(loaded: ThreadLoaderData) { return clampPage(fromHash ?? fromReply ?? fromUrl, allRefs.length); }); - const [initialScrollDone, setInitialScrollDone] = useState(!initialScrollRkey); + const [initialScrollDone, setInitialScrollDone] = + useState(!initialScrollRkey); // Keep the URL in sync when the user changes page (e.g. via PageNav). useEffect(() => { @@ -152,7 +152,9 @@ export function useThreadReplies(loaded: ThreadLoaderData) { // Pending scroll target — set when navigating to a reply on another page. // Cleared once the scroll completes. - const [pendingScrollRkey, setPendingScrollRkey] = useState(null); + const [pendingScrollRkey, setPendingScrollRkey] = useState( + null, + ); const fetchVisiblePage = useCallback( async (currentRefs: BacklinkRef[], currentPage: number) => { @@ -224,7 +226,9 @@ export function useThreadReplies(loaded: ThreadLoaderData) { .map((i) => i.quote!) .filter((uri) => !replyCache[uri]); if (missingQuotes.length) { - const quoteRefs = [...new Set(missingQuotes)].map((uri) => parseAtUri(uri)); + const quoteRefs = [...new Set(missingQuotes)].map((uri) => + parseAtUri(uri), + ); const quoteRecords = await getRecordsBatch(quoteRefs); const quoteDids = quoteRecords.map((r) => parseAtUri(r.uri).did); const quoteAuthors = await resolveIdentitiesBatch(quoteDids); diff --git a/web/src/pages/Home.tsx b/web/src/pages/Home.tsx index 0140e67..7083a4b 100644 --- a/web/src/pages/Home.tsx +++ b/web/src/pages/Home.tsx @@ -87,7 +87,10 @@ export default function Home() {

Dial a BBS

-
+ setQuote({ uri: reply.uri, handle: reply.handle })} - onQuoteClick={reply.quote ? () => scrollToReply(reply.quote!) : undefined} + onQuoteClick={ + reply.quote ? () => scrollToReply(reply.quote!) : undefined + } onDelete={() => onDeleteReply(reply)} onBan={() => onBan(reply.did)} onHide={() => onHide(reply.uri)}