import {app} from '@bsky.app/sdk/lexicons'
import {ComponentChildren, h} from 'preact'
import {useMemo} from 'preact/hooks'
import {Link} from '#/components/link'
import {VerificationCheck} from '#/components/verification-check'
import {Globe} from '#/icons/Globe'
import {CONTENT_LABELS, labelsToInfo} from '#/labels'
import {getRkey} from '#/util/rkey'
import {getVerificationState} from '#/util/verification-state'
import infoIcon from '../../assets/arrowBottom_stroke2_corner0_rounded.svg'
import playIcon from '../../assets/play_filled_corner0_rounded.svg'
import starterPackIcon from '../../assets/starterPack.svg'
export function Embed({
content,
labels,
hideRecord,
}: {
content: app.bsky.feed.defs.PostView['embed']
labels: app.bsky.feed.defs.PostView['labels']
hideRecord?: boolean
}) {
const labelInfo = useMemo(() => labelsToInfo(labels), [labels])
if (!content) return null
try {
// Case 1: Image
if (app.bsky.embed.images.view.isTypeOf(content)) {
return
}
// Case 1b: Gallery (Photos v2)
if (app.bsky.embed.gallery.view.isTypeOf(content)) {
return
}
// Case 2: External link
if (app.bsky.embed.external.view.isTypeOf(content)) {
return
}
// Case 3: Record (quote or linked post)
if (app.bsky.embed.record.view.isTypeOf(content)) {
if (hideRecord) {
return null
}
const record = content.record
// Case 3.1: Post
if (app.bsky.embed.record.viewRecord.isTypeOf(record)) {
const pwiOptOut = !!record.author.labels?.find(
label => label.val === '!no-unauthenticated',
)
if (pwiOptOut) {
return (
The author of the quoted post has requested their posts not be
displayed on external sites.
)
}
let text
const validation = app.bsky.feed.post.$safeValidate(record.value)
if (validation.success) {
text = validation.value.text
}
const isAuthorLabeled = record.author.labels?.some(label =>
CONTENT_LABELS.includes(label.val),
)
const verification = getVerificationState({profile: record.author})
return (
}
{record.embeds?.map(embed => (
))}
)
}
// Case 3.2: List
if (app.bsky.graph.defs.listView.isTypeOf(record)) {
if (labelInfo) {
return {labelInfo}
}
return (
)
}
// Case 3.3: Feed
if (app.bsky.feed.defs.generatorView.isTypeOf(record)) {
if (labelInfo) {
return {labelInfo}
}
return (
)
}
// Case 3.4: Labeler
if (app.bsky.labeler.defs.labelerView.isTypeOf(record)) {
// Embed type does not exist in the app, so show nothing
return null
}
// Case 3.5: Starter pack
if (app.bsky.graph.defs.starterPackViewBasic.isTypeOf(record)) {
return
}
// Case 3.6: Post not found
if (app.bsky.embed.record.viewNotFound.isTypeOf(record)) {
return Quoted post not found, it may have been deleted.
}
// Case 3.7: Post blocked
if (app.bsky.embed.record.viewBlocked.isTypeOf(record)) {
return The quoted post is blocked.
}
// Case 3.8: Detached quote post
if (app.bsky.embed.record.viewDetached.isTypeOf(record)) {
// Just don't show anything
return null
}
// Unknown embed type
return null
}
// Case 4: Video
if (app.bsky.embed.video.view.isTypeOf(content)) {
return
}
// Case 5: Record with media
if (
app.bsky.embed.recordWithMedia.view.isTypeOf(content) &&
app.bsky.embed.record.viewRecord.isTypeOf(content.record.record)
) {
return (