import { Component } from 'solid-js'; import { createSignal, createEffect } from "solid-js"; import styles from './globals.css?inline' import { agent } from "./lib/api"; import { formatData } from './lib/utils' import { DateFormat } from './lib/types' import BskyPost from './components/BskyPost'; interface Props { username?: string; feed?: string; search?: string; limit?: number; mode?: 'dark' | ''; linkTarget?: '_self' | '_blank' | '_parent' | '_top'; linkImage?: boolean; disableStyles?: boolean; customStyles?: string; customStylesFile?: string; loadMore?: boolean; disableImages?: boolean; disableVideos?: boolean; disableAutoplay?: boolean; dateFormat?: DateFormat; } const BskyEmbed: Component = ({ username, feed, limit = 10, mode = '', linkTarget = '_self', linkImage = false, customStyles = '', customStylesFile, disableStyles = false, search, loadMore = false, dateFormat, disableImages = false, disableVideos = false, disableAutoplay = false, }: Props) => { let modalRef: HTMLDialogElement | null = null; let modalImageRef: HTMLImageElement | null = null; const [isLoading, setIsLoading] = createSignal(false); const [feedData, setFeedData] = createSignal([]); const [displayLimit] = createSignal(limit); const [cursor, setCursor] = createSignal(undefined); createEffect((): void => { setIsLoading(true); // https://docs.bsky.app/docs/api/app-bsky-feed-get-author-feed fetchData(); }, [username, feed, search, displayLimit]); const fetchData = async (cursor?: string) => { if (username) { agent.app.bsky.feed.getAuthorFeed({ limit: displayLimit(), actor: username, filter: "posts_no_replies", cursor }).then(({success, data}): void => { if (success) { const feed = formatData(data) loadFeed(feed) setIsLoading(false) setCursor(data.cursor) } else { // todo error handling } }); } else if (feed) { agent.app.bsky.feed.getFeed({ limit: displayLimit(), feed, cursor }).then(({success, data}): void => { if (success) { const feed = formatData(data) loadFeed(feed) setIsLoading(false) setCursor(data.cursor) } else { // todo error handling } }); } else if (search) { agent.app.bsky.feed.searchPosts({ limit: displayLimit(), q: search, cursor }).then(({success, data}): void => { if (success) { const mappedData = {...data, feed: data.posts.map(p => ({post: p}))} const feed = formatData(mappedData) loadFeed(feed) setIsLoading(false) setCursor(data.cursor) } else { // todo error handling } }); } }; const handleModalContent = (e: Event, image: { fullsize: string; alt: string; }): void => { if (!linkImage && modalRef && modalImageRef) { e.preventDefault(); modalImageRef.src = image.fullsize; modalImageRef.alt = image.alt; modalRef.showModal(); } } const loadMorePosts = () => { setIsLoading(true); fetchData(cursor()); }; const loadFeed = (newData: any[]) => { const updatedFeed = [...feedData(), ...newData]; setFeedData(updatedFeed); }; return ( <> {!disableStyles && } {customStyles && } {customStylesFile && }
{(feedData().length > 0) && feedData().map((post, lastIndex) =>
)} {isLoading() && Array.from(Array(limit)).map(() =>
)} modalRef = el} class="backdrop:bg-gray-800 backdrop:opacity-90">
modalImageRef = el} src="" alt="" class="max-h-[90vh]"/>
{ loadMore && cursor() &&
}
); }; export default BskyEmbed;