diff --git a/package-lock.json b/package-lock.json index b35f0fb..1740776 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "framer-motion": "^11.0.20", "gsap": "^3.12.5", "lumina-node-wasm": "file:app/packages/lumina-node-wasm", + "mobx-react-lite": "^4.0.7", "next": "^14.0.2", "next-image-export-optimizer": "^1.12.3", "next-transpile-modules": "^10.0.1", @@ -3981,6 +3982,40 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mobx": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.12.3.tgz", + "integrity": "sha512-c8NKkO4R2lShkSXZ2Ongj1ycjugjzFFo/UswHBnS62y07DMcTc9Rvo03/3nRyszIvwPNljlkd4S828zIBv/piw==", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + } + }, + "node_modules/mobx-react-lite": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-4.0.7.tgz", + "integrity": "sha512-RjwdseshK9Mg8On5tyJZHtGD+J78ZnCnRaxeQDSiciKVQDUbfZcXhmld0VMxAwvcTnPEHZySGGewm467Fcpreg==", + "dependencies": { + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.9.0", + "react": "^16.8.0 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", diff --git a/package.json b/package.json index 942e575..2a2bfe2 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "framer-motion": "^11.0.20", "gsap": "^3.12.5", "lumina-node-wasm": "file:app/packages/lumina-node-wasm", + "mobx-react-lite": "^4.0.7", "next": "^14.0.2", "next-image-export-optimizer": "^1.12.3", "next-transpile-modules": "^10.0.1", diff --git a/public/cfg.json b/public/cfg.json index b810333..55ea878 100644 --- a/public/cfg.json +++ b/public/cfg.json @@ -1,5 +1,5 @@ { - "network":0, - "bootnodes":["/dns4/lumina.eiger.co/udp/2121/quic-v1/webtransport/p2p/12D3KooW9z4jLqwodwNRcSa5qgcSgtJ13kN7CYLcwZQjPRYodqWx"], - "genesis_hash":"6BE39EFD10BA412A9DB5288488303F5DD32CF386707A5BEF33617F4C43301872" + "network": 0, + "bootnodes": ["/dns4/lumina.eiger.co/udp/2121/quic-v1/webtransport/p2p/12D3KooW9z4jLqwodwNRcSa5qgcSgtJ13kN7CYLcwZQjPRYodqWx"], + "genesis_hash": "6BE39EFD10BA412A9DB5288488303F5DD32CF386707A5BEF33617F4C43301872" } \ No newline at end of file diff --git a/public/lumina.svg b/public/lumina.svg new file mode 100644 index 0000000..4d15b13 --- /dev/null +++ b/public/lumina.svg @@ -0,0 +1,971 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/parts/Form/Input/index.jsx b/src/parts/Form/Input/index.jsx index fd1e28c..d59370f 100644 --- a/src/parts/Form/Input/index.jsx +++ b/src/parts/Form/Input/index.jsx @@ -6,18 +6,22 @@ import React from 'react'; // Styles // ------------ -import { Jacket } from './styles'; +import { Jacket, Field } from './styles'; // Component // ------------ const Input = ({ + name, value, onChange, placeholder, type = 'text', + light, }) => { return ( - + + + ); } diff --git a/src/parts/Form/Input/styles.js b/src/parts/Form/Input/styles.js index 254a9eb..4ceee0e 100644 --- a/src/parts/Form/Input/styles.js +++ b/src/parts/Form/Input/styles.js @@ -5,10 +5,21 @@ import { bp } from '@tackl'; // Exports // ------------ -export const Jacket = styled.input( +export const Jacket = styled.div( props => css` position: relative; width: 100%; - padding: 1.2rem; + padding: .3rem; + border-radius: .6rem; + border: 1px solid ${props.theme.colors.brand.bc1}; ` ); + +export const Field = styled.input(props => css` + position: relative; + width: 100%; + padding: 1.2rem; + border-radius: .6rem; + background: ${props.$light ? props.theme.colors.global.black05 : props.theme.colors.global.white10}; + color: ${props.$light ? props.theme.colors.global.black : props.theme.colors.brand.bc2}; +`); diff --git a/src/parts/Form/index.jsx b/src/parts/Form/index.jsx index b35fcec..093cb5c 100644 --- a/src/parts/Form/index.jsx +++ b/src/parts/Form/index.jsx @@ -2,25 +2,22 @@ // Imports // ------------ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, use } from 'react'; import init, { Node, NodeConfig } from '@package/lumina-node-wasm'; import Input from './Input'; import Button from '@parts/Button'; +import Icon from '@icon'; import { Grid } from '@waffl'; // Styles // ------------ -import { Jacket, Container, Title, } from './styles'; +import { Blanket, Jacket, ImageContainer, Container, Title, NetworkList, NetworkItem, StatsItem, Col, } from './styles'; // Component // ------------ const Form = () => { const [node, setNode] = useState(null); const [config, setConfig] = useState({}); - const [peerId, setPeerId] = useState(''); - const [syncInfo, setSyncInfo] = useState(''); - const [connectedPeers, setConnectedPeers] = useState([]); - const [networkHead, setNetworkHead] = useState(null); const [begin, setBegin] = useState(false); const [go, setGo] = useState(false); const [modalOpen, setModalOpen] = useState({ @@ -28,6 +25,15 @@ const Form = () => { modal2: false, }); + const [stats, setStats] = useState({ + peerId: '', + syncInfo: '', + connectedPeers: [], + networkHeadHeight: '', + networkHeadHash: '', + networkHeadDataSquare: '', + }); + // NOTE • Initialisation const fetchConfig = async () => { try { @@ -51,10 +57,10 @@ const Form = () => { useEffect(() => { const loadConfig = async () => { - const config = await fetchConfig(); - if (config) { - // console.log('Setting config to state:', config); // Debugging - setConfig(config); + const tempConfig = await fetchConfig(); + if (tempConfig) { + // console.log('Setting config to state:', tempConfig); // Debugging + setConfig(tempConfig); } }; @@ -70,17 +76,19 @@ const Form = () => { const interval = setInterval(async () => { if (node) { const info = await node.syncer_info(); - setSyncInfo(`${info.local_head}/${info.subjective_head}`); - + const peers = await node.connected_peers(); - setConnectedPeers(peers); const head = node.get_network_head_header(); if (head) { - setNetworkHead({ - height: head.header.height, - hash: head.commit.block_id.hash, - dataSquare: `${head.dah.row_roots.length}x${head.dah.column_roots.length} shares`, + + setStats({ + ...stats, + syncInfo: `${info.local_head}/${info.subjective_head}`, + connectedPeers: peers, + networkHeadHeight: head.header.height, + networkHeadHash: head.commit.block_id.hash, + networkHeadDataSquare: `${head.dah.row_roots.length}x${head.dah.column_roots.length} shares`, }); } } @@ -88,26 +96,6 @@ const Form = () => { return () => clearInterval(interval); }, [node]); - const startNode = async () => { - setGo(true); - - if (!config.genesis_hash || !config.bootnodes || config.bootnodes.length === 0) { - alert('Genesis hash and at least one bootnode are required.'); - return; - } - try { - let anotherConfig = config; - setConfig({genesis_hash: config.genesis_hash, bootnodes: config.bootnodes}); - - const newNode = await new Node(anotherConfig); - // console.log("Node initialized successfully:", newNode); - setNode(newNode); - setPeerId(await newNode.local_peer_id()); - } catch (error) { - console.error("Error initializing Node:", error); - } - }; - const handleGhash = (e) => { setConfig({ ...config, @@ -132,8 +120,55 @@ const Form = () => { }); } + const handleNetwork = (e) => { + setConfig({ + ...config, + network: Number(e) + }); + } + + const handleInput = (e) => { + setStats({ + ...stats, + [e.target.name]: e.target.value + }); + } + + const startNode = async () => { + setGo(true); + setModalOpen(prev => { + return { + ...prev, + modal2: true, + } + }); + + if (!config.genesis_hash || !config.bootnodes || config.bootnodes.length === 0) { + alert('Genesis hash and at least one bootnode are required.'); + return; + } + try { + let anotherConfig = config; + setConfig({genesis_hash: config.genesis_hash, bootnodes: config.bootnodes}); + + const newNode = await new Node(anotherConfig); + + setNode(newNode); + + setStats({ + peerId: await newNode.local_peer_id(), + }); + } catch (error) { + console.error("Error initializing Node:", error); + } + }; + return ( - <> + + + Lumina Logo + + Ready to get started? @@ -143,60 +178,116 @@ const Form = () => { + Let's go! +

