|
<script lang="ts"> |
|
import LikeDislike from "./LikeDislike.svelte"; |
|
import Copy from "./Copy.svelte"; |
|
import type { FileData } from "@gradio/client"; |
|
import DownloadIcon from "./Download.svelte"; |
|
import { DownloadLink } from "@gradio/wasm/svelte"; |
|
import type { NormalisedMessage, TextMessage } from "../types"; |
|
import { is_component_message } from "./utils"; |
|
import { Retry, Undo } from "@gradio/icons"; |
|
import { IconButtonWrapper, IconButton } from "@gradio/atoms"; |
|
|
|
export let likeable: boolean; |
|
export let show_retry: boolean; |
|
export let show_undo: boolean; |
|
export let show_copy_button: boolean; |
|
export let show: boolean; |
|
export let message: NormalisedMessage | NormalisedMessage[]; |
|
export let position: "right" | "left"; |
|
export let avatar: FileData | null; |
|
export let generating: boolean; |
|
|
|
export let handle_action: (selected: string | null) => void; |
|
export let layout: "bubble" | "panel"; |
|
|
|
function is_all_text( |
|
message: NormalisedMessage[] | NormalisedMessage |
|
): message is TextMessage[] | TextMessage { |
|
return ( |
|
(Array.isArray(message) && |
|
message.every((m) => typeof m.content === "string")) || |
|
(!Array.isArray(message) && typeof message.content === "string") |
|
); |
|
} |
|
|
|
function all_text(message: TextMessage[] | TextMessage): string { |
|
if (Array.isArray(message)) { |
|
return message.map((m) => m.content).join("\n"); |
|
} |
|
return message.content; |
|
} |
|
|
|
$: message_text = is_all_text(message) ? all_text(message) : ""; |
|
|
|
$: show_copy = show_copy_button && message && is_all_text(message); |
|
$: show_download = |
|
!Array.isArray(message) && |
|
is_component_message(message) && |
|
message.content.value?.url; |
|
</script> |
|
|
|
{#if show} |
|
<div |
|
class="message-buttons-{position} {layout} message-buttons {avatar !== |
|
null && 'with-avatar'}" |
|
> |
|
<IconButtonWrapper top_panel={false}> |
|
{#if show_copy} |
|
<Copy value={message_text} /> |
|
{/if} |
|
{#if show_download && !Array.isArray(message) && is_component_message(message)} |
|
<DownloadLink |
|
href={message?.content?.value.url} |
|
download={message.content.value.orig_name || "image"} |
|
> |
|
<IconButton Icon={DownloadIcon} /> |
|
</DownloadLink> |
|
{/if} |
|
{#if show_retry} |
|
<IconButton |
|
Icon={Retry} |
|
label="Retry" |
|
on:click={() => handle_action("retry")} |
|
disabled={generating} |
|
/> |
|
{/if} |
|
{#if show_undo} |
|
<IconButton |
|
label="Undo" |
|
Icon={Undo} |
|
on:click={() => handle_action("undo")} |
|
disabled={generating} |
|
/> |
|
{/if} |
|
{#if likeable} |
|
<LikeDislike {handle_action} /> |
|
{/if} |
|
</IconButtonWrapper> |
|
</div> |
|
{/if} |
|
|
|
<style> |
|
.bubble :global(.icon-button-wrapper) { |
|
margin: 0px calc(var(--spacing-xl) * 2); |
|
} |
|
|
|
.message-buttons-left { |
|
align-self: flex-start; |
|
} |
|
|
|
.bubble.message-buttons-right { |
|
align-self: flex-end; |
|
} |
|
|
|
.message-buttons-right :global(.icon-button-wrapper) { |
|
margin-left: auto; |
|
} |
|
|
|
.bubble.with-avatar { |
|
margin-left: calc(var(--spacing-xl) * 5); |
|
margin-right: calc(var(--spacing-xl) * 5); |
|
} |
|
|
|
.panel { |
|
display: flex; |
|
align-self: flex-start; |
|
padding: 0 var(--spacing-xl); |
|
z-index: var(--layer-1); |
|
} |
|
</style> |
|
|