forked from coracle/flotilla
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b6b8145901 | |||
| cdc9f927b5 | |||
| 4d57e4e6ed | |||
| 1b8d6e50e2 |
@@ -12,6 +12,7 @@ if (execSync('git status --porcelain', { encoding: 'utf8' }).trim() && !force) {
|
||||
|
||||
const pkg = JSON.parse(fs.readFileSync('./package.json', 'utf8'))
|
||||
|
||||
pkg.pnpm = pkg.pnpm || {}
|
||||
pkg.pnpm.overrides = pkg.pnpm.overrides || {}
|
||||
pkg.pnpm.overrides["@welshman/app"] = "link:../welshman/packages/app"
|
||||
pkg.pnpm.overrides["@welshman/content"] = "link:../welshman/packages/content"
|
||||
|
||||
@@ -262,12 +262,6 @@ app.use(
|
||||
// SPA fallback for routes that don't match static files
|
||||
app.get("*", async context => {
|
||||
const requestUrl = requestUrlFromContext(context)
|
||||
|
||||
// If the path has an extension, it's likely a missing static asset, not an SPA route
|
||||
if (path.extname(requestUrl.pathname)) {
|
||||
return context.text("Not found", 404)
|
||||
}
|
||||
|
||||
const metadata = await getMetadataForRoute(requestUrl)
|
||||
const html = metadata ? injectMeta(metadata) : TEMPLATE_HTML
|
||||
|
||||
|
||||
@@ -280,7 +280,7 @@
|
||||
</div>
|
||||
</PageBar>
|
||||
|
||||
<PageContent class="flex flex-col-reverse gap-2 py-4">
|
||||
<PageContent class="flex flex-col-reverse gap-2 py-2 !mb-0">
|
||||
{#if missingRelayLists.length > 0}
|
||||
<div class="py-12">
|
||||
<div class="card2 col-2 m-auto max-w-md items-center text-center">
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
<input bind:value={term} class="grow" type="text" placeholder="Search for relays..." />
|
||||
</label>
|
||||
<div class="column -m-6 mt-0 h-[50vh] gap-2 overflow-auto p-6 pt-2" bind:this={element}>
|
||||
{#if customUrl && isShareableRelayUrl(customUrl) && !$relays.includes(normalizeRelayUrl(customUrl))}
|
||||
{#if customUrl && isShareableRelayUrl(customUrl) && !$relays.includes(customUrl)}
|
||||
<RelayItem url={term}>
|
||||
<Button
|
||||
class="btn btn-outline btn-sm flex items-center"
|
||||
|
||||
@@ -45,20 +45,11 @@
|
||||
event: TrustedEvent
|
||||
replyTo?: (event: TrustedEvent) => void
|
||||
showPubkey?: boolean
|
||||
addSpaceBelow?: boolean
|
||||
canEdit: (event: TrustedEvent) => boolean
|
||||
onEdit: (event: TrustedEvent) => void
|
||||
}
|
||||
|
||||
const {
|
||||
url,
|
||||
event,
|
||||
replyTo = undefined,
|
||||
showPubkey = false,
|
||||
addSpaceBelow = false,
|
||||
canEdit,
|
||||
onEdit,
|
||||
}: Props = $props()
|
||||
const {url, event, replyTo = undefined, showPubkey = false, canEdit, onEdit}: Props = $props()
|
||||
|
||||
const path = getRoomItemPath(url, event)
|
||||
const shouldProtect = canEnforceNip70(url)
|
||||
@@ -95,7 +86,7 @@
|
||||
{onTap}
|
||||
class={cx(
|
||||
"group relative flex w-full cursor-default flex-col px-2 py-0.5 text-left hover:bg-base-100/50",
|
||||
{"mt-1.5": showPubkey, "mb-1.5": addSpaceBelow},
|
||||
{"mt-1.5": showPubkey},
|
||||
)}>
|
||||
<div class="flex w-full gap-3 overflow-auto">
|
||||
{#if showPubkey}
|
||||
@@ -127,7 +118,7 @@
|
||||
<div class:mt-2={showPubkey && event.kind !== MESSAGE}>
|
||||
<RoomItemContent {url} event={$innerEvent ?? event} />
|
||||
{#if thunk}
|
||||
<ThunkFailure showToastOnRetry {thunk} class="mt-2 text-sm" />
|
||||
<ThunkFailure showToastOnRetry {thunk} class="mt-1 flex justify-end" />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import {stopPropagation} from "svelte/legacy"
|
||||
import {noop} from "@welshman/lib"
|
||||
import type {AbstractThunk} from "@welshman/app"
|
||||
import {retryThunk, thunkIsComplete, getFailedThunkUrls} from "@welshman/app"
|
||||
import {flattenThunks, getFailedThunkUrls, publishThunk, thunkIsComplete} from "@welshman/app"
|
||||
import Danger from "@assets/icons/danger-triangle.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Tippy from "@lib/components/Tippy.svelte"
|
||||
@@ -16,40 +16,45 @@
|
||||
class?: string
|
||||
}
|
||||
|
||||
let {thunk, showToastOnRetry, ...restProps}: Props = $props()
|
||||
const {thunk, showToastOnRetry, ...restProps}: Props = $props()
|
||||
|
||||
const retry = () => {
|
||||
thunk = retryThunk(thunk)
|
||||
const showFailure = $derived(thunkIsComplete($thunk) && getFailedThunkUrls($thunk).length > 0)
|
||||
|
||||
if (showToastOnRetry) {
|
||||
pushToast({
|
||||
timeout: 30_000,
|
||||
children: {
|
||||
component: ThunkToast,
|
||||
props: {thunk},
|
||||
},
|
||||
})
|
||||
const retry = (url: string) => {
|
||||
for (const child of flattenThunks([thunk])) {
|
||||
if (!child.options.relays.includes(url)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const retried = publishThunk({...child.options, relays: [url]})
|
||||
|
||||
if (showToastOnRetry) {
|
||||
pushToast({
|
||||
timeout: 30_000,
|
||||
children: {
|
||||
component: ThunkToast,
|
||||
props: {thunk: retried},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const failedUrls = $derived(getFailedThunkUrls($thunk))
|
||||
const showFailure = $derived(thunkIsComplete($thunk) && failedUrls.length > 0)
|
||||
</script>
|
||||
|
||||
{#if showFailure}
|
||||
{@const url = failedUrls[0]}
|
||||
{@const {status, detail: message} = $thunk.results[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}}>
|
||||
props={{thunk, retry}}
|
||||
params={{interactive: true, maxWidth: "none"}}>
|
||||
{#snippet children()}
|
||||
<span class="flex cursor-pointer items-center gap-1 text-error">
|
||||
<Icon icon={Danger} size={3} />
|
||||
<span class="flex cursor-pointer items-center gap-1 opacity-75">
|
||||
<Icon icon={Danger} class="text-error" size={3} />
|
||||
<span>Failed to send!</span>
|
||||
</span>
|
||||
{/snippet}
|
||||
|
||||
@@ -6,17 +6,18 @@
|
||||
|
||||
interface Props {
|
||||
thunk: AbstractThunk
|
||||
showToastOnRetry?: boolean
|
||||
class?: string
|
||||
}
|
||||
|
||||
const {thunk, ...restProps}: Props = $props()
|
||||
const {thunk, showToastOnRetry, ...restProps}: Props = $props()
|
||||
|
||||
const showFailure = $derived(thunkIsComplete($thunk) && getFailedThunkUrls($thunk).length > 0)
|
||||
const showPending = $derived(!thunkIsComplete($thunk))
|
||||
</script>
|
||||
|
||||
{#if showFailure}
|
||||
<ThunkFailure class={restProps.class} {thunk} />
|
||||
<ThunkFailure class={restProps.class} {thunk} {showToastOnRetry} />
|
||||
{:else if showPending}
|
||||
<ThunkPending class={restProps.class} {thunk} />
|
||||
{/if}
|
||||
|
||||
@@ -1,32 +1,69 @@
|
||||
<script lang="ts">
|
||||
import {stopPropagation} from "svelte/legacy"
|
||||
import type {AbstractThunk} from "@welshman/app"
|
||||
import {getFailedThunkUrls, getThunkUrlsWithStatus} from "@welshman/app"
|
||||
import {PublishStatus} from "@welshman/net"
|
||||
import {displayRelayUrl} from "@welshman/util"
|
||||
import CheckCircle from "@assets/icons/check-circle.svg?dataurl"
|
||||
import Danger from "@assets/icons/danger-triangle.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import {addPeriod} from "@lib/util"
|
||||
|
||||
interface Props {
|
||||
url: string
|
||||
status: string
|
||||
message: string
|
||||
retry: () => void
|
||||
thunk: AbstractThunk
|
||||
retry: (url: string) => void
|
||||
}
|
||||
|
||||
let {url, status, message = $bindable(), retry}: Props = $props()
|
||||
const {thunk, retry}: Props = $props()
|
||||
|
||||
$effect(() => {
|
||||
if (!message && status === PublishStatus.Timeout) {
|
||||
message = "request timed out"
|
||||
const successUrls = $derived(getThunkUrlsWithStatus(PublishStatus.Success, $thunk))
|
||||
const failedUrls = $derived(getFailedThunkUrls($thunk))
|
||||
const total = $derived(successUrls.length + failedUrls.length)
|
||||
const isPartial = $derived(successUrls.length > 0 && failedUrls.length > 0)
|
||||
|
||||
const title = $derived(
|
||||
isPartial ? `Partial delivery ${successUrls.length}/${total} relays` : "Failed to send!",
|
||||
)
|
||||
|
||||
const relayMessage = (status: PublishStatus | undefined, detail: string | undefined) => {
|
||||
if (detail) {
|
||||
return detail
|
||||
}
|
||||
|
||||
if (!message) {
|
||||
message = "no details recieved"
|
||||
if (status === PublishStatus.Timeout) {
|
||||
return "request timed out"
|
||||
}
|
||||
})
|
||||
|
||||
return "no details received"
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="card2 bg-alt col-2 shadow-lg">
|
||||
<p>
|
||||
Failed to publish to {displayRelayUrl(url)}: {addPeriod(message)}
|
||||
</p>
|
||||
<Button class="link" onclick={retry}>Retry</Button>
|
||||
<div class="card2 bg-alt flex min-w-72 max-w-sm flex-col gap-3 px-4 py-3 shadow-lg">
|
||||
<span class="flex items-center gap-2 text-sm font-medium">
|
||||
<Icon icon={Danger} class="text-error" size={4} />
|
||||
{title}
|
||||
</span>
|
||||
<div class="divider my-0"></div>
|
||||
<div class="flex flex-col gap-3">
|
||||
{#each successUrls as url (url)}
|
||||
<div class="flex items-start gap-2 text-sm">
|
||||
<Icon icon={CheckCircle} class="mt-0.5 shrink-0 text-success" size={4} />
|
||||
<span>{displayRelayUrl(url)}</span>
|
||||
</div>
|
||||
{/each}
|
||||
{#each failedUrls as url (url)}
|
||||
{@const {detail, status} = $thunk.results[url] || {}}
|
||||
<div class="grid grid-cols-[1rem_1fr_auto] items-start gap-x-3 gap-y-1 text-sm">
|
||||
<Icon icon={Danger} class="mt-0.5 text-error" size={4} />
|
||||
<div class="min-w-0">
|
||||
<p class="break-all">{displayRelayUrl(url)}</p>
|
||||
<p class="text-xs opacity-60">{addPeriod(relayMessage(status, detail))}</p>
|
||||
</div>
|
||||
<Button class="link shrink-0 px-1" onclick={stopPropagation(() => retry(url))}>
|
||||
Retry
|
||||
</Button>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -755,7 +755,7 @@ export const getSpaceUrlsFromGroupList = (groupList: List | undefined) => {
|
||||
}
|
||||
}
|
||||
|
||||
return uniq(urls.map(normalizeRelayUrl))
|
||||
return uniqBy(normalizeRelayUrl, urls)
|
||||
}
|
||||
|
||||
export const getSpaceRoomsFromGroupList = (url: string, groupList: List | undefined) => {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
const className = $derived(
|
||||
cx(
|
||||
props.class,
|
||||
"scroll-container z-feature flex min-h-0 w-full min-w-0 flex-col overflow-y-auto overflow-x-hidden pb-14 md:pb-0",
|
||||
"scroll-container z-feature flex flex-col min-h-0 w-full min-w-0 overflow-y-auto overflow-x-hidden mb-14 md:mb-0",
|
||||
),
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -254,7 +254,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</PageBar>
|
||||
<PageContent class="flex flex-col gap-2 p-2 pt-4">
|
||||
<PageContent class="flex flex-col gap-2 p-2">
|
||||
<div class="flex flex-col gap-2" bind:this={element}>
|
||||
{#each PLATFORM_RELAYS as url (url)}
|
||||
<Button
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
<script lang="ts">
|
||||
import type {Snippet} from "svelte"
|
||||
import {get} from "svelte/store"
|
||||
import {page} from "$app/stores"
|
||||
import {once} from "@welshman/lib"
|
||||
import {pubkey} from "@welshman/app"
|
||||
import Page from "@lib/components/Page.svelte"
|
||||
import SecondaryNav from "@lib/components/SecondaryNav.svelte"
|
||||
import SpaceMenu from "@app/components/SpaceMenu.svelte"
|
||||
import SpaceAuthError from "@app/components/SpaceAuthError.svelte"
|
||||
import SpaceTrustRelay from "@app/components/SpaceTrustRelay.svelte"
|
||||
import SpaceJoin from "@app/components/SpaceJoin.svelte"
|
||||
import {pushModal} from "@app/util/modal"
|
||||
import {makeSpacePath} from "@app/util/routes"
|
||||
import {decodeRelay, relaysPendingTrust, userSpaceUrls, loadUserGroupList} from "@app/core/state"
|
||||
import {decodeRelay, relaysPendingTrust} from "@app/core/state"
|
||||
import {deriveRelayAuthError} from "@app/core/commands"
|
||||
|
||||
type Props = {
|
||||
@@ -31,8 +28,6 @@
|
||||
|
||||
const showPendingTrust = once(() => pushModal(SpaceTrustRelay, {url}, {noEscape: true}))
|
||||
|
||||
const joinPrompted = new Set<string>()
|
||||
|
||||
// Watch for relay errors and notify the user
|
||||
$effect(() => {
|
||||
if ($authError) {
|
||||
@@ -41,49 +36,6 @@
|
||||
showPendingTrust()
|
||||
}
|
||||
})
|
||||
|
||||
// Direct links skip Discover — prompt to join when relay is not in the user's space list.
|
||||
$effect(() => {
|
||||
const spaceUrl = url
|
||||
const currentPubkey = get(pubkey)
|
||||
|
||||
if (!currentPubkey) {
|
||||
return
|
||||
}
|
||||
|
||||
if ($userSpaceUrls.includes(spaceUrl) || $authError || $relaysPendingTrust.includes(spaceUrl)) {
|
||||
return
|
||||
}
|
||||
|
||||
let cancelled = false
|
||||
|
||||
void loadUserGroupList().then(() => {
|
||||
if (cancelled) {
|
||||
return
|
||||
}
|
||||
|
||||
if (get(pubkey) !== currentPubkey) {
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
get(userSpaceUrls).includes(spaceUrl) ||
|
||||
get(authError) ||
|
||||
get(relaysPendingTrust).includes(spaceUrl) ||
|
||||
joinPrompted.has(spaceUrl)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
joinPrompted.add(spaceUrl)
|
||||
pushModal(SpaceJoin, {url: spaceUrl})
|
||||
})
|
||||
|
||||
return () => {
|
||||
cancelled = true
|
||||
joinPrompted.delete(spaceUrl)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if $page.url.pathname === makeSpacePath(url)}
|
||||
|
||||
@@ -350,16 +350,11 @@
|
||||
event.created_at - previousCreatedAt > int(3, MINUTE) ||
|
||||
previousKind === ROOM_ADD_MEMBER
|
||||
|
||||
if (showPubkey && elements.length > 0) {
|
||||
elements[elements.length - 1].addSpaceBelow = true
|
||||
}
|
||||
|
||||
elements.push({
|
||||
id: event.id,
|
||||
type: "note",
|
||||
value: event,
|
||||
showPubkey,
|
||||
addSpaceBelow: false,
|
||||
})
|
||||
|
||||
previousDate = date
|
||||
@@ -368,9 +363,6 @@
|
||||
previousCreatedAt = event.created_at
|
||||
seen.add(event.id)
|
||||
}
|
||||
if (elements.length > 0) {
|
||||
elements[elements.length - 1].addSpaceBelow = true
|
||||
}
|
||||
}
|
||||
|
||||
elements.reverse()
|
||||
@@ -470,7 +462,7 @@
|
||||
bind:element
|
||||
onscroll={onScroll}
|
||||
class={cx(
|
||||
"flex-col-reverse pb-0! pt-4",
|
||||
"flex-col-reverse !mb-0",
|
||||
showMobileVideoPanel ? "hidden md:flex md:flex-col-reverse" : "flex",
|
||||
pageContentHiddenDesktopVideoOnly && "md:hidden",
|
||||
)}>
|
||||
@@ -501,7 +493,7 @@
|
||||
<Spinner loading={loadingForward}>Looking for messages...</Spinner>
|
||||
</p>
|
||||
{/if}
|
||||
{#each elements as { type, id, value, showPubkey, addSpaceBelow }, i (id)}
|
||||
{#each elements as { type, id, value, showPubkey }, i (id)}
|
||||
{#if type === "new-messages"}
|
||||
<div
|
||||
{id}
|
||||
@@ -523,7 +515,6 @@
|
||||
{event}
|
||||
{replyTo}
|
||||
{showPubkey}
|
||||
{addSpaceBelow}
|
||||
canEdit={canEditEvent}
|
||||
onEdit={onEditEvent} />
|
||||
{/if}
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
{/snippet}
|
||||
</SpaceBar>
|
||||
|
||||
<PageContent bind:element class="flex flex-col gap-2 p-2 pt-4">
|
||||
<PageContent bind:element class="flex flex-col gap-2 p-2">
|
||||
{#each items as { event, dateDisplay, isFirstFutureEvent }, i (event.id)}
|
||||
<div class={"calendar-event-" + event.id}>
|
||||
{#if isFirstFutureEvent}
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
{/snippet}
|
||||
</SpaceBar>
|
||||
|
||||
<PageContent class="flex flex-col gap-3 p-2 pt-4">
|
||||
<PageContent class="flex flex-col gap-3 p-2">
|
||||
{#if $event}
|
||||
<div class="card2 bg-alt col-3 z-feature">
|
||||
<div class="flex items-start gap-4">
|
||||
@@ -109,10 +109,12 @@
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
{#await sleep(5000)}
|
||||
<Spinner loading>Loading comments...</Spinner>
|
||||
{:then}
|
||||
<p>Failed to load comments.</p>
|
||||
{/await}
|
||||
<div class="flex justify-center py-20">
|
||||
{#await sleep(5000)}
|
||||
<Spinner loading>Loading event...</Spinner>
|
||||
{:then}
|
||||
<p>Failed to load event.</p>
|
||||
{/await}
|
||||
</div>
|
||||
{/if}
|
||||
</PageContent>
|
||||
|
||||
@@ -227,16 +227,11 @@
|
||||
event.created_at - previousCreatedAt > int(3, MINUTE) ||
|
||||
previousKind === RELAY_ADD_MEMBER
|
||||
|
||||
if (showPubkey && elements.length > 0) {
|
||||
elements[elements.length - 1].addSpaceBelow = true
|
||||
}
|
||||
|
||||
elements.push({
|
||||
id: event.id,
|
||||
type: "note",
|
||||
value: event,
|
||||
showPubkey,
|
||||
addSpaceBelow: false,
|
||||
})
|
||||
|
||||
previousDate = date
|
||||
@@ -245,9 +240,6 @@
|
||||
previousCreatedAt = event.created_at
|
||||
seen.add(event.id)
|
||||
}
|
||||
if (elements.length > 0) {
|
||||
elements[elements.length - 1].addSpaceBelow = true
|
||||
}
|
||||
}
|
||||
|
||||
elements.reverse()
|
||||
@@ -318,13 +310,13 @@
|
||||
{/snippet}
|
||||
</SpaceBar>
|
||||
|
||||
<PageContent bind:element onscroll={onScroll} class="flex flex-col-reverse pt-4 pb-0!">
|
||||
<PageContent bind:element onscroll={onScroll} class="flex-col-reverse !mb-0">
|
||||
{#if loadingForward}
|
||||
<p class="py-20 flex justify-center">
|
||||
<Spinner loading={loadingForward}>Looking for messages...</Spinner>
|
||||
</p>
|
||||
{/if}
|
||||
{#each elements as { type, id, value, showPubkey, addSpaceBelow }, i (id)}
|
||||
{#each elements as { type, id, value, showPubkey }, i (id)}
|
||||
{#if type === "new-messages"}
|
||||
<div
|
||||
{id}
|
||||
@@ -347,8 +339,7 @@
|
||||
{replyTo}
|
||||
{showPubkey}
|
||||
canEdit={canEditEvent}
|
||||
onEdit={onEditEvent}
|
||||
{addSpaceBelow} />
|
||||
onEdit={onEditEvent} />
|
||||
{/if}
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
{/snippet}
|
||||
</SpaceBar>
|
||||
|
||||
<PageContent bind:element class="flex flex-col gap-2 p-2 pt-4">
|
||||
<PageContent bind:element class="flex flex-col gap-2 p-2">
|
||||
{#each items as event (event.id)}
|
||||
<div in:fly>
|
||||
<ClassifiedItem {url} event={$state.snapshot(event)} />
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
{/snippet}
|
||||
</SpaceBar>
|
||||
|
||||
<PageContent class="flex flex-col p-2 pt-4">
|
||||
<PageContent class="flex flex-col gap-2 p-2">
|
||||
{#if $event}
|
||||
<div class="flex flex-col gap-3">
|
||||
<NoteCard event={$event} {url} class="card2 bg-alt z-feature w-full">
|
||||
@@ -90,7 +90,7 @@
|
||||
{#if showReply}
|
||||
<EventReply {url} event={$event} onClose={closeReply} onSubmit={closeReply} />
|
||||
{:else}
|
||||
<div class="flex justify-end p-2">
|
||||
<div class="flex justify-end">
|
||||
<Button class="btn btn-primary" onclick={openReply}>
|
||||
<Icon icon={Reply} />
|
||||
Reply to listing
|
||||
@@ -98,7 +98,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="py-20 m-auto">
|
||||
<div class="flex justify-center py-20">
|
||||
{#await sleep(5000)}
|
||||
<Spinner loading>Loading listing...</Spinner>
|
||||
{:then}
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
{/snippet}
|
||||
</SpaceBar>
|
||||
|
||||
<PageContent bind:element class="flex flex-col gap-2 p-2 pt-4">
|
||||
<PageContent bind:element class="flex flex-col gap-2 p-2">
|
||||
{#each items as event (event.id)}
|
||||
<div in:fly>
|
||||
<GoalItem {url} event={$state.snapshot(event)} />
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
{/snippet}
|
||||
</SpaceBar>
|
||||
|
||||
<PageContent class="flex flex-col p-2 pt-4">
|
||||
<PageContent class="flex flex-col gap-2 p-2">
|
||||
{#if $event}
|
||||
<div class="flex flex-col gap-3">
|
||||
<NoteCard event={$event} {url} class="card2 bg-alt z-feature w-full">
|
||||
@@ -91,7 +91,7 @@
|
||||
{#if showReply}
|
||||
<EventReply {url} event={$event} onClose={closeReply} onSubmit={closeReply} />
|
||||
{:else}
|
||||
<div class="flex justify-end p-2">
|
||||
<div class="flex justify-end">
|
||||
<Button class="btn btn-primary" onclick={openReply}>
|
||||
<Icon icon={Reply} />
|
||||
Comment on this goal
|
||||
@@ -99,10 +99,12 @@
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
{#await sleep(5000)}
|
||||
<Spinner loading>Loading funding goal...</Spinner>
|
||||
{:then}
|
||||
<p>Failed to load funding goal.</p>
|
||||
{/await}
|
||||
<div class="flex justify-center py-20">
|
||||
{#await sleep(5000)}
|
||||
<Spinner loading>Loading funding goal...</Spinner>
|
||||
{:then}
|
||||
<p>Failed to load funding goal.</p>
|
||||
{/await}
|
||||
</div>
|
||||
{/if}
|
||||
</PageContent>
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
{/snippet}
|
||||
</SpaceBar>
|
||||
|
||||
<PageContent bind:element class="flex flex-col gap-2 p-2 pt-4">
|
||||
<PageContent bind:element class="flex flex-col gap-2 p-2">
|
||||
{#each items as event (event.id)}
|
||||
<div in:fly>
|
||||
<PollItem {url} event={$state.snapshot(event)} />
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
{/snippet}
|
||||
</SpaceBar>
|
||||
|
||||
<PageContent class="flex flex-col gap-3 p-2 pt-4">
|
||||
<PageContent class="flex flex-col gap-2 p-2">
|
||||
{#if $event}
|
||||
<div class="flex flex-col gap-3">
|
||||
<NoteCard event={$event} {url} class="card2 bg-alt z-feature w-full">
|
||||
@@ -92,15 +92,17 @@
|
||||
{#if showReply}
|
||||
<EventReply {url} event={$event} onClose={closeReply} onSubmit={closeReply} />
|
||||
{:else}
|
||||
<div class="flex justify-end p-2">
|
||||
<div class="flex justify-end">
|
||||
<Button class="btn btn-primary" onclick={openReply}>Comment on this poll</Button>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
{#await sleep(5000)}
|
||||
<Spinner loading>Loading poll...</Spinner>
|
||||
{:then}
|
||||
<p>Failed to load poll.</p>
|
||||
{/await}
|
||||
<div class="flex justify-center py-20">
|
||||
{#await sleep(5000)}
|
||||
<Spinner loading>Loading poll...</Spinner>
|
||||
{:then}
|
||||
<p>Failed to load poll.</p>
|
||||
{/await}
|
||||
</div>
|
||||
{/if}
|
||||
</PageContent>
|
||||
|
||||
@@ -292,7 +292,7 @@
|
||||
{/snippet}
|
||||
</SpaceBar>
|
||||
|
||||
<PageContent class="flex flex-col gap-2 p-2 pt-4" bind:element>
|
||||
<PageContent class="flex flex-col gap-2 p-2" bind:element>
|
||||
{#if $recentActivity.length === 0}
|
||||
<p class="flex flex-col items-center py-20 text-center">No recent activity found!</p>
|
||||
{:else}
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
{/snippet}
|
||||
</SpaceBar>
|
||||
|
||||
<PageContent bind:element class="flex flex-col gap-2 p-2 pt-4">
|
||||
<PageContent bind:element class="flex flex-col gap-2 p-2">
|
||||
{#each items as event (event.id)}
|
||||
<div in:fly>
|
||||
<ThreadItem {url} event={$state.snapshot(event)} />
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
{/snippet}
|
||||
</SpaceBar>
|
||||
|
||||
<PageContent class="flex flex-col p-2 pt-4">
|
||||
<PageContent class="flex flex-col gap-2 p-2">
|
||||
{#if $event}
|
||||
<div class="flex flex-col gap-3">
|
||||
<NoteCard event={$event} {url} class="card2 bg-alt z-feature w-full">
|
||||
@@ -90,7 +90,7 @@
|
||||
{#if showReply}
|
||||
<EventReply {url} event={$event} onClose={closeReply} onSubmit={closeReply} />
|
||||
{:else}
|
||||
<div class="flex justify-end p-2">
|
||||
<div class="flex justify-end">
|
||||
<Button class="btn btn-primary" onclick={openReply}>
|
||||
<Icon icon={Reply} />
|
||||
Reply to thread
|
||||
@@ -98,10 +98,12 @@
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
{#await sleep(5000)}
|
||||
<Spinner loading>Loading thread...</Spinner>
|
||||
{:then}
|
||||
<p>Failed to load thread.</p>
|
||||
{/await}
|
||||
<div class="flex justify-center py-20">
|
||||
{#await sleep(5000)}
|
||||
<Spinner loading>Loading thread...</Spinner>
|
||||
{:then}
|
||||
<p>Failed to load thread.</p>
|
||||
{/await}
|
||||
</div>
|
||||
{/if}
|
||||
</PageContent>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</script>
|
||||
|
||||
<Page>
|
||||
<PageContent class="flex flex-col items-center gap-2 p-2 pt-4">
|
||||
<PageContent class="flex flex-col items-center gap-2 p-2">
|
||||
<PageHeader>
|
||||
{#snippet title()}
|
||||
<div>Choose your Hosting Plan</div>
|
||||
|
||||
Reference in New Issue
Block a user