import { useMemo, useState } from "react"; import { useUIState } from "src/useUIState"; import { useEntity, useReplicache } from "src/replicache"; import { BlockProps, BlockLayout } from "./Block"; import { usePublicationData, useNormalizedPublicationRecord, } from "app/(app)/lish/[did]/[publication]/dashboard/PublicationSWRProvider"; import { PublicationPostsList } from "app/(app)/lish/[did]/[publication]/PublicationPostsList"; import { Popover } from "components/Popover"; import { Toggle } from "components/Toggle"; import { SettingsTriggerButton } from "./SettingsTriggerButton"; import { PlaceholderText } from "./PostSizeIcons"; import { CloseTiny } from "components/Icons/CloseTiny"; type PostsListView = "small" | "medium"; export const PostsListBlock = (props: BlockProps & { preview?: boolean }) => { let isSelected = useUIState( (s) => !!s.selectedBlocks.find((b) => b.value === props.value), ); if (props.preview) { return ( ); } return ( } > ); }; function PostsListBlockContent({ entityID }: { entityID: string }) { let { data } = usePublicationData(); let publicationRecord = useNormalizedPublicationRecord(); let viewFact = useEntity(entityID, "posts-list/view"); let view: PostsListView = viewFact?.data.value ?? "medium"; let highlightFirstFact = useEntity( entityID, "posts-list/highlight-first-post", ); let highlightFirst = highlightFirstFact?.data.value ?? false; let filterTagFacts = useEntity(entityID, "posts-list/filter-tag"); let filteredPosts = useMemo(() => { if (!data?.documents) return data?.documents; let filterTags = filterTagFacts.map((f) => f.data.value); if (filterTags.length === 0) return data.documents; return data.documents.filter((d) => d.record.tags?.some((t) => filterTags.includes(t)), ); }, [data?.documents, filterTagFacts]); if (data === undefined) return ; if (!data?.publication) return ; return ( ); } function PostsListPlaceholder() { return (
{[0, 1, 2].map((i) => (

))}
); } function PostsListSettingsButton(props: { entityID: string }) { let { rep } = useReplicache(); let { data } = usePublicationData(); let viewFact = useEntity(props.entityID, "posts-list/view"); let view: PostsListView = viewFact?.data.value ?? "medium"; let highlightFirstFact = useEntity( props.entityID, "posts-list/highlight-first-post", ); let highlightFirst = highlightFirstFact?.data.value ?? false; let filterTagFacts = useEntity(props.entityID, "posts-list/filter-tag"); let selectedTags = useMemo( () => filterTagFacts.map((f) => f.data.value), [filterTagFacts], ); let [filterByTagEnabled, setFilterByTagEnabled] = useState( () => selectedTags.length > 0, ); let allTags = useMemo(() => { let tagSet = new Set(); for (let doc of data?.documents ?? []) { for (let tag of doc.record.tags ?? []) tagSet.add(tag); } return Array.from(tagSet).sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" }), ); }, [data?.documents]); return ( } >

List Layout

{( [ { value: "small", Icon: SmallIcon }, { value: "medium", Icon: MedIcon }, ] as { value: PostsListView; Icon: (props: { selected: boolean }) => React.ReactNode; }[] ).map((option) => { let selected = view === option.value || (option.value === "medium" && view !== "small"); return ( ); })}
{ if (!rep) return; rep.mutate.assertFact({ entity: props.entityID, attribute: "posts-list/highlight-first-post", data: { type: "boolean", value: !highlightFirst }, }); }} > Highlight First Post

Settings

{ if (filterByTagEnabled) { // turning off the filter clears any selected tags if (rep) for (let fact of filterTagFacts) rep.mutate.retractFact({ factID: fact.id }); setFilterByTagEnabled(false); } else { setFilterByTagEnabled(true); } }} > Filter by Tag {filterByTagEnabled && selectedTags.length > 0 && ( )}
{filterByTagEnabled ? (
{allTags.length === 0 ? (
no tags yet
) : (
{allTags.map((tag) => { let selectedFact = filterTagFacts.find( (f) => f.data.value === tag, ); let isSelected = !!selectedFact; return ( ); })}
)}
) : null}
); } const SmallIcon = ({ selected }: { selected: boolean }) => { return (
{[0, 1, 2].map((i) => (
{PlaceholderText("lg")}
{PlaceholderText("sm", "60%")}
))}
); }; const MedIcon = ({ selected }: { selected: boolean }) => { return (
{[0, 1].map((i) => (
{PlaceholderText("lg")} {PlaceholderText("md")} {PlaceholderText("md", "80%")}
{PlaceholderText("sm", "60%")}
))}
); };