better UX

This commit is contained in:
DaKheera47 2026-02-15 20:49:46 +00:00
parent 06dfda996c
commit 07b3c23492
3 changed files with 66 additions and 32 deletions

View File

@ -1,4 +1,4 @@
import { Send } from "lucide-react";
import { RefreshCcw, Send, Square } from "lucide-react";
import type React from "react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
@ -6,10 +6,21 @@ import { Textarea } from "@/components/ui/textarea";
type ComposerProps = {
disabled?: boolean;
isStreaming: boolean;
canRegenerate: boolean;
onRegenerate: () => Promise<void>;
onStop: () => Promise<void>;
onSend: (content: string) => Promise<void>;
};
export const Composer: React.FC<ComposerProps> = ({ disabled, onSend }) => {
export const Composer: React.FC<ComposerProps> = ({
disabled,
isStreaming,
canRegenerate,
onRegenerate,
onStop,
onSend,
}) => {
const [value, setValue] = useState("");
const submit = async () => {
@ -38,14 +49,40 @@ export const Composer: React.FC<ComposerProps> = ({ disabled, onSend }) => {
<div className="text-[10px] text-muted-foreground">
Cmd/Ctrl+Enter to send
</div>
<Button
size="sm"
onClick={() => void submit()}
disabled={disabled || !value.trim()}
>
<Send className="mr-1 h-3.5 w-3.5" />
Send
</Button>
<div className="flex items-center gap-1">
{isStreaming ? (
<Button
size="icon"
variant="outline"
onClick={() => void onStop()}
aria-label="Stop generating"
title="Stop generating"
>
<Square className="h-3.5 w-3.5" />
</Button>
) : (
<Button
size="icon"
variant="outline"
onClick={() => void onRegenerate()}
disabled={disabled || !canRegenerate}
aria-label="Regenerate response"
title="Regenerate response"
>
<RefreshCcw className="h-3.5 w-3.5" />
</Button>
)}
<Button
size="icon"
onClick={() => void submit()}
disabled={disabled || !value.trim()}
aria-label="Send message"
title="Send message"
>
<Send className="h-3.5 w-3.5" />
</Button>
</div>
</div>
</div>
);

View File

@ -26,28 +26,25 @@ export const GhostwriterDrawer: React.FC<GhostwriterDrawerProps> = ({
const [open, setOpen] = useState(false);
return (
<Sheet
open={open}
onOpenChange={setOpen}
>
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild>
<Button
size="sm"
variant="outline"
className="h-8 gap-1.5 text-xs"
className={cn("h-8 gap-1.5 text-xs", triggerClassName)}
disabled={!job}
>
<PanelRightOpen className='h-3.5 w-3.5' />
<PanelRightOpen className="h-3.5 w-3.5" />
Ghostwriter
</Button>
</SheetTrigger>
<SheetContent
side='right'
className='w-full p-0 sm:max-w-none lg:w-[50vw] xl:w-[40vw] 2xl:w-[30vw]'
side="right"
className="flex w-full flex-col p-0 sm:max-w-none lg:w-[50vw] xl:w-[40vw] 2xl:w-[30vw]"
>
<div className="h-full overflow-y-auto p-4">
<SheetHeader>
<div className="border-b border-border/50 p-4 ">
<SheetHeader className="space-y-2">
<SheetTitle>Ghostwriter</SheetTitle>
<SheetDescription>
The Ghostwriter will use the context of this job and your resume,
@ -55,12 +52,13 @@ export const GhostwriterDrawer: React.FC<GhostwriterDrawerProps> = ({
message.
</SheetDescription>
</SheetHeader>
{job && (
<div className="mt-4">
<GhostwriterPanel job={job} />
</div>
)}
</div>
{job && (
<div className="flex min-h-0 flex-1 p-4 pt-0">
<GhostwriterPanel job={job} />
</div>
)}
</SheetContent>
</Sheet>
);

View File

@ -5,7 +5,6 @@ import { toast } from "sonner";
import * as api from "../../api";
import { Composer } from "./Composer";
import { MessageList } from "./MessageList";
import { RunControls } from "./RunControls";
type GhostwriterPanelProps = {
job: Job;
@ -237,7 +236,7 @@ export const GhostwriterPanel: React.FC<GhostwriterPanelProps> = ({ job }) => {
}, [isStreaming, job.id, loadMessages, messages, onStreamEvent]);
return (
<div className="flex min-h-0 flex-1 flex-col">
<div className="flex h-full min-h-0 flex-1 flex-col">
<div
ref={messageListRef}
className="min-h-0 flex-1 overflow-y-auto border-b border-border/50 pb-3 pr-1"
@ -249,15 +248,15 @@ export const GhostwriterPanel: React.FC<GhostwriterPanelProps> = ({ job }) => {
/>
</div>
<div className="mt-4 space-y-3">
<RunControls
<div className="mt-4">
<Composer
disabled={isLoading || isStreaming}
isStreaming={isStreaming}
canRegenerate={canRegenerate}
onStop={stopStreaming}
onRegenerate={regenerate}
onStop={stopStreaming}
onSend={sendMessage}
/>
<Composer disabled={isLoading || isStreaming} onSend={sendMessage} />
</div>
</div>
);