diff --git a/src/components/actionBar/index.tsx b/src/components/actionBar/index.tsx index a54a09431..6dff432a6 100644 --- a/src/components/actionBar/index.tsx +++ b/src/components/actionBar/index.tsx @@ -62,6 +62,7 @@ function ActionBar({ children, text, onClickBack, button }: Props) { const noAccount = !defaultAccount.account; const noPassport = CHAIN_ID === Networks.BOSTROM && !passport; + // FIXME: refactor const exception = (!location.pathname.includes('/keys') && !location.pathname.includes('/drive') && @@ -87,7 +88,8 @@ function ActionBar({ children, text, onClickBack, button }: Props) { (noAccount || noPassport) && // maybe change to props exception && - !location.pathname.includes(routes.gift.path) + !location.pathname.includes(routes.gift.path) && + !location.pathname.includes('/brain') // both full and robot ) { return ( @@ -103,7 +105,8 @@ function ActionBar({ children, text, onClickBack, button }: Props) { if ( !signerReady && exception && - !location.pathname.includes(routes.gift.path) + !location.pathname.includes(routes.gift.path) && + !location.pathname.includes('/brain') // both full and robot ) { const activeAddress = defaultAccount.account?.cyber.name || diff --git a/src/components/appMenu/SubMenu/SubMenu.tsx b/src/components/appMenu/SubMenu/SubMenu.tsx index c2f2778c9..19a51acbe 100644 --- a/src/components/appMenu/SubMenu/SubMenu.tsx +++ b/src/components/appMenu/SubMenu/SubMenu.tsx @@ -2,6 +2,7 @@ import { NavLink } from 'react-router-dom'; import { MenuItem } from 'src/types/menu'; import cx from 'classnames'; import { useMemo } from 'react'; +import { checkIsEmoji } from 'src/utils/emoji'; import styles from './SubMenu.module.scss'; interface Props { @@ -39,8 +40,19 @@ function SubMenu({ selectedApp, closeMenu }: Props) { } onClick={closeMenu} > + {/* // clean */} {item.icon && ( - icon + <> + {checkIsEmoji(item.icon) ? ( + {item.icon} + ) : ( + {`${item.name} + )} + )} {item.name} diff --git a/src/components/valueImg/imgDenom.tsx b/src/components/valueImg/imgDenom.tsx index 2b089520c..1deff2128 100644 --- a/src/components/valueImg/imgDenom.tsx +++ b/src/components/valueImg/imgDenom.tsx @@ -10,6 +10,7 @@ import tocyb from 'images/boot.png'; import boot from 'images/large-green.png'; import defaultImg from 'images/large-orange-circle.png'; import useQueueIpfsContent from 'src/hooks/useQueueIpfsContent'; +import { checkIsEmoji } from 'src/utils/emoji'; import Tooltip from '../tooltip/tooltip'; import { trimString } from '../../utils/utils'; import styles from './TextDenom.module.scss'; @@ -105,8 +106,7 @@ function ImgDenom({ } }, [coinDenom, infoDenom, fetchWithDetails, getImgFromIpfsByCid]); - // refactor - const isEmoji = imgDenom && imgDenom?.length < 3; + const isEmoji = imgDenom && checkIsEmoji(imgDenom); const img = isEmoji ? ( imgDenom diff --git a/src/components/valueImg/index.jsx b/src/components/valueImg/index.jsx index d1d0b7fad..77ba35bc9 100644 --- a/src/components/valueImg/index.jsx +++ b/src/components/valueImg/index.jsx @@ -1,3 +1,4 @@ +import { checkIsEmoji } from 'src/utils/emoji'; import { trimString } from '../../utils/utils'; import styles from './ValueImg.module.scss'; @@ -142,8 +143,7 @@ function ValueImg({ img = ibc; } - // maybe check different - const emojiIcon = img.length < 3; + const emojiIcon = checkIsEmoji(img); return (
state.pocket); const queryClient = useQueryClient(); @@ -110,6 +110,15 @@ function App() { // } // }; + // initial focus on commander + useEffect(() => { + const isGraphPages = window.location.pathname.includes('/brain'); + + if (!isGraphPages) { + dispatch(setFocus(true)); + } + }, [dispatch]); + return ( diff --git a/src/features/adviser/Adviser/Adviser.tsx b/src/features/adviser/Adviser/Adviser.tsx index 390833712..96b60aadf 100644 --- a/src/features/adviser/Adviser/Adviser.tsx +++ b/src/features/adviser/Adviser/Adviser.tsx @@ -33,6 +33,7 @@ function prepareText(text: string) { // replace emoji // TODO: RGI_Emoji can be used in ECMAScript 2024 soon + // FIXME: use utils/emoji.ts t = t.replace( /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F700}-\u{1F77F}\u{1F780}-\u{1F7FF}\u{1F800}-\u{1F8FF}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/gu, '' diff --git a/src/features/cyberlinks/CyberlinksGraph/CyberlinksGraph.tsx b/src/features/cyberlinks/CyberlinksGraph/CyberlinksGraph.tsx index 0ec2064f1..c62c50fde 100644 --- a/src/features/cyberlinks/CyberlinksGraph/CyberlinksGraph.tsx +++ b/src/features/cyberlinks/CyberlinksGraph/CyberlinksGraph.tsx @@ -204,7 +204,7 @@ function CyberlinksGraph({ data, size, minVersion }: Props) { // linkDirectionalArrowLength={10} // linkDirectionalArrowColor={() => 'rgba(9,255,13,1)'} - onNodeClick={handleNodeRightClick} + onNodeClick={!minVersion ? handleNodeRightClick : undefined} onNodeRightClick={handleNodeClick} onLinkClick={handleLinkRightClick} onLinkRightClick={handleLinkClick} diff --git a/src/features/cyberlinks/CyberlinksGraph/GraphHoverInfo/GraphHoverInfo.tsx b/src/features/cyberlinks/CyberlinksGraph/GraphHoverInfo/GraphHoverInfo.tsx index 8053a870f..f96025370 100644 --- a/src/features/cyberlinks/CyberlinksGraph/GraphHoverInfo/GraphHoverInfo.tsx +++ b/src/features/cyberlinks/CyberlinksGraph/GraphHoverInfo/GraphHoverInfo.tsx @@ -1,6 +1,6 @@ -import ContentItem from 'src/components/ContentItem/contentItem'; import { useMemo } from 'react'; import * as THREE from 'three'; +import ContentItem from 'src/components/ContentItem/contentItem'; import styles from './GraphHoverInfo.module.scss'; // fix @@ -10,7 +10,7 @@ type Props = { size: number; }; -function HoverInfo({ node, camera, size, left, top }: Props) { +function HoverInfo({ node, camera, size, left, top, right }: Props) { let l = left; let t = top; @@ -58,8 +58,10 @@ function HoverInfo({ node, camera, size, left, top }: Props) { style={{ top: t, left: l, + right, }} > + {/* {node.id} */}
); diff --git a/src/features/cyberlinks/GraphFullscreenBtn/GraphFullscreenBtn.module.scss b/src/features/cyberlinks/GraphFullscreenBtn/GraphFullscreenBtn.module.scss index 71fb70287..a7103d34c 100644 --- a/src/features/cyberlinks/GraphFullscreenBtn/GraphFullscreenBtn.module.scss +++ b/src/features/cyberlinks/GraphFullscreenBtn/GraphFullscreenBtn.module.scss @@ -1,2 +1,3 @@ .btn { + min-width: 100px; } diff --git a/src/features/cyberlinks/GraphFullscreenBtn/GraphFullscreenBtn.tsx b/src/features/cyberlinks/GraphFullscreenBtn/GraphFullscreenBtn.tsx index 5329e1f74..2fd55f1ee 100644 --- a/src/features/cyberlinks/GraphFullscreenBtn/GraphFullscreenBtn.tsx +++ b/src/features/cyberlinks/GraphFullscreenBtn/GraphFullscreenBtn.tsx @@ -2,14 +2,17 @@ import { PORTAL_ID } from 'src/containers/application/App'; import { useState } from 'react'; import useEventListener from 'src/hooks/dom/useEventListener'; import { Button } from 'src/components'; +import AdviserHoverWrapper from 'src/features/adviser/AdviserHoverWrapper/AdviserHoverWrapper'; import styles from './GraphFullscreenBtn.module.scss'; +import expandIcon from './images/expand.svg'; +import minimizeIcon from './images/minimize.svg'; export function useFullscreen() { const [isFullscreen, setIsFullscreen] = useState(false); - const handleFullscreenChange = () => { + function handleFullscreenChange() { setIsFullscreen(document.fullscreenElement !== null); - }; + } useEventListener('fullscreenchange', handleFullscreenChange, document); @@ -51,10 +54,14 @@ function GraphFullscreenBtn() { } } + const text = isFullscreen ? 'Exit Fullscreen' : 'Enter Fullscreen'; + return ( - + + + ); } diff --git a/src/features/cyberlinks/GraphFullscreenBtn/images/expand.svg b/src/features/cyberlinks/GraphFullscreenBtn/images/expand.svg new file mode 100644 index 000000000..e189371b3 --- /dev/null +++ b/src/features/cyberlinks/GraphFullscreenBtn/images/expand.svg @@ -0,0 +1,120 @@ + + + 0-atoms/images/20x20/move-expand-fullscreen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/features/cyberlinks/GraphFullscreenBtn/images/minimize.svg b/src/features/cyberlinks/GraphFullscreenBtn/images/minimize.svg new file mode 100644 index 000000000..308507656 --- /dev/null +++ b/src/features/cyberlinks/GraphFullscreenBtn/images/minimize.svg @@ -0,0 +1,130 @@ + + + 0-atoms/images/20x20/move-minimize-fullscreen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/features/cyberlinks/GraphNew/GraphNew.tsx b/src/features/cyberlinks/GraphNew/GraphNew.tsx index e15ed251f..9b585d60e 100644 --- a/src/features/cyberlinks/GraphNew/GraphNew.tsx +++ b/src/features/cyberlinks/GraphNew/GraphNew.tsx @@ -1,5 +1,4 @@ -import { scaleSymlog } from 'd3-scale'; -import { useState, useRef, useMemo, useEffect } from 'react'; +import { useState, useRef, useMemo, useCallback, useEffect } from 'react'; import { CosmographProvider, Cosmograph, @@ -11,13 +10,15 @@ import { Button } from 'src/components'; import useAdviserTexts from 'src/features/adviser/useAdviserTexts'; import useGraphLimit from 'src/pages/robot/Brain/useGraphLimit'; import { useLocation } from 'react-router-dom'; -import { Node } from './data'; +import { isDevEnv } from 'src/utils/dev'; +import useForceUpdate from 'src/hooks/react/useForceUpdate'; +import { scaleSymlog } from 'd3-scale'; import styles from './GraphNew.module.scss'; import { useCyberlinkWithWaitAndAdviser } from '../hooks/useCyberlink'; import GraphHoverInfo from '../CyberlinksGraph/GraphHoverInfo/GraphHoverInfo'; import GraphActionBar from '../graph/GraphActionBar/GraphActionBar'; -export default function GraphNew({ address, data, size }) { +function GraphNew({ address, data, size }) { const cosmograph = useRef(); // const histogram = useRef>(); // const timeline = useRef>(); @@ -27,10 +28,7 @@ export default function GraphNew({ address, data, size }) { const [degree, setDegree] = useState([]); - const { limit } = useGraphLimit(); - - // max 2 nodes - const [selectedNodes, setSelectedNodes] = useState([]); + const { limit, isCurvedStyle } = useGraphLimit(); const [localData, setLocalData] = useState<{ nodes: CosmosInputNode[]; @@ -40,9 +38,23 @@ export default function GraphNew({ address, data, size }) { nodes: [], }); - const [hoverNode, setHoverNode] = useState(null); - const [nodePostion, setNodePostion] = useState(null); - const [selectedNode, setSelectedNode] = useState(); + const [hoverNode, setHoverNode] = useState(); + + const { forceUpdate } = useForceUpdate(); + + useEffect(() => { + const timeoutId = setTimeout(() => { + cosmograph.current?.pause(); + }, 6000); + return () => clearTimeout(timeoutId); + }, []); + + // const onSearchSelectResult = useCallback< + // Exclude['onSelectResult'], undefined> + // >((n) => { + // setShowLabelsFor(n ? [n] : undefined); + // setSelectedNode(n); + // }, []); const scaleColor = useRef( scaleSymlog() @@ -58,65 +70,15 @@ export default function GraphNew({ address, data, size }) { } }, [degree]); - useEffect(() => { - const timeoutId = setTimeout(() => { - cosmograph.current?.pause(); - }, 5000); - - return () => clearTimeout(timeoutId); - }, []); - - // const nodeColor = useCallback( - // (n: Node, index: number) => { - // if (index === undefined) { - // return null; - // } - - // const degreeValue = degree[index]; - // if (degreeValue === undefined) { - // return null; - // } - // return scaleColor.current?.(degreeValue); - // }, - // [degree] - // ); - - // const [showLabelsFor, setShowLabelsFor] = useState( - // undefined - // ); - - // const onCosmographClick = useCallback< - // Exclude['onClick'], undefined> - // >((n) => { - // search?.current?.clearInput(); - // if (n) { - // cosmograph.current?.selectNode(n); - // setShowLabelsFor([n]); - // setSelectedNode(n); - // } else { - // cosmograph.current?.unselectNodes(); - // setShowLabelsFor(undefined); - // setSelectedNode(undefined); - // } - // }, []); - - // const onSearchSelectResult = useCallback< - // Exclude['onSelectResult'], undefined> - // >((n) => { - // setShowLabelsFor(n ? [n] : undefined); - // setSelectedNode(n); - // }, []); + const selectedNodes = cosmograph.current?.getSelectedNodes(); + console.log('selectedNodes', selectedNodes); function callback() { - cosmograph.current?.unselectNodes(); - // setShowLabelsFor(undefined); - setSelectedNode(undefined); + debugger; setLocalData({ - nodes: [ - ...localData.nodes, - ...selectedNodes.map((node) => ({ ...node, color: 'orange' })), - ], + ...localData, + links: [ ...localData.links, { @@ -126,6 +88,8 @@ export default function GraphNew({ address, data, size }) { }, ], }); + + cosmograph.current?.unselectNodes(); } const { links, nodes } = useMemo(() => { @@ -141,7 +105,7 @@ export default function GraphNew({ address, data, size }) { const links = [...data.links, ...localData.links].map((link) => { return { ...link, - width: 2.5, + width: 3.5, color: link.color || 'rgba(9,255,13,1)', }; }); @@ -163,14 +127,79 @@ export default function GraphNew({ address, data, size }) { }, [nodes.length, links.length, limit]), }); - return ( -
+ function renderInfo(node, position?: string) { + const xOffset = 100; + const toRight = position === 'right'; + + return ( + ); + } + + const handleNodeSelection = useCallback( + (node?: CosmosInputNode) => { + if (!node) { + cosmograph.current?.unselectNodes(); + forceUpdate(); + return; + } + + let newNodes = [...(selectedNodes || [])]; + + // check for duplicate + if (newNodes.find((n) => n.id === node.id)) { + newNodes = newNodes.filter((n) => n.id !== node.id); + } else if (newNodes.length < 2) { + newNodes.push(node); + } else { + newNodes = [node]; + } + + console.log('nodes to update', newNodes); + + if (newNodes.length === 0) { + cosmograph.current?.unselectNodes(); + } else { + cosmograph.current?.selectNodes(newNodes); + forceUpdate(); + } + }, + [selectedNodes, forceUpdate] + ); + + const selectedNodeIds = selectedNodes?.map((n) => n.id) || []; + + const selectedNodesToRender = selectedNodes || []; + + return ( +
+ {/* complex checks, change carefully */} + {(selectedNodesToRender[0] || hoverNode) && + renderInfo( + (hoverNode && + // (selectedNodesToRender[1] && selectedNodesToRender[1].id !== hoverNode.id)) + selectedNodesToRender.length === 0 + ? hoverNode + : false) || selectedNodesToRender[0] + )} + + {(selectedNodesToRender[1] || + (hoverNode && selectedNodesToRender.length === 1)) && + renderInfo( + (hoverNode && + // render right only if first node selected + selectedNodesToRender.length === 1 && + selectedNodesToRender[0].id !== hoverNode.id + ? hoverNode + : false) || selectedNodesToRender[1], + 'right' + )} {/* { - cosmograph.current?.pause(); - - if (node) { - // setShowLabelsFor([node]); - - // check for duplicate - - let newNodes = [...selectedNodes]; - - if (newNodes.length < 2) { - newNodes.push(node); - } else { - newNodes = [node]; - } - - setSelectedNodes(newNodes); - cosmograph.current?.selectNodes(newNodes); - } else { - cosmograph.current?.unselectNodes(); - // setShowLabelsFor(undefined); - setSelectedNodes([]); - } - }} + focusedNodeRingColor="rgba(243, 30, 30, 0.5)" + curvedLinks={isCurvedStyle} // showLabelsFor={showLabelsFor} showHoveredNodeLabel={false} nodeLabelColor="white" simulationFriction={0.95} simulationDecay={5000} + nodeGreyoutOpacity={0.35} + linkGreyoutOpacity={0.35} hoveredNodeLabelColor="white" nodeSize={(n) => n.size ?? null} // nodeColor={nodeColor} - nodeColor={(d) => d.color} + nodeColor={(d) => { + return selectedNodeIds.includes(d.id) + ? 'rgb(246, 43, 253)' + : d.color; + }} linkColor={(d) => d.color} // linkWidth={(l: Link) => l.width ?? null} // linkColor={(l: Link) => l.color ?? null} - onNodeMouseOver={(n, _, _1, e) => { - setHoverNode(n); + onClick={(node) => { + handleNodeSelection(node); - if (e) { - setNodePostion({ - x: e.clientX, - y: e.clientY, - }); + if (!cosmograph.current?.isSimulationRunning && !node) { + cosmograph.current?.restart(); + } else { + cosmograph.current?.pause(); } }} + onNodeMouseOver={(n) => { + cosmograph.current?.pause(); + setHoverNode(n); + }} onNodeMouseOut={() => { - setHoverNode(null); - setNodePostion(null); + setHoverNode(undefined); }} - showFPSMonitor={process.env.NODE_ENV === 'development'} + showFPSMonitor={isDevEnv()} /> )} -
- {selectedNode ? ( -
- {`id: ${selectedNode?.id} - value: ${selectedNode?.value}`} -
- ) : ( - <> - )} - {/*
- -
*/} -
+ {/* - + )}
); } +export default GraphNew; + type Props2 = { selectedNodes: CosmosInputNode[]; callback: () => void; diff --git a/src/hooks/react/useForceUpdate.ts b/src/hooks/react/useForceUpdate.ts new file mode 100644 index 000000000..6463f14c5 --- /dev/null +++ b/src/hooks/react/useForceUpdate.ts @@ -0,0 +1,15 @@ +import React, { useCallback } from 'react'; + +function useForceUpdate() { + const [, setTick] = React.useState(0); + + const update = useCallback(() => { + setTick((tick) => tick + 1); + }, []); + + return { + forceUpdate: update, + }; +} + +export default useForceUpdate; diff --git a/src/image/enlarge.svg b/src/image/enlarge.svg deleted file mode 100644 index d799389d4..000000000 --- a/src/image/enlarge.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/layouts/Main.tsx b/src/layouts/Main.tsx index ee3547a4d..fb2feeeac 100644 --- a/src/layouts/Main.tsx +++ b/src/layouts/Main.tsx @@ -1,45 +1,34 @@ import { useEffect, useRef, useState } from 'react'; import Header from 'src/containers/application/Header/Header'; -import { useAppDispatch } from 'src/redux/hooks'; import { routes } from 'src/routes'; import { useDevice } from 'src/contexts/device'; -import { setFocus } from 'src/containers/application/Header/Commander/commander.redux'; import CyberlinksGraphContainer from 'src/features/cyberlinks/CyberlinksGraph/CyberlinksGraphContainer'; import TimeFooter from 'src/features/TimeFooter/TimeFooter'; import { Networks } from 'src/types/networks'; import { CHAIN_ID } from 'src/constants/config'; -import { Link, useLocation } from 'react-router-dom'; +import { Link } from 'react-router-dom'; import CircularMenu from 'src/components/appMenu/CircularMenu/CircularMenu'; import TimeHistory from 'src/features/TimeHistory/TimeHistory'; import MobileMenu from 'src/components/appMenu/MobileMenu/MobileMenu'; import useCurrentAddress from 'src/hooks/useCurrentAddress'; -import { BrainBtn } from 'src/pages/oracle/landing/OracleLanding'; import graphDataPrepared from '../pages/oracle/landing/graphDataPrepared.json'; import stylesOracle from '../pages/oracle/landing/OracleLanding.module.scss'; import SenseButton from '../features/sense/ui/SenseButton/SenseButton'; import styles from './Main.module.scss'; import SideHydrogenBtn from './ui/SideHydrogenBtn/SideHydrogenBtn'; -// TODO: seems merge with App.tsx +// TODO: seems merge with App.tsx, not reusing function MainLayout({ children }: { children: JSX.Element }) { const currentAddress = useCurrentAddress(); const { viewportWidth } = useDevice(); const ref = useRef(null); - const dispatch = useAppDispatch(); const [isRenderGraph, setIsRenderGraph] = useState(false); const graphSize = Math.min(viewportWidth * 0.13, 220); const isMobile = viewportWidth <= Number(stylesOracle.mobileBreakpoint.replace('px', '')); - const location = useLocation(); - - // TODO: move setFocus to App.tsx, not layout useEffect(() => { - if (location.pathname.includes('brain')) { - dispatch(setFocus(true)); - } - const timeout = setTimeout(() => { setIsRenderGraph(true); }, 1000 * 1.5); @@ -47,9 +36,7 @@ function MainLayout({ children }: { children: JSX.Element }) { return () => { clearTimeout(timeout); }; - // location is not needed, only initial render - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [dispatch]); + }, []); useEffect(() => { if (!ref.current) { @@ -83,8 +70,6 @@ function MainLayout({ children }: { children: JSX.Element }) { className={stylesOracle.graphWrapper} style={{ bottom: '0px' }} > - - {isRenderGraph && ( - ); -} diff --git a/src/pages/robot/Brain/useGraphLimit.ts b/src/pages/robot/Brain/useGraphLimit.ts index 44386e2d0..be7b5e1ca 100644 --- a/src/pages/robot/Brain/useGraphLimit.ts +++ b/src/pages/robot/Brain/useGraphLimit.ts @@ -1,23 +1,38 @@ -import { useEffect } from 'react'; +import { useCallback, useEffect } from 'react'; import { useSearchParams } from 'react-router-dom'; -const DEFAULT_LIMIT = 20000; +const DEFAULT_LIMIT = 10000; +// WIP function useGraphLimit(initialLimit?: number) { const [searchParams, setSearchParams] = useSearchParams(); const limit = Number(searchParams.get('limit')) || initialLimit || DEFAULT_LIMIT; + const style = searchParams.get('style'); + + const addLimit = useCallback( + (limit: number) => { + setSearchParams((prev) => { + const next = new URLSearchParams(prev); + next.set('limit', String(limit)); + return next; + }); + }, + [setSearchParams] + ); + useEffect(() => { - setSearchParams({ limit }); - }, [limit]); + addLimit(limit); + }, [limit, addLimit]); return { limit, + isCurvedStyle: style === 'curved', setSearchParams, setLimit: (limit: number) => { - setSearchParams({ limit }); + addLimit(limit); }, }; } diff --git a/src/router.tsx b/src/router.tsx index 9bf28dd35..6fb8b776a 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -54,11 +54,11 @@ import OracleLanding from './pages/oracle/landing/OracleLanding'; import Learn from './pages/oracle/Learn/Learn'; import ToOracleAsk from './pages/redirects/ToOracleAsk'; import Social from './pages/Social/Social'; -import Brain from './pages/Brain/Brain'; import Cybernet from './features/cybernet/ui/Cybernet'; import Settings from './pages/Settings/Settings'; import FreestyleIde from './pages/robot/Soul/RuneEditor/FreestyleIde/FreestyleIde'; import Map from './pages/Portal/Map/Map'; +import BrainRoutes from './routing/Brain'; import StudioWrapper from './features/studio/StudioWrapper'; type WrappedRouterProps = { @@ -107,11 +107,6 @@ function RedirectToRobot() { return ; } -function RedirectToRobotBrain() { - const params = useParams(); - return ; -} - function AppRouter() { return ( @@ -165,11 +160,7 @@ function AppRouter() { } /> } /> - {['/graph', '/brain'].map((path) => ( - } /> - ))} - - } /> + {BrainRoutes()} } /> diff --git a/src/routing/Brain.tsx b/src/routing/Brain.tsx new file mode 100644 index 000000000..638d8ea8d --- /dev/null +++ b/src/routing/Brain.tsx @@ -0,0 +1,20 @@ +import { useParams, Navigate, Route } from 'react-router-dom'; +import Brain from 'src/pages/Brain/Brain'; +import { routes } from 'src/routes'; + +function RedirectToRobotBrain() { + const params = useParams(); + return ; +} + +function BrainRoutes() { + return ( + <> + } /> + } /> + } /> + + ); +} + +export default BrainRoutes; diff --git a/src/utils/appsMenu/appsMenu.ts b/src/utils/appsMenu/appsMenu.ts index f7f5a6bc9..65dc582eb 100644 --- a/src/utils/appsMenu/appsMenu.ts +++ b/src/utils/appsMenu/appsMenu.ts @@ -42,6 +42,11 @@ const getMenuItems = () => { to: '/particles', icon: require('./images/tag@2x.png'), }, + { + name: 'brain', + to: routes.brain.path, + icon: '🧠', + }, { name: 'Stats', to: '/oracle/stats', diff --git a/src/utils/emoji.ts b/src/utils/emoji.ts new file mode 100644 index 000000000..b1e73002c --- /dev/null +++ b/src/utils/emoji.ts @@ -0,0 +1,4 @@ +export function checkIsEmoji(emoji: string): boolean { + // improve + return emoji.length < 3; +}