diff options
author | dan <dan.abramov@gmail.com> | 2024-04-13 12:19:21 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-13 12:19:21 +0100 |
commit | 9fb20915e890be0993c15ad19b59105b78cf8f12 (patch) | |
tree | 5428a2f5c2eb93fa116af1afe6c71bfbc0a86f44 /bskyembed | |
parent | 1390b1dc9e35aafda328877c46e90860c6268453 (diff) | |
download | voidsky-9fb20915e890be0993c15ad19b59105b78cf8f12.tar.zst |
[Embed] Don't reuse DOM when changing embed (#3530)
* Don't reuse DOM when changing embed * add skeleton loading state 💀 * autoselect text --------- Co-authored-by: Samuel Newman <mozzius@protonmail.com>
Diffstat (limited to 'bskyembed')
-rw-r--r-- | bskyembed/src/components/container.tsx | 6 | ||||
-rw-r--r-- | bskyembed/src/screens/landing.tsx | 49 |
2 files changed, 43 insertions, 12 deletions
diff --git a/bskyembed/src/components/container.tsx b/bskyembed/src/components/container.tsx index a96addc8c..5b1b2b7fb 100644 --- a/bskyembed/src/components/container.tsx +++ b/bskyembed/src/components/container.tsx @@ -8,7 +8,7 @@ export function Container({ href, }: { children: ComponentChildren - href: string + href?: string }) { const ref = useRef<HTMLDivElement>(null) const prevHeight = useRef(0) @@ -39,7 +39,7 @@ export function Container({ ref={ref} className="w-full bg-white hover:bg-neutral-50 relative transition-colors max-w-[600px] min-w-[300px] flex border rounded-xl" onClick={() => { - if (ref.current) { + if (ref.current && href) { // forwardRef requires preact/compat - let's keep it simple // to keep the bundle size down const anchor = ref.current.querySelector('a') @@ -48,7 +48,7 @@ export function Container({ } } }}> - <Link href={href} /> + {href && <Link href={href} />} <div className="flex-1 px-4 pt-3 pb-2.5">{children}</div> </div> ) diff --git a/bskyembed/src/screens/landing.tsx b/bskyembed/src/screens/landing.tsx index f10100baa..0c5508935 100644 --- a/bskyembed/src/screens/landing.tsx +++ b/bskyembed/src/screens/landing.tsx @@ -1,7 +1,7 @@ import '../index.css' import {AppBskyFeedDefs, AppBskyFeedPost, AtUri, BskyAgent} from '@atproto/api' -import {Fragment, h, render} from 'preact' +import {h, render} from 'preact' import {useEffect, useMemo, useRef, useState} from 'preact/hooks' import arrowBottom from '../../assets/arrowBottom_stroke2_corner0_rounded.svg' @@ -30,6 +30,7 @@ render(<LandingPage />, root) function LandingPage() { const [uri, setUri] = useState('') const [error, setError] = useState<string | null>(null) + const [loading, setLoading] = useState(false) const [thread, setThread] = useState<AppBskyFeedDefs.ThreadViewPost | null>( null, ) @@ -37,6 +38,8 @@ function LandingPage() { useEffect(() => { void (async () => { setError(null) + setThread(null) + setLoading(true) try { let atUri = DEFAULT_URI @@ -98,6 +101,8 @@ function LandingPage() { } catch (err) { console.error(err) setError(err instanceof Error ? err.message : 'Invalid Bluesky URL') + } finally { + setLoading(false) } })() }, [uri]) @@ -122,16 +127,39 @@ function LandingPage() { <img src={arrowBottom as string} className="w-6" /> - <div className="w-full max-w-[600px] gap-8 flex flex-col"> - {uri && !error && thread && <Snippet thread={thread} />} - {!error && thread && <Post thread={thread} key={thread.post.uri} />} - {error && ( - <div className="w-full border border-red-500 bg-red-50 px-4 py-3 rounded-lg"> - <p className="text-red-500 text-center">{error}</p> + {loading ? ( + <Skeleton /> + ) : ( + <div className="w-full max-w-[600px] gap-8 flex flex-col"> + {!error && thread && uri && <Snippet thread={thread} />} + {!error && thread && <Post thread={thread} key={thread.post.uri} />} + {error && ( + <div className="w-full border border-red-500 bg-red-50 px-4 py-3 rounded-lg"> + <p className="text-red-500 text-center">{error}</p> + </div> + )} + </div> + )} + </main> + ) +} + +function Skeleton() { + return ( + <Container> + <div className="flex-1 flex-col flex gap-2 pb-8"> + <div className="flex gap-2.5 items-center"> + <div className="w-10 h-10 overflow-hidden rounded-full bg-neutral-100 shrink-0 animate-pulse" /> + <div className="flex-1"> + <div className="bg-neutral-100 animate-pulse w-64 h-4 rounded" /> + <div className="bg-neutral-100 animate-pulse w-32 h-3 mt-1 rounded" /> </div> - )} + </div> + <div className="w-full h-4 mt-2 bg-neutral-100 rounded animate-pulse" /> + <div className="w-5/6 h-4 bg-neutral-100 rounded animate-pulse" /> + <div className="w-3/4 h-4 bg-neutral-100 rounded animate-pulse" /> </div> - </main> + </Container> ) } @@ -195,6 +223,9 @@ function Snippet({thread}: {thread: AppBskyFeedDefs.ThreadViewPost}) { className="border rounded-lg py-3 w-full px-4" readOnly autoFocus + onFocus={() => { + ref.current?.select() + }} /> <button className="rounded-lg bg-brand text-white color-white py-3 px-4 whitespace-nowrap min-w-28" |