Network

- + + + + + + + + + + +

Genesis Hash

- - {/* {config?.genesis_hash ? config?.genesis_hash : `Loading...`} */} + + {/* {config.genesis_hash ? config.genesis_hash : `Loading...`} */}

Bootnodes

- +
-
- + -

Status

- -
- PeerId: - {peerId} -
+ + + Status -
- Synchronizing headers: - {syncInfo} -
+ + + + + + + + + + + + + + + + + -
- Network Head: -
- Height: {networkHead?.height} - Hash: {networkHead?.hash} - Data Square: {networkHead?.dataSquare} -
-
+ + + + + + + + + + + + + + + + + + + + VFX + +
-
- Peers: -
    - {connectedPeers?.map((peer, index) => ( -
  • {peer}
  • - ))} -
-
+ {/* // TODO • Visualisation to be a random square of data in first version */}
- +
); }; diff --git a/src/parts/Form/styles.js b/src/parts/Form/styles.js index 9c58220..f27653f 100644 --- a/src/parts/Form/styles.js +++ b/src/parts/Form/styles.js @@ -5,11 +5,18 @@ import { bp, Section, Div, H3 } from '@tackl'; // Exports // ------------ +export const Blanket = styled(Div)(props => css` + overflow: hidden; + position: absolute; + top: 0; + width: 100%; + height: 100vh; +`); + export const Jacket = styled(Section)( props => css` position: absolute; inset: 0 2.4rem; - // padding-top: 25vh; overflow: hidden; display: flex; @@ -17,12 +24,24 @@ export const Jacket = styled(Section)( ${props.$modal === 3 && css` padding-top: 25vh; - align-items: flex-start; overflow: scroll; `} ` ); +export const ImageContainer = styled(Div)(props => css` + position: absolute; + bottom: 15vh; + left: 50%; + transform: translateX(-50%) scale(1) rotate(0deg); + + transition: all 1.2s ${props.theme.easing.bezzy}; + + ${props.$active && css` + ${bp.large` transform: translateX(-50%) scale(3) rotate(-15deg); `} + `} +`); + export const Container = styled(Div)(props => css` position: relative; @@ -63,13 +82,159 @@ export const Container = styled(Div)(props => css` transform: translateY(${props.$activated ? 0 : `100%`}); color: ${props.theme.colors.global.black}; + min-height: 80vh; ${bp.large` width: calc(100% - 7.2rem); + margin-left: 7.2rem; `} `} `); export const Title = styled(H3)(props => css` - color: ${props.theme.colors.global.white}; -`); \ No newline at end of file + color: ${props.$dark ? props.theme.colors.global.black : props.theme.colors.global.white}; + + ${props.$dark && css` margin-bottom: 3.6rem; `} +`); + +export const NetworkList = styled.ul(props => css` + position: relative; + display: flex; + flex-direction: row; + gap: .1rem; + + border-radius: .6rem; + border: 1px solid ${props.theme.colors.brand.bc1}; + padding: .4rem; +`); + +export const NetworkItem = styled.li(props => css` + position: relative; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + width: 100%; + + background: ${props.theme.colors.global.white10}; + overflow: hidden; + + transition: all .4s ${props.theme.easing.bezzy}; + + &:hover { + background: ${props.theme.colors.global.white20}; + } + + label { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + gap: .6rem; + + padding: 1.2rem 2.4rem; + width: 100%; + + svg { + width: 0; + fill: ${props.theme.colors.global.white}; + transform: scale(0); + transition: all .2s ${props.theme.easing.bezzy}; + } + + &:hover { + cursor: pointer; + } + } + + input { + display: none; + } + + &:first-child { + border-radius: .6rem 0 0 .6rem; + } + + &:last-child { + border-radius: 0 .6rem .6rem 0; + } + + &:before { + content: ''; + position: absolute; + inset: 0; + z-index: -1; + + background: linear-gradient(180deg, #CDB4DB 0%, #A2D2FF 100%); + opacity: 0; + + transition: all .6s ${props.theme.easing.bezzy}; + } + + ${props.$selected && css` + &:before { + opacity: 1; + } + + label { + svg { + width: auto; + transform: scale(1); + } + } + `} + + ${props.$disabled && css` + opacity: .5; + pointer-events: none; + `} +`); + +export const StatsItem = styled.div(props => css` + position: relative; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + width: 100%; + + ${props.$block && css` margin-bottom: 3.6rem; `} + + label { + display: flex; + flex-direction: ${props.$block ? `column` : `row`}; + align-items: ${props.$block ? `flex-start` : `center`}; + justify-content: flex-start; + gap: 2.4rem; + width: 100%; + + span { + width: max-content; + min-width: max-content; + } + } + + ul { + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + gap: .3rem; + + position: relative; + width: 100%; + padding: .3rem; + border-radius: .6rem; + border: 1px solid ${props.theme.colors.brand.bc1}; + + li { + position: relative; + width: 100%; + padding: 1.2rem; + border-radius: .6rem; + background: ${props.theme.colors.global.black05}; + } + } +`); + +export const Col = styled(Div)(props => css``); \ No newline at end of file diff --git a/src/parts/Icon/index.jsx b/src/parts/Icon/index.jsx index 40d04bb..e51b5cb 100644 --- a/src/parts/Icon/index.jsx +++ b/src/parts/Icon/index.jsx @@ -142,22 +142,6 @@ const Icon = ({ type, className, onClick }) => {
); - if (type === 'check') - return ( - - - - ); - if (type === 'arrow-up-right') return ( { ); + if (type === 'check') + return ( + + + + ); + + console.error( `You've not added the correct 'type' prop to your component` ); diff --git a/src/parts/Webgl/Background/styles.js b/src/parts/Webgl/Background/styles.js index 6d3df1e..9845019 100644 --- a/src/parts/Webgl/Background/styles.js +++ b/src/parts/Webgl/Background/styles.js @@ -10,6 +10,7 @@ export const Jacket = styled(Section)( position: fixed; inset: 0; z-index: -1; + overflow: hidden; img { position: absolute; diff --git a/src/theme/index.js b/src/theme/index.js index 9b2cb25..6b00341 100644 --- a/src/theme/index.js +++ b/src/theme/index.js @@ -38,27 +38,28 @@ export const theme = { colors: { global: { white: '#ffffff', - whiteTrans: Color('#ffffff').rgb().alpha(0), - white10: Color('#ffffff').rgb().alpha(0.1), - white20: Color('#ffffff').rgb().alpha(0.2), - white30: Color('#ffffff').rgb().alpha(0.3), - white40: Color('#ffffff').rgb().alpha(0.4), - white50: Color('#ffffff').rgb().alpha(0.5), - white60: Color('#ffffff').rgb().alpha(0.6), - white70: Color('#ffffff').rgb().alpha(0.7), - white80: Color('#ffffff').rgb().alpha(0.8), - white90: Color('#ffffff').rgb().alpha(0.9), + whiteTrans: Color('#ffffff').rgb().alpha(0).string(), + white10: Color('#ffffff').rgb().alpha(0.1).string(), + white20: Color('#ffffff').rgb().alpha(0.2).string(), + white30: Color('#ffffff').rgb().alpha(0.3).string(), + white40: Color('#ffffff').rgb().alpha(0.4).string(), + white50: Color('#ffffff').rgb().alpha(0.5).string(), + white60: Color('#ffffff').rgb().alpha(0.6).string(), + white70: Color('#ffffff').rgb().alpha(0.7).string(), + white80: Color('#ffffff').rgb().alpha(0.8).string(), + white90: Color('#ffffff').rgb().alpha(0.9).string(), black: '#000000', blackTrans: Color('#000000').rgb().alpha(0), - black10: Color('#000000').rgb().alpha(0.1), - black20: Color('#000000').rgb().alpha(0.2), - black30: Color('#000000').rgb().alpha(0.3), - black40: Color('#000000').rgb().alpha(0.4), - black50: Color('#000000').rgb().alpha(0.5), - black60: Color('#000000').rgb().alpha(0.6), - black70: Color('#000000').rgb().alpha(0.7), - black80: Color('#000000').rgb().alpha(0.8), - black90: Color('#000000').rgb().alpha(0.9), + black05: Color('#000000').rgb().alpha(0.03).string(), + black10: Color('#000000').rgb().alpha(0.1).string(), + black20: Color('#000000').rgb().alpha(0.2).string(), + black30: Color('#000000').rgb().alpha(0.3).string(), + black40: Color('#000000').rgb().alpha(0.4).string(), + black50: Color('#000000').rgb().alpha(0.5).string(), + black60: Color('#000000').rgb().alpha(0.6).string(), + black70: Color('#000000').rgb().alpha(0.7).string(), + black80: Color('#000000').rgb().alpha(0.8).string(), + black90: Color('#000000').rgb().alpha(0.9).string(), }, social: { diff --git a/src/theme/waffl/index.ts b/src/theme/waffl/index.ts index d741e8f..be64301 100644 --- a/src/theme/waffl/index.ts +++ b/src/theme/waffl/index.ts @@ -73,6 +73,7 @@ export const Grid = styled.div( align-items: ${props.$isCenter ? 'center' : 'stretch'}; justify-content: ${props.$isCenter ? 'center' : 'stretch'}; max-width: ${props.$isFixed ? theme.grid.maxSize : '100%'}; + width: 100%; gap: ${props.$noGutter ? 0 : theme.grid.gutter.small}; grid-template-columns: repeat(${mobileColCount}, 1fr); padding: 0 ${noMpad};