a tool for shared writing and social publishing
1import { useEntitySetContext } from "components/EntitySetProvider";
2import { useEffect } from "react";
3import { useEntity } from "src/replicache";
4import { useUIState } from "src/useUIState";
5import { BlockProps, BlockLayout } from "../Block";
6import { elementId } from "src/utils/elementId";
7import { focusBlock } from "src/utils/focusBlock";
8import { AppBskyFeedDefs } from "@atproto/api";
9import { PostNotAvailable } from "./BlueskyEmbed";
10import { BlueskyPostEmpty } from "./BlueskyEmpty";
11
12import { BskyPostContent } from "app/lish/[did]/[publication]/[rkey]/BskyPostContent";
13import { PostView } from "@atproto/api/dist/client/types/app/bsky/feed/defs";
14
15export const BlueskyPostBlock = (props: BlockProps & { preview?: boolean }) => {
16 let { permissions } = useEntitySetContext();
17 let isSelected = useUIState((s) =>
18 s.selectedBlocks.find((b) => b.value === props.entityID),
19 );
20 let post = useEntity(props.entityID, "block/bluesky-post")?.data.value;
21 let clientHost = useEntity(props.entityID, "bluesky-post/host")?.data.value;
22
23 useEffect(() => {
24 if (props.preview) return;
25 let input = document.getElementById(elementId.block(props.entityID).input);
26 if (isSelected) {
27 input?.focus();
28 } else input?.blur();
29 }, [isSelected, props.entityID, props.preview]);
30
31 switch (true) {
32 case !post:
33 if (!permissions.write) return null;
34 return (
35 <label
36 id={props.preview ? undefined : elementId.block(props.entityID).input}
37 className={`
38 w-full h-[104px] p-2
39 text-tertiary hover:text-accent-contrast hover:cursor-pointer
40 flex flex-auto gap-2 items-center justify-center hover:border-2 border-dashed rounded-lg
41 ${isSelected ? "border-2 border-tertiary" : "border border-border"}
42 ${props.pageType === "canvas" && "bg-bg-page"}`}
43 onMouseDown={() => {
44 focusBlock(
45 { type: props.type, value: props.entityID, parent: props.parent },
46 { type: "start" },
47 );
48 }}
49 >
50 <BlueskyPostEmpty {...props} />
51 </label>
52 );
53
54 case AppBskyFeedDefs.isBlockedPost(post) ||
55 AppBskyFeedDefs.isBlockedAuthor(post) ||
56 AppBskyFeedDefs.isNotFoundPost(post):
57 return (
58 <BlockLayout isSelected={!!isSelected} className="w-full">
59 <PostNotAvailable />
60 </BlockLayout>
61 );
62
63 case AppBskyFeedDefs.isThreadViewPost(post):
64 let postView = post.post as PostView;
65
66 return (
67 <BlockLayout
68 isSelected={!!isSelected}
69 hasBackground="page"
70 borderOnHover
71 className="blueskyPostBlock sm:px-3! sm:py-2! px-2! py-1!"
72 >
73 <BskyPostContent
74 post={postView}
75 parent={undefined}
76 showBlueskyLink={true}
77 showEmbed={true}
78 avatarSize="large"
79 className="text-sm text-secondary "
80 clientHost={clientHost}
81 />
82 </BlockLayout>
83 );
84 }
85};