Add shared EventActivity component

This commit is contained in:
Jon Staab
2025-02-06 09:53:50 -08:00
parent d66371d573
commit a7e9318819
5 changed files with 67 additions and 61 deletions

View File

@@ -1,12 +1,8 @@
<script lang="ts"> <script lang="ts">
import {onMount} from "svelte"
import {type Instance} from "tippy.js" import {type Instance} from "tippy.js"
import type {NativeEmoji} from "emoji-picker-element/shared" import type {NativeEmoji} from "emoji-picker-element/shared"
import {max} from "@welshman/lib"
import {deriveEvents} from "@welshman/store"
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
import {COMMENT} from "@welshman/util" import {pubkey} from "@welshman/app"
import {load, pubkey, repository, formatTimestampRelative} from "@welshman/app"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Tippy from "@lib/components/Tippy.svelte" import Tippy from "@lib/components/Tippy.svelte"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
@@ -14,20 +10,21 @@
import ReactionSummary from "@app/components/ReactionSummary.svelte" import ReactionSummary from "@app/components/ReactionSummary.svelte"
import ThunkStatusOrDeleted from "@app/components/ThunkStatusOrDeleted.svelte" import ThunkStatusOrDeleted from "@app/components/ThunkStatusOrDeleted.svelte"
import CalendarEventMenu from "@app/components/CalendarEventMenu.svelte" import CalendarEventMenu from "@app/components/CalendarEventMenu.svelte"
import EventActivity from "@app/components/EventActivity.svelte"
import {publishDelete, publishReaction} from "@app/commands" import {publishDelete, publishReaction} from "@app/commands"
import {notifications} from "@app/notifications"
import {makeCalendarPath} from "@app/routes" import {makeCalendarPath} from "@app/routes"
interface Props { const {
url: any url,
event: any event,
showActivity = false,
}: {
url: string
event: TrustedEvent
showActivity?: boolean showActivity?: boolean
} } = $props()
const {url, event, showActivity = false}: Props = $props()
const path = makeCalendarPath(url, event.id) const path = makeCalendarPath(url, event.id)
const filters = [{kinds: [COMMENT], "#E": [event.id]}]
const replies = deriveEvents(repository, {filters})
const showPopover = () => popover?.show() const showPopover = () => popover?.show()
@@ -47,12 +44,6 @@
publishReaction({event, content: emoji.unicode, relays: [url]}) publishReaction({event, content: emoji.unicode, relays: [url]})
let popover: Instance | undefined = $state() let popover: Instance | undefined = $state()
const lastActive = $derived(max([...$replies, event].map(e => e.created_at)))
onMount(() => {
load({relays: [url], filters})
})
</script> </script>
<div class="flex flex-wrap items-center justify-between gap-2"> <div class="flex flex-wrap items-center justify-between gap-2">
@@ -60,16 +51,7 @@
<ReactionSummary {url} {event} {onReactionClick} reactionClass="tooltip-left" /> <ReactionSummary {url} {event} {onReactionClick} reactionClass="tooltip-left" />
<ThunkStatusOrDeleted {event} /> <ThunkStatusOrDeleted {event} />
{#if showActivity} {#if showActivity}
<div class="flex-inline btn btn-neutral btn-xs gap-1 rounded-full"> <EventActivity {url} {path} {event} />
<Icon icon="reply" />
<span>{$replies.length} {$replies.length === 1 ? "reply" : "replies"}</span>
</div>
<div class="btn btn-neutral btn-xs relative hidden rounded-full sm:flex">
{#if $notifications.has(path)}
<div class="h-2 w-2 rounded-full bg-primary"></div>
{/if}
Active {formatTimestampRelative(lastActive)}
</div>
{/if} {/if}
<Button class="join rounded-full"> <Button class="join rounded-full">
<EmojiButton {onEmoji} class="btn join-item btn-neutral btn-xs"> <EmojiButton {onEmoji} class="btn join-item btn-neutral btn-xs">

View File

@@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import {fromPairs} from "@welshman/lib" import {fromPairs} from "@welshman/lib"
import type {TrustedEvent} from "@welshman/util"
import {formatTimestamp, formatTimestampAsDate, formatTimestampAsTime} from "@welshman/app" import {formatTimestamp, formatTimestampAsDate, formatTimestampAsTime} from "@welshman/app"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Link from "@lib/components/Link.svelte" import Link from "@lib/components/Link.svelte"
@@ -8,7 +9,15 @@
import EventPostedBy from "@app/components/EventPostedBy.svelte" import EventPostedBy from "@app/components/EventPostedBy.svelte"
import {makeCalendarPath} from "@app/routes" import {makeCalendarPath} from "@app/routes"
const {url, event} = $props() const {
url,
event,
hideActions = false,
}: {
url: string
event: TrustedEvent
hideActions?: boolean
} = $props()
const meta = $derived(fromPairs(event.tags) as Record<string, string>) const meta = $derived(fromPairs(event.tags) as Record<string, string>)
const end = $derived(parseInt(meta.end)) const end = $derived(parseInt(meta.end))
@@ -31,6 +40,8 @@
<Content {event} expandMode="inline" quoteProps={{relays: [url]}} /> <Content {event} expandMode="inline" quoteProps={{relays: [url]}} />
<div class="flex w-full flex-col items-end justify-between gap-2 sm:flex-row"> <div class="flex w-full flex-col items-end justify-between gap-2 sm:flex-row">
<EventPostedBy {event} /> <EventPostedBy {event} />
<CalendarEventActions {url} {event} /> {#if !hideActions}
<CalendarEventActions showActivity {url} {event} />
{/if}
</div> </div>
</Link> </Link>

View File

@@ -0,0 +1,31 @@
<script lang="ts">
import {onMount} from "svelte"
import {max} from "@welshman/lib"
import {COMMENT} from "@welshman/util"
import {deriveEvents} from "@welshman/store"
import type {TrustedEvent} from "@welshman/util"
import {formatTimestampRelative, repository, load} from "@welshman/app"
import {notifications} from "@app/notifications"
import Icon from "@lib/components/Icon.svelte"
const {url, path, event}: {url: string; path: string; event: TrustedEvent} = $props()
const filters = [{kinds: [COMMENT], "#E": [event.id]}]
const replies = deriveEvents(repository, {filters})
const lastActive = $derived(max([...$replies, event].map(e => e.created_at)))
onMount(() => {
load({relays: [url], filters})
})
</script>
<div class="flex-inline btn btn-neutral btn-xs gap-1 rounded-full">
<Icon icon="reply" />
<span>{$replies.length} {$replies.length === 1 ? "reply" : "replies"}</span>
</div>
<div class="btn btn-neutral btn-xs relative hidden rounded-full sm:flex">
{#if $notifications.has(path)}
<div class="h-2 w-2 rounded-full bg-primary"></div>
{/if}
Active {formatTimestampRelative(lastActive)}
</div>

View File

@@ -1,12 +1,8 @@
<script lang="ts"> <script lang="ts">
import {onMount} from "svelte"
import {type Instance} from "tippy.js" import {type Instance} from "tippy.js"
import type {NativeEmoji} from "emoji-picker-element/shared" import type {NativeEmoji} from "emoji-picker-element/shared"
import {max} from "@welshman/lib"
import {deriveEvents} from "@welshman/store"
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
import {COMMENT} from "@welshman/util" import {pubkey} from "@welshman/app"
import {load, pubkey, repository, formatTimestampRelative} from "@welshman/app"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Tippy from "@lib/components/Tippy.svelte" import Tippy from "@lib/components/Tippy.svelte"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
@@ -14,8 +10,8 @@
import ReactionSummary from "@app/components/ReactionSummary.svelte" import ReactionSummary from "@app/components/ReactionSummary.svelte"
import ThunkStatusOrDeleted from "@app/components/ThunkStatusOrDeleted.svelte" import ThunkStatusOrDeleted from "@app/components/ThunkStatusOrDeleted.svelte"
import ThreadMenu from "@app/components/ThreadMenu.svelte" import ThreadMenu from "@app/components/ThreadMenu.svelte"
import EventActivity from "@app/components/EventActivity.svelte"
import {publishDelete, publishReaction} from "@app/commands" import {publishDelete, publishReaction} from "@app/commands"
import {notifications} from "@app/notifications"
import {makeThreadPath} from "@app/routes" import {makeThreadPath} from "@app/routes"
interface Props { interface Props {
@@ -27,8 +23,6 @@
const {url, event, showActivity = false}: Props = $props() const {url, event, showActivity = false}: Props = $props()
const path = makeThreadPath(url, event.id) const path = makeThreadPath(url, event.id)
const filters = [{kinds: [COMMENT], "#E": [event.id]}]
const replies = deriveEvents(repository, {filters})
const showPopover = () => popover?.show() const showPopover = () => popover?.show()
@@ -48,12 +42,6 @@
publishReaction({event, content: emoji.unicode, relays: [url]}) publishReaction({event, content: emoji.unicode, relays: [url]})
let popover: Instance | undefined = $state() let popover: Instance | undefined = $state()
const lastActive = $derived(max([...$replies, event].map(e => e.created_at)))
onMount(() => {
load({relays: [url], filters})
})
</script> </script>
<div class="flex flex-wrap items-center justify-between gap-2"> <div class="flex flex-wrap items-center justify-between gap-2">
@@ -61,16 +49,7 @@
<ReactionSummary {url} {event} {onReactionClick} reactionClass="tooltip-left" /> <ReactionSummary {url} {event} {onReactionClick} reactionClass="tooltip-left" />
<ThunkStatusOrDeleted {event} /> <ThunkStatusOrDeleted {event} />
{#if showActivity} {#if showActivity}
<div class="flex-inline btn btn-neutral btn-xs gap-1 rounded-full"> <EventActivity {url} {path} {event} />
<Icon icon="reply" />
<span>{$replies.length} {$replies.length === 1 ? "reply" : "replies"}</span>
</div>
<div class="btn btn-neutral btn-xs relative hidden rounded-full sm:flex">
{#if $notifications.has(path)}
<div class="h-2 w-2 rounded-full bg-primary"></div>
{/if}
Active {formatTimestampRelative(lastActive)}
</div>
{/if} {/if}
<Button class="join rounded-full"> <Button class="join rounded-full">
<EmojiButton {onEmoji} class="btn join-item btn-neutral btn-xs"> <EmojiButton {onEmoji} class="btn join-item btn-neutral btn-xs">

View File

@@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import {nthEq} from "@welshman/lib" import {nthEq} from "@welshman/lib"
import type {TrustedEvent} from "@welshman/util"
import {formatTimestamp} from "@welshman/app" import {formatTimestamp} from "@welshman/app"
import Link from "@lib/components/Link.svelte" import Link from "@lib/components/Link.svelte"
import Content from "@app/components/Content.svelte" import Content from "@app/components/Content.svelte"
@@ -7,13 +8,15 @@
import ThreadActions from "@app/components/ThreadActions.svelte" import ThreadActions from "@app/components/ThreadActions.svelte"
import {makeThreadPath} from "@app/routes" import {makeThreadPath} from "@app/routes"
interface Props { const {
url: any url,
event: any event,
hideActions = false,
}: {
url: string
event: TrustedEvent
hideActions?: boolean hideActions?: boolean
} } = $props()
const {url, event, hideActions = false}: Props = $props()
const title = event.tags.find(nthEq(0, "title"))?.[1] const title = event.tags.find(nthEq(0, "title"))?.[1]
</script> </script>