From f3f07ed1e3421641e84b2f87397a31a9e39c6f14 Mon Sep 17 00:00:00 2001 From: khannurien Date: Tue, 29 Sep 2026 21:42:08 +0000 Subject: [PATCH] =?UTF-8?q?v3:=20every=20doc=20opens=20with=20the=20role,?= =?UTF-8?q?=20then=20the=20mechanism,=20then=20the=20details=20=E2=80=94?= =?UTF-8?q?=20the=20docs=20were=20written=20bottom-up:=20what=20a=20thing?= =?UTF-8?q?=20does=20first=20("Declares=20the=20three=20contexts=20WSProvi?= =?UTF-8?q?der=20fills=E2=80=A6"),=20details=20that=20only=20make=20sense?= =?UTF-8?q?=20once=20its=20purpose=20is=20known=20next,=20and=20the=20reas?= =?UTF-8?q?on=20it=20exists=20last=20("=E2=80=A6so=20that=20a=20feed=20doe?= =?UTF-8?q?sn't=20re-render"),=20so=20a=20reader=20had=20nothing=20to=20ha?= =?UTF-8?q?ng=20the=20first=20sentences=20on.=20The=20README's=20rule=20ca?= =?UTF-8?q?used=20it,=20since=20a=20module=20doc=20"opened=20with=20what?= =?UTF-8?q?=20the=20module=20does";=20it=20now=20opens=20with=20the=20modu?= =?UTF-8?q?le's=20role=20in=20the=20app,=20and=20the=20value-side=20phrasi?= =?UTF-8?q?ng=20of=20a=20type=20("Returned=20to=20Y=20by=20X")=20comes=20o?= =?UTF-8?q?nce=20the=20role=20is=20said,=20with=20WSContext=20as=20the=20b?= =?UTF-8?q?efore=20and=20after.=20WSContext.ts=20is=20rewritten=20that=20w?= =?UTF-8?q?ay=20throughout,=20and=20so=20are=20the=20docs=20elsewhere=20th?= =?UTF-8?q?at=20buried=20their=20purpose=20in=20a=20trailing=20"so=20that"?= =?UTF-8?q?=20(the=20migrations,=20og,=20image-proxy,=20public-address,=20?= =?UTF-8?q?useFading,=20useFeedCache,=20the=20drafts),=20opened=20on=20a?= =?UTF-8?q?=20generic=20verb=20that=20hid=20it=20("Holds",=20"Declares",?= =?UTF-8?q?=20"Loads",=20"Defines",=20"Types":=20the=20contexts=20and=20pr?= =?UTF-8?q?oviders,=20the=20shared=20types,=20the=20models,=20the=20hooks)?= =?UTF-8?q?,=20or=20were=20label=20fragments=20("The=20page=20of=20a=20dum?= =?UTF-8?q?p=E2=80=A6",=20"A=20row=20of=20tabs.").=20A=20function=20whose?= =?UTF-8?q?=20verb=20is=20its=20action=20("Stores=20`session`"),=20a=20pro?= =?UTF-8?q?ps=20or=20result=20type,=20and=20a=20protocol=20message=20("Sen?= =?UTF-8?q?t=20by=20X=20when=20Y")=20already=20say=20their=20role=20and=20?= =?UTF-8?q?are=20left=20as=20they=20are.=20Only=20comments=20changed,=20an?= =?UTF-8?q?d=20the=20catalogs=20only=20move=20their=20references;=20deno?= =?UTF-8?q?=20fmt,=20deno=20lint=20and=20doc:lint=20are=20clean.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- README.md | 31 ++- api/config.ts | 15 +- api/db/migrations/0002_dump_thumbnail.ts | 6 +- api/db/migrations/0003_dump_backlinks.ts | 8 +- api/db/migrations/0004_user_roles.ts | 4 +- api/db/migrations/0009_chat_reply.ts | 8 +- api/db/migrations/0010_youtube_embed_start.ts | 8 +- .../0011_split_favicon_thumbnail.ts | 13 +- api/db/migrations/0013_dump_url_canonical.ts | 5 +- api/db/migrations/0015_token_revocation.ts | 6 +- .../0018_attachment_resource_type.ts | 10 +- api/lib/api-exception.ts | 4 +- api/lib/canonical-url.ts | 11 +- api/lib/pagination.ts | 6 +- api/middleware/og.ts | 8 +- api/model/auth.ts | 5 +- api/model/category.ts | 4 +- api/model/chat.ts | 2 +- api/model/comment.ts | 4 +- api/model/dump.ts | 7 +- api/model/follow.ts | 4 +- api/model/invite.ts | 4 +- api/model/notification.ts | 4 +- api/model/password-reset.ts | 4 +- api/model/playlist.ts | 4 +- api/model/rows.ts | 5 +- api/model/user.ts | 6 +- api/remote/image-proxy.ts | 9 +- api/remote/providers/provider.ts | 5 +- api/remote/public-address.ts | 8 +- api/remote/youtube-playlist.ts | 6 +- api/routes/avatars.ts | 6 +- api/routes/categories.ts | 3 +- api/routes/invites.ts | 4 +- api/routes/thumbnails.ts | 8 +- api/services/attachment-service.ts | 7 +- api/services/rich-content-service.ts | 6 +- shared/api.ts | 7 +- shared/category.ts | 7 +- shared/chat.ts | 4 +- shared/comment.ts | 5 +- shared/dump.ts | 8 +- shared/follow.ts | 5 +- shared/mention.ts | 4 +- shared/notification.ts | 8 +- shared/permissions.ts | 7 +- shared/player.ts | 5 +- shared/playlist.ts | 6 +- shared/search.ts | 4 +- shared/user.ts | 7 +- shared/validation.ts | 4 +- shared/ws.ts | 5 +- .../dump/create/DumpCreateModal.tsx | 4 +- src/components/dump/create/StepIndicator.tsx | 4 +- src/components/dump/create/TitleField.tsx | 4 +- src/components/feed/FeedTabBar.tsx | 3 +- src/components/shared/TabBar.tsx | 2 +- src/config/playerMode.ts | 3 +- src/contexts/auth/AuthContext.ts | 4 +- src/contexts/auth/AuthProvider.tsx | 2 +- src/contexts/category/CategoriesContext.ts | 4 +- src/contexts/category/CategoriesProvider.tsx | 4 +- src/contexts/chat/ChatContext.ts | 5 +- src/contexts/chat/ChatProvider.tsx | 5 +- src/contexts/player/PlayerContext.ts | 9 +- src/contexts/player/PlayerProvider.tsx | 7 +- src/contexts/social/FollowContext.ts | 10 +- src/contexts/social/FollowProvider.tsx | 5 +- src/contexts/theme/ThemeContext.ts | 4 +- src/contexts/theme/ThemeProvider.tsx | 5 +- src/contexts/ws/AvatarOverrideContext.ts | 10 +- src/contexts/ws/WSContext.ts | 179 +++++++++++------- src/contexts/ws/WSProvider.tsx | 15 +- src/hooks/chat/useChat.ts | 2 +- src/hooks/dump/useUserDumpFeed.ts | 4 +- src/hooks/editor/useEmojiTrigger.ts | 6 +- src/hooks/editor/useMentionAutocomplete.ts | 6 +- src/hooks/feed/useDefaultFeedTab.ts | 3 +- src/hooks/feed/useFading.ts | 4 +- src/hooks/feed/useFeedCache.ts | 5 +- src/hooks/feed/usePagedList.ts | 6 +- src/hooks/form/useApiForm.ts | 6 +- src/hooks/playlist/usePlaylist.ts | 5 +- src/hooks/playlist/usePlaylistMemberships.ts | 5 +- src/hooks/profile/useProfile.ts | 5 +- src/hooks/shared/useFetchState.ts | 3 +- src/hooks/social/useFollows.ts | 3 +- src/hooks/ws/useWS.ts | 6 +- src/locales/en.po | 32 ++-- src/locales/fr.po | 32 ++-- src/pages/Dump.tsx | 2 +- src/pages/DumpEdit.tsx | 2 +- src/pages/Search.tsx | 4 +- src/pages/UserDumps.tsx | 4 +- src/pages/UserUpvoted.tsx | 4 +- src/utils/auth/storage.ts | 4 +- src/utils/chat/draft.ts | 6 +- src/utils/chat/text.ts | 4 +- src/utils/dump/draft.ts | 6 +- src/utils/editor/skinTone.ts | 4 +- src/utils/editor/text.ts | 4 +- src/utils/feed/pagedList.ts | 6 +- src/utils/shared/api.ts | 5 +- src/utils/shared/loadState.ts | 4 +- src/utils/shared/sound.ts | 6 +- 105 files changed, 459 insertions(+), 371 deletions(-) diff --git a/README.md b/README.md index 84a31552..ea656956 100644 --- a/README.md +++ b/README.md @@ -188,9 +188,20 @@ one of: Add an example only when the call isn't obvious. 3. **Place in the chain**: where its input comes from and where its output goes. -A type's doc is phrased from the value's side, naming the producer and the -consumer: "Returned to Y by X when Z", "Passed to Y by X". It is never "What X -returns to Y" or "What X passes to Y". +**A doc opens with the role, then the mechanism, then the details.** Its first +sentence says what part of the app the thing serves or what problem it solves, +so a reader who has never seen it knows why it exists. How it does that (what +feeds it, what reads it, how it's split) comes next, and the details last. Each +sentence makes sense given only the ones before it. Not "Declares the three +contexts `WSProvider` fills from the WebSocket. They are split so that a feed +doesn't re-render with every chat message", which leaves the reason for last, +but "Live updates from the server reach the pages through three contexts, split +so that a feed doesn't re-render with every chat message. `WSProvider` fills +them from its WebSocket." + +Once the role is said, a type's doc is phrased from the value's side, naming the +producer and the consumer: "Returned to Y by X when Z", "Passed to Y by X". It +is never "What X returns to Y" or "What X passes to Y". Don't pack a doc into a label followed by a colon and a list ("X: one thing, plus some other thing"). Write sentences with a subject and a verb. @@ -209,13 +220,13 @@ and locals. None of these count as a doc: When a comment is there, it is as short as it can be, often one sentence, and it is written in full sentences. Labels and fragments ("Upvotes on dumps.") don't -count. A module doc is a few lines at most. It opens with what the module does, -then says who calls it and what it hands back, and it doesn't repeat what its -exports' docs say. `@throws` stays on whatever throws to its caller, with the -statuses of an `APIException` and when each happens. A router's module doc lists -its endpoints (method, path, who may call it), since the code states them -nowhere in one place. A summary never ends in a colon: the reference shows it -alone. +count. A module doc is a few lines at most. It opens with the module's role in +the app, then says how it plays it, who calls it and what it hands back, and it +doesn't repeat what its exports' docs say. `@throws` stays on whatever throws to +its caller, with the statuses of an `APIException` and when each happens. A +router's module doc lists its endpoints (method, path, who may call it), since +the code states them nowhere in one place. A summary never ends in a colon: the +reference shows it alone. **`//` comments** go wherever the code isn't obvious. They explain why, not what: a workaround, an ordering constraint, a surprising limitation, a security diff --git a/api/config.ts b/api/config.ts index 1a0aeca9..f3464a6f 100644 --- a/api/config.ts +++ b/api/config.ts @@ -1,7 +1,8 @@ /** - * Reads the server's settings from the `GERBEUR_*` environment variables, once - * at import, and holds the fixed limits the backend applies. The deno tasks - * load `.env` with `--env-file`, so changing a setting needs a restart. + * Lets a deployment configure the server through the `GERBEUR_*` environment + * variables, which it reads once at import, and holds the fixed limits the + * backend applies. The deno tasks load `.env` with `--env-file`, so changing a + * setting needs a restart. * * @module */ @@ -55,10 +56,10 @@ export const PUBLIC_URL: string = Deno.env.get("GERBEUR_PUBLIC_URL")?.trim().replace(/\/$/, "") || `http://localhost:${PORT}`; /** - * Holds the URL the frontend is served from (`GERBEUR_FRONTEND_URL`), without - * a trailing slash, when it isn't {@link PUBLIC_URL}, as with a separate Vite - * server. It is an allowed origin, and password reset links and the Open Graph - * tags' page URLs point to it. + * Points password reset links and the Open Graph tags' page URLs at the + * frontend when it isn't served from {@link PUBLIC_URL}, as with a separate + * Vite server, and allows it as an origin. It is `GERBEUR_FRONTEND_URL`, + * without a trailing slash. */ export const FRONTEND_URL: string = Deno.env.get("GERBEUR_FRONTEND_URL")?.trim().replace(/\/$/, "") || diff --git a/api/db/migrations/0002_dump_thumbnail.ts b/api/db/migrations/0002_dump_thumbnail.ts index b4f7b1c4..86080c13 100644 --- a/api/db/migrations/0002_dump_thumbnail.ts +++ b/api/db/migrations/0002_dump_thumbnail.ts @@ -1,7 +1,7 @@ /** - * Adds `dumps.custom_thumbnail_mime`, so a poster can upload a thumbnail that - * replaces the fetched one. It holds the uploaded image's type, and NULL means - * the dump has none. + * Lets a poster upload a thumbnail that replaces the fetched one. It adds + * `dumps.custom_thumbnail_mime`, which holds the uploaded image's type; NULL + * means the dump has none. * * @module */ diff --git a/api/db/migrations/0003_dump_backlinks.ts b/api/db/migrations/0003_dump_backlinks.ts index ad1f033e..ac6e47f7 100644 --- a/api/db/migrations/0003_dump_backlinks.ts +++ b/api/db/migrations/0003_dump_backlinks.ts @@ -1,8 +1,8 @@ /** - * Adds `dump_backlinks`, which records the links from a dump's note or - * comments to other dumps, so a dump page can list the dumps related to it. - * backlink-service fills it, and the index on `dumps.url` lets it find the - * dumps an external link was posted as. + * Lets a dump page list the dumps related to it. It adds `dump_backlinks`, + * which records the links from a dump's note or comments to other dumps and + * which backlink-service fills, and an index on `dumps.url` to find the dumps + * an external link was posted as. * * @module */ diff --git a/api/db/migrations/0004_user_roles.ts b/api/db/migrations/0004_user_roles.ts index 4056eb78..162ef5a7 100644 --- a/api/db/migrations/0004_user_roles.ts +++ b/api/db/migrations/0004_user_roles.ts @@ -1,6 +1,6 @@ /** - * Adds `users.role`, which replaces the `is_admin` flag so that moderators can - * exist between users and admins. 0005 then drops the flag. + * Makes room for moderators between users and admins. It adds `users.role`, + * which replaces the `is_admin` flag, and 0005 then drops the flag. * * @module */ diff --git a/api/db/migrations/0009_chat_reply.ts b/api/db/migrations/0009_chat_reply.ts index 2e163667..7d7d514e 100644 --- a/api/db/migrations/0009_chat_reply.ts +++ b/api/db/migrations/0009_chat_reply.ts @@ -1,8 +1,8 @@ /** - * Adds `chat_messages.reply_to_id`, so a message can reply to another. It has - * no foreign key on purpose: when the replied-to message is deleted, the id - * stays and chat-service's join reads null, so the chat shows "deleted - * message" where the quote was. + * Lets a chat message reply to another, through `chat_messages.reply_to_id`. + * The column has no foreign key on purpose: when the replied-to message is + * deleted, the id stays and chat-service's join reads null, so the chat shows + * "deleted message" where the quote was. * * @module */ diff --git a/api/db/migrations/0010_youtube_embed_start.ts b/api/db/migrations/0010_youtube_embed_start.ts index b831ca5f..15da15bf 100644 --- a/api/db/migrations/0010_youtube_embed_start.ts +++ b/api/db/migrations/0010_youtube_embed_start.ts @@ -1,8 +1,8 @@ /** - * Adds the `start` parameter to the YouTube embed URLs stored before the - * YouTube provider carried it over. `rich_content.embedUrl` is computed when a - * dump is posted, and used to drop the source URL's `t` (`?t=1265`, - * `?t=1h2m3s`), so those videos played from 0:00. + * Makes the YouTube dumps posted with a start time, before the YouTube provider + * kept it, start there instead of at 0:00. `rich_content.embedUrl` is computed + * when a dump is posted, and it used to drop the source URL's `t` (`?t=1265`, + * `?t=1h2m3s`); this adds the `start` parameter back to the stored embed URLs. * * It reads the time from the stored source URL and fetches nothing. It keeps * its own copy of the parsing, so that it migrates every database alike should diff --git a/api/db/migrations/0011_split_favicon_thumbnail.ts b/api/db/migrations/0011_split_favicon_thumbnail.ts index 07196a89..d6734675 100644 --- a/api/db/migrations/0011_split_favicon_thumbnail.ts +++ b/api/db/migrations/0011_split_favicon_thumbnail.ts @@ -1,10 +1,11 @@ /** - * Moves site icons out of `rich_content.thumbnailUrl` into the new - * `faviconUrl`. The metadata fetch used to fall back on the page's icon, and - * then on a guessed `/favicon.ico`, so most thumbnails were a 16×16 icon, or a - * 404, that the UI stretched over a 128×72 box. It now stops at real artwork, - * and a missing `thumbnailUrl` means none, which the frontend draws a - * placeholder for. This gives the older rows that meaning. + * Stops older dumps from showing a site's icon as their thumbnail. The metadata + * fetch used to fall back on the page's icon, and then on a guessed + * `/favicon.ico`, so most thumbnails were a 16×16 icon, or a 404, that the UI + * stretched over a 128×72 box. It now stops at real artwork, and a missing + * `thumbnailUrl` means none, which the frontend draws a placeholder for. This + * gives the older rows that meaning, by moving their icons out of + * `rich_content.thumbnailUrl` into the new `faviconUrl`. * * It judges the stored URL alone and fetches nothing, so it doesn't fill * `accentColor`. The frontend derives a hue from the hostname when it is diff --git a/api/db/migrations/0013_dump_url_canonical.ts b/api/db/migrations/0013_dump_url_canonical.ts index 75d0675a..da1a17ea 100644 --- a/api/db/migrations/0013_dump_url_canonical.ts +++ b/api/db/migrations/0013_dump_url_canonical.ts @@ -1,6 +1,7 @@ /** - * Adds `dumps.url_canonical`, the key the create form's "already dumped" hint - * looks a URL up by, and fills it for every URL dump already posted. + * Lets the create form warn that a link was already dumped. It adds + * `dumps.url_canonical`, the key the hint looks a URL up by, and fills it for + * every URL dump already posted. * * It fills the key from each stored URL and fetches nothing. Its helpers are a * copy of lib/canonical-url.ts as it stood when this shipped: importing the diff --git a/api/db/migrations/0015_token_revocation.ts b/api/db/migrations/0015_token_revocation.ts index 0ffd9947..c95ae19e 100644 --- a/api/db/migrations/0015_token_revocation.ts +++ b/api/db/migrations/0015_token_revocation.ts @@ -1,7 +1,7 @@ /** - * Adds `users.tokens_valid_after`, so that changing a password ends every - * session opened before. Tokens are stateless JWTs, so lib/auth.ts refuses a - * token issued before that time instead. + * Lets a password change end every session opened before it. Tokens are + * stateless JWTs, so this adds `users.tokens_valid_after`, and lib/auth.ts + * refuses a token issued before that time. * * @module */ diff --git a/api/db/migrations/0018_attachment_resource_type.ts b/api/db/migrations/0018_attachment_resource_type.ts index e66dabc4..dc91220f 100644 --- a/api/db/migrations/0018_attachment_resource_type.ts +++ b/api/db/migrations/0018_attachment_resource_type.ts @@ -1,8 +1,10 @@ /** - * Adds `attachments.resource_type`, the kind of thing an attachment's - * `resource_id` names. Without it, an attachment couldn't tell whose it was: - * one pasted into a private dump was served to anyone with its URL, and one - * whose dump, comment or message was deleted was kept for good. + * Serves an attachment only to those who may see what it was pasted into, and + * deletes it once that is gone. It adds `attachments.resource_type`, the kind + * of thing an attachment's `resource_id` names. Without it, an attachment + * couldn't tell whose it was: one pasted into a private dump was served to + * anyone with its URL, and one whose dump, comment or message was deleted was + * kept for good. * * @module */ diff --git a/api/lib/api-exception.ts b/api/lib/api-exception.ts index 9f9cae9f..6f412d88 100644 --- a/api/lib/api-exception.ts +++ b/api/lib/api-exception.ts @@ -1,6 +1,6 @@ /** - * Defines the exception that carries an HTTP error from any layer up to the - * error middleware. + * Lets any layer fail a request with an HTTP status, which the error middleware + * turns into the response. * * @module */ diff --git a/api/lib/canonical-url.ts b/api/lib/canonical-url.ts index ed56840b..2f7c4246 100644 --- a/api/lib/canonical-url.ts +++ b/api/lib/canonical-url.ts @@ -1,9 +1,10 @@ /** - * Reduces a URL to a key shared by every link to the same page or video. - * `dump-service` stores it in `dumps.url_canonical` when a - * dump is posted or edited, and `GET /api/dumps/by-url` matches on it - * to warn the create form of a repost. The key is never fetched or shown, so it - * may be lossy: it forces `https`, drops `www.`, tracking parameters and + * Spots reposts and links to known dumps, by reducing a URL to a key shared by + * every link to the same page or video. `dump-service` stores it in + * `dumps.url_canonical` when a dump is posted or edited, `GET + * /api/dumps/by-url` matches on it to warn the create form of a repost, and + * backlink-service compares links by it. The key is never fetched or shown, so + * it may be lossy: it forces `https`, drops `www.`, tracking parameters and * timestamps. * * Migration 0013 backfilled existing rows with a frozen copy of these rules. diff --git a/api/lib/pagination.ts b/api/lib/pagination.ts index 713ce309..82e2cf7e 100644 --- a/api/lib/pagination.ts +++ b/api/lib/pagination.ts @@ -1,7 +1,7 @@ /** - * Reads the page a list route's query string asks for, and cuts the rows a - * service fetched into that page. The routes send the page as - * `PaginatedData`. + * Pages every list route the same way. It reads the page a list route's query + * string asks for, and cuts the rows a service fetched into that page, which + * the routes send as `PaginatedData`. * * @module */ diff --git a/api/middleware/og.ts b/api/middleware/og.ts index c561ef18..9974c36c 100644 --- a/api/middleware/og.ts +++ b/api/middleware/og.ts @@ -1,8 +1,8 @@ /** - * Answers a link to a dump, a profile or a public playlist with `index.html` - * carrying that page's Open Graph and Twitter card tags, for the link previews - * of chat apps and social sites, which don't run the app. main.ts installs it - * before the routers. + * Gives links to the site rich previews in chat apps and social sites, which + * don't run the app. It answers a link to a dump, a profile or a public + * playlist with `index.html` carrying that page's Open Graph and Twitter card + * tags. main.ts installs it before the routers. * * @module */ diff --git a/api/model/auth.ts b/api/model/auth.ts index 9515e708..767730e4 100644 --- a/api/model/auth.ts +++ b/api/model/auth.ts @@ -1,6 +1,7 @@ /** - * Types the payloads of session and password reset tokens, and guards them. - * `lib/jwt.ts` signs the tokens and runs the guards when it verifies one. + * Checks what a verified token says before it is trusted. It types the payloads + * of session and password reset tokens, and `lib/jwt.ts` runs their guards when + * it verifies one. * * @module */ diff --git a/api/model/category.ts b/api/model/category.ts index 2de6e2b8..c74c59f0 100644 --- a/api/model/category.ts +++ b/api/model/category.ts @@ -1,6 +1,6 @@ /** - * Types the rows the category service reads from `categories`, and turns them - * into the {@link Category} the category routes send. + * Turns the rows the category service reads from `categories` into the {@link + * Category} the category routes send. * * @module */ diff --git a/api/model/chat.ts b/api/model/chat.ts index 75efd53c..ef1c6cb1 100644 --- a/api/model/chat.ts +++ b/api/model/chat.ts @@ -1,5 +1,5 @@ /** - * Maps the rows of `chat_messages` to the {@link ChatMessage} the API sends. + * Turns the rows of `chat_messages` into the {@link ChatMessage} the API sends. * Only `services/chat-service.ts` uses it, on the rows of its one query. * * @module diff --git a/api/model/comment.ts b/api/model/comment.ts index 36b032c0..854d5a1a 100644 --- a/api/model/comment.ts +++ b/api/model/comment.ts @@ -1,6 +1,6 @@ /** - * Types the rows the comment service reads from `comments`, and turns them into - * the {@link Comment} the comment routes send. + * Turns the rows the comment service reads from `comments` into the {@link + * Comment} the comment routes send. * * @module */ diff --git a/api/model/dump.ts b/api/model/dump.ts index b26e2dbd..8adf80cd 100644 --- a/api/model/dump.ts +++ b/api/model/dump.ts @@ -1,7 +1,8 @@ /** - * Maps the `dumps` table to the API's {@link Dump}. Every service that reads - * dumps selects them with the column lists here, checks each row with - * {@link isDumpRow} and converts it with {@link dumpRowToApi}. + * Turns the rows of `dumps` into the API's {@link Dump} the same way for every + * service that reads dumps: each selects them with the column lists here, + * checks each row with {@link isDumpRow} and converts it with {@link + * dumpRowToApi}. * * @module */ diff --git a/api/model/follow.ts b/api/model/follow.ts index c18d37ea..36905fcd 100644 --- a/api/model/follow.ts +++ b/api/model/follow.ts @@ -1,6 +1,6 @@ /** - * Types and guards the rows of `follows`, which `follow-service.ts` reads to - * answer what a user follows. + * Checks the rows `follow-service.ts` reads from `follows` to answer what a + * user follows. * * @module */ diff --git a/api/model/invite.ts b/api/model/invite.ts index 0ab0a01a..92f59aab 100644 --- a/api/model/invite.ts +++ b/api/model/invite.ts @@ -1,6 +1,6 @@ /** - * Types and guards the rows of `invites`, which `invite-service.ts` reads to - * check an invite before sign-up. + * Checks the rows `invite-service.ts` reads from `invites` to vet an invite + * before sign-up. * * @module */ diff --git a/api/model/notification.ts b/api/model/notification.ts index ccdb6f58..a025e662 100644 --- a/api/model/notification.ts +++ b/api/model/notification.ts @@ -1,6 +1,6 @@ /** - * Types and guards the rows of `notifications`, and converts them to the - * {@link Notification} that `GET /api/notifications` answers. + * Turns the rows of `notifications`, once checked, into the {@link + * Notification} that `GET /api/notifications` answers. * * @module */ diff --git a/api/model/password-reset.ts b/api/model/password-reset.ts index b8685ec6..07d7ace5 100644 --- a/api/model/password-reset.ts +++ b/api/model/password-reset.ts @@ -1,6 +1,6 @@ /** - * Types and guards the rows of `password_reset_tokens`, which - * `password-reset-service.ts` reads to make each reset link work once. + * Checks the rows `password-reset-service.ts` reads from + * `password_reset_tokens` to make each reset link work once. * * @module */ diff --git a/api/model/playlist.ts b/api/model/playlist.ts index 1113dd29..9536aa57 100644 --- a/api/model/playlist.ts +++ b/api/model/playlist.ts @@ -1,6 +1,6 @@ /** - * Types the rows the playlist and follow services read from `playlists`, and - * turns them into the {@link Playlist} the API sends. + * Turns the rows the playlist and follow services read from `playlists` into + * the {@link Playlist} the API sends. * * @module */ diff --git a/api/model/rows.ts b/api/model/rows.ts index 6e50c6d6..75909126 100644 --- a/api/model/rows.ts +++ b/api/model/rows.ts @@ -1,7 +1,6 @@ /** - * Checks the rows of a list query, for the services. Every service answers a - * row that doesn't have its table's shape with a 500 rather than leaving it - * out, so that damage shows instead of making items silently vanish. + * Makes a damaged row fail its query with a 500 rather than silently vanish + * from a list. Every service checks the rows of its list queries with it. * * @module */ diff --git a/api/model/user.ts b/api/model/user.ts index 7237533a..a4a195de 100644 --- a/api/model/user.ts +++ b/api/model/user.ts @@ -1,7 +1,7 @@ /** - * Types and guards the rows of `users`, and converts them to the {@link User} - * that `user-service.ts` returns. A route turns a `User` into what it may send - * with {@link toPublicUser} or {@link toSelfUser}. + * Turns the rows of `users`, once checked, into the {@link User} that + * `user-service.ts` returns. A route turns a `User` into what it may send with + * {@link toPublicUser} or {@link toSelfUser}. * * @module */ diff --git a/api/remote/image-proxy.ts b/api/remote/image-proxy.ts index b11cef12..da5f5e73 100644 --- a/api/remote/image-proxy.ts +++ b/api/remote/image-proxy.ts @@ -1,8 +1,9 @@ /** - * Fetches and caches the remote images `GET /api/proxy-image` serves. The - * frontend routes a thumbnail through it when the image is on plain http, - * which an https page would block, or when loading it directly failed, often - * to hotlink protection. + * Shows the thumbnails a browser can't load from their own site: those on plain + * http, which an https page would block, and those behind hotlink protection. + * It fetches and caches the images `GET /api/proxy-image` serves, which the + * frontend routes a thumbnail through when it is on http or when loading it + * directly failed. * * @module */ diff --git a/api/remote/providers/provider.ts b/api/remote/providers/provider.ts index a027ea80..525c534a 100644 --- a/api/remote/providers/provider.ts +++ b/api/remote/providers/provider.ts @@ -1,6 +1,7 @@ /** - * Declares what a link provider implements. `rich-content-service.ts` asks its - * providers in turn and fetches a link's preview from the first that matches. + * Lets each kind of site have its own link previews. A provider implements this + * interface, and `rich-content-service.ts` asks its providers in turn and + * fetches a link's preview from the first that matches. * * @module */ diff --git a/api/remote/public-address.ts b/api/remote/public-address.ts index 4c571f22..096c417f 100644 --- a/api/remote/public-address.ts +++ b/api/remote/public-address.ts @@ -1,8 +1,8 @@ /** - * Tells private addresses from public ones, so that a user-supplied URL can't - * make the server fetch what only it can reach: loopback, the LAN, container - * networks or the cloud metadata endpoint at 169.254.169.254. `fetch.ts` checks - * every hop with it. + * Keeps a user-supplied URL from making the server fetch what only it can + * reach: loopback, the LAN, container networks or the cloud metadata endpoint + * at 169.254.169.254. It tells private addresses from public ones, and + * `fetch.ts` checks every hop with it. * * @module */ diff --git a/api/remote/youtube-playlist.ts b/api/remote/youtube-playlist.ts index 6a763d65..377fa827 100644 --- a/api/remote/youtube-playlist.ts +++ b/api/remote/youtube-playlist.ts @@ -1,7 +1,7 @@ /** - * Resolves a YouTube playlist to its entries' titles and lengths, for - * `GET /api/youtube/playlist`. The embed plays the list but doesn't expose - * them, and the global player needs them to draw a tracklist. + * Gives the global player a tracklist for a YouTube playlist, which the embed + * plays but doesn't list. It resolves the playlist to its entries' titles and + * lengths, for `GET /api/youtube/playlist`. * * They are read from the `ytInitialData` JSON of the public playlist page, * whose undocumented shape changes, so both the current `lockupViewModel` rows diff --git a/api/routes/avatars.ts b/api/routes/avatars.ts index 878b1cc7..12b5a5be 100644 --- a/api/routes/avatars.ts +++ b/api/routes/avatars.ts @@ -1,7 +1,7 @@ /** - * Serves the avatar endpoints. The profile page uploads the avatar, and the - * client's `Avatar` component loads it, with the user's `updatedAt` as a - * cache-busting version. + * Stores and serves the users' avatars. The profile page uploads the avatar, + * and the client's `Avatar` component loads it, with the user's `updatedAt` as + * a cache-busting version. * * - `POST /api/avatars/me` — signed in. Replaces the caller's avatar (multipart * `file`, at most 5 MB), sends `user_updated` to everyone, and answers the diff --git a/api/routes/categories.ts b/api/routes/categories.ts index f8c71838..95d3f1e2 100644 --- a/api/routes/categories.ts +++ b/api/routes/categories.ts @@ -1,5 +1,6 @@ /** - * The category routes. + * Serves the categories dumps are filed under and their feeds, and changes them + * for those with `category:manage`. * * - `GET /api/categories` — public. Answers every category, in order. * - `GET /api/categories/:slug` — public. Answers one category. diff --git a/api/routes/invites.ts b/api/routes/invites.ts index 822eaf6d..3a560e15 100644 --- a/api/routes/invites.ts +++ b/api/routes/invites.ts @@ -1,6 +1,6 @@ /** - * Serves the invite endpoints. Any signed-in user can invite someone, from - * their profile page, and the invite link opens the `/register` page. + * Lets any signed-in user invite someone, from their profile page. The invite + * link opens the `/register` page. * * - `POST /api/invites` — signed in. Makes an invite and answers its token. * - `GET /api/invites/:token` — public. Checks that an invite still works, diff --git a/api/routes/thumbnails.ts b/api/routes/thumbnails.ts index 21617b68..24fa25ee 100644 --- a/api/routes/thumbnails.ts +++ b/api/routes/thumbnails.ts @@ -31,8 +31,8 @@ import { authenticateMedia } from "../lib/auth.ts"; const router: Router = new Router({ prefix: "/api/thumbnails" }); /** - * Holds whether ffmpeg runs, probed once per process: probing on every uncached - * thumbnail request cost a process per card. + * Spares a process per uncached thumbnail request: whether ffmpeg runs is + * probed once per process, and kept here. */ let ffmpegProbe: Promise | undefined; @@ -146,8 +146,8 @@ function imagePreview(srcPath: string, outPath: string): Promise { } /** - * Holds the generations under way, by output path. A feed full of cards asking - * for the same new still at once then waits on a single ffmpeg run. + * Lets a feed full of cards asking for the same new still at once wait on a + * single ffmpeg run. It holds the generations under way, by output path. */ const inFlight = new Map>(); diff --git a/api/services/attachment-service.ts b/api/services/attachment-service.ts index 878f9e30..415b9348 100644 --- a/api/services/attachment-service.ts +++ b/api/services/attachment-service.ts @@ -1,7 +1,8 @@ /** - * Records the images pasted into Markdown bodies, and binds each one to the - * resource whose body links it. `routes/attachments.ts` stores and serves the - * files; the services that save a body call {@link linkAttachments}. + * Ties each image pasted into a Markdown body to the dump, comment, playlist or + * message that links it, so the image is served only to those who may see that, + * and purged at startup once it is gone. `routes/attachments.ts` stores and + * serves the files; the services that save a body call {@link linkAttachments}. * * @module */ diff --git a/api/services/rich-content-service.ts b/api/services/rich-content-service.ts index f882e241..d800834d 100644 --- a/api/services/rich-content-service.ts +++ b/api/services/rich-content-service.ts @@ -52,9 +52,9 @@ const RECENT_TTL_MS = 5 * 60 * 1000; /** How many previews are kept. The oldest written goes first. */ const RECENT_MAX = 200; /** - * Holds the previews fetched in the last few minutes, by URL. The create form - * previews a link and then posts it, and without this the second fetch of the - * page was the slow part of posting. Only successes are kept. + * Makes posting a link fast after the create form previewed it, by keeping the + * previews fetched in the last few minutes, by URL. Without it, the second + * fetch of the page was the slow part of posting. Only successes are kept. */ const recent = new Map< string, diff --git a/shared/api.ts b/shared/api.ts index 1c44ddac..f738a249 100644 --- a/shared/api.ts +++ b/shared/api.ts @@ -1,7 +1,8 @@ /** - * Defines the envelope every JSON endpoint answers with, and {@link Wire}, the - * form a type takes once it has crossed JSON. The routes build the envelope, - * and the frontend's API helpers unwrap it. + * Lets the client tell success from failure the same way for every JSON + * endpoint, through the envelope they all answer with. It also defines {@link + * Wire}, the form a type takes once it has crossed JSON. The routes build the + * envelope, and the frontend's API helpers unwrap it. * * @module */ diff --git a/shared/category.ts b/shared/category.ts index 19590e74..4230e34b 100644 --- a/shared/category.ts +++ b/shared/category.ts @@ -1,7 +1,8 @@ /** - * Declares the categories that dumps are filed under, and the bodies that - * create and change them. Only admins manage categories, through the API, since - * no page does it. The client lists them in its `CategoriesProvider`. + * Categories file dumps by topic, and give each topic its own feed on the + * index. This module types them for the server and the client, with the bodies + * that create and change them. Only admins manage categories, through the API, + * since no page does it. The client lists them in its `CategoriesProvider`. * * @module */ diff --git a/shared/chat.ts b/shared/chat.ts index 08db5a6d..9c0dc19d 100644 --- a/shared/chat.ts +++ b/shared/chat.ts @@ -1,6 +1,6 @@ /** - * Defines a message of the site-wide chat, as the server sends it to the - * chatbox. + * The site-wide chat lets signed-in users talk live. This module types one of + * its messages, as the server sends it to the chatbox. * * @module */ diff --git a/shared/comment.ts b/shared/comment.ts index fc4232b8..c40f300b 100644 --- a/shared/comment.ts +++ b/shared/comment.ts @@ -1,6 +1,7 @@ /** - * Declares the comments posted under a dump, and the bodies that post and edit - * them. The dump page's `CommentThread` renders them as a tree, by `parentId`. + * Comments let users discuss a dump under it, in threads. This module types + * them, with the bodies that post and edit them. The dump page's + * `CommentThread` renders them as a tree, by `parentId`. * * @module */ diff --git a/shared/dump.ts b/shared/dump.ts index 5e442c76..ac1493f5 100644 --- a/shared/dump.ts +++ b/shared/dump.ts @@ -1,8 +1,8 @@ /** - * Defines the dump, the link or file a user posts, as the API sends it, with - * its link preview and the bodies that create and edit it. The backend's - * `dump-service.ts` produces these types and the frontend's dump pages and - * create form consume them. + * A dump is what users post: a link or a file, with a title and a note. This + * module types it as the API sends it, with its link preview and the bodies + * that create and edit it. The backend's `dump-service.ts` produces these types + * and the frontend's dump pages and create form consume them. * * @module */ diff --git a/shared/follow.ts b/shared/follow.ts index 32062569..af6b0e0c 100644 --- a/shared/follow.ts +++ b/shared/follow.ts @@ -1,6 +1,7 @@ /** - * Types what the signed-in user follows, as the client's `FollowProvider` - * loads it to show follow buttons pressed. + * Following a user or a playlist puts their dumps in the index's "followed" + * tab. This module types what the signed-in user follows, as the client's + * `FollowProvider` loads it to show the Follow buttons pressed. * * @module */ diff --git a/shared/mention.ts b/shared/mention.ts index a0dee2f2..b8152197 100644 --- a/shared/mention.ts +++ b/shared/mention.ts @@ -1,6 +1,6 @@ /** - * Defines what counts as an @mention, so that the server notifies the same - * users the chat highlights and the editor suggests. + * Makes the server notify the same users the chat highlights and the editor + * suggests, by defining once what counts as an @mention. * * @module */ diff --git a/shared/notification.ts b/shared/notification.ts index 21ef3f27..1ba38dd0 100644 --- a/shared/notification.ts +++ b/shared/notification.ts @@ -1,7 +1,9 @@ /** - * Types the notifications `api/services/notification-service.ts` makes, and - * the data each kind carries. The client's `/notifications` page lists them - * and turns each into a sentence and a link. + * Notifications tell a user when someone follows them or their playlists, + * upvotes, comments, likes or mentions them, or posts where they follow. This + * module types the ones `api/services/notification-service.ts` makes, and the + * data each kind carries. The client's `/notifications` page lists them and + * turns each into a sentence and a link. * * @module */ diff --git a/shared/permissions.ts b/shared/permissions.ts index adf9197b..1fb6eec5 100644 --- a/shared/permissions.ts +++ b/shared/permissions.ts @@ -1,7 +1,8 @@ /** - * Maps each role to what it may do. The server enforces the table - * (`api/lib/permissions.ts`, `api/routes/ws.ts`) and the client reads the same - * one to hide what a role can't do (`src/utils/auth/permissions.ts`). + * Keeps the server and the client agreed on what each role may do. The server + * enforces this table (`api/lib/permissions.ts`, `api/routes/ws.ts`) and the + * client reads the same one to hide what a role can't do + * (`src/utils/auth/permissions.ts`). * * @module */ diff --git a/shared/player.ts b/shared/player.ts index 64da7f43..1a6b6df5 100644 --- a/shared/player.ts +++ b/shared/player.ts @@ -1,6 +1,7 @@ /** - * Defines what the Bandcamp and YouTube routes return to the frontend's - * player when it plays a Bandcamp release or a YouTube playlist. + * Lets the global player play a Bandcamp release with its own controls and list + * a YouTube playlist's tracks. This module types what the Bandcamp and YouTube + * routes return to it. * * @module */ diff --git a/shared/playlist.ts b/shared/playlist.ts index 39e42ce5..94996c67 100644 --- a/shared/playlist.ts +++ b/shared/playlist.ts @@ -1,7 +1,7 @@ /** - * Declares playlists, the ordered collections of dumps their owners curate, and - * the bodies that create, edit and reorder them. The client shows them on - * `/playlists/:playlistId`, on profiles and in search results. + * Playlists are ordered collections of dumps their owners curate. This module + * types them, with the bodies that create, edit and reorder them. The client + * shows them on `/playlists/:playlistId`, on profiles and in search results. * * @module */ diff --git a/shared/search.ts b/shared/search.ts index dfbcdf8a..e964c7b9 100644 --- a/shared/search.ts +++ b/shared/search.ts @@ -1,6 +1,6 @@ /** - * Declares the results of the site search, which the `Search` page shows under - * one tab per kind. + * The site search finds dumps, users and playlists at once. This module types + * its results, which the `Search` page shows under one tab per kind. * * @module */ diff --git a/shared/user.ts b/shared/user.ts index 8531106f..f671cae5 100644 --- a/shared/user.ts +++ b/shared/user.ts @@ -1,7 +1,8 @@ /** - * Types users as the API sends them, their roles, and the bodies and answers - * of the `/api/users` and `/api/invites` endpoints, for the server and the - * client alike. + * A user crosses the wire in several shapes: as anyone sees them, as they see + * themselves, and in the bodies and answers of the `/api/users` and + * `/api/invites` endpoints. This module types them all, with the roles, for the + * server and the client alike. * * @module */ diff --git a/shared/validation.ts b/shared/validation.ts index 2f61062d..a89494a4 100644 --- a/shared/validation.ts +++ b/shared/validation.ts @@ -1,6 +1,6 @@ /** - * Holds the limits on what users submit, shared so that the forms check the - * same limits the server enforces. + * Makes the forms check the same limits on what users submit as the server + * enforces, by holding them in one place. * * @module */ diff --git a/shared/ws.ts b/shared/ws.ts index d55122e3..ed18c66c 100644 --- a/shared/ws.ts +++ b/shared/ws.ts @@ -1,6 +1,7 @@ /** - * Defines the messages of the WebSocket between `WSProvider` in the client and - * `routes/ws.ts` in the server, as JSON objects told apart by `type`. + * Live updates, votes, likes and the chat travel over one WebSocket between + * `WSProvider` in the client and `routes/ws.ts` in the server. This module + * types its messages, JSON objects told apart by `type`. * * The server's messages go out from `services/ws-service.ts`, and `WSProvider` * handles them. Their Dates arrive as strings, so the client reads them as diff --git a/src/components/dump/create/DumpCreateModal.tsx b/src/components/dump/create/DumpCreateModal.tsx index 515b23fb..022aa7cd 100644 --- a/src/components/dump/create/DumpCreateModal.tsx +++ b/src/components/dump/create/DumpCreateModal.tsx @@ -1,6 +1,6 @@ /** - * The modal that posts a dump from a link or a file, then offers to add it to - * the poster's playlists. Every "new dump" button opens it. + * Renders the modal that posts a dump from a link or a file, then offers to add + * it to the poster's playlists. Every "new dump" button opens it. * * @module */ diff --git a/src/components/dump/create/StepIndicator.tsx b/src/components/dump/create/StepIndicator.tsx index cdfa5784..f7a3ab4b 100644 --- a/src/components/dump/create/StepIndicator.tsx +++ b/src/components/dump/create/StepIndicator.tsx @@ -1,6 +1,6 @@ /** - * The panels of the dump creation modal, and the indicator showing which one - * is open. + * Shows which panel of the dump creation modal is open, and declares the panels + * in the order they are walked. * * @module */ diff --git a/src/components/dump/create/TitleField.tsx b/src/components/dump/create/TitleField.tsx index cc068a62..59936f3a 100644 --- a/src/components/dump/create/TitleField.tsx +++ b/src/components/dump/create/TitleField.tsx @@ -1,6 +1,6 @@ /** - * The title field of the dump creation modal, read-only until the poster - * chooses to edit it. + * Renders the title field of the dump creation modal, read-only until the + * poster chooses to edit it. * * @module */ diff --git a/src/components/feed/FeedTabBar.tsx b/src/components/feed/FeedTabBar.tsx index 957891fd..031bf640 100644 --- a/src/components/feed/FeedTabBar.tsx +++ b/src/components/feed/FeedTabBar.tsx @@ -1,5 +1,6 @@ /** - * The tab bar of the index page, with the category switcher before the tabs. + * Renders the tab bar of the index page, with the category switcher before the + * tabs. * * @module */ diff --git a/src/components/shared/TabBar.tsx b/src/components/shared/TabBar.tsx index 2c6a24a2..a27073e7 100644 --- a/src/components/shared/TabBar.tsx +++ b/src/components/shared/TabBar.tsx @@ -1,5 +1,5 @@ /** - * A row of tabs. + * Renders the row of tabs of the index, profile and search pages. * * @module */ diff --git a/src/config/playerMode.ts b/src/config/playerMode.ts index f6bc6152..dab428e0 100644 --- a/src/config/playerMode.ts +++ b/src/config/playerMode.ts @@ -1,5 +1,6 @@ /** - * Reads which Bandcamp player this deployment uses, for `usePlayRichContent`. + * Lets a deployment choose between Bandcamp's embed and the site's own player. + * It reads the choice for `usePlayRichContent`. * * The server writes `GERBEUR_BANDCAMP_PLAYER` into index.html's * `bandcamp-player` `` tag (`api/lib/index-html.ts`, and the Vite config diff --git a/src/contexts/auth/AuthContext.ts b/src/contexts/auth/AuthContext.ts index 3f0c8006..2cce7775 100644 --- a/src/contexts/auth/AuthContext.ts +++ b/src/contexts/auth/AuthContext.ts @@ -1,6 +1,6 @@ /** - * Declares the session's React context. `AuthProvider` fills it and `useAuth` - * reads it; nothing else should touch it. + * Shares the session with every component. `AuthProvider` fills this context + * and `useAuth` reads it; nothing else should touch it. * * @module */ diff --git a/src/contexts/auth/AuthProvider.tsx b/src/contexts/auth/AuthProvider.tsx index 250b1ffb..0e28d9c0 100644 --- a/src/contexts/auth/AuthProvider.tsx +++ b/src/contexts/auth/AuthProvider.tsx @@ -1,5 +1,5 @@ /** - * Holds the session for the whole app and keeps it in step with the other tabs + * Keeps the user signed in across the whole app, in step with the other tabs * and with the server. `App` mounts it near the root. * * @module diff --git a/src/contexts/category/CategoriesContext.ts b/src/contexts/category/CategoriesContext.ts index bd27889f..d6bce39c 100644 --- a/src/contexts/category/CategoriesContext.ts +++ b/src/contexts/category/CategoriesContext.ts @@ -1,6 +1,6 @@ /** - * Declares the categories' React context. `CategoriesProvider` fills it and - * `useCategories` reads it. + * Shares the site's categories with every component. `CategoriesProvider` fills + * this context and `useCategories` reads it. * * @module */ diff --git a/src/contexts/category/CategoriesProvider.tsx b/src/contexts/category/CategoriesProvider.tsx index 3bd97d4b..f6e0502a 100644 --- a/src/contexts/category/CategoriesProvider.tsx +++ b/src/contexts/category/CategoriesProvider.tsx @@ -1,6 +1,6 @@ /** - * Loads the site's categories once for the whole app, and again when the - * category manager changes them. `App` mounts it. + * Spares every page fetching the site's categories: it loads them once for the + * whole app, and again when the category manager changes them. `App` mounts it. * * @module */ diff --git a/src/contexts/chat/ChatContext.ts b/src/contexts/chat/ChatContext.ts index 039ea488..e3f3be05 100644 --- a/src/contexts/chat/ChatContext.ts +++ b/src/contexts/chat/ChatContext.ts @@ -1,7 +1,6 @@ /** - * Declares the context through which the header's chat button and the floating - * chat button open the one chat modal, which `ChatProvider` owns. Read it with - * `useChat`. + * Lets the header's chat button and the floating one open the same chat modal, + * which `ChatProvider` owns. Read it with `useChat`. * * @module */ diff --git a/src/contexts/chat/ChatProvider.tsx b/src/contexts/chat/ChatProvider.tsx index fabc69d5..70e4a2b1 100644 --- a/src/contexts/chat/ChatProvider.tsx +++ b/src/contexts/chat/ChatProvider.tsx @@ -1,6 +1,7 @@ /** - * Provides `ChatContext` and renders the chat modal while it is open. `App` - * mounts it inside the router, around every page. + * Owns the one chat modal: it renders it while it is open, and provides + * `ChatContext` to the buttons that open it. `App` mounts it inside the router, + * around every page. * * @module */ diff --git a/src/contexts/player/PlayerContext.ts b/src/contexts/player/PlayerContext.ts index 68ca8e60..35f3fa38 100644 --- a/src/contexts/player/PlayerContext.ts +++ b/src/contexts/player/PlayerContext.ts @@ -1,8 +1,9 @@ /** - * Defines the player's two contexts, one for the queue and the controls and one - * for the playhead alone. PlayerProvider provides both around the whole app; - * GlobalPlayer draws the player, and the cards and previews that start playback - * read and drive it. + * Shares the player docked at the bottom of every page with the whole app. The + * cards and previews that start playback read and drive it, and GlobalPlayer + * draws it. It is two contexts, one for the queue and the controls and one for + * the playhead alone, which changes several times a second. PlayerProvider + * provides both around the whole app. * * @module */ diff --git a/src/contexts/player/PlayerProvider.tsx b/src/contexts/player/PlayerProvider.tsx index 35d72142..6b9986dc 100644 --- a/src/contexts/player/PlayerProvider.tsx +++ b/src/contexts/player/PlayerProvider.tsx @@ -1,7 +1,8 @@ /** - * Holds the player's queue, playback state and controls, saves them across - * reloads and keeps streams' signed URLs fresh. App mounts it around the whole - * app, and GlobalPlayer draws what it holds. + * Keeps playback going from page to page and across reloads. It holds the + * player's queue, playback state and controls, saves them as they change and + * keeps streams' signed URLs fresh. App mounts it around the whole app, and + * GlobalPlayer draws what it holds. * * @module */ diff --git a/src/contexts/social/FollowContext.ts b/src/contexts/social/FollowContext.ts index dc171cee..5a42c995 100644 --- a/src/contexts/social/FollowContext.ts +++ b/src/contexts/social/FollowContext.ts @@ -1,7 +1,6 @@ /** - * Declares the context that holds the users and playlists the signed-in user - * follows, for the Follow buttons. `FollowProvider` provides it and - * `useFollows` reads it. + * Tells the Follow buttons what the signed-in user follows. `FollowProvider` + * provides this context and `useFollows` reads it. * * @module */ @@ -42,7 +41,10 @@ export const defaultFollowValue: FollowContextValue = { isLoaded: false, }; -/** Holds the signed-in user's follows. Read it with `useFollows`. */ +/** + * Tells the Follow buttons what the signed-in user follows. Read it with + * `useFollows`. + */ export const FollowContext: React.Context = createContext< FollowContextValue >( diff --git a/src/contexts/social/FollowProvider.tsx b/src/contexts/social/FollowProvider.tsx index 14700b81..f34b6d58 100644 --- a/src/contexts/social/FollowProvider.tsx +++ b/src/contexts/social/FollowProvider.tsx @@ -1,6 +1,7 @@ /** - * Provides `FollowContext`, from `GET /api/follows/status`. `App` mounts it - * around every page. + * Keeps what the signed-in user follows for the Follow buttons, loaded from + * `GET /api/follows/status` and again when another tab changes it. `App` mounts + * it around every page. * * @module */ diff --git a/src/contexts/theme/ThemeContext.ts b/src/contexts/theme/ThemeContext.ts index dcf94126..7e75f8de 100644 --- a/src/contexts/theme/ThemeContext.ts +++ b/src/contexts/theme/ThemeContext.ts @@ -1,6 +1,6 @@ /** - * Declares the theme's React context. `ThemeProvider` fills it and `useTheme` - * reads it. + * Shares the chosen theme with every component. `ThemeProvider` fills this + * context and `useTheme` reads it. * * @module */ diff --git a/src/contexts/theme/ThemeProvider.tsx b/src/contexts/theme/ThemeProvider.tsx index 9d933a36..b14cd56f 100644 --- a/src/contexts/theme/ThemeProvider.tsx +++ b/src/contexts/theme/ThemeProvider.tsx @@ -1,6 +1,7 @@ /** - * Holds the chosen style and color scheme, stores them in localStorage and - * applies them to the document. `App` mounts it outermost. + * Lets each browser pick the site's style and color scheme. It holds the + * choice, stores it in localStorage and applies it to the document. `App` + * mounts it outermost. * * @module */ diff --git a/src/contexts/ws/AvatarOverrideContext.ts b/src/contexts/ws/AvatarOverrideContext.ts index d6a42817..6c053f77 100644 --- a/src/contexts/ws/AvatarOverrideContext.ts +++ b/src/contexts/ws/AvatarOverrideContext.ts @@ -1,6 +1,7 @@ /** - * Declares the context through which `Avatar` learns of avatars changed since - * the page loaded. `WSProvider` fills it from `user_updated` messages. + * Shows a user's new avatar everywhere as soon as they change it, without a + * reload. `WSProvider` fills this context from `user_updated` messages, and + * `Avatar` reads it. * * @module */ @@ -21,8 +22,9 @@ export interface AvatarOverride { } /** - * Holds an {@link AvatarOverride} by user id. It is apart from `WSContext`, so - * the many avatars of a page don't re-render on every vote or comment. + * Shows changed avatars without a reload, as an {@link AvatarOverride} by user + * id. It is apart from `WSContext`, so the many avatars of a page don't + * re-render on every vote or comment. */ export const AvatarOverrideContext: React.Context< Record diff --git a/src/contexts/ws/WSContext.ts b/src/contexts/ws/WSContext.ts index e0f2d348..15bab4cd 100644 --- a/src/contexts/ws/WSContext.ts +++ b/src/contexts/ws/WSContext.ts @@ -1,7 +1,10 @@ /** - * Declares the three contexts `WSProvider` fills from the WebSocket, and the - * types they carry. They are split by how often each part changes, so that a - * feed doesn't re-render with every chat message or presence change. + * Live updates from the server reach the pages through the three contexts + * declared here: votes and likes, dumps, playlists, comments, profiles and + * notifications in one, the chat in another, who is online in the third. They + * are split so that a feed doesn't re-render with every chat message or + * presence change. `WSProvider` fills them from its WebSocket, and components + * read them with `useWS`, `useWSChat` and `useWSPresence`. * * @module */ @@ -16,8 +19,9 @@ import type { Playlist } from "../../../shared/playlist.ts"; import type { PublicUser } from "../../../shared/user.ts"; /** - * Set as `lastVoteEvent` by `WSProvider` on a `votes_update`. The profile - * pages read it to add or drop a dump from a user's upvoted list. + * Keeps a user's upvoted list live, on their profile and on `UserUpvoted`. + * `WSProvider` sets it as `lastVoteEvent` on each `votes_update`, and + * `useUpvotedList` adds or drops the dump. */ export interface VoteEvent { dumpId: string; @@ -26,9 +30,11 @@ export interface VoteEvent { } /** - * Set as `lastPlaylistEvent` by `WSProvider` on each `playlist_*` message. - * The pages that show playlists apply it, some through `usePlaylistListSync`. - * Which fields are set depends on `type`. + * Keeps the playlists on screen up to date, in lists, on a playlist's page and + * on a dump's page. `WSProvider` sets it as `lastPlaylistEvent` on each + * `playlist_*` message; lists apply it through `usePlaylistListSync`, a + * playlist's page through `usePlaylist`. Which fields are set depends on + * `type`. */ export interface PlaylistEvent { type: "created" | "updated" | "deleted" | "dumps_updated"; @@ -47,9 +53,9 @@ export interface PlaylistEvent { } /** - * Set as `lastCommentEvent` by `WSProvider` on each `comment_*` message. The - * `Dump` page applies it to its thread, and `useDumpListSync` to its comment - * counts. + * Keeps comment threads and comment counts live. `WSProvider` sets it as + * `lastCommentEvent` on each `comment_*` message; the `Dump` page applies it + * to its thread, and `useDumpListSync` to the counts on dump cards. */ export interface CommentEvent { type: "created" | "deleted" | "updated"; @@ -61,16 +67,18 @@ export interface CommentEvent { } /** - * Set as `lastUserEvent` by `WSProvider` on a `user_updated`, which the - * server sends on any change to a profile. `useProfile` applies it. + * Keeps a profile page live while its user edits their profile. `WSProvider` + * sets it as `lastUserEvent` on each `user_updated`, which the server sends on + * any change to a profile, and `useProfile` applies it. */ export interface UserEvent { user: PublicUser; } /** - * Chosen in `ChatModal` for the reply bar, and kept on the pending message so - * it shows the reply before the server's echo. Only `id` goes to the server. + * Quotes the message a chat message replies to. `ChatModal` shows it in the + * reply bar once the user picks it, and it stays on the pending message so + * the quote shows before the server's echo. Only `id` goes to the server. */ export interface ChatReplyTarget { id: string; @@ -79,9 +87,9 @@ export interface ChatReplyTarget { } /** - * Held by `WSProvider` for a chat message this client sent and the server - * hasn't echoed back yet. `ChatModal` shows it, as `PendingItem`, after the - * messages the server has. + * Shows a chat message the moment the user sends it, and lets them retry it if + * it fails. `WSProvider` holds it until the server echoes the message back, and + * `ChatModal` shows it, as `PendingItem`, after the messages the server has. */ export interface PendingChatMessage { /** @@ -102,8 +110,8 @@ export interface PendingChatMessage { } /** - * Set as `chatError` by `WSProvider` when the server refuses a chat edit or - * delete. `ChatModal` shows it for a few seconds. + * Tells the user the server refused their chat edit or delete. `WSProvider` + * sets it as `chatError`, and `ChatModal` shows it for a few seconds. */ export interface ChatError { /** Tells apart two errors with the same message. */ @@ -112,60 +120,75 @@ export interface ChatError { } /** - * Provided by `WSProvider` through {@link WSContext}, read with `useWS`. The - * `last*Event` fields hold only the latest event of their kind: a consumer - * reacts in an effect when one changes, and an event that another replaces - * within the same render is missed. After a reconnect, `connectionEpoch` tells - * pages to fetch what they missed. + * Carries everything live but the chat and presence, for pages to lay over + * what they fetched. `WSProvider` provides it through {@link WSContext}, and + * components read it with `useWS`. Each `last*Event` field holds only the + * latest event of its kind: a consumer reacts in an effect when one changes, + * and an event that another replaces within the same render is missed. After a + * reconnect, `connectionEpoch` tells pages to fetch what they missed. */ export interface WSContextValue { wsStatus: "connecting" | "connected" | "disconnected"; /** Set while the socket is down, for the banner that says so. */ wsErrorMessage: string | null; /** - * Counts known to the socket, by dump id: pushed by the server, or changed - * optimistically. A missing dump shows its fetched `voteCount`. + * Shows vote counts live. It holds, by dump id, the counts the server pushed + * or this tab changed optimistically; a dump missing from it shows its + * fetched `voteCount`. */ voteCounts: Record; - /** Reset from the server's `welcome` on every connection. */ + /** + * Marks the dumps this user upvoted, for their vote buttons. The server's + * `welcome` resets it on every connection. + */ myVotes: Set; /** As `voteCounts`, for comments. */ likeCounts: Record; /** As `myVotes`, for comments. */ myLikes: Set; /** - * Dumps that arrived this session, newest first and at most 100: the ones - * the server announced, which are public, and the ones this user posted, - * which may be private. `Index` puts them above the feed it fetched. + * Shows new dumps on the index as they are posted, above the feed `Index` + * fetched. It holds, newest first and at most 100, the ones the server + * announced this session, which are public, and the ones this user posted, + * which may be private. */ recentDumps: Dump[]; /** - * It holds the dumps deleted this session, or made private by someone else, - * for the lists to filter out. A dump made public again leaves it. + * Takes deleted dumps off every list at once. It holds the dumps deleted this + * session, or made private by someone else; a dump made public again leaves + * it. */ deletedDumpIds: Set; lastVoteEvent: VoteEvent | null; /** - * It holds the dump as its latest `dump_created` or `dump_updated` has it, - * for the lists to update it in place, or put it back where it was. + * Keeps a dump up to date in every list that shows it. It holds the dump as + * its latest `dump_created` or `dump_updated` has it, and a list updates it + * in place, or puts it back where it was. */ lastDumpEvent: Dump | null; lastPlaylistEvent: PlaylistEvent | null; deletedPlaylistIds: Set; lastCommentEvent: CommentEvent | null; lastUserEvent: UserEvent | null; - /** Read from the `welcome`, then counted up by each new notification. */ + /** + * Drives the bell's badge. It comes from the `welcome`, then each new + * notification counts it up. + */ unreadNotificationCount: number; - /** Read by the bell, which rings, and by the notifications page. */ + /** + * Makes the bell ring, and puts the notification on the notifications page + * as it arrives. + */ lastNotification: Notification | null; /** - * Incremented on each reconnect, never on the first connection, so pages - * fetch again what they missed while the socket was down. + * Tells pages to fetch again what they missed while the socket was down. It + * goes up on each reconnect, never on the first connection. */ connectionEpoch: number; /** - * Incremented when the user follows or unfollows something in another tab - * (or this one), so `FollowProvider` fetches the follow status again. + * Keeps the Follow buttons right when the user follows or unfollows in + * another tab. It goes up on every follow change, in any tab, and + * `FollowProvider` fetches the follow status again. */ followsVersion: number; /** @@ -182,8 +205,9 @@ export interface WSContextValue { /** Withdraws a like, as {@link WSContextValue.castVote} casts a vote. */ removeCommentLike: (commentId: string, shownCount?: number) => void; /** - * Adds a dump this user just posted to `recentDumps`, without waiting for - * its broadcast, which a private dump never gets. `DumpCreateModal` calls it. + * Shows a dump this user just posted on the index without waiting for its + * broadcast, which a private dump never gets. `DumpCreateModal` calls it, + * and it adds the dump to `recentDumps`. */ injectDump: (dump: Dump) => void; /** @@ -194,36 +218,43 @@ export interface WSContextValue { } /** - * Provided by `WSProvider` through {@link WSChatContext}, read with - * `useWSChat`. The socket sends chat messages only to signed-in users, so for - * a visitor it stays empty. + * Carries the chat's live side, which `ChatModal` lays over the history it + * fetches and the chat buttons show as a badge. `WSProvider` provides it + * through {@link WSChatContext}, and components read it with `useWSChat`. The + * socket sends chat only to signed-in users, so for a visitor it stays empty. */ export interface WSChatContextValue { /** - * The messages received this session, at most 200, for `ChatModal` to merge - * with the history it fetches. A reconnect empties it while the chat is - * closed, since `ChatModal` fetches everything again on open. + * Shows chat messages as they arrive. It holds the ones received this + * session, at most 200, which `ChatModal` merges with the history it + * fetches. A reconnect empties it while the chat is closed, since `ChatModal` + * fetches everything again on open. */ chatMessages: ChatMessage[]; /** - * Messages deleted this session, which `ChatModal` filters out of its - * fetched history. + * Takes the messages deleted this session out of the history `ChatModal` + * fetched. */ deletedChatIds: Set; /** - * Messages from others after the read marker. The server keeps the marker, - * so the count agrees across tabs and devices. + * Drives the chat buttons' unread badge. It counts the messages from others + * after the read marker, which the server keeps, so the count agrees across + * tabs and devices. */ unreadChatCount: number; /** - * The time of the newest message the user has seen, which the server keeps. - * Null until the `welcome`, and for a visitor. + * Places the "new" divider when the chat opens. It holds the time of the + * newest message the user has seen, which the server keeps, and is null + * until the `welcome`, and for a visitor. */ chatReadAt: Date | null; pendingChatMessages: PendingChatMessage[]; /** Only for edits and deletes. A failed send shows on its pending message. */ chatError: ChatError | null; - /** Includes the user when they are typing: `ChatModal` filters them out. */ + /** + * Shows who is typing. It includes the user themselves, whom `ChatModal` + * filters out. + */ typingUsers: OnlineUser[]; /** Trims `body` and sends it as a pending message. Ignores a blank body. */ sendChatMessage: (body: string, replyTo?: ChatReplyTarget) => void; @@ -244,10 +275,10 @@ export interface WSChatContextValue { */ markChatRead: (at: Date) => void; /** - * Replaces the live buffer's messages between `from` and `to` with - * `messages`, which `ChatModal` fetched after a reconnect. A message missing - * from them was deleted while the socket was down. A failed send found among - * them did reach the server, and leaves the pending list. + * Repairs the live buffer after a reconnect. It replaces its messages between + * `from` and `to` with `messages`, which `ChatModal` fetched. A message + * missing from them was deleted while the socket was down. A failed send + * found among them did reach the server, and leaves the pending list. */ reconcileChat: (messages: ChatMessage[], from: Date, to: Date) => void; /** @@ -257,23 +288,27 @@ export interface WSChatContextValue { */ setChatTyping: (typing: boolean) => void; /** - * Tells the server whether the user is reading the chat: open, in a visible - * tab. The server sends no notification for a mention the user reads live, - * and this client doesn't count the message unread. + * Spares the user a notification for a mention they read live. It tells the + * server whether the chat is open in a visible tab; while it is, the server + * sends no notification for a mention, and this client doesn't count the + * message unread. */ setChatOpen: (open: boolean) => void; } /** - * Provided by `WSProvider` through {@link WSPresenceContext}, read with - * `useWSPresence`. + * Carries who is online, for `PresenceRow`. `WSProvider` provides it through + * {@link WSPresenceContext}, and components read it with `useWSPresence`. */ export interface WSPresenceContextValue { /** The signed-in users with a socket open, each once. */ onlineUsers: OnlineUser[]; } -/** Given to a consumer outside `WSProvider`, as if it were still connecting. */ +/** + * Lets a component render outside `WSProvider`, as if the socket were + * connecting. + */ export const defaultWSValue: WSContextValue = { wsStatus: "connecting", wsErrorMessage: null, @@ -301,7 +336,7 @@ export const defaultWSValue: WSContextValue = { clearUnreadNotifications: () => {}, }; -/** Given to a consumer outside `WSProvider`: an empty chat. */ +/** Lets a component render outside `WSProvider`, with an empty chat. */ export const defaultWSChatValue: WSChatContextValue = { chatMessages: [], deletedChatIds: new Set(), @@ -322,25 +357,25 @@ export const defaultWSChatValue: WSChatContextValue = { setChatOpen: () => {}, }; -/** Given to a consumer outside `WSProvider`: nobody is online. */ +/** Lets a component render outside `WSProvider`, with nobody online. */ export const defaultWSPresenceValue: WSPresenceContextValue = { onlineUsers: [], }; /** - * Holds the connection, the votes and likes, and the latest live event of - * each kind. Read it with `useWS`. + * Carries the live state pages lay over what they fetched: the connection, the + * votes and likes, and the latest event of each kind. Read it with `useWS`. */ export const WSContext: React.Context = createContext< WSContextValue >(defaultWSValue); -/** Holds the chat's live stream and read state. Read it with `useWSChat`. */ +/** Carries the chat's live stream and read state. Read it with `useWSChat`. */ export const WSChatContext: React.Context = createContext< WSChatContextValue >( defaultWSChatValue, ); -/** Holds who is online. Read it with `useWSPresence`. */ +/** Carries who is online. Read it with `useWSPresence`. */ export const WSPresenceContext: React.Context = createContext< WSPresenceContextValue diff --git a/src/contexts/ws/WSProvider.tsx b/src/contexts/ws/WSProvider.tsx index 3ba2a397..4e93964b 100644 --- a/src/contexts/ws/WSProvider.tsx +++ b/src/contexts/ws/WSProvider.tsx @@ -1,8 +1,9 @@ /** - * Holds the app's one WebSocket to `/ws` and turns its messages into the state - * of `WSContext`, `WSChatContext`, `WSPresenceContext` and - * `AvatarOverrideContext`. `App` mounts it around every page. The protocol is - * `shared/ws.ts`, and the server's side is `api/routes/ws.ts`. + * Brings the server's live updates into the app. It holds the one WebSocket to + * `/ws` and turns its messages into the state of `WSContext`, `WSChatContext`, + * `WSPresenceContext` and `AvatarOverrideContext`. `App` mounts it around every + * page. The protocol is `shared/ws.ts`, and the server's side is + * `api/routes/ws.ts`. * * @module */ @@ -94,9 +95,9 @@ const CHAT_READ_THROTTLE = 1_000; const CHAT_ECHO_WINDOW = 60_000; /** - * Held by {@link useOptimisticToggles} for an item whose toggles the server - * hasn't all acknowledged yet. `count` and `on` are as before the first of - * them, for a failure to restore. + * Lets a failed toggle restore what was shown before the first click the server + * hasn't acknowledged. {@link useOptimisticToggles} holds one for each such + * item; `count` and `on` are as they were before that click. */ interface PendingToggle { timeout: ReturnType; diff --git a/src/hooks/chat/useChat.ts b/src/hooks/chat/useChat.ts index ef904c1d..0639fd38 100644 --- a/src/hooks/chat/useChat.ts +++ b/src/hooks/chat/useChat.ts @@ -1,5 +1,5 @@ /** - * Reads `ChatContext`, for the buttons that open the chat. + * Lets a button open the chat, by reading `ChatContext`. * * @module */ diff --git a/src/hooks/dump/useUserDumpFeed.ts b/src/hooks/dump/useUserDumpFeed.ts index 460543fe..f5b58e08 100644 --- a/src/hooks/dump/useUserDumpFeed.ts +++ b/src/hooks/dump/useUserDumpFeed.ts @@ -1,6 +1,6 @@ /** - * Loads a user's dumps or upvoted dumps, a page at a time, for the profile - * subpages that list them in full. + * Feeds the profile subpages that list all of a user's dumps, or all they + * upvoted, loading them a page at a time. * * @module */ diff --git a/src/hooks/editor/useEmojiTrigger.ts b/src/hooks/editor/useEmojiTrigger.ts index 52a7f9c2..ff1fff5e 100644 --- a/src/hooks/editor/useEmojiTrigger.ts +++ b/src/hooks/editor/useEmojiTrigger.ts @@ -1,7 +1,7 @@ /** - * Keeps the state of `TextEditor`'s emoji picker, which opens on a typed - * `:query` or from the editor's button. `TextEditor` renders the picker and - * handles its keys. + * Lets a user insert an emoji by typing `:query` or from the editor's button. + * It keeps the state of `TextEditor`'s emoji picker, and `TextEditor` renders + * the picker and handles its keys. * * @module */ diff --git a/src/hooks/editor/useMentionAutocomplete.ts b/src/hooks/editor/useMentionAutocomplete.ts index a53ad453..f5c78b54 100644 --- a/src/hooks/editor/useMentionAutocomplete.ts +++ b/src/hooks/editor/useMentionAutocomplete.ts @@ -1,7 +1,7 @@ /** - * Keeps the state of `TextEditor`'s `@mention` suggestions, which it fetches - * from `GET /api/users/search`. `TextEditor` renders them in a - * `MentionDropdown`. + * Suggests users to @mention as the user types in `TextEditor`. It keeps the + * state of the suggestions, fetched from `GET /api/users/search`, and + * `TextEditor` renders them in a `MentionDropdown`. * * @module */ diff --git a/src/hooks/feed/useDefaultFeedTab.ts b/src/hooks/feed/useDefaultFeedTab.ts index 33cdddf6..f46d4956 100644 --- a/src/hooks/feed/useDefaultFeedTab.ts +++ b/src/hooks/feed/useDefaultFeedTab.ts @@ -1,5 +1,6 @@ /** - * Stores, in this browser, which feed tab the index opens on. + * Lets a user choose which feed tab the index opens on, remembered in this + * browser. * * @module */ diff --git a/src/hooks/feed/useFading.ts b/src/hooks/feed/useFading.ts index 4ff0955e..9fcbd975 100644 --- a/src/hooks/feed/useFading.ts +++ b/src/hooks/feed/useFading.ts @@ -1,6 +1,6 @@ /** - * Times the fade-out of items leaving a list, so that a removal made by - * mistake can be undone before the item is gone. + * Lets a removal made by mistake be undone before the item leaves the list, by + * timing the fade-out of items leaving a list. * * @module */ diff --git a/src/hooks/feed/useFeedCache.ts b/src/hooks/feed/useFeedCache.ts index 23bcb473..3fb3ce2e 100644 --- a/src/hooks/feed/useFeedCache.ts +++ b/src/hooks/feed/useFeedCache.ts @@ -1,6 +1,7 @@ /** - * Keeps a feed's loaded pages and scroll position in sessionStorage, so that - * going back to a feed page shows it as it was left instead of refetching it. + * Shows a feed as it was left when the user comes back to it, instead of + * fetching it again. It keeps the feed's loaded pages and scroll position in + * sessionStorage. * * @module */ diff --git a/src/hooks/feed/usePagedList.ts b/src/hooks/feed/usePagedList.ts index 1e0a4187..8d2692d5 100644 --- a/src/hooks/feed/usePagedList.ts +++ b/src/hooks/feed/usePagedList.ts @@ -1,7 +1,7 @@ /** - * Loads a list a page at a time. Every list the API pages goes through - * {@link useLoadMore} for its next pages, and a list that loads on its own - * through {@link usePagedList}, from its first page on. + * Gives every paged list of the app the same loading. Every list the API pages + * goes through {@link useLoadMore} for its next pages, and a list that loads on + * its own through {@link usePagedList}, from its first page on. * * @module */ diff --git a/src/hooks/form/useApiForm.ts b/src/hooks/form/useApiForm.ts index 47f736b5..81bd12d9 100644 --- a/src/hooks/form/useApiForm.ts +++ b/src/hooks/form/useApiForm.ts @@ -1,5 +1,7 @@ /** - * react-hook-form, with the shared lifecycle of a form that posts to the API. + * Gives every form that posts to the API the same submit, which shows a failed + * request as the form's root error. It is react-hook-form's `useForm` plus that + * `submit`. * * @module */ @@ -15,7 +17,7 @@ import { import { friendlyFetchError } from "../../utils/shared/api.ts"; -/** What {@link useApiForm} returns: the form, and `submit`. */ +/** Returned by {@link useApiForm}, the form with `submit` added. */ export interface UseApiFormResult extends UseFormReturn { /** diff --git a/src/hooks/playlist/usePlaylist.ts b/src/hooks/playlist/usePlaylist.ts index 01123b82..6c895084 100644 --- a/src/hooks/playlist/usePlaylist.ts +++ b/src/hooks/playlist/usePlaylist.ts @@ -1,6 +1,7 @@ /** - * Loads a playlist with its dumps for its page, keeps them live, and makes the - * changes its owner or a moderator makes there. + * Everything a playlist's page shows and changes goes through this hook. It + * loads the playlist with its dumps, keeps them live, and makes the changes its + * owner or a moderator makes there. * * @module */ diff --git a/src/hooks/playlist/usePlaylistMemberships.ts b/src/hooks/playlist/usePlaylistMemberships.ts index 716a2b8e..5135b95e 100644 --- a/src/hooks/playlist/usePlaylistMemberships.ts +++ b/src/hooks/playlist/usePlaylistMemberships.ts @@ -1,6 +1,7 @@ /** - * Loads which of the signed-in user's playlists hold a dump, and adds the dump - * to them or takes it out. + * Lets the user add a dump to their playlists or take it out, in + * `AddToPlaylistModal` and the dump form's last step. It loads which of their + * playlists hold the dump. * * @module */ diff --git a/src/hooks/profile/useProfile.ts b/src/hooks/profile/useProfile.ts index b9cbe84c..fafede14 100644 --- a/src/hooks/profile/useProfile.ts +++ b/src/hooks/profile/useProfile.ts @@ -1,6 +1,7 @@ /** - * Loads a profile's user with the first page of their dumps, upvotes and - * playlists, and keeps them live. + * Everything a profile page shows comes through this hook. It loads the user + * with the first page of their dumps, upvotes and playlists, and keeps them + * live. * * @module */ diff --git a/src/hooks/shared/useFetchState.ts b/src/hooks/shared/useFetchState.ts index 6c9b0db4..d412e838 100644 --- a/src/hooks/shared/useFetchState.ts +++ b/src/hooks/shared/useFetchState.ts @@ -1,5 +1,6 @@ /** - * Loads one thing from the API, once per key, when first asked to. + * Lets a component load one thing from the API the first time it's needed, and + * keep it for as long as its key holds, as the profile's lazy tabs do. * * @module */ diff --git a/src/hooks/social/useFollows.ts b/src/hooks/social/useFollows.ts index 27b01c53..cd109c52 100644 --- a/src/hooks/social/useFollows.ts +++ b/src/hooks/social/useFollows.ts @@ -1,5 +1,6 @@ /** - * Reads `FollowContext`, for the Follow buttons. + * Tells a Follow button what the user follows, and follows or unfollows, by + * reading `FollowContext`. * * @module */ diff --git a/src/hooks/ws/useWS.ts b/src/hooks/ws/useWS.ts index b8e9e404..31070fad 100644 --- a/src/hooks/ws/useWS.ts +++ b/src/hooks/ws/useWS.ts @@ -1,7 +1,7 @@ /** - * Reads the live state that `WSProvider` keeps from the WebSocket. Each hook - * reads one of its three contexts, so that a component re-renders only with - * the part it uses. Outside `WSProvider`, they return inert defaults. + * Gives components the server's live updates. Each hook reads one of the three + * contexts `WSProvider` fills, so that a component re-renders only with the + * part it uses. Outside `WSProvider`, they return inert defaults. * * @module */ diff --git a/src/locales/en.po b/src/locales/en.po index 28e1a1c9..1afa1027 100644 --- a/src/locales/en.po +++ b/src/locales/en.po @@ -200,7 +200,7 @@ msgstr "Already dumped by {0} {1}" msgid "Already have an account? <0>Log in" msgstr "Already have an account? <0>Log in" -#: src/utils/shared/api.ts:34 +#: src/utils/shared/api.ts:35 msgid "An unexpected error occurred." msgstr "An unexpected error occurred." @@ -228,8 +228,8 @@ msgstr "Auto" msgid "Back to login" msgstr "Back to login" -#: src/contexts/ws/WSProvider.tsx:394 -#: src/contexts/ws/WSProvider.tsx:760 +#: src/contexts/ws/WSProvider.tsx:395 +#: src/contexts/ws/WSProvider.tsx:761 msgid "Can't connect to the live updates server. Upvotes and notifications may not sync until it reconnects." msgstr "Can't connect to the live updates server. Upvotes and notifications may not sync until it reconnects." @@ -341,7 +341,7 @@ msgstr "Color scheme" msgid "Confirm new password" msgstr "Confirm new password" -#: src/contexts/ws/WSProvider.tsx:753 +#: src/contexts/ws/WSProvider.tsx:754 msgid "Connection lost — this message may not have been sent" msgstr "Connection lost — this message may not have been sent" @@ -357,7 +357,7 @@ msgstr "Copy" msgid "Could not change password" msgstr "Could not change password" -#: src/utils/shared/api.ts:32 +#: src/utils/shared/api.ts:33 msgid "Could not connect to the server. Check your connection and try again." msgstr "Could not connect to the server. Check your connection and try again." @@ -699,7 +699,7 @@ msgstr "Follow some public playlists to see their dumps here." msgid "Follow some users to see their dumps here." msgstr "Follow some users to see their dumps here." -#: src/components/feed/FeedTabBar.tsx:48 +#: src/components/feed/FeedTabBar.tsx:49 #: src/components/profile/ProfileSettingsTab.tsx:44 #: src/pages/UserPublicProfile.tsx:191 msgid "Followed" @@ -745,7 +745,7 @@ msgstr "Go home" msgid "Go to login" msgstr "Go to login" -#: src/components/feed/FeedTabBar.tsx:44 +#: src/components/feed/FeedTabBar.tsx:45 #: src/components/profile/ProfileSettingsTab.tsx:41 msgid "Hot" msgstr "Hot" @@ -789,7 +789,7 @@ msgstr "invited by" msgid "Invitees" msgstr "Invitees" -#: src/components/feed/FeedTabBar.tsx:46 +#: src/components/feed/FeedTabBar.tsx:47 #: src/components/profile/ProfileSettingsTab.tsx:43 msgid "Journal" msgstr "Journal" @@ -814,7 +814,7 @@ msgstr "Link" msgid "Link or file" msgstr "Link or file" -#: src/contexts/ws/WSProvider.tsx:759 +#: src/contexts/ws/WSProvider.tsx:760 msgid "Live updates are temporarily disconnected. Trying to reconnect…" msgstr "Live updates are temporarily disconnected. Trying to reconnect…" @@ -919,7 +919,7 @@ msgid "new" msgstr "new" #: src/components/chat/ChatModal.tsx:669 -#: src/components/feed/FeedTabBar.tsx:45 +#: src/components/feed/FeedTabBar.tsx:46 #: src/components/profile/ProfileSettingsTab.tsx:42 msgid "New" msgstr "New" @@ -993,7 +993,7 @@ msgstr "No playlists match \"{q}\"." msgid "No playlists yet." msgstr "No playlists yet." -#: src/contexts/ws/WSProvider.tsx:928 +#: src/contexts/ws/WSProvider.tsx:929 msgid "No reply from the server — this message may not have been sent" msgstr "No reply from the server — this message may not have been sent" @@ -1351,7 +1351,7 @@ msgstr "Some images couldn't be uploaded." #: src/components/form/FormError.tsx:31 #: src/components/layout/PageError.tsx:29 -#: src/contexts/ws/WSProvider.tsx:728 +#: src/contexts/ws/WSProvider.tsx:729 #: src/pages/PlaylistDetail.tsx:119 msgid "Something went wrong" msgstr "Something went wrong" @@ -1380,7 +1380,7 @@ msgstr "That file is over {limit}." msgid "the chat" msgstr "the chat" -#: src/hooks/playlist/usePlaylist.ts:160 +#: src/hooks/playlist/usePlaylist.ts:161 msgid "The dump couldn't be removed. Try again." msgstr "The dump couldn't be removed. Try again." @@ -1388,7 +1388,7 @@ msgstr "The dump couldn't be removed. Try again." msgid "The image couldn't be uploaded." msgstr "The image couldn't be uploaded." -#: src/hooks/playlist/usePlaylist.ts:306 +#: src/hooks/playlist/usePlaylist.ts:307 msgid "The new order couldn't be saved. Try again." msgstr "The new order couldn't be saved. Try again." @@ -1448,7 +1448,7 @@ msgstr "Type a message…" msgid "Undo" msgstr "Undo" -#: src/utils/shared/api.ts:21 +#: src/utils/shared/api.ts:22 msgid "Unexpected response format" msgstr "Unexpected response format" @@ -1580,7 +1580,7 @@ msgstr "You can post it anyway." msgid "You'll be notified when someone follows your playlists, upvotes your dumps, or posts new content." msgstr "You'll be notified when someone follows your playlists, upvotes your dumps, or posts new content." -#: src/contexts/ws/WSProvider.tsx:909 +#: src/contexts/ws/WSProvider.tsx:910 msgid "You're offline — not sent" msgstr "You're offline — not sent" diff --git a/src/locales/fr.po b/src/locales/fr.po index df227388..75436f4f 100644 --- a/src/locales/fr.po +++ b/src/locales/fr.po @@ -200,7 +200,7 @@ msgstr "Déjà recommandé par {0} {1}" msgid "Already have an account? <0>Log in" msgstr "Vous avez déjà un compte ? <0>Se connecter" -#: src/utils/shared/api.ts:34 +#: src/utils/shared/api.ts:35 msgid "An unexpected error occurred." msgstr "Une erreur inattendue s'est produite." @@ -228,8 +228,8 @@ msgstr "Auto" msgid "Back to login" msgstr "Retour à la connexion" -#: src/contexts/ws/WSProvider.tsx:394 -#: src/contexts/ws/WSProvider.tsx:760 +#: src/contexts/ws/WSProvider.tsx:395 +#: src/contexts/ws/WSProvider.tsx:761 msgid "Can't connect to the live updates server. Upvotes and notifications may not sync until it reconnects." msgstr "Impossible de se connecter au serveur de mises à jour en direct. Les votes et les notifications pourraient ne pas se synchroniser avant la reconnexion." @@ -341,7 +341,7 @@ msgstr "Thème de couleur" msgid "Confirm new password" msgstr "Confirmer le nouveau mot de passe" -#: src/contexts/ws/WSProvider.tsx:753 +#: src/contexts/ws/WSProvider.tsx:754 msgid "Connection lost — this message may not have been sent" msgstr "Connexion perdue — ce message n'a peut-être pas été envoyé" @@ -357,7 +357,7 @@ msgstr "Copier" msgid "Could not change password" msgstr "Impossible de changer le mot de passe" -#: src/utils/shared/api.ts:32 +#: src/utils/shared/api.ts:33 msgid "Could not connect to the server. Check your connection and try again." msgstr "Impossible de joindre le serveur. Vérifiez votre connexion et réessayez." @@ -699,7 +699,7 @@ msgstr "Suivez des collections publiques pour voir leurs recos ici." msgid "Follow some users to see their dumps here." msgstr "Suivez des utilisateurs pour voir leurs recos ici." -#: src/components/feed/FeedTabBar.tsx:48 +#: src/components/feed/FeedTabBar.tsx:49 #: src/components/profile/ProfileSettingsTab.tsx:44 #: src/pages/UserPublicProfile.tsx:191 msgid "Followed" @@ -745,7 +745,7 @@ msgstr "Accueil" msgid "Go to login" msgstr "Aller à la connexion" -#: src/components/feed/FeedTabBar.tsx:44 +#: src/components/feed/FeedTabBar.tsx:45 #: src/components/profile/ProfileSettingsTab.tsx:41 msgid "Hot" msgstr "Tendances" @@ -789,7 +789,7 @@ msgstr "invité par" msgid "Invitees" msgstr "Invités" -#: src/components/feed/FeedTabBar.tsx:46 +#: src/components/feed/FeedTabBar.tsx:47 #: src/components/profile/ProfileSettingsTab.tsx:43 msgid "Journal" msgstr "Journal" @@ -814,7 +814,7 @@ msgstr "Lien" msgid "Link or file" msgstr "Lien ou fichier" -#: src/contexts/ws/WSProvider.tsx:759 +#: src/contexts/ws/WSProvider.tsx:760 msgid "Live updates are temporarily disconnected. Trying to reconnect…" msgstr "Les mises à jour en direct sont temporairement interrompues. Tentative de reconnexion…" @@ -919,7 +919,7 @@ msgid "new" msgstr "nouveau" #: src/components/chat/ChatModal.tsx:669 -#: src/components/feed/FeedTabBar.tsx:45 +#: src/components/feed/FeedTabBar.tsx:46 #: src/components/profile/ProfileSettingsTab.tsx:42 msgid "New" msgstr "Nouveau" @@ -993,7 +993,7 @@ msgstr "Aucune collection ne correspond à « {q} »." msgid "No playlists yet." msgstr "Pas encore de collections." -#: src/contexts/ws/WSProvider.tsx:928 +#: src/contexts/ws/WSProvider.tsx:929 msgid "No reply from the server — this message may not have been sent" msgstr "Pas de réponse du serveur — ce message n'a peut-être pas été envoyé" @@ -1351,7 +1351,7 @@ msgstr "Certaines images n'ont pas pu être envoyées." #: src/components/form/FormError.tsx:31 #: src/components/layout/PageError.tsx:29 -#: src/contexts/ws/WSProvider.tsx:728 +#: src/contexts/ws/WSProvider.tsx:729 #: src/pages/PlaylistDetail.tsx:119 msgid "Something went wrong" msgstr "Une erreur est survenue" @@ -1380,7 +1380,7 @@ msgstr "Ce fichier dépasse {limit}." msgid "the chat" msgstr "la tribune" -#: src/hooks/playlist/usePlaylist.ts:160 +#: src/hooks/playlist/usePlaylist.ts:161 msgid "The dump couldn't be removed. Try again." msgstr "Le dump n'a pas pu être retiré. Réessayez." @@ -1388,7 +1388,7 @@ msgstr "Le dump n'a pas pu être retiré. Réessayez." msgid "The image couldn't be uploaded." msgstr "L'image n'a pas pu être envoyée." -#: src/hooks/playlist/usePlaylist.ts:306 +#: src/hooks/playlist/usePlaylist.ts:307 msgid "The new order couldn't be saved. Try again." msgstr "Le nouvel ordre n'a pas pu être enregistré. Réessayez." @@ -1448,7 +1448,7 @@ msgstr "Écrivez un message…" msgid "Undo" msgstr "Annuler" -#: src/utils/shared/api.ts:21 +#: src/utils/shared/api.ts:22 msgid "Unexpected response format" msgstr "Format de réponse inattendu" @@ -1580,7 +1580,7 @@ msgstr "Vous pouvez la publier quand même." msgid "You'll be notified when someone follows your playlists, upvotes your dumps, or posts new content." msgstr "Vous serez notifié lorsque quelqu'un suit vos collections, vote pour vos recos ou publie du nouveau contenu." -#: src/contexts/ws/WSProvider.tsx:909 +#: src/contexts/ws/WSProvider.tsx:910 msgid "You're offline — not sent" msgstr "Hors ligne — message non envoyé" diff --git a/src/pages/Dump.tsx b/src/pages/Dump.tsx index c510033d..40b064bf 100644 --- a/src/pages/Dump.tsx +++ b/src/pages/Dump.tsx @@ -1,5 +1,5 @@ /** - * The page of a dump, with its preview, comments, related dumps and the + * Renders a dump's page, with its preview, comments, related dumps and the * playlists holding it. * * @module diff --git a/src/pages/DumpEdit.tsx b/src/pages/DumpEdit.tsx index 73d7d729..2d071ea1 100644 --- a/src/pages/DumpEdit.tsx +++ b/src/pages/DumpEdit.tsx @@ -1,5 +1,5 @@ /** - * The page where a dump's poster, or a moderator, edits or deletes it. + * Renders the page where a dump's poster, or a moderator, edits or deletes it. * * @module */ diff --git a/src/pages/Search.tsx b/src/pages/Search.tsx index a735ec0a..1ee6684b 100644 --- a/src/pages/Search.tsx +++ b/src/pages/Search.tsx @@ -1,6 +1,6 @@ /** - * The page that shows the results of a search, in a tab for dumps, one for - * users and one for playlists. + * Renders the results of a search, in a tab for dumps, one for users and one + * for playlists. * * @module */ diff --git a/src/pages/UserDumps.tsx b/src/pages/UserDumps.tsx index c1eadaf1..c0214239 100644 --- a/src/pages/UserDumps.tsx +++ b/src/pages/UserDumps.tsx @@ -1,6 +1,6 @@ /** - * The page listing all of a user's dumps, which the "dumps" section of their - * profile links to. + * Renders the page listing all of a user's dumps, which the "dumps" section of + * their profile links to. * * @module */ diff --git a/src/pages/UserUpvoted.tsx b/src/pages/UserUpvoted.tsx index d6cfc5b7..7627e1cf 100644 --- a/src/pages/UserUpvoted.tsx +++ b/src/pages/UserUpvoted.tsx @@ -1,6 +1,6 @@ /** - * The page listing all the dumps a user upvoted, which the "upvoted" section of - * their profile links to. + * Renders the page listing all the dumps a user upvoted, which the "upvoted" + * section of their profile links to. * * @module */ diff --git a/src/utils/auth/storage.ts b/src/utils/auth/storage.ts index 7d2a5c5c..215ca38e 100644 --- a/src/utils/auth/storage.ts +++ b/src/utils/auth/storage.ts @@ -1,6 +1,6 @@ /** - * Reads and writes the session in localStorage, where every tab shares one - * entry. `AuthProvider` and `useAuth` are its only users. + * Keeps the user signed in across reloads and tabs, in one localStorage entry + * every tab shares. `AuthProvider` and `useAuth` are its only users. * * @module */ diff --git a/src/utils/chat/draft.ts b/src/utils/chat/draft.ts index 90e568e7..fe322079 100644 --- a/src/utils/chat/draft.ts +++ b/src/utils/chat/draft.ts @@ -1,7 +1,7 @@ /** - * Keeps the chat composer's unsent message in sessionStorage, per user, so - * closing the chat modal or reloading the tab doesn't lose it. `ChatModal` - * reads it on open and writes it on every change. + * Keeps the chat composer's unsent message when the chat modal closes or the + * tab reloads. It lives in sessionStorage, per user; `ChatModal` reads it on + * open and writes it on every change. * * @module */ diff --git a/src/utils/chat/text.ts b/src/utils/chat/text.ts index 6461829f..6c9f7023 100644 --- a/src/utils/chat/text.ts +++ b/src/utils/chat/text.ts @@ -1,6 +1,6 @@ /** - * Reads the Markdown of chat messages, to find mentions and to flatten it into - * reply previews. + * Finds the mentions in a chat message, and flattens its Markdown into reply + * previews. * * @module */ diff --git a/src/utils/dump/draft.ts b/src/utils/dump/draft.ts index d769aec1..db938f4e 100644 --- a/src/utils/dump/draft.ts +++ b/src/utils/dump/draft.ts @@ -1,7 +1,7 @@ /** - * Keeps the half-written dump of the dump creation modal in localStorage, so - * that closing the modal by mistake, with Escape or a click outside, loses - * nothing but an attached file, which can't be stored. + * Gives back the half-written dump when the dump creation modal is closed by + * mistake, with Escape or a click outside. It is kept in localStorage, all but + * an attached file, which can't be stored. * * There is one draft, not one per tab: whoever closed the modal by mistake * wants back what they were just writing, wherever they reopen it. diff --git a/src/utils/editor/skinTone.ts b/src/utils/editor/skinTone.ts index f6950925..09fdb2ac 100644 --- a/src/utils/editor/skinTone.ts +++ b/src/utils/editor/skinTone.ts @@ -1,6 +1,6 @@ /** - * Stores the emoji picker's skin tone in localStorage, so that it outlasts the - * picker and the page. `EmojiPickerPopup` reads and writes it. + * Remembers the emoji picker's skin tone across pickers and pages. It lives in + * localStorage, and `EmojiPickerPopup` reads and writes it. * * @module */ diff --git a/src/utils/editor/text.ts b/src/utils/editor/text.ts index f1e9d4a6..3202c23b 100644 --- a/src/utils/editor/text.ts +++ b/src/utils/editor/text.ts @@ -1,6 +1,6 @@ /** - * Reads a text as the editor's autocompletes and the chat see it: whether the - * caret is inside code, and whether a message is only emoji. + * Tells the editor's autocompletes when the caret is inside code, where they + * stay closed, and the chat when a message is only emoji, which it shows large. * * @module */ diff --git a/src/utils/feed/pagedList.ts b/src/utils/feed/pagedList.ts index 299e080c..d99cdec5 100644 --- a/src/utils/feed/pagedList.ts +++ b/src/utils/feed/pagedList.ts @@ -1,7 +1,7 @@ /** - * Declares a list the API serves a page at a time, and reads its pages. Every - * such list in the app is a {@link PagedList}, whose next page `useLoadMore` - * appends. + * Makes every list the API serves a page at a time work the same way. Each is a + * {@link PagedList}, whose next page `useLoadMore` appends, and this module + * reads its pages. * * @module */ diff --git a/src/utils/shared/api.ts b/src/utils/shared/api.ts index e897145c..655f0c8a 100644 --- a/src/utils/shared/api.ts +++ b/src/utils/shared/api.ts @@ -1,6 +1,7 @@ /** - * Reads the API's JSON envelope, and turns the errors a request can end in into - * messages. Every component and hook that calls the API goes through it. + * Makes every call to the API succeed or fail the same way. It reads the JSON + * envelope, and turns the errors a request can end in into messages. Every + * component and hook that calls the API goes through it. * * @module */ diff --git a/src/utils/shared/loadState.ts b/src/utils/shared/loadState.ts index e9c4f169..8258dc50 100644 --- a/src/utils/shared/loadState.ts +++ b/src/utils/shared/loadState.ts @@ -1,6 +1,6 @@ /** - * Declares the state of something a component loads from the API, which - * `ListState` renders while it isn't loaded. + * Gives every component that loads from the API the same states, so that + * `ListState` renders loading, error and empty alike everywhere. * * @module */ diff --git a/src/utils/shared/sound.ts b/src/utils/shared/sound.ts index eddbd46b..fe74eb0d 100644 --- a/src/utils/shared/sound.ts +++ b/src/utils/shared/sound.ts @@ -9,9 +9,9 @@ const STORAGE_KEY = "sounds"; /** - * Holds, in localStorage, the id of the last event that chimed, so that a user - * with the site open in several tabs hears one chime per event, not one per - * tab. + * Makes a user with the site open in several tabs hear one chime per event, not + * one per tab. The key holds, in localStorage, the id of the last event that + * chimed. */ const CLAIM_KEY = "sounds-last-claim"; /**