grain.social is a photo sharing platform built on atproto.
grain.social
atproto
photography
appview
1import { GalleryView } from "$lexicon/types/social/grain/gallery/defs.ts";
2import { AtUri } from "@atproto/syntax";
3import { cn } from "@bigmoves/bff/components";
4import { Button } from "./Button.tsx";
5
6export type ButtonVariant = "button" | "icon-button";
7
8export function FavoriteButton({
9 class: classProp,
10 variant,
11 gallery,
12}: Readonly<{
13 class?: string;
14 variant?: "button" | "icon-button";
15 gallery: GalleryView;
16}>) {
17 const variantClass = variant === "icon-button"
18 ? "flex w-fit items-center gap-2 m-0 p-0 mt-2"
19 : "flex-1";
20 const galleryRkey = new AtUri(gallery.uri).rkey;
21 const favRrkey = gallery.viewer?.fav
22 ? new AtUri(gallery.viewer.fav).rkey
23 : undefined;
24 return (
25 <Button
26 variant={variant === "icon-button" ? "ghost" : "secondary"}
27 class={cn(
28 "whitespace-nowrap",
29 gallery.viewer?.fav ? "text-pink-500" : undefined,
30 variantClass,
31 classProp,
32 )}
33 type="button"
34 {...gallery.viewer?.fav
35 ? {
36 "hx-delete":
37 `/actions/${gallery.creator.did}/gallery/${galleryRkey}/favorite/${favRrkey}?variant=${variant}`,
38 }
39 : {
40 "hx-post":
41 `/actions/${gallery.creator.did}/gallery/${galleryRkey}/favorite?variant=${variant}`,
42 }}
43 hx-target="this"
44 hx-swap="outerHTML"
45 >
46 <i
47 class={cn(
48 "fa-heart",
49 variant === "icon-button" && gallery.viewer?.fav
50 ? "text-pink-500"
51 : undefined,
52 gallery.viewer?.fav ? "fa-solid" : "fa-regular",
53 )}
54 >
55 </i>{" "}
56 {gallery.favCount}
57 </Button>
58 );
59}