feat: integrate nstart (#33)
This commit is contained in:
parent
7daa566cec
commit
a264b747e7
15 changed files with 154 additions and 47 deletions
|
|
@ -9,12 +9,18 @@ import { useState } from 'react'
|
|||
import { SimpleUserAvatar } from '../UserAvatar'
|
||||
import { SimpleUsername } from '../Username'
|
||||
|
||||
export default function AccountList({ afterSwitch }: { afterSwitch: () => void }) {
|
||||
export default function AccountList({
|
||||
className,
|
||||
afterSwitch
|
||||
}: {
|
||||
className?: string
|
||||
afterSwitch: () => void
|
||||
}) {
|
||||
const { accounts, account, switchAccount } = useNostr()
|
||||
const [switchingAccount, setSwitchingAccount] = useState<TAccountPointer | null>(null)
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<div className={cn('space-y-2', className)}>
|
||||
{accounts.map((act) => (
|
||||
<div
|
||||
key={`${act.pubkey}-${act.signerType}`}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import { Button } from '@/components/ui/button'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { useNostr } from '@/providers/NostrProvider'
|
||||
import { NstartModal } from 'nstart-modal'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import AccountList from '../AccountList'
|
||||
import BunkerLogin from './BunkerLogin'
|
||||
import PrivateKeyLogin from './PrivateKeyLogin'
|
||||
import GenerateNewAccount from './GenerateNewAccount'
|
||||
import PrivateKeyLogin from './PrivateKeyLogin'
|
||||
|
||||
type TAccountManagerPage = 'nsec' | 'bunker' | 'generate' | null
|
||||
|
||||
|
|
@ -36,38 +37,74 @@ function AccountManagerNav({
|
|||
close?: () => void
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const { nip07Login, accounts } = useNostr()
|
||||
const { nip07Login, bunkerLogin, nsecLogin, ncryptsecLogin, accounts } = useNostr()
|
||||
|
||||
return (
|
||||
<div onClick={(e) => e.stopPropagation()} className="flex flex-col gap-4">
|
||||
<div className="text-center text-muted-foreground text-sm font-semibold">
|
||||
{t('Add an Account')}
|
||||
<div onClick={(e) => e.stopPropagation()} className="flex flex-col gap-8">
|
||||
<div>
|
||||
<div className="text-center text-muted-foreground text-sm font-semibold">
|
||||
{t('Add an Account')}
|
||||
</div>
|
||||
<div className="space-y-2 mt-4">
|
||||
{!!window.nostr && (
|
||||
<Button onClick={() => nip07Login().then(() => close?.())} className="w-full">
|
||||
{t('Login with Browser Extension')}
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="secondary" onClick={() => setPage('bunker')} className="w-full">
|
||||
{t('Login with Bunker')}
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={() => setPage('nsec')} className="w-full">
|
||||
{t('Login with Private Key')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{!!window.nostr && (
|
||||
<Button onClick={() => nip07Login().then(() => close?.())} className="w-full">
|
||||
{t('Login with Browser Extension')}
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="secondary" onClick={() => setPage('bunker')} className="w-full">
|
||||
{t('Login with Bunker')}
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={() => setPage('nsec')} className="w-full">
|
||||
{t('Login with Private Key')}
|
||||
</Button>
|
||||
<Separator />
|
||||
<div className="text-center text-muted-foreground text-sm font-semibold">
|
||||
{t("Don't have an account yet?")}
|
||||
<div>
|
||||
<div className="text-center text-muted-foreground text-sm font-semibold">
|
||||
{t("Don't have an account yet?")}
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => {
|
||||
const wizard = new NstartModal({
|
||||
baseUrl: 'https://start.njump.me',
|
||||
an: 'Jumble',
|
||||
onComplete: ({ nostrLogin }) => {
|
||||
if (!nostrLogin) return
|
||||
|
||||
if (nostrLogin.startsWith('bunker://')) {
|
||||
bunkerLogin(nostrLogin)
|
||||
} else if (nostrLogin.startsWith('ncryptsec')) {
|
||||
ncryptsecLogin(nostrLogin)
|
||||
} else if (nostrLogin.startsWith('nsec')) {
|
||||
nsecLogin(nostrLogin)
|
||||
}
|
||||
}
|
||||
})
|
||||
close?.()
|
||||
wizard.open()
|
||||
}}
|
||||
className="w-full mt-4"
|
||||
>
|
||||
{t('Signup with Nstart wizard')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="link"
|
||||
onClick={() => setPage('generate')}
|
||||
className="w-full text-muted-foreground py-0 h-fit mt-1"
|
||||
>
|
||||
{t('or generate your private key here')}
|
||||
</Button>
|
||||
</div>
|
||||
<Button variant="secondary" onClick={() => setPage('generate')} className="w-full">
|
||||
{t('Generate New Account')}
|
||||
</Button>
|
||||
{accounts.length > 0 && (
|
||||
<>
|
||||
<Separator />
|
||||
<div className="text-center text-muted-foreground text-sm font-semibold">
|
||||
{t('Logged in Accounts')}
|
||||
<div>
|
||||
<div className="text-center text-muted-foreground text-sm font-semibold">
|
||||
{t('Logged in Accounts')}
|
||||
</div>
|
||||
<AccountList className="mt-4" afterSwitch={() => close?.()} />
|
||||
</div>
|
||||
<AccountList afterSwitch={() => close?.()} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import PostEditor from '@/components/PostEditor'
|
||||
import { useNostr } from '@/providers/NostrProvider'
|
||||
import { PencilLine } from 'lucide-react'
|
||||
import { useState } from 'react'
|
||||
import BottomNavigationBarItem from './BottomNavigationBarItem'
|
||||
|
||||
export default function PostButton() {
|
||||
const { checkLogin } = useNostr()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
return (
|
||||
|
|
@ -11,7 +13,9 @@ export default function PostButton() {
|
|||
<BottomNavigationBarItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setOpen(true)
|
||||
checkLogin(() => {
|
||||
setOpen(true)
|
||||
})
|
||||
}}
|
||||
>
|
||||
<PencilLine />
|
||||
|
|
|
|||
|
|
@ -1,10 +1,4 @@
|
|||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle
|
||||
} from '@/components/ui/dialog'
|
||||
import { Dialog, DialogContent } from '@/components/ui/dialog'
|
||||
import { Drawer, DrawerContent } from '@/components/ui/drawer'
|
||||
import { useScreenSize } from '@/providers/ScreenSizeProvider'
|
||||
import { Dispatch } from 'react'
|
||||
|
|
@ -33,11 +27,7 @@ export default function LoginDialog({
|
|||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogContent className="w-[520px] max-h-[90vh] overflow-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="hidden" />
|
||||
<DialogDescription className="hidden" />
|
||||
</DialogHeader>
|
||||
<DialogContent className="w-[520px] max-h-[90vh] py-8 overflow-auto">
|
||||
<AccountManager close={() => setOpen(false)} />
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { useNostr } from '@/providers/NostrProvider'
|
||||
import { useNoteStats } from '@/providers/NoteStatsProvider'
|
||||
import { MessageCircle } from 'lucide-react'
|
||||
import { Event } from 'nostr-tools'
|
||||
|
|
@ -8,6 +9,7 @@ import { formatCount } from './utils'
|
|||
|
||||
export default function ReplyButton({ event }: { event: Event }) {
|
||||
const { t } = useTranslation()
|
||||
const { checkLogin } = useNostr()
|
||||
const { noteStatsMap } = useNoteStats()
|
||||
const { replyCount } = useMemo(() => noteStatsMap.get(event.id) ?? {}, [noteStatsMap, event.id])
|
||||
const [open, setOpen] = useState(false)
|
||||
|
|
@ -18,7 +20,9 @@ export default function ReplyButton({ event }: { event: Event }) {
|
|||
className="flex gap-1 items-center text-muted-foreground enabled:hover:text-blue-400"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setOpen(true)
|
||||
checkLogin(() => {
|
||||
setOpen(true)
|
||||
})
|
||||
}}
|
||||
title={t('Reply')}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -94,7 +94,14 @@ export default function RepostButton({
|
|||
<DropdownMenuItem onClick={repost} disabled={!canRepost}>
|
||||
<Repeat /> {t('Repost')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setIsPostDialogOpen(true)}>
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
checkLogin(() => {
|
||||
setIsPostDialogOpen(true)
|
||||
})
|
||||
}}
|
||||
>
|
||||
<PencilLine /> {t('Quote')}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { useSecondaryPage } from '@/PageManager'
|
||||
import { toNote } from '@/lib/link'
|
||||
import { useNostr } from '@/providers/NostrProvider'
|
||||
import { Event } from 'nostr-tools'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
|
@ -23,6 +24,7 @@ export default function ReplyNote({
|
|||
highlight?: boolean
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const { checkLogin } = useNostr()
|
||||
const { push } = useSecondaryPage()
|
||||
const [isPostDialogOpen, setIsPostDialogOpen] = useState(false)
|
||||
|
||||
|
|
@ -56,7 +58,7 @@ export default function ReplyNote({
|
|||
className="text-muted-foreground hover:text-primary cursor-pointer"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setIsPostDialogOpen(true)
|
||||
checkLogin(() => setIsPostDialogOpen(true))
|
||||
}}
|
||||
>
|
||||
{t('reply')}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import PostEditor from '@/components/PostEditor'
|
||||
import { useNostr } from '@/providers/NostrProvider'
|
||||
import { PencilLine } from 'lucide-react'
|
||||
import { useState } from 'react'
|
||||
import SidebarItem from './SidebarItem'
|
||||
|
||||
export default function PostButton() {
|
||||
const { checkLogin } = useNostr()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
return (
|
||||
|
|
@ -13,7 +15,9 @@ export default function PostButton() {
|
|||
description="Post"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setOpen(true)
|
||||
checkLogin(() => {
|
||||
setOpen(true)
|
||||
})
|
||||
}}
|
||||
variant="default"
|
||||
className="bg-primary xl:justify-center gap-2"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue