-
Notifications
You must be signed in to change notification settings - Fork 490
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1635 from blockscout/add-info-to-dapp-page
Add a top bar to the dapp page
- Loading branch information
Showing
12 changed files
with
361 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { Alert } from '@chakra-ui/react'; | ||
import React from 'react'; | ||
|
||
import type { IconName } from 'ui/shared/IconSvg'; | ||
import IconSvg from 'ui/shared/IconSvg'; | ||
|
||
import useMarketplaceWallet from './useMarketplaceWallet'; | ||
|
||
type Props = { | ||
internalWallet: boolean | undefined; | ||
} | ||
|
||
const MarketplaceAppAlert = ({ internalWallet }: Props) => { | ||
const { address } = useMarketplaceWallet(); | ||
const isWalletConnected = Boolean(address); | ||
|
||
const message = React.useMemo(() => { | ||
let icon: IconName = 'wallet'; | ||
let text = 'Connect your wallet to Blockscout for full-featured access'; | ||
let status: 'warning' | 'success' = 'warning'; | ||
|
||
if (isWalletConnected && internalWallet) { | ||
icon = 'integration/full'; | ||
text = 'Your wallet is connected with Blockscout'; | ||
status = 'success'; | ||
} else if (isWalletConnected) { | ||
icon = 'integration/partial'; | ||
text = 'Connect your wallet in the app below'; | ||
} | ||
|
||
return { icon, text, status }; | ||
}, [ isWalletConnected, internalWallet ]); | ||
|
||
return ( | ||
<Alert | ||
status={ message.status } | ||
borderRadius="base" | ||
px={ 3 } | ||
py={{ base: 3, md: 1.5 }} | ||
fontSize="sm" | ||
lineHeight={ 5 } | ||
> | ||
<IconSvg | ||
name={ message.icon } | ||
color={ message.status === 'success' ? 'green.600' : 'current' } | ||
boxSize={ 5 } | ||
flexShrink={ 0 } | ||
mr={ 2 } | ||
/> | ||
{ message.text } | ||
</Alert> | ||
); | ||
}; | ||
|
||
export default MarketplaceAppAlert; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { | ||
Popover, PopoverTrigger, PopoverContent, PopoverBody, | ||
Modal, ModalContent, ModalCloseButton, useDisclosure, | ||
} from '@chakra-ui/react'; | ||
import React from 'react'; | ||
|
||
import type { MarketplaceAppOverview } from 'types/client/marketplace'; | ||
|
||
import useIsMobile from 'lib/hooks/useIsMobile'; | ||
|
||
import Content from './MarketplaceAppInfo/Content'; | ||
import TriggerButton from './MarketplaceAppInfo/TriggerButton'; | ||
|
||
interface Props { | ||
data: MarketplaceAppOverview | undefined; | ||
} | ||
|
||
const MarketplaceAppInfo = ({ data }: Props) => { | ||
const isMobile = useIsMobile(); | ||
const { isOpen, onToggle, onClose } = useDisclosure(); | ||
|
||
if (isMobile) { | ||
return ( | ||
<> | ||
<TriggerButton onClick={ onToggle }/> | ||
<Modal isOpen={ isOpen } onClose={ onClose } size="full"> | ||
<ModalContent> | ||
<ModalCloseButton/> | ||
<Content data={ data }/> | ||
</ModalContent> | ||
</Modal> | ||
</> | ||
); | ||
} | ||
|
||
return ( | ||
<Popover isOpen={ isOpen } onClose={ onClose } placement="bottom-start" isLazy> | ||
<PopoverTrigger> | ||
<TriggerButton onClick={ onToggle }/> | ||
</PopoverTrigger> | ||
<PopoverContent w="500px"> | ||
<PopoverBody px={ 6 } py={ 5 }> | ||
<Content data={ data }/> | ||
</PopoverBody> | ||
</PopoverContent> | ||
</Popover> | ||
); | ||
}; | ||
|
||
export default React.memo(MarketplaceAppInfo); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { Flex, Text, Grid } from '@chakra-ui/react'; | ||
import React from 'react'; | ||
|
||
import type { MarketplaceAppOverview } from 'types/client/marketplace'; | ||
|
||
import SocialLink from './SocialLink'; | ||
import type { Props as SocialLinkProps } from './SocialLink'; | ||
import WebsiteLink from './WebsiteLink'; | ||
|
||
interface Props { | ||
data: MarketplaceAppOverview | undefined; | ||
} | ||
|
||
const SOCIAL_LINKS: Array<Omit<SocialLinkProps, 'href'>> = [ | ||
{ field: 'github', icon: 'social/github_filled', title: 'Github' }, | ||
{ field: 'twitter', icon: 'social/twitter_filled', title: 'Twitter' }, | ||
{ field: 'telegram', icon: 'social/telegram_filled', title: 'Telegram' }, | ||
{ field: 'discord', icon: 'social/discord_filled', title: 'Discord' }, | ||
]; | ||
|
||
const Content = ({ data }: Props) => { | ||
const socialLinks: Array<SocialLinkProps> = []; | ||
SOCIAL_LINKS.forEach((link) => { | ||
const href = data?.[link.field]; | ||
if (href) { | ||
if (Array.isArray(href)) { | ||
href.forEach((href) => socialLinks.push({ ...link, href })); | ||
} else { | ||
socialLinks.push({ ...link, href }); | ||
} | ||
} | ||
}); | ||
|
||
return ( | ||
<Flex fontSize="sm" flexDir="column" rowGap={ 5 }> | ||
<div> | ||
<Text variant="secondary" fontSize="xs">Project info</Text> | ||
<Text fontSize="sm" mt={ 3 }>{ data?.shortDescription }</Text> | ||
<WebsiteLink url={ data?.site }/> | ||
</div> | ||
{ socialLinks.length > 0 && ( | ||
<div> | ||
<Text variant="secondary" fontSize="xs">Links</Text> | ||
<Grid templateColumns={{ base: 'repeat(2, 1fr)', lg: 'repeat(3, 1fr)' }} columnGap={ 4 } rowGap={ 3 } mt={ 3 }> | ||
{ socialLinks.map((link, index) => <SocialLink key={ index } { ...link }/>) } | ||
</Grid> | ||
</div> | ||
) } | ||
</Flex> | ||
); | ||
}; | ||
|
||
export default Content; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { Link } from '@chakra-ui/react'; | ||
import React from 'react'; | ||
|
||
import type { MarketplaceAppSocialInfo } from 'types/client/marketplace'; | ||
|
||
import type { IconName } from 'ui/shared/IconSvg'; | ||
import IconSvg from 'ui/shared/IconSvg'; | ||
|
||
export interface Props { | ||
field: keyof MarketplaceAppSocialInfo; | ||
icon: IconName; | ||
title: string; | ||
href?: string; | ||
} | ||
|
||
const SocialLink = ({ href, icon, title }: Props) => { | ||
return ( | ||
<Link | ||
href={ href } | ||
aria-label={ title } | ||
title={ title } | ||
target="_blank" | ||
display="inline-flex" | ||
alignItems="center" | ||
> | ||
<IconSvg name={ icon } boxSize={ 5 } mr={ 2 } color="text_secondary"/> | ||
<span>{ title }</span> | ||
</Link> | ||
); | ||
}; | ||
|
||
export default SocialLink; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { Button } from '@chakra-ui/react'; | ||
import React from 'react'; | ||
|
||
import IconSvg from 'ui/shared/IconSvg'; | ||
|
||
interface Props { | ||
onClick: () => void; | ||
} | ||
|
||
const TriggerButton = ({ onClick }: Props, ref: React.ForwardedRef<HTMLButtonElement>) => { | ||
return ( | ||
<Button | ||
ref={ ref } | ||
size="sm" | ||
variant="outline" | ||
colorScheme="gray" | ||
onClick={ onClick } | ||
aria-label="Show project info" | ||
fontWeight={ 500 } | ||
px={ 2 } | ||
h="32px" | ||
> | ||
<IconSvg name="info" boxSize={ 6 } mr={ 1 }/> | ||
<span>Info</span> | ||
</Button> | ||
); | ||
}; | ||
|
||
export default React.forwardRef(TriggerButton); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Link } from '@chakra-ui/react'; | ||
import React from 'react'; | ||
|
||
import IconSvg from 'ui/shared/IconSvg'; | ||
|
||
interface Props { | ||
url?: string | undefined; | ||
} | ||
|
||
const WebsiteLink = ({ url }: Props) => { | ||
if (!url) { | ||
return null; | ||
} | ||
|
||
function getHostname(url: string) { | ||
try { | ||
return new URL(url).hostname; | ||
} catch (err) {} | ||
} | ||
|
||
return ( | ||
<Link | ||
href={ url } | ||
target="_blank" | ||
display="inline-flex" | ||
alignItems="center" | ||
columnGap={ 1 } | ||
mt={ 3 } | ||
> | ||
<IconSvg name="link" boxSize={ 5 } color="text_secondary"/> | ||
<span>{ getHostname(url) }</span> | ||
</Link> | ||
); | ||
}; | ||
|
||
export default WebsiteLink; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { chakra, Flex, Tooltip, Skeleton } from '@chakra-ui/react'; | ||
import React from 'react'; | ||
|
||
import type { MarketplaceAppOverview } from 'types/client/marketplace'; | ||
|
||
import { route } from 'nextjs-routes'; | ||
|
||
import { useAppContext } from 'lib/contexts/app'; | ||
import IconSvg from 'ui/shared/IconSvg'; | ||
import LinkExternal from 'ui/shared/LinkExternal'; | ||
import LinkInternal from 'ui/shared/LinkInternal'; | ||
|
||
import MarketplaceAppAlert from './MarketplaceAppAlert'; | ||
import MarketplaceAppInfo from './MarketplaceAppInfo'; | ||
|
||
type Props = { | ||
data: MarketplaceAppOverview | undefined; | ||
isLoading: boolean; | ||
} | ||
|
||
const MarketplaceAppTopBar = ({ data, isLoading }: Props) => { | ||
const appProps = useAppContext(); | ||
|
||
const goBackUrl = React.useMemo(() => { | ||
if (appProps.referrer && appProps.referrer.includes('/apps') && !appProps.referrer.includes('/apps/')) { | ||
return appProps.referrer; | ||
} | ||
return route({ pathname: '/apps' }); | ||
}, [ appProps.referrer ]); | ||
|
||
function getHostname(url: string | undefined) { | ||
try { | ||
return new URL(url || '').hostname; | ||
} catch (err) {} | ||
} | ||
|
||
return ( | ||
<Flex alignItems="center" flexWrap="wrap" mb={{ base: 6, md: 2 }} rowGap={ 3 } columnGap={ 2 }> | ||
<Tooltip label="Back to dApps list" order={ 1 }> | ||
<LinkInternal display="inline-flex" href={ goBackUrl } h="32px" isLoading={ isLoading }> | ||
<IconSvg name="arrows/east" boxSize={ 6 } transform="rotate(180deg)" margin="auto" color="gray.400"/> | ||
</LinkInternal> | ||
</Tooltip> | ||
<Skeleton width={{ base: '100%', md: 'auto' }} order={{ base: 4, md: 2 }} isLoaded={ !isLoading }> | ||
<MarketplaceAppAlert internalWallet={ data?.internalWallet }/> | ||
</Skeleton> | ||
<Skeleton order={{ base: 2, md: 3 }} isLoaded={ !isLoading }> | ||
<MarketplaceAppInfo data={ data }/> | ||
</Skeleton> | ||
<LinkExternal | ||
order={{ base: 3, md: 4 }} | ||
href={ data?.url } | ||
variant="subtle" | ||
fontSize="sm" | ||
lineHeight={ 5 } | ||
minW={ 0 } | ||
maxW={{ base: 'calc(100% - 114px)', md: 'auto' }} | ||
display="flex" | ||
isLoading={ isLoading } | ||
> | ||
<chakra.span isTruncated> | ||
{ getHostname(data?.url) } | ||
</chakra.span> | ||
</LinkExternal> | ||
</Flex> | ||
); | ||
}; | ||
|
||
export default MarketplaceAppTopBar; |
Oops, something went wrong.