mirror of https://github.com/certusone/oyster.git
Add a bunch of common components from lending that have css to common
This commit is contained in:
parent
511c9932fb
commit
c46969eed0
|
@ -0,0 +1,31 @@
|
|||
import React from 'react';
|
||||
import { Button } from 'antd';
|
||||
import { LABELS } from '../../constants';
|
||||
import { Link } from 'react-router-dom';
|
||||
import './style.css';
|
||||
|
||||
export const ActionConfirmation = (props: {
|
||||
className?: string;
|
||||
onClose: () => void;
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-around',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<h2>Congratulations!</h2>
|
||||
<div>Your action has been successfully executed</div>
|
||||
<div className="success-icon" />
|
||||
<Link to="/dashboard">
|
||||
<Button type="primary">{LABELS.DASHBOARD_ACTION}</Button>
|
||||
</Link>
|
||||
<Button type="text" onClick={props.onClose}>
|
||||
{LABELS.GO_BACK_ACTION}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
.success-icon {
|
||||
background-image: url('data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjNzBjMDQxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGRhdGEtbmFtZT0iTGF5ZXIgMSIgdmlld0JveD0iMCAwIDY0IDY0IiB4PSIwcHgiIHk9IjBweCI+PHRpdGxlPmJ1c2luZXNzIGZpbmFuY2UgdXAgcmlzZSBhcnJvdyBkZW1hbmQ8L3RpdGxlPjxwYXRoIGQ9Ik01LDE0YTEsMSwwLDEsMC0xLTFINEExLDEsMCwwLDAsNSwxNFoiPjwvcGF0aD48cGF0aCBkPSJNNyw1Mkg1NWExLDEsMCwwLDAsMC0ySDUwVjI3YTEsMSwwLDAsMC0yLDBWNTBINDRWMzRhMSwxLDAsMCwwLTIsMFY1MEgzOFYzOWExLDEsMCwwLDAtMiwwVjUwSDMyVjQzYTEsMSwwLDAsMC0yLDB2N0gyNlY0NmExLDEsMCwwLDAtMiwwdjRIMjBWNDdhMSwxLDAsMCwwLTIsMHYzSDE0VjQ4YTEsMSwwLDAsMC0yLDB2Mkg3YTEsMSwwLDAsMS0xLTFWMTdhMSwxLDAsMCwwLTIsMFY0OUEzLDMsMCwwLDAsNyw1MloiPjwvcGF0aD48cGF0aCBkPSJNNTksNTBhMSwxLDAsMCwwLTEsMWgwYTEsMSwwLDEsMCwxLTFaIj48L3BhdGg+PHBhdGggZD0iTTExLDQ0aC4wN2E0OS4wNyw0OS4wNywwLDAsMCwyNS41Mi05LjE5QTQ4LjkxLDQ4LjkxLDAsMCwwLDQ5LjcsMjAuNTlMNTIuMzgsMjIsNTIsMTRsLTYuNzEsNC4zMSwyLjYzLDEuMzZBNDYuODEsNDYuODEsMCwwLDEsMzUuNDEsMzMuMTksNDYuOTQsNDYuOTQsMCwwLDEsMTAuOTMsNDIsMSwxLDAsMCwwLDExLDQ0WiI+PC9wYXRoPjwvc3ZnPg==');
|
||||
width: 280px;
|
||||
height: 280px;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
import React from 'react';
|
||||
import { Button, Popover } from 'antd';
|
||||
import { CurrentUserBadge } from '../CurrentUserBadge';
|
||||
import { SettingOutlined } from '@ant-design/icons';
|
||||
import { Settings } from '../Settings';
|
||||
import { LABELS } from '../../constants/labels';
|
||||
import { ConnectButton } from '..';
|
||||
import { useWallet } from '../../contexts/wallet';
|
||||
import './style.css';
|
||||
export const AppBar = (props: { left?: JSX.Element; right?: JSX.Element }) => {
|
||||
const { connected, wallet } = useWallet();
|
||||
|
||||
const TopBar = (
|
||||
<div className="App-Bar-right">
|
||||
{connected ? (
|
||||
<CurrentUserBadge />
|
||||
) : (
|
||||
<ConnectButton
|
||||
type="text"
|
||||
size="large"
|
||||
allowWalletChange={true}
|
||||
style={{ color: '#2abdd2' }}
|
||||
/>
|
||||
)}
|
||||
<Popover
|
||||
placement="topRight"
|
||||
title={LABELS.SETTINGS_TOOLTIP}
|
||||
content={<Settings />}
|
||||
trigger="click"
|
||||
>
|
||||
<Button
|
||||
shape="circle"
|
||||
size="large"
|
||||
type="text"
|
||||
icon={<SettingOutlined />}
|
||||
/>
|
||||
</Popover>
|
||||
{props.right}
|
||||
</div>
|
||||
);
|
||||
|
||||
return TopBar;
|
||||
};
|
|
@ -0,0 +1,58 @@
|
|||
.App-Bar {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 120px;
|
||||
-webkit-box-pack: justify;
|
||||
justify-content: space-between;
|
||||
-webkit-box-align: center;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
top: 0px;
|
||||
position: relative;
|
||||
padding: 1rem;
|
||||
z-index: 2;
|
||||
|
||||
.ant-menu-horizontal {
|
||||
border-bottom-color: transparent;
|
||||
background-color: transparent;
|
||||
line-height: inherit;
|
||||
font-size: 16px;
|
||||
margin: 0 10px;
|
||||
|
||||
.ant-menu-item {
|
||||
margin: 0 10px;
|
||||
color: lightgrey;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
border-width: 0px !important;
|
||||
}
|
||||
|
||||
.ant-menu-item:hover {
|
||||
color: white;
|
||||
border-width: 0px !important;
|
||||
}
|
||||
|
||||
.ant-menu-item-selected {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.App-Bar-left {
|
||||
box-sizing: border-box;
|
||||
margin: 0px;
|
||||
min-width: 0px;
|
||||
display: flex;
|
||||
padding: 0px;
|
||||
-webkit-box-align: center;
|
||||
align-items: center;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.App-Bar-right {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
-webkit-box-align: center;
|
||||
align-items: center;
|
||||
justify-self: flex-end;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
import { Button } from 'antd';
|
||||
import { LABELS } from '../../constants';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
export const BackButton = () => {
|
||||
const history = useHistory();
|
||||
return (
|
||||
<Button type="text" onClick={history.goBack}>
|
||||
{LABELS.GO_BACK_ACTION}
|
||||
</Button>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
import React from 'react';
|
||||
|
||||
import { Identicon } from '../Identicon';
|
||||
import { LAMPORTS_PER_SOL } from '@solana/web3.js';
|
||||
import { useWallet } from '../../contexts/wallet';
|
||||
import { useNativeAccount } from '../../contexts/accounts';
|
||||
import { formatNumber, shortenAddress } from '../../utils';
|
||||
|
||||
export const CurrentUserBadge = (props: {}) => {
|
||||
const { wallet } = useWallet();
|
||||
const { account } = useNativeAccount();
|
||||
|
||||
if (!wallet || !wallet.publicKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// should use SOL ◎ ?
|
||||
|
||||
return (
|
||||
<div className="wallet-wrapper">
|
||||
<span>
|
||||
{formatNumber.format((account?.lamports || 0) / LAMPORTS_PER_SOL)} SOL
|
||||
</span>
|
||||
<div className="wallet-key">
|
||||
{shortenAddress(`${wallet.publicKey}`)}
|
||||
<Identicon
|
||||
address={wallet.publicKey?.toBase58()}
|
||||
style={{ marginLeft: '0.5rem', display: 'flex' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
import { Button, Popover } from "antd";
|
||||
import React from "react";
|
||||
|
||||
import { InfoCircleOutlined } from "@ant-design/icons";
|
||||
|
||||
export const Info = (props: {
|
||||
text: React.ReactElement;
|
||||
style?: React.CSSProperties;
|
||||
}) => {
|
||||
return (
|
||||
<Popover
|
||||
trigger="hover"
|
||||
content={<div style={{ width: 300 }}>{props.text}</div>}
|
||||
>
|
||||
<Button type="text" shape="circle">
|
||||
<InfoCircleOutlined style={props.style} />
|
||||
</Button>
|
||||
</Popover>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
import React, { useEffect, useRef } from 'react';
|
||||
|
||||
import Jazzicon from 'jazzicon';
|
||||
import bs58 from 'bs58';
|
||||
import './style.css';
|
||||
import { PublicKey } from '@solana/web3.js';
|
||||
|
||||
export const Identicon = (props: {
|
||||
address?: string | PublicKey;
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
}) => {
|
||||
const { style, className } = props;
|
||||
const address =
|
||||
typeof props.address === 'string'
|
||||
? props.address
|
||||
: props.address?.toBase58();
|
||||
const ref = useRef<HTMLDivElement>();
|
||||
|
||||
useEffect(() => {
|
||||
if (address && ref.current) {
|
||||
ref.current.innerHTML = '';
|
||||
ref.current.className = className || '';
|
||||
ref.current.appendChild(
|
||||
Jazzicon(
|
||||
style?.width || 16,
|
||||
parseInt(bs58.decode(address).toString('hex').slice(5, 15), 16),
|
||||
),
|
||||
);
|
||||
}
|
||||
}, [address, style, className]);
|
||||
|
||||
return (
|
||||
<div className="identicon-wrapper" ref={ref as any} style={props.style} />
|
||||
);
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
.identicon-wrapper {
|
||||
display: flex;
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
border-radius: 1.125rem;
|
||||
margin: 0.2rem 0.2rem 0.2rem 0.1rem;
|
||||
/* background-color: ${({ theme }) => theme.bg4}; */
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
import React from 'react';
|
||||
import { Button, Select } from 'antd';
|
||||
import { useWallet } from '../../contexts/wallet';
|
||||
import { ENDPOINTS, useConnectionConfig } from '../../contexts/connection';
|
||||
|
||||
export const Settings = () => {
|
||||
const { connected, disconnect } = useWallet();
|
||||
const { endpoint, setEndpoint } = useConnectionConfig();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: 'grid' }}>
|
||||
Network:{' '}
|
||||
<Select
|
||||
onSelect={setEndpoint}
|
||||
value={endpoint}
|
||||
style={{ marginBottom: 20 }}
|
||||
>
|
||||
{ENDPOINTS.map(({ name, endpoint }) => (
|
||||
<Select.Option value={endpoint} key={endpoint}>
|
||||
{name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
{connected && (
|
||||
<Button type="primary" onClick={disconnect}>
|
||||
Disconnect
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -1,2 +1,8 @@
|
|||
export { ExplorerLink } from './ExplorerLink/index';
|
||||
export { ConnectButton } from './ConnectButton/index';
|
||||
export { CurrentUserBadge } from './CurrentUserBadge/index';
|
||||
export { Identicon } from './Identicon/index';
|
||||
export { Info } from './Icons/info';
|
||||
export { NumericInput } from './Input/numeric';
|
||||
export { AppBar } from './AppBar/index';
|
||||
export { Settings } from './Settings/index';
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
export * from './math';
|
||||
export * from './labels';
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
export const LABELS = {
|
||||
CONNECT_LABEL: 'Connect Wallet',
|
||||
AUDIT_WARNING:
|
||||
'Oyster is an unaudited software project used for internal purposes at the Solana Foundation. This app is not for public use.',
|
||||
FOOTER:
|
||||
'This page was produced by the Solana Foundation ("SF") for internal educational and inspiration purposes only. SF does not encourage, induce or sanction the deployment, integration or use of Oyster or any similar application (including its code) in violation of applicable laws or regulations and hereby prohibits any such deployment, integration or use. Anyone using this code or a derivation thereof must comply with applicable laws and regulations when releasing related software.',
|
||||
MENU_HOME: 'Home',
|
||||
MENU_DASHBOARD: 'Dashboard',
|
||||
CONNECT_BUTTON: 'Connect',
|
||||
WALLET_TOOLTIP: 'Wallet public key',
|
||||
WALLET_BALANCE: 'Wallet balance',
|
||||
SETTINGS_TOOLTIP: 'Settings',
|
||||
DASHBOARD_ACTION: 'Go to dashboard',
|
||||
GO_BACK_ACTION: 'Go back',
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
export * as actions from './actions';
|
||||
export * from './components';
|
||||
export * as components from './components';
|
||||
export * as config from './config';
|
||||
export * as constants from './constants';
|
||||
export * as hooks from './hooks';
|
||||
|
|
|
@ -18,6 +18,11 @@ let WORMHOLE_BRIDGE: {
|
|||
wrappedMaster: string;
|
||||
};
|
||||
|
||||
let TIMELOCK: {
|
||||
programId: PublicKey;
|
||||
programAccountId: PublicKey;
|
||||
};
|
||||
|
||||
let SWAP_PROGRAM_ID: PublicKey;
|
||||
let SWAP_PROGRAM_LEGACY_IDS: PublicKey[];
|
||||
let SWAP_PROGRAM_LAYOUT: any;
|
||||
|
@ -34,6 +39,12 @@ export const ENABLE_FEES_INPUT = false;
|
|||
export const PROGRAM_IDS = [
|
||||
{
|
||||
name: 'mainnet-beta',
|
||||
timelock: () => ({
|
||||
programAccountId: new PublicKey(
|
||||
'9gBhDCCKV7KELLFRY8sAJZXqDmvUfmNzFzpB2b4FUVVr',
|
||||
),
|
||||
programId: new PublicKey('9iAeqqppjn7g1Jn8o2cQCqU5aQVV3h4q9bbWdKRbeC2w'),
|
||||
}),
|
||||
wormhole: () => ({
|
||||
pubkey: new PublicKey('WormT3McKhFJ2RkiGpdw9GKvNCrB2aB54gb2uV9MfQC'),
|
||||
bridge: '0xf92cD566Ea4864356C5491c177A430C222d7e678',
|
||||
|
@ -52,6 +63,12 @@ export const PROGRAM_IDS = [
|
|||
},
|
||||
{
|
||||
name: 'testnet',
|
||||
timelock: () => ({
|
||||
programAccountId: new PublicKey(
|
||||
'9gBhDCCKV7KELLFRY8sAJZXqDmvUfmNzFzpB2b4FUVVr',
|
||||
),
|
||||
programId: new PublicKey('9iAeqqppjn7g1Jn8o2cQCqU5aQVV3h4q9bbWdKRbeC2w'),
|
||||
}),
|
||||
wormhole: () => ({
|
||||
pubkey: new PublicKey('5gQf5AUhAgWYgUCt9ouShm9H7dzzXUsLdssYwe5krKhg'),
|
||||
bridge: '0x251bBCD91E84098509beaeAfF0B9951859af66D3',
|
||||
|
@ -67,6 +84,12 @@ export const PROGRAM_IDS = [
|
|||
},
|
||||
{
|
||||
name: 'devnet',
|
||||
timelock: () => ({
|
||||
programAccountId: new PublicKey(
|
||||
'9gBhDCCKV7KELLFRY8sAJZXqDmvUfmNzFzpB2b4FUVVr',
|
||||
),
|
||||
programId: new PublicKey('9iAeqqppjn7g1Jn8o2cQCqU5aQVV3h4q9bbWdKRbeC2w'),
|
||||
}),
|
||||
wormhole: () => ({
|
||||
pubkey: new PublicKey('WormT3McKhFJ2RkiGpdw9GKvNCrB2aB54gb2uV9MfQC'),
|
||||
bridge: '0xf92cD566Ea4864356C5491c177A430C222d7e678',
|
||||
|
@ -82,6 +105,12 @@ export const PROGRAM_IDS = [
|
|||
},
|
||||
{
|
||||
name: 'localnet',
|
||||
timelock: () => ({
|
||||
programAccountId: new PublicKey(
|
||||
'9gBhDCCKV7KELLFRY8sAJZXqDmvUfmNzFzpB2b4FUVVr',
|
||||
),
|
||||
programId: new PublicKey('9iAeqqppjn7g1Jn8o2cQCqU5aQVV3h4q9bbWdKRbeC2w'),
|
||||
}),
|
||||
wormhole: () => ({
|
||||
pubkey: new PublicKey('WormT3McKhFJ2RkiGpdw9GKvNCrB2aB54gb2uV9MfQC'),
|
||||
bridge: '0xf92cD566Ea4864356C5491c177A430C222d7e678',
|
||||
|
@ -111,6 +140,8 @@ export const setProgramIds = (envName: string) => {
|
|||
SWAP_PROGRAM_LAYOUT = swap.current.layout;
|
||||
SWAP_PROGRAM_LEGACY_IDS = swap.legacy;
|
||||
|
||||
TIMELOCK = instance.timelock();
|
||||
|
||||
if (envName === 'mainnet-beta') {
|
||||
LENDING_PROGRAM_ID = new PublicKey(
|
||||
'LendZqTs7gn5CTSJU1jWKhKuVpjJGom45nnwPb2AMTi',
|
||||
|
@ -125,5 +156,6 @@ export const programIds = () => {
|
|||
swapLayout: SWAP_PROGRAM_LAYOUT,
|
||||
lending: LENDING_PROGRAM_ID,
|
||||
wormhole: WORMHOLE_BRIDGE,
|
||||
timelock: TIMELOCK,
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue