mirror of
https://github.com/status-im/nimbus-gui.git
synced 2025-02-27 18:40:33 +00:00
Merge branch 'main' into rd.pair-device-responsive
This commit is contained in:
commit
201a25a01a
1
.gitignore
vendored
1
.gitignore
vendored
@ -36,3 +36,4 @@ dist-ssr
|
||||
|
||||
# vercel
|
||||
/.vercel
|
||||
.vercel
|
||||
|
@ -16,11 +16,11 @@ import PairDevice from './pages/PairDevice/PairDevice'
|
||||
import PinnedNotification from './components/General/PinnedNottification'
|
||||
import CreateLocalNodePage from './pages/CreateLocalNodePage/CreateLocalNodePage'
|
||||
import ValidatorOnboarding from './pages/ValidatorOnboarding/ValidatorOnboarding'
|
||||
import { ethereumRopsten, wcV2InitOptions, apiKey } from './constants'
|
||||
import Dashboard from './pages/Dashboard/Dashboard'
|
||||
import ConnectExistingInstance from './pages/ConnectExistingInstance/ConnectExistingInstance'
|
||||
import './App.css'
|
||||
import ValidatorManagement from './pages/ValidatorManagement/ValidatorManagement'
|
||||
import { ethereumRopsten, wcV2InitOptions, apiKey } from './constants'
|
||||
import './App.css'
|
||||
|
||||
const injected = injectedModule()
|
||||
const walletConnect = walletConnectModule(wcV2InitOptions)
|
||||
|
@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react'
|
||||
import AddCardsContainer from './AddCardsContainer'
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/AddCardsContainer',
|
||||
title: 'General/AddCardsContainer',
|
||||
component: AddCardsContainer,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
@ -15,5 +15,13 @@ export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
args: {
|
||||
cardsAmount: 2,
|
||||
},
|
||||
}
|
||||
|
||||
export const WithoutCards: Story = {
|
||||
args: {
|
||||
cardsAmount: 0,
|
||||
},
|
||||
}
|
||||
|
@ -4,14 +4,19 @@ import AddCard from './AddCard'
|
||||
import DashboardCardWrapper from '../../../pages/Dashboard/DashboardCardWrapper'
|
||||
import { getHeightPercentages } from '../../../utilities'
|
||||
|
||||
const AddCardsContainer = () => {
|
||||
const cards = 2
|
||||
type AddCardsContainerProps = {
|
||||
cardsAmount: number
|
||||
}
|
||||
|
||||
const AddCardsContainer = ({ cardsAmount }: AddCardsContainerProps) => {
|
||||
return (
|
||||
<DashboardCardWrapper padding="0" minWidth="50px">
|
||||
<YStack height={'100%'}>
|
||||
{Array.from({ length: cards }).map((_, index) => (
|
||||
<AddCard key={index} style={{ padding: '56px', height: getHeightPercentages(cards) }} />
|
||||
{Array.from({ length: cardsAmount }).map((_, index) => (
|
||||
<AddCard
|
||||
key={index}
|
||||
style={{ padding: '40px', height: getHeightPercentages(cardsAmount) }}
|
||||
/>
|
||||
))}
|
||||
</YStack>
|
||||
</DashboardCardWrapper>
|
||||
|
@ -2,44 +2,23 @@ import { Tabs } from '@status-im/components'
|
||||
import { Stack } from 'tamagui'
|
||||
|
||||
import ValidatorsList from './ValidatorsList'
|
||||
import { useMemo } from 'react'
|
||||
import { VALIDATOR_TABS_RIGHT_SIDEBAR } from '../../../../constants'
|
||||
|
||||
const ValidatorsTabs = () => {
|
||||
const VALIDATOR_TABS = useMemo(
|
||||
() => [
|
||||
{
|
||||
label: 'Active',
|
||||
value: 'active',
|
||||
children: <ValidatorsList />,
|
||||
},
|
||||
{
|
||||
label: 'Pending',
|
||||
value: 'pending',
|
||||
children: <ValidatorsList />,
|
||||
},
|
||||
{
|
||||
label: 'Inactive',
|
||||
value: 'inactive',
|
||||
children: <ValidatorsList />,
|
||||
},
|
||||
],
|
||||
[],
|
||||
)
|
||||
|
||||
return (
|
||||
<Tabs defaultValue="active">
|
||||
<Tabs defaultValue={VALIDATOR_TABS_RIGHT_SIDEBAR[0]}>
|
||||
<Stack style={{ cursor: 'pointer', width: 'fit-content' }}>
|
||||
<Tabs.List size={32}>
|
||||
{VALIDATOR_TABS.map(tab => (
|
||||
<Tabs.Trigger key={tab.value} type="default" value={tab.value}>
|
||||
{tab.label}
|
||||
{VALIDATOR_TABS_RIGHT_SIDEBAR.map(tab => (
|
||||
<Tabs.Trigger key={tab} type="default" value={tab}>
|
||||
{tab}
|
||||
</Tabs.Trigger>
|
||||
))}
|
||||
</Tabs.List>
|
||||
</Stack>
|
||||
{VALIDATOR_TABS.map(tab => (
|
||||
<Tabs.Content key={tab.value} value={tab.value} style={{ marginTop: '8px' }}>
|
||||
{tab.children}
|
||||
{VALIDATOR_TABS_RIGHT_SIDEBAR.map(tab => (
|
||||
<Tabs.Content key={tab} value={tab} style={{ marginTop: '8px' }}>
|
||||
<ValidatorsList />
|
||||
</Tabs.Content>
|
||||
))}
|
||||
</Tabs>
|
||||
|
@ -1,15 +1,15 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import KeyGenerationSyncCard from './KeyGenerationSyncCard'
|
||||
import SyncStatusCard from './SyncStatusCard'
|
||||
|
||||
const meta = {
|
||||
title: 'ValidatorOnboarding/KeyGenerationSyncCard',
|
||||
component: KeyGenerationSyncCard,
|
||||
title: 'General/SyncStatusCard',
|
||||
component: SyncStatusCard,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof KeyGenerationSyncCard>
|
||||
} satisfies Meta<typeof SyncStatusCard>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
@ -2,18 +2,18 @@ import { Stack, XStack, YStack } from 'tamagui'
|
||||
import { InfoBadgeIcon } from '@status-im/icons'
|
||||
import { Text } from '@status-im/components'
|
||||
|
||||
import StandardGauge from '../../../../components/Charts/StandardGauge'
|
||||
import BorderBox from '../../../../components/General/BorderBox'
|
||||
import { formatNumbersWithComa } from '../../../../utilities'
|
||||
import StandardGauge from '../Charts/StandardGauge'
|
||||
import BorderBox from './BorderBox'
|
||||
import { formatNumbersWithComa } from '../../utilities'
|
||||
|
||||
type KeyGenerationSyncCardProps = {
|
||||
type SyncStatusCardProps = {
|
||||
synced: number
|
||||
total: number
|
||||
title: string
|
||||
color: string
|
||||
}
|
||||
|
||||
const KeyGenerationSyncCard = ({ synced, total, title, color }: KeyGenerationSyncCardProps) => {
|
||||
const SyncStatusCard = ({ synced, total, title, color }: SyncStatusCardProps) => {
|
||||
return (
|
||||
<BorderBox style={{ borderRadius: '10.1px', borderWidth: '0.5px' }}>
|
||||
<XStack space={'$2'} alignItems="center">
|
||||
@ -54,4 +54,4 @@ const KeyGenerationSyncCard = ({ synced, total, title, color }: KeyGenerationSyn
|
||||
)
|
||||
}
|
||||
|
||||
export default KeyGenerationSyncCard
|
||||
export default SyncStatusCard
|
@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react'
|
||||
import TitleLogo from './TitleLogo'
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/TitleLogo',
|
||||
title: 'General/TitleLogo',
|
||||
component: TitleLogo,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
@ -15,5 +15,11 @@ export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
subtitle: 'Node Management Dashboard',
|
||||
},
|
||||
}
|
||||
|
||||
export const WithoutSubtitle: Story = {
|
||||
args: {},
|
||||
}
|
@ -1,7 +1,11 @@
|
||||
import { Avatar, Text } from '@status-im/components'
|
||||
import { Stack, XStack, YStack } from 'tamagui'
|
||||
|
||||
const TitleLogo = () => {
|
||||
type TitleLogoProps = {
|
||||
subtitle?: string
|
||||
}
|
||||
|
||||
const TitleLogo = ({ subtitle }: TitleLogoProps) => {
|
||||
return (
|
||||
<XStack space={'$2'}>
|
||||
<Stack style={{ marginTop: '3px' }}>
|
||||
@ -18,7 +22,7 @@ const TitleLogo = () => {
|
||||
Nimbus
|
||||
</Text>
|
||||
<Text size={19} color="#647084">
|
||||
Node Management Dashboard
|
||||
{subtitle}
|
||||
</Text>
|
||||
</YStack>
|
||||
</XStack>
|
19
src/components/General/ValidatorProfile.stories.tsx
Normal file
19
src/components/General/ValidatorProfile.stories.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import ValidatorProfile from './ValidatorProfile'
|
||||
|
||||
const meta = {
|
||||
title: 'General/ValidatorProfile',
|
||||
component: ValidatorProfile,
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof ValidatorProfile>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
number: 1,
|
||||
address: 'zQ3asdf9d4Gs0',
|
||||
},
|
||||
}
|
33
src/components/General/ValidatorProfile.tsx
Normal file
33
src/components/General/ValidatorProfile.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import { Avatar, Text } from '@status-im/components'
|
||||
import { XStack, YStack } from 'tamagui'
|
||||
|
||||
import { getFormattedValidatorAddress } from '../../utilities'
|
||||
|
||||
type ValidatorProfileProps = {
|
||||
number: number
|
||||
address: string
|
||||
}
|
||||
|
||||
const ValidatorProfile = ({ number, address }: ValidatorProfileProps) => {
|
||||
return (
|
||||
<XStack space={'$2'}>
|
||||
<Avatar
|
||||
type="user"
|
||||
size={32}
|
||||
src="/icons/validator-request.svg"
|
||||
name={number.toString()}
|
||||
indicator="online"
|
||||
/>
|
||||
<YStack>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
Validator {number}
|
||||
</Text>
|
||||
<Text size={13} color="#647084">
|
||||
{getFormattedValidatorAddress(address)}
|
||||
</Text>
|
||||
</YStack>
|
||||
</XStack>
|
||||
)
|
||||
}
|
||||
|
||||
export default ValidatorProfile
|
@ -45,7 +45,6 @@ export const DEPOSIT_SUBTITLE = 'Connect you Wallet to stake required ETH for ne
|
||||
export const CLIENT_SETUP_SUBTITLE = 'How many Validators would you like to run?'
|
||||
|
||||
// Dashboard
|
||||
|
||||
export const years = [
|
||||
'JAN',
|
||||
'FEB',
|
||||
@ -60,3 +59,57 @@ export const years = [
|
||||
'NOV',
|
||||
'DEC',
|
||||
]
|
||||
export const VALIDATOR_TABS_RIGHT_SIDEBAR = ['Active', 'Pending', 'Inactive']
|
||||
|
||||
// Validator Management
|
||||
export const VALIDATOR_TABS_MANAGEMENT = [
|
||||
'Active',
|
||||
'Pending',
|
||||
'Inactive',
|
||||
'Exited',
|
||||
'Withdraw',
|
||||
'All',
|
||||
]
|
||||
|
||||
export const VALIDATORS_DATA = [
|
||||
{
|
||||
number: 1,
|
||||
address: 'zQ3asdf9d4Gs0',
|
||||
balance: 32.0786,
|
||||
income: 0.0786,
|
||||
proposals: '1/102',
|
||||
attestations: '1/102',
|
||||
effectiveness: 98,
|
||||
status: 'Active',
|
||||
},
|
||||
{
|
||||
number: 1,
|
||||
address: 'zQ3asdf9d4Gs0',
|
||||
balance: 32.0786,
|
||||
income: 0.0786,
|
||||
proposals: '1/102',
|
||||
attestations: '1/102',
|
||||
effectiveness: 98,
|
||||
status: 'Active',
|
||||
},
|
||||
{
|
||||
number: 1,
|
||||
address: 'zQ3asdf9d4Gs0',
|
||||
balance: 32.0786,
|
||||
income: 0.0786,
|
||||
proposals: '1/102',
|
||||
attestations: '1/102',
|
||||
effectiveness: 98,
|
||||
status: 'Active',
|
||||
},
|
||||
{
|
||||
number: 1,
|
||||
address: 'zQ3asdf9d4Gs0',
|
||||
balance: 32.0786,
|
||||
income: 0.0786,
|
||||
proposals: '1/102',
|
||||
attestations: '1/102',
|
||||
effectiveness: 98,
|
||||
status: 'Active',
|
||||
},
|
||||
]
|
||||
|
@ -62,7 +62,6 @@
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
h1,
|
||||
@ -103,11 +102,13 @@ ul li {
|
||||
}
|
||||
.transparent-scrollbar::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.transparent-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 10px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.transparent-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
@ -136,4 +137,10 @@ ul li {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.right-sidebar-wrapper {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Stack, YStack } from 'tamagui'
|
||||
import { Stack, YStack, XStack } from 'tamagui'
|
||||
|
||||
import BasicInfoCards from './BasicInfoCards/BasicInfoCards'
|
||||
import AddCardsContainer from '../../components/General/AddCards/AddCardsContainer'
|
||||
import BalanceChartCard from './BalanceChartCard/BalanceChartCard'
|
||||
@ -6,15 +7,16 @@ import CPUCard from './CPULoad/CPUCard'
|
||||
import ConsensusUptimeCard from './ConsensusUptime/ConsensusUptimeCard'
|
||||
import ExecutionUptime from './ExecutionUptime/ExecutionUptime'
|
||||
import DeviceUptime from './DeviceUptime/DeviceUptime'
|
||||
import TitleLogo from './TitleLogo'
|
||||
import TitleLogo from '../../components/General/TitleLogo'
|
||||
import StorageCard from './StorageCard/StorageCard'
|
||||
import NetworkCard from './NetworkCard/NetworkCard'
|
||||
import SyncStatusCard from './SyncStatusCards/SyncStatusCards'
|
||||
import SyncStatusCards from './SyncStatusCards/SyncStatusCards'
|
||||
import MemoryCard from './MemoryCard/MemoryCard'
|
||||
import { XStack } from 'tamagui'
|
||||
|
||||
type DashboardContentProps = {
|
||||
windowWidth: number
|
||||
}
|
||||
|
||||
const DashboardContent = ({ windowWidth }: DashboardContentProps) => {
|
||||
return (
|
||||
<YStack
|
||||
@ -30,7 +32,7 @@ const DashboardContent = ({ windowWidth }: DashboardContentProps) => {
|
||||
}}
|
||||
className={'transparent-scrollbar'}
|
||||
>
|
||||
<TitleLogo />
|
||||
<TitleLogo subtitle="Node Management Dashboard" />
|
||||
<Stack
|
||||
style={{
|
||||
display: 'grid',
|
||||
@ -39,8 +41,8 @@ const DashboardContent = ({ windowWidth }: DashboardContentProps) => {
|
||||
gridAutoFlow: 'row',
|
||||
}}
|
||||
>
|
||||
<SyncStatusCard />
|
||||
<AddCardsContainer />
|
||||
<SyncStatusCards />
|
||||
<AddCardsContainer cardsAmount={2} />
|
||||
{windowWidth < 1375 ? (
|
||||
<Stack style={{ gridColumn: '1 / span 2' }} width={'101%'}>
|
||||
<BalanceChartCard />
|
||||
|
@ -5,7 +5,7 @@ import DashboardCardWrapper from '../DashboardCardWrapper'
|
||||
import ExecutionClientCard from './ExecutionClientCard'
|
||||
import ConsensusCard from './ConsensusClientCard'
|
||||
|
||||
const SyncStatusCard = () => {
|
||||
const SyncStatusCards = () => {
|
||||
return (
|
||||
<DashboardCardWrapper padding="0" minWidth="50px">
|
||||
<YStack space={'$2'}>
|
||||
@ -24,4 +24,4 @@ const SyncStatusCard = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default SyncStatusCard
|
||||
export default SyncStatusCards
|
||||
|
19
src/pages/ValidatorManagement/ManagementCard.stories.ts
Normal file
19
src/pages/ValidatorManagement/ManagementCard.stories.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import ManagementCard from './ManagementCard'
|
||||
|
||||
const meta = {
|
||||
title: 'ValidatorManagement/ManagementCard',
|
||||
component: ManagementCard,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof ManagementCard>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
}
|
31
src/pages/ValidatorManagement/ManagementCard.tsx
Normal file
31
src/pages/ValidatorManagement/ManagementCard.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import { Text } from '@status-im/components'
|
||||
import { Separator, Stack, YStack } from 'tamagui'
|
||||
|
||||
const ManagementCard = () => {
|
||||
return (
|
||||
<YStack
|
||||
space={'$3'}
|
||||
style={{ border: '1px solid #F0F2F5', borderRadius: '16px', minWidth: '33%' }}
|
||||
>
|
||||
<Stack style={{ padding: '12px 16px' }}>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
Validators
|
||||
</Text>
|
||||
</Stack>
|
||||
<Separator borderColor={'#F0F2F5'} />
|
||||
<Stack style={{ padding: '12px 16px' }}>
|
||||
<Text size={15} weight={'semibold'} color="#647084">
|
||||
Total Balance
|
||||
</Text>
|
||||
</Stack>
|
||||
<Separator borderColor={'#F0F2F5'} />
|
||||
<Stack style={{ padding: '12px 16px', marginBottom: '16px' }}>
|
||||
<Text size={15} weight={'semibold'} color="#647084">
|
||||
Total Income
|
||||
</Text>
|
||||
</Stack>
|
||||
</YStack>
|
||||
)
|
||||
}
|
||||
|
||||
export default ManagementCard
|
19
src/pages/ValidatorManagement/ManagementHeader.stories.ts
Normal file
19
src/pages/ValidatorManagement/ManagementHeader.stories.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import ManagementHeader from './ManagementHeader'
|
||||
|
||||
const meta = {
|
||||
title: 'ValidatorManagement/ManagementHeader',
|
||||
component: ManagementHeader,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof ManagementHeader>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
}
|
39
src/pages/ValidatorManagement/ManagementHeader.tsx
Normal file
39
src/pages/ValidatorManagement/ManagementHeader.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import { XStack } from 'tamagui'
|
||||
|
||||
import TitleLogo from '../../components/General/TitleLogo'
|
||||
import SyncStatusCard from '../../components/General/SyncStatusCard'
|
||||
|
||||
const ManagementHeader = () => {
|
||||
return (
|
||||
<XStack
|
||||
style={{
|
||||
width: '100%',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginTop: '16px',
|
||||
}}
|
||||
>
|
||||
<TitleLogo subtitle="Validator Management" />
|
||||
<XStack space={'$2'}>
|
||||
<div className="sync-status-card-container-first">
|
||||
<SyncStatusCard
|
||||
synced={123.524}
|
||||
total={172.503}
|
||||
title="Execution Sync Status"
|
||||
color="#2a4af5"
|
||||
/>
|
||||
</div>
|
||||
<div className="sync-status-card-container-second">
|
||||
<SyncStatusCard
|
||||
synced={123.524}
|
||||
total={172.503}
|
||||
title="Consensus Sync Status"
|
||||
color="#ff6161"
|
||||
/>
|
||||
</div>
|
||||
</XStack>
|
||||
</XStack>
|
||||
)
|
||||
}
|
||||
|
||||
export default ManagementHeader
|
@ -0,0 +1,19 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import DropdownFilter from './DropdownFilter'
|
||||
|
||||
const meta = {
|
||||
title: 'ValidatorManagement/DropdownFilter',
|
||||
component: DropdownFilter,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof DropdownFilter>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
import { DropdownMenu } from '@status-im/components'
|
||||
import { SortIcon } from '@status-im/icons'
|
||||
import { Stack } from 'tamagui'
|
||||
|
||||
const DropdownFilter = () => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<Stack style={{ position: 'relative', display: 'flex', alignItems: 'center' }}>
|
||||
<SortIcon
|
||||
size={20}
|
||||
color="#647084"
|
||||
style={{
|
||||
border: '1px solid #DCE0E5',
|
||||
borderRadius: '10px',
|
||||
padding: '8px',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
/>
|
||||
<Stack
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: -2,
|
||||
top: -1.5,
|
||||
width: '9px',
|
||||
height: '9px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: '#1992D7',
|
||||
border: '1.5px solid #fff',
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
<DropdownMenu.Content sideOffset={5} position="absolute" zIndex={999} />
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
||||
|
||||
export default DropdownFilter
|
@ -0,0 +1,18 @@
|
||||
table {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
margin: 20px 0;
|
||||
font-size: 14px;
|
||||
border: 1px solid #e7eaee;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
th {
|
||||
border-bottom: 1px solid #e7eaee;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 9px 19px;
|
||||
text-align: center;
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
import { useState } from 'react'
|
||||
|
||||
import ManagementTable from './ManagementTable'
|
||||
import { VALIDATOR_TABS_MANAGEMENT } from '../../../constants'
|
||||
|
||||
const meta = {
|
||||
title: 'ValidatorManagement/ManagementTable',
|
||||
component: ManagementTable,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof ManagementTable>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = () => {
|
||||
const [searchValue, setSearchValue] = useState('')
|
||||
|
||||
const changeSearchValue = (os: string) => {
|
||||
setSearchValue(os)
|
||||
}
|
||||
|
||||
return (
|
||||
<ManagementTable
|
||||
tab={VALIDATOR_TABS_MANAGEMENT[0]}
|
||||
searchValue={searchValue}
|
||||
changeSearchValue={changeSearchValue}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
Default.args = {
|
||||
tab: VALIDATOR_TABS_MANAGEMENT[0],
|
||||
searchValue: '',
|
||||
changeSearchValue: () => {},
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { YStack, XStack } from 'tamagui'
|
||||
|
||||
import { VALIDATORS_DATA, VALIDATOR_TABS_MANAGEMENT } from '../../../constants'
|
||||
import SearchManagement from './SearchManagement'
|
||||
import DropdownFilter from './DropdownFilter'
|
||||
import ManagementTableHeader from './ManagementTableHeader'
|
||||
import ManagementTableBody from './ManagementTableBody'
|
||||
import './ManagementTable.css'
|
||||
|
||||
type ManagementTableProps = {
|
||||
tab: string
|
||||
searchValue: string
|
||||
changeSearchValue: (value: string) => void
|
||||
}
|
||||
|
||||
export type Validator = {
|
||||
number: number
|
||||
address: string
|
||||
balance: number
|
||||
income: number
|
||||
proposals: string
|
||||
attestations: string
|
||||
effectiveness: number
|
||||
status: string
|
||||
}
|
||||
|
||||
const isValidStatus = (validatorStatus: string, tabStatus: string) => {
|
||||
if (
|
||||
validatorStatus === tabStatus ||
|
||||
tabStatus === VALIDATOR_TABS_MANAGEMENT[VALIDATOR_TABS_MANAGEMENT.length - 1]
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const isValidNumberOrAddress = (
|
||||
validatorNumber: number,
|
||||
validatorAddress: string,
|
||||
searchValue: string,
|
||||
) => {
|
||||
if (validatorNumber.toString().includes(searchValue) || validatorAddress.includes(searchValue)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const ManagementTable = ({ tab, searchValue, changeSearchValue }: ManagementTableProps) => {
|
||||
const [validators, setValidators] = useState<Validator[]>([])
|
||||
const [isAllSelected, setIsAllSelected] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setValidators(VALIDATORS_DATA)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
setIsAllSelected(false)
|
||||
}, [validators, tab, searchValue])
|
||||
|
||||
const filteredValidators = useMemo(() => {
|
||||
return validators
|
||||
.filter(validator => isValidStatus(validator.status, tab))
|
||||
.filter(validator => isValidNumberOrAddress(validator.number, validator.address, searchValue))
|
||||
}, [validators, tab, searchValue])
|
||||
|
||||
const handleSelectAll = () => {
|
||||
setIsAllSelected(state => !state)
|
||||
}
|
||||
|
||||
return (
|
||||
<YStack>
|
||||
<XStack space={'$3'} justifyContent="space-between" alignItems="center">
|
||||
<SearchManagement searchValue={searchValue} changeSearchValue={changeSearchValue} />
|
||||
<DropdownFilter />
|
||||
</XStack>
|
||||
<table>
|
||||
<ManagementTableHeader
|
||||
validatorsAmount={filteredValidators.length}
|
||||
isAllSelected={isAllSelected}
|
||||
handleSelectAll={handleSelectAll}
|
||||
/>
|
||||
<ManagementTableBody
|
||||
filteredValidators={filteredValidators}
|
||||
isAllSelected={isAllSelected}
|
||||
/>
|
||||
</table>
|
||||
</YStack>
|
||||
)
|
||||
}
|
||||
|
||||
export default ManagementTable
|
@ -0,0 +1,30 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import ManagementTableBody from './ManagementTableBody'
|
||||
import { VALIDATORS_DATA } from '../../../constants'
|
||||
|
||||
const meta = {
|
||||
title: 'ValidatorManagement/ManagementTableBody',
|
||||
component: ManagementTableBody,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof ManagementTableBody>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
filteredValidators: VALIDATORS_DATA,
|
||||
isAllSelected: false,
|
||||
},
|
||||
}
|
||||
|
||||
export const AllSelected: Story = {
|
||||
args: {
|
||||
filteredValidators: VALIDATORS_DATA,
|
||||
isAllSelected: true,
|
||||
},
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
import { Text } from '@status-im/components'
|
||||
|
||||
import { Validator } from './ManagementTable'
|
||||
import ManagementTableRow from './ManagementTableRow'
|
||||
|
||||
type ManagementTableBodyProps = {
|
||||
filteredValidators: Validator[]
|
||||
isAllSelected: boolean
|
||||
}
|
||||
|
||||
const ManagementTableBody = ({ filteredValidators, isAllSelected }: ManagementTableBodyProps) => {
|
||||
return (
|
||||
<tbody>
|
||||
{filteredValidators.map(validator => (
|
||||
<ManagementTableRow
|
||||
key={validator.address}
|
||||
validator={validator}
|
||||
isAllSelected={isAllSelected}
|
||||
/>
|
||||
))}
|
||||
{filteredValidators.length === 0 && (
|
||||
<tr>
|
||||
<td colSpan={11}>
|
||||
<Text size={15} color={'#647084'} weight={'semibold'}>
|
||||
No validators
|
||||
</Text>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
)
|
||||
}
|
||||
|
||||
export default ManagementTableBody
|
@ -0,0 +1,38 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
import { useState } from 'react'
|
||||
|
||||
import ManagementTableHeader from './ManagementTableHeader'
|
||||
|
||||
const meta = {
|
||||
title: 'ValidatorManagement/ManagementTableHeader',
|
||||
component: ManagementTableHeader,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof ManagementTableHeader>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = () => {
|
||||
const [isAllSelected, setIsAllSelected] = useState(false)
|
||||
|
||||
const handleSelectAll = () => {
|
||||
setIsAllSelected(state => !state)
|
||||
}
|
||||
|
||||
return (
|
||||
<ManagementTableHeader
|
||||
validatorsAmount={4}
|
||||
isAllSelected={isAllSelected}
|
||||
handleSelectAll={handleSelectAll}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
Default.args = {
|
||||
isAllSelected: false,
|
||||
validatorsAmount: 4,
|
||||
handleSelectAll: () => {},
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
import { Checkbox, Text } from '@status-im/components'
|
||||
|
||||
type ManagementTableHeaderProps = {
|
||||
validatorsAmount: number
|
||||
isAllSelected: boolean
|
||||
handleSelectAll: () => void
|
||||
}
|
||||
|
||||
const ManagementTableHeader = ({
|
||||
validatorsAmount,
|
||||
isAllSelected,
|
||||
handleSelectAll,
|
||||
}: ManagementTableHeaderProps) => {
|
||||
return (
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<Checkbox
|
||||
id="table"
|
||||
variant="outline"
|
||||
selected={isAllSelected}
|
||||
onCheckedChange={handleSelectAll}
|
||||
/>
|
||||
</th>
|
||||
<th>
|
||||
<Text size={15} color={'#647084'}>
|
||||
{validatorsAmount} Validators
|
||||
</Text>
|
||||
</th>
|
||||
<th>
|
||||
<Text size={15} color={'#647084'}>
|
||||
Balance
|
||||
</Text>
|
||||
</th>
|
||||
<th>
|
||||
<Text size={15} color={'#647084'}>
|
||||
Income
|
||||
</Text>
|
||||
</th>
|
||||
<th>
|
||||
<Text size={15} color={'#647084'}>
|
||||
Proposals
|
||||
</Text>
|
||||
</th>
|
||||
<th>
|
||||
<Text size={15} color={'#647084'}>
|
||||
Attestations
|
||||
</Text>
|
||||
</th>
|
||||
<th>
|
||||
<Text size={15} color={'#647084'}>
|
||||
Effectiveness
|
||||
</Text>
|
||||
</th>
|
||||
<th>
|
||||
<Text size={15} color={'#647084'}>
|
||||
Status
|
||||
</Text>
|
||||
</th>
|
||||
<th />
|
||||
</tr>
|
||||
</thead>
|
||||
)
|
||||
}
|
||||
|
||||
export default ManagementTableHeader
|
@ -0,0 +1,23 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import ManagementTableRow from './ManagementTableRow'
|
||||
import { VALIDATORS_DATA } from '../../../constants'
|
||||
|
||||
const meta = {
|
||||
title: 'ValidatorManagement/ManagementTableRow',
|
||||
component: ManagementTableRow,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof ManagementTableRow>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
validator: VALIDATORS_DATA[0],
|
||||
isAllSelected: false,
|
||||
},
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Checkbox, Text } from '@status-im/components'
|
||||
import { OptionsIcon } from '@status-im/icons'
|
||||
|
||||
import ValidatorProfile from '../../../components/General/ValidatorProfile'
|
||||
import { Validator } from './ManagementTable'
|
||||
|
||||
type ManagementTableRowProps = {
|
||||
validator: Validator
|
||||
isAllSelected: boolean
|
||||
}
|
||||
|
||||
const ManagementTableRow = ({ validator, isAllSelected }: ManagementTableRowProps) => {
|
||||
const [isSelected, setIsSelected] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setIsSelected(isAllSelected)
|
||||
}, [isAllSelected])
|
||||
|
||||
const handleChangeIsSelected = () => {
|
||||
setIsSelected(state => !state)
|
||||
}
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<Checkbox
|
||||
id={validator.address}
|
||||
variant="outline"
|
||||
selected={isSelected}
|
||||
onCheckedChange={handleChangeIsSelected}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<ValidatorProfile number={validator.number} address={validator.address} />
|
||||
</td>
|
||||
<td>
|
||||
<Text size={15} color={'#647084'} weight={'semibold'}>
|
||||
{validator.balance}
|
||||
</Text>
|
||||
</td>
|
||||
<td>
|
||||
<Text size={15} color={'#647084'} weight={'semibold'}>
|
||||
{validator.income}
|
||||
</Text>
|
||||
</td>
|
||||
<td>
|
||||
<Text size={15} color={'#647084'}>
|
||||
{validator.proposals}
|
||||
</Text>
|
||||
</td>
|
||||
<td>
|
||||
<Text size={15} color={'#647084'}>
|
||||
{validator.attestations}
|
||||
</Text>
|
||||
</td>
|
||||
<td>
|
||||
<Text size={15} color={'#647084'}>
|
||||
{validator.effectiveness}%
|
||||
</Text>
|
||||
</td>
|
||||
<td>
|
||||
<Text size={15} color={'#2F80ED'} weight={'semibold'}>
|
||||
{validator.status}
|
||||
</Text>
|
||||
</td>
|
||||
<td>
|
||||
<OptionsIcon size={20} color="#647084" style={{ cursor: 'pointer' }} />
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
export default ManagementTableRow
|
@ -0,0 +1,26 @@
|
||||
import { useState } from 'react'
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import SearchManagement from './SearchManagement'
|
||||
|
||||
const meta = {
|
||||
title: 'ValidatorManagement/SearchManagement',
|
||||
component: SearchManagement,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof SearchManagement>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = (args: { searchValue: string }) => {
|
||||
const [searchValue, setSearchValue] = useState(args.searchValue)
|
||||
|
||||
return <SearchManagement searchValue={searchValue} changeSearchValue={setSearchValue} />
|
||||
}
|
||||
|
||||
Default.args = {
|
||||
searchValue: '',
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import { Input } from '@status-im/components'
|
||||
import { SearchIcon } from '@status-im/icons'
|
||||
|
||||
type SearchManagementProps = {
|
||||
searchValue: string
|
||||
changeSearchValue: (value: string) => void
|
||||
}
|
||||
|
||||
const SearchManagement = ({ searchValue, changeSearchValue }: SearchManagementProps) => {
|
||||
return (
|
||||
<div style={{ width: '100%' }}>
|
||||
<Input
|
||||
placeholder="Filter Validators"
|
||||
value={searchValue}
|
||||
onChangeText={changeSearchValue}
|
||||
icon={<SearchIcon size={20} />}
|
||||
onClear={() => changeSearchValue('')}
|
||||
size={40}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SearchManagement
|
19
src/pages/ValidatorManagement/ManagementTabs.stories.ts
Normal file
19
src/pages/ValidatorManagement/ManagementTabs.stories.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import ManagementTabs from './ManagementTabs'
|
||||
|
||||
const meta = {
|
||||
title: 'ValidatorManagement/ManagementTabs',
|
||||
component: ManagementTabs,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof ManagementTabs>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
}
|
43
src/pages/ValidatorManagement/ManagementTabs.tsx
Normal file
43
src/pages/ValidatorManagement/ManagementTabs.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import { Tabs } from '@status-im/components'
|
||||
import { Stack } from 'tamagui'
|
||||
import { useState } from 'react'
|
||||
|
||||
import ManagementTable from './ManagementTable/ManagementTable'
|
||||
import { VALIDATOR_TABS_MANAGEMENT } from '../../constants'
|
||||
|
||||
const ManagementTabs = () => {
|
||||
const [searchValue, setSearchValue] = useState('')
|
||||
|
||||
const changeSearchValue = (value: string) => {
|
||||
setSearchValue(value)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ width: '100%' }}>
|
||||
<Tabs defaultValue={VALIDATOR_TABS_MANAGEMENT[0]}>
|
||||
<div className="tabs transparent-scrollbar">
|
||||
<Stack maxWidth={'120px'} style={{ cursor: 'pointer', margin: '8px 0' }}>
|
||||
<Tabs.List size={32}>
|
||||
{VALIDATOR_TABS_MANAGEMENT.map(tab => (
|
||||
<Tabs.Trigger key={tab} type="default" value={tab}>
|
||||
{tab}
|
||||
</Tabs.Trigger>
|
||||
))}
|
||||
</Tabs.List>
|
||||
</Stack>
|
||||
</div>
|
||||
{VALIDATOR_TABS_MANAGEMENT.map(tab => (
|
||||
<Tabs.Content key={tab} value={tab} style={{ marginTop: '8px' }}>
|
||||
<ManagementTable
|
||||
tab={tab}
|
||||
searchValue={searchValue}
|
||||
changeSearchValue={changeSearchValue}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
))}
|
||||
</Tabs>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ManagementTabs
|
19
src/pages/ValidatorManagement/ValidatorManagement.stories.ts
Normal file
19
src/pages/ValidatorManagement/ValidatorManagement.stories.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import ValidatorManagement from './ValidatorManagement'
|
||||
|
||||
const meta = {
|
||||
title: 'Pages/ValidatorManagement',
|
||||
component: ValidatorManagement,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof ValidatorManagement>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Page: Story = {
|
||||
args: {},
|
||||
}
|
@ -1,7 +1,20 @@
|
||||
import { YStack } from 'tamagui'
|
||||
import { XStack } from 'tamagui'
|
||||
|
||||
import ValidatorManagementContent from './ValidatorManagementContent'
|
||||
import LeftSidebar from '../../components/General/LeftSidebar/LeftSidebar'
|
||||
import RightSidebar from '../../components/General/RightSideBar/RightSidebar'
|
||||
import './validatorManagement.css'
|
||||
|
||||
const ValidatorManagement = () => {
|
||||
return <YStack></YStack>
|
||||
return (
|
||||
<XStack style={{ height: '100vh' }}>
|
||||
<LeftSidebar />
|
||||
<ValidatorManagementContent />
|
||||
<div className="right-sidebar-wrapper">
|
||||
<RightSidebar />
|
||||
</div>
|
||||
</XStack>
|
||||
)
|
||||
}
|
||||
|
||||
export default ValidatorManagement
|
||||
|
@ -0,0 +1,19 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import ValidatorManagementContent from './ValidatorManagementContent'
|
||||
|
||||
const meta = {
|
||||
title: 'ValidatorManagement/ValidatorManagementContent',
|
||||
component: ValidatorManagementContent,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof ValidatorManagementContent>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
}
|
44
src/pages/ValidatorManagement/ValidatorManagementContent.tsx
Normal file
44
src/pages/ValidatorManagement/ValidatorManagementContent.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
import { Text } from '@status-im/components'
|
||||
import { YStack } from 'tamagui'
|
||||
|
||||
import ManagementTabs from './ManagementTabs'
|
||||
import AddCardsContainer from '../../components/General/AddCards/AddCardsContainer'
|
||||
import ManagementHeader from './ManagementHeader'
|
||||
import ManagementCard from './ManagementCard'
|
||||
|
||||
const ValidatorManagementContent = () => {
|
||||
return (
|
||||
<YStack
|
||||
space="$4"
|
||||
alignItems="start"
|
||||
px="24px"
|
||||
style={{
|
||||
flexGrow: '1',
|
||||
overflowY: 'auto',
|
||||
}}
|
||||
className="transparent-scrollbar"
|
||||
>
|
||||
<ManagementHeader />
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'space-between',
|
||||
width: '100%',
|
||||
gap: '16px',
|
||||
}}
|
||||
className="cards"
|
||||
>
|
||||
<ManagementCard />
|
||||
<ManagementCard />
|
||||
<AddCardsContainer cardsAmount={2} />
|
||||
</div>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
Validators
|
||||
</Text>
|
||||
<ManagementTabs />
|
||||
</YStack>
|
||||
)
|
||||
}
|
||||
|
||||
export default ValidatorManagementContent
|
94
src/pages/ValidatorManagement/validatorManagement.css
Normal file
94
src/pages/ValidatorManagement/validatorManagement.css
Normal file
@ -0,0 +1,94 @@
|
||||
@media (max-width: 1130px) {
|
||||
.sync-status-card-container-first {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) and (min-width: 810px) {
|
||||
.sync-status-card-container-first {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 590px) {
|
||||
.sync-status-card-container-second {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.tabs {
|
||||
overflow-x: auto;
|
||||
overflow-y: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.cards {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide Effectiveness */
|
||||
@media (max-width: 1300px) {
|
||||
th:nth-child(7),
|
||||
td:nth-child(7) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide the Attestations */
|
||||
@media (max-width: 1200px) {
|
||||
th:nth-child(6),
|
||||
td:nth-child(6) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide the Proposals */
|
||||
@media (max-width: 1100px) {
|
||||
th:nth-child(5),
|
||||
td:nth-child(5) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide and show Proposals */
|
||||
@media (max-width: 900px) and (min-width: 800px) {
|
||||
th:nth-child(5),
|
||||
td:nth-child(5) {
|
||||
display: table-cell;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide the Income */
|
||||
@media (max-width: 1000px) {
|
||||
th:nth-child(4),
|
||||
td:nth-child(4) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide and show Income */
|
||||
@media (max-width: 900px) and (min-width: 700px) {
|
||||
th:nth-child(4),
|
||||
td:nth-child(4) {
|
||||
display: table-cell;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide Status */
|
||||
@media (max-width: 560px) {
|
||||
th:nth-child(8),
|
||||
td:nth-child(8) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide Balance */
|
||||
@media (max-width: 475px) {
|
||||
th:nth-child(3),
|
||||
td:nth-child(3) {
|
||||
display: none;
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import { Avatar, DividerLine, Text } from '@status-im/components'
|
||||
import { DividerLine, Text } from '@status-im/components'
|
||||
import { XStack, YStack } from 'tamagui'
|
||||
|
||||
import { getFormattedValidatorAddress } from '../../../../utilities'
|
||||
import TransactionStatus from './TransactionStatus'
|
||||
import ValidatorProfile from '../../../../components/General/ValidatorProfile'
|
||||
|
||||
type ValidatorRequestProps = {
|
||||
number: number
|
||||
@ -17,23 +17,7 @@ const ValidatorRequest = ({ number, isTransactionConfirmation }: ValidatorReques
|
||||
<YStack space={'$3'} style={{ width: '100%' }}>
|
||||
<XStack style={{ justifyContent: 'space-between', width: '100%', alignItems: 'center' }}>
|
||||
<XStack style={{ justifyContent: 'space-between', width: '44%', alignItems: 'center' }}>
|
||||
<XStack space={'$2'}>
|
||||
<Avatar
|
||||
type="user"
|
||||
size={32}
|
||||
src="/icons/validator-request.svg"
|
||||
name={number.toString()}
|
||||
indicator="online"
|
||||
/>
|
||||
<YStack>
|
||||
<Text size={13} weight={'semibold'}>
|
||||
Validator {number}
|
||||
</Text>
|
||||
<Text size={13} color="#647084">
|
||||
{getFormattedValidatorAddress('zQ3asdf9d4Gs0')}
|
||||
</Text>
|
||||
</YStack>
|
||||
</XStack>
|
||||
<ValidatorProfile number={number} address={'zQ3asdf9d4Gs0'} />
|
||||
<Text size={13} color="#647084" weight={'semibold'}>
|
||||
Keys Generated
|
||||
</Text>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { XStack } from 'tamagui'
|
||||
|
||||
import KeyGenerationSyncCard from './KeyGenerationSyncCard'
|
||||
import SyncStatusCard from '../../../../components/General/SyncStatusCard'
|
||||
import KeyGenerationTitle from '../KeyGenerationTitle'
|
||||
|
||||
const KeyGenerationHeader = () => {
|
||||
@ -8,13 +8,13 @@ const KeyGenerationHeader = () => {
|
||||
<XStack style={{ width: '100%', justifyContent: 'space-between' }}>
|
||||
<KeyGenerationTitle />
|
||||
<XStack space={'$2'}>
|
||||
<KeyGenerationSyncCard
|
||||
<SyncStatusCard
|
||||
synced={123.524}
|
||||
total={172.503}
|
||||
title="Execution Sync Status"
|
||||
color="#2a4af5"
|
||||
/>
|
||||
<KeyGenerationSyncCard
|
||||
<SyncStatusCard
|
||||
synced={123.524}
|
||||
total={172.503}
|
||||
title="Consensus Sync Status"
|
||||
|
Loading…
x
Reference in New Issue
Block a user