mirror of
https://github.com/dergigi/boris.git
synced 2025-12-17 22:54:30 +01:00
refactor(components): improve type safety and simplify IconButton
- Add proper type guards in ContentWithResolvedProfiles to avoid type assertions - Remove href/link functionality from IconButton component for simplification - Replace 'as any' with proper type narrowing using type predicates
This commit is contained in:
16
.cursor/rules/bookmarks.mdc
Normal file
16
.cursor/rules/bookmarks.mdc
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
description: documentation that's useful when dealing with bookmark events (kind:10003 or kind:30003) or anything related to NIP-51
|
||||||
|
alwaysApply: false
|
||||||
|
---
|
||||||
|
|
||||||
|
Read the nostrbook to understand how bookmarks work:
|
||||||
|
- https://nostrbook.dev/kinds/10003
|
||||||
|
- https://nostrbook.dev/kinds/30003
|
||||||
|
|
||||||
|
They are defined in NIP-51:
|
||||||
|
- https://github.com/nostr-protocol/nips/blob/master/51.md
|
||||||
|
|
||||||
|
Also refer to the applesauce bookmark helpers:
|
||||||
|
- https://github.com/hzrd149/applesauce/blob/17c9dbb0f2c263e2ebd01729ea2fa138eca12bd1/packages/core/src/helpers/bookmarks.ts
|
||||||
|
|
||||||
|
Make sure to always use applesauce, and use it properly.
|
||||||
19
kind-icons.txt
Normal file
19
kind-icons.txt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
kind:0 = fa-circle-user
|
||||||
|
kind:1 = fa-feather
|
||||||
|
kind:6 = fa-retweet
|
||||||
|
kind:7 = fa-heart
|
||||||
|
kind:20 = fa-image
|
||||||
|
kind:21 = fa-video
|
||||||
|
kind:22 = fa-video
|
||||||
|
kind:1063 = fa-file
|
||||||
|
kind:1337 = fa-laptop-code
|
||||||
|
kind:1617 = fa-code-pull-request
|
||||||
|
kind:1621 = fa-bug
|
||||||
|
kind:1984 = fa-exclamation-triangle
|
||||||
|
kind:9735 = fa-bolt
|
||||||
|
kind:9321 = fa-cloud-bolt
|
||||||
|
kind:9802 = fa-highlighter
|
||||||
|
kind:30023 = fa-newspaper
|
||||||
|
kind:10000 = fa-eye-slash
|
||||||
|
kind:10001 = fa-thumbtack
|
||||||
|
kind:10003 = fa-bookmark
|
||||||
@@ -11,17 +11,19 @@ const ContentWithResolvedProfiles: React.FC<Props> = ({ content }) => {
|
|||||||
const matches = extractNprofilePubkeys(content)
|
const matches = extractNprofilePubkeys(content)
|
||||||
const decoded = matches
|
const decoded = matches
|
||||||
.map((m) => {
|
.map((m) => {
|
||||||
try { return decode(m) } catch { return undefined }
|
try { return decode(m) } catch { return undefined as undefined }
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter((v): v is ReturnType<typeof decode> => Boolean(v))
|
||||||
|
|
||||||
const lookups = decoded.map((res) => getPubkeyFromDecodeResult(res as any)).filter(Boolean) as string[]
|
const lookups = decoded
|
||||||
|
.map((res) => getPubkeyFromDecodeResult(res))
|
||||||
|
.filter((v): v is string => typeof v === 'string')
|
||||||
|
|
||||||
const profiles = lookups.map((pubkey) => ({ pubkey, profile: useEventModel(Models.ProfileModel, [pubkey]) }))
|
const profiles = lookups.map((pubkey) => ({ pubkey, profile: useEventModel(Models.ProfileModel, [pubkey]) }))
|
||||||
|
|
||||||
let rendered = content
|
let rendered = content
|
||||||
matches.forEach((m, i) => {
|
matches.forEach((m, i) => {
|
||||||
const pk = getPubkeyFromDecodeResult(decoded[i] as any)
|
const pk = getPubkeyFromDecodeResult(decoded[i])
|
||||||
const found = profiles.find((p) => p.pubkey === pk)
|
const found = profiles.find((p) => p.pubkey === pk)
|
||||||
const name = found?.profile?.name || found?.profile?.display_name || found?.profile?.nip05 || `${pk?.slice(0,8)}...`
|
const name = found?.profile?.name || found?.profile?.display_name || found?.profile?.nip05 || `${pk?.slice(0,8)}...`
|
||||||
if (name) rendered = rendered.replace(m, `@${name}`)
|
if (name) rendered = rendered.replace(m, `@${name}`)
|
||||||
|
|||||||
@@ -9,9 +9,6 @@ interface IconButtonProps {
|
|||||||
ariaLabel?: string
|
ariaLabel?: string
|
||||||
variant?: 'primary' | 'success' | 'ghost'
|
variant?: 'primary' | 'success' | 'ghost'
|
||||||
size?: number
|
size?: number
|
||||||
href?: string
|
|
||||||
target?: string
|
|
||||||
rel?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const IconButton: React.FC<IconButtonProps> = ({
|
const IconButton: React.FC<IconButtonProps> = ({
|
||||||
@@ -20,35 +17,15 @@ const IconButton: React.FC<IconButtonProps> = ({
|
|||||||
title,
|
title,
|
||||||
ariaLabel,
|
ariaLabel,
|
||||||
variant = 'ghost',
|
variant = 'ghost',
|
||||||
size = 44,
|
size = 44
|
||||||
href,
|
|
||||||
target,
|
|
||||||
rel
|
|
||||||
}) => {
|
}) => {
|
||||||
const commonProps = {
|
|
||||||
className: `icon-button ${variant}`,
|
|
||||||
title,
|
|
||||||
'aria-label': ariaLabel || title,
|
|
||||||
style: { width: size, height: size }
|
|
||||||
} as const
|
|
||||||
|
|
||||||
if (href) {
|
|
||||||
return (
|
|
||||||
<a
|
|
||||||
{...(commonProps as any)}
|
|
||||||
href={href}
|
|
||||||
target={target || '_blank'}
|
|
||||||
rel={rel || 'noopener noreferrer'}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={icon} />
|
|
||||||
</a>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
{...(commonProps as any)}
|
className={`icon-button ${variant}`}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
title={title}
|
||||||
|
aria-label={ariaLabel || title}
|
||||||
|
style={{ width: size, height: size }}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={icon} />
|
<FontAwesomeIcon icon={icon} />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user