add verification
This commit is contained in:
committed by
Eric Bailey
parent
25b56c40d2
commit
e78fa95c3e
@@ -7,11 +7,12 @@ import {
|
|||||||
import {ModeratorData} from '../../data/getModeratorData.js'
|
import {ModeratorData} from '../../data/getModeratorData.js'
|
||||||
import {PostData} from '../../data/getPostData.js'
|
import {PostData} from '../../data/getPostData.js'
|
||||||
import {atoms as a, theme as t} from '../../theme/index.js'
|
import {atoms as a, theme as t} from '../../theme/index.js'
|
||||||
import * as bsky from '../../types/bsky.js'
|
import * as bsky from '../../types/bsky/index.js'
|
||||||
import {formatCount} from '../../util/formatCount.js'
|
import {formatCount} from '../../util/formatCount.js'
|
||||||
import {formatDate} from '../../util/formatDate.js'
|
import {formatDate} from '../../util/formatDate.js'
|
||||||
import {moderatePost} from '../../util/moderatePost.js'
|
import {moderatePost} from '../../util/moderatePost.js'
|
||||||
import {sanitizeHandle} from '../../util/sanitizeHandle.js'
|
import {sanitizeHandle} from '../../util/sanitizeHandle.js'
|
||||||
|
import {getVerificationState} from '../../util/verificationState.js'
|
||||||
import {Avatar} from '../Avatar.js'
|
import {Avatar} from '../Avatar.js'
|
||||||
import {Box} from '../Box.js'
|
import {Box} from '../Box.js'
|
||||||
import {Heart} from '../icons/Heart.js'
|
import {Heart} from '../icons/Heart.js'
|
||||||
@@ -21,6 +22,7 @@ import {Repost} from '../icons/Repost.js'
|
|||||||
import {PostEmbed} from '../PostEmbed.js'
|
import {PostEmbed} from '../PostEmbed.js'
|
||||||
import {RichText} from '../RichText.js'
|
import {RichText} from '../RichText.js'
|
||||||
import {Text} from '../Text.js'
|
import {Text} from '../Text.js'
|
||||||
|
import {VerificationCheck} from '../VerificationCheck.js'
|
||||||
|
|
||||||
export function Post({
|
export function Post({
|
||||||
post,
|
post,
|
||||||
@@ -52,6 +54,7 @@ export function Post({
|
|||||||
: undefined
|
: undefined
|
||||||
const hasInteractions = post.likeCount > 0 || post.repostCount > 0
|
const hasInteractions = post.likeCount > 0 || post.repostCount > 0
|
||||||
const moderation = moderatePost(post, moderatorData.moderationOptions)
|
const moderation = moderatePost(post, moderatorData.moderationOptions)
|
||||||
|
const verification = getVerificationState({profile: post.author})
|
||||||
|
|
||||||
const bgTop = avatar?.colors?.muted ?? '#1083fe'
|
const bgTop = avatar?.colors?.muted ?? '#1083fe'
|
||||||
const bgBottom = avatar?.colors?.lightMuted ?? '#67b0fe'
|
const bgBottom = avatar?.colors?.lightMuted ?? '#67b0fe'
|
||||||
@@ -91,9 +94,20 @@ export function Post({
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Box cx={[a.flex_col, a.flex_1]}>
|
<Box cx={[a.flex_col, a.flex_1]}>
|
||||||
<Text cx={[a.text_md, a.font_heavy, a.pb_2xs, a.line_clamp_2]}>
|
<Box cx={[a.flex_1, a.flex_row]}>
|
||||||
{post.author.displayName || post.author.handle}
|
<Text cx={[a.text_md, a.font_heavy, a.pb_2xs, a.line_clamp_2]}>
|
||||||
</Text>
|
{post.author.displayName || post.author.handle}
|
||||||
|
</Text>
|
||||||
|
{verification.isVerified && (
|
||||||
|
<Box cx={[a.pl_xs, a.pt_2xs]}>
|
||||||
|
<VerificationCheck
|
||||||
|
size={12}
|
||||||
|
verifier={verification.role === 'verifier'}
|
||||||
|
fill={t.palette.primary_500}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
<Text
|
<Text
|
||||||
cx={[a.text_sm, t.atoms.text_contrast_medium, a.line_clamp_1]}>
|
cx={[a.text_sm, t.atoms.text_contrast_medium, a.line_clamp_1]}>
|
||||||
{sanitizeHandle(post.author.handle, '@')}
|
{sanitizeHandle(post.author.handle, '@')}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
import {ModeratorData} from '../data/getModeratorData.js'
|
import {ModeratorData} from '../data/getModeratorData.js'
|
||||||
import {Image as ImageSource, PostData} from '../data/getPostData.js'
|
import {Image as ImageSource, PostData} from '../data/getPostData.js'
|
||||||
import {atoms as a, theme as t} from '../theme/index.js'
|
import {atoms as a, theme as t} from '../theme/index.js'
|
||||||
import * as bsky from '../types/bsky.js'
|
import * as bsky from '../types/bsky/index.js'
|
||||||
import {getModerationCauseInfo} from '../util/getModerationCauseInfo.js'
|
import {getModerationCauseInfo} from '../util/getModerationCauseInfo.js'
|
||||||
import {getStarterPackImageUri} from '../util/getStarterPackImageUri.js'
|
import {getStarterPackImageUri} from '../util/getStarterPackImageUri.js'
|
||||||
import {Embed, EmbedType, parseEmbed} from '../util/parseEmbed.js'
|
import {Embed, EmbedType, parseEmbed} from '../util/parseEmbed.js'
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ import {
|
|||||||
import {ModeratorData} from '../../data/getModeratorData.js'
|
import {ModeratorData} from '../../data/getModeratorData.js'
|
||||||
import {PostData} from '../../data/getPostData.js'
|
import {PostData} from '../../data/getPostData.js'
|
||||||
import {atoms as a, theme as t} from '../../theme/index.js'
|
import {atoms as a, theme as t} from '../../theme/index.js'
|
||||||
import * as bsky from '../../types/bsky.js'
|
import * as bsky from '../../types/bsky/index.js'
|
||||||
import {getModerationCauseInfo} from '../../util/getModerationCauseInfo.js'
|
import {getModerationCauseInfo} from '../../util/getModerationCauseInfo.js'
|
||||||
import {moderatePost} from '../../util/moderatePost.js'
|
import {moderatePost} from '../../util/moderatePost.js'
|
||||||
import {sanitizeHandle} from '../../util/sanitizeHandle.js'
|
import {sanitizeHandle} from '../../util/sanitizeHandle.js'
|
||||||
|
import {getVerificationState} from '../../util/verificationState.js'
|
||||||
import {viewRecordToPostView} from '../../util/viewRecordToPostView.js'
|
import {viewRecordToPostView} from '../../util/viewRecordToPostView.js'
|
||||||
import {Avatar} from '../Avatar.js'
|
import {Avatar} from '../Avatar.js'
|
||||||
import {Box} from '../Box.js'
|
import {Box} from '../Box.js'
|
||||||
@@ -19,6 +20,7 @@ import {ModeratedEmbed} from '../ModeratedEmbed.js'
|
|||||||
import {PostEmbed} from '../PostEmbed.js'
|
import {PostEmbed} from '../PostEmbed.js'
|
||||||
import {RichText} from '../RichText.js'
|
import {RichText} from '../RichText.js'
|
||||||
import {Text} from '../Text.js'
|
import {Text} from '../Text.js'
|
||||||
|
import {VerificationCheck} from '../VerificationCheck.js'
|
||||||
|
|
||||||
export function QuotePost({
|
export function QuotePost({
|
||||||
embed,
|
embed,
|
||||||
@@ -43,6 +45,7 @@ export function QuotePost({
|
|||||||
: undefined
|
: undefined
|
||||||
const postView = viewRecordToPostView(embed)
|
const postView = viewRecordToPostView(embed)
|
||||||
const moderation = moderatePost(postView, moderatorData.moderationOptions)
|
const moderation = moderatePost(postView, moderatorData.moderationOptions)
|
||||||
|
const verification = getVerificationState({profile: embed.author})
|
||||||
|
|
||||||
const mod = moderation.ui('contentView')
|
const mod = moderation.ui('contentView')
|
||||||
const info = getModerationCauseInfo({
|
const info = getModerationCauseInfo({
|
||||||
@@ -79,10 +82,32 @@ export function QuotePost({
|
|||||||
moderatorData={moderatorData}
|
moderatorData={moderatorData}
|
||||||
/>
|
/>
|
||||||
<Box cx={[a.flex_row, a.align_center, a.gap_xs, a.pt_2xs]}>
|
<Box cx={[a.flex_row, a.align_center, a.gap_xs, a.pt_2xs]}>
|
||||||
<Text cx={[a.text_sm, a.font_bold]}>
|
<Text
|
||||||
|
cx={[
|
||||||
|
a.text_sm,
|
||||||
|
a.font_bold,
|
||||||
|
a.flex_shrink_0,
|
||||||
|
{maxWidth: '70%'},
|
||||||
|
a.line_clamp_1,
|
||||||
|
]}>
|
||||||
{author.displayName || author.handle}
|
{author.displayName || author.handle}
|
||||||
</Text>
|
</Text>
|
||||||
<Text cx={[a.text_xs, t.atoms.text_contrast_medium]}>
|
{verification.isVerified && (
|
||||||
|
<Box cx={[{marginTop: -2}]}>
|
||||||
|
<VerificationCheck
|
||||||
|
size={12}
|
||||||
|
verifier={verification.role === 'verifier'}
|
||||||
|
fill={t.palette.primary_500}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
<Text
|
||||||
|
cx={[
|
||||||
|
a.text_xs,
|
||||||
|
t.atoms.text_contrast_medium,
|
||||||
|
{flexShrink: 10},
|
||||||
|
a.line_clamp_1,
|
||||||
|
]}>
|
||||||
{sanitizeHandle(author.handle, '@')}
|
{sanitizeHandle(author.handle, '@')}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api'
|
import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api'
|
||||||
|
|
||||||
import * as bsky from '../types/bsky.js'
|
import * as bsky from '../types/bsky/index.js'
|
||||||
import {Butterfly} from './Butterfly.js'
|
import {Butterfly} from './Butterfly.js'
|
||||||
import {Img} from './Img.js'
|
import {Img} from './Img.js'
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import {type IconProps} from './icons/types.js'
|
||||||
|
import {VerifiedCheck} from './icons/VerifiedCheck.js'
|
||||||
|
import {VerifierCheck} from './icons/VerifierCheck.js'
|
||||||
|
|
||||||
|
export function VerificationCheck({
|
||||||
|
verifier,
|
||||||
|
...rest
|
||||||
|
}: IconProps & {
|
||||||
|
verifier?: boolean
|
||||||
|
}) {
|
||||||
|
return verifier ? <VerifierCheck {...rest} /> : <VerifiedCheck {...rest} />
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import {IconProps} from './types.js'
|
||||||
|
|
||||||
|
export function VerifiedCheck({size, fill}: IconProps) {
|
||||||
|
return (
|
||||||
|
<svg fill="none" viewBox="0 0 24 24" width={size} height={size}>
|
||||||
|
<circle cx="12" cy="12" r="11.5" fill={fill} />
|
||||||
|
<path
|
||||||
|
fill="#fff"
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M17.659 8.175a1.361 1.361 0 0 1 0 1.925l-6.224 6.223a1.361 1.361 0 0 1-1.925 0L6.4 13.212a1.361 1.361 0 0 1 1.925-1.925l2.149 2.148 5.26-5.26a1.361 1.361 0 0 1 1.925 0Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import {IconProps} from './types.js'
|
||||||
|
|
||||||
|
export function VerifierCheck({size, fill}: IconProps) {
|
||||||
|
return (
|
||||||
|
<svg fill="none" viewBox="0 0 24 24" width={size} height={size}>
|
||||||
|
<path
|
||||||
|
fill={fill}
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M8.792 1.615a4.154 4.154 0 0 1 6.416 0 4.154 4.154 0 0 0 3.146 1.515 4.154 4.154 0 0 1 4 5.017 4.154 4.154 0 0 0 .777 3.404 4.154 4.154 0 0 1-1.427 6.255 4.153 4.153 0 0 0-2.177 2.73 4.154 4.154 0 0 1-5.781 2.784 4.154 4.154 0 0 0-3.492 0 4.154 4.154 0 0 1-5.78-2.784 4.154 4.154 0 0 0-2.178-2.73A4.154 4.154 0 0 1 .87 11.551a4.154 4.154 0 0 0 .776-3.404A4.154 4.154 0 0 1 5.646 3.13a4.154 4.154 0 0 0 3.146-1.515Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="#fff"
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M17.861 8.26a1.438 1.438 0 0 1 0 2.033l-6.571 6.571a1.437 1.437 0 0 1-2.033 0L5.97 13.58a1.438 1.438 0 0 1 2.033-2.033l2.27 2.269 5.554-5.555a1.437 1.437 0 0 1 2.033 0Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import {ValidationResult} from '@atproto/lexicon'
|
import {ValidationResult} from '@atproto/lexicon'
|
||||||
|
|
||||||
|
export * as profile from './profile.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fast type checking without full schema validation, for use with data we
|
* Fast type checking without full schema validation, for use with data we
|
||||||
* trust, or for non-critical path use cases. Why? Our SDK's `is*` identity
|
* trust, or for non-critical path use cases. Why? Our SDK's `is*` identity
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import {type AppBskyActorDefs, type ChatBskyActorDefs} from '@atproto/api'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches any profile view exported by our SDK
|
||||||
|
*/
|
||||||
|
export type AnyProfileView =
|
||||||
|
| AppBskyActorDefs.ProfileViewBasic
|
||||||
|
| AppBskyActorDefs.ProfileView
|
||||||
|
| AppBskyActorDefs.ProfileViewDetailed
|
||||||
|
| ChatBskyActorDefs.ProfileViewBasic
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import {useMemo} from 'react'
|
||||||
|
|
||||||
|
import * as bsky from '../types/bsky/index.js'
|
||||||
|
|
||||||
|
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