Files
zopu-code/repos/web/components/chat/chat-composer.tsx
-Puter cc47007fa9 Slice 1 polish: archive dormant code, merge work-os into primitives, add futures
- Archive dormant apps (daemon, desktop, native, tui) and superseded
  packages/server into repos/ for reference
- Archive 21 dead web components (chat page shell, work-os cluster, strays)
  into repos/web/; keep reused message-rendering primitives in components/chat
- Merge @code/work-os into @code/primitives; work.ts absorbed via ./work
  subpath and barrel export; update all four importers
- Add docs/futures.md tracking audio/video (blocked at Flue + provider),
  web layout cleanup, and message rendering quality
- Repoint dev:zopu script to @code/agents (the live Flue server)
- Note repos/ reference-code convention in AGENTS.md
2026-07-27 16:34:17 +05:30

41 lines
1.2 KiB
TypeScript

import { MobileChatComposer } from "@code/ui/components/mobile-chat";
import { LoaderCircle } from "lucide-react";
import type { ReactNode } from "react";
import { useChatComposer } from "@/hooks/chat/use-chat-composer";
import type { ChatComposerProps } from "@/lib/chat/types";
export const ChatComposer = ({ error, onSend, status }: ChatComposerProps) => {
const busy =
status === "connecting" || status === "submitted" || status === "streaming";
const composer = useChatComposer({ busy, onSend });
let statusMessage: ReactNode;
if (busy) {
statusMessage = (
<span className="inline-flex items-center gap-1.5">
<LoaderCircle className="size-3 animate-spin" />
{status === "connecting" ? "Preparing Zopu" : "Zopu is responding"}
</span>
);
}
return (
<MobileChatComposer
busy={busy}
canSend={composer.canSend}
errorMessage={
error ? error.message || "Message failed to send" : undefined
}
onSubmit={composer.handleSubmit}
statusMessage={statusMessage}
textareaProps={{
...composer.inputProps,
"aria-describedby": error ? "composer-error" : undefined,
"aria-invalid": error ? true : undefined,
disabled: busy,
}}
/>
);
};