The errors locales had no entry for 1008 (a guest session tried a change),
4009 (wallet withdrawals disabled) or 13008 (RSSHub instance already
added), so clients showed English text or the bare code. Every errors
locale now has them, and a test checks each code the server can send.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The handle format check also ran on the stored handle, so a handle older
clients saved with spaces or non-ASCII characters blocked saving any other
field. It now runs only once the handle changes, as the server keeps a
stored handle that a save sends back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The server now refuses a handle with spaces or invisible characters with
HANDLE_INVALID_CHARACTERS, a code added after the profile form mapped the
others, so it would have toasted English text. It now shows the translated
handle message under the field, like the form's own check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Opening the list or feed follow form logged "A component is changing from
uncontrolled to controlled": the Private Follow and Hide from Timeline
switches had no value until the followed settings loaded. They now start
off, and the values the form sends are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The profile form toasted the server's English text for a taken handle, a
blank name or a value too long, and its own limits differed from the
server's (a 50-character name, 64-character website). Update-user codes
now show their translated message under the field, the form checks the
server's lengths, and the handle lookup stays for servers without them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An entry of any feed that linked to a post on X showed that post's author
with the X badge, so a Hacker News item about a tweet named @karpathy next
to Hacker News. The handle and badge now appear only for entries of X
feeds, known by their rsshub://twitter route or their x.com site.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tab and Shift+Tab switched the timeline view even on a focused button, link,
field, switch or menu item, so keyboard users could not Tab between them.
On such a control they now move the focus; on the timeline itself and the
subscription rows they still switch views.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since links took Space and Enter from the app's shortcuts, Space on a
timeline entry that was just clicked scrolled the list instead of playing
or pausing the corner player. A link only acts on Enter, so it keeps Enter
and Space goes to the shortcut again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the corrected name order, a click on the sort button from the default
order sorted the subscriptions Z to A, and everyone who sorted by name saw
the list flip. The click now pairs most unread first with A to Z, and a
one-time migration flips stored name orders so they show as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Alphabetical, ascending" listed folders and feeds from Z to A and
"descending" from A to Z, because the A-to-Z comparison was reversed for
the ascending order. The unread count orders already matched their labels.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each chat history item held a "Today" tooltip button inside the menu
item; the date is plain text there now. A chat whose reply brought no
generated title, such as a failed one, stayed "New Chat" in the header
while the history listed its stored title; it now takes that title. A
first load of /settings/ai opened General because the AI tab waits for
the server configs; the modal now moves to it once it appears.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous and next buttons of the media lightbox had no accessible
name. Closing a global popover such as Share moved the focus to its
invisible anchor at the pointer; it now goes back to the element the
popover was opened from, unless the user clicked somewhere else.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The export link pointed at the API's origin, where browsers ignore the
download name and keep the server's follow.opml. The OPML is now fetched
through the API client, which also signs it in on desktop, and saved as
folo.opml. Entries saved to Readwise say Folo, not Follow, as their source.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Free and Basic users could turn on Bring Your Own Key and add keys,
which the server ignores for their plans. The switch is now disabled for
them with a note and Upgrade; keys saved earlier stay listed so they can
be deleted, and BYOK can still be turned off.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pausing TTS before its audio had finished downloading flipped the player
back to "playing" with every new chunk, while the audio stayed silent. A
decoded chunk now only ends the loading state and leaves a pause alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The subscription sort options and the picture view options were hover
cards, which keep their controls out of the tab order. They are now
popovers that still open on hover; Enter (and a click on the picture view
button) opens them with focus inside, and Escape returns focus to the
button. A click on the sort button still switches count and name sorting.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Space and Enter on a focused button ran the app's single-key shortcuts
instead: Space toggled the corner player rather than opening the picture
view options, and Enter on the sidebar sort button moved focus to the
timeline. Native controls and fields, and controls that handled the key
themselves, now get these keys; elsewhere the shortcuts work as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Free users could turn on Hide from Timeline when following or editing a
list, which the plan does not include. The switch now shows the paid badge
and is disabled for them, like Private Follow. A list that already has
either switch on keeps it usable, so it can still be turned off.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Escape or the X button closed the Add/Edit Feed and List forms (and the
inbox and RSSHub route forms) and silently dropped what was typed. With
changes they now ask "Discard changes?" first; without any they close at
once. Edit forms start from the followed settings, so only real edits count.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The entry shows its AI summary again next to an open fixed AI panel once
the chat has messages, but the card's Ask AI only opens the panel, so
there it did nothing. It is now offered only while the panel is closed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With AI usage on a single day, Usage Trends drew nothing: one point makes
no line, and the area path came out invalid. A single day now shows as a
dot.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The "Start free trial" notice above the AI input is a button that held a
second "Free Trial" button, which is invalid HTML, gave screen readers two
nested controls and keyboard users two stops for one action. The inner
label is now plain text inside the one button.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hovering the Summarize shortcut showed its prompt with the raw tag
<mention-date text="24hoursago"></mention-date>. The tooltip now shows
the dates such a tag stands for, as the server resolves it for the model.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The model picker was a plain div that could not take focus, and Tab in
the composer indented text instead of leaving it, so keyboard users could
not change the model. The picker is now a button named "Model: <name>",
Tab moves on from the composer, and the title that opens the chat history
is named "Chat history: <title>" instead of repeating "New Chat".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The full-page chat at /ai showed "Switch to Fixed/Floating Panel" and
More > "Close Sidebar", which only change the timeline's AI panel and did
nothing visible there. The /ai header no longer shows them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The shortcut row read the route once while mounting, which on navigation
into /ai (the avatar menu, Back) still held the previous page, so entry
shortcuts such as Analyze were missing until a reload. It now follows
the route.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the fixed AI panel open, the entry hides its AI summary because the
panel's welcome screen shows it, but that screen goes away with the first
message, so the summary was shown nowhere. The entry now shows it again
whenever the chat has messages.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
More > Generate Title closed the menu and did nothing when the request
failed: the error was only logged. A failure now shows "Couldn't generate
a title" with the reason.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The error bubble in AI chat always said "Error occurred", and a chat
without a title was named "<date> chat" or "<date> timeline summary" with
the date in the UI language but the rest in English. Both now come from
the locale files.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A reply whose stream went silent stayed on "Thinking..." with the Stop
button for as long as the connection was open. After two minutes without
any data the reply now ends with an error that says so, and the message
can be retried.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The timestamp and Copy action only appeared once the server sent the
reply's finish time, which a reply stopped midway never gets, so the
partial text could not be copied. They now show for every reply that is
no longer streaming; the usage details still need a finished reply.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Screen readers announced the composer's icon button, which sends a message
and stops a streaming reply, and the delete button of a chat in the
history only as "button". They are now "Send message", "Stop generating"
and "Delete Chat".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The New Task button checked a fixed limit of 10, so free and Basic users,
whose plans include no AI tasks, filled in the whole form only to be
rejected, while Plus and Pro users were stopped at 10. The limit now comes
from the plan, and the AI tab says when the plan has no tasks, with Upgrade.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On the free plan the server rejects AI sort with 402, but the toggle stayed
on over the local list, which looked sorted, and nothing was shown. A
failed AI-sorted load now turns the toggle off and shows the error, with
the Upgrade action when the plan does not include it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Attachments that failed to upload were sent with the message anyway, and
the upload error toast showed the SDK's request dump with the session
headers. Only uploaded files go out now, sending waits while a file is
still uploading, and the error shows the server's message alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Saving an AI chat message without changing it sent it again, dropping the
existing reply and using another request: the check compared the editor
JSON with the stored string, so it never matched. Both sides now go through
the editor's own serialization, and an unchanged save just closes the editor.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The trigger comment said Space opens the options too, but Space is the global
play/pause shortcut and never reaches the button. Only a click or Enter does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The welcome entries show View Source Content and Readability as disabled in
the entry header, but a click still ran them: the source panel loaded the app
itself and readability replaced the article with an empty page. Both now
ignore onboarding entries, like the link commands.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Export as PDF printed the summary card even when it only held the "Start
free trial" upsell, a loading skeleton or "not available". The card is now
hidden in print unless it has a summary.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The hidden anchor of the global popover sat as an inline button after the
full-height layout, making the page 24px taller than the window. Closing the
Share popover focused it and scrolled the whole app up, cutting off the header,
and modals could do the same. The anchor now always stays fixed and sizeless.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Unstarring an entry from the Starred list keeps it there for the session but
drops its starred time, so the meta line ended in a bare "·" (and the All view
lost its date). It now falls back to the published time.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Preview Mode and Image Only options only opened on mouse hover, and the
trigger was an unnamed button nested inside an anchor. The named button is now
the trigger itself and also opens the options on click or Enter, while hover
keeps working.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The welcome entries showed Copy Link and Open in New Tab as disabled, yet
Shift+Cmd+C, B, Share and Cmd+Alt+S still copied, opened or shared their
internal folo:// address. The link commands now ignore onboarding entries and
Share is disabled for them like the other link actions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Items whose link is a tweet showed the post id as the author's X handle, for
example @2109361546505966046, and linked to a profile that does not exist.
The handle now comes from the first path segment, and x.com routes such as
/i/web/status are not treated as handles.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TTS plays from a live audio stream or a temporary blob, so Download opened a
blank about:blank tab instead of saving anything. The button is now hidden
while the player holds TTS and stays for podcasts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Screen readers announced Mark All as Read, the More menus, the previous and
next entry arrows, the wide-mode close button, reader avatars, the corner
player controls and the sidebar feed badges as unnamed buttons, because their
labels only lived in hover tooltips. Each now has an accessible name.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sites that refuse to be framed left View Source Content showing a blank or
broken page with no way forward, because a blocked iframe still reports a
load. The web build now shows a short notice with an Open in New Tab button
under the source page, in the panel and in the modal.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shift+Cmd+V did nothing once focus was in the open article, because the
entry-scope shortcuts bound every Entry command except Play TTS. It is now
bound there too, so the shortcut works wherever the menus advertise it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>