forked from coracle/flotilla
Avoid reflow by showing chat thunk status in a toast
This commit is contained in:
@@ -1,95 +1,22 @@
|
||||
<script lang="ts">
|
||||
import {stopPropagation} from "svelte/legacy"
|
||||
import {nth, noop} from "@welshman/lib"
|
||||
import {PublishStatus} from "@welshman/net"
|
||||
import {
|
||||
MergedThunk,
|
||||
publishThunk,
|
||||
isMergedThunk,
|
||||
thunkIsComplete,
|
||||
thunkHasStatus,
|
||||
} from "@welshman/app"
|
||||
import {MergedThunk, thunkIsComplete, getFailedThunkUrls} from "@welshman/app"
|
||||
import type {Thunk} from "@welshman/app"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Tippy from "@lib/components/Tippy.svelte"
|
||||
import ThunkStatusDetail from "@app/components/ThunkStatusDetail.svelte"
|
||||
import {userSettingValues} from "@app/state"
|
||||
import ThunkFailure from "@app/components/ThunkFailure.svelte"
|
||||
import ThunkPending from "@app/components/ThunkPending.svelte"
|
||||
|
||||
interface Props {
|
||||
thunk: Thunk | MergedThunk
|
||||
class?: string
|
||||
}
|
||||
|
||||
let {thunk, ...restProps}: Props = $props()
|
||||
const {thunk, ...restProps}: Props = $props()
|
||||
|
||||
const abort = () => thunk.controller.abort()
|
||||
|
||||
const retry = () => {
|
||||
thunk = isMergedThunk(thunk)
|
||||
? new MergedThunk(thunk.thunks.map(t => publishThunk(t.options)))
|
||||
: publishThunk(thunk.options)
|
||||
}
|
||||
|
||||
const statuses = $derived(Object.entries($thunk.status))
|
||||
const isSending = $derived(thunkHasStatus($thunk, PublishStatus.Sending))
|
||||
const canCancel = $derived(isSending && $userSettingValues.send_delay > 0)
|
||||
const failedUrls = $derived(
|
||||
statuses
|
||||
.filter(([_, status]) => [PublishStatus.Failure, PublishStatus.Timeout].includes(status))
|
||||
.map(nth(0)),
|
||||
)
|
||||
|
||||
const showFailure = $derived(thunkIsComplete($thunk) && failedUrls.length > 0)
|
||||
|
||||
let isPending = $state(thunkHasStatus($thunk, PublishStatus.Pending))
|
||||
|
||||
const showPending = $derived(canCancel || isPending)
|
||||
|
||||
// Delay updating isPending so users can see that the message is sent
|
||||
$effect(() => {
|
||||
isPending = isPending || thunkHasStatus($thunk, PublishStatus.Pending)
|
||||
|
||||
if (!thunkHasStatus($thunk, PublishStatus.Pending)) {
|
||||
setTimeout(() => {
|
||||
isPending = false
|
||||
}, 2000)
|
||||
}
|
||||
})
|
||||
const showFailure = $derived(thunkIsComplete($thunk) && getFailedThunkUrls($thunk).length > 0)
|
||||
const showPending = $derived(!thunkIsComplete($thunk))
|
||||
</script>
|
||||
|
||||
{#if showFailure}
|
||||
{@const url = failedUrls[0]}
|
||||
{@const status = $thunk.status[url]}
|
||||
{@const message = $thunk.details[url]}
|
||||
<button
|
||||
class="flex w-full justify-end px-1 text-xs {restProps.class}"
|
||||
onclick={stopPropagation(noop)}>
|
||||
<Tippy
|
||||
class="flex items-center"
|
||||
component={ThunkStatusDetail}
|
||||
props={{url, message, status, retry}}
|
||||
params={{interactive: true}}>
|
||||
{#snippet children()}
|
||||
<span class="flex cursor-pointer items-center gap-1 text-error">
|
||||
<Icon icon="danger" size={3} />
|
||||
<span>Failed to send!</span>
|
||||
</span>
|
||||
{/snippet}
|
||||
</Tippy>
|
||||
</button>
|
||||
<ThunkFailure class={restProps.class} {thunk} />
|
||||
{:else if showPending}
|
||||
<div class="flex w-full justify-end px-1 text-xs {restProps.class}">
|
||||
<span class="flex items-center gap-1">
|
||||
<span class="loading loading-spinner mx-1 h-3 w-3 translate-y-px"></span>
|
||||
<span class="opacity-50">Sending...</span>
|
||||
<button
|
||||
type="button"
|
||||
class="underline transition-all"
|
||||
class:link={canCancel}
|
||||
class:opacity-25={!canCancel}
|
||||
onclick={stopPropagation(abort)}>
|
||||
Cancel
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<ThunkPending class={restProps.class} {thunk} />
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user