Merge pull request #65 from nimbus-gui/main
feat: emoji picker, flow between pages
This commit is contained in:
commit
7d4180f5cb
|
@ -1,4 +1,4 @@
|
||||||
name: 'Deploy Storybook'
|
name: 'Deployment'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
@ -69,3 +69,9 @@ jobs:
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
id: deployment
|
id: deployment
|
||||||
uses: actions/deploy-pages@v2
|
uses: actions/deploy-pages@v2
|
||||||
|
- name: Pull Vercel configuration
|
||||||
|
run: yarn vercel pull --yes --token ${{ secrets.vercel_token }}
|
||||||
|
- name: Build Vercel bundle
|
||||||
|
run: yarn vercel build --prod
|
||||||
|
- name: Deploy to Vercel
|
||||||
|
run: yarn vercel deploy --prebuilt --prod --token ${{ secrets.vercel_token }}
|
|
@ -1,6 +1,14 @@
|
||||||
name: 'UI tests'
|
name: 'UI tests'
|
||||||
|
|
||||||
on: push
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '*'
|
||||||
|
- '!main'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
deployments: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
cache-dependencies:
|
cache-dependencies:
|
||||||
|
@ -22,11 +30,16 @@ jobs:
|
||||||
if: steps.yarn-cache.outputs.cache-hit != 'true'
|
if: steps.yarn-cache.outputs.cache-hit != 'true'
|
||||||
run: yarn
|
run: yarn
|
||||||
|
|
||||||
build:
|
build-and-deploy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: cache-dependencies
|
needs: cache-dependencies
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- name: Get PR number
|
||||||
|
id: pull_request
|
||||||
|
run: echo "::set-output name=number::$(gh pr view --json number -q .number || echo "")"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: '18.x'
|
node-version: '18.x'
|
||||||
|
@ -42,6 +55,65 @@ jobs:
|
||||||
${{ runner.os }}-yarn-v3
|
${{ runner.os }}-yarn-v3
|
||||||
- name: Build
|
- name: Build
|
||||||
run: yarn build
|
run: yarn build
|
||||||
|
- name: Pull Vercel configuration
|
||||||
|
run: yarn vercel pull --yes --token ${{ secrets.vercel_token }}
|
||||||
|
- name: Build Vercel bundle
|
||||||
|
run: yarn vercel build
|
||||||
|
- name: Deploy to Vercel
|
||||||
|
run: yarn vercel deploy --prebuilt --token ${{ secrets.vercel_token }} > _vercel-deployment-url
|
||||||
|
- name: Comment on PR with deployment URL
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const fs = require('fs');
|
||||||
|
const deploymentUrl = fs.readFileSync('_vercel-deployment-url', 'utf8');
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
issue_number: ${{ steps.pull_request.outputs.number }},
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
body: `Deployed to ${deploymentUrl}`,
|
||||||
|
});
|
||||||
|
- name: Add deployment to PR
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
id: deployment
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const fs = require('fs');
|
||||||
|
const deploymentUrl = fs.readFileSync('_vercel-deployment-url', 'utf8');
|
||||||
|
const deployment = await github.rest.repos.createDeployment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
ref: context.sha,
|
||||||
|
environment: 'preview',
|
||||||
|
transient_environment: true,
|
||||||
|
required_contexts: [],
|
||||||
|
auto_merge: false,
|
||||||
|
production_environment: false,
|
||||||
|
payload: JSON.stringify({
|
||||||
|
deploymentUrl,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
console.log("::set-output name=deployment_id::" + deployment.data.id);
|
||||||
|
- name: Add deployment status to PR
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const fs = require('fs');
|
||||||
|
const deploymentUrl = fs.readFileSync('_vercel-deployment-url', 'utf8');
|
||||||
|
await github.rest.repos.createDeploymentStatus({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
deployment_id: ${{ steps.deployment.outputs.deployment_id }},
|
||||||
|
state: 'success',
|
||||||
|
environment_url: deploymentUrl,
|
||||||
|
log_url: deploymentUrl,
|
||||||
|
description: 'Deployed to Vercel',
|
||||||
|
environment: 'preview',
|
||||||
|
auto_inactive: true,
|
||||||
|
});
|
||||||
|
|
||||||
interaction-and-and-accessibility:
|
interaction-and-and-accessibility:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -70,3 +142,4 @@ jobs:
|
||||||
npx concurrently -k -s first -n "SB,TEST" -c "magenta,blue" \
|
npx concurrently -k -s first -n "SB,TEST" -c "magenta,blue" \
|
||||||
"npx http-server storybook-static --port 6006 --silent" \
|
"npx http-server storybook-static --port 6006 --silent" \
|
||||||
"npx wait-on tcp:127.0.0.1:6006 && yarn test-storybook"
|
"npx wait-on tcp:127.0.0.1:6006 && yarn test-storybook"
|
||||||
|
|
||||||
|
|
|
@ -33,3 +33,6 @@ dist-ssr
|
||||||
!.yarn/versions
|
!.yarn/versions
|
||||||
/.tamagui/
|
/.tamagui/
|
||||||
/storybook-static/
|
/storybook-static/
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
/.vercel
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# React + TypeScript + Vite
|
# nimbus-gui
|
||||||
|
|
||||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
"@tamagui/vite-plugin": "1.36.4",
|
"@tamagui/vite-plugin": "1.36.4",
|
||||||
"@types/react": "18",
|
"@types/react": "18",
|
||||||
"@types/react-dom": "18",
|
"@types/react-dom": "18",
|
||||||
|
"emoji-picker-react": "^4.4.11",
|
||||||
"expo-modules-core": "^1.5.9",
|
"expo-modules-core": "^1.5.9",
|
||||||
"react": "18",
|
"react": "18",
|
||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
|
@ -63,6 +64,7 @@
|
||||||
"storybook": "^7.2.0",
|
"storybook": "^7.2.0",
|
||||||
"storybook-addon-react-router-v6": "^2.0.5",
|
"storybook-addon-react-router-v6": "^2.0.5",
|
||||||
"typescript": "^5.0.2",
|
"typescript": "^5.0.2",
|
||||||
|
"vercel": "^32.0.1",
|
||||||
"vite": "^4.4.9"
|
"vite": "^4.4.9"
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@3.6.1"
|
"packageManager": "yarn@3.6.1"
|
||||||
|
|
21
src/App.tsx
21
src/App.tsx
|
@ -1,4 +1,4 @@
|
||||||
import { TamaguiProvider } from 'tamagui'
|
import { TamaguiProvider, Theme } from 'tamagui'
|
||||||
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
|
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
|
||||||
import { Provider as StatusProvider } from '@status-im/components'
|
import { Provider as StatusProvider } from '@status-im/components'
|
||||||
import './App.css'
|
import './App.css'
|
||||||
|
@ -8,9 +8,9 @@ import DeviceHealthCheck from './pages/DeviceHealthCheck/DeviceHealthCheck'
|
||||||
import ConnectDevicePage from './pages/ConnectDevicePage/ConnectDevicePage'
|
import ConnectDevicePage from './pages/ConnectDevicePage/ConnectDevicePage'
|
||||||
import DeviceSyncStatus from './pages/DeviceSyncStatus/DeviceSyncStatus'
|
import DeviceSyncStatus from './pages/DeviceSyncStatus/DeviceSyncStatus'
|
||||||
import PairDevice from './pages/PairDevice/PairDevice'
|
import PairDevice from './pages/PairDevice/PairDevice'
|
||||||
import { Provider as ReduxProvider } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
import PinnedNotification from './components/General/PinnedNottification'
|
import PinnedNotification from './components/General/PinnedNottification'
|
||||||
import store from './redux/store'
|
import { RootState } from './redux/store'
|
||||||
import CreateLocalNodePage from './pages/CreateLocalNodePage/CreateLocalNodePage'
|
import CreateLocalNodePage from './pages/CreateLocalNodePage/CreateLocalNodePage'
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
|
@ -36,16 +36,19 @@ const router = createBrowserRouter([
|
||||||
},
|
},
|
||||||
{ path: '/create-local-node', element: <CreateLocalNodePage /> },
|
{ path: '/create-local-node', element: <CreateLocalNodePage /> },
|
||||||
])
|
])
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
const theme = useSelector((state: RootState) => state.theme)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReduxProvider store={store}>
|
<TamaguiProvider config={config}>
|
||||||
<TamaguiProvider config={config}>
|
<StatusProvider>
|
||||||
<StatusProvider>
|
<Theme name={theme}>
|
||||||
<PinnedNotification />
|
<PinnedNotification />
|
||||||
<RouterProvider router={router} />
|
<RouterProvider router={router} />
|
||||||
</StatusProvider>
|
</Theme>
|
||||||
</TamaguiProvider>
|
</StatusProvider>
|
||||||
</ReduxProvider>
|
</TamaguiProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react'
|
||||||
|
import EmojiPickerDialog from './EmojiPickerDialog'
|
||||||
|
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: 'General/EmojiPickerDialog',
|
||||||
|
component: EmojiPickerDialog,
|
||||||
|
parameters: {
|
||||||
|
layout: 'centered',
|
||||||
|
},
|
||||||
|
tags: ['autodocs'],
|
||||||
|
} satisfies Meta<typeof EmojiPickerDialog>
|
||||||
|
|
||||||
|
export default meta
|
||||||
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
|
export const DefaultColors: Story = {
|
||||||
|
args: {emojiStyle: 'TWITTER'},
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
import EmojiPicker, {
|
||||||
|
EmojiStyle,
|
||||||
|
Theme,
|
||||||
|
EmojiClickData,
|
||||||
|
SuggestionMode,
|
||||||
|
Categories,
|
||||||
|
} from 'emoji-picker-react'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { Stack } from 'tamagui'
|
||||||
|
|
||||||
|
type EmojiStyleType = 'FACEBOOK' | 'APPLE' | 'GOOGLE' | 'TWITTER' | 'NATIVE'
|
||||||
|
|
||||||
|
function EmojiPickerDialog({ emojiStyle }: { emojiStyle: EmojiStyleType }) {
|
||||||
|
const [selectedEmoji, setSelectedEmoji] = useState<string>('')
|
||||||
|
console.log(selectedEmoji)
|
||||||
|
function onClick(emojiData: EmojiClickData) {
|
||||||
|
setSelectedEmoji(emojiData.unified)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack position="absolute" zIndex={1} left={120}>
|
||||||
|
{/* <XStack>
|
||||||
|
Your selected Emoji is:
|
||||||
|
{selectedEmoji ? (
|
||||||
|
<Emoji unified={selectedEmoji} emojiStyle={EmojiStyle.APPLE} size={22} />
|
||||||
|
) : null}
|
||||||
|
</XStack> */}
|
||||||
|
|
||||||
|
<EmojiPicker
|
||||||
|
onEmojiClick={onClick}
|
||||||
|
autoFocusSearch={false}
|
||||||
|
theme={Theme.AUTO}
|
||||||
|
height={350}
|
||||||
|
width="100%"
|
||||||
|
emojiVersion="1"
|
||||||
|
lazyLoadEmojis={false}
|
||||||
|
previewConfig={{ showPreview: false }}
|
||||||
|
suggestedEmojisMode={SuggestionMode.RECENT}
|
||||||
|
skinTonesDisabled
|
||||||
|
searchPlaceHolder="Search emojis"
|
||||||
|
emojiStyle={EmojiStyle[emojiStyle]}
|
||||||
|
categories={[
|
||||||
|
{
|
||||||
|
name: 'People',
|
||||||
|
category: Categories.SMILEYS_PEOPLE,
|
||||||
|
},
|
||||||
|
{ name: 'Animals and Nature', category: Categories.ANIMALS_NATURE },
|
||||||
|
{
|
||||||
|
name: 'Fun and Games',
|
||||||
|
category: Categories.ACTIVITIES,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Flags',
|
||||||
|
category: Categories.FLAGS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Yum Yum',
|
||||||
|
category: Categories.FOOD_DRINK,
|
||||||
|
},
|
||||||
|
{ name: 'Objects', category: Categories.OBJECTS },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default EmojiPickerDialog
|
|
@ -4,7 +4,7 @@ import { RootState } from '../../redux/store'
|
||||||
|
|
||||||
function PinnedNotification() {
|
function PinnedNotification() {
|
||||||
const pinnedMessage = useSelector((state: RootState) => state.pinnedMessage.pinnedMessage)
|
const pinnedMessage = useSelector((state: RootState) => state.pinnedMessage.pinnedMessage)
|
||||||
console.log(pinnedMessage)
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{pinnedMessage && pinnedMessage.pinned && (
|
{pinnedMessage && pinnedMessage.pinned && (
|
||||||
|
|
|
@ -2,19 +2,52 @@ import { Tag } from '@status-im/components'
|
||||||
import { XStack } from 'tamagui'
|
import { XStack } from 'tamagui'
|
||||||
import './TagContainer.css'
|
import './TagContainer.css'
|
||||||
import { ConnectionIcon, AddSmallIcon, SwapIcon } from '@status-im/icons'
|
import { ConnectionIcon, AddSmallIcon, SwapIcon } from '@status-im/icons'
|
||||||
|
import { useNavigate } from 'react-router'
|
||||||
|
|
||||||
type TagContainerProps = {
|
type TagContainerProps = {
|
||||||
selectedTag: 'pair' | 'create' | 'connect'
|
selectedTag: 'pair' | 'create' | 'connect'
|
||||||
}
|
}
|
||||||
|
|
||||||
const TagContainer = ({ selectedTag }: TagContainerProps) => {
|
const TagContainer = ({ selectedTag }: TagContainerProps) => {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
const onPressConnect = () => {
|
||||||
|
navigate('/connect-device')
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPressPair = () => {
|
||||||
|
navigate('/pair-device')
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPressCreate = () => {
|
||||||
|
navigate('/create-local-node')
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<XStack space={'$2'} alignItems="center" className="tag-container">
|
<XStack space={'$2'} alignItems="center" className="tag-container">
|
||||||
{selectedTag === 'connect' ? (
|
{selectedTag === 'connect' ? (
|
||||||
<Tag selected={selectedTag === 'connect'} icon={ConnectionIcon} label="Connect" size={32} />
|
<Tag
|
||||||
|
selected={selectedTag === 'connect'}
|
||||||
|
icon={ConnectionIcon}
|
||||||
|
label="Connect"
|
||||||
|
size={32}
|
||||||
|
onPress={onPressConnect}
|
||||||
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<Tag selected={selectedTag === 'pair'} icon={SwapIcon} label="Pair" size={32} />
|
<Tag
|
||||||
<Tag selected={selectedTag === 'create'} icon={AddSmallIcon} label="Create" size={32} />
|
selected={selectedTag === 'pair'}
|
||||||
|
icon={SwapIcon}
|
||||||
|
label="Pair"
|
||||||
|
size={32}
|
||||||
|
onPress={onPressPair}
|
||||||
|
/>
|
||||||
|
<Tag
|
||||||
|
selected={selectedTag === 'create'}
|
||||||
|
icon={AddSmallIcon}
|
||||||
|
label="Create"
|
||||||
|
size={32}
|
||||||
|
onPress={onPressCreate}
|
||||||
|
/>
|
||||||
</XStack>
|
</XStack>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
import './layout.css'
|
import './layout.css'
|
||||||
import NimbusLogoMark from '../Logos/NimbusLogoMark'
|
import NimbusLogoMark from '../Logos/NimbusLogoMark'
|
||||||
|
import { useTheme } from 'tamagui'
|
||||||
|
|
||||||
type PageWrapperShadowProps = {
|
type PageWrapperShadowProps = {
|
||||||
breadcrumbBar?: ReactNode
|
breadcrumbBar?: ReactNode
|
||||||
|
@ -15,8 +16,10 @@ const PageWrapperShadow = ({
|
||||||
rightImageLogo,
|
rightImageLogo,
|
||||||
children,
|
children,
|
||||||
}: PageWrapperShadowProps) => {
|
}: PageWrapperShadowProps) => {
|
||||||
|
const theme = useTheme()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="layout">
|
<div className="layout" style={{ backgroundColor: theme.background.val }}>
|
||||||
<section className="layout-left">
|
<section className="layout-left">
|
||||||
{breadcrumbBar}
|
{breadcrumbBar}
|
||||||
<div className="container">
|
<div className="container">
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom/client'
|
import ReactDOM from 'react-dom/client'
|
||||||
|
import { Provider as ReduxProvider } from 'react-redux'
|
||||||
import App from './App.tsx'
|
import App from './App.tsx'
|
||||||
import './index.css'
|
import './index.css'
|
||||||
|
import store from './redux/store.tsx'
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<ReduxProvider store={store}>
|
||||||
</React.StrictMode>
|
<App />
|
||||||
|
</ReduxProvider>
|
||||||
|
</React.StrictMode>,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import type { Meta, StoryObj } from '@storybook/react'
|
import type { Meta, StoryObj } from '@storybook/react'
|
||||||
|
|
||||||
import ConnectDevicePage from './ConnectDevicePage'
|
import ConnectDevicePage from './ConnectDevicePage'
|
||||||
|
import { withRouter } from 'storybook-addon-react-router-v6'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: 'Pages/ConnectDevicePage',
|
title: 'Pages/ConnectDevicePage',
|
||||||
|
@ -10,6 +11,7 @@ const meta = {
|
||||||
},
|
},
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
argTypes: {},
|
argTypes: {},
|
||||||
|
decorators: [withRouter],
|
||||||
} satisfies Meta<typeof ConnectDevicePage>
|
} satisfies Meta<typeof ConnectDevicePage>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import type { Meta, StoryObj } from '@storybook/react'
|
import type { Meta, StoryObj } from '@storybook/react'
|
||||||
|
|
||||||
import CreateLocalNodePage from './CreateLocalNodePage'
|
import CreateLocalNodePage from './CreateLocalNodePage'
|
||||||
|
import { withRouter } from 'storybook-addon-react-router-v6'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: 'Pages/CreateLocalNodePage',
|
title: 'Pages/CreateLocalNodePage',
|
||||||
|
@ -10,6 +11,7 @@ const meta = {
|
||||||
},
|
},
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
argTypes: {},
|
argTypes: {},
|
||||||
|
decorators: [withRouter],
|
||||||
} satisfies Meta<typeof CreateLocalNodePage>
|
} satisfies Meta<typeof CreateLocalNodePage>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
|
|
|
@ -7,9 +7,11 @@ import Header from '../../components/General/Header'
|
||||||
import Titles from '../../components/General/Titles'
|
import Titles from '../../components/General/Titles'
|
||||||
import LabelInputField from '../../components/General/LabelInputField'
|
import LabelInputField from '../../components/General/LabelInputField'
|
||||||
import ColorPicker from '../../components/General/ColorPicker'
|
import ColorPicker from '../../components/General/ColorPicker'
|
||||||
|
import EmojiPickerDialog from '../../components/General/EmojiPickerDialog'
|
||||||
|
|
||||||
const CreateLocalNodePage = () => {
|
const CreateLocalNodePage = () => {
|
||||||
const [autoConnectChecked, setAutoConnectChecked] = useState(false)
|
const [autoConnectChecked, setAutoConnectChecked] = useState(false)
|
||||||
|
const [isEmojiDialogOpen, setIsEmojiDialogOpen] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageWrapperShadow rightImageSrc="./background-images/day-night-bg.png" rightImageLogo={true}>
|
<PageWrapperShadow rightImageSrc="./background-images/day-night-bg.png" rightImageLogo={true}>
|
||||||
|
@ -31,7 +33,18 @@ const CreateLocalNodePage = () => {
|
||||||
</Text>
|
</Text>
|
||||||
<XStack my={10}>
|
<XStack my={10}>
|
||||||
<Avatar type="account" size={80} name="Device Avatar" />
|
<Avatar type="account" size={80} name="Device Avatar" />
|
||||||
<Avatar type="icon" size={32} icon={<ReactionIcon size={20} />} />
|
<Avatar
|
||||||
|
type="icon"
|
||||||
|
size={32}
|
||||||
|
icon={
|
||||||
|
<ReactionIcon
|
||||||
|
size={20}
|
||||||
|
onClick={() => setIsEmojiDialogOpen(prev => !prev)}
|
||||||
|
style={{ cursor: 'pointer' }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{isEmojiDialogOpen && <EmojiPickerDialog emojiStyle="TWITTER" />}
|
||||||
</XStack>
|
</XStack>
|
||||||
</YStack>
|
</YStack>
|
||||||
<YStack>
|
<YStack>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import type { Meta, StoryObj } from '@storybook/react'
|
import type { Meta, StoryObj } from '@storybook/react'
|
||||||
|
import { withRouter } from 'storybook-addon-react-router-v6'
|
||||||
|
|
||||||
import LandingPage from './LandingPage'
|
import LandingPage from './LandingPage'
|
||||||
|
|
||||||
|
@ -10,6 +11,7 @@ const meta = {
|
||||||
},
|
},
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
argTypes: {},
|
argTypes: {},
|
||||||
|
decorators: [withRouter],
|
||||||
} satisfies Meta<typeof LandingPage>
|
} satisfies Meta<typeof LandingPage>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
|
|
|
@ -6,8 +6,15 @@ import NimbusLogo from '../../components/Logos/NimbusLogo'
|
||||||
import { NodeIcon } from '@status-im/icons'
|
import { NodeIcon } from '@status-im/icons'
|
||||||
import { Button as StatusButton, Text } from '@status-im/components'
|
import { Button as StatusButton, Text } from '@status-im/components'
|
||||||
import QuickStartBar from '../../components/General/QuickStartBar/QuickStartBar'
|
import QuickStartBar from '../../components/General/QuickStartBar/QuickStartBar'
|
||||||
|
import { useNavigate } from 'react-router'
|
||||||
|
|
||||||
|
const LandingPage = () => {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
const getStartedHanlder = () => {
|
||||||
|
navigate('/pair-device')
|
||||||
|
}
|
||||||
|
|
||||||
function LandingPage() {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageWrapperShadow rightImageSrc="./background-images/landing-page-bg.png">
|
<PageWrapperShadow rightImageSrc="./background-images/landing-page-bg.png">
|
||||||
|
@ -15,17 +22,20 @@ function LandingPage() {
|
||||||
<XStack pt={'70px'}>
|
<XStack pt={'70px'}>
|
||||||
<NimbusLogo />
|
<NimbusLogo />
|
||||||
</XStack>
|
</XStack>
|
||||||
|
|
||||||
<YStack style={{ width: '100%', margin: '30vh 0 4vh' }}>
|
<YStack style={{ width: '100%', margin: '30vh 0 4vh' }}>
|
||||||
<Title>Light and performant clients, for all Ethereum validators.</Title>
|
<Title color="$textPrimary">
|
||||||
<Text size={15} weight="regular">
|
Light and performant clients, for all Ethereum validators.
|
||||||
|
</Title>
|
||||||
|
<Text size={15} weight="regular" color="$textPrimary">
|
||||||
<strong>Nimbus Nodes</strong> allows you to take control and ownership of the services
|
<strong>Nimbus Nodes</strong> allows you to take control and ownership of the services
|
||||||
you wish to run in a completely trustless and decentralized manner.
|
you wish to run in a completely trustless and decentralized manner.
|
||||||
</Text>
|
</Text>
|
||||||
</YStack>
|
</YStack>
|
||||||
|
|
||||||
<XStack>
|
<XStack>
|
||||||
<StatusButton icon={<NodeIcon size={20} />}>Get Started</StatusButton>
|
<StatusButton icon={<NodeIcon size={20} />} onPress={getStartedHanlder}>
|
||||||
|
Get Started
|
||||||
|
</StatusButton>
|
||||||
</XStack>
|
</XStack>
|
||||||
</YStack>
|
</YStack>
|
||||||
</PageWrapperShadow>
|
</PageWrapperShadow>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import type { Meta, StoryObj } from '@storybook/react'
|
import type { Meta, StoryObj } from '@storybook/react'
|
||||||
|
|
||||||
import SyncStatus from './SyncStatus'
|
import SyncStatus from './SyncStatus'
|
||||||
|
import { withRouter } from 'storybook-addon-react-router-v6'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: 'Pair Device/SyncStatus',
|
title: 'Pair Device/SyncStatus',
|
||||||
|
@ -10,6 +11,7 @@ const meta = {
|
||||||
},
|
},
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
argTypes: {},
|
argTypes: {},
|
||||||
|
decorators: [withRouter],
|
||||||
} satisfies Meta<typeof SyncStatus>
|
} satisfies Meta<typeof SyncStatus>
|
||||||
|
|
||||||
export default meta
|
export default meta
|
||||||
|
|
|
@ -7,6 +7,7 @@ import Icon from '../../components/General/Icon'
|
||||||
import ConnectionIcon from '/icons/connection.svg'
|
import ConnectionIcon from '/icons/connection.svg'
|
||||||
import { convertSecondsToTimerFormat } from '../../utilities'
|
import { convertSecondsToTimerFormat } from '../../utilities'
|
||||||
import { RefreshIcon } from '@status-im/icons'
|
import { RefreshIcon } from '@status-im/icons'
|
||||||
|
import { useNavigate } from 'react-router'
|
||||||
|
|
||||||
type SyncStatusProps = {
|
type SyncStatusProps = {
|
||||||
isPairing: boolean
|
isPairing: boolean
|
||||||
|
@ -20,11 +21,13 @@ const SyncStatus = ({
|
||||||
changeSetIsAwaitingPairing,
|
changeSetIsAwaitingPairing,
|
||||||
}: SyncStatusProps) => {
|
}: SyncStatusProps) => {
|
||||||
const [elapsedTime, setElapsedTime] = useState(0)
|
const [elapsedTime, setElapsedTime] = useState(0)
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
const resetTimer = () => {
|
const resetTimer = () => {
|
||||||
setElapsedTime(0)
|
setElapsedTime(0)
|
||||||
changeSetIsAwaitingPairing(false)
|
changeSetIsAwaitingPairing(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let timer: ReturnType<typeof setTimeout>
|
let timer: ReturnType<typeof setTimeout>
|
||||||
|
|
||||||
|
@ -42,7 +45,11 @@ const SyncStatus = ({
|
||||||
return () => clearInterval(timer)
|
return () => clearInterval(timer)
|
||||||
}, [isPairing, elapsedTime])
|
}, [isPairing, elapsedTime])
|
||||||
|
|
||||||
const timer = convertSecondsToTimerFormat(elapsedTime) // Assuming you've imported the convertSecondsToTimerFormat function
|
const timer = convertSecondsToTimerFormat(elapsedTime)
|
||||||
|
|
||||||
|
const connectViaIpHandler = () => {
|
||||||
|
navigate('/connect-device');
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<YStack space={'$2'}>
|
<YStack space={'$2'}>
|
||||||
|
@ -84,7 +91,7 @@ const SyncStatus = ({
|
||||||
)}
|
)}
|
||||||
{isAwaitingPairing && (
|
{isAwaitingPairing && (
|
||||||
<XStack>
|
<XStack>
|
||||||
<Button icon={<Icon src={ConnectionIcon} />} size={40}>
|
<Button icon={<Icon src={ConnectionIcon} />} size={40} onPress={connectViaIpHandler} >
|
||||||
Connect via IP
|
Connect via IP
|
||||||
</Button>
|
</Button>
|
||||||
</XStack>
|
</XStack>
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import { configureStore } from '@reduxjs/toolkit'
|
import { configureStore } from '@reduxjs/toolkit'
|
||||||
import deviceHealthReducer from './deviceHealthCheck/slice'
|
import deviceHealthReducer from './deviceHealthCheck/slice'
|
||||||
import pinnedMessageReducer from './PinnedMessage/slice'
|
import pinnedMessageReducer from './PinnedMessage/slice'
|
||||||
|
import themeReducer from './theme/slice'
|
||||||
|
|
||||||
const store = configureStore({
|
const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
deviceHealth: deviceHealthReducer,
|
deviceHealth: deviceHealthReducer,
|
||||||
pinnedMessage: pinnedMessageReducer,
|
pinnedMessage: pinnedMessageReducer,
|
||||||
|
theme: themeReducer,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { createSlice } from '@reduxjs/toolkit'
|
||||||
|
|
||||||
|
const initialState: 'light' | 'dark' = 'light'
|
||||||
|
|
||||||
|
const themeSlice = createSlice({
|
||||||
|
name: 'theme',
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
setTheme: (_, action) => {
|
||||||
|
return action.payload
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const { setTheme } = themeSlice.actions
|
||||||
|
|
||||||
|
export default themeSlice.reducer
|
Loading…
Reference in New Issue