Finish the mobile performance pass

- Cache the model catalog once per user and each conversation's setting
  separately; clear both on logout and after model saves
- Compress hashed assets asynchronously with a byte budget and set Vary
- Memoize message parsing and throttle selection reads
- Debounce draft writes to localStorage
- Keep the composer editor on the page and focused, as before
- Add a bundle budget check and run it in CI
- Show a loading block while sessions load and a workspace avatar in the
  mobile conversation header
This commit is contained in:
2026-10-20 14:37:11 +01:00
parent c1a94fc9a5
commit 4f7e0a6bf0
38 changed files with 1320 additions and 334 deletions
@@ -15,6 +15,12 @@ import MessageReplyQuote from "./message-reply-quote";
import NeedsYouChip from "./needs-you-chip";
import SpeakMessageButton from "./speak-message-button";
/**
* Kept module-level: a new array on every render makes `react-markdown`
* parse the message again.
*/
const RemarkPlugins = [remarkGfm];
type Props = {
message: BotMessageWithAttachments;
bot_name: string;
@@ -52,7 +58,7 @@ function BotMessageLine({ message, bot_name, at }: Props) {
className="w-full gap-2.5! items-start break-words"
>
<Markdown
remarkPlugins={[remarkGfm]}
remarkPlugins={RemarkPlugins}
components={MessageMarkdownComponents}
>
{linkComputerRefs({ text: message.text || "" })}