diff --git a/cli/src/types.ts b/cli/src/types.ts index c366fa42..f2b7c7ff 100644 --- a/cli/src/types.ts +++ b/cli/src/types.ts @@ -427,3 +427,16 @@ export interface DispatchResponse { }; } +export interface DispatchImagePromptRequest { + title: string; + tags: string[]; + tldr: string; + format: DispatchFormat; +} + +export interface DispatchImagePromptResponse { + prompt: string; + model: string; + tokensUsed: { input: number; output: number }; +} + diff --git a/dashboard/src/components/dispatch/CoverImagePromptSection.tsx b/dashboard/src/components/dispatch/CoverImagePromptSection.tsx new file mode 100644 index 00000000..8b935f1e --- /dev/null +++ b/dashboard/src/components/dispatch/CoverImagePromptSection.tsx @@ -0,0 +1,101 @@ +import { useState } from 'react'; +import { useMutation } from '@tanstack/react-query'; +import { Sparkles, Loader2, AlertCircle, Copy, Check } from 'lucide-react'; +import { toast } from 'sonner'; +import { Button } from '@/components/ui/button'; +import { Textarea } from '@/components/ui/textarea'; +import { Alert, AlertDescription } from '@/components/ui/alert'; +import { generateDispatchImagePrompt } from '@/lib/api'; +import type { DispatchFormat } from '@/lib/api'; + +interface CoverImagePromptSectionProps { + title: string; + tags: string[]; + tldr: string; + format: DispatchFormat; +} + +export function CoverImagePromptSection({ title, tags, tldr, format }: CoverImagePromptSectionProps) { + const [copied, setCopied] = useState(false); + + const mutation = useMutation({ + mutationFn: () => generateDispatchImagePrompt({ title, tags, tldr, format }), + }); + + function handleCopy() { + if (!mutation.data) return; + void navigator.clipboard.writeText(mutation.data.prompt).then(() => { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + toast.success('Prompt copied to clipboard'); + }); + } + + function handleRegenerate() { + mutation.reset(); + mutation.mutate(); + } + + return ( +
+

Cover image prompt

+ + {!mutation.data && !mutation.isPending && !mutation.isError && ( + + )} + + {mutation.isPending && ( + + )} + + {mutation.isError && ( +
+ + + + {mutation.error instanceof Error ? mutation.error.message : 'Failed to generate prompt.'} + + + +
+ )} + + {mutation.data && ( +
+