Skip to content

Commit

Permalink
Creation and Submission delay and status (#457)
Browse files Browse the repository at this point in the history
* add cancelable delay to reply and create note

* final tweaks

* remove note state from event object

* clearInterval on store

* format and check

* missing a status or a callback

* missing import

* use thunk for NoteCreate

* use thunks in replies

* migrate from publishes

* rebase and check

* - get rid of context in Note
- slider to define send_delay

* bring the check back

* use @welshman/app thunks store

* remove callback addToContext

* remove LOCAL_RELAY from statuses

* sign event before sending

* delay configuration in seconds

* remove grouphints store

* loading indicator until event is signed
  • Loading branch information
ticruz38 authored Nov 19, 2024
1 parent 5c2998d commit 6536ca0
Show file tree
Hide file tree
Showing 15 changed files with 334 additions and 150 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ VITE_INDEXER_RELAYS=wss://relay.nostr.band,wss://purplepag.es,wss://relay.damus.
VITE_DEFAULT_FOLLOWS=fe7f6bc6f7338b76bbf80db402ade65953e20b2f23e66e898204b63cc42539a3,f4db5270bd991b17bea1e6d035f45dee392919c29474bbac10342d223c74e0d0,180a6d42c7d64f8c3958d9d10dd5a4117eaaacea8e7f980781e9a53136cf5693,7bdef7be22dd8e59f4600e044aa53a1cf975a9dc7d27df5833bc77db784a5805,676ffea2ec31426a906d7795d7ebae2ba5e61f0b9fa815995b4a299dd085d510,4d5ce768123563bc583697db5e84841fb528f7b708d966f2e546286ce3c72077,eab0e756d32b80bcd464f3d844b8040303075a13eabc3599a762c9ac7ab91f4f,04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9,85080d3bad70ccdcd7f74c29a44f55bb85cbcd3dd0cbb957da1d215bdb931204,74ffc51cc30150cf79b6cb316d3a15cf332ab29a38fec9eb484ab1551d6d1856,93518f91dfa51d8acf39217cdcd3d2ccd178433cb9e72368544aacd7412cb50c,f728d9e6e7048358e70930f5ca64b097770d989ccd86854fe618eda9c8a38106,91c9a5e1a9744114c6fe2d61ae4de82629eaaa0fb52f48288093c7e7e036f832,83e818dfbeccea56b0f551576b3fd39a7a50e1d8159343500368fa085ccd964b,090254801a7e8e5085b02e711622f0dfa1a85503493af246aa42af08f5e4d2df,472f440f29ef996e92a186b8d320ff180c855903882e59d50de1b8bd5669301e,7b3f7803750746f455413a221f80965eecb69ef308f2ead1da89cc2c8912e968,330fb1431ff9d8c250706bbcdc016d5495a3f744e047a408173e92ae7ee42dac,c4eabae1be3cf657bc1855ee05e69de9f059cb7a059227168b80b89761cbc4e0,a4cb51f4618cfcd16b2d3171c466179bed8e197c43b8598823b04de266cef110,f9acb0b034c4c1177e985f14639f317ef0fedee7657c060b146ee790024317ec,6e468422dfb74a5738702a8823b9b28168abab8655faacb6853cd0ee15deee93,e88a691e98d9987c964521dff60025f60700378a4879180dcbbb4a5027850411,6389be6491e7b693e9f368ece88fcd145f07c068d2c1bbae4247b9b5ef439d32,e1ff3bfdd4e40315959b08b4fcc8245eaa514637e1d4ec2ae166b743341be1af,38dbb9b07d93861d40620ad62d44b1a8e8785df0997eeb4454f12d217048cd5c,064de2497ce621aee2a5b4b926a08b1ca01bce9da85b0c714e883e119375140c,aa5e6ccfc7cb7c3431d12b0ea4b83e5b35427602522080a6a8618950527f811b,97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322,676ffea2ec31426a906d7795d7ebae2ba5e61f0b9fa815995b4a299dd085d510,f783ba3b12b91e375aba6594015b90bd95f7e132b03cc8c4c52ce0a7c36aab52,9a4acdeb978565e27490dca65c83e9f65745eaec1d9a0405a52d198c1489913b,e5177ebf513530c2d0924083b64b7eadd7fb85efcc3e4dfb55c73a924c901ca7,5b0183ab6c3e322bf4d41c6b3aef98562a144847b7499543727c5539a114563e,958b754a1d3de5b5eca0fe31d2d555f451325f8498a83da1997b7fcd5c39e88c,5c508c34f58866ec7341aaf10cc1af52e9232bb9f859c8103ca5ecf2aa93bf78,26bd32c67232bdf16d05e763ec67d883015eb99fd1269025224c20c6cfdb0158,d307643547703537dfdef811c3dea96f1f9e84c8249e200353425924a9908cf8,604e96e099936a104883958b040b47672e0f048c98ac793f37ffe4c720279eb2,90b9bec74789688e515125596ab6350bfe646176ac75742275063922c5fea010,baf27a4cc4da49913e7fdecc951fd3b971c9279959af62b02b761a043c33384c,2edbcea694d164629854a52583458fd6d965b161e3c48b57d3aff01940558884,82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2,66bd8fed3590f2299ef0128f58d67879289e6a99a660e83ead94feab7606fd17,eeb11961b25442b16389fe6c7ebea9adf0ac36dd596816ea7119e521b8821b9e,61066504617ee79387021e18c89fb79d1ddbc3e7bff19cf2298f40466f8715e9,1bc70a0148b3f316da33fe3c89f23e3e71ac4ff998027ec712b905cd24f6a411,a9434ee165ed01b286becfc2771ef1705d3537d051b387288898cc00d5c885be,ee6ea13ab9fe5c4a68eaf9b1a34fe014a66b40117c50ee2a614f4cda959b6e74,7bdef7be22dd8e59f4600e044aa53a1cf975a9dc7d27df5833bc77db784a5805,1577e4599dd10c863498fe3c20bd82aafaf829a595ce83c5cf8ac3463531b09b,1739d937dc8c0c7370aa27585938c119e25c41f6c441a5d34c6d38503e3136ef,fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52,cc8d072efdcc676fcbac14f6cd6825edc3576e55eb786a2a975ee034a6a026cb,d91191e30e00444b942c0e82cad470b32af171764c2275bee0bd99377efd4075,3335d373e6c1b5bc669b4b1220c08728ea8ce622e5a7cfeeb4c0001d91ded1de,0b118e40d6f3dfabb17f21a94a647701f140d8b063a9e84fe6e483644edc09cb,b83a28b7e4e5d20bd960c5faeb6625f95529166b8bdb045d42634a2f35919450,958b754a1d3de5b5eca0fe31d2d555f451325f8498a83da1997b7fcd5c39e88c,a4cb51f4618cfcd16b2d3171c466179bed8e197c43b8598823b04de266cef110,e56e7b4326618f3d626c0e398f5082c3b16732e469e0a048b7ddb544c2be294a,011c1b374c12fbd3633e98957d3c46bed67983abecef50706c73a77c171d0d2c,b9e76546ba06456ed301d9e52bc49fa48e70a6bf2282be7a1ae72947612023dc,b708f7392f588406212c3882e7b3bc0d9b08d62f95fa170d099127ece2770e5e,5c508c34f58866ec7341aaf10cc1af52e9232bb9f859c8103ca5ecf2aa93bf78,baf27a4cc4da49913e7fdecc951fd3b971c9279959af62b02b761a043c33384c,2edbcea694d164629854a52583458fd6d965b161e3c48b57d3aff01940558884,0fecf65daa26faf3f668e8143325a4c199a040b6345ed40a08614d7dd85b1823,1bc70a0148b3f316da33fe3c89f23e3e71ac4ff998027ec712b905cd24f6a411,f783ba3b12b91e375aba6594015b90bd95f7e132b03cc8c4c52ce0a7c36aab52,3f770d65d3a764a9c5cb503ae123e62ec7598ad035d836e2a810f3877a745b24,82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2,3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d,ee11a5dff40c19a555f41fe42b48f00e618c91225622ae37b6c2bb67b76c4e49,eab0e756d32b80bcd464f3d844b8040303075a13eabc3599a762c9ac7ab91f4f,58c741aa630c2da35a56a77c1d05381908bd10504fdd2d8b43f725efa6d23196,84dee6e676e5bb67b4ad4e042cf70cbd8681155db535942fcc6a0533858a7240,33bd77e5394520747faae1394a4af5fa47f404389676375b6dc7be865ed81452,21335073401a310cc9179fe3a77e9666710cfdf630dfd840f972c183a244b1ad,36732cc35fe56185af1b11160a393d6c73a1fe41ddf1184c10394c28ca5d627b,3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d,fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52,32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245,63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed,97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322,00000000827ffaa94bfea288c3dfce4422c794fbb96625b6b31e9049f729d700,3f770d65d3a764a9c5cb503ae123e62ec7598ad035d836e2a810f3877a745b24,e88a691e98d9987c964521dff60025f60700378a4879180dcbbb4a5027850411,82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2,e8ed3798c6ffebffa08501ac39e271662bfd160f688f94c45d692d8767dd345a,c5fb6ecc876e0458e3eca9918e370cbcd376901c58460512fe537a46e58c38bb,40b9c85fffeafc1cadf8c30a4e5c88660ff6e4971a0dc723d5ab674b5e61b451,a3eb29554bd27fca7f53f66272e4bb59d066f2f31708cf341540cb4729fbd841,460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c,0000005f87f64341c212cc93d6c266c03ae752c02660e78a6da1424f7b05c470,d61f3bc5b3eb4400efdae6169a5c17cabf3246b514361de939ce4a1a0da6ef4a,1739d937dc8c0c7370aa27585938c119e25c41f6c441a5d34c6d38503e3136ef,7adb520c3ac7cb6dc8253508df0ce1d975da49fefda9b5c956744a049d230ace,3335d373e6c1b5bc669b4b1220c08728ea8ce622e5a7cfeeb4c0001d91ded1de,266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5,17717ad4d20e2a425cda0a2195624a0a4a73c4f6975f16b1593fc87fa46f2d58,af9d70407464247d19fd243cf1bee81e6df1e639217dc66366bf37aa42d05d35,ddf03aca85ade039e6742d5bef3df352df199d0d31e22b9858e7eda85cb3bbbe,d36e8083fa7b36daee646cb8b3f99feaa3d89e5a396508741f003e21ac0b6bec,7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194,cc8d072efdcc676fcbac14f6cd6825edc3576e55eb786a2a975ee034a6a026cb,d91191e30e00444b942c0e82cad470b32af171764c2275bee0bd99377efd4075,3d842afecd5e293f28b6627933704a3fb8ce153aa91d790ab11f6a752d44a42d,79c2cae114ea28a981e7559b4fe7854a473521a8d22a66bbab9fa248eb820ff6,17538dc2a62769d09443f18c37cbe358fab5bbf981173542aa7c5ff171ed77c4,ff27d01cb1e56fb58580306c7ba76bb037bf211c5b573c56e4e70ca858755af0,8fb140b4e8ddef97ce4b821d247278a1a4353362623f64021484b372f948000c,27797bd4e5ee52db0a197668c92b9a3e7e237e1f9fa73a10c38d731c294cfc9a,7cc328a08ddb2afdf9f9be77beff4c83489ff979721827d628a542f32a247c0e,c35ff8c340449f0d68af1aec4844bb44a9c0b8c1dd4f4d4efbc65e12039a348a,1bc70a0148b3f316da33fe3c89f23e3e71ac4ff998027ec712b905cd24f6a411,fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52,3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d,0b118e40d6f3dfabb17f21a94a647701f140d8b063a9e84fe6e483644edc09cb,2edbcea694d164629854a52583458fd6d965b161e3c48b57d3aff01940558884,1739d937dc8c0c7370aa27585938c119e25c41f6c441a5d34c6d38503e3136ef,eab0e756d32b80bcd464f3d844b8040303075a13eabc3599a762c9ac7ab91f4f,dace63b00c42e6e017d00dd190a9328386002ff597b841eb5ef91de4f1ce8491,76c71aae3a491f1d9eec47cba17e229cda4113a0bbb6e6ae1776d7643e29cafa,266815e0c9210dfa324c6cba3573b14bee49da4209a9456f9484e5106cd408a5,d91191e30e00444b942c0e82cad470b32af171764c2275bee0bd99377efd4075,7a3288f5b2a382317ddcbab9c0b6e9a22a999a064dfb9b7284508a0da3fa9114,6a72db8ef3f3b9ee5ecd808ed6d0631d1e4dda5c5dadf07887104d33957eba48
VITE_ONBOARDING_LISTS="30000:97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322:3121977322800018,30000:97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322:680038570738458,30000:97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322:33178290670580934,30000:97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322:49330924355910266,30000:97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322:9358486925304412,30000:97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322:3151213286926533"
VITE_NIP96_URLS=https://nostr.build,https://nostrcheck.me,https://sove.rent,https://void.cat
VITE_BLOSSOM_URLS=https://cdn.satellite.earth,https://blossom.hzrd149.com,https://blossom.f7z.io,https://void.cat
VITE_IMGPROXY_URL=https://imgproxy.coracle.social
VITE_DUFFLEPUD_URL=https://dufflepud.onrender.com
VITE_PLATFORM_ZAP_SPLIT=0
Expand Down
14 changes: 8 additions & 6 deletions src/app/MenuDesktop.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import {seconds} from "hurdak"
import {derived} from "svelte/store"
import {derived, get} from "svelte/store"
import {now} from "@welshman/lib"
import {PublishStatus} from "@welshman/net"
import {
Expand All @@ -9,6 +9,8 @@
sessions,
deriveProfileDisplay,
displayProfileByPubkey,
thunks,
type Thunk,
} from "@welshman/app"
import {toggleTheme, theme} from "src/partials/state"
import MenuItem from "src/partials/MenuItem.svelte"
Expand All @@ -20,21 +22,21 @@
import MenuDesktopSecondary from "src/app/MenuDesktopSecondary.svelte"
import {slowConnections} from "src/app/state"
import {router} from "src/app/util/router"
import {env, hasNewMessages, hasNewNotifications, publishes} from "src/engine"
import {env, hasNewMessages, hasNewNotifications} from "src/engine"
const {page} = router
const hud = derived(publishes, $publishes => {
const hud = derived(thunks, $thunks => {
const pending = []
const success = []
const failure = []
for (const {created_at, request, status} of Object.values($publishes)) {
if (created_at < now() - seconds(5, "minute")) {
for (const {event, request, status} of Object.values($thunks) as Thunk[]) {
if (event.created_at < now() - seconds(5, "minute")) {
continue
}
const statuses = Array.from(status.values())
const statuses = Object.values(get(status)).map(s => s.status)
if (statuses.includes(PublishStatus.Success)) {
success.push(request.event)
Expand Down
74 changes: 40 additions & 34 deletions src/app/shared/Note.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
getAncestorTagValues,
} from "@welshman/util"
import {repository, deriveZapperForPubkey, deriveZapper} from "@welshman/app"
import {identity, reject, whereEq, uniqBy, prop} from "ramda"
import {deriveEvents} from "@welshman/store"
import {identity, uniqBy, prop} from "ramda"
import {onMount} from "svelte"
import {quantify, batch} from "hurdak"
import {quantify} from "hurdak"
import {fly, slide} from "src/util/transition"
import {replyKinds, isLike} from "src/util/nostr"
import {formatTimestamp} from "src/util/misc"
import {formatTimestamp, timestamp1} from "src/util/misc"
import Popover from "src/partials/Popover.svelte"
import AltColor from "src/partials/AltColor.svelte"
import Spinner from "src/partials/Spinner.svelte"
Expand All @@ -30,6 +31,7 @@
import NoteReply from "src/app/shared/NoteReply.svelte"
import NoteActions from "src/app/shared/NoteActions.svelte"
import NoteContent from "src/app/shared/NoteContent.svelte"
import NotePending from "src/app/shared/NotePending.svelte"
import {router} from "src/app/util/router"
import {
env,
Expand All @@ -50,6 +52,8 @@
export let anchor = null
export let topLevel = false
export let isLastReply = false
export let isDraft = false
export let removeDraftCb = null
export let showParent = true
export let showLoading = false
export let showHidden = false
Expand All @@ -60,14 +64,19 @@
let replyCtrl = null
let replyIsActive = false
let showMutedReplies = false
let actions = null
let collapsed = depth === 0
let context = repository.query([{"#e": [event.id]}]).filter(e => isChildOf(e, event))
let showHiddenReplies = anchor === getIdOrAddress(event)
let draftEventId: string
let removeDraft: () => void
const showEntire = showHiddenReplies
const interactive = !anchor || !showEntire
const addDraftToContext = (event, cb) => {
draftEventId = event.id
removeDraft = () => cb() && repository.removeEvent(event.id)
}
const onClick = e => {
const target = (e.detail?.target || e.target) as HTMLElement
Expand Down Expand Up @@ -100,13 +109,9 @@
.at("thread")
.open()
const removeFromContext = e => {
context = reject(whereEq({id: e.id}), context)
}
const addToContext = events => {
context = context.concat(events)
}
const context = deriveEvents(repository, {
filters: [{"#e": [event.id]}],
})
$: ancestors = getAncestorTagValues(event.tags || [])
$: reply = ancestors.replies[0]
Expand All @@ -117,8 +122,7 @@
$: hidden = $isEventMuted(event, true)
// Find children in our context
$: children = context.filter(e => isChildOf(e, event))
$: children = $context.filter(e => isChildOf(e, event))
// Sort our replies
$: replies = sortEventsDesc(children.filter(e => replyKinds.includes(e.kind)))
Expand All @@ -134,7 +138,12 @@
mutedReplies.push(e)
} else if (collapsed) {
hiddenReplies.push(e)
} else if (!showHiddenReplies && filters && !matchFilters(filters, e)) {
} else if (
!showHiddenReplies &&
filters &&
!matchFilters(filters, e) &&
draftEventId !== e.id
) {
hiddenReplies.push(e)
} else {
visibleReplies.push(e)
Expand Down Expand Up @@ -200,9 +209,6 @@
load({
relays: ctx.app.router.Replies(event).getUrls(),
filters: getReplyFilters([event], {kinds}),
onEvent: batch(200, events => {
context = uniqBy(prop("id"), context.concat(events))
}),
})
}
})
Expand Down Expand Up @@ -284,18 +290,19 @@
<NoteContent note={event} {showEntire} {showMedia} />
{/if}
<div class="cy-note-click-target h-[2px]" />
<NoteActions
note={event}
zapper={$zapper}
bind:this={actions}
{removeFromContext}
{addToContext}
{replyCtrl}
{showHidden}
{replies}
{likes}
{zaps}
{muted} />
{#if !isDraft || event.created_at < $timestamp1 - 45}
<NoteActions
note={event}
zapper={$zapper}
{replyCtrl}
{showHidden}
{replies}
{likes}
{zaps}
{muted} />
{:else}
<NotePending {event} removeDraft={removeDraftCb} />
{/if}
</div>
</div>
</Card>
Expand Down Expand Up @@ -327,7 +334,7 @@
{/if}

<NoteReply
{addToContext}
{addDraftToContext}
parent={event}
showBorder={visibleReplies.length > 0}
bind:this={replyCtrl}
Expand All @@ -336,9 +343,6 @@
}}
on:reset={() => {
replyIsActive = false
}}
on:event={e => {
context = [e.detail, ...context]
}} />

{#if visibleReplies.length > 0 || hiddenReplies.length > 0 || mutedReplies.length > 0}
Expand Down Expand Up @@ -369,6 +373,8 @@
isLastReply={i === visibleReplies.length - 1}
showParent={false}
showHidden
isDraft={r.id === draftEventId}
removeDraftCb={removeDraft}
note={r}
depth={depth - 1}
{filters}
Expand Down
8 changes: 1 addition & 7 deletions src/app/shared/NoteActions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@
export let muted
export let replyCtrl
export let showHidden
export let addToContext
export let removeFromContext
export let replies, likes, zaps
export let zapper
Expand Down Expand Up @@ -116,14 +114,11 @@
const tags = [...tagReactionTo(note), ...getClientTags()]
const template = createEvent(7, {content, tags})
const pub = await signAndPublish(template)
addToContext(pub.request.event)
await signAndPublish(template)
}
const deleteReaction = e => {
deleteEvent(e)
removeFromContext(e)
}
const startZap = () => {
Expand All @@ -138,7 +133,6 @@
id: note.id,
anonymous: Boolean(note.wrap),
})
.cx({callback: addToContext})
.open()
}
Expand Down
91 changes: 91 additions & 0 deletions src/app/shared/NotePending.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<style>
.loading-bar {
position: absolute;
top: 0;
left: 0;
height: 100%;
}
div.loading-bar::after {
content: "";
position: absolute;
top: 0;
right: -50px;
width: 50px;
height: 100%;
background: linear-gradient(to left, rgba(0, 0, 0, 0), var(--accent));
}
.loading-bar-content > * {
z-index: 1;
}
</style>

<script lang="ts">
import {thunks, type Thunk} from "@welshman/app"
import {PublishStatus} from "@welshman/net"
import {LOCAL_RELAY_URL, type SignedEvent} from "@welshman/util"
import {userSettings} from "src/engine"
import Anchor from "src/partials/Anchor.svelte"
import {timestamp1} from "src/util/misc"
import {spring} from "svelte/motion"
export let event: SignedEvent
export let removeDraft: () => void
$: thunk = $thunks[event.id] as Thunk
$: status = thunk?.status
$: relays = thunk?.request?.relays.filter(r => r !== LOCAL_RELAY_URL)
$: statuses = Object.entries($status || {})
.filter(([k, v]) => k !== LOCAL_RELAY_URL)
.map(([k, v]) => v)
$: pendings = statuses.filter(s => s.status === PublishStatus.Pending).length
$: failed = statuses.filter(
s => s.status === PublishStatus.Failure || s.status === PublishStatus.Aborted,
).length
$: timeout = statuses.filter(s => s.status === PublishStatus.Timeout).length
$: success = statuses.filter(s => s.status === PublishStatus.Success).length
$: total = relays.length || 0
const completed = spring(0)
$: {
if (thunk) {
$completed = ((total - pendings) / total) * 100
}
}
$: isPending = pendings > 0
$: isCompleted = total === success + failed + timeout
</script>

<div
class="loading-bar-content relative flex h-6 w-full items-center justify-between overflow-hidden rounded-md pl-4 text-sm"
class:border={!thunk}
on:click|stopPropagation>
{#if thunk && (isPending || isCompleted)}
<div class="loading-bar bg-accent" style="width: {$completed}%"></div>
{#if isPending}
<span>Publishing...</span>
<span>{total - pendings} of {total} relays</span>
{:else}
<span>Published to {success}/{total} ({failed} failed, {timeout} timed out)</span>
<Anchor
class="staatliches z-feature rounded-r-md bg-tinted-100-d px-4 py-1 uppercase text-tinted-700-d"
modal
href="/publishes">See details</Anchor>
{/if}
{:else if $userSettings.send_delay > 0}
<span
>Sending reply in {event.created_at +
Math.ceil($userSettings.send_delay / 1000) -
$timestamp1} seconds</span>

<button
class="ml-2 cursor-pointer rounded-md bg-neutral-100-d px-4 py-1 text-tinted-700-d"
on:click={() => {
removeDraft()
}}>Cancel</button>
{/if}
</div>
Loading

0 comments on commit 6536ca0

Please sign in to comment.