~james/core

core/web/src/lib/components/reaction/Reaction.svelte -rw-r--r-- 1.9 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 17 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<script lang="ts">
	import { reactorNames, type ReactionGroup } from "#lib/components/reaction/reactions.ts";
	import { formatCount } from "#lib/format.ts";
	import Button from "#lib/components/ui/Button.svelte";
	import Tooltip from "#lib/components/ui/Tooltip.svelte";

	interface Props {
		reaction: ReactionGroup;
		ontoggle?: () => void; // null for loggedout users
		pending?: boolean;
		failed?: boolean;
		onhold?: () => void;
	}

	let { reaction, ontoggle, pending = false, failed = false, onhold }: Props = $props();

	const HOLD = 500;
	let timer: ReturnType<typeof setTimeout> | undefined;
	let held = false;

	const release = () => {
		clearTimeout(timer);
		timer = undefined;
	};

	const onpointerdown = (event: PointerEvent) => {
		held = false;
		if (!onhold || event.pointerType !== "touch") return;
		release();
		timer = setTimeout(() => {
			timer = undefined;
			held = true;
			onhold();
		}, HOLD);
	};

	const onclick = () => {
		if (held) {
			held = false;
			return;
		}
		ontoggle?.();
	};

	const title = $derived(reactorNames(reaction));
</script>

<Tooltip content="Something went wrong. Try again." disabled={!failed}>
	<Button
		data-testid="reactionChip"
		data-kind={reaction.kind}
		data-count={reaction.count}
		size="small"
		variant={failed ? "danger" : "default"}
		{title}
		disabled={pending}
		aria-pressed={reaction.isReacted}
		{onclick}
		{onpointerdown}
		onpointerup={release}
		onpointercancel={release}
		onpointerleave={release}
		class={reaction.isReacted && !failed
			? "border-background-info-emphasis/10 bg-background-info-subtle shadow-none hover:bg-background-info-subtle-hover dark:border-background-info-emphasis/30"
			: "shadow-none"}
	>
		<span class="typography-paragraph-large leading-none">{reaction.kind}</span>
		<span class="typography-paragraph-small leading-none">{formatCount(reaction.count)}</span>
	</Button>
</Tooltip>