fix: 🐛
This commit is contained in:
@@ -240,13 +240,13 @@ function ListModeSwitch({
|
|||||||
setListMode: (listMode: TNoteListMode) => void
|
setListMode: (listMode: TNoteListMode) => void
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { deepBrowsing } = useDeepBrowsing()
|
const { deepBrowsing, lastScrollTop } = useDeepBrowsing()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'sticky top-12 bg-background z-10 duration-700 transition-transform',
|
'sticky top-12 bg-background z-10 duration-700 transition-transform',
|
||||||
deepBrowsing ? '-translate-y-[calc(100%+12rem)]' : ''
|
deepBrowsing && lastScrollTop > 800 ? '-translate-y-[calc(100%+12rem)]' : ''
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ function formatSoftware(software: string) {
|
|||||||
return parts[parts.length - 1]
|
return parts[parts.length - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
function RelayBadges({ relayInfo }: { relayInfo: TRelayInfo }) {
|
export function RelayBadges({ relayInfo }: { relayInfo: TRelayInfo }) {
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
{relayInfo.supported_nips?.includes(42) && (
|
{relayInfo.supported_nips?.includes(42) && (
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ import { SecondaryPageLink } from '@/PageManager'
|
|||||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
||||||
import { CommandDialog, CommandInput, CommandItem, CommandList } from '@/components/ui/command'
|
import { CommandDialog, CommandInput, CommandItem, CommandList } from '@/components/ui/command'
|
||||||
import { useSearchProfiles } from '@/hooks'
|
import { useSearchProfiles } from '@/hooks'
|
||||||
import { toNote, toNoteList, toProfile, toProfileList } from '@/lib/link'
|
import { toNote, toNoteList, toProfile, toProfileList, toRelay } from '@/lib/link'
|
||||||
import { generateImageByPubkey } from '@/lib/pubkey'
|
import { generateImageByPubkey } from '@/lib/pubkey'
|
||||||
|
import { normalizeUrl } from '@/lib/url'
|
||||||
import { TProfile } from '@/types'
|
import { TProfile } from '@/types'
|
||||||
import { Hash, Notebook, UserRound } from 'lucide-react'
|
import { Hash, Notebook, Server, UserRound } from 'lucide-react'
|
||||||
import { nip19 } from 'nostr-tools'
|
import { nip19 } from 'nostr-tools'
|
||||||
import { Dispatch, useEffect, useMemo, useState } from 'react'
|
import { Dispatch, useEffect, useMemo, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@@ -15,6 +16,13 @@ export function SearchDialog({ open, setOpen }: { open: boolean; setOpen: Dispat
|
|||||||
const [input, setInput] = useState('')
|
const [input, setInput] = useState('')
|
||||||
const [debouncedInput, setDebouncedInput] = useState(input)
|
const [debouncedInput, setDebouncedInput] = useState(input)
|
||||||
const { profiles } = useSearchProfiles(debouncedInput, 10)
|
const { profiles } = useSearchProfiles(debouncedInput, 10)
|
||||||
|
const normalizedUrl = useMemo(() => {
|
||||||
|
try {
|
||||||
|
return normalizeUrl(debouncedInput)
|
||||||
|
} catch {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}, [debouncedInput])
|
||||||
|
|
||||||
const list = useMemo(() => {
|
const list = useMemo(() => {
|
||||||
const search = input.trim()
|
const search = input.trim()
|
||||||
@@ -47,6 +55,7 @@ export function SearchDialog({ open, setOpen }: { open: boolean; setOpen: Dispat
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{!!normalizedUrl && <RelayItem url={normalizedUrl} onClick={() => setOpen(false)} />}
|
||||||
<NormalItem search={search} onClick={() => setOpen(false)} />
|
<NormalItem search={search} onClick={() => setOpen(false)} />
|
||||||
<HashtagItem search={search} onClick={() => setOpen(false)} />
|
<HashtagItem search={search} onClick={() => setOpen(false)} />
|
||||||
{profiles.map((profile) => (
|
{profiles.map((profile) => (
|
||||||
@@ -61,7 +70,7 @@ export function SearchDialog({ open, setOpen }: { open: boolean; setOpen: Dispat
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}, [input, profiles, setOpen])
|
}, [input, debouncedInput, profiles, setOpen])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handler = setTimeout(() => {
|
const handler = setTimeout(() => {
|
||||||
@@ -146,3 +155,14 @@ function ProfileItem({ profile, onClick }: { profile: TProfile; onClick?: () =>
|
|||||||
</SecondaryPageLink>
|
</SecondaryPageLink>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function RelayItem({ url, onClick }: { url: string; onClick?: () => void }) {
|
||||||
|
return (
|
||||||
|
<SecondaryPageLink to={toRelay(url)} onClick={onClick}>
|
||||||
|
<CommandItem>
|
||||||
|
<Server className="text-muted-foreground" />
|
||||||
|
<div className="font-semibold truncate">{url}</div>
|
||||||
|
</CommandItem>
|
||||||
|
</SecondaryPageLink>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ import client from '@/services/client.service'
|
|||||||
import { TRelayInfo } from '@/types'
|
import { TRelayInfo } from '@/types'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
export function useFetchRelayInfo(url: string) {
|
export function useFetchRelayInfo(url?: string) {
|
||||||
const [isFetching, setIsFetching] = useState(true)
|
const [isFetching, setIsFetching] = useState(true)
|
||||||
const [relayInfo, setRelayInfo] = useState<TRelayInfo | undefined>(undefined)
|
const [relayInfo, setRelayInfo] = useState<TRelayInfo | undefined>(undefined)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!url) return
|
||||||
const fetchRelayInfos = async () => {
|
const fetchRelayInfos = async () => {
|
||||||
setIsFetching(true)
|
setIsFetching(true)
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createContext, useContext, useEffect, useState } from 'react'
|
import { createContext, useContext, useEffect, useRef, useState } from 'react'
|
||||||
|
|
||||||
type TDeepBrowsingContext = {
|
type TDeepBrowsingContext = {
|
||||||
deepBrowsing: boolean
|
deepBrowsing: boolean
|
||||||
@@ -25,9 +25,12 @@ export function DeepBrowsingProvider({
|
|||||||
scrollAreaRef?: React.RefObject<HTMLDivElement>
|
scrollAreaRef?: React.RefObject<HTMLDivElement>
|
||||||
}) {
|
}) {
|
||||||
const [deepBrowsing, setDeepBrowsing] = useState(false)
|
const [deepBrowsing, setDeepBrowsing] = useState(false)
|
||||||
const [lastScrollTop, setLastScrollTop] = useState(0)
|
const lastScrollTopRef = useRef(
|
||||||
|
(!scrollAreaRef ? window.scrollY : scrollAreaRef.current?.scrollTop) || 0
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setDeepBrowsing(false)
|
||||||
if (!active) return
|
if (!active) return
|
||||||
|
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
@@ -43,19 +46,17 @@ export function DeepBrowsingProvider({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const scrollTop = (!scrollAreaRef ? window.scrollY : scrollAreaRef.current?.scrollTop) || 0
|
const scrollTop = (!scrollAreaRef ? window.scrollY : scrollAreaRef.current?.scrollTop) || 0
|
||||||
const diff = scrollTop - lastScrollTop
|
const diff = scrollTop - lastScrollTopRef.current
|
||||||
|
lastScrollTopRef.current = scrollTop
|
||||||
if (scrollTop <= 800) {
|
if (scrollTop <= 800) {
|
||||||
setDeepBrowsing(false)
|
setDeepBrowsing(false)
|
||||||
setLastScrollTop(scrollTop)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (diff > 20) {
|
if (diff > 20) {
|
||||||
setDeepBrowsing(true)
|
setDeepBrowsing(true)
|
||||||
setLastScrollTop(scrollTop)
|
|
||||||
} else if (diff < -20) {
|
} else if (diff < -20) {
|
||||||
setDeepBrowsing(false)
|
setDeepBrowsing(false)
|
||||||
setLastScrollTop(scrollTop)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,10 +71,10 @@ export function DeepBrowsingProvider({
|
|||||||
return () => {
|
return () => {
|
||||||
scrollAreaRef.current?.removeEventListener('scroll', handleScroll)
|
scrollAreaRef.current?.removeEventListener('scroll', handleScroll)
|
||||||
}
|
}
|
||||||
}, [lastScrollTop, active])
|
}, [active])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DeepBrowsingContext.Provider value={{ deepBrowsing, lastScrollTop }}>
|
<DeepBrowsingContext.Provider value={{ deepBrowsing, lastScrollTop: lastScrollTopRef.current }}>
|
||||||
{children}
|
{children}
|
||||||
</DeepBrowsingContext.Provider>
|
</DeepBrowsingContext.Provider>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user