Merge branch 'Create-Dashboard' of github.com:nimbus-gui/nimbus-gui into Create-Dashboard
|
@ -55,6 +55,8 @@ jobs:
|
|||
${{ runner.os }}-yarn-v3
|
||||
- name: Build
|
||||
run: yarn build
|
||||
- name: Check formatting
|
||||
run: yarn format:check
|
||||
- name: Pull Vercel configuration
|
||||
run: yarn vercel pull --yes --token ${{ secrets.vercel_token }}
|
||||
- name: Build Vercel bundle
|
||||
|
|
43
README.md
|
@ -1,27 +1,36 @@
|
|||
# nimbus-gui
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
A GUI for managing your [Nimbus](https://nimbus.team/) nodes.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
## Deployed pages showing the project
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
We have a Storybook up at https://nimbus-gui.github.io/nimbus-gui/ which shows
|
||||
the components of the project. We also have a deployed version of the GUI up at
|
||||
https://nimbus-gui.vercel.app/ which shows the GUI as it currently looks in the
|
||||
`main` branch of the
|
||||
[`nimbus-gui/nimbus-gui`](https://github.com/nimbus-gui/nimbus-gui) repository.
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
## Development and running the project yourself
|
||||
|
||||
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
||||
### Dependencies
|
||||
|
||||
- Configure the top-level `parserOptions` property like this:
|
||||
Run `yarn` in the root directory of the project in order to install dependencies.
|
||||
|
||||
```js
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
project: ['./tsconfig.json', './tsconfig.node.json'],
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
### Running a development server
|
||||
|
||||
If you want to run a development server to see what the GUI looks like you can
|
||||
run the following command:
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
|
||||
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
|
||||
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
|
||||
This will start the server on port 5173 and you can open https://localhost:5173
|
||||
in order to see the page.
|
||||
|
||||
### Running storybook locally
|
||||
|
||||
If you want to run the Storybook locally you can simply run `yarn storybook` in
|
||||
the root of the project. This is useful if you want to contribute a component
|
||||
and be sure that it renders as you expect it to, without testing it out on any
|
||||
given page.
|
||||
|
|
14
index.html
|
@ -5,6 +5,20 @@
|
|||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + React + TS</title>
|
||||
<link
|
||||
rel="preload"
|
||||
href="./Inter-font/Inter-Regular.ttf"
|
||||
as="font"
|
||||
type="font/ttf"
|
||||
crossOrigin=""
|
||||
/>
|
||||
<link
|
||||
rel="preload"
|
||||
href="./Inter-font/Inter-Bold.ttf"
|
||||
as="font"
|
||||
type="font/ttf"
|
||||
crossOrigin=""
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<script>window.global = window;</script>
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
"preview": "vite preview",
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"build-storybook": "storybook build",
|
||||
"test-storybook": "test-storybook"
|
||||
"test-storybook": "test-storybook",
|
||||
"format:check": "yarn prettier --check src",
|
||||
"format": "yarn prettier --write src"
|
||||
},
|
||||
"resolutions": {
|
||||
"@tamagui/web": "1.36.4",
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
<svg width="74" height="60" viewBox="0 0 74 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Frame 31443">
|
||||
<path id="Vector" d="M59.1019 45.0375V59.0747C51.3854 59.0747 47.4072 58.373 42.7293 52.0562C38.0514 45.7393 35.0293 45.0373 31.0346 45.0373V59.0747H17.001V45.0373H31.0346V31C38.2347 31 42.7293 31.9358 47.4072 38.0187C52.0851 44.1016 54.5517 45.0375 59.1019 45.0375V31H73.1355V45.0375H59.1019Z" fill="#DCE0E5"/>
|
||||
</g>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="74" height="60" viewBox="0 0 74 60" fill="none">
|
||||
<path d="M59.1019 45.0375V59.0747C51.3854 59.0747 47.4072 58.373 42.7293 52.0562C38.0514 45.7393 35.0293 45.0373 31.0346 45.0373V59.0747H17.001V45.0373H31.0346V31C38.2347 31 42.7293 31.9358 47.4072 38.0187C52.0851 44.1016 54.5517 45.0375 59.1019 45.0375V31H73.1355V45.0375H59.1019Z" fill="#DCE0E5"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 441 B After Width: | Height: | Size: 405 B |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 37 KiB |
|
@ -1,3 +1,3 @@
|
|||
#root {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import StandartLineChart from './StandardLineChart'
|
||||
import IconText from '../General/IconText'
|
||||
import { Paragraph, Separator, XStack, YStack } from 'tamagui'
|
||||
import { Separator, XStack, YStack } from 'tamagui'
|
||||
import { Shadow, Text } from '@status-im/components'
|
||||
import { CheckCircleIcon, IncorrectIcon } from '@status-im/icons'
|
||||
|
||||
|
@ -38,8 +38,8 @@ const DeviceCPULoad: React.FC<DeviceCPULoadProps> = ({ load }) => {
|
|||
<Shadow
|
||||
variant="$2"
|
||||
style={{
|
||||
width: '284px',
|
||||
height: '136px',
|
||||
width: '50%',
|
||||
minHeight: '135px',
|
||||
borderRadius: '16px',
|
||||
border: message === 'Poor' ? '1px solid #D92344' : 'none',
|
||||
backgroundColor: message === 'Poor' ? '#fefafa' : '#fff',
|
||||
|
@ -49,7 +49,7 @@ const DeviceCPULoad: React.FC<DeviceCPULoadProps> = ({ load }) => {
|
|||
<XStack
|
||||
justifyContent="space-between"
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
padding: '0.75rem 1rem',
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
|
@ -57,16 +57,16 @@ const DeviceCPULoad: React.FC<DeviceCPULoadProps> = ({ load }) => {
|
|||
<StandartLineChart data={chartData} />
|
||||
</div>
|
||||
<YStack space={'$3'}>
|
||||
<Paragraph color={'#09101C'} size={'$6'} fontWeight={'600'}>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
CPU
|
||||
</Paragraph>
|
||||
<Paragraph color={'#09101C'} size={'$8'} fontWeight={'700'}>
|
||||
</Text>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
{currentLoad} GB
|
||||
</Paragraph>
|
||||
</Text>
|
||||
</YStack>
|
||||
</XStack>
|
||||
<Separator borderColor={'#e3e3e3'} />
|
||||
<XStack space={'$4'} style={{ padding: '10px 16px 10px 16px' }}>
|
||||
<XStack space={'$4'} style={{ padding: '0.65rem 1rem' }}>
|
||||
<IconText
|
||||
icon={message === 'Good' ? <CheckCircleIcon size={16} /> : <IncorrectIcon size={16} />}
|
||||
weight={'semibold'}
|
||||
|
@ -74,7 +74,7 @@ const DeviceCPULoad: React.FC<DeviceCPULoadProps> = ({ load }) => {
|
|||
{message}
|
||||
</IconText>
|
||||
{message === 'Poor' && (
|
||||
<Text size={13} color="#E95460">
|
||||
<Text size={13} color={'#E95460'} weight={'semibold'}>
|
||||
{((currentLoad / 80) * 100).toFixed(0)}% Utilization
|
||||
</Text>
|
||||
)}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import StandartLineChart from './StandardLineChart'
|
||||
|
||||
import IconText from '../General/IconText'
|
||||
import { Paragraph, Separator, XStack, YStack } from 'tamagui'
|
||||
import { Separator, XStack, YStack } from 'tamagui'
|
||||
import { Shadow as ShadowBox, Text } from '@status-im/components'
|
||||
import { CheckCircleIcon, IncorrectIcon } from '@status-im/icons'
|
||||
|
||||
|
@ -42,8 +42,8 @@ const DeviceMemoryHealth = ({ currentMemory, maxMemory }: DeviceMemoryHealthProp
|
|||
<ShadowBox
|
||||
variant="$2"
|
||||
style={{
|
||||
width: '284px',
|
||||
height: '136px',
|
||||
width: '50%',
|
||||
minHeight: '135px',
|
||||
borderRadius: '16px',
|
||||
border: message === 'Poor' ? '1px solid #D92344' : 'none',
|
||||
backgroundColor: message === 'Poor' ? '#fefafa' : '#fff',
|
||||
|
@ -53,7 +53,7 @@ const DeviceMemoryHealth = ({ currentMemory, maxMemory }: DeviceMemoryHealthProp
|
|||
<XStack
|
||||
justifyContent="space-between"
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
padding: '0.75rem 1rem',
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
|
@ -61,23 +61,24 @@ const DeviceMemoryHealth = ({ currentMemory, maxMemory }: DeviceMemoryHealthProp
|
|||
<StandartLineChart data={chartData} />
|
||||
</div>
|
||||
<YStack space={'$3'}>
|
||||
<Paragraph color={'#09101C'} size={'$6'} fontWeight={'600'}>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
Memory
|
||||
</Paragraph>
|
||||
<Paragraph color={'#09101C'} size={'$8'} fontWeight={'700'}>
|
||||
</Text>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
{currentLoad} GB
|
||||
</Paragraph>
|
||||
</Text>
|
||||
</YStack>
|
||||
</XStack>
|
||||
<Separator borderColor={'#e3e3e3'} />
|
||||
<XStack space={'$4'} style={{ padding: '10px 16px 10px 16px' }}>
|
||||
<XStack space={'$4'} style={{ padding: '0.65rem 1rem' }}>
|
||||
<IconText
|
||||
icon={message === 'Good' ? <CheckCircleIcon size={16} /> : <IncorrectIcon size={16} />}
|
||||
weight={'semibold'}
|
||||
>
|
||||
{message}
|
||||
</IconText>
|
||||
{message === 'Poor' && (
|
||||
<Text size={13} color="#E95460">
|
||||
<Text size={13} color={'#E95460'} weight={'semibold'}>
|
||||
{((currentLoad / maxMemory || 0) * 100).toFixed(0)}% Utilization
|
||||
</Text>
|
||||
)}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import StandartLineChart from './StandardLineChart'
|
||||
import IconText from '../General/IconText'
|
||||
import { Paragraph, Separator, XStack, YStack } from 'tamagui'
|
||||
import { Separator, XStack, YStack } from 'tamagui'
|
||||
import { Shadow as ShadowBox, Text } from '@status-im/components'
|
||||
import { CheckCircleIcon, IncorrectIcon } from '@status-im/icons'
|
||||
|
||||
|
@ -47,8 +47,8 @@ const DeviceNetworkHealth = ({ uploadRate, downloadRate }: DeviceNetworkHealthPr
|
|||
<ShadowBox
|
||||
variant="$2"
|
||||
style={{
|
||||
width: '284px',
|
||||
height: '136px',
|
||||
width: '50%',
|
||||
minHeight: '135px',
|
||||
borderRadius: '16px',
|
||||
border: message === 'Poor' ? '1px solid #D92344' : 'none',
|
||||
backgroundColor: message === 'Poor' ? '#fefafa' : '#fff',
|
||||
|
@ -58,7 +58,7 @@ const DeviceNetworkHealth = ({ uploadRate, downloadRate }: DeviceNetworkHealthPr
|
|||
<XStack
|
||||
justifyContent="space-between"
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
padding: '0.75rem 1rem',
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
|
@ -66,23 +66,24 @@ const DeviceNetworkHealth = ({ uploadRate, downloadRate }: DeviceNetworkHealthPr
|
|||
<StandartLineChart data={chartData} />
|
||||
</div>
|
||||
<YStack space={'$3'}>
|
||||
<Paragraph color={'#09101C'} size={'$6'} fontWeight={'600'}>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
Network
|
||||
</Paragraph>
|
||||
<Paragraph color={'#09101C'} size={'$8'} fontWeight={'700'}>
|
||||
</Text>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
{currentLoad} GB
|
||||
</Paragraph>
|
||||
</Text>
|
||||
</YStack>
|
||||
</XStack>
|
||||
<Separator borderColor={'#e3e3e3'} />
|
||||
<XStack space={'$4'} style={{ padding: '10px 16px 10px 16px' }}>
|
||||
<XStack space={'$4'} style={{ padding: '0.65rem 1rem' }}>
|
||||
<IconText
|
||||
icon={message === 'Good' ? <CheckCircleIcon size={16} /> : <IncorrectIcon size={16} />}
|
||||
weight={'semibold'}
|
||||
>
|
||||
{message}
|
||||
</IconText>
|
||||
{message === 'Poor' && (
|
||||
<Text size={13} color="#E95460">
|
||||
<Text size={13} color={'#E95460'} weight={'semibold'}>
|
||||
{((currentLoad / 60) * 100).toFixed(0)}% Utilization
|
||||
</Text>
|
||||
)}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import IconText from '../General/IconText'
|
||||
import { Paragraph, Separator, XStack, YStack } from 'tamagui'
|
||||
import { Separator, XStack, YStack } from 'tamagui'
|
||||
import StandardGauge from './StandardGauge'
|
||||
import { Shadow, Text } from '@status-im/components'
|
||||
import { CheckCircleIcon, IncorrectIcon } from '@status-im/icons'
|
||||
|
@ -33,8 +33,8 @@ const DeviceStorageHealth: React.FC<DeviceStorageHealthProps> = ({ storage, maxS
|
|||
<Shadow
|
||||
variant="$2"
|
||||
style={{
|
||||
width: '284px',
|
||||
height: '136px',
|
||||
width: '50%',
|
||||
minHeight: '135px',
|
||||
borderRadius: '16px',
|
||||
border: message === 'Poor' ? '1px solid #D92344' : 'none',
|
||||
backgroundColor: message === 'Poor' ? '#fefafa' : '#fff',
|
||||
|
@ -44,31 +44,31 @@ const DeviceStorageHealth: React.FC<DeviceStorageHealthProps> = ({ storage, maxS
|
|||
<XStack
|
||||
justifyContent="space-between"
|
||||
style={{
|
||||
padding: '8px 16px',
|
||||
padding: '0.75rem 1rem',
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: '44px',
|
||||
width: '75px',
|
||||
height: '75px',
|
||||
right: '33px',
|
||||
width: '4.75rem',
|
||||
height: '4.75rem',
|
||||
}}
|
||||
>
|
||||
<StandardGauge data={data(free)} />
|
||||
</div>
|
||||
<YStack space={'$3'}>
|
||||
<Paragraph color={'#09101C'} size={'$6'} fontWeight={'600'}>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
Storage
|
||||
</Paragraph>
|
||||
<Paragraph color={'#09101C'} size={'$8'} fontWeight={'700'}>
|
||||
</Text>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
{storage} GB
|
||||
</Paragraph>
|
||||
</Text>
|
||||
</YStack>
|
||||
</XStack>
|
||||
<Separator borderColor={'#e3e3e3'} />
|
||||
<XStack space={'$4'} style={{ padding: '10px 16px 10px 16px' }}>
|
||||
<XStack space={'$4'} style={{ padding: '0.65rem 1rem' }}>
|
||||
<IconText
|
||||
icon={message === 'Good' ? <CheckCircleIcon size={16} /> : <IncorrectIcon size={16} />}
|
||||
weight={'semibold'}
|
||||
|
@ -76,7 +76,7 @@ const DeviceStorageHealth: React.FC<DeviceStorageHealthProps> = ({ storage, maxS
|
|||
{message}
|
||||
</IconText>
|
||||
{message === 'Poor' && (
|
||||
<Text size={13} color="#E95460">
|
||||
<Text size={13} color={'#E95460'} weight={'semibold'}>
|
||||
{utilization.toFixed(0)}% Utilization
|
||||
</Text>
|
||||
)}
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
.breadcrumb-bar-nav {
|
||||
width: 100%;
|
||||
flex: 1 1 100%;
|
||||
padding: 1rem 2rem;
|
||||
margin: 0.5rem;
|
||||
width: 100%;
|
||||
flex: 1 1 100%;
|
||||
padding: 1rem 2rem;
|
||||
margin: 0.5rem;
|
||||
}
|
||||
.breadcrumb-bar-ul {
|
||||
display: flex;
|
||||
display: flex;
|
||||
}
|
||||
.breadcrumb-bar-li {
|
||||
color: #647084;
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
color: #647084;
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
}
|
||||
.breadcrumb-bar-li:last-child {
|
||||
color: #09101C;
|
||||
.breadcrumb-bar-li:last-child {
|
||||
color: #09101c;
|
||||
}
|
||||
.breadcrumb-bar-li::after {
|
||||
display: inline-block;
|
||||
content: url("./icons/chevron.svg");
|
||||
color: #09101C;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 100%;
|
||||
transform: translateX(-50%);
|
||||
display: inline-block;
|
||||
content: url('./icons/chevron.svg');
|
||||
color: #09101c;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 100%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.breadcrumb-bar-li:last-child::after {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
.color-picker-button {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 10px;
|
||||
position: relative;
|
||||
outline: none;
|
||||
border: none;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 10px;
|
||||
position: relative;
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.color-picker-button::before ,
|
||||
.color-picker-button::after {
|
||||
display: block;
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
transform-origin: center;
|
||||
opacity: 0;
|
||||
transition: 120ms opacity ease-in-out;
|
||||
.color-picker-button::before,
|
||||
.color-picker-button::after {
|
||||
display: block;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transform-origin: center;
|
||||
opacity: 0;
|
||||
transition: 120ms opacity ease-in-out;
|
||||
}
|
||||
.color-picker-button::before {
|
||||
content: "\2713";
|
||||
font-size: 25px;
|
||||
color: white;
|
||||
content: '\2713';
|
||||
font-size: 25px;
|
||||
color: white;
|
||||
}
|
||||
.color-picker-button::after {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid currentColor;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid currentColor;
|
||||
}
|
||||
|
||||
.color-picker-button:focus::before,
|
||||
.color-picker-button:focus::after,
|
||||
.color-picker-button:focus::before,
|
||||
.color-picker-button:focus::after,
|
||||
.color-picker-button:hover::after {
|
||||
opacity: 1;
|
||||
opacity: 1;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.device-avatar {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: -30px;
|
||||
}
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: -30px;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useState } from 'react'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { XStack, YStack } from 'tamagui'
|
||||
import { Avatar, Text } from '@status-im/components'
|
||||
import { ReactionIcon } from '@status-im/icons'
|
||||
|
@ -6,15 +6,30 @@ import './CreateAvatar.css'
|
|||
import LabelInputField from '../LabelInputField'
|
||||
import ColorPicker from '../ColorPicker/ColorPicker'
|
||||
import EmojiPickerDialog from '../EmojiPickerDialog'
|
||||
import { Emoji, EmojiClickData } from 'emoji-picker-react'
|
||||
import { Emoji, EmojiClickData, EmojiStyle } from 'emoji-picker-react'
|
||||
|
||||
const CreateAvatar = () => {
|
||||
const [chosenColor, setChosenColor] = useState('#2A4AF5')
|
||||
const [isEmojiDialogOpen, setIsEmojiDialogOpen] = useState(false)
|
||||
const [selectedEmoji, setSelectedEmoji] = useState<string>('1f600')
|
||||
const emojiRef = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
function changeEmoji(emojiData: EmojiClickData) {
|
||||
setSelectedEmoji(emojiData.unified)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
function handleClickOutside(event: any) {
|
||||
if (emojiRef.current && !emojiRef.current.contains(event.target)) {
|
||||
setIsEmojiDialogOpen(false)
|
||||
}
|
||||
}
|
||||
document.addEventListener('mousedown', handleClickOutside)
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside)
|
||||
}
|
||||
}, [emojiRef])
|
||||
|
||||
return (
|
||||
<YStack my={16}>
|
||||
<XStack space>
|
||||
|
@ -27,7 +42,9 @@ const CreateAvatar = () => {
|
|||
</Text>
|
||||
<XStack my={10} alignItems={'end'}>
|
||||
<div className="device-avatar" style={{ background: chosenColor }}>
|
||||
{selectedEmoji ? <Emoji unified={selectedEmoji} size={30} /> : null}
|
||||
{selectedEmoji ? (
|
||||
<Emoji unified={selectedEmoji} emojiStyle={EmojiStyle.TWITTER} size={30} />
|
||||
) : null}
|
||||
</div>
|
||||
<Avatar
|
||||
type="icon"
|
||||
|
@ -40,9 +57,11 @@ const CreateAvatar = () => {
|
|||
/>
|
||||
}
|
||||
/>
|
||||
{isEmojiDialogOpen && (
|
||||
<EmojiPickerDialog changeEmoji={changeEmoji} emojiStyle="TWITTER" />
|
||||
)}
|
||||
<div ref={emojiRef}>
|
||||
{isEmojiDialogOpen && (
|
||||
<EmojiPickerDialog changeEmoji={changeEmoji} emojiStyle="TWITTER" />
|
||||
)}
|
||||
</div>
|
||||
</XStack>
|
||||
</YStack>
|
||||
<YStack flexWrap="wrap" width="80%">
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
import EmojiPickerDialog from './EmojiPickerDialog'
|
||||
|
||||
|
||||
const meta = {
|
||||
title: 'General/EmojiPickerDialog',
|
||||
component: EmojiPickerDialog,
|
||||
|
@ -15,5 +14,5 @@ export default meta
|
|||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const DefaultColors: Story = {
|
||||
args: {emojiStyle: 'TWITTER'},
|
||||
args: { emojiStyle: 'TWITTER' },
|
||||
}
|
||||
|
|
|
@ -16,13 +16,13 @@ type EmojiPickerProps = {
|
|||
|
||||
function EmojiPickerDialog({ emojiStyle, changeEmoji }: EmojiPickerProps) {
|
||||
return (
|
||||
<Stack position="absolute" zIndex={1} left={100}>
|
||||
<Stack position="absolute" zIndex={1} left={100} top={-150}>
|
||||
<EmojiPicker
|
||||
onEmojiClick={changeEmoji}
|
||||
autoFocusSearch={false}
|
||||
theme={Theme.AUTO}
|
||||
height={350}
|
||||
width={350}
|
||||
height={'50vh'}
|
||||
width={'50vw'}
|
||||
emojiVersion="1"
|
||||
lazyLoadEmojis={false}
|
||||
previewConfig={{ showPreview: false }}
|
||||
|
|
|
@ -8,7 +8,7 @@ type HeaderProps = {
|
|||
|
||||
const Header = ({ selectedTag }: HeaderProps) => {
|
||||
return (
|
||||
<XStack justifyContent="space-between" py={'25px'} mt={'70px'}>
|
||||
<XStack justifyContent="space-between" py={'25px'} mt={'4.4rem'}>
|
||||
<NimbusLogo />
|
||||
<TagContainer selectedTag={selectedTag} />
|
||||
</XStack>
|
||||
|
|
|
@ -17,7 +17,7 @@ const IconText = ({ icon, children, weight }: IconTextProps) => {
|
|||
space={'$2'}
|
||||
>
|
||||
{icon}
|
||||
<Text size={13} color={'#000000'} weight={weight}>
|
||||
<Text size={13} color={'#09101C'} weight={weight}>
|
||||
{children}
|
||||
</Text>
|
||||
</XStack>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.input-container {
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
margin-top: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
background-color: #fff;
|
||||
border-radius: 12px;
|
||||
margin-top: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,15 @@ const LinkWithArrow = ({
|
|||
onClick={navigateHandler}
|
||||
>
|
||||
{arrowLeft && <ArrowLeftIcon size={20} color="#2A4CF4" />}
|
||||
<Link style={{ color: textColor || '#2A4CF4', marginBottom: '2px' }} to={to}>
|
||||
<Link
|
||||
style={{
|
||||
color: textColor || '#2A4CF4',
|
||||
marginBottom: '2px',
|
||||
fontSize: 'inherit',
|
||||
fontWeight: 'inherit',
|
||||
}}
|
||||
to={to}
|
||||
>
|
||||
{text}
|
||||
</Link>
|
||||
{arrowRight && <ArrowRightIcon size={20} color="#2A4CF4" />}
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
.quick-start-bar {
|
||||
border-radius: 18px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.10);
|
||||
opacity: 0.949999988079071;
|
||||
background: rgba(255, 255, 255, 0.70);
|
||||
backdrop-filter: blur(15px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 66%;
|
||||
margin: 0 auto;
|
||||
padding: 12px 1rem;
|
||||
position: relative;
|
||||
top: -18vh;
|
||||
border-radius: 18px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
opacity: 0.949999988079071;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
backdrop-filter: blur(15px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 66%;
|
||||
margin: 0 auto;
|
||||
padding: 12px 1rem;
|
||||
position: relative;
|
||||
top: -18vh;
|
||||
}
|
||||
.quick-start-bar > div {
|
||||
width: 100%;
|
||||
border-radius: 24px;
|
||||
background: rgba(100, 112, 132, 0.05);
|
||||
margin-left: 1rem;
|
||||
padding: 1rem 0.5rem;
|
||||
width: 100%;
|
||||
border-radius: 24px;
|
||||
background: rgba(100, 112, 132, 0.05);
|
||||
margin-left: 1rem;
|
||||
padding: 1rem 0.5rem;
|
||||
}
|
||||
.quick-start-bar ul {
|
||||
display: flex;
|
||||
.quick-start-bar ul {
|
||||
display: flex;
|
||||
}
|
||||
.quick-start-bar ul li {
|
||||
color: #0D1625;
|
||||
font-size: 13px;
|
||||
color: #0d1625;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
/* .tag-container div:nth-child(1) {
|
||||
background:transparent;
|
||||
} */
|
||||
} */
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
|
||||
.nimbus-logomark{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.nimbus-logomark {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.nimbus-logomark svg {
|
||||
width: auto;
|
||||
height: 24px;
|
||||
}
|
||||
width: auto;
|
||||
height: 24px;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ type PageWrapperShadowProps = {
|
|||
rightImageSrc?: string
|
||||
rightImageLogo?: boolean
|
||||
children: ReactNode
|
||||
imgHeight?: string
|
||||
}
|
||||
|
||||
const PageWrapperShadow = ({
|
||||
|
@ -15,6 +16,7 @@ const PageWrapperShadow = ({
|
|||
rightImageSrc,
|
||||
rightImageLogo,
|
||||
children,
|
||||
imgHeight,
|
||||
}: PageWrapperShadowProps) => {
|
||||
const theme = useTheme()
|
||||
|
||||
|
@ -26,10 +28,15 @@ const PageWrapperShadow = ({
|
|||
<div className="container-inner">{children}</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section className="layout-right">
|
||||
<div className="image-container">
|
||||
<img src={rightImageSrc} alt="background" className="background-img" />
|
||||
<img
|
||||
src={rightImageSrc}
|
||||
alt="background"
|
||||
className="background-img"
|
||||
style={{ height: imgHeight }}
|
||||
/>
|
||||
{rightImageLogo ? <NimbusLogoMark /> : null}
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -1,85 +1,85 @@
|
|||
.layout{
|
||||
background-color: #FFF;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
overflow: hidden;
|
||||
.layout {
|
||||
background-color: #fff;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
.layout::after {
|
||||
display: block;
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(to bottom, rgba(113, 64, 253, 0.075) 15%, rgba(255,255,255,0) 50%);
|
||||
display: block;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(to bottom, rgba(113, 64, 253, 0.075) 15%, rgba(255, 255, 255, 0) 50%);
|
||||
}
|
||||
.layout-left {
|
||||
flex: 0 0 55%;
|
||||
max-width: 55%;
|
||||
z-index: 2;
|
||||
flex: 0 0 55%;
|
||||
max-width: 55%;
|
||||
z-index: 2;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: end;
|
||||
height: 100%;
|
||||
/* padding: 70px 0 0; */
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: end;
|
||||
height: 100%;
|
||||
/* padding: 70px 0 0; */
|
||||
}
|
||||
.container-inner {
|
||||
max-width: 70%;
|
||||
flex: 1 0 70%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 70%;
|
||||
flex: 1 0 70%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.content {
|
||||
flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
/* LAYOUT RIGHT ELEMENT WITH IMAGE TAKING UP THE WHOLE HIGHT OF THE VIEWPORT */
|
||||
.layout-right {
|
||||
flex: 0 0 45%;
|
||||
max-width: 45%;
|
||||
z-index: 0;
|
||||
flex: 0 0 45%;
|
||||
max-width: 45%;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.image-container {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
color: #FFF;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
color: #fff;
|
||||
}
|
||||
.image-container::before {
|
||||
display: block;
|
||||
content: "";
|
||||
padding-bottom: 100%;
|
||||
display: block;
|
||||
content: '';
|
||||
padding-bottom: 100%;
|
||||
}
|
||||
.image-container::after {
|
||||
display: block;
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -1%;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
background: linear-gradient(to right, rgba(255, 255, 255, 1) 20%, rgba(255, 255, 255, 0.0));
|
||||
display: block;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -1%;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
background: linear-gradient(to right, rgba(255, 255, 255, 1) 20%, rgba(255, 255, 255, 0));
|
||||
}
|
||||
.image-container .background-img {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
height: 140%;
|
||||
width: auto;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
height: 140%;
|
||||
width: auto;
|
||||
}
|
||||
.image-container .nimbus-logomark {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.image-container .nimbus-logomark svg {
|
||||
height: 73px;
|
||||
height: 73px;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,55 @@
|
|||
@font-face {
|
||||
font-family: 'Inter';
|
||||
src: url('./Inter-font/Inter-Light.ttf') format('truetype');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
src: url('./Inter-font/Inter-Regular.ttf') format('truetype');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
src: url('./Inter-font/Inter-Medium.ttf') format('truetype');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
src: url('./Inter-font/Inter-SemiBold.ttf') format('truetype');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
src: url('./Inter-font/Inter-Bold.ttf') format('truetype');
|
||||
font-weight: 800;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
src: url('./Inter-font/Inter-Black.ttf') format('truetype');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
:root {
|
||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
|
@ -22,7 +65,12 @@ body {
|
|||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.2;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
@ -44,7 +92,7 @@ button:focus,
|
|||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
ul{
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
@ -55,7 +103,7 @@ ul li {
|
|||
}
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #09101C;
|
||||
color: #09101c;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
|
|
|
@ -38,7 +38,6 @@ const BalanceChartCard = () => {
|
|||
|
||||
return (
|
||||
<DashboardCardWrapper>
|
||||
|
||||
<YStack space={'$4'} style={{ width: '536px' }}>
|
||||
<XStack justifyContent={'space-between'}>
|
||||
<YStack>
|
||||
|
@ -90,11 +89,10 @@ const BalanceChartCard = () => {
|
|||
onSelect={handleRangeSelect}
|
||||
/>
|
||||
)}
|
||||
<Stack >
|
||||
<Stack>
|
||||
<LineChart years={filteredYears} userGains={filteredUserGains} />
|
||||
</Stack>
|
||||
</YStack>
|
||||
|
||||
</DashboardCardWrapper>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -31,9 +31,7 @@ const LineChart = ({ years, userGains }: LineChartProps) => {
|
|||
],
|
||||
options: {
|
||||
responsive: true,
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
return <Line options={data.options} data={data} />
|
||||
|
|
|
@ -1,354 +1,354 @@
|
|||
.rdp {
|
||||
--rdp-cell-size: 32px;
|
||||
--rdp-caption-font-size: 15px;
|
||||
--rdp-accent-color: #2a4af5;
|
||||
--rdp-background-color: #e7edff;
|
||||
--rdp-background-color-selected-secondary: #f5f6f8;
|
||||
--rdp-hover-color: #f5f6f8;
|
||||
--rdp-hover-color-darker: #f0f2f5;
|
||||
--rdp-accent-color-dark: #223bc4;
|
||||
--rdp-outline: 2px solid var(--rdp-accent-color); /* Outline border for focused elements */
|
||||
--rdp-outline-selected: 3px solid var(--rdp-accent-color); /* Outline border for focused _and_ selected elements */
|
||||
--rdp-text-color: #09101c;
|
||||
color: var(--rdp-text-color);
|
||||
font-family: Inter, sans-serif;
|
||||
font-weight: 500;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* Hide elements for devices that are not screen readers */
|
||||
.rdp-vhidden {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
position: absolute !important;
|
||||
top: 0;
|
||||
width: 1px !important;
|
||||
height: 1px !important;
|
||||
padding: 0 !important;
|
||||
overflow: hidden !important;
|
||||
clip: rect(1px, 1px, 1px, 1px) !important;
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.rdp-button_reset {
|
||||
appearance: none;
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
cursor: default;
|
||||
color: inherit;
|
||||
background: none;
|
||||
font: inherit;
|
||||
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.rdp-button_reset:focus-visible {
|
||||
/* Make sure to reset outline only when :focus-visible is supported */
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.rdp-button {
|
||||
border: 2px solid transparent;
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.rdp-button[disabled]:not(.rdp-day_selected) {
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.rdp-button:not([disabled]) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.rdp-button:focus-visible:not([disabled]) {
|
||||
color: inherit;
|
||||
background-color: var(--rdp-background-color);
|
||||
border: var(--rdp-outline);
|
||||
}
|
||||
|
||||
.rdp-button:hover:not([disabled]):not(.rdp-day_selected) {
|
||||
background-color: var(--rdp-hover-color);
|
||||
}
|
||||
|
||||
.rdp-months {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.rdp-month {
|
||||
margin: 0 1em;
|
||||
}
|
||||
|
||||
.rdp-month:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.rdp-month:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.rdp-table {
|
||||
margin: 0;
|
||||
max-width: calc(var(--rdp-cell-size) * 7);
|
||||
border-collapse: separate;
|
||||
border-spacing: 0 2px;
|
||||
padding: 0 0.75rem 0.625rem 0.75rem;
|
||||
}
|
||||
|
||||
.rdp-with_weeknumber .rdp-table {
|
||||
max-width: calc(var(--rdp-cell-size) * 8);
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.rdp-caption {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.rdp-multiple_months .rdp-caption {
|
||||
position: relative;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.rdp-caption_dropdowns {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.rdp-caption_label {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
color: currentColor;
|
||||
font-family: inherit;
|
||||
font-size: var(--rdp-caption-font-size);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.rdp-nav {
|
||||
white-space: nowrap;
|
||||
padding: 0.375rem 0.375rem 0 0.75rem;
|
||||
}
|
||||
|
||||
.rdp-multiple_months .rdp-caption_start .rdp-nav {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.rdp-multiple_months .rdp-caption_end .rdp-nav {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.rdp-nav_button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
padding: 0.25em;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
/* ---------- */
|
||||
/* Dropdowns */
|
||||
/* ---------- */
|
||||
|
||||
.rdp-dropdown_year,
|
||||
.rdp-dropdown_month {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.rdp-dropdown {
|
||||
appearance: none;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
cursor: inherit;
|
||||
opacity: 0;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.rdp-dropdown[disabled] {
|
||||
opacity: unset;
|
||||
color: unset;
|
||||
}
|
||||
|
||||
.rdp-dropdown:focus-visible:not([disabled]) + .rdp-caption_label {
|
||||
background-color: var(--rdp-background-color);
|
||||
border: var(--rdp-outline);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.rdp-dropdown_icon {
|
||||
margin: 0 0 0 5px;
|
||||
}
|
||||
|
||||
.rdp-head {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.rdp-head_row,
|
||||
.rdp-row {
|
||||
height: 100%;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.rdp-head_cell {
|
||||
vertical-align: middle;
|
||||
font-size: 0.8125em;
|
||||
font-weight: 500;
|
||||
|
||||
text-align: center;
|
||||
height: var(--rdp-cell-size);
|
||||
padding: 0;
|
||||
|
||||
line-height: 140%;
|
||||
color: #647084;
|
||||
letter-spacing: -0.003em;
|
||||
}
|
||||
|
||||
.rdp-tbody {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.rdp-tfoot {
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
.rdp-cell {
|
||||
width: var(--rdp-cell-size);
|
||||
height: var(--rdp-cell-size);
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.rdp-cell_selected_start {
|
||||
border-top-left-radius: 10px;
|
||||
border-bottom-left-radius: 10px;
|
||||
background-color: var(--rdp-background-color-selected-secondary);
|
||||
}
|
||||
|
||||
.rdp-cell_selected_end {
|
||||
border-top-right-radius: 10px;
|
||||
border-bottom-right-radius: 10px;
|
||||
background-color: var(--rdp-background-color-selected-secondary);
|
||||
}
|
||||
|
||||
.rdp-cell_selected_range {
|
||||
background-color: var(--rdp-background-color-selected-secondary);
|
||||
}
|
||||
|
||||
.rdp-weeknumber {
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
.rdp-weeknumber,
|
||||
.rdp-day {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
width: var(--rdp-cell-size);
|
||||
max-width: var(--rdp-cell-size);
|
||||
height: var(--rdp-cell-size);
|
||||
margin: 0;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.rdp-day_today:not(.rdp-day_outside) {
|
||||
position: relative;
|
||||
}
|
||||
.rdp-day_today:not(.rdp-day_outside)::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 3px;
|
||||
left: 50%;
|
||||
width: 4px;
|
||||
height: 2px;
|
||||
transform: translateX(-50%);
|
||||
|
||||
border-radius: 10px;
|
||||
background-color: var(--rdp-accent-color);
|
||||
}
|
||||
|
||||
.rdp-day_selected {
|
||||
opacity: 1;
|
||||
background-color: var(--rdp-accent-color);
|
||||
color: var(--rdp-background-color);
|
||||
transition: all 150ms ease-in-out;
|
||||
}
|
||||
|
||||
.rdp-day_selected:focus-visible,
|
||||
.rdp-day_selected:hover {
|
||||
opacity: 1;
|
||||
background-color: var(--rdp-accent-color-dark);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.rdp-day_outside {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.rdp-day_selected:focus-visible {
|
||||
/* Since the background is the same use again the outline */
|
||||
outline: var(--rdp-outline);
|
||||
outline-offset: 2px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.rdp[dir='rtl'] .rdp-day_range_start:not(.rdp-day_range_end) {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.rdp[dir='rtl'] .rdp-day_range_end:not(.rdp-day_range_start) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.rdp-day_range_end.rdp-day_range_start {
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.rdp-day_range_middle {
|
||||
color: var(--rdp-text-color);
|
||||
background-color: var(--rdp-background-color-selected-secondary);
|
||||
}
|
||||
|
||||
.rdp-day_range_middle:hover {
|
||||
color: var(--rdp-text-color);
|
||||
background-color: var(--rdp-hover-color-darker);
|
||||
}
|
||||
--rdp-cell-size: 32px;
|
||||
--rdp-caption-font-size: 15px;
|
||||
--rdp-accent-color: #2a4af5;
|
||||
--rdp-background-color: #e7edff;
|
||||
--rdp-background-color-selected-secondary: #f5f6f8;
|
||||
--rdp-hover-color: #f5f6f8;
|
||||
--rdp-hover-color-darker: #f0f2f5;
|
||||
--rdp-accent-color-dark: #223bc4;
|
||||
--rdp-outline: 2px solid var(--rdp-accent-color); /* Outline border for focused elements */
|
||||
--rdp-outline-selected: 3px solid var(--rdp-accent-color); /* Outline border for focused _and_ selected elements */
|
||||
--rdp-text-color: #09101c;
|
||||
color: var(--rdp-text-color);
|
||||
font-family: Inter, sans-serif;
|
||||
font-weight: 500;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* Hide elements for devices that are not screen readers */
|
||||
.rdp-vhidden {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
position: absolute !important;
|
||||
top: 0;
|
||||
width: 1px !important;
|
||||
height: 1px !important;
|
||||
padding: 0 !important;
|
||||
overflow: hidden !important;
|
||||
clip: rect(1px, 1px, 1px, 1px) !important;
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.rdp-button_reset {
|
||||
appearance: none;
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
cursor: default;
|
||||
color: inherit;
|
||||
background: none;
|
||||
font: inherit;
|
||||
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.rdp-button_reset:focus-visible {
|
||||
/* Make sure to reset outline only when :focus-visible is supported */
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.rdp-button {
|
||||
border: 2px solid transparent;
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.rdp-button[disabled]:not(.rdp-day_selected) {
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.rdp-button:not([disabled]) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.rdp-button:focus-visible:not([disabled]) {
|
||||
color: inherit;
|
||||
background-color: var(--rdp-background-color);
|
||||
border: var(--rdp-outline);
|
||||
}
|
||||
|
||||
.rdp-button:hover:not([disabled]):not(.rdp-day_selected) {
|
||||
background-color: var(--rdp-hover-color);
|
||||
}
|
||||
|
||||
.rdp-months {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.rdp-month {
|
||||
margin: 0 1em;
|
||||
}
|
||||
|
||||
.rdp-month:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.rdp-month:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.rdp-table {
|
||||
margin: 0;
|
||||
max-width: calc(var(--rdp-cell-size) * 7);
|
||||
border-collapse: separate;
|
||||
border-spacing: 0 2px;
|
||||
padding: 0 0.75rem 0.625rem 0.75rem;
|
||||
}
|
||||
|
||||
.rdp-with_weeknumber .rdp-table {
|
||||
max-width: calc(var(--rdp-cell-size) * 8);
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.rdp-caption {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.rdp-multiple_months .rdp-caption {
|
||||
position: relative;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.rdp-caption_dropdowns {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.rdp-caption_label {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
color: currentColor;
|
||||
font-family: inherit;
|
||||
font-size: var(--rdp-caption-font-size);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.rdp-nav {
|
||||
white-space: nowrap;
|
||||
padding: 0.375rem 0.375rem 0 0.75rem;
|
||||
}
|
||||
|
||||
.rdp-multiple_months .rdp-caption_start .rdp-nav {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.rdp-multiple_months .rdp-caption_end .rdp-nav {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.rdp-nav_button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
padding: 0.25em;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
/* ---------- */
|
||||
/* Dropdowns */
|
||||
/* ---------- */
|
||||
|
||||
.rdp-dropdown_year,
|
||||
.rdp-dropdown_month {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.rdp-dropdown {
|
||||
appearance: none;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
cursor: inherit;
|
||||
opacity: 0;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.rdp-dropdown[disabled] {
|
||||
opacity: unset;
|
||||
color: unset;
|
||||
}
|
||||
|
||||
.rdp-dropdown:focus-visible:not([disabled]) + .rdp-caption_label {
|
||||
background-color: var(--rdp-background-color);
|
||||
border: var(--rdp-outline);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.rdp-dropdown_icon {
|
||||
margin: 0 0 0 5px;
|
||||
}
|
||||
|
||||
.rdp-head {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.rdp-head_row,
|
||||
.rdp-row {
|
||||
height: 100%;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.rdp-head_cell {
|
||||
vertical-align: middle;
|
||||
font-size: 0.8125em;
|
||||
font-weight: 500;
|
||||
|
||||
text-align: center;
|
||||
height: var(--rdp-cell-size);
|
||||
padding: 0;
|
||||
|
||||
line-height: 140%;
|
||||
color: #647084;
|
||||
letter-spacing: -0.003em;
|
||||
}
|
||||
|
||||
.rdp-tbody {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.rdp-tfoot {
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
.rdp-cell {
|
||||
width: var(--rdp-cell-size);
|
||||
height: var(--rdp-cell-size);
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.rdp-cell_selected_start {
|
||||
border-top-left-radius: 10px;
|
||||
border-bottom-left-radius: 10px;
|
||||
background-color: var(--rdp-background-color-selected-secondary);
|
||||
}
|
||||
|
||||
.rdp-cell_selected_end {
|
||||
border-top-right-radius: 10px;
|
||||
border-bottom-right-radius: 10px;
|
||||
background-color: var(--rdp-background-color-selected-secondary);
|
||||
}
|
||||
|
||||
.rdp-cell_selected_range {
|
||||
background-color: var(--rdp-background-color-selected-secondary);
|
||||
}
|
||||
|
||||
.rdp-weeknumber {
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
.rdp-weeknumber,
|
||||
.rdp-day {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
width: var(--rdp-cell-size);
|
||||
max-width: var(--rdp-cell-size);
|
||||
height: var(--rdp-cell-size);
|
||||
margin: 0;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.rdp-day_today:not(.rdp-day_outside) {
|
||||
position: relative;
|
||||
}
|
||||
.rdp-day_today:not(.rdp-day_outside)::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 3px;
|
||||
left: 50%;
|
||||
width: 4px;
|
||||
height: 2px;
|
||||
transform: translateX(-50%);
|
||||
|
||||
border-radius: 10px;
|
||||
background-color: var(--rdp-accent-color);
|
||||
}
|
||||
|
||||
.rdp-day_selected {
|
||||
opacity: 1;
|
||||
background-color: var(--rdp-accent-color);
|
||||
color: var(--rdp-background-color);
|
||||
transition: all 150ms ease-in-out;
|
||||
}
|
||||
|
||||
.rdp-day_selected:focus-visible,
|
||||
.rdp-day_selected:hover {
|
||||
opacity: 1;
|
||||
background-color: var(--rdp-accent-color-dark);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.rdp-day_outside {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.rdp-day_selected:focus-visible {
|
||||
/* Since the background is the same use again the outline */
|
||||
outline: var(--rdp-outline);
|
||||
outline-offset: 2px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.rdp[dir='rtl'] .rdp-day_range_start:not(.rdp-day_range_end) {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.rdp[dir='rtl'] .rdp-day_range_end:not(.rdp-day_range_start) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.rdp-day_range_end.rdp-day_range_start {
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.rdp-day_range_middle {
|
||||
color: var(--rdp-text-color);
|
||||
background-color: var(--rdp-background-color-selected-secondary);
|
||||
}
|
||||
|
||||
.rdp-day_range_middle:hover {
|
||||
color: var(--rdp-text-color);
|
||||
background-color: var(--rdp-hover-color-darker);
|
||||
}
|
||||
|
|
|
@ -18,5 +18,5 @@ export const Default: Story = {
|
|||
args: { load: [32, 12, 45, 10] },
|
||||
}
|
||||
export const BadStats: Story = {
|
||||
args:{load:[12,32,14,35,65,90]}
|
||||
}
|
||||
args: { load: [12, 32, 14, 35, 65, 90] },
|
||||
}
|
||||
|
|
|
@ -39,15 +39,16 @@ const CPUCard = ({ load }: CPUCardProps) => {
|
|||
const message = currentLoad < 80 ? 'Good' : 'Poor'
|
||||
|
||||
return (
|
||||
<DashboardCardWrapper padding='0'>
|
||||
<YStack style={{
|
||||
width: '284px',
|
||||
height: '136px',
|
||||
borderRadius: '16px',
|
||||
border: message === 'Poor' ? '1px solid #D92344' : 'none',
|
||||
backgroundColor: message === 'Poor' ? '#fefafa' : '#fff',
|
||||
|
||||
}}>
|
||||
<DashboardCardWrapper padding="0">
|
||||
<YStack
|
||||
style={{
|
||||
width: '284px',
|
||||
height: '136px',
|
||||
borderRadius: '16px',
|
||||
border: message === 'Poor' ? '1px solid #D92344' : 'none',
|
||||
backgroundColor: message === 'Poor' ? '#fefafa' : '#fff',
|
||||
}}
|
||||
>
|
||||
<XStack
|
||||
justifyContent="space-between"
|
||||
style={{
|
||||
|
|
|
@ -3,17 +3,17 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||
import DeviceUptime from './DeviceUptime'
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/DeviceUptime',
|
||||
component: DeviceUptime,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
title: 'Dashboard/DeviceUptime',
|
||||
component: DeviceUptime,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof DeviceUptime>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
args: {},
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import { IconButton } from '@status-im/components'
|
||||
import { Stack } from 'tamagui'
|
||||
|
||||
type IconButtonWithDotProps = {
|
||||
iconEl: any
|
||||
variant: 'ghost' | 'outline'
|
||||
isDotOn: boolean
|
||||
selected?: boolean
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const IconButtonWithDot = ({
|
||||
iconEl,
|
||||
variant,
|
||||
isDotOn,
|
||||
selected,
|
||||
disabled,
|
||||
}: IconButtonWithDotProps) => {
|
||||
return (
|
||||
<Stack style={{ position: 'relative', display: 'inline-block' }}>
|
||||
<IconButton icon={iconEl} variant={variant} selected={selected} disabled={disabled} />
|
||||
{isDotOn && (
|
||||
<Stack
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: 7,
|
||||
top: 5,
|
||||
width: '9px',
|
||||
height: '9px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: '#1992D7',
|
||||
border: '1.5px solid #fff',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
export default IconButtonWithDot
|
|
@ -0,0 +1,19 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import LeftSidebar from './LeftSidebar'
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/LeftSidebar',
|
||||
component: LeftSidebar,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof LeftSidebar>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
import { IconButton } from '@status-im/components'
|
||||
import {
|
||||
DashboardIcon,
|
||||
SpeedIcon,
|
||||
|
@ -10,8 +9,12 @@ import {
|
|||
SettingsIcon,
|
||||
} from '@status-im/icons'
|
||||
import { YStack } from 'tamagui'
|
||||
import IconButtonWithDot from './IconButtonWithDot'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
|
||||
const LeftSidebar = () => {
|
||||
const buttons = useSelector((state: any) => state.leftSidebar.buttons)
|
||||
console.log(buttons)
|
||||
return (
|
||||
<YStack
|
||||
space={'$4'}
|
||||
|
@ -24,14 +27,24 @@ const LeftSidebar = () => {
|
|||
border: '1px solid #F0F2F5',
|
||||
}}
|
||||
>
|
||||
<IconButton icon={<DashboardIcon size={20} />} variant="ghost" selected />
|
||||
<IconButton icon={<SpeedIcon size={20} />} variant="ghost" />
|
||||
<IconButton icon={<ChartIcon size={20} />} variant="outline" disabled />
|
||||
<IconButton icon={<HeartIcon size={20} />} variant="ghost" />
|
||||
<IconButton icon={<CodeBlockIcon size={20} />} variant="ghost" />
|
||||
<IconButton icon={<CommunitiesIcon size={20} />} variant="ghost" />
|
||||
<IconButton icon={<ActivityCenterIcon size={20} />} variant="ghost" />
|
||||
<IconButton icon={<SettingsIcon size={20} />} variant="ghost" />
|
||||
<IconButtonWithDot
|
||||
iconEl={<DashboardIcon size={20} />}
|
||||
variant="ghost"
|
||||
isDotOn={false}
|
||||
selected={true}
|
||||
/>
|
||||
<IconButtonWithDot iconEl={<SpeedIcon size={20} />} variant="ghost" isDotOn={false} />
|
||||
<IconButtonWithDot
|
||||
iconEl={<ChartIcon size={20} />}
|
||||
variant="outline"
|
||||
isDotOn={false}
|
||||
disabled={true}
|
||||
/>
|
||||
<IconButtonWithDot iconEl={<HeartIcon size={20} />} variant="ghost" isDotOn={false} />
|
||||
<IconButtonWithDot iconEl={<CodeBlockIcon size={20} />} variant="ghost" isDotOn={false} />
|
||||
<IconButtonWithDot iconEl={<CommunitiesIcon size={20} />} variant="ghost" isDotOn={false} />
|
||||
<IconButtonWithDot iconEl={<ActivityCenterIcon size={20} />} variant="ghost" isDotOn={true} />
|
||||
<IconButtonWithDot iconEl={<SettingsIcon size={20} />} variant="ghost" isDotOn={false} />
|
||||
</YStack>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,20 +3,20 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||
import MemoryCard from './MemoryCard'
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/MemoryCard',
|
||||
component: MemoryCard,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
title: 'Dashboard/MemoryCard',
|
||||
component: MemoryCard,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof MemoryCard>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: { currentMemory: [12, 24, 12, 4, 30, 50], maxMemory: 100 },
|
||||
args: { currentMemory: [12, 24, 12, 4, 30, 50], maxMemory: 100 },
|
||||
}
|
||||
export const BadStats: Story = {
|
||||
args: { maxMemory: 60, currentMemory: [2, 5, 7, 32, 23, 12, 89] }
|
||||
}
|
||||
args: { maxMemory: 60, currentMemory: [2, 5, 7, 32, 23, 12, 89] },
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Paragraph, Separator, Stack, XStack, YStack } from 'tamagui'
|
||||
import { Text } from '@status-im/components'
|
||||
import { Text } from '@status-im/components'
|
||||
import { CheckCircleIcon, IncorrectIcon } from '@status-im/icons'
|
||||
|
||||
import StandartLineChart from '../../../components/Charts/StandardLineChart'
|
||||
|
@ -24,7 +24,6 @@ type MemoryCardProps = {
|
|||
}
|
||||
|
||||
const MemoryCard = ({ currentMemory, maxMemory }: MemoryCardProps) => {
|
||||
|
||||
const chartData: ChartData[] = [
|
||||
{
|
||||
id: 'cpu',
|
||||
|
@ -42,14 +41,16 @@ const MemoryCard = ({ currentMemory, maxMemory }: MemoryCardProps) => {
|
|||
const message = currentLoad < maxMemory ? 'Good' : 'Poor'
|
||||
|
||||
return (
|
||||
<DashboardCardWrapper padding='0'>
|
||||
<YStack style={{
|
||||
width: '284px',
|
||||
height: '136px',
|
||||
borderRadius: '16px',
|
||||
border: message === 'Poor' ? '1px solid #D92344' : 'none',
|
||||
backgroundColor: message === 'Poor' ? '#fefafa' : '#fff',
|
||||
}}>
|
||||
<DashboardCardWrapper padding="0">
|
||||
<YStack
|
||||
style={{
|
||||
width: '284px',
|
||||
height: '136px',
|
||||
borderRadius: '16px',
|
||||
border: message === 'Poor' ? '1px solid #D92344' : 'none',
|
||||
backgroundColor: message === 'Poor' ? '#fefafa' : '#fff',
|
||||
}}
|
||||
>
|
||||
<XStack
|
||||
justifyContent="space-between"
|
||||
style={{
|
||||
|
@ -71,7 +72,7 @@ const MemoryCard = ({ currentMemory, maxMemory }: MemoryCardProps) => {
|
|||
</XStack>
|
||||
|
||||
<Separator borderColor={'#e3e3e3'} />
|
||||
|
||||
|
||||
<XStack space={'$4'} style={{ padding: '10px 16px 10px 16px' }}>
|
||||
<IconText
|
||||
icon={message === 'Good' ? <CheckCircleIcon size={16} /> : <IncorrectIcon size={16} />}
|
||||
|
@ -85,7 +86,7 @@ const MemoryCard = ({ currentMemory, maxMemory }: MemoryCardProps) => {
|
|||
)}
|
||||
</XStack>
|
||||
</YStack>
|
||||
</DashboardCardWrapper >
|
||||
</DashboardCardWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,20 +3,20 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||
import NetworkCard from './NetworkCard'
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/NetworkCard',
|
||||
component: NetworkCard,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
title: 'Dashboard/NetworkCard',
|
||||
component: NetworkCard,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof NetworkCard>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {downloadRate:[12,24,12,4,30,50], uploadRate:[2,5,7,32,23,82] },
|
||||
args: { downloadRate: [12, 24, 12, 4, 30, 50], uploadRate: [2, 5, 7, 32, 23, 82] },
|
||||
}
|
||||
export const BadStats: Story = {
|
||||
args: { downloadRate:[12,24,12,4,30, 1], uploadRate:[2,5,7,32,23,12] }
|
||||
}
|
||||
args: { downloadRate: [12, 24, 12, 4, 30, 1], uploadRate: [2, 5, 7, 32, 23, 12] },
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Paragraph, Separator, Stack, XStack, YStack } from 'tamagui'
|
||||
import { Text } from '@status-im/components'
|
||||
import { Text } from '@status-im/components'
|
||||
import { CheckCircleIcon, IncorrectIcon } from '@status-im/icons'
|
||||
|
||||
import StandartLineChart from '../../../components/Charts/StandardLineChart'
|
||||
|
@ -23,7 +23,6 @@ type NetworkCardProps = {
|
|||
}
|
||||
|
||||
const NetworkCard = ({ uploadRate, downloadRate }: NetworkCardProps) => {
|
||||
|
||||
const chartData: ChartData[] = [
|
||||
{
|
||||
id: 'uploadRate',
|
||||
|
@ -49,16 +48,16 @@ const NetworkCard = ({ uploadRate, downloadRate }: NetworkCardProps) => {
|
|||
const message = currentLoad > 60 ? 'Good' : 'Poor'
|
||||
|
||||
return (
|
||||
<DashboardCardWrapper padding='0'>
|
||||
|
||||
|
||||
<YStack style={{
|
||||
width: '284px',
|
||||
height: '136px',
|
||||
borderRadius: '16px',
|
||||
border: message === 'Poor' ? '1px solid #D92344' : 'none',
|
||||
backgroundColor: message === 'Poor' ? '#fefafa' : '#fff',
|
||||
}}>
|
||||
<DashboardCardWrapper padding="0">
|
||||
<YStack
|
||||
style={{
|
||||
width: '284px',
|
||||
height: '136px',
|
||||
borderRadius: '16px',
|
||||
border: message === 'Poor' ? '1px solid #D92344' : 'none',
|
||||
backgroundColor: message === 'Poor' ? '#fefafa' : '#fff',
|
||||
}}
|
||||
>
|
||||
<XStack
|
||||
justifyContent="space-between"
|
||||
style={{
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import RightSidebar from './RightSidebar'
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/RightSidebar',
|
||||
component: RightSidebar,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof RightSidebar>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
}
|
|
@ -3,20 +3,20 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||
import StorageCard from './StorageCard'
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/StorageCard',
|
||||
component: StorageCard,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
title: 'Dashboard/StorageCard',
|
||||
component: StorageCard,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof StorageCard>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: { storage: 45, maxStorage: 100 },
|
||||
args: { storage: 45, maxStorage: 100 },
|
||||
}
|
||||
export const BadStats: Story = {
|
||||
args: { storage: 110, maxStorage: 100 }
|
||||
}
|
||||
args: { storage: 110, maxStorage: 100 },
|
||||
}
|
||||
|
|
|
@ -35,14 +35,16 @@ const StorageCard = ({ storage, maxStorage }: StorageCardProps) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<DashboardCardWrapper padding="0" >
|
||||
<YStack style={{
|
||||
width: '284px',
|
||||
height: '136px',
|
||||
borderRadius: '16px',
|
||||
border: message === 'Poor' ? '1px solid #D92344' : 'none',
|
||||
backgroundColor: message === 'Poor' ? '#fefafa' : '#fff',
|
||||
}}>
|
||||
<DashboardCardWrapper padding="0">
|
||||
<YStack
|
||||
style={{
|
||||
width: '284px',
|
||||
height: '136px',
|
||||
borderRadius: '16px',
|
||||
border: message === 'Poor' ? '1px solid #D92344' : 'none',
|
||||
backgroundColor: message === 'Poor' ? '#fefafa' : '#fff',
|
||||
}}
|
||||
>
|
||||
<XStack
|
||||
justifyContent="space-between"
|
||||
style={{
|
||||
|
|
|
@ -3,18 +3,17 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||
import ConsensusClientCard from './ConsensusClientCard'
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/ConsensusClientCard',
|
||||
component: ConsensusClientCard,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
title: 'Dashboard/ConsensusClientCard',
|
||||
component: ConsensusClientCard,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof ConsensusClientCard>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: { value: 200000, total: 123562 },
|
||||
args: { value: 200000, total: 123562 },
|
||||
}
|
||||
|
|
@ -9,58 +9,56 @@ import Icon from '../../../components/General/Icon'
|
|||
import StandardGauge from '../../../components/Charts/StandardGauge'
|
||||
|
||||
type ConsensusCardProps = {
|
||||
value: number
|
||||
total: number
|
||||
|
||||
value: number
|
||||
total: number
|
||||
}
|
||||
|
||||
const ConsensusCard = ({ value, total }: ConsensusCardProps) => {
|
||||
const style: CSSProperties = {}
|
||||
const data = [
|
||||
{
|
||||
id: 'storage',
|
||||
label: 'Used',
|
||||
value: value,
|
||||
color: '#ff6161',
|
||||
},
|
||||
{
|
||||
id: 'storage',
|
||||
label: 'Free',
|
||||
value: total,
|
||||
color: '#E7EAEE',
|
||||
},
|
||||
]
|
||||
const style: CSSProperties = {}
|
||||
const data = [
|
||||
{
|
||||
id: 'storage',
|
||||
label: 'Used',
|
||||
value: value,
|
||||
color: '#ff6161',
|
||||
},
|
||||
{
|
||||
id: 'storage',
|
||||
label: 'Free',
|
||||
value: total,
|
||||
color: '#E7EAEE',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
return (
|
||||
<Shadow variant="$1" style={style}>
|
||||
<YStack>
|
||||
<Stack style={{ minHeight: '90px', padding: '12px 16px' }}>
|
||||
<Text size={15} weight={'semibold'} color="#647084">
|
||||
Consensus Client
|
||||
</Text>
|
||||
<XStack style={{ justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Icon src="./icons/vector.svg" height={30} width={60} />
|
||||
<Stack
|
||||
style={{
|
||||
height: '56px',
|
||||
width: '56px',
|
||||
}}
|
||||
>
|
||||
<StandardGauge data={data} />
|
||||
</Stack>
|
||||
</XStack>
|
||||
</Stack>
|
||||
<Separator borderColor={'#e3e3e3'} />
|
||||
<XStack space={'$3'} style={{ padding: '12px 16px' }}>
|
||||
<IconText icon={<SwapIcon size={16} />}>Syncing</IconText>
|
||||
<Text size={13} weight={'semibold'}>
|
||||
{formatNumbersWithComa(value)} / {formatNumbersWithComa(total)}
|
||||
</Text>
|
||||
</XStack>
|
||||
</YStack>
|
||||
</Shadow>
|
||||
)
|
||||
return (
|
||||
<Shadow variant="$1" style={style}>
|
||||
<YStack>
|
||||
<Stack style={{ minHeight: '90px', padding: '12px 16px' }}>
|
||||
<Text size={15} weight={'semibold'} color="#647084">
|
||||
Consensus Client
|
||||
</Text>
|
||||
<XStack style={{ justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Icon src="./icons/vector.svg" height={30} width={60} />
|
||||
<Stack
|
||||
style={{
|
||||
height: '56px',
|
||||
width: '56px',
|
||||
}}
|
||||
>
|
||||
<StandardGauge data={data} />
|
||||
</Stack>
|
||||
</XStack>
|
||||
</Stack>
|
||||
<Separator borderColor={'#e3e3e3'} />
|
||||
<XStack space={'$3'} style={{ padding: '12px 16px' }}>
|
||||
<IconText icon={<SwapIcon size={16} />}>Syncing</IconText>
|
||||
<Text size={13} weight={'semibold'}>
|
||||
{formatNumbersWithComa(value)} / {formatNumbersWithComa(total)}
|
||||
</Text>
|
||||
</XStack>
|
||||
</YStack>
|
||||
</Shadow>
|
||||
)
|
||||
}
|
||||
|
||||
export default ConsensusCard
|
||||
|
|
|
@ -3,18 +3,17 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||
import ExecutionClientCard from './ExecutionClientCard'
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/ExecutionClientCard',
|
||||
component: ExecutionClientCard,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
title: 'Dashboard/ExecutionClientCard',
|
||||
component: ExecutionClientCard,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof ExecutionClientCard>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: { value: 200000, total: 123562 },
|
||||
args: { value: 200000, total: 123562 },
|
||||
}
|
||||
|
|
@ -11,7 +11,6 @@ import StandardGauge from '../../../components/Charts/StandardGauge'
|
|||
type ExecutionClientCardProps = {
|
||||
value: number
|
||||
total: number
|
||||
|
||||
}
|
||||
|
||||
const ExecutionClientCard = ({ value, total }: ExecutionClientCardProps) => {
|
||||
|
@ -31,8 +30,6 @@ const ExecutionClientCard = ({ value, total }: ExecutionClientCardProps) => {
|
|||
]
|
||||
const style: CSSProperties = {}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<Shadow variant="$1" style={style}>
|
||||
<YStack>
|
||||
|
@ -41,7 +38,9 @@ const ExecutionClientCard = ({ value, total }: ExecutionClientCardProps) => {
|
|||
Execution Client
|
||||
</Text>
|
||||
<XStack style={{ justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Text size={19} weight={'semibold'}>Geth</Text>
|
||||
<Text size={19} weight={'semibold'}>
|
||||
Geth
|
||||
</Text>
|
||||
<Stack
|
||||
style={{
|
||||
height: '56px',
|
||||
|
|
|
@ -3,17 +3,17 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||
import SyncStatusCards from './SyncStatusCards'
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/SyncStatusCards',
|
||||
component: SyncStatusCards,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
title: 'Dashboard/SyncStatusCards',
|
||||
component: SyncStatusCards,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof SyncStatusCards>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {},
|
||||
args: {},
|
||||
}
|
||||
|
|
|
@ -3,123 +3,122 @@ import type { Meta, StoryObj } from '@storybook/react'
|
|||
import UptimeChart from './UptimeChart'
|
||||
|
||||
const meta = {
|
||||
title: 'Dashboard/UptimeChart',
|
||||
component: UptimeChart,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
decorators: [
|
||||
Story => (
|
||||
<div style={{ height: '20vh', width: '50vh' }}>
|
||||
<Story />
|
||||
</div>
|
||||
),
|
||||
],
|
||||
tags: ['autodocs'],
|
||||
title: 'Dashboard/UptimeChart',
|
||||
component: UptimeChart,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
decorators: [
|
||||
Story => (
|
||||
<div style={{ height: '20vh', width: '50vh' }}>
|
||||
<Story />
|
||||
</div>
|
||||
),
|
||||
],
|
||||
tags: ['autodocs'],
|
||||
} satisfies Meta<typeof UptimeChart>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const WithoutLabels: Story = {
|
||||
args: {
|
||||
data: [
|
||||
{
|
||||
pv: 1,
|
||||
pa: 1,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 1,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 1,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 1,
|
||||
},
|
||||
]
|
||||
|
||||
},
|
||||
args: {
|
||||
data: [
|
||||
{
|
||||
pv: 1,
|
||||
pa: 1,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 1,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 1,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
pv: 0,
|
||||
pa: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
export const WithMonths: Story = {
|
||||
args: {
|
||||
data: [
|
||||
{
|
||||
name: 'Jan',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Feb',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Mar',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Apr',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'May',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Aug',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Jun',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Jul',
|
||||
pv: 1,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Sep',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Oct',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Nov',
|
||||
pv: 1,
|
||||
pa: 1,
|
||||
},
|
||||
{
|
||||
name: 'Dec',
|
||||
pv: 1,
|
||||
pa: 1,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
args: {
|
||||
data: [
|
||||
{
|
||||
name: 'Jan',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Feb',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Mar',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Apr',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'May',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Aug',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Jun',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Jul',
|
||||
pv: 1,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Sep',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Oct',
|
||||
pv: 0,
|
||||
pa: 0,
|
||||
},
|
||||
{
|
||||
name: 'Nov',
|
||||
pv: 1,
|
||||
pa: 1,
|
||||
},
|
||||
{
|
||||
name: 'Dec',
|
||||
pv: 1,
|
||||
pa: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { BarChart, Bar, ResponsiveContainer, XAxis } from 'recharts';
|
||||
import { BarChart, Bar, ResponsiveContainer, XAxis } from 'recharts'
|
||||
|
||||
type DataItem = {
|
||||
name?: string
|
||||
|
@ -12,20 +12,15 @@ type UptimeChartProps = {
|
|||
|
||||
const UptimeChart = ({ data }: UptimeChartProps) => {
|
||||
return (
|
||||
<ResponsiveContainer >
|
||||
<BarChart
|
||||
data={data}
|
||||
style={{ backgroundColor: '#F0F2F5' }}
|
||||
>
|
||||
<ResponsiveContainer>
|
||||
<BarChart data={data} style={{ backgroundColor: '#F0F2F5' }}>
|
||||
<Bar dataKey="pv" barSize={2} fill="#E95460" />
|
||||
{/* @NOTE: We can add as many Bar items as we need and use them for each day of the month */}
|
||||
<Bar dataKey="pa" barSize={2} fill="#E95460" />
|
||||
{data[0].name && (
|
||||
<XAxis dataKey="name" fontSize={'10px'} tickMargin={10} />
|
||||
)}
|
||||
{data[0].name && <XAxis dataKey="name" fontSize={'10px'} tickMargin={10} />}
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
export default UptimeChart
|
||||
|
|
|
@ -16,13 +16,14 @@ const DeviceHealthCheck = () => {
|
|||
const deviceHealthState = useSelector((state: RootState) => state.deviceHealth)
|
||||
|
||||
return (
|
||||
<PageWrapperShadow rightImageSrc="./background-images/eye-background.png">
|
||||
<PageWrapperShadow rightImageSrc="./background-images/eye-background.png" imgHeight="100%">
|
||||
<YStack
|
||||
space={'$4'}
|
||||
style={{
|
||||
justifyContent: 'end',
|
||||
alignItems: 'start',
|
||||
marginBottom: '2rem',
|
||||
marginTop: '4.4rem',
|
||||
maxWidth: '100%',
|
||||
}}
|
||||
>
|
||||
|
@ -32,14 +33,14 @@ const DeviceHealthCheck = () => {
|
|||
subtitle="Configure your device to start Staking on Nimbus"
|
||||
isAdvancedSettings={true}
|
||||
/>
|
||||
<XStack space={'$4'}>
|
||||
<XStack space={'$4'} width={'100%'}>
|
||||
<DeviceStorageHealth
|
||||
storage={deviceHealthState.storage}
|
||||
maxStorage={deviceHealthState.maxMemory}
|
||||
/>
|
||||
<DeviceCPULoad load={deviceHealthState.cpuLoad} />
|
||||
</XStack>
|
||||
<XStack space={'$4'}>
|
||||
<XStack space={'$4'} width={'100%'}>
|
||||
<DeviceMemory
|
||||
currentMemory={deviceHealthState.memory}
|
||||
maxMemory={deviceHealthState.maxMemory}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
|
||||
import DeviceSyncStatus from './DeviceSyncStatus'
|
||||
|
||||
const meta = {
|
||||
|
|
|
@ -25,13 +25,17 @@ const DeviceSyncStatus = () => {
|
|||
}, [dispatch])
|
||||
|
||||
return (
|
||||
<PageWrapperShadow rightImageSrc="./background-images/sync-status-background.png">
|
||||
<PageWrapperShadow
|
||||
rightImageSrc="./background-images/sync-status-background.png"
|
||||
imgHeight="120%"
|
||||
>
|
||||
<YStack
|
||||
space={'$4'}
|
||||
style={{
|
||||
justifyContent: 'end',
|
||||
alignItems: 'start',
|
||||
maxWidth: '100%',
|
||||
marginTop: '4.4rem',
|
||||
}}
|
||||
>
|
||||
<NimbusLogo />
|
||||
|
|
|
@ -46,7 +46,7 @@ const SyncStatusCardConsensus: React.FC<DeviceStorageHealthProps> = ({ synced, t
|
|||
style={{
|
||||
padding: '8px 16px',
|
||||
position: 'relative',
|
||||
height: '160px',
|
||||
minHeight: '180px',
|
||||
}}
|
||||
>
|
||||
<YStack space={'$3'} style={{ width: '100%' }}>
|
||||
|
|
|
@ -45,7 +45,7 @@ const SyncStatusCardExecution: React.FC<DeviceStorageHealthProps> = ({ synced, t
|
|||
style={{
|
||||
padding: '8px 16px',
|
||||
position: 'relative',
|
||||
height: '160px',
|
||||
minHeight: '180px',
|
||||
}}
|
||||
>
|
||||
<YStack space={'$3'} style={{ width: '100%' }}>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
.landing-page {
|
||||
height: 100%;
|
||||
.landing-page {
|
||||
height: 100%;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ const LandingPage = () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<PageWrapperShadow rightImageSrc="./background-images/landing-page-bg.png">
|
||||
<PageWrapperShadow rightImageSrc="./background-images/landing-page-bg.png" imgHeight="150%">
|
||||
<YStack className="landing-page">
|
||||
<XStack pt={'70px'}>
|
||||
<NimbusLogo />
|
||||
|
|
|
@ -48,8 +48,8 @@ const SyncStatus = ({
|
|||
const timer = convertSecondsToTimerFormat(elapsedTime)
|
||||
|
||||
const connectViaIpHandler = () => {
|
||||
navigate('/connect-device');
|
||||
};
|
||||
navigate('/connect-device')
|
||||
}
|
||||
|
||||
return (
|
||||
<YStack space={'$2'}>
|
||||
|
@ -91,7 +91,7 @@ const SyncStatus = ({
|
|||
)}
|
||||
{isAwaitingPairing && (
|
||||
<XStack>
|
||||
<Button icon={<Icon src={ConnectionIcon} />} size={40} onPress={connectViaIpHandler} >
|
||||
<Button icon={<Icon src={ConnectionIcon} />} size={40} onPress={connectViaIpHandler}>
|
||||
Connect via IP
|
||||
</Button>
|
||||
</XStack>
|
||||
|
|
|
@ -20,22 +20,21 @@ export const Default: Story = {
|
|||
args: {
|
||||
validatorsValue: '4',
|
||||
executionSyncStatus1: {
|
||||
text: "Execution Sync Status",
|
||||
text: 'Execution Sync Status',
|
||||
isGaugeIncluded: true,
|
||||
gaugeColor: "$blue",
|
||||
gaugeColor: '$blue',
|
||||
gaugeSynced: 123.524,
|
||||
gaugeTotal: 172.503,
|
||||
|
||||
},
|
||||
executionSyncStatus2: {
|
||||
text: "Execution Sync Status",
|
||||
text: 'Execution Sync Status',
|
||||
isGaugeIncluded: true,
|
||||
gaugeColor: "$red",
|
||||
gaugeColor: '$red',
|
||||
gaugeSynced: 123.524,
|
||||
gaugeTotal: 172.503,
|
||||
},
|
||||
currentAPRValue: "4.40%",
|
||||
estimatedActivationTimeValue: "32 Days",
|
||||
validatorQueueValue: "92603",
|
||||
currentAPRValue: '4.40%',
|
||||
estimatedActivationTimeValue: '32 Days',
|
||||
validatorQueueValue: '92603',
|
||||
},
|
||||
}
|
||||
|
|
|
@ -48,20 +48,20 @@ const Activation = ({
|
|||
}, [])
|
||||
|
||||
return (
|
||||
<Stack style={styles.confettiContainer} width={'100%'}>
|
||||
<Stack style={styles.confettiContainer} width={'100%'} minHeight={'65vh'}>
|
||||
{showConfetti && <Confetti style={styles.confettiCanvas} />}
|
||||
<YStack style={{ padding: '16px 32px' }}>
|
||||
<YStack style={{ padding: '26px 32px' }}>
|
||||
<YStack space={'$5'}>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
Activation
|
||||
</Text>
|
||||
<Stack style={{ width: '66%' }}>
|
||||
<Text size={27}>
|
||||
<Text size={19}>
|
||||
Congratulations! You have successfully setup your Nimbus Validators and are currently
|
||||
syncing your nodes.
|
||||
</Text>
|
||||
</Stack>
|
||||
<YStack space={'$3'} marginTop={'10px'} width={'33%'}>
|
||||
<YStack space={'$3'} marginTop={'25px'} width={'33%'}>
|
||||
<XStack space={'$3'} justifyContent={'space-between'}>
|
||||
<ActivationCard text="Validators" value={validatorsValue} />
|
||||
<ActivationCard {...executionSyncStatus1} />
|
||||
|
@ -81,7 +81,7 @@ const Activation = ({
|
|||
text="Edit Validators"
|
||||
to="/"
|
||||
arrowLeft={true}
|
||||
style={{ marginTop: '44px', marginBottom: '88px' }}
|
||||
style={{ marginTop: '44px', marginBottom: '88px', fontSize: '13px' }}
|
||||
/>
|
||||
</YStack>
|
||||
</Stack>
|
||||
|
|
|
@ -30,7 +30,7 @@ const ActivationCard = ({
|
|||
}}
|
||||
>
|
||||
{!isGaugeIncluded && (
|
||||
<Stack>
|
||||
<Stack space={'$2'}>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
{text}
|
||||
</Text>
|
||||
|
@ -40,7 +40,7 @@ const ActivationCard = ({
|
|||
</Stack>
|
||||
)}
|
||||
{isGaugeIncluded && (
|
||||
<Stack>
|
||||
<Stack space={'$2'}>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
{text}
|
||||
</Text>
|
||||
|
|
|
@ -15,8 +15,8 @@ const Advisories = () => {
|
|||
|
||||
return (
|
||||
<XStack
|
||||
style={{ padding: '16px 32px', justifyContent: 'space-between' }}
|
||||
height={'65vh'}
|
||||
style={{ padding: '30px 33px', justifyContent: 'space-between' }}
|
||||
minHeight={'65vh'}
|
||||
width={'100%'}
|
||||
>
|
||||
<YStack space={'$2'}>
|
||||
|
@ -33,7 +33,7 @@ const Advisories = () => {
|
|||
space={'$2'}
|
||||
>
|
||||
<Text
|
||||
size={27}
|
||||
size={19}
|
||||
weight={isSameTitle(title) && 'semibold'}
|
||||
color={isSameTitle(title) ? 'blue' : ''}
|
||||
>
|
||||
|
|
|
@ -17,11 +17,11 @@ const AdvisoriesContent = ({ title, content }: AdvisoriesContentProps) => {
|
|||
</Stack>
|
||||
<YStack space={'$4'}>
|
||||
{content.map(row => (
|
||||
<Text key={row} size={19}>
|
||||
<Text key={row} size={15}>
|
||||
{row}
|
||||
</Text>
|
||||
))}
|
||||
<Text size={19}>
|
||||
<Text size={15}>
|
||||
<Link
|
||||
to={'https://github.com/ethereum/consensus-specs'}
|
||||
style={{ textDecorationLine: 'underline', color: '#484848' }}
|
||||
|
@ -29,7 +29,7 @@ const AdvisoriesContent = ({ title, content }: AdvisoriesContentProps) => {
|
|||
The Ethereum consensus layer specification
|
||||
</Link>
|
||||
</Text>
|
||||
<Text size={19} weight={'semibold'}>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
<Link
|
||||
to={'https://github.com/ethereum/consensus-specs'}
|
||||
style={{ textDecorationLine: 'underline', color: '#2A4CF4', fontWeight: 'bold' }}
|
||||
|
|
|
@ -6,7 +6,7 @@ import LinkWithArrow from '../../../components/General/LinkWithArrow'
|
|||
|
||||
const ClientSetup = () => {
|
||||
return (
|
||||
<YStack padding={'26px'} width={'100%'} space={'$5'}>
|
||||
<YStack space={'$8'} padding={'26px'} width={'100%'} minHeight={'65vh'}>
|
||||
<SetupRow title={'Setup up Validators'} />
|
||||
<Separator borderColor={'#F0F2F5'} />
|
||||
<WithdrawalAddress title={'Withdrawal address'} />
|
||||
|
@ -14,7 +14,7 @@ const ClientSetup = () => {
|
|||
text="Advanced Recovery Method"
|
||||
to={'/'}
|
||||
arrowRight={true}
|
||||
style={{ marginBottom: '50px' }}
|
||||
style={{ marginBottom: '50px', fontWeight: 'bold', fontSize: '15px' }}
|
||||
/>
|
||||
</YStack>
|
||||
)
|
||||
|
|
|
@ -22,7 +22,7 @@ const SetupRow = ({ title }: SetupRowProps) => {
|
|||
|
||||
return (
|
||||
<YStack space={'$4'}>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
<Text size={19} weight={'semibold'}>
|
||||
{title}
|
||||
</Text>
|
||||
<XStack justifyContent={'space-between'} width={'80%'}>
|
||||
|
@ -38,7 +38,7 @@ const SetupRow = ({ title }: SetupRowProps) => {
|
|||
/>
|
||||
</Stack>
|
||||
<YStack space={'$2'}>
|
||||
<Text size={19} weight={'semibold'} color="#09101C">
|
||||
<Text size={15} weight={'semibold'} color="#09101C">
|
||||
ETH
|
||||
</Text>
|
||||
<Text size={27} weight={'semibold'} color="#09101C">
|
||||
|
@ -47,7 +47,7 @@ const SetupRow = ({ title }: SetupRowProps) => {
|
|||
</YStack>
|
||||
<YStack space={'$2'}>
|
||||
<XStack style={{ justifyContent: 'space-between' }}>
|
||||
<Text size={19} weight={'semibold'} color="#09101C">
|
||||
<Text size={15} weight={'semibold'} color="#09101C">
|
||||
USD
|
||||
</Text>
|
||||
<ChevronDownIcon size={16} color={'#919191'} />
|
||||
|
|
|
@ -20,7 +20,7 @@ const WithdrawalAddress = ({ title }: WithdrawalAddressProps) => {
|
|||
|
||||
return (
|
||||
<YStack space={'$4'}>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
<Text size={19} weight={'semibold'}>
|
||||
{title}
|
||||
</Text>
|
||||
<YStack space={'$3'}>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Stack, XStack } from 'tamagui'
|
||||
import { Stack, YStack } from 'tamagui'
|
||||
import { Button, InformationBox } from '@status-im/components'
|
||||
import { CloseCircleIcon } from '@status-im/icons'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
|
@ -43,7 +43,7 @@ const ContinueButton = ({
|
|||
const isActivationValScreen = activeStep === 3 && subStepValidatorSetup === 3
|
||||
|
||||
return (
|
||||
<XStack style={{ width: '100%', alignItems: 'center', zIndex: 999, marginTop: '40px' }}>
|
||||
<YStack style={{ width: '100%', alignItems: 'center', zIndex: 999, marginTop: '30px' }}>
|
||||
<Stack style={{ width: '100%' }}>
|
||||
{isCopyPastedPhrase && (
|
||||
<InformationBox
|
||||
|
@ -66,14 +66,13 @@ const ContinueButton = ({
|
|||
width: '100%',
|
||||
zIndex: 999,
|
||||
alignItems: 'end',
|
||||
position: 'absolute',
|
||||
}}
|
||||
>
|
||||
<Button onPress={continueHandler} size={40} disabled={isDisabled()}>
|
||||
{activeStep < 5 ? 'Continue' : 'Continue to Dashboard'}
|
||||
</Button>
|
||||
</Stack>
|
||||
</XStack>
|
||||
</YStack>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,23 @@
|
|||
.custom-step {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
div[class*='StepMain-'] {
|
||||
align-items: start;
|
||||
}
|
||||
div[class*='LabelContainer-'] span[class*='Label-'] {
|
||||
text-align: initial;
|
||||
text-transform: uppercase;
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
div[class*='ConnectorContainer-'] {
|
||||
right: unset;
|
||||
left: calc(-100% + 28px);
|
||||
width: 100%;
|
||||
}
|
||||
span[class*='Connector-'] {
|
||||
position: relative;
|
||||
z-index: -1;
|
||||
}
|
||||
.custom-step.StepMain--active,
|
||||
.custom-step.StepMain--completed {
|
||||
background-color: #2a4cf4;
|
||||
|
@ -37,32 +53,9 @@
|
|||
content: attr(data-subtitle);
|
||||
position: absolute;
|
||||
top: calc(100% + 4px);
|
||||
left: 8px;
|
||||
font-size: 12px;
|
||||
color: #A2A9B0;
|
||||
background: transparent;
|
||||
border: none;
|
||||
font-family: 'Inter', sans-serif;
|
||||
color: #a2a9b0;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
[data-step="Overview"]::after {
|
||||
left: 35%;
|
||||
}
|
||||
|
||||
[data-step="Advisories"]::after {
|
||||
left: 30%;
|
||||
}
|
||||
|
||||
[data-step="Client Setup"]::after {
|
||||
left: 32%;
|
||||
}
|
||||
|
||||
[data-step="Validator Setup"]::after {
|
||||
left: 25%;
|
||||
}
|
||||
|
||||
[data-step="Key Generation"]::after {
|
||||
left: 24.5%;
|
||||
}
|
||||
|
||||
[data-step="Activation"]::after {
|
||||
left: 33%;
|
||||
}
|
|
@ -22,7 +22,14 @@ const FormStepper = ({ activeStep, changeActiveStep }: FormStepperProps) => {
|
|||
nonLinear={true}
|
||||
styleConfig={stepStyle}
|
||||
connectorStyleConfig={customConnectorStyle}
|
||||
style={{ fontSize: '14px', zIndex: 999, width: '100%', padding: 0, marginBottom: '2rem' }}
|
||||
style={{
|
||||
fontSize: '14px',
|
||||
zIndex: 999,
|
||||
width: '100%',
|
||||
padding: 0,
|
||||
marginBottom: '3rem',
|
||||
fontFamily: 'Inter',
|
||||
}}
|
||||
>
|
||||
{steps.map((step, index) => (
|
||||
<Step
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
background-color: #f7f8f9;
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
color: rgb(13, 22, 37);
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
|
@ -40,9 +42,9 @@
|
|||
position: absolute;
|
||||
left: 15px;
|
||||
transform: translateY(-50%);
|
||||
pointer-events: none;
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
color: #0D162566;
|
||||
color: #0d162566;
|
||||
top: 48%;
|
||||
}
|
||||
|
||||
|
@ -76,4 +78,4 @@
|
|||
|
||||
.suggestion-list::-webkit-scrollbar-thumb:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ const ConfirmRecoveryPhrase = () => {
|
|||
return (
|
||||
<YStack space={'$3'} style={{ width: '100%', marginTop: '20px' }}>
|
||||
<KeyGenerationTitle />
|
||||
<Text size={27}>Confirm Recovery Phrase</Text>
|
||||
<Text size={19}>Confirm Recovery Phrase</Text>
|
||||
<Stack
|
||||
style={{
|
||||
display: 'grid',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Text as TextTam, XStack, YStack } from 'tamagui'
|
||||
import { XStack, YStack } from 'tamagui'
|
||||
import { Text } from '@status-im/components'
|
||||
|
||||
import OverviewCard from './OverviewCard'
|
||||
|
@ -7,29 +7,37 @@ import LinkWithArrow from '../../../components/General/LinkWithArrow'
|
|||
const Overview = () => {
|
||||
return (
|
||||
<>
|
||||
<YStack className="layout-left" space={'$5'} style={{ padding: '16px 32px' }}>
|
||||
<TextTam fontSize={27} fontWeight={'600'}>
|
||||
Overview
|
||||
</TextTam>
|
||||
<Text size={27}>
|
||||
Becoming a validator is a big responsibility with important preparation steps. Only start
|
||||
the deposit process when youre ready.
|
||||
</Text>
|
||||
<Text size={15} color="#939BA1">
|
||||
By running a validator, you'll be responsible for securing the network and receive
|
||||
continuous payouts for actions that help the network reach consensus.
|
||||
</Text>
|
||||
<Text size={15} color="#939BA1">
|
||||
Since the successful transition to proof-of-stake via The Merge, Ethereum is fully secured
|
||||
by proof-of-stake validators. By running a validator, you'll be helping to secure the
|
||||
Ethereum network.
|
||||
</Text>
|
||||
<LinkWithArrow
|
||||
text="Learn more"
|
||||
to={'/'}
|
||||
arrowRight={true}
|
||||
style={{ marginBottom: '1%' }}
|
||||
/>
|
||||
<YStack
|
||||
className="layout-left"
|
||||
space={'$5'}
|
||||
style={{ padding: '26px 0 32px 32px' }}
|
||||
minHeight={'65vh'}
|
||||
justifyContent={'space-between'}
|
||||
>
|
||||
<YStack space={'$5'}>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
Overview
|
||||
</Text>
|
||||
<Text size={19}>
|
||||
Becoming a validator is a big responsibility with important preparation steps. Only
|
||||
start the deposit process when you're ready.
|
||||
</Text>
|
||||
<Text size={15} color="#939BA1">
|
||||
By running a validator, you'll be responsible for securing the network and receive
|
||||
continuous payouts for actions that help the network reach consensus.
|
||||
</Text>
|
||||
<Text size={15} color="#939BA1">
|
||||
Since the successful transition to proof-of-stake via The Merge, Ethereum is fully
|
||||
secured by proof-of-stake validators. By running a validator, you'll be helping to
|
||||
secure the Ethereum network.
|
||||
</Text>
|
||||
<LinkWithArrow
|
||||
text="Learn More"
|
||||
to={'/'}
|
||||
arrowRight={true}
|
||||
style={{ marginBottom: '1%', fontSize: '13px' }}
|
||||
/>
|
||||
</YStack>
|
||||
<XStack space={'$3'}>
|
||||
<OverviewCard text={'Current APR'} value={'4.40%'} />
|
||||
<OverviewCard text={'Total ETH Staked'} value={'9,451,123'} />
|
||||
|
|
|
@ -12,12 +12,12 @@ const OverviewCard = ({ text, value }: OverviewCardProps) => {
|
|||
style={{
|
||||
borderRadius: '16px',
|
||||
border: '1px solid rgba(0, 0, 0, 0.15)',
|
||||
width: '46%',
|
||||
width: '44%',
|
||||
padding: '12px 16px',
|
||||
backgroundColor: '#FFF',
|
||||
}}
|
||||
>
|
||||
<Text size={19} weight={'semibold'}>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
{text}
|
||||
</Text>
|
||||
<Text size={27} color="blue" weight={'semibold'}>
|
||||
|
|
|
@ -82,8 +82,8 @@ const ValidatorOnboarding = () => {
|
|||
<YStack
|
||||
style={{
|
||||
width: '100%',
|
||||
margin: '0 auto',
|
||||
padding: '2% 10% 2%',
|
||||
maxWidth: '1100px',
|
||||
margin: '4rem auto 2rem',
|
||||
justifyContent: 'start',
|
||||
alignItems: 'start',
|
||||
}}
|
||||
|
|
|
@ -18,10 +18,10 @@ const ConsensusClientCard = ({ name, icon }: ConsensusClientCardProps) => {
|
|||
padding: '12px 16px',
|
||||
width: '29%',
|
||||
}}
|
||||
space={'$10'}
|
||||
space={'$8'}
|
||||
>
|
||||
<Stack>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
{name}
|
||||
</Text>
|
||||
</Stack>
|
||||
|
|
|
@ -18,6 +18,9 @@ type Story = StoryObj<typeof meta>
|
|||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
color: 'orange', synced: 140000, total: 200000, title: 'Synced Files'
|
||||
color: 'orange',
|
||||
synced: 140000,
|
||||
total: 200000,
|
||||
title: 'Synced Files',
|
||||
},
|
||||
}
|
||||
|
|
|
@ -32,29 +32,29 @@ const ConsensusSelection = () => {
|
|||
]
|
||||
|
||||
return (
|
||||
<YStack style={{ width: '100%', padding: '32px' }}>
|
||||
<XStack justifyContent={'space-between'}>
|
||||
<YStack style={{ width: '100%', padding: '32px' }} minHeight={'65vh'}>
|
||||
<XStack justifyContent={'space-between'} alignItems={'center'} mb={'30px'}>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
Validator Setup
|
||||
</Text>
|
||||
<XStack space={'$2'}>
|
||||
<PairedDeviceCard isVisibleState={true} />
|
||||
<ConsensusGaugeCard
|
||||
color="blue"
|
||||
synced={134879}
|
||||
title="Execution Sync Status"
|
||||
total={150000}
|
||||
/>
|
||||
<PairedDeviceCard isVisibleState={true} />
|
||||
</XStack>
|
||||
</XStack>
|
||||
|
||||
<YStack>
|
||||
<YStack mb={'50px'}>
|
||||
<Stack style={{ marginBottom: '4px' }}>
|
||||
<Text size={13} color="#647084">
|
||||
Consensus Client Detection
|
||||
</Text>
|
||||
</Stack>
|
||||
<Text size={15} weight={'regular'}>
|
||||
<Text size={15}>
|
||||
No existing execution client installations have been detected on paired device.
|
||||
</Text>
|
||||
<Text size={13} color="#828282">
|
||||
|
@ -63,14 +63,14 @@ const ConsensusSelection = () => {
|
|||
</Text>
|
||||
</YStack>
|
||||
|
||||
<TextTam fontSize={27} style={{ margin: '5px', marginLeft: 0, marginTop: '50px' }}>
|
||||
<TextTam fontSize={19} style={{ marginLeft: 0, marginTop: '50px', marginBottom: '25px' }}>
|
||||
Install Consensus client
|
||||
</TextTam>
|
||||
|
||||
<XStack space={'$8'}>
|
||||
<ConsensusClientCard name={clients[0].name} icon={clients[0].icon} />
|
||||
<YStack width={'67%'} space={'$4'}>
|
||||
<Text size={27}>The resource efficient Ethereum Clients.</Text>
|
||||
<Text size={19}>The resource efficient Ethereum Clients.</Text>
|
||||
<Text size={15}>
|
||||
{selectedClient} is a client implementation for both execution and consensus layers that
|
||||
strives to be as lightweight as possible in terms of resources used. This allows it to
|
||||
|
@ -81,6 +81,7 @@ const ConsensusSelection = () => {
|
|||
<LinkWithArrow
|
||||
textColor="black"
|
||||
text="Nimbus Documentation"
|
||||
style={{ fontSize: '15px' }}
|
||||
arrowRight={true}
|
||||
to="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
||||
/>
|
||||
|
|
|
@ -20,9 +20,9 @@ const PairedDeviceCard = ({ isVisibleState }: PairedDeviceCardProps) => {
|
|||
<XStack
|
||||
space={'$7'}
|
||||
style={{
|
||||
padding: '2px 6px',
|
||||
padding: '6px 12px',
|
||||
border: '1px solid #DCE0E5',
|
||||
borderRadius: '15px',
|
||||
borderRadius: '10px',
|
||||
}}
|
||||
alignItems={'center'}
|
||||
>
|
||||
|
|
|
@ -4,16 +4,16 @@ import ActivationValidatorSetup from './ActivationValidatorSetup'
|
|||
import { withRouter } from 'storybook-addon-react-router-v6'
|
||||
|
||||
const meta = {
|
||||
title: 'ValidatorOnboarding/ActivationValidatorSetup',
|
||||
component: ActivationValidatorSetup,
|
||||
title: 'ValidatorOnboarding/ActivationValidatorSetup',
|
||||
component: ActivationValidatorSetup,
|
||||
|
||||
tags: ['autodocs'],
|
||||
decorators: [withRouter()],
|
||||
tags: ['autodocs'],
|
||||
decorators: [withRouter()],
|
||||
} satisfies Meta<typeof ActivationValidatorSetup>
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: { },
|
||||
args: {},
|
||||
}
|
||||
|
|
|
@ -19,21 +19,21 @@ const ActivationValidatorSetup = () => {
|
|||
}, [])
|
||||
|
||||
return (
|
||||
<Stack style={styles.confettiContainer} width={'100%'}>
|
||||
<Stack style={styles.confettiContainer} width={'100%'} minHeight={'65vh'}>
|
||||
{showConfetti && <Confetti style={styles.confettiCanvas} />}
|
||||
<YStack style={{ padding: '16px 32px' }}>
|
||||
<YStack space={'$3'}>
|
||||
<YStack style={{ padding: '26px 32px' }}>
|
||||
<YStack space={'$5'}>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
Activation
|
||||
</Text>
|
||||
<Stack>
|
||||
<Text size={27}>
|
||||
<Text size={19}>
|
||||
Congratulations! You have successfully setup your Execution and Consensus clients and
|
||||
are currently syncing your nodes. You need to be sufficiently synced prior to setting
|
||||
up your validators and making a deposit.
|
||||
</Text>
|
||||
</Stack>
|
||||
<YStack space={'$3'} marginTop={'10px'} width={'33%'}>
|
||||
<YStack space={'$3'} marginTop={'25px'} width={'33%'}>
|
||||
<XStack width={'151%'} space={'$3'}>
|
||||
<ActivationCard
|
||||
text="Execution Sync Status"
|
||||
|
|
|
@ -18,13 +18,13 @@ const OsCard = ({ name, icon, onClick, isSelected }: OsCardProps) => {
|
|||
border: isSelected ? '1px solid #2A4AF566' : '1px solid rgba(0, 0, 0, 0.15);',
|
||||
borderRadius: '16px',
|
||||
padding: '12px 16px',
|
||||
width: '33%',
|
||||
width: '32%',
|
||||
}}
|
||||
space={'$12'}
|
||||
space={'$8'}
|
||||
onPress={onClick}
|
||||
>
|
||||
<Stack>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
<Text size={19} weight={'semibold'}>
|
||||
{name}
|
||||
</Text>
|
||||
</Stack>
|
||||
|
|
|
@ -13,7 +13,7 @@ const ValidatorSetupInstall = () => {
|
|||
const selectedClient = useSelector((state: RootState) => state.execClient.selectedClient)
|
||||
|
||||
return (
|
||||
<YStack style={{ width: '100%', padding: '16px 32px' }}>
|
||||
<YStack style={{ width: '100%', padding: '26px 32px' }}>
|
||||
<XStack justifyContent={'space-between'} style={{ marginBottom: '10px' }}>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
Validator Setup
|
||||
|
@ -23,7 +23,7 @@ const ValidatorSetupInstall = () => {
|
|||
<YStack>
|
||||
<Stack style={{ marginBottom: '4px' }}>
|
||||
<YStack space={'$3'}>
|
||||
<Text size={19} weight={'semibold'}>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
{selectedClient}
|
||||
</Text>
|
||||
|
||||
|
@ -41,12 +41,12 @@ const ValidatorSetupInstall = () => {
|
|||
style={{
|
||||
border: '1px solid #00000026',
|
||||
borderRadius: '16px',
|
||||
padding: '6px 12px',
|
||||
padding: '19px 16px',
|
||||
}}
|
||||
space={'$3'}
|
||||
>
|
||||
<Text size={27}> Installing {selectedClient}</Text>
|
||||
<Text size={19} color="#647084" weight={'regular'}>
|
||||
<Text size={19}> Installing {selectedClient}</Text>
|
||||
<Text size={15} color="#647084" weight={'regular'}>
|
||||
There are several ways to install Geth, including via a package manager, downloading
|
||||
a pre-built bundle, running as a docker container or building from downloaded source
|
||||
code. On this page the various installation options are explained for several major
|
||||
|
@ -59,10 +59,10 @@ const ValidatorSetupInstall = () => {
|
|||
are also provided in each section.
|
||||
</Text>
|
||||
|
||||
<XStack justifyContent={'space-between'} space={'$2'} margin={'50px 0px'}>
|
||||
<XStack justifyContent={'space-between'} my={'15px'}>
|
||||
<OsCard
|
||||
icon="/icons/MAC.png"
|
||||
name="Mac"
|
||||
name="MacOS"
|
||||
isSelected={selectedOs === 'Mac'}
|
||||
onClick={() => setSelectedOs('Mac')}
|
||||
/>
|
||||
|
@ -80,17 +80,17 @@ const ValidatorSetupInstall = () => {
|
|||
/>
|
||||
</XStack>
|
||||
<YStack space={'$2'}>
|
||||
<Text size={27}> Package Managers</Text>
|
||||
<Text size={19}> Package Managers</Text>
|
||||
<Text size={15} weight={'semibold'}>
|
||||
MacOS via Homebrew
|
||||
</Text>
|
||||
<Text size={19} color="#647084" weight={'regular'}>
|
||||
<Text size={15} color="#647084">
|
||||
The easiest way to install go-ethereum is to use the Geth Homebrew tap. The first
|
||||
step is to check that Homebrew is installed. The following command should return a
|
||||
version number.
|
||||
</Text>
|
||||
<SyntaxHighlighterBox rows={['brew -v']} />
|
||||
<Text size={19} color="#647084" weight={'regular'}>
|
||||
<Text size={15} color="#647084">
|
||||
If a version number is returned, then Homebrew is installed. If not, Homebrew can
|
||||
be installed by following the instructions here. With Homebrew installed, the
|
||||
following commands add the Geth tap and install Geth:
|
||||
|
|
|
@ -24,19 +24,19 @@ const ExecClientCard = ({ name, icon, isComingSoon }: ExecClientCardProps) => {
|
|||
border: isComingSoon
|
||||
? '1px solid #F5F6F8'
|
||||
: isSelected
|
||||
? '1px solid #2A4AF5'
|
||||
: '1px solid #DCE0E5',
|
||||
? '1px solid #2A4AF5'
|
||||
: '1px solid #DCE0E5',
|
||||
borderRadius: '16px',
|
||||
padding: '12px 16px',
|
||||
width: '19%',
|
||||
}}
|
||||
space={'$12'}
|
||||
space={'$8'}
|
||||
onClick={() => {
|
||||
dispatch(selectClient(name))
|
||||
}}
|
||||
>
|
||||
<Stack>
|
||||
<Text size={27} weight={'semibold'} color={isComingSoon ? '#DCE0E5' : ''}>
|
||||
<Text size={19} weight={'semibold'} color={isComingSoon ? '#DCE0E5' : ''}>
|
||||
{name}
|
||||
</Text>
|
||||
{isComingSoon && (
|
||||
|
@ -46,9 +46,9 @@ const ExecClientCard = ({ name, icon, isComingSoon }: ExecClientCardProps) => {
|
|||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: '3px',
|
||||
padding: '3px 6px',
|
||||
borderRadius: '67px',
|
||||
width: '50%',
|
||||
width: 'fit-content',
|
||||
}}
|
||||
>
|
||||
<Text size={11} color="#fff">
|
||||
|
|
|
@ -7,8 +7,12 @@ import LinkWithArrow from '../../../../components/General/LinkWithArrow'
|
|||
|
||||
const ValidatorSetup = () => {
|
||||
return (
|
||||
<YStack style={{ width: '100%', padding: '16px 32px' }}>
|
||||
<XStack justifyContent={'space-between'}>
|
||||
<YStack
|
||||
style={{ width: '100%', padding: '26px 32px' }}
|
||||
minHeight={'65vh'}
|
||||
justifyContent={'space-between'}
|
||||
>
|
||||
<XStack justifyContent={'space-between'} alignItems={'center'}>
|
||||
<Text size={27} weight={'semibold'}>
|
||||
Validator Setup
|
||||
</Text>
|
||||
|
@ -21,7 +25,7 @@ const ValidatorSetup = () => {
|
|||
Execution Client Detection
|
||||
</Text>
|
||||
</Stack>
|
||||
<Text size={15} weight={'regular'}>
|
||||
<Text size={15}>
|
||||
No existing execution client installations have been detected on paired device.
|
||||
</Text>
|
||||
<Text size={13} color="#828282">
|
||||
|
@ -30,7 +34,7 @@ const ValidatorSetup = () => {
|
|||
</Text>
|
||||
</YStack>
|
||||
|
||||
<TextTam fontSize={27} style={{ margin: '5px', marginLeft: 0 }}>
|
||||
<TextTam fontSize={27} style={{ marginTop: '15px', marginLeft: 0, marginBottom: '15px' }}>
|
||||
Select Execution client
|
||||
</TextTam>
|
||||
<XStack justifyContent={'space-between'}>
|
||||
|
@ -43,7 +47,7 @@ const ValidatorSetup = () => {
|
|||
<LinkWithArrow
|
||||
to="/"
|
||||
text="View Execution client comparison chart"
|
||||
style={{ marginTop: '3%' }}
|
||||
style={{ marginTop: '6%', fontWeight: 'bold' }}
|
||||
/>
|
||||
</YStack>
|
||||
)
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
.gradient-wrapper:after {
|
||||
display: block;
|
||||
content: "";
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(to bottom, rgba(113, 64, 253, 0.075) 15%, rgba(255,255,255,0) 50%);
|
||||
}
|
||||
background: linear-gradient(to bottom, rgba(113, 64, 253, 0.075) 15%, rgba(255, 255, 255, 0) 50%);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||
|
||||
interface SidebarButton {
|
||||
id: string
|
||||
isDotOn: boolean
|
||||
isSelected: boolean
|
||||
isDisabled?: boolean
|
||||
|
||||
}
|
||||
|
||||
interface LeftSidebarState {
|
||||
buttons: SidebarButton[]
|
||||
}
|
||||
|
||||
const initialState: LeftSidebarState = {
|
||||
buttons: [
|
||||
{ id: 'dashboard', isDotOn: false, isSelected: true },
|
||||
{ id: 'speed', isDotOn: false, isSelected: false },
|
||||
{ id: 'chart', isDotOn: false, isSelected: false, isDisabled: true },
|
||||
{ id: 'heart', isDotOn: false, isSelected: false },
|
||||
{ id: 'codeBlock', isDotOn: false, isSelected: false },
|
||||
{ id: 'communities', isDotOn: false, isSelected: false },
|
||||
{ id: 'activityCenter', isDotOn: true, isSelected: false },
|
||||
{ id: 'settings', isDotOn: false, isSelected: false },
|
||||
],
|
||||
}
|
||||
|
||||
const leftSidebarSlice = createSlice({
|
||||
name: 'leftSidebar',
|
||||
initialState,
|
||||
reducers: {
|
||||
toggleButtonSelection: (state, action: PayloadAction<string>) => {
|
||||
state.buttons.forEach(button => {
|
||||
button.isSelected = button.id === action.payload
|
||||
})
|
||||
},
|
||||
toggleDot: (state, action: PayloadAction<string>) => {
|
||||
const button = state.buttons.find(button => button.id === action.payload)
|
||||
if (button) button.isDotOn = !button.isDotOn
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export const { toggleButtonSelection, toggleDot } = leftSidebarSlice.actions
|
||||
|
||||
export default leftSidebarSlice.reducer
|
|
@ -4,6 +4,7 @@ import pinnedMessageReducer from './PinnedMessage/slice'
|
|||
import execClientReducer from './ValidatorOnboarding/ValidatorSetup/slice'
|
||||
import themeReducer from './theme/slice'
|
||||
import keyGenerationReducer from './ValidatorOnboarding/KeyGeneration/slice'
|
||||
import leftSidebarReducer from './Sidebars/slice'
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
|
@ -12,6 +13,7 @@ const store = configureStore({
|
|||
execClient: execClientReducer,
|
||||
theme: themeReducer,
|
||||
keyGeneration: keyGenerationReducer,
|
||||
leftSidebar: leftSidebarReducer,
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
@ -26,13 +26,13 @@ export const convertSecondsToTimerFormat = (seconds: number) => {
|
|||
}
|
||||
|
||||
export const formatNumbersWithComa = (n: number): string => {
|
||||
const parts = n.toString().split('.');
|
||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
return parts.join('.');
|
||||
};
|
||||
const parts = n.toString().split('.')
|
||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||
return parts.join('.')
|
||||
}
|
||||
|
||||
export const getMonthIndicesFromRange = (range: DateRange) => {
|
||||
if (!range.from || !range.to) return [0, 11]
|
||||
|
||||
return [range.from.getMonth(), range.to.getMonth()]
|
||||
}
|
||||
}
|
||||
|
|