forked from coracle/flotilla
Tweak layout css
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Divider from "@lib/components/Divider.svelte"
|
||||
import PageBar from "@lib/components/PageBar.svelte"
|
||||
import PageContent from "@lib/components/PageContent.svelte"
|
||||
import MenuSpaceButton from "@app/components/MenuSpaceButton.svelte"
|
||||
import ProfileFeed from "@app/components/ProfileFeed.svelte"
|
||||
import ChannelName from "@app/components/ChannelName.svelte"
|
||||
@@ -45,154 +46,152 @@
|
||||
const pubkey = $derived($relay?.profile?.pubkey)
|
||||
</script>
|
||||
|
||||
<div class="relative flex flex-col">
|
||||
<PageBar>
|
||||
{#snippet icon()}
|
||||
<div class="center">
|
||||
<Icon icon="home-smile" />
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<strong>Home</strong>
|
||||
{/snippet}
|
||||
{#snippet action()}
|
||||
<div class="row-2">
|
||||
{#if !$userRoomsByUrl.has(url)}
|
||||
<Button class="btn btn-primary btn-sm" onclick={joinSpace}>
|
||||
<Icon icon="login-2" />
|
||||
Join Space
|
||||
</Button>
|
||||
{:else if pubkey}
|
||||
<Link class="btn btn-primary btn-sm" href={makeChatPath([pubkey])}>
|
||||
<Icon icon="letter" />
|
||||
Contact Owner
|
||||
</Link>
|
||||
{/if}
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
<div class="col-2 p-2">
|
||||
<div class="card2 bg-alt col-4 text-left">
|
||||
<div class="relative flex gap-4">
|
||||
<div class="relative">
|
||||
<div class="avatar relative">
|
||||
<div
|
||||
class="center !flex h-12 w-12 min-w-12 rounded-full border-2 border-solid border-base-300 bg-base-300">
|
||||
{#if $relay?.profile?.icon}
|
||||
<img alt="" src={$relay.profile.icon} />
|
||||
{:else}
|
||||
<Icon icon="ghost" size={5} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
<h2 class="ellipsize whitespace-nowrap text-xl">
|
||||
<RelayName {url} />
|
||||
</h2>
|
||||
<p class="ellipsize text-sm opacity-75">{displayRelayUrl(url)}</p>
|
||||
</div>
|
||||
</div>
|
||||
<RelayDescription {url} />
|
||||
{#if $relay?.profile}
|
||||
{@const {software, version, supported_nips, limitation} = $relay.profile}
|
||||
<div class="flex flex-wrap gap-1">
|
||||
{#if limitation?.auth_required}
|
||||
<p class="badge badge-neutral">
|
||||
<span class="ellipsize">Authentication Required</span>
|
||||
</p>
|
||||
{/if}
|
||||
{#if limitation?.payment_required}
|
||||
<p class="badge badge-neutral"><span class="ellipsize">Payment Required</span></p>
|
||||
{/if}
|
||||
{#if limitation?.min_pow_difficulty}
|
||||
<p class="badge badge-neutral">
|
||||
<span class="ellipsize">Requires PoW {limitation?.min_pow_difficulty}</span>
|
||||
</p>
|
||||
{/if}
|
||||
{#if supported_nips}
|
||||
<p class="badge badge-neutral">
|
||||
<span class="ellipsize">NIPs: {supported_nips.join(", ")}</span>
|
||||
</p>
|
||||
{/if}
|
||||
{#if software}
|
||||
<p class="badge badge-neutral"><span class="ellipsize">Software: {software}</span></p>
|
||||
{/if}
|
||||
{#if version}
|
||||
<p class="badge badge-neutral"><span class="ellipsize">Version: {version}</span></p>
|
||||
{/if}
|
||||
</div>
|
||||
<PageBar>
|
||||
{#snippet icon()}
|
||||
<div class="center">
|
||||
<Icon icon="home-smile" />
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<strong>Home</strong>
|
||||
{/snippet}
|
||||
{#snippet action()}
|
||||
<div class="row-2">
|
||||
{#if !$userRoomsByUrl.has(url)}
|
||||
<Button class="btn btn-primary btn-sm" onclick={joinSpace}>
|
||||
<Icon icon="login-2" />
|
||||
Join Space
|
||||
</Button>
|
||||
{:else if pubkey}
|
||||
<Link class="btn btn-primary btn-sm" href={makeChatPath([pubkey])}>
|
||||
<Icon icon="letter" />
|
||||
Contact Owner
|
||||
</Link>
|
||||
{/if}
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
<Divider>Your Rooms</Divider>
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
<Link href={threadsPath} class="btn btn-primary">
|
||||
<div class="relative flex items-center gap-2">
|
||||
<Icon icon="notes-minimalistic" />
|
||||
Threads
|
||||
{#if $notifications.has(threadsPath)}
|
||||
<div
|
||||
class="absolute -right-3 -top-1 h-2 w-2 rounded-full bg-primary-content"
|
||||
transition:fade>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Link>
|
||||
<Link href={calendarPath} class="btn btn-secondary">
|
||||
<div class="relative flex items-center gap-2">
|
||||
<Icon icon="notes-minimalistic" />
|
||||
Calendar
|
||||
{#if $notifications.has(calendarPath)}
|
||||
<div
|
||||
class="absolute -right-3 -top-1 h-2 w-2 rounded-full bg-primary-content"
|
||||
transition:fade>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Link>
|
||||
{#each $userRooms as room (room)}
|
||||
{@const roomPath = makeRoomPath(url, room)}
|
||||
<Link href={roomPath} class="btn btn-neutral relative">
|
||||
<div class="flex min-w-0 items-center gap-2 overflow-hidden text-nowrap">
|
||||
{#if channelIsLocked($channelsById.get(makeChannelId(url, room)))}
|
||||
<Icon icon="lock" size={4} />
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
|
||||
<PageContent class="flex flex-col p-2 pt-4">
|
||||
<div class="card2 bg-alt col-4 text-left">
|
||||
<div class="relative flex gap-4">
|
||||
<div class="relative">
|
||||
<div class="avatar relative">
|
||||
<div
|
||||
class="center !flex h-12 w-12 min-w-12 rounded-full border-2 border-solid border-base-300 bg-base-300">
|
||||
{#if $relay?.profile?.icon}
|
||||
<img alt="" src={$relay.profile.icon} />
|
||||
{:else}
|
||||
<Icon icon="hashtag" />
|
||||
<Icon icon="ghost" size={5} />
|
||||
{/if}
|
||||
<ChannelName {url} {room} />
|
||||
</div>
|
||||
{#if $notifications.has(roomPath)}
|
||||
<div class="absolute right-1 top-1 h-2 w-2 rounded-full bg-primary" transition:fade>
|
||||
</div>
|
||||
{/if}
|
||||
</Link>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
<h2 class="ellipsize whitespace-nowrap text-xl">
|
||||
<RelayName {url} />
|
||||
</h2>
|
||||
<p class="ellipsize text-sm opacity-75">{displayRelayUrl(url)}</p>
|
||||
</div>
|
||||
</div>
|
||||
<Divider>Other Rooms</Divider>
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
{#each $otherRooms as room (room)}
|
||||
<Link href={makeRoomPath(url, room)} class="btn btn-neutral">
|
||||
<div class="relative flex min-w-0 items-center gap-2 overflow-hidden text-nowrap">
|
||||
{#if channelIsLocked($channelsById.get(makeChannelId(url, room)))}
|
||||
<Icon icon="lock" size={4} />
|
||||
{:else}
|
||||
<Icon icon="hashtag" />
|
||||
{/if}
|
||||
<ChannelName {url} {room} />
|
||||
</div>
|
||||
</Link>
|
||||
{/each}
|
||||
<Button onclick={addRoom} class="btn btn-neutral whitespace-nowrap">
|
||||
<Icon icon="add-circle" />
|
||||
Create
|
||||
</Button>
|
||||
</div>
|
||||
{#if pubkey}
|
||||
<div class="hidden flex-col gap-2" class:!flex={relayAdminEvents.length > 0}>
|
||||
<Divider>Recent posts from the relay admin</Divider>
|
||||
<ProfileFeed hideLoading {url} {pubkey} bind:events={relayAdminEvents} />
|
||||
<RelayDescription {url} />
|
||||
{#if $relay?.profile}
|
||||
{@const {software, version, supported_nips, limitation} = $relay.profile}
|
||||
<div class="flex flex-wrap gap-1">
|
||||
{#if limitation?.auth_required}
|
||||
<p class="badge badge-neutral">
|
||||
<span class="ellipsize">Authentication Required</span>
|
||||
</p>
|
||||
{/if}
|
||||
{#if limitation?.payment_required}
|
||||
<p class="badge badge-neutral"><span class="ellipsize">Payment Required</span></p>
|
||||
{/if}
|
||||
{#if limitation?.min_pow_difficulty}
|
||||
<p class="badge badge-neutral">
|
||||
<span class="ellipsize">Requires PoW {limitation?.min_pow_difficulty}</span>
|
||||
</p>
|
||||
{/if}
|
||||
{#if supported_nips}
|
||||
<p class="badge badge-neutral">
|
||||
<span class="ellipsize">NIPs: {supported_nips.join(", ")}</span>
|
||||
</p>
|
||||
{/if}
|
||||
{#if software}
|
||||
<p class="badge badge-neutral"><span class="ellipsize">Software: {software}</span></p>
|
||||
{/if}
|
||||
{#if version}
|
||||
<p class="badge badge-neutral"><span class="ellipsize">Version: {version}</span></p>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<Divider>Your Rooms</Divider>
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
<Link href={threadsPath} class="btn btn-primary">
|
||||
<div class="relative flex items-center gap-2">
|
||||
<Icon icon="notes-minimalistic" />
|
||||
Threads
|
||||
{#if $notifications.has(threadsPath)}
|
||||
<div
|
||||
class="absolute -right-3 -top-1 h-2 w-2 rounded-full bg-primary-content"
|
||||
transition:fade>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Link>
|
||||
<Link href={calendarPath} class="btn btn-secondary">
|
||||
<div class="relative flex items-center gap-2">
|
||||
<Icon icon="notes-minimalistic" />
|
||||
Calendar
|
||||
{#if $notifications.has(calendarPath)}
|
||||
<div
|
||||
class="absolute -right-3 -top-1 h-2 w-2 rounded-full bg-primary-content"
|
||||
transition:fade>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Link>
|
||||
{#each $userRooms as room (room)}
|
||||
{@const roomPath = makeRoomPath(url, room)}
|
||||
<Link href={roomPath} class="btn btn-neutral relative">
|
||||
<div class="flex min-w-0 items-center gap-2 overflow-hidden text-nowrap">
|
||||
{#if channelIsLocked($channelsById.get(makeChannelId(url, room)))}
|
||||
<Icon icon="lock" size={4} />
|
||||
{:else}
|
||||
<Icon icon="hashtag" />
|
||||
{/if}
|
||||
<ChannelName {url} {room} />
|
||||
</div>
|
||||
{#if $notifications.has(roomPath)}
|
||||
<div class="absolute right-1 top-1 h-2 w-2 rounded-full bg-primary" transition:fade></div>
|
||||
{/if}
|
||||
</Link>
|
||||
{/each}
|
||||
</div>
|
||||
<Divider>Other Rooms</Divider>
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
{#each $otherRooms as room (room)}
|
||||
<Link href={makeRoomPath(url, room)} class="btn btn-neutral">
|
||||
<div class="relative flex min-w-0 items-center gap-2 overflow-hidden text-nowrap">
|
||||
{#if channelIsLocked($channelsById.get(makeChannelId(url, room)))}
|
||||
<Icon icon="lock" size={4} />
|
||||
{:else}
|
||||
<Icon icon="hashtag" />
|
||||
{/if}
|
||||
<ChannelName {url} {room} />
|
||||
</div>
|
||||
</Link>
|
||||
{/each}
|
||||
<Button onclick={addRoom} class="btn btn-neutral whitespace-nowrap">
|
||||
<Icon icon="add-circle" />
|
||||
Create
|
||||
</Button>
|
||||
</div>
|
||||
{#if pubkey}
|
||||
<div class="hidden flex-col gap-2" class:!flex={relayAdminEvents.length > 0}>
|
||||
<Divider>Recent posts from the relay admin</Divider>
|
||||
<ProfileFeed hideLoading {url} {pubkey} bind:events={relayAdminEvents} />
|
||||
</div>
|
||||
{/if}
|
||||
</PageContent>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import PageBar from "@lib/components/PageBar.svelte"
|
||||
import PageContent from "@lib/components/PageContent.svelte"
|
||||
import Divider from "@lib/components/Divider.svelte"
|
||||
import MenuSpaceButton from "@app/components/MenuSpaceButton.svelte"
|
||||
import ChannelName from "@app/components/ChannelName.svelte"
|
||||
@@ -232,7 +233,7 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<PageBar class="chat__page-bar">
|
||||
<PageBar>
|
||||
{#snippet icon()}
|
||||
<div class="center">
|
||||
<Icon icon="hashtag" />
|
||||
@@ -267,7 +268,7 @@
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
|
||||
<div class="chat__messages scroll-container" onscroll={onScroll} bind:this={element}>
|
||||
<PageContent bind:element onscroll={onScroll} class="flex flex-col-reverse pt-4">
|
||||
<div bind:this={dynamicPadding}></div>
|
||||
{#each elements as { type, id, value, showPubkey } (id)}
|
||||
{#if type === "new-messages"}
|
||||
@@ -299,7 +300,7 @@
|
||||
<Spinner>End of message history</Spinner>
|
||||
{/if}
|
||||
</p>
|
||||
</div>
|
||||
</PageContent>
|
||||
|
||||
<div class="chat__compose bg-base-200" bind:this={chatCompose}>
|
||||
<div>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import PageBar from "@lib/components/PageBar.svelte"
|
||||
import PageContent from "@lib/components/PageContent.svelte"
|
||||
import Divider from "@lib/components/Divider.svelte"
|
||||
import MenuSpaceButton from "@app/components/MenuSpaceButton.svelte"
|
||||
import CalendarEventItem from "@app/components/CalendarEventItem.svelte"
|
||||
@@ -27,7 +28,7 @@
|
||||
|
||||
const getStart = (event: TrustedEvent) => parseInt(getTagValue("start", event.tags) || "")
|
||||
|
||||
let element: HTMLElement
|
||||
let element: HTMLElement | undefined = $state()
|
||||
let loading = $state(true)
|
||||
let cleanup: () => void
|
||||
let events: Readable<TrustedEvent[]> = $state(readable([]))
|
||||
@@ -69,11 +70,11 @@
|
||||
if (initialScrollDone) {
|
||||
// If new events are prepended, adjust the scroll position so that the viewport content remains anchored
|
||||
if (prevFirstEventId && items[0].event.id !== prevFirstEventId) {
|
||||
const newScrollHeight = element.scrollHeight
|
||||
const newScrollHeight = element!.scrollHeight
|
||||
const delta = newScrollHeight - previousScrollHeight
|
||||
|
||||
if (delta > 0) {
|
||||
element.scrollTop += delta
|
||||
element!.scrollTop += delta
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -83,11 +84,11 @@
|
||||
) as HTMLElement
|
||||
|
||||
// On initial load, center the scroll container on today's date (or the next available event)
|
||||
element.scrollTop = offsetTop - element.clientHeight / 2 + clientHeight / 2
|
||||
element!.scrollTop = offsetTop - element!.clientHeight / 2 + clientHeight / 2
|
||||
initialScrollDone = true
|
||||
}
|
||||
|
||||
previousScrollHeight = element.scrollHeight
|
||||
previousScrollHeight = element!.scrollHeight
|
||||
prevFirstEventId = items[0].event.id
|
||||
})
|
||||
|
||||
@@ -98,7 +99,7 @@
|
||||
]
|
||||
|
||||
;({events, cleanup} = makeCalendarFeed({
|
||||
element,
|
||||
element: element!,
|
||||
relays: [url],
|
||||
feedFilters,
|
||||
subscriptionFilters,
|
||||
@@ -115,50 +116,49 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="relative flex h-screen flex-col">
|
||||
<PageBar>
|
||||
{#snippet icon()}
|
||||
<div class="center">
|
||||
<Icon icon="calendar-minimalistic" />
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<strong>Calendar</strong>
|
||||
{/snippet}
|
||||
{#snippet action()}
|
||||
<div class="row-2">
|
||||
<Button class="btn btn-primary btn-sm" onclick={createEvent}>
|
||||
<Icon icon="calendar-add" />
|
||||
Create an Event
|
||||
</Button>
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
<div class="scroll-container flex flex-grow flex-col gap-2 overflow-auto p-2" bind:this={element}>
|
||||
{#each items as { event, dateDisplay, isFirstFutureEvent }, i (event.id)}
|
||||
<div class={"calendar-event-" + event.id}>
|
||||
{#if isFirstFutureEvent}
|
||||
<div class="flex items-center gap-2 p-2">
|
||||
<div class="h-px flex-grow bg-primary"></div>
|
||||
<p class="text-xs uppercase text-primary">Today</p>
|
||||
<div class="h-px flex-grow bg-primary"></div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if dateDisplay}
|
||||
<Divider>{dateDisplay}</Divider>
|
||||
{/if}
|
||||
<CalendarEventItem {url} {event} />
|
||||
</div>
|
||||
{/each}
|
||||
{#if loading}
|
||||
<p class="flex h-10 items-center justify-center py-20" transition:fly>
|
||||
<Spinner {loading}>Looking for events...</Spinner>
|
||||
</p>
|
||||
{:else if items.length === 0}
|
||||
<p class="flex h-10 items-center justify-center py-20" transition:fly>No events found.</p>
|
||||
{:else}
|
||||
<p class="flex h-10 items-center justify-center py-20" transition:fly>That's all!</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<PageBar>
|
||||
{#snippet icon()}
|
||||
<div class="center">
|
||||
<Icon icon="calendar-minimalistic" />
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<strong>Calendar</strong>
|
||||
{/snippet}
|
||||
{#snippet action()}
|
||||
<div class="row-2">
|
||||
<Button class="btn btn-primary btn-sm" onclick={createEvent}>
|
||||
<Icon icon="calendar-add" />
|
||||
Create an Event
|
||||
</Button>
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
|
||||
<PageContent bind:element class="flex flex-col gap-2 p-2 pt-4">
|
||||
{#each items as { event, dateDisplay, isFirstFutureEvent }, i (event.id)}
|
||||
<div class={"calendar-event-" + event.id}>
|
||||
{#if isFirstFutureEvent}
|
||||
<div class="flex items-center gap-2 p-2">
|
||||
<div class="h-px flex-grow bg-primary"></div>
|
||||
<p class="text-xs uppercase text-primary">Today</p>
|
||||
<div class="h-px flex-grow bg-primary"></div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if dateDisplay}
|
||||
<Divider>{dateDisplay}</Divider>
|
||||
{/if}
|
||||
<CalendarEventItem {url} {event} />
|
||||
</div>
|
||||
{/each}
|
||||
{#if loading}
|
||||
<p class="flex h-10 items-center justify-center py-20" transition:fly>
|
||||
<Spinner {loading}>Looking for events...</Spinner>
|
||||
</p>
|
||||
{:else if items.length === 0}
|
||||
<p class="flex h-10 items-center justify-center py-20" transition:fly>No events found.</p>
|
||||
{:else}
|
||||
<p class="flex h-10 items-center justify-center py-20" transition:fly>That's all!</p>
|
||||
{/if}
|
||||
</PageContent>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import {deriveEvents} from "@welshman/store"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import PageBar from "@lib/components/PageBar.svelte"
|
||||
import PageContent from "@lib/components/PageContent.svelte"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Content from "@app/components/Content.svelte"
|
||||
@@ -53,33 +54,25 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="relative flex flex-col-reverse gap-3 px-2">
|
||||
<div class="absolute left-[51px] top-32 h-[calc(100%-248px)] w-[2px] bg-neutral"></div>
|
||||
<PageBar>
|
||||
{#snippet icon()}
|
||||
<div>
|
||||
<Button class="btn btn-neutral btn-sm flex-nowrap whitespace-nowrap" onclick={back}>
|
||||
<Icon icon="alt-arrow-left" />
|
||||
<span class="hidden sm:inline">Go back</span>
|
||||
</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<h1 class="text-xl">{getTagValue("title", $event?.tags || []) || ""}</h1>
|
||||
{/snippet}
|
||||
{#snippet action()}
|
||||
<MenuSpaceButton {url} />
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
|
||||
<PageContent class="flex flex-col gap-3 p-2 pt-4">
|
||||
{#if $event}
|
||||
{#if !showReply}
|
||||
<div class="flex justify-end px-2 pb-2">
|
||||
<Button class="btn btn-primary" onclick={openReply}>
|
||||
<Icon icon="reply" />
|
||||
Leave comment
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
{#each sortBy(e => -e.created_at, $replies).slice(0, showAll ? undefined : 4) as reply (reply.id)}
|
||||
<NoteCard event={reply} class="card2 bg-alt z-feature w-full">
|
||||
<div class="col-3 ml-12">
|
||||
<Content showEntire event={reply} />
|
||||
<CalendarEventActions event={reply} {url} />
|
||||
</div>
|
||||
</NoteCard>
|
||||
{/each}
|
||||
{#if !showAll && $replies.length > 4}
|
||||
<div class="flex justify-center">
|
||||
<Button class="btn btn-link" onclick={expand}>
|
||||
<Icon icon="sort-vertical" />
|
||||
Show all {$replies.length} replies
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="card2 bg-alt col-3 z-feature">
|
||||
<div class="flex items-start gap-4">
|
||||
<CalendarEventDate event={$event} />
|
||||
@@ -96,6 +89,32 @@
|
||||
<CalendarEventActions {url} event={$event} />
|
||||
</div>
|
||||
</div>
|
||||
{#if !showAll && $replies.length > 4}
|
||||
<div class="flex justify-center">
|
||||
<Button class="btn btn-link" onclick={expand}>
|
||||
<Icon icon="sort-vertical" />
|
||||
Show all {$replies.length} replies
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
{#each sortBy(e => e.created_at, $replies).slice(0, showAll ? undefined : 4) as reply (reply.id)}
|
||||
<NoteCard event={reply} class="card2 bg-alt z-feature w-full">
|
||||
<div class="col-3 ml-12">
|
||||
<Content showEntire event={reply} />
|
||||
<CalendarEventActions event={reply} {url} />
|
||||
</div>
|
||||
</NoteCard>
|
||||
{/each}
|
||||
{#if showReply}
|
||||
<EventReply {url} event={$event} onClose={closeReply} onSubmit={closeReply} />
|
||||
{:else}
|
||||
<div class="flex justify-end px-2 pb-2">
|
||||
<Button class="btn btn-primary" onclick={openReply}>
|
||||
<Icon icon="reply" />
|
||||
Leave comment
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
{#await sleep(5000)}
|
||||
<Spinner loading>Loading comments...</Spinner>
|
||||
@@ -103,23 +122,4 @@
|
||||
<p>Failed to load comments.</p>
|
||||
{/await}
|
||||
{/if}
|
||||
<PageBar class="!mx-0">
|
||||
{#snippet icon()}
|
||||
<div>
|
||||
<Button class="btn btn-neutral btn-sm flex-nowrap whitespace-nowrap" onclick={back}>
|
||||
<Icon icon="alt-arrow-left" />
|
||||
<span class="hidden sm:inline">Go back</span>
|
||||
</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<h1 class="text-xl">{getTagValue("title", $event?.tags || []) || ""}</h1>
|
||||
{/snippet}
|
||||
{#snippet action()}
|
||||
<MenuSpaceButton {url} />
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
</div>
|
||||
{#if showReply}
|
||||
<EventReply {url} event={$event} onClose={closeReply} onSubmit={closeReply} />
|
||||
{/if}
|
||||
</PageContent>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import PageBar from "@lib/components/PageBar.svelte"
|
||||
import PageContent from "@lib/components/PageContent.svelte"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import MenuSpaceButton from "@app/components/MenuSpaceButton.svelte"
|
||||
import ThreadItem from "@app/components/ThreadItem.svelte"
|
||||
@@ -73,42 +74,41 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="relative flex h-screen flex-col" bind:this={element}>
|
||||
<PageBar>
|
||||
{#snippet icon()}
|
||||
<div class="center">
|
||||
<PageBar>
|
||||
{#snippet icon()}
|
||||
<div class="center">
|
||||
<Icon icon="notes-minimalistic" />
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<strong>Threads</strong>
|
||||
{/snippet}
|
||||
{#snippet action()}
|
||||
<div class="row-2">
|
||||
<Button class="btn btn-primary btn-sm" onclick={createThread}>
|
||||
<Icon icon="notes-minimalistic" />
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<strong>Threads</strong>
|
||||
{/snippet}
|
||||
{#snippet action()}
|
||||
<div class="row-2">
|
||||
<Button class="btn btn-primary btn-sm" onclick={createThread}>
|
||||
<Icon icon="notes-minimalistic" />
|
||||
Create a Thread
|
||||
</Button>
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
<div class="flex flex-grow flex-col gap-2 overflow-auto p-2">
|
||||
{#each events as event (event.id)}
|
||||
<div in:fly>
|
||||
<ThreadItem {url} event={$state.snapshot(event)} />
|
||||
</div>
|
||||
{/each}
|
||||
<p class="flex h-10 items-center justify-center py-20">
|
||||
<Spinner {loading}>
|
||||
{#if loading}
|
||||
Looking for threads...
|
||||
{:else if events.length === 0}
|
||||
No threads found.
|
||||
{:else}
|
||||
That's all!
|
||||
{/if}
|
||||
</Spinner>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
Create a Thread
|
||||
</Button>
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
|
||||
<PageContent bind:element class="flex flex-col gap-2 p-2 pt-4">
|
||||
{#each events as event (event.id)}
|
||||
<div in:fly>
|
||||
<ThreadItem {url} event={$state.snapshot(event)} />
|
||||
</div>
|
||||
{/each}
|
||||
<p class="flex h-10 items-center justify-center py-20">
|
||||
<Spinner {loading}>
|
||||
{#if loading}
|
||||
Looking for threads...
|
||||
{:else if events.length === 0}
|
||||
No threads found.
|
||||
{:else}
|
||||
That's all!
|
||||
{/if}
|
||||
</Spinner>
|
||||
</p>
|
||||
</PageContent>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import {deriveEvents} from "@welshman/store"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import PageBar from "@lib/components/PageBar.svelte"
|
||||
import PageContent from "@lib/components/PageContent.svelte"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Content from "@app/components/Content.svelte"
|
||||
@@ -50,39 +51,61 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="relative flex flex-col-reverse gap-3 px-2">
|
||||
<div class="absolute left-[51px] top-32 h-[calc(100%-248px)] w-[2px] bg-neutral"></div>
|
||||
<PageBar>
|
||||
{#snippet icon()}
|
||||
<div>
|
||||
<Button class="btn btn-neutral btn-sm flex-nowrap whitespace-nowrap" onclick={back}>
|
||||
<Icon icon="alt-arrow-left" />
|
||||
<span class="hidden sm:inline">Go back</span>
|
||||
</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<h1 class="text-xl">{getTagValue("title", $event?.tags || []) || ""}</h1>
|
||||
{/snippet}
|
||||
{#snippet action()}
|
||||
<div>
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
|
||||
<PageContent class="flex flex-col p-2 pt-4">
|
||||
{#if $event}
|
||||
{#if !showReply}
|
||||
<div class="flex justify-end px-2 pb-2">
|
||||
<div class="flex flex-col gap-3">
|
||||
<NoteCard event={$event} class="card2 bg-alt z-feature w-full">
|
||||
<div class="col-3 ml-12">
|
||||
<Content showEntire event={$event} relays={[url]} />
|
||||
<ThreadActions event={$event} {url} />
|
||||
</div>
|
||||
</NoteCard>
|
||||
{#if !showAll && $replies.length > 4}
|
||||
<div class="flex justify-center">
|
||||
<Button class="btn btn-link" onclick={expand}>
|
||||
<Icon icon="sort-vertical" />
|
||||
Show all {$replies.length} replies
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
{#each sortBy(e => -e.created_at, $replies).slice(0, showAll ? undefined : 4) as reply (reply.id)}
|
||||
<NoteCard event={reply} class="card2 bg-alt z-feature w-full">
|
||||
<div class="col-3 ml-12">
|
||||
<Content showEntire event={reply} />
|
||||
<ThreadActions event={reply} {url} />
|
||||
</div>
|
||||
</NoteCard>
|
||||
{/each}
|
||||
</div>
|
||||
{#if showReply}
|
||||
<EventReply {url} event={$event} onClose={closeReply} onSubmit={closeReply} />
|
||||
{:else}
|
||||
<div class="flex justify-end p-2">
|
||||
<Button class="btn btn-primary" onclick={openReply}>
|
||||
<Icon icon="reply" />
|
||||
Reply to thread
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
{#each sortBy(e => -e.created_at, $replies).slice(0, showAll ? undefined : 4) as reply (reply.id)}
|
||||
<NoteCard event={reply} class="card2 bg-alt z-feature w-full">
|
||||
<div class="col-3 ml-12">
|
||||
<Content showEntire event={reply} />
|
||||
<ThreadActions event={reply} {url} />
|
||||
</div>
|
||||
</NoteCard>
|
||||
{/each}
|
||||
{#if !showAll && $replies.length > 4}
|
||||
<div class="flex justify-center">
|
||||
<Button class="btn btn-link" onclick={expand}>
|
||||
<Icon icon="sort-vertical" />
|
||||
Show all {$replies.length} replies
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
<NoteCard event={$event} class="card2 bg-alt z-feature w-full">
|
||||
<div class="col-3 ml-12">
|
||||
<Content showEntire event={$event} relays={[url]} />
|
||||
<ThreadActions event={$event} {url} />
|
||||
</div>
|
||||
</NoteCard>
|
||||
{:else}
|
||||
{#await sleep(5000)}
|
||||
<Spinner loading>Loading thread...</Spinner>
|
||||
@@ -90,25 +113,4 @@
|
||||
<p>Failed to load thread.</p>
|
||||
{/await}
|
||||
{/if}
|
||||
<PageBar class="!mx-0">
|
||||
{#snippet icon()}
|
||||
<div>
|
||||
<Button class="btn btn-neutral btn-sm flex-nowrap whitespace-nowrap" onclick={back}>
|
||||
<Icon icon="alt-arrow-left" />
|
||||
<span class="hidden sm:inline">Go back</span>
|
||||
</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet title()}
|
||||
<h1 class="text-xl">{getTagValue("title", $event?.tags || []) || ""}</h1>
|
||||
{/snippet}
|
||||
{#snippet action()}
|
||||
<div>
|
||||
<MenuSpaceButton {url} />
|
||||
</div>
|
||||
{/snippet}
|
||||
</PageBar>
|
||||
</div>
|
||||
{#if showReply}
|
||||
<EventReply {url} event={$event} onClose={closeReply} onSubmit={closeReply} />
|
||||
{/if}
|
||||
</PageContent>
|
||||
|
||||
Reference in New Issue
Block a user