Add search bar

This commit is contained in:
Nathaniel Parke 2020-11-06 16:38:38 +08:00
parent d357569029
commit fb33a2a338
8 changed files with 598 additions and 129 deletions

View File

@ -1,7 +1,7 @@
import React, {useState} from "react";
import {Select} from "antd";
import apps from "./app-list.json";
import {SearchOutlined} from "@ant-design/icons";
import React, {useRef, useState} from 'react';
import { Select, Typography } from 'antd';
import apps from './app-list.json';
import { SearchOutlined } from '@ant-design/icons';
const { Option } = Select;
@ -12,35 +12,70 @@ interface App {
tags: string[];
}
export default function AppSearch() {
export default function AppSearch(props) {
const [searchMatches, setSearchMatches] = useState<App[]>([]);
const [searchValue, setSearchValue] = useState<string | undefined>(undefined);
const matchApp = (searchString: string, app: App) => {
return app.name.toLowerCase().includes(searchString.toLowerCase());
}
const lowerSearchStr = searchString.toLowerCase();
return (
app.name.toLowerCase().includes(lowerSearchStr) ||
app.tags.some(
(tag) =>
tag.toLowerCase().includes(lowerSearchStr) ||
lowerSearchStr.includes(tag.toLowerCase()),
)
);
};
const handleSearch = (value) => {
console.log(value);
setSearchValue(value);
console.log(apps);
setSearchMatches(apps.filter(app => matchApp(value, app)));
}
setSearchValue(value === '' ? undefined : value);
const filteredApps = apps.filter((app) => matchApp(value, app));
setSearchMatches(filteredApps);
};
const options = searchMatches.map(d => <Option key={d.name} value={d.name}>{d.name}</Option>);
const handleSelect = (value, option) => {
window.open(option.href, '_blank');
handleClear();
};
const handleClear = () => {
setSearchMatches([]);
setSearchValue(undefined);
};
const options = searchMatches.map((d) => (
<Option key={d.name} value={d.name} href={d.url}>
<h3>{d.name}</h3>
<Typography.Text type="secondary">
{d.url.replace('https://', '')}
</Typography.Text>
</Option>
));
const ref = useRef<any>();
return (
<Select
ref={ref}
showSearch
allowClear
value={searchValue}
placeholder={"Search for app..."}
placeholder={props.focussed || props.focussed === undefined ? 'Search for apps...' : ''}
onSearch={handleSearch}
notFoundContent={null} // have this be your history
onClear={handleClear}
onSelect={handleSelect}
onFocus={props.onFocus}
onBlur={() => props.onBlur() && handleClear()}
notFoundContent={null} // todo: make this search history
style={{
width: '250px'
width: props.width || '300px',
transition: props.focussed ? "width 0.1s ease 0.1s" : ""
}}
suffixIcon={<SearchOutlined/>}
dropdownStyle={{
width: "300px"
}}
suffixIcon={<SearchOutlined onClick={() => ref.current && ref.current.focus()}/>}
filterOption={false}
>
{options}
</Select>

View File

@ -1,4 +1,4 @@
import {Button, Col, Divider, Popover, Row } from 'antd';
import { Button, Col, Divider, Popover, Row } from 'antd';
import React, { useState } from 'react';
import FloatingElement from './layout/FloatingElement';
import styled from 'styled-components';
@ -18,8 +18,8 @@ import { useSendConnection } from '../utils/connection';
import { notify } from '../utils/notifications';
import { Balances } from '../utils/types';
import StandaloneTokenAccountsSelect from './StandaloneTokenAccountSelect';
import LinkAddress from "./LinkAddress";
import {InfoCircleOutlined} from "@ant-design/icons";
import LinkAddress from './LinkAddress';
import { InfoCircleOutlined } from '@ant-design/icons';
const RowBox = styled(Row)`
padding-bottom: 20px;
@ -129,7 +129,7 @@ export default function StandaloneBalancesDisplay() {
([currency, balances, baseOrQuote, mint], index) => (
<React.Fragment key={index}>
<Divider style={{ borderColor: 'white' }}>
{currency}{" "}
{currency}{' '}
{mint && (
<Popover
content={<LinkAddress address={mint} />}

View File

@ -16,7 +16,7 @@ import { EndpointInfo } from '../utils/types';
import { notify } from '../utils/notifications';
import { Connection } from '@solana/web3.js';
import WalletConnect from './WalletConnect';
import AppSearch from "./AppSearch";
import AppSearch from './AppSearch';
const Wrapper = styled.div`
background-color: #0d1017;
@ -46,7 +46,7 @@ const EXTERNAL_LINKS = {
'/developer-resources': 'https://serum-academy.com/en/developer-resources/',
'/explorer': 'https://explorer.solana.com',
'/srm-faq': 'https://projectserum.com/srm-faq',
'/swap': 'https://swap.projectserum.com'
'/swap': 'https://swap.projectserum.com',
};
export default function TopBar() {
@ -62,6 +62,7 @@ export default function TopBar() {
const [testingConnection, setTestingConnection] = useState(false);
const location = useLocation();
const history = useHistory();
const [searchFocussed, setSearchFocussed] = useState(false);
const handleClick = useCallback(
(e) => {
@ -134,8 +135,8 @@ export default function TopBar() {
onClose={() => setAddEndpointVisible(false)}
/>
<Wrapper>
<LogoWrapper>
<img src={logo} alt="" onClick={() => history.push('/')} />
<LogoWrapper onClick={() => history.push('/')} >
<img src={logo} alt=""/>
{'SERUM'}
</LogoWrapper>
<Menu
@ -150,89 +151,106 @@ export default function TopBar() {
flex: 1,
}}
>
<Menu.Item key="/">TRADE</Menu.Item>
<Menu.Item key="/swap">
<a
href={EXTERNAL_LINKS['/swap']}
target="_blank"
rel="noopener noreferrer"
<Menu.Item key="/" style={{margin: "0 10px 0 20px"}}>TRADE</Menu.Item>
{!searchFocussed && (
<Menu.Item key="/swap" style={{margin: "0 10px"}}>
<a
href={EXTERNAL_LINKS['/swap']}
target="_blank"
rel="noopener noreferrer"
>
SWAP
</a>
</Menu.Item>
)}
{connected && (!searchFocussed || location.pathname === '/balances') &&
<Menu.Item key="/balances" style={{margin: "0 10px"}}>BALANCES</Menu.Item>
}
{connected && (!searchFocussed || location.pathname === '/orders') &&
<Menu.Item key="/orders" style={{margin: "0 10px"}}>ORDERS</Menu.Item>
}
{connected && (!searchFocussed || location.pathname === '/convert') &&
<Menu.Item key="/convert" style={{margin: "0 10px"}}>CONVERT</Menu.Item>
}
{(!searchFocussed || location.pathname === '/list-new-market') &&
<Menu.Item key="/list-new-market" style={{margin: "0 10px"}}>ADD MARKET</Menu.Item>
}
{!searchFocussed && (
<Menu.SubMenu
title="LEARN"
onTitleClick={() => window.open(EXTERNAL_LINKS['/learn'], '_blank')}
style={{margin: "0 0px 0 10px"}}
>
SWAP
</a>
</Menu.Item>
{connected && <Menu.Item key="/balances">BALANCES</Menu.Item>}
{connected && <Menu.Item key="/orders">ORDERS</Menu.Item>}
{connected && <Menu.Item key="/convert">CONVERT</Menu.Item>}
<Menu.Item key="/list-new-market">ADD MARKET</Menu.Item>
<Menu.SubMenu
title="LEARN"
onTitleClick={() => window.open(EXTERNAL_LINKS['/learn'], '_blank')}
>
<Menu.Item key="/add-market">
<a
href={EXTERNAL_LINKS['/add-market']}
target="_blank"
rel="noopener noreferrer"
>
Adding a market
</a>
</Menu.Item>
<Menu.Item key="/wallet-support">
<a
href={EXTERNAL_LINKS['/wallet-support']}
target="_blank"
rel="noopener noreferrer"
>
Supported wallets
</a>
</Menu.Item>
<Menu.Item key="/dex-list">
<a
href={EXTERNAL_LINKS['/dex-list']}
target="_blank"
rel="noopener noreferrer"
>
DEX list
</a>
</Menu.Item>
<Menu.Item key="/developer-resources">
<a
href={EXTERNAL_LINKS['/developer-resources']}
target="_blank"
rel="noopener noreferrer"
>
Developer resources
</a>
</Menu.Item>
<Menu.Item key="/explorer">
<a
href={EXTERNAL_LINKS['/explorer']}
target="_blank"
rel="noopener noreferrer"
>
Solana block explorer
</a>
</Menu.Item>
<Menu.Item key="/srm-faq">
<a
href={EXTERNAL_LINKS['/srm-faq']}
target="_blank"
rel="noopener noreferrer"
>
SRM FAQ
</a>
</Menu.Item>
</Menu.SubMenu>
<Menu.Item key="/add-market">
<a
href={EXTERNAL_LINKS['/add-market']}
target="_blank"
rel="noopener noreferrer"
>
Adding a market
</a>
</Menu.Item>
<Menu.Item key="/wallet-support">
<a
href={EXTERNAL_LINKS['/wallet-support']}
target="_blank"
rel="noopener noreferrer"
>
Supported wallets
</a>
</Menu.Item>
<Menu.Item key="/dex-list">
<a
href={EXTERNAL_LINKS['/dex-list']}
target="_blank"
rel="noopener noreferrer"
>
DEX list
</a>
</Menu.Item>
<Menu.Item key="/developer-resources">
<a
href={EXTERNAL_LINKS['/developer-resources']}
target="_blank"
rel="noopener noreferrer"
>
Developer resources
</a>
</Menu.Item>
<Menu.Item key="/explorer">
<a
href={EXTERNAL_LINKS['/explorer']}
target="_blank"
rel="noopener noreferrer"
>
Solana block explorer
</a>
</Menu.Item>
<Menu.Item key="/srm-faq">
<a
href={EXTERNAL_LINKS['/srm-faq']}
target="_blank"
rel="noopener noreferrer"
>
SRM FAQ
</a>
</Menu.Item>
</Menu.SubMenu>
)}
</Menu>
<div
style={{
display: 'flex',
alignItems: 'center',
paddingLeft: 5,
paddingRight: 5,
}}
>
<AppSearch/>
<AppSearch
onFocus={() => setSearchFocussed(true)}
onBlur={() => setSearchFocussed(false)}
focussed={searchFocussed}
width={searchFocussed ? "350px" : "35px"}
/>
</div>
<div>
<Row

View File

@ -21,7 +21,7 @@ import { useSendConnection } from '../utils/connection';
import FloatingElement from './layout/FloatingElement';
import { placeOrder } from '../utils/send';
import { SwitchChangeEventHandler } from 'antd/es/switch';
import {refreshCache} from "../utils/fetch-loop";
import { refreshCache } from '../utils/fetch-loop';
import tuple from 'immutable-tuple';
const SellButton = styled(Button)`
@ -222,7 +222,7 @@ export default function TradeForm({
baseCurrencyAccount: baseCurrencyAccount?.pubkey,
quoteCurrencyAccount: quoteCurrencyAccount?.pubkey,
});
refreshCache(tuple('getTokenAccounts', wallet, connected))
refreshCache(tuple('getTokenAccounts', wallet, connected));
setPrice(undefined);
onSetBaseSize(undefined);
} catch (e) {

View File

@ -12,8 +12,8 @@ import {
useTokenAccounts,
} from '../../utils/markets';
import StandaloneTokenAccountsSelect from '../StandaloneTokenAccountSelect';
import {abbreviateAddress} from "../../utils/utils";
import {PublicKey} from "@solana/web3.js";
import { abbreviateAddress } from '../../utils/utils';
import { PublicKey } from '@solana/web3.js';
export default function WalletBalancesTable({
walletBalances,
@ -80,13 +80,14 @@ export default function WalletBalancesTable({
<Row align="middle">
<a
href={`https://explorer.solana.com/address/${walletBalance.mint}`}
target={"_blank"}
target={'_blank'}
rel="noopener noreferrer"
>
{walletBalance.coin || abbreviateAddress(new PublicKey(walletBalance.mint))}
{walletBalance.coin ||
abbreviateAddress(new PublicKey(walletBalance.mint))}
</a>
</Row>
)
),
},
{
title: 'Wallet Balance',

View File

@ -1,13 +1,437 @@
[
{
"name": "BONFIDA",
"url": "https://bonfida.com/",
"name": "Bonfida",
"url": "https://bonfida.com",
"description": "A dex, wallet, and analytics ecosystem",
"tags": [
"dex",
"analytics",
"nft",
"wallet"
]
"icon": "",
"tags": ["dex", "analytics", "nft", "wallet", "token"]
},
{
"name": "Cryptocurrencies.ai",
"url": "https://dex.cryptocurrencies.ai",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "Serum Swap",
"url": "https://swap.projectserum.com",
"description": "Automated market maker swap service on Serum",
"icon": "",
"tags": ["dex", "amm", "swap", "pool"]
},
{
"name": "Token Creator",
"url": "https://spl-token-ui.netlify.app",
"description": "Create spl tokens",
"icon": "",
"tags": ["wallet", "token"]
},
{
"name": "Bonfida DEX",
"url": "https://bonfida.com/dex",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "Cryptocurrencies.Ai DEX",
"url": "https://dex.cryptocurrencies.ai/",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "Serum Today",
"url": "https://serum.today",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "Serum Pro",
"url": "https://serumpro.org",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "Folkvang.io DEX",
"url": "https://serum-mirror.folkvang.io/",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "SerumStake DEX",
"url": "https://dex.serumstakers.com",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "Tech.Ed Training",
"url": "https://serum.techedtraining.com/",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "Santosha Exchange",
"url": "https://exchange.santosha.digital",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "Pangea DEX",
"url": "https://pangeadex.com/",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "SerumDex.Exchange",
"url": "https://serumdex.exchange",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "SolFlare DEX",
"url": "https://dex.solflare.com",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "Advance Finance DEX",
"url": "https://advance.finance",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "Viralic DEX",
"url": "https://dex.viralic.io",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "Illuminati Finance",
"url": "http://illuminati.finance/serum",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "Ourord DEX",
"url": "https://dex.ourord.com",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "BallsDeep DEX",
"url": "https://serumdex.ballsdeep.me",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "TradeOnSerum DEX",
"url": "https://www.tradeonserum.com/",
"description": "",
"icon": "",
"tags": ["dex"]
},
{
"name": "YMAX DEX",
"url": "https://ymax.finance/",
"description": "",
"icon": "",
"tags": ["dex", "yield"]
},
{
"name": "Coin98",
"url": "https://coin98.app",
"description": "",
"icon": "",
"tags": ["dex", "mobile", "wallet"]
},
{
"name": "AMM Project Proposal",
"url": "https://serum-academy.com//en/serum-project-ideas/project-ideas/#amm-bots-using-pools",
"description": "",
"icon": "",
"tags": ["amm", "yield"]
},
{
"name": "Serum Swap UI Source",
"url": "https://github.com/project-serum/oyster-swap",
"description": "",
"icon": "",
"tags": ["source", "amm", "swap", "yield"]
},
{
"name": "Serum Swap Source",
"url": "https://github.com/solana-labs/solana-program-library/tree/master/token-swap",
"description": "",
"icon": "",
"tags": ["source", "amm", "swap", "yield"]
},
{
"name": "Folkvang.io Swap",
"url": "https://serum-swap.folkvang.io/",
"description": "",
"icon": "",
"tags": ["amm", "swap", "yield"]
},
{
"name": "Solible",
"url": "https://solible.com",
"description": "",
"icon": "",
"tags": ["nft", "token", "wallet"]
},
{
"name": "Sollet.io",
"url": "https://sollet.io",
"description": "",
"icon": "",
"tags": ["token", "wallet"]
},
{
"name": "Sollet.io Source",
"url": "https://github.com/project-serum/spl-token-wallet",
"description": "",
"icon": "",
"tags": ["token", "wallet", "source"]
},
{
"name": "Bonfida Wallet",
"url": "https://bonfida.com/wallet",
"description": "",
"icon": "",
"tags": ["token", "wallet"]
},
{
"name": "Bonfida Wallet Source",
"url": "https://github.com/dr497/spl-token-wallet",
"description": "",
"icon": "",
"tags": ["token", "wallet", "source"]
},
{
"name": "Math Wallet",
"url": "https://mathwallet.org",
"description": "",
"icon": "",
"tags": ["token", "wallet"]
},
{
"name": "Cryptocurrencies.ai Yield",
"url": "https://dex.cryptocurrencies.ai/rewards",
"description": "",
"icon": "",
"tags": ["yield"]
},
{
"name": "Solana Blockchain Source",
"url": "https://github.com/solana-labs/solana",
"description": "",
"icon": "",
"tags": ["solana", "source", "on-chain", "blockchain", "chain"]
},
{
"name": "Solana Program Library",
"url": "https://github.com/solana-labs/solana-program-library",
"description": "",
"icon": "",
"tags": ["solana", "source", "on-chain", "blockchain", "chain"]
},
{
"name": "Solana Web3 SDK",
"url": "https://github.com/solana-labs/solana-web3.js",
"description": "",
"icon": "",
"tags": ["solana", "source", "on-chain", "blockchain", "chain", "js"]
},
{
"name": "Solana Explorer",
"url": "https://github.com/solana-labs/solana/tree/master/explorer",
"description": "",
"icon": "",
"tags": ["solana", "explorer", "chain", "blockchain", "transaction"]
},
{
"name": "Solana Hello World",
"url": "https://github.com/solana-labs/example-helloworld",
"description": "",
"icon": "",
"tags": ["solana", "chain", "blockchain", "on-chain", "program", "source"]
},
{
"name": "Solana Technical Documentation",
"url": "https://docs.solana.com/",
"description": "",
"icon": "",
"tags": ["documentation", "docs", "solana", "blockchain", "chain", "on-chain"]
},
{
"name": "Solana Discord",
"url": "https://solana.com/discord",
"description": "",
"icon": "",
"tags": ["discord", "solana", "community"]
},
{
"name": "Solana Wormhole Source",
"url": "https://github.com/certusone/wormhole",
"description": "",
"icon": "",
"tags": ["source", "bridge", "swap", "token", "wallet"]
},
{
"name": "Solana Wormhold Description",
"url": "https://medium.com/certus-one/introducing-the-wormhole-bridge-24911b7335f7",
"description": "",
"icon": "",
"tags": ["source", "bridge", "swap", "token", "wallet"]
},
{
"name": "Solana NFT",
"url": "https://spl.solana.com/token#example-create-a-non-fungible-token",
"description": "",
"icon": "",
"tags": ["nft", "solana", "source", "documentation"]
},
{
"name": "Awesome Serum",
"url": "https://github.com/project-serum/awesome-serum",
"description": "",
"icon": "",
"tags": ["documentation", "community"]
},
{
"name": "Staking RFC",
"url": "https://github.com/project-serum/rfcs/blob/master/text/0001-registry.md",
"description": "",
"icon": "",
"tags": ["staking", "on-chain", "blockchain", "rewards", "solana", "srm", "node"]
},
{
"name": "Node RFC",
"url": "https://github.com/project-serum/rfcs/blob/master/text/0001-registry.md",
"description": "",
"icon": "",
"tags": ["node", "staking", "on-chain", "blockchain", "rewards", "governance", "solana", "srm"]
},
{
"name": "SolFlare",
"url": "https://solflare.com/",
"description": "",
"icon": "",
"tags": ["wallet", "explorer", "token"]
},
{
"name": "SolFlare Hardware Guide",
"url": "https://docs.solana.com/wallet-guide/ledger-live",
"description": "",
"icon": "",
"tags": ["wallet", "explorer", "token", "hardware"]
},
{
"name": "SOL Wallet Adapter",
"url": "https://github.com/project-serum/sol-wallet-adapter",
"description": "",
"icon": "",
"tags": ["wallet", "js"]
},
{
"name": "Serum DEX Source",
"url": "https://github.com/project-serum/serum-dex",
"description": "",
"icon": "",
"tags": ["source", "dex"]
},
{
"name": "serum.js Source",
"url": "https://github.com/project-serum/serum-js",
"description": "",
"icon": "",
"tags": ["js", "source", "documentation"]
},
{
"name": "Serum DEX UI Source",
"url": "https://github.com/project-serum/serum-dex-ui",
"description": "",
"icon": "",
"tags": ["source", "ui"]
},
{
"name": "PySerum",
"url": "https://github.com/serum-community/pyserum",
"description": "",
"icon": "",
"tags": ["python", "source"]
},
{
"name": "Serum Academy",
"url": "https://serum-academy.com",
"description": "",
"icon": "",
"tags": ["documentation"]
},
{
"name": "Soltalk",
"url": "https://github.com/kemargrant/soltalk",
"description": "",
"icon": "",
"tags": ["messaging"]
},
{
"name": "SAMM Source",
"url": "https://gitlab.com/OpinionatedGeek/samm",
"description": "",
"icon": "",
"tags": ["amm"]
},
{
"name": "SAMM RFC",
"url": "https://github.com/project-serum/rfcs/blob/master/text/0003-samm.md",
"description": "",
"icon": "",
"tags": ["amm", "documentation"]
},
{
"name": "Serum (SRM) SPL",
"url": "https://explorer.solana.com/address/SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt",
"description": "",
"icon": "",
"tags": ["srm", "token", "solana"]
},
{
"name": "Serum (SRM) ERC20",
"url": "https://etherscan.io/token/0x476c5e26a75bd202a9683ffd34359c0cc15be0ff",
"description": "",
"icon": "",
"tags": ["srm", "token", "solana", "eth"]
},
{
"name": "MegaSerum (MSRM) SPL",
"url": "https://explorer.solana.com/address/MSRMcoVyrFxnSgo5uXwone5SKcGhT1KEJMFEkMEWf9L",
"description": "",
"icon": "",
"tags": ["srm", "token", "solana"]
},
{
"name": "MegaSerum (MSRM) ERC20",
"url": "https://etherscan.io/token/0x1320c8c64b9f2eAa851F70702e6C9FC1EE4E8Ce4",
"description": "",
"icon": "",
"tags": ["srm", "token", "solana", "eth"]
}
]

View File

@ -1,9 +0,0 @@
import React from 'react';
export default function AppStore() {
return (
<div>
hello
</div>
)
}

View File

@ -395,11 +395,11 @@ export async function placeOrder({
const {
transaction: createAccountTransaction,
signer: createAccountSigners,
newAccountPubkey
newAccountPubkey,
} = await createTokenAccountTransaction({
connection,
wallet,
mintPublicKey: market.baseMintAddress
mintPublicKey: market.baseMintAddress,
});
transaction.add(createAccountTransaction);
signers.push(createAccountSigners);
@ -409,11 +409,11 @@ export async function placeOrder({
const {
transaction: createAccountTransaction,
signer: createAccountSigners,
newAccountPubkey
newAccountPubkey,
} = await createTokenAccountTransaction({
connection,
wallet,
mintPublicKey: market.quoteMintAddress
mintPublicKey: market.quoteMintAddress,
});
transaction.add(createAccountTransaction);
signers.push(createAccountSigners);
@ -439,7 +439,7 @@ export async function placeOrder({
console.log(params);
const matchOrderstransaction = market.makeMatchOrdersTransaction(5);
transaction.add(matchOrderstransaction)
transaction.add(matchOrderstransaction);
let {
transaction: placeOrderTx,
signers: placeOrderSigners,