feat: add quick account switch interaction
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
import { Badge } from '@/components/ui/badge'
|
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { isSameAccount } from '@/lib/account'
|
import { isSameAccount } from '@/lib/account'
|
||||||
import { formatPubkey } from '@/lib/pubkey'
|
import { formatPubkey } from '@/lib/pubkey'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { useNostr } from '@/providers/NostrProvider'
|
import { useNostr } from '@/providers/NostrProvider'
|
||||||
import { TAccountPointer, TSignerType } from '@/types'
|
import { TAccountPointer } from '@/types'
|
||||||
import { Loader, Trash2 } from 'lucide-react'
|
import { Loader, Trash2 } from 'lucide-react'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
import SignerTypeBadge from '../SignerTypeBadge'
|
||||||
import { SimpleUserAvatar } from '../UserAvatar'
|
import { SimpleUserAvatar } from '../UserAvatar'
|
||||||
import { SimpleUsername } from '../Username'
|
import { SimpleUsername } from '../Username'
|
||||||
|
|
||||||
@@ -74,17 +74,3 @@ export default function AccountList({
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function SignerTypeBadge({ signerType }: { signerType: TSignerType }) {
|
|
||||||
if (signerType === 'nip-07') {
|
|
||||||
return <Badge className=" bg-green-400 hover:bg-green-400/80">NIP-07</Badge>
|
|
||||||
} else if (signerType === 'bunker') {
|
|
||||||
return <Badge className=" bg-blue-400 hover:bg-blue-400/80">Bunker</Badge>
|
|
||||||
} else if (signerType === 'ncryptsec') {
|
|
||||||
return <Badge>NCRYPTSEC</Badge>
|
|
||||||
} else if (signerType === 'nsec') {
|
|
||||||
return <Badge className=" bg-orange-400 hover:bg-orange-400/80">NSEC</Badge>
|
|
||||||
} else if (signerType === 'npub') {
|
|
||||||
return <Badge className=" bg-yellow-400 hover:bg-yellow-400/80">NPUB</Badge>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,36 +1,57 @@
|
|||||||
import { Skeleton } from '@/components/ui/skeleton'
|
import { Skeleton } from '@/components/ui/skeleton'
|
||||||
|
import { LONG_PRESS_THRESHOLD } from '@/constants'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { usePrimaryPage } from '@/PageManager'
|
import { usePrimaryPage } from '@/PageManager'
|
||||||
import { useNostr } from '@/providers/NostrProvider'
|
import { useNostr } from '@/providers/NostrProvider'
|
||||||
import { UserRound } from 'lucide-react'
|
import { UserRound } from 'lucide-react'
|
||||||
import { useMemo } from 'react'
|
import { useMemo, useRef, useState } from 'react'
|
||||||
|
import LoginDialog from '../LoginDialog'
|
||||||
import { SimpleUserAvatar } from '../UserAvatar'
|
import { SimpleUserAvatar } from '../UserAvatar'
|
||||||
import BottomNavigationBarItem from './BottomNavigationBarItem'
|
import BottomNavigationBarItem from './BottomNavigationBarItem'
|
||||||
|
|
||||||
export default function AccountButton() {
|
export default function AccountButton() {
|
||||||
const { navigate, current, display } = usePrimaryPage()
|
const { navigate, current, display } = usePrimaryPage()
|
||||||
const { pubkey, profile } = useNostr()
|
const { pubkey, profile } = useNostr()
|
||||||
|
const [loginDialogOpen, setLoginDialogOpen] = useState(false)
|
||||||
const active = useMemo(() => current === 'me' && display, [display, current])
|
const active = useMemo(() => current === 'me' && display, [display, current])
|
||||||
|
const pressTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||||
|
|
||||||
|
const handlePointerDown = () => {
|
||||||
|
pressTimerRef.current = setTimeout(() => {
|
||||||
|
setLoginDialogOpen(true)
|
||||||
|
pressTimerRef.current = null
|
||||||
|
}, LONG_PRESS_THRESHOLD)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePointerUp = () => {
|
||||||
|
if (pressTimerRef.current) {
|
||||||
|
clearTimeout(pressTimerRef.current)
|
||||||
|
navigate('me')
|
||||||
|
pressTimerRef.current = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BottomNavigationBarItem
|
<>
|
||||||
onClick={() => {
|
<BottomNavigationBarItem
|
||||||
navigate('me')
|
onPointerDown={handlePointerDown}
|
||||||
}}
|
onPointerUp={handlePointerUp}
|
||||||
active={active}
|
active={active}
|
||||||
>
|
>
|
||||||
{pubkey ? (
|
{pubkey ? (
|
||||||
profile ? (
|
profile ? (
|
||||||
<SimpleUserAvatar
|
<SimpleUserAvatar
|
||||||
userId={pubkey}
|
userId={pubkey}
|
||||||
className={cn('w-7 h-7', active ? 'ring-primary ring-1' : '')}
|
className={cn('w-7 h-7', active ? 'ring-primary ring-1' : '')}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<Skeleton className={cn('w-7 h-7 rounded-full', active ? 'ring-primary ring-1' : '')} />
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<Skeleton className={cn('w-7 h-7 rounded-full', active ? 'ring-primary ring-1' : '')} />
|
<UserRound />
|
||||||
)
|
)}
|
||||||
) : (
|
</BottomNavigationBarItem>
|
||||||
<UserRound />
|
<LoginDialog open={loginDialogOpen} setOpen={setLoginDialogOpen} />
|
||||||
)}
|
</>
|
||||||
</BottomNavigationBarItem>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
|
import { Button } from '@/components/ui/button'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { Button } from '../ui/button'
|
|
||||||
import { MouseEventHandler } from 'react'
|
import { MouseEventHandler } from 'react'
|
||||||
|
|
||||||
export default function BottomNavigationBarItem({
|
export default function BottomNavigationBarItem({
|
||||||
children,
|
children,
|
||||||
active = false,
|
active = false,
|
||||||
onClick
|
onClick,
|
||||||
|
onPointerDown,
|
||||||
|
onPointerUp
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
active?: boolean
|
active?: boolean
|
||||||
onClick: MouseEventHandler
|
onClick?: MouseEventHandler
|
||||||
|
onPointerDown?: MouseEventHandler
|
||||||
|
onPointerUp?: MouseEventHandler
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
@@ -19,6 +23,8 @@ export default function BottomNavigationBarItem({
|
|||||||
)}
|
)}
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
onPointerDown={onPointerDown}
|
||||||
|
onPointerUp={onPointerUp}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { LONG_PRESS_THRESHOLD } from '@/constants'
|
||||||
import { useNoteStatsById } from '@/hooks/useNoteStatsById'
|
import { useNoteStatsById } from '@/hooks/useNoteStatsById'
|
||||||
import { getLightningAddressFromProfile } from '@/lib/lightning'
|
import { getLightningAddressFromProfile } from '@/lib/lightning'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
@@ -86,7 +87,7 @@ export default function ZapButton({ event }: { event: Event }) {
|
|||||||
setOpenZapDialog(true)
|
setOpenZapDialog(true)
|
||||||
setZapping(true)
|
setZapping(true)
|
||||||
})
|
})
|
||||||
}, 500)
|
}, LONG_PRESS_THRESHOLD)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,24 @@
|
|||||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
|
DropdownMenuLabel,
|
||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger
|
DropdownMenuTrigger
|
||||||
} from '@/components/ui/dropdown-menu'
|
} from '@/components/ui/dropdown-menu'
|
||||||
import { toWallet } from '@/lib/link'
|
import { toWallet } from '@/lib/link'
|
||||||
import { formatPubkey, generateImageByPubkey } from '@/lib/pubkey'
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { usePrimaryPage, useSecondaryPage } from '@/PageManager'
|
import { useSecondaryPage } from '@/PageManager'
|
||||||
import { useNostr } from '@/providers/NostrProvider'
|
import { useNostr } from '@/providers/NostrProvider'
|
||||||
import { ArrowDownUp, LogIn, LogOut, UserRound, Wallet } from 'lucide-react'
|
import { LogIn, LogOut, Plus, Wallet } from 'lucide-react'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import LoginDialog from '../LoginDialog'
|
import LoginDialog from '../LoginDialog'
|
||||||
import LogoutDialog from '../LogoutDialog'
|
import LogoutDialog from '../LogoutDialog'
|
||||||
|
import SignerTypeBadge from '../SignerTypeBadge'
|
||||||
|
import { SimpleUserAvatar } from '../UserAvatar'
|
||||||
|
import { SimpleUsername } from '../Username'
|
||||||
import SidebarItem from './SidebarItem'
|
import SidebarItem from './SidebarItem'
|
||||||
|
|
||||||
export default function AccountButton({ collapse }: { collapse: boolean }) {
|
export default function AccountButton({ collapse }: { collapse: boolean }) {
|
||||||
@@ -31,17 +33,13 @@ export default function AccountButton({ collapse }: { collapse: boolean }) {
|
|||||||
|
|
||||||
function ProfileButton({ collapse }: { collapse: boolean }) {
|
function ProfileButton({ collapse }: { collapse: boolean }) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { account, profile } = useNostr()
|
const { account, accounts, switchAccount } = useNostr()
|
||||||
const pubkey = account?.pubkey
|
const pubkey = account?.pubkey
|
||||||
const { navigate } = usePrimaryPage()
|
|
||||||
const { push } = useSecondaryPage()
|
const { push } = useSecondaryPage()
|
||||||
const [loginDialogOpen, setLoginDialogOpen] = useState(false)
|
const [loginDialogOpen, setLoginDialogOpen] = useState(false)
|
||||||
const [logoutDialogOpen, setLogoutDialogOpen] = useState(false)
|
const [logoutDialogOpen, setLogoutDialogOpen] = useState(false)
|
||||||
if (!pubkey) return null
|
if (!pubkey) return null
|
||||||
|
|
||||||
const defaultAvatar = generateImageByPubkey(pubkey)
|
|
||||||
const { username, avatar } = profile || { username: formatPubkey(pubkey), avatar: defaultAvatar }
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
@@ -53,37 +51,68 @@ function ProfileButton({ collapse }: { collapse: boolean }) {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex gap-2 items-center flex-1 w-0">
|
<div className="flex gap-2 items-center flex-1 w-0">
|
||||||
<Avatar className="w-8 h-8">
|
<SimpleUserAvatar size="medium" userId={pubkey} />
|
||||||
<AvatarImage src={avatar} />
|
{!collapse && (
|
||||||
<AvatarFallback>
|
<SimpleUsername className="truncate font-semibold text-lg" userId={pubkey} />
|
||||||
<img src={defaultAvatar} />
|
)}
|
||||||
</AvatarFallback>
|
|
||||||
</Avatar>
|
|
||||||
{!collapse && <div className="truncate font-semibold text-lg">{username}</div>}
|
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent side="top">
|
<DropdownMenuContent side="top" className="w-72">
|
||||||
<DropdownMenuItem onClick={() => navigate('profile')}>
|
|
||||||
<UserRound />
|
|
||||||
{t('Profile')}
|
|
||||||
</DropdownMenuItem>
|
|
||||||
<DropdownMenuSeparator />
|
|
||||||
<DropdownMenuItem onClick={() => push(toWallet())}>
|
<DropdownMenuItem onClick={() => push(toWallet())}>
|
||||||
<Wallet />
|
<Wallet />
|
||||||
{t('Wallet')}
|
{t('Wallet')}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem onClick={() => setLoginDialogOpen(true)}>
|
<DropdownMenuLabel>{t('Switch account')}</DropdownMenuLabel>
|
||||||
<ArrowDownUp />
|
{accounts.map((act) => (
|
||||||
{t('Switch account')}
|
<DropdownMenuItem
|
||||||
|
className={act.pubkey === pubkey ? 'cursor-default focus:bg-background' : ''}
|
||||||
|
key={`${act.pubkey}:${act.signerType}`}
|
||||||
|
onClick={() => {
|
||||||
|
if (act.pubkey !== pubkey) {
|
||||||
|
switchAccount(act)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex gap-2 items-center flex-1">
|
||||||
|
<SimpleUserAvatar userId={act.pubkey} />
|
||||||
|
<div className="flex-1 w-0">
|
||||||
|
<SimpleUsername
|
||||||
|
userId={act.pubkey}
|
||||||
|
className="font-medium truncate"
|
||||||
|
skeletonClassName="h-3"
|
||||||
|
/>
|
||||||
|
<SignerTypeBadge signerType={act.signerType} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'border border-muted-foreground rounded-full size-3.5',
|
||||||
|
act.pubkey === pubkey && 'size-4 border-4 border-primary'
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
))}
|
||||||
|
<DropdownMenuItem
|
||||||
|
onClick={() => setLoginDialogOpen(true)}
|
||||||
|
className="border border-dashed m-2 focus:border-muted-foreground focus:bg-background"
|
||||||
|
>
|
||||||
|
<div className="flex gap-2 items-center justify-center w-full py-2">
|
||||||
|
<Plus />
|
||||||
|
{t('Add an Account')}
|
||||||
|
</div>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
className="text-destructive focus:text-destructive"
|
className="text-destructive focus:text-destructive"
|
||||||
onClick={() => setLogoutDialogOpen(true)}
|
onClick={() => setLogoutDialogOpen(true)}
|
||||||
>
|
>
|
||||||
<LogOut />
|
<LogOut />
|
||||||
{t('Logout')}
|
<span className="shrink-0">{t('Logout')}</span>
|
||||||
|
<SimpleUsername
|
||||||
|
userId={pubkey}
|
||||||
|
className="text-muted-foreground border border-muted-foreground px-1 rounded-md text-xs truncate"
|
||||||
|
/>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
<LoginDialog open={loginDialogOpen} setOpen={setLoginDialogOpen} />
|
<LoginDialog open={loginDialogOpen} setOpen={setLoginDialogOpen} />
|
||||||
|
|||||||
23
src/components/SignerTypeBadge/index.tsx
Normal file
23
src/components/SignerTypeBadge/index.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { Badge } from '@/components/ui/badge'
|
||||||
|
import { TSignerType } from '@/types'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
export default function SignerTypeBadge({ signerType }: { signerType: TSignerType }) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
if (signerType === 'nip-07') {
|
||||||
|
return <Badge className=" bg-green-400 hover:bg-green-400 px-1 py-0">{t('Extension')}</Badge>
|
||||||
|
} else if (signerType === 'bunker') {
|
||||||
|
return <Badge className=" bg-blue-400 hover:bg-blue-400 px-1 py-0">{t('Remote')}</Badge>
|
||||||
|
} else if (signerType === 'ncryptsec') {
|
||||||
|
return (
|
||||||
|
<Badge className="bg-violet-400 hover:bg-violet-400 px-1 py-0">{t('Encrypted Key')}</Badge>
|
||||||
|
)
|
||||||
|
} else if (signerType === 'nsec') {
|
||||||
|
return (
|
||||||
|
<Badge className=" bg-orange-400 hover:bg-orange-400 px-1 py-0">{t('Private Key')}</Badge>
|
||||||
|
)
|
||||||
|
} else if (signerType === 'npub') {
|
||||||
|
return <Badge className=" bg-yellow-400 hover:bg-yellow-400 px-1 py-0">NPUB</Badge>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,8 +19,8 @@ export default function Username({
|
|||||||
skeletonClassName?: string
|
skeletonClassName?: string
|
||||||
withoutSkeleton?: boolean
|
withoutSkeleton?: boolean
|
||||||
}) {
|
}) {
|
||||||
const { profile } = useFetchProfile(userId)
|
const { profile, isFetching } = useFetchProfile(userId)
|
||||||
if (!profile && !withoutSkeleton) {
|
if (!profile && isFetching && !withoutSkeleton) {
|
||||||
return (
|
return (
|
||||||
<div className="py-1">
|
<div className="py-1">
|
||||||
<Skeleton className={cn('w-16', skeletonClassName)} />
|
<Skeleton className={cn('w-16', skeletonClassName)} />
|
||||||
@@ -63,8 +63,8 @@ export function SimpleUsername({
|
|||||||
skeletonClassName?: string
|
skeletonClassName?: string
|
||||||
withoutSkeleton?: boolean
|
withoutSkeleton?: boolean
|
||||||
}) {
|
}) {
|
||||||
const { profile } = useFetchProfile(userId)
|
const { profile, isFetching } = useFetchProfile(userId)
|
||||||
if (!profile && !withoutSkeleton) {
|
if (!profile && isFetching && !withoutSkeleton) {
|
||||||
return (
|
return (
|
||||||
<div className="py-1">
|
<div className="py-1">
|
||||||
<Skeleton className={cn('w-16', skeletonClassName)} />
|
<Skeleton className={cn('w-16', skeletonClassName)} />
|
||||||
|
|||||||
@@ -432,3 +432,5 @@ export const PRIMARY_COLORS = {
|
|||||||
}
|
}
|
||||||
} as const
|
} as const
|
||||||
export type TPrimaryColor = keyof typeof PRIMARY_COLORS
|
export type TPrimaryColor = keyof typeof PRIMARY_COLORS
|
||||||
|
|
||||||
|
export const LONG_PRESS_THRESHOLD = 500
|
||||||
|
|||||||
@@ -480,6 +480,10 @@ export default {
|
|||||||
Layout: 'التخطيط',
|
Layout: 'التخطيط',
|
||||||
'Two-column': 'عمودين',
|
'Two-column': 'عمودين',
|
||||||
'Single-column': 'عمود واحد',
|
'Single-column': 'عمود واحد',
|
||||||
Reviews: 'المراجعات'
|
Reviews: 'المراجعات',
|
||||||
|
Extension: 'امتداد',
|
||||||
|
Remote: 'عن بُعد',
|
||||||
|
'Encrypted Key': 'مفتاح مشفر',
|
||||||
|
'Private Key': 'مفتاح خاص'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -494,6 +494,10 @@ export default {
|
|||||||
Layout: 'Layout',
|
Layout: 'Layout',
|
||||||
'Two-column': 'Zweispaltig',
|
'Two-column': 'Zweispaltig',
|
||||||
'Single-column': 'Einspaltig',
|
'Single-column': 'Einspaltig',
|
||||||
Reviews: 'Bewertungen'
|
Reviews: 'Bewertungen',
|
||||||
|
Extension: 'Erweiterung',
|
||||||
|
Remote: 'Remote',
|
||||||
|
'Encrypted Key': 'Verschlüsselter Schlüssel',
|
||||||
|
'Private Key': 'Privater Schlüssel'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -479,6 +479,10 @@ export default {
|
|||||||
Layout: 'Layout',
|
Layout: 'Layout',
|
||||||
'Two-column': 'Two-column',
|
'Two-column': 'Two-column',
|
||||||
'Single-column': 'Single-column',
|
'Single-column': 'Single-column',
|
||||||
Reviews: 'Reviews'
|
Reviews: 'Reviews',
|
||||||
|
Extension: 'Extension',
|
||||||
|
Remote: 'Remote',
|
||||||
|
'Encrypted Key': 'Encrypted Key',
|
||||||
|
'Private Key': 'Private Key'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -488,6 +488,10 @@ export default {
|
|||||||
Layout: 'Diseño',
|
Layout: 'Diseño',
|
||||||
'Two-column': 'Doble columna',
|
'Two-column': 'Doble columna',
|
||||||
'Single-column': 'Columna única',
|
'Single-column': 'Columna única',
|
||||||
Reviews: 'Reseñas'
|
Reviews: 'Reseñas',
|
||||||
|
Extension: 'Extensión',
|
||||||
|
Remote: 'Remoto',
|
||||||
|
'Encrypted Key': 'Clave privada cifrada',
|
||||||
|
'Private Key': 'Clave privada'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -483,6 +483,10 @@ export default {
|
|||||||
Layout: 'چیدمان',
|
Layout: 'چیدمان',
|
||||||
'Two-column': 'دو ستونی',
|
'Two-column': 'دو ستونی',
|
||||||
'Single-column': 'تک ستونی',
|
'Single-column': 'تک ستونی',
|
||||||
Reviews: 'نقدها'
|
Reviews: 'نقدها',
|
||||||
|
Extension: 'افزونه',
|
||||||
|
Remote: 'از راه دور',
|
||||||
|
'Encrypted Key': 'رمزگذاری شده کلید',
|
||||||
|
'Private Key': 'کلید خصوصی'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -493,6 +493,10 @@ export default {
|
|||||||
Layout: 'Disposition',
|
Layout: 'Disposition',
|
||||||
'Two-column': 'Deux colonnes',
|
'Two-column': 'Deux colonnes',
|
||||||
'Single-column': 'Une seule colonne',
|
'Single-column': 'Une seule colonne',
|
||||||
Reviews: 'Avis'
|
Reviews: 'Avis',
|
||||||
|
Extension: 'Extension',
|
||||||
|
Remote: 'Distant',
|
||||||
|
'Encrypted Key': 'Clé chiffrée',
|
||||||
|
'Private Key': 'Clé privée'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -485,6 +485,10 @@ export default {
|
|||||||
Layout: 'लेआउट',
|
Layout: 'लेआउट',
|
||||||
'Two-column': 'दोहरा स्तंभ',
|
'Two-column': 'दोहरा स्तंभ',
|
||||||
'Single-column': 'एकल स्तंभ',
|
'Single-column': 'एकल स्तंभ',
|
||||||
Reviews: 'समीक्षाएं'
|
Reviews: 'समीक्षाएं',
|
||||||
|
Extension: 'एक्सटेंशन',
|
||||||
|
Remote: 'रिमोट',
|
||||||
|
'Encrypted Key': 'एन्क्रिप्टेड की',
|
||||||
|
'Private Key': 'प्राइवेट की'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -488,6 +488,10 @@ export default {
|
|||||||
Layout: 'Layout',
|
Layout: 'Layout',
|
||||||
'Two-column': 'Doppia colonna',
|
'Two-column': 'Doppia colonna',
|
||||||
'Single-column': 'Colonna singola',
|
'Single-column': 'Colonna singola',
|
||||||
Reviews: 'Recensioni'
|
Reviews: 'Recensioni',
|
||||||
|
Extension: 'Estensione',
|
||||||
|
Remote: 'Remoto',
|
||||||
|
'Encrypted Key': 'Chiave Crittografata',
|
||||||
|
'Private Key': 'Chiave Privata'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -484,6 +484,10 @@ export default {
|
|||||||
Layout: 'レイアウト',
|
Layout: 'レイアウト',
|
||||||
'Two-column': '2列',
|
'Two-column': '2列',
|
||||||
'Single-column': '1列',
|
'Single-column': '1列',
|
||||||
Reviews: 'レビュー'
|
Reviews: 'レビュー',
|
||||||
|
Extension: '拡張機能',
|
||||||
|
Remote: 'リモート',
|
||||||
|
'Encrypted Key': '暗号化キー',
|
||||||
|
'Private Key': '暗号化されたキー'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -484,6 +484,10 @@ export default {
|
|||||||
Layout: '레이아웃',
|
Layout: '레이아웃',
|
||||||
'Two-column': '두 열',
|
'Two-column': '두 열',
|
||||||
'Single-column': '한 열',
|
'Single-column': '한 열',
|
||||||
Reviews: '리뷰'
|
Reviews: '리뷰',
|
||||||
|
Extension: '확장 프로그램',
|
||||||
|
Remote: '원격',
|
||||||
|
'Encrypted Key': '암호화된 키',
|
||||||
|
'Private Key': '개인 키'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -488,6 +488,10 @@ export default {
|
|||||||
Layout: 'Układ',
|
Layout: 'Układ',
|
||||||
'Two-column': 'Dwie kolumny',
|
'Two-column': 'Dwie kolumny',
|
||||||
'Single-column': 'Jedna kolumna',
|
'Single-column': 'Jedna kolumna',
|
||||||
Reviews: 'Opinie'
|
Reviews: 'Opinie',
|
||||||
|
Extension: 'Rozszerzenie',
|
||||||
|
Remote: 'Zdalne',
|
||||||
|
'Encrypted Key': 'Zaszyfrowany Klucz',
|
||||||
|
'Private Key': 'Zaszyfrowany Klucz'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -485,6 +485,10 @@ export default {
|
|||||||
Layout: 'Layout',
|
Layout: 'Layout',
|
||||||
'Two-column': 'Coluna dupla',
|
'Two-column': 'Coluna dupla',
|
||||||
'Single-column': 'Coluna única',
|
'Single-column': 'Coluna única',
|
||||||
Reviews: 'Avaliações'
|
Reviews: 'Avaliações',
|
||||||
|
Extension: 'Extensão',
|
||||||
|
Remote: 'Remoto',
|
||||||
|
'Encrypted Key': 'Chave Criptografada',
|
||||||
|
'Private Key': 'Chave Privada'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -488,6 +488,10 @@ export default {
|
|||||||
Layout: 'Layout',
|
Layout: 'Layout',
|
||||||
'Two-column': 'Coluna dupla',
|
'Two-column': 'Coluna dupla',
|
||||||
'Single-column': 'Coluna única',
|
'Single-column': 'Coluna única',
|
||||||
Reviews: 'Avaliações'
|
Reviews: 'Avaliações',
|
||||||
|
Extension: 'Extensão',
|
||||||
|
Remote: 'Remoto',
|
||||||
|
'Encrypted Key': 'Chave Criptografada',
|
||||||
|
'Private Key': 'Chave Privada'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -490,6 +490,10 @@ export default {
|
|||||||
Layout: 'Макет',
|
Layout: 'Макет',
|
||||||
'Two-column': 'Две колонки',
|
'Two-column': 'Две колонки',
|
||||||
'Single-column': 'Одна колонка',
|
'Single-column': 'Одна колонка',
|
||||||
Reviews: 'Отзывы'
|
Reviews: 'Отзывы',
|
||||||
|
Extension: 'Расширение',
|
||||||
|
Remote: 'Удалённый',
|
||||||
|
'Encrypted Key': 'Зашифрованный ключ',
|
||||||
|
'Private Key': 'Приватный ключ'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -478,6 +478,10 @@ export default {
|
|||||||
Layout: 'เค้าโครง',
|
Layout: 'เค้าโครง',
|
||||||
'Two-column': 'สองคอลัมน์',
|
'Two-column': 'สองคอลัมน์',
|
||||||
'Single-column': 'คอลัมน์เดียว',
|
'Single-column': 'คอลัมน์เดียว',
|
||||||
Reviews: 'รีวิว'
|
Reviews: 'รีวิว',
|
||||||
|
Extension: 'ส่วนขยาย',
|
||||||
|
Remote: 'ระยะไกล',
|
||||||
|
'Encrypted Key': 'คีย์ที่เข้ารหัส',
|
||||||
|
'Private Key': 'คีย์ส่วนตัว'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -476,6 +476,10 @@ export default {
|
|||||||
Layout: '布局',
|
Layout: '布局',
|
||||||
'Two-column': '双栏',
|
'Two-column': '双栏',
|
||||||
'Single-column': '单栏',
|
'Single-column': '单栏',
|
||||||
Reviews: '评价'
|
Reviews: '评价',
|
||||||
|
Extension: '扩展',
|
||||||
|
Remote: '远程',
|
||||||
|
'Encrypted Key': '加密私钥',
|
||||||
|
'Private Key': '私钥'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user