Add verification checkmarks to embed.bsky.app (#8644)
* update vite+typescript * update atproto api to latest, split out utils * add checkmark to post * add checkie to embed * revert change to example post * fix ext link color
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
export function niceDate(date: number | string | Date) {
|
||||
const d = new Date(date)
|
||||
return `${d.toLocaleDateString('en-us', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
})} at ${d.toLocaleTimeString(undefined, {
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
})}`
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* This file is a copy of what exists in the social-app
|
||||
*/
|
||||
|
||||
import {
|
||||
AppBskyEmbedExternal,
|
||||
AppBskyEmbedImages,
|
||||
AppBskyEmbedRecord,
|
||||
AppBskyEmbedRecordWithMedia,
|
||||
AppBskyEmbedVideo,
|
||||
AppBskyFeedDefs,
|
||||
AppBskyGraphDefs,
|
||||
AppBskyLabelerDefs,
|
||||
} from '@atproto/api'
|
||||
|
||||
export type Embed =
|
||||
| {
|
||||
type: 'post'
|
||||
view: AppBskyEmbedRecord.ViewRecord
|
||||
}
|
||||
| {
|
||||
type: 'post_not_found'
|
||||
view: AppBskyEmbedRecord.ViewNotFound
|
||||
}
|
||||
| {
|
||||
type: 'post_blocked'
|
||||
view: AppBskyEmbedRecord.ViewBlocked
|
||||
}
|
||||
| {
|
||||
type: 'post_detached'
|
||||
view: AppBskyEmbedRecord.ViewDetached
|
||||
}
|
||||
| {
|
||||
type: 'feed'
|
||||
view: AppBskyFeedDefs.GeneratorView
|
||||
}
|
||||
| {
|
||||
type: 'list'
|
||||
view: AppBskyGraphDefs.ListView
|
||||
}
|
||||
| {
|
||||
type: 'labeler'
|
||||
view: AppBskyLabelerDefs.LabelerView
|
||||
}
|
||||
| {
|
||||
type: 'starter_pack'
|
||||
view: AppBskyGraphDefs.StarterPackViewBasic
|
||||
}
|
||||
| {
|
||||
type: 'images'
|
||||
view: AppBskyEmbedImages.View
|
||||
}
|
||||
| {
|
||||
type: 'link'
|
||||
view: AppBskyEmbedExternal.View
|
||||
}
|
||||
| {
|
||||
type: 'video'
|
||||
view: AppBskyEmbedVideo.View
|
||||
}
|
||||
| {
|
||||
type: 'post_with_media'
|
||||
view: Embed
|
||||
media: Embed
|
||||
}
|
||||
| {
|
||||
type: 'unknown'
|
||||
view: null
|
||||
}
|
||||
|
||||
export type EmbedType<T extends Embed['type']> = Extract<Embed, {type: T}>
|
||||
|
||||
export function parseEmbedRecordView({record}: AppBskyEmbedRecord.View): Embed {
|
||||
if (AppBskyEmbedRecord.isViewRecord(record)) {
|
||||
return {
|
||||
type: 'post',
|
||||
view: record,
|
||||
}
|
||||
} else if (AppBskyEmbedRecord.isViewNotFound(record)) {
|
||||
return {
|
||||
type: 'post_not_found',
|
||||
view: record,
|
||||
}
|
||||
} else if (AppBskyEmbedRecord.isViewBlocked(record)) {
|
||||
return {
|
||||
type: 'post_blocked',
|
||||
view: record,
|
||||
}
|
||||
} else if (AppBskyEmbedRecord.isViewDetached(record)) {
|
||||
return {
|
||||
type: 'post_detached',
|
||||
view: record,
|
||||
}
|
||||
} else if (AppBskyFeedDefs.isGeneratorView(record)) {
|
||||
return {
|
||||
type: 'feed',
|
||||
view: record,
|
||||
}
|
||||
} else if (AppBskyGraphDefs.isListView(record)) {
|
||||
return {
|
||||
type: 'list',
|
||||
view: record,
|
||||
}
|
||||
} else if (AppBskyLabelerDefs.isLabelerView(record)) {
|
||||
return {
|
||||
type: 'labeler',
|
||||
view: record,
|
||||
}
|
||||
} else if (AppBskyGraphDefs.isStarterPackViewBasic(record)) {
|
||||
return {
|
||||
type: 'starter_pack',
|
||||
view: record,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
type: 'unknown',
|
||||
view: null,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function parseEmbed(embed: AppBskyFeedDefs.PostView['embed']): Embed {
|
||||
if (AppBskyEmbedImages.isView(embed)) {
|
||||
return {
|
||||
type: 'images',
|
||||
view: embed,
|
||||
}
|
||||
} else if (AppBskyEmbedExternal.isView(embed)) {
|
||||
return {
|
||||
type: 'link',
|
||||
view: embed,
|
||||
}
|
||||
} else if (AppBskyEmbedVideo.isView(embed)) {
|
||||
return {
|
||||
type: 'video',
|
||||
view: embed,
|
||||
}
|
||||
} else if (AppBskyEmbedRecord.isView(embed)) {
|
||||
return parseEmbedRecordView(embed)
|
||||
} else if (AppBskyEmbedRecordWithMedia.isView(embed)) {
|
||||
return {
|
||||
type: 'post_with_media',
|
||||
view: parseEmbedRecordView(embed.record),
|
||||
media: parseEmbed(embed.media),
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
type: 'unknown',
|
||||
view: null,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
const formatter = new Intl.NumberFormat('en-US', {
|
||||
notation: 'compact',
|
||||
maximumFractionDigits: 1,
|
||||
roundingMode: 'trunc',
|
||||
})
|
||||
|
||||
export function prettyNumber(number: number) {
|
||||
return formatter.format(number)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import {AtUri} from '@atproto/api'
|
||||
|
||||
export function getRkey({uri}: {uri: string}): string {
|
||||
const at = new AtUri(uri)
|
||||
return at.rkey
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import * as bsky from '../types/bsky'
|
||||
|
||||
export type VerificationState = {
|
||||
role: 'default' | 'verifier'
|
||||
isVerified: boolean
|
||||
}
|
||||
|
||||
export function getVerificationState({
|
||||
profile,
|
||||
}: {
|
||||
profile?: bsky.profile.AnyProfileView
|
||||
}): VerificationState {
|
||||
if (!profile || !profile.verification) {
|
||||
return {
|
||||
role: 'default',
|
||||
isVerified: false,
|
||||
}
|
||||
}
|
||||
|
||||
const {verifiedStatus, trustedVerifierStatus} = profile.verification
|
||||
const isVerifiedUser = ['valid', 'invalid'].includes(verifiedStatus)
|
||||
const isVerifierUser = ['valid', 'invalid'].includes(trustedVerifierStatus)
|
||||
const isVerified =
|
||||
(isVerifiedUser && verifiedStatus === 'valid') ||
|
||||
(isVerifierUser && trustedVerifierStatus === 'valid')
|
||||
|
||||
return {
|
||||
role: isVerifierUser ? 'verifier' : 'default',
|
||||
isVerified,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user