Skip to content

Commit

Permalink
feat: redesign - homepage - recent-blocks: btc
Browse files Browse the repository at this point in the history
  • Loading branch information
He1DAr committed Mar 6, 2025
1 parent 3530fa1 commit c0840dc
Show file tree
Hide file tree
Showing 25 changed files with 573 additions and 66 deletions.
2 changes: 2 additions & 0 deletions src/app/PageClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useGlobalContext } from '../common/context/useGlobalContext';
import { TxListTabs } from '../features/txs-list/tabs/TxListTabs';
import { HomePageBlockListSkeleton } from './_components/BlockList/Grouped/skeleton';
import { PageTitle } from './_components/PageTitle';
import { RecentBlocks } from './_components/RecentBlocks/RecentBlocks';

Check warning on line 13 in src/app/PageClient.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/PageClient.tsx#L13

Added line #L13 was not covered by tests
import { Stats } from './_components/Stats/Stats';
import HomePageSkeleton from './skeleton';

Expand All @@ -35,6 +36,7 @@ export function HomePageLayout({
}) {
return (
<>
<RecentBlocks />
{title}
{stats}
<Grid
Expand Down
4 changes: 2 additions & 2 deletions src/app/_components/BlockList/Grouped/BlockListGrouped.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useInfiniteQueryResult } from '../../../../common/hooks/useInfiniteQuer
import { useBlocksByBurnBlock } from '../../../../common/queries/useBlocksByBurnBlock';
import { truncateMiddle } from '../../../../common/utils/utils';
import { Text } from '../../../../ui/Text';
import BitcoinIcon from '../../../../ui/icons/BitcoinIcon';
import BitcoinCircleIcon from '../../../../ui/icons/BitcoinCircleIcon';

Check warning on line 13 in src/app/_components/BlockList/Grouped/BlockListGrouped.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/BlockList/Grouped/BlockListGrouped.tsx#L13

Added line #L13 was not covered by tests
import StxIcon from '../../../../ui/icons/StxIcon';
import { Caption } from '../../../../ui/typography';
import { ListHeader } from '../../ListHeader';
Expand Down Expand Up @@ -264,7 +264,7 @@ function BitcoinHeader({
<ArrowElbowLeftDown />
</Icon>
<Icon h={4.5} w={4.5}>
<BitcoinIcon />
<BitcoinCircleIcon />
</Icon>
<Flex height="full" alignItems="center">
<ExplorerLink
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useInfiniteQueryResult } from '../../../../common/hooks/useInfiniteQuer
import { useBlocksByBurnBlock } from '../../../../common/queries/useBlocksByBurnBlock';
import { truncateMiddle } from '../../../../common/utils/utils';
import { Text } from '../../../../ui/Text';
import BitcoinIcon from '../../../../ui/icons/BitcoinIcon';
import BitcoinCircleIcon from '../../../../ui/icons/BitcoinCircleIcon';

Check warning on line 13 in src/app/_components/BlockList/Ungrouped/BlockListUngrouped.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/BlockList/Ungrouped/BlockListUngrouped.tsx#L13

Added line #L13 was not covered by tests
import StxIcon from '../../../../ui/icons/StxIcon';
import { Caption } from '../../../../ui/typography';
import { ListHeader } from '../../ListHeader';
Expand Down Expand Up @@ -60,7 +60,7 @@ export function BtcBlockRowContent({ timestamp, height, hash, isFirst }: BtcBloc
<ArrowBendDownLeft />
</Icon>
<Icon h={18} w={18} position={'relative'} bottom={'1px'}>
<BitcoinIcon />
<BitcoinCircleIcon />
</Icon>
{isFirst ? (
<Text fontSize="sm" color="textSubdued" fontWeight="medium">
Expand Down
4 changes: 2 additions & 2 deletions src/app/_components/NavBar/BtcStxPrice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ReactNode } from 'react';
import { Circle } from '../../../common/components/Circle';
import { TokenPrice } from '../../../common/types/tokenPrice';
import { usdFormatter } from '../../../common/utils/utils';
import BitcoinIcon from '../../../ui/icons/BitcoinIcon';
import BitcoinCircleIcon from '../../../ui/icons/BitcoinCircleIcon';
import StxIcon from '../../../ui/icons/StxIcon';
import { ExplorerErrorBoundary } from '../ErrorBoundary';

Expand All @@ -33,7 +33,7 @@ function BtcStxPriceBase({ tokenPrice }: { tokenPrice: TokenPrice }) {
<PriceContainer
icon={
<Icon h={4.5} w={4.5}>
<BitcoinIcon />
<BitcoinCircleIcon />
</Icon>
}
minWidth={'92px'}
Expand Down
25 changes: 14 additions & 11 deletions src/app/_components/PageWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,20 @@ function WrapperWithBg({
}) {
const [clientThemeCookie] = useCookies(['stacks-explorer-theme']);
const isServer = typeof window === 'undefined';
const bgColor = isServer
? serverThemeCookie
? serverThemeCookie === 'light'
? lightBg
: darkBg
: lightBg
: clientThemeCookie['stacks-explorer-theme']
? clientThemeCookie['stacks-explorer-theme'] === 'light'
? lightBg
: darkBg
: lightBg;
const isRedesign = isRedesignUrl();

Check warning on line 60 in src/app/_components/PageWrapper.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/PageWrapper.tsx#L60

Added line #L60 was not covered by tests
const bgColor = isRedesign
? 'surfaceTertiary'

Check warning on line 62 in src/app/_components/PageWrapper.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/PageWrapper.tsx#L62

Added line #L62 was not covered by tests
: isServer
? serverThemeCookie
? serverThemeCookie === 'light'
? lightBg
: darkBg
: lightBg

Check warning on line 68 in src/app/_components/PageWrapper.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/PageWrapper.tsx#L66-L68

Added lines #L66 - L68 were not covered by tests
: clientThemeCookie['stacks-explorer-theme']
? clientThemeCookie['stacks-explorer-theme'] === 'light'
? lightBg
: darkBg
: lightBg;

Check warning on line 73 in src/app/_components/PageWrapper.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/PageWrapper.tsx#L71-L73

Added lines #L71 - L73 were not covered by tests
return (
<StyledWrapper bg={bgColor} className="wrapper-with-bg">
{children}
Expand Down
180 changes: 180 additions & 0 deletions src/app/_components/RecentBlocks/BtcBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import { Flex, HStack, Icon, Stack } from '@chakra-ui/react';
import { CaretRight } from '@phosphor-icons/react';

Check warning on line 2 in src/app/_components/RecentBlocks/BtcBlock.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/RecentBlocks/BtcBlock.tsx#L1-L2

Added lines #L1 - L2 were not covered by tests

import { BurnBlock } from '@stacks/blockchain-api-client';

import { useGlobalContext } from '../../../common/context/useGlobalContext';
import { Text } from '../../../ui/Text';
import BitcoinCircleIcon from '../../../ui/icons/BitcoinCircleIcon';
import StxSquareIcon from '../../../ui/icons/StxSquareIcon';
import { BORDER_WIDTH, BTC_BLOCK_WIDTH, RING_WIDTH } from './consts';
import { formatTimestamp } from './utils';

Check warning on line 11 in src/app/_components/RecentBlocks/BtcBlock.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/RecentBlocks/BtcBlock.tsx#L6-L11

Added lines #L6 - L11 were not covered by tests

export function BtcBlock({ burnBlock }: { burnBlock: BurnBlock }) {
const { btcBlockBaseUrl } = useGlobalContext().activeNetwork;

Check warning on line 14 in src/app/_components/RecentBlocks/BtcBlock.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/RecentBlocks/BtcBlock.tsx#L13-L14

Added lines #L13 - L14 were not covered by tests
return (
<Flex
bg={
'linear-gradient(to bottom, var(--stacks-colors-accent-bitcoin-500), var(--stacks-colors-surface-primary))'
}
padding={`${BORDER_WIDTH}px`}
borderRadius={`calc(var(--stacks-radii-redesign-lg) + ${BORDER_WIDTH}px)`}
_hover={{
bg: 'var(--stacks-colors-accent-bitcoin-500)',
'& .block-height': { textDecoration: 'underline' },
'& .stacks-blocks-count': { color: 'textPrimary' },
}}
cursor={'pointer'}
asChild
>
<a
href={`${btcBlockBaseUrl}/${burnBlock.burn_block_height}`}
target={'_blank'}
rel="noreferrer"
>
<Stack
position="relative"
gap={0}
width={BTC_BLOCK_WIDTH}
p={3}
bg="surfacePrimary"
borderRadius="redesign.lg"
flex="0 0 auto"
>
<Stack gap={4}>
<Stack gap={2}>
<HStack gap={0} justifyContent={'space-between'}>
<HStack
gap={1.5}
px={1.5}
py={1}
borderRadius={'redesign.sm'}
bg={'surfaceSecondary'}
>
<Icon w={4} h={4}>
<BitcoinCircleIcon />
</Icon>
<Text textStyle={'text-mono-sm'} color={'textPrimary'} className={'block-height'}>
#{burnBlock.burn_block_height}
</Text>
</HStack>
<Icon w={4} h={4} color={'iconTertiary'}>
<CaretRight />
</Icon>
</HStack>
<Text textStyle={'text-medium-xs'} color={'textSecondary'}>
{formatTimestamp(burnBlock.burn_block_time)}
</Text>
</Stack>
<HStack gap={1.5} p={2} borderRadius={'redesign.md'} bg={'surfaceSecondary'}>
<Icon w={4} h={4} color={'iconTertiary'}>
<StxSquareIcon />
</Icon>
<Text
textStyle={'text-medium-xs'}
color={'textSecondary'}
className={'stacks-blocks-count'}
>
{burnBlock.stacks_blocks.length} Stacks blocks
</Text>
</HStack>
</Stack>
</Stack>
</a>
</Flex>
);
}

export function NewestBtcBlock({ burnBlock }: { burnBlock: BurnBlock }) {
const { btcBlockBaseUrl } = useGlobalContext().activeNetwork;

Check warning on line 89 in src/app/_components/RecentBlocks/BtcBlock.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/RecentBlocks/BtcBlock.tsx#L88-L89

Added lines #L88 - L89 were not covered by tests
return (
<Flex
bg={
'linear-gradient(to bottom, var(--stacks-colors-alpha-bitcoin-500-alpha-15), var(--stacks-colors-alpha-bitcoin-200-alpha-15))'
}
padding={`${RING_WIDTH}px`}
borderRadius={`calc(var(--stacks-radii-redesign-lg) + ${BORDER_WIDTH + RING_WIDTH * 2}px)`}
my={`-${RING_WIDTH * 2}px`}
asChild
_hover={{
bg: 'linear-gradient(to bottom, var(--stacks-colors-alpha-bitcoin-500-alpha-25), var(--stacks-colors-alpha-bitcoin-200-alpha-25))',
'& .block-height': { textDecoration: 'underline' },
}}
role={'group'}
>
<a
href={`${btcBlockBaseUrl}/${burnBlock.burn_block_height}`}
target={'_blank'}
rel="noreferrer"
>
<Flex
bg={
'linear-gradient(to bottom, var(--stacks-colors-alpha-bitcoin-500-alpha-40), var(--stacks-colors-alpha-bitcoin-200-alpha-40))'
}
padding={`${RING_WIDTH}px`}
borderRadius={`calc(var(--stacks-radii-redesign-lg) + ${BORDER_WIDTH + RING_WIDTH}px)`}
_hover={{
bg: 'linear-gradient(to bottom, var(--stacks-colors-alpha-bitcoin-500-alpha-60), var(--stacks-colors-alpha-bitcoin-200-alpha-60))',
}}
>
<Flex
bg={
'linear-gradient(to bottom, var(--stacks-colors-alpha-bitcoin-500-alpha-75), var(--stacks-colors-accent-stacks-400))'
}
padding={`${BORDER_WIDTH}px`}
borderRadius={`calc(var(--stacks-radii-redesign-lg) + ${BORDER_WIDTH}px)`}
>
<Stack
position="relative"
gap={0}
width="184px"
p={3}
bg="surfacePrimary"
borderRadius="redesign.lg"
flex="0 0 auto"
>
<Stack gap={4}>
<Stack gap={2}>
<HStack gap={0} justifyContent={'space-between'}>
<HStack
gap={1.5}
px={1.5}
py={1}
borderRadius={'redesign.sm'}
bg={'surfaceSecondary'}
>
<Icon w={4} h={4}>
<BitcoinCircleIcon />
</Icon>
<Text
textStyle={'text-mono-sm'}
color={'textPrimary'}
className={'block-height'}
>
#{burnBlock.burn_block_height}
</Text>
</HStack>
<Icon w={4} h={4} color={'iconTertiary'}>
<CaretRight />
</Icon>
</HStack>
<Text textStyle={'text-medium-xs'} color={'textSecondary'}>
{formatTimestamp(burnBlock.burn_block_time)}
</Text>
</Stack>
<HStack gap={1.5} p={2} borderRadius={'redesign.md'} bg={'surfaceSecondary'}>
<Icon w={4} h={4} color={'iconTertiary'}>
<StxSquareIcon />
</Icon>
<Text textStyle={'text-medium-xs'} color={'textPrimary'}>
{burnBlock.stacks_blocks.length} Stacks blocks
</Text>
</HStack>
</Stack>
</Stack>
</Flex>
</Flex>
</a>
</Flex>
);
}
77 changes: 77 additions & 0 deletions src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Box, Icon, Stack } from '@chakra-ui/react';
import { ArrowsClockwise } from '@phosphor-icons/react';
import { useEffect, useRef, useState } from 'react';

Check warning on line 3 in src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx#L1-L3

Added lines #L1 - L3 were not covered by tests

import { StacksApiSocketClient } from '@stacks/blockchain-api-client';

Check warning on line 5 in src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx#L5

Added line #L5 was not covered by tests

import { useGlobalContext } from '../../../common/context/useGlobalContext';
import { Text } from '../../../ui/Text';
import { BTC_BLOCK_WIDTH, EMPTY_BTC_BLOCK_WIDTH } from './consts';

Check warning on line 9 in src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx#L7-L9

Added lines #L7 - L9 were not covered by tests

export function NewBlockPlaceholder({

Check warning on line 11 in src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx#L11

Added line #L11 was not covered by tests
newestBtcBlockHeight,
refetch,
}: {
newestBtcBlockHeight: number;
refetch: () => void;
}) {
const [hasNewBlocks, setHasNewBlocks] = useState(false);
const { activeNetwork } = useGlobalContext();
const lastBlockHeightRef = useRef(newestBtcBlockHeight);

Check warning on line 20 in src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx#L17-L20

Added lines #L17 - L20 were not covered by tests

useEffect(() => {
lastBlockHeightRef.current = newestBtcBlockHeight;
setHasNewBlocks(false);

Check warning on line 24 in src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx#L22-L24

Added lines #L22 - L24 were not covered by tests
}, [newestBtcBlockHeight]);

useEffect(() => {
const socketClient = new StacksApiSocketClient({ url: activeNetwork.url });

Check warning on line 28 in src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx#L27-L28

Added lines #L27 - L28 were not covered by tests

const blocksWebsocket = socketClient.subscribeBlocks(block => {

Check warning on line 30 in src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx#L30

Added line #L30 was not covered by tests
if (block.burn_block_height > lastBlockHeightRef.current) {
setHasNewBlocks(true);
blocksWebsocket.unsubscribe();

Check warning on line 33 in src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx#L32-L33

Added lines #L32 - L33 were not covered by tests
}
});

return () => {
blocksWebsocket.unsubscribe();

Check warning on line 38 in src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx

View check run for this annotation

Codecov / codecov/patch

src/app/_components/RecentBlocks/NewBlockPlaceholder.tsx#L37-L38

Added lines #L37 - L38 were not covered by tests
};
}, [activeNetwork.url]);

return (
<Stack
width={hasNewBlocks ? BTC_BLOCK_WIDTH : EMPTY_BTC_BLOCK_WIDTH}
border="1px dashed var(--stacks-colors-accent-bitcoin-500)"
flex="0 0 auto"
alignItems="center"
justifyContent="center"
gap={1.5}
p={5}
borderRadius={hasNewBlocks ? 'redesign.lg' : 'redesign.xs'}
transition="all 0.2s ease-in-out"
cursor={hasNewBlocks ? 'pointer' : 'default'}
onClick={hasNewBlocks ? refetch : undefined}
boxShadow={hasNewBlocks ? '0px 4px 12px 0px rgba(255, 145, 0, 0.25)' : undefined}
>
<Box opacity={hasNewBlocks ? 1 : 0} transition="opacity 0.2s ease-in-out">
<Text textStyle="text-medium-sm" color="textTertiary" textAlign="center">
New blocks have been mined.
</Text>
<Text
textStyle="text-medium-sm"
color="textSecondary"
display="flex"
gap={1.5}
alignItems="center"
justifyContent="center"
>
Update
<Icon w={3.5} h={3.5}>
<ArrowsClockwise />
</Icon>
</Text>
</Box>
</Stack>
);
}
Loading

0 comments on commit c0840dc

Please sign in to comment.