Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175<script module lang="ts"> import { tv, type VariantProps } from "tailwind-variants";
export const comment = tv({ slots: { root: "grid grid-cols-[auto_minmax(0,1fr)] gap-x-1.5", avatar: "row-span-2 self-start", meta: "flex flex-wrap items-center gap-xs text-foreground-muted", actions: "ml-auto shrink-0", content: "col-start-2", editor: "mt-2xs", markup: "markup mt-2xs", plain: "mt-2xs wrap-anywhere whitespace-pre-wrap text-foreground-default", reactions: "mt-xs" }, variants: { variant: { top: { root: "border-b border-border-default bg-background-default p-sm pb-lg" }, reply: { root: "pt-sm pr-md pb-md" } }, deleted: { true: { root: "block text-foreground-muted italic" } }, masked: { true: {} } }, compoundVariants: [{ variant: "top", masked: true, class: { root: "pb-sm" } }], defaultVariants: { variant: "top" } });
export type CommentVariants = VariantProps<typeof comment>;</script>
<script lang="ts"> import type { Snippet } from "svelte"; import type { Moderation } from "#lib/api/moderationLabels.ts"; import type { KnotOrigin } from "#lib/api/syntax.ts"; import TriangleAlert from "$icon/triangle-alert"; import ModerationNotice from "#lib/components/moderation/ModerationNotice.svelte"; import { createAuthorGate, type ModerationGate } from "#lib/components/moderation/gate.svelte.ts"; import VouchAvatar from "#lib/components/profile/VouchAvatar.svelte"; import { avatar } from "#lib/components/ui/Avatar.svelte"; import ProfilePopover from "#lib/components/profile/ProfilePopover.svelte"; import User from "#lib/components/ui/User.svelte"; import TimeAgo from "#lib/components/ui/TimeAgo.svelte"; import Link from "#lib/components/ui/Link.svelte"; import Reactions from "#lib/components/reaction/Reactions.svelte"; import { codeblockToolbars } from "#lib/components/ui/codeblockToolbars.ts"; import { mermaidDiagrams } from "#lib/components/ui/mermaidDiagrams.ts"; import type { ReactionGroup } from "#lib/components/reaction/reactions.ts";
interface Props { authorHandle: string; authorDid: string; moderation?: Moderation; gate?: ModerationGate; createdAt: string; anchor?: string; body: string; bodyHtml: string | null; variant?: CommentVariants["variant"]; deleted?: boolean; reactions?: ReactionGroup[]; subjectUri: string; subjectCid?: string; knot?: KnotOrigin; onreactionschange?: (next: ReactionGroup[]) => void; editor?: Snippet; actions?: Snippet; }
let { authorHandle, authorDid, moderation, gate: sharedGate, createdAt, anchor, body, bodyHtml, variant = "top", deleted = false, reactions = [], subjectUri, subjectCid, knot, onreactionschange, editor, actions }: Props = $props();
const classes = $derived(comment({ variant, deleted })); const anchorId = $derived(anchor ? `comment-${anchor}` : undefined);
const ownGate = createAuthorGate( () => moderation, () => authorDid ); const gate = $derived(sharedGate ?? ownGate);</script>
{#if deleted} <div id={anchorId} data-testid="deletedCommentNotice" class={classes.root()}> This comment was deleted. </div>{:else if gate.masked} <div id={anchorId} class={comment({ variant, masked: true }).root()}> <span class={avatar({ size: "large", class: classes.avatar() })}> <TriangleAlert class="size-1/2" aria-hidden="true" /> </span> <ModerationNotice {gate} icon={false} /> </div>{:else} <div id={anchorId} class={classes.root()}> <div class={classes.avatar()}> <ProfilePopover identifier={authorDid}> <VouchAvatar did={authorDid} handle={authorHandle} size="large" /> </ProfilePopover> </div> <div class={classes.meta()}> <ProfilePopover identifier={authorDid}> <User handle={authorHandle} did={authorDid} showImage={false} link handleClass="font-semibold" /> </ProfilePopover> {#if anchorId} <Link fragment={anchorId} variant="inherit"><TimeAgo value={createdAt} /></Link> {:else} <TimeAgo value={createdAt} /> {/if} {#if actions} <!-- kept mounted while editing so the row keeps its height (no header shift) --> <div class={classes.actions()} class:invisible={!!editor}>{@render actions()}</div> {/if} </div> <div class={classes.content()}> {#if editor} <div class={classes.editor()}>{@render editor()}</div> {:else if bodyHtml} <article data-testid="commentBody" class={classes.markup()} use:codeblockToolbars={bodyHtml} use:mermaidDiagrams={bodyHtml} > <!-- eslint-disable-next-line svelte/no-at-html-tags -- sanitised in $lib/markup --> {@html bodyHtml} </article> {:else if body} <article data-testid="commentBody" class={classes.plain()}>{body}</article> {/if} {#if !editor} <Reactions {reactions} {subjectUri} {subjectCid} {knot} onchange={onreactionschange} class={classes.reactions()} /> {/if} </div> </div>{/if}