use bsky.app/sdk
This commit is contained in:
@@ -1,16 +1,17 @@
|
||||
import {app} from '@bsky.app/sdk/lexicons'
|
||||
import {ComponentChildren, h} from 'preact'
|
||||
import {useMemo} from 'preact/hooks'
|
||||
|
||||
import infoIcon from '../../assets/circleInfo_stroke2_corner0_rounded.svg'
|
||||
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'
|
||||
import {Globe} from '../icons/Globe'
|
||||
import {CONTENT_LABELS, labelsToInfo} from '../labels'
|
||||
import * as app from '../lexicons/app'
|
||||
import {getRkey} from '../util/rkey'
|
||||
import {getVerificationState} from '../util/verification-state'
|
||||
import {Link} from './link'
|
||||
import {VerificationCheck} from './verification-check'
|
||||
|
||||
export function Embed({
|
||||
content,
|
||||
@@ -32,7 +33,7 @@ export function Embed({
|
||||
}
|
||||
|
||||
// Case 1b: Gallery (Photos v2)
|
||||
if (AppBskyEmbedGallery.isView(content)) {
|
||||
if (app.bsky.embed.gallery.view.isTypeOf(content)) {
|
||||
return <GalleryEmbed content={content} labelInfo={labelInfo} />
|
||||
}
|
||||
|
||||
@@ -253,14 +254,14 @@ function GalleryEmbed({
|
||||
content,
|
||||
labelInfo,
|
||||
}: {
|
||||
content: AppBskyEmbedGallery.View
|
||||
content: app.bsky.embed.gallery.View
|
||||
labelInfo?: string
|
||||
}) {
|
||||
if (labelInfo) {
|
||||
return <Info>{labelInfo}</Info>
|
||||
}
|
||||
const images = content.items
|
||||
.filter(AppBskyEmbedGallery.isViewImage)
|
||||
.filter(i => app.bsky.embed.gallery.viewImage.isTypeOf(i))
|
||||
.map(i => ({thumb: i.thumbnail, alt: i.alt}))
|
||||
return <ImageGrid images={images} />
|
||||
}
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
import {app} from '@bsky.app/sdk/lexicons'
|
||||
import {RichText} from '@bsky.app/sdk/richtext'
|
||||
import {ComponentChild, h} from 'preact'
|
||||
|
||||
import {Container} from '#/components/container'
|
||||
import {Embed} from '#/components/embed'
|
||||
import {Link} from '#/components/link'
|
||||
import {VerificationCheck} from '#/components/verification-check'
|
||||
import {Like as LikeIcon} from '#/icons/Like'
|
||||
import {Reply as ReplyIcon} from '#/icons/Reply'
|
||||
import {Repost as RepostIcon} from '#/icons/Repost'
|
||||
import {Robot as RobotIcon} from '#/icons/Robot'
|
||||
import {CONTENT_LABELS} from '#/labels'
|
||||
import {niceDate} from '#/util/nice-date'
|
||||
import {prettyNumber} from '#/util/pretty-number'
|
||||
import {getRkey} from '#/util/rkey'
|
||||
import {getVerificationState} from '#/util/verification-state'
|
||||
|
||||
import logo from '../../assets/logo_full_name.svg'
|
||||
import {Like as LikeIcon} from '../icons/Like'
|
||||
import {Reply as ReplyIcon} from '../icons/Reply'
|
||||
import {Repost as RepostIcon} from '../icons/Repost'
|
||||
import {Robot as RobotIcon} from '../icons/Robot'
|
||||
import {CONTENT_LABELS} from '../labels'
|
||||
import * as app from '../lexicons/app'
|
||||
import {FacetRenderer} from '../util/facet-renderer'
|
||||
import {niceDate} from '../util/nice-date'
|
||||
import {prettyNumber} from '../util/pretty-number'
|
||||
import {getRkey} from '../util/rkey'
|
||||
import {getVerificationState} from '../util/verification-state'
|
||||
import {Container} from './container'
|
||||
import {Embed} from './embed'
|
||||
import {Link} from './link'
|
||||
import {VerificationCheck} from './verification-check'
|
||||
|
||||
interface Props {
|
||||
post: app.bsky.feed.defs.PostView
|
||||
@@ -147,7 +148,7 @@ function PostContent({record}: {record: app.bsky.feed.post.Main | null}) {
|
||||
// render an empty <p> that adds an extra flex gap above the embed
|
||||
if (!record?.text) return null
|
||||
|
||||
const rt = new FacetRenderer({text: record.text, facets: record.facets})
|
||||
const rt = new RichText({text: record.text, facets: record.facets})
|
||||
const richText: ComponentChild[] = []
|
||||
|
||||
let counter = 0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as app from './lexicons/app'
|
||||
import {app} from '@bsky.app/sdk/lexicons'
|
||||
|
||||
export const CONTENT_LABELS = ['porn', 'sexual', 'nudity', 'graphic-media']
|
||||
|
||||
|
||||
@@ -2,22 +2,22 @@ import '../index.css'
|
||||
|
||||
import {AtUriString, Client, type HandleString} from '@atproto/lex'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {app, com} from '@bsky.app/sdk/lexicons'
|
||||
import {h, render} from 'preact'
|
||||
import {useEffect, useMemo, useRef, useState} from 'preact/hooks'
|
||||
|
||||
import arrowBottom from '../../assets/arrowBottom_stroke2_corner0_rounded.svg'
|
||||
import logo from '../../assets/logo.svg'
|
||||
import {
|
||||
assertColorModeValues,
|
||||
ColorModeValues,
|
||||
initSystemColorMode,
|
||||
} from '../color-mode'
|
||||
import {Container} from '../components/container'
|
||||
import {Link} from '../components/link'
|
||||
import {Post} from '../components/post'
|
||||
import * as app from '../lexicons/app'
|
||||
import * as com from '../lexicons/com'
|
||||
import {niceDate} from '../util/nice-date'
|
||||
} from '#/color-mode'
|
||||
import {Container} from '#/components/container'
|
||||
import {Link} from '#/components/link'
|
||||
import {Post} from '#/components/post'
|
||||
import {niceDate} from '#/util/nice-date'
|
||||
|
||||
import arrowBottom from '../../assets/arrowBottom_stroke2_corner0_rounded.svg'
|
||||
import logo from '../../assets/logo.svg'
|
||||
|
||||
const DEFAULT_POST =
|
||||
'https://bsky.app/profile/did:plc:vjug55kidv6sye7ykr5faxxn/post/3jzn6g7ixgq2y'
|
||||
@@ -85,7 +85,7 @@ function LandingPage() {
|
||||
atUri = `at://${did}/app.bsky.feed.post/${rkey}`
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
throw new Error('Invalid Bluesky URL')
|
||||
throw new Error('Invalid Bluesky URL', {cause: err})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import '../index.css'
|
||||
|
||||
import {Client, isAtUriString} from '@atproto/lex'
|
||||
import {app} from '@bsky.app/sdk/lexicons'
|
||||
import {h, render} from 'preact'
|
||||
|
||||
import {applyTheme, initSystemColorMode} from '#/color-mode'
|
||||
import {Container} from '#/components/container'
|
||||
import {Link} from '#/components/link'
|
||||
import {Post} from '#/components/post'
|
||||
import {getRkey} from '#/util/rkey'
|
||||
|
||||
import logo from '../../assets/logo.svg'
|
||||
import {applyTheme, initSystemColorMode} from '../color-mode'
|
||||
import {Container} from '../components/container'
|
||||
import {Link} from '../components/link'
|
||||
import {Post} from '../components/post'
|
||||
import * as app from '../lexicons/app'
|
||||
import {getRkey} from '../util/rkey'
|
||||
|
||||
const root = document.getElementById('app')
|
||||
if (!root) throw new Error('No root element')
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
import * as app from '../lexicons/app'
|
||||
|
||||
type Facet = app.bsky.richtext.facet.Main
|
||||
|
||||
const encoder = new TextEncoder()
|
||||
const decoder = new TextDecoder()
|
||||
|
||||
export class FacetSegment {
|
||||
constructor(
|
||||
public text: string,
|
||||
public facet?: Facet,
|
||||
) {}
|
||||
|
||||
get link() {
|
||||
return this.facet?.features.find(app.bsky.richtext.facet.link.$isTypeOf)
|
||||
}
|
||||
|
||||
get mention() {
|
||||
return this.facet?.features.find(app.bsky.richtext.facet.mention.$isTypeOf)
|
||||
}
|
||||
|
||||
get tag() {
|
||||
return this.facet?.features.find(app.bsky.richtext.facet.tag.$isTypeOf)
|
||||
}
|
||||
}
|
||||
|
||||
export class FacetRenderer {
|
||||
private utf8: Uint8Array
|
||||
private facets: Facet[]
|
||||
|
||||
constructor({text, facets}: {text: string; facets?: Facet[]}) {
|
||||
this.utf8 = encoder.encode(text)
|
||||
this.facets = (facets ?? [])
|
||||
.filter(f => f.index.byteStart <= f.index.byteEnd)
|
||||
.sort((a, b) => a.index.byteStart - b.index.byteStart)
|
||||
}
|
||||
|
||||
private slice(start: number, end: number): string {
|
||||
return decoder.decode(this.utf8.slice(start, end))
|
||||
}
|
||||
|
||||
*segments(): Generator<FacetSegment, void, void> {
|
||||
if (!this.facets.length) {
|
||||
yield new FacetSegment(decoder.decode(this.utf8))
|
||||
return
|
||||
}
|
||||
|
||||
let textCursor = 0
|
||||
let facetCursor = 0
|
||||
do {
|
||||
const currFacet = this.facets[facetCursor]
|
||||
if (textCursor < currFacet.index.byteStart) {
|
||||
yield new FacetSegment(
|
||||
this.slice(textCursor, currFacet.index.byteStart),
|
||||
)
|
||||
} else if (textCursor > currFacet.index.byteStart) {
|
||||
facetCursor++
|
||||
continue
|
||||
}
|
||||
if (currFacet.index.byteStart < currFacet.index.byteEnd) {
|
||||
const subtext = this.slice(
|
||||
currFacet.index.byteStart,
|
||||
currFacet.index.byteEnd,
|
||||
)
|
||||
if (!subtext.trim()) {
|
||||
yield new FacetSegment(subtext)
|
||||
} else {
|
||||
yield new FacetSegment(subtext, currFacet)
|
||||
}
|
||||
}
|
||||
textCursor = currFacet.index.byteEnd
|
||||
facetCursor++
|
||||
} while (facetCursor < this.facets.length)
|
||||
if (textCursor < this.utf8.byteLength) {
|
||||
yield new FacetSegment(this.slice(textCursor, this.utf8.byteLength))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as app from '../lexicons/app'
|
||||
import {app} from '@bsky.app/sdk/lexicons'
|
||||
|
||||
export type VerificationState = {
|
||||
role: 'default' | 'verifier'
|
||||
|
||||
Reference in New Issue
Block a user