Merge branch 'migrate-next' of https://github.com/exromany/metaplex into exromany-migrate-next
This commit is contained in:
commit
742fd11fa1
|
@ -1,4 +1,5 @@
|
|||
node_modules
|
||||
.git
|
||||
.editorconfig
|
||||
.gitignore
|
||||
.gitignore
|
||||
.next
|
||||
|
|
41
Dockerfile
41
Dockerfile
|
@ -1,40 +1,47 @@
|
|||
# Stage 1: Compile and Build the app
|
||||
|
||||
# Node veersion
|
||||
FROM node:14.15.1 as build
|
||||
FROM node:14.17.3-alpine as build
|
||||
|
||||
# update
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install curl gnupg
|
||||
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
|
||||
RUN apt-get -y install nodejs
|
||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||
RUN apk add --no-cache libc6-compat git
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /usr/local/app
|
||||
WORKDIR /app
|
||||
|
||||
# Add the source code to app
|
||||
COPY ./ /usr/local/app/
|
||||
COPY ./js /app
|
||||
|
||||
WORKDIR js
|
||||
# Install all the dependencies
|
||||
RUN yarn install
|
||||
RUN yarn install --frozen-lockfile
|
||||
RUN yarn bootstrap
|
||||
|
||||
# HERE ADD YOUR STORE WALLET ADDRESS
|
||||
ENV REACT_APP_STORE_OWNER_ADDRESS_ADDRESS=""
|
||||
|
||||
# Generate the build of the application
|
||||
ENV GENERATE_SOURCEMAP=false
|
||||
RUN yarn build
|
||||
|
||||
# Stage 2: Serve app with nginx server
|
||||
|
||||
# Use official nginx image as the base image
|
||||
FROM nginx:latest
|
||||
# Production image, copy all the files and run next
|
||||
FROM node:14.17.3-alpine AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV production
|
||||
|
||||
RUN addgroup -g 1001 -S nodejs
|
||||
RUN adduser -S nextjs -u 1001
|
||||
|
||||
# Copy the build output to replace the default nginx contents.
|
||||
COPY --from=build /usr/local/app/js/build/web /usr/share/nginx/html
|
||||
COPY --from=build /app/packages/web/next.config.js ./
|
||||
COPY --from=build /app/packages/web/public ./public
|
||||
COPY --from=build --chown=nextjs:nodejs /app/packages/web/.next ./.next
|
||||
COPY --from=build /app/node_modules ./node_modules
|
||||
COPY --from=build /app/packages/web/package.json ./package.json
|
||||
|
||||
# Expose port 80
|
||||
EXPOSE 80
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["yarn", "start:prod"]
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "^11.0.1",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2"
|
||||
},
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
"main": "dist/lib/index.js",
|
||||
"types": "dist/lib/index.d.ts",
|
||||
"exports": {
|
||||
".": "./dist/lib/"
|
||||
".": "./dist/lib",
|
||||
"./styles.css": "./dist/lib/styles.css"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"publishConfig": {
|
||||
|
|
|
@ -2,7 +2,6 @@ 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;
|
||||
|
|
|
@ -6,7 +6,6 @@ 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;
|
||||
|
@ -18,11 +17,9 @@ export const AppBar = (props: {
|
|||
const TopBar = (
|
||||
<div className="App-Bar-right">
|
||||
{props.left}
|
||||
{connected ?
|
||||
(
|
||||
<CurrentUserBadge />
|
||||
)
|
||||
: (
|
||||
{connected ? (
|
||||
<CurrentUserBadge />
|
||||
) : (
|
||||
<ConnectButton
|
||||
type="text"
|
||||
size="large"
|
||||
|
|
|
@ -5,11 +5,14 @@ import { LAMPORTS_PER_SOL } from '@solana/web3.js';
|
|||
import { useWallet } from '../../contexts/wallet';
|
||||
import { useNativeAccount } from '../../contexts/accounts';
|
||||
import { formatNumber, shortenAddress } from '../../utils';
|
||||
import './styles.css';
|
||||
import { Popover } from 'antd';
|
||||
import { Settings } from '../Settings';
|
||||
|
||||
export const CurrentUserBadge = (props: { showBalance?: boolean, showAddress?: boolean, iconSize?: number }) => {
|
||||
export const CurrentUserBadge = (props: {
|
||||
showBalance?: boolean;
|
||||
showAddress?: boolean;
|
||||
iconSize?: number;
|
||||
}) => {
|
||||
const { wallet } = useWallet();
|
||||
const { account } = useNativeAccount();
|
||||
|
||||
|
@ -17,54 +20,59 @@ export const CurrentUserBadge = (props: { showBalance?: boolean, showAddress?: b
|
|||
return null;
|
||||
}
|
||||
|
||||
const iconStyle: React.CSSProperties = props.showAddress ?
|
||||
{
|
||||
marginLeft: '0.5rem',
|
||||
display: 'flex',
|
||||
width: props.iconSize,
|
||||
borderRadius: 50,
|
||||
const iconStyle: React.CSSProperties = props.showAddress
|
||||
? {
|
||||
marginLeft: '0.5rem',
|
||||
display: 'flex',
|
||||
width: props.iconSize,
|
||||
borderRadius: 50,
|
||||
}
|
||||
: {
|
||||
display: 'flex',
|
||||
width: props.iconSize,
|
||||
paddingLeft: 0,
|
||||
borderRadius: 50,
|
||||
};
|
||||
|
||||
} :{
|
||||
display: 'flex',
|
||||
width: props.iconSize,
|
||||
paddingLeft: 0,
|
||||
borderRadius: 50,
|
||||
const baseWalletKey: React.CSSProperties = {
|
||||
height: props.iconSize,
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
};
|
||||
|
||||
const baseWalletKey: React.CSSProperties = { height: props.iconSize, cursor: 'pointer', userSelect: 'none' };
|
||||
const walletKeyStyle: React.CSSProperties = props.showAddress ?
|
||||
baseWalletKey
|
||||
:{ ...baseWalletKey, paddingLeft: 0 };
|
||||
const walletKeyStyle: React.CSSProperties = props.showAddress
|
||||
? baseWalletKey
|
||||
: { ...baseWalletKey, paddingLeft: 0 };
|
||||
|
||||
let name = props.showAddress ? shortenAddress(`${wallet.publicKey}`) : '';
|
||||
const unknownWallet = wallet as any;
|
||||
if(unknownWallet.name) {
|
||||
if (unknownWallet.name) {
|
||||
name = unknownWallet.name;
|
||||
}
|
||||
|
||||
let image = <Identicon
|
||||
address={wallet.publicKey?.toBase58()}
|
||||
style={iconStyle}
|
||||
/>;
|
||||
let image = (
|
||||
<Identicon address={wallet.publicKey?.toBase58()} style={iconStyle} />
|
||||
);
|
||||
|
||||
if(unknownWallet.image) {
|
||||
if (unknownWallet.image) {
|
||||
image = <img src={unknownWallet.image} style={iconStyle} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="wallet-wrapper">
|
||||
{props.showBalance && <span>
|
||||
{formatNumber.format((account?.lamports || 0) / LAMPORTS_PER_SOL)} SOL
|
||||
</span>}
|
||||
{props.showBalance && (
|
||||
<span>
|
||||
{formatNumber.format((account?.lamports || 0) / LAMPORTS_PER_SOL)} SOL
|
||||
</span>
|
||||
)}
|
||||
|
||||
<Popover
|
||||
placement="topRight"
|
||||
title="Settings"
|
||||
content={<Settings />}
|
||||
trigger="click"
|
||||
>
|
||||
placement="topRight"
|
||||
title="Settings"
|
||||
content={<Settings />}
|
||||
trigger="click"
|
||||
>
|
||||
<div className="wallet-key" style={walletKeyStyle}>
|
||||
{name && (<span style={{ marginRight: '0.5rem' }}>{name}</span>)}
|
||||
{name && <span style={{ marginRight: '0.5rem' }}>{name}</span>}
|
||||
{image}
|
||||
</div>
|
||||
</Popover>
|
||||
|
|
|
@ -2,7 +2,6 @@ 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: {
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
import React from 'react';
|
||||
import { Modal } from 'antd';
|
||||
|
||||
import './index.css';
|
||||
|
||||
export const MetaplexModal = (props: any) => {
|
||||
|
||||
const { children, bodyStyle, ...rest } = props
|
||||
const { children, bodyStyle, ...rest } = props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
bodyStyle={{
|
||||
background: "#2F2F2F",
|
||||
background: '#2F2F2F',
|
||||
boxShadow: '0px 6px 12px 8px rgba(0, 0, 0, 0.3)',
|
||||
borderRadius: 16,
|
||||
display: 'flex',
|
||||
|
|
|
@ -1,35 +1,40 @@
|
|||
import { WalletAdapter } from "@solana/wallet-base";
|
||||
import { WalletAdapter } from '@solana/wallet-base';
|
||||
|
||||
import Wallet from "@project-serum/sol-wallet-adapter";
|
||||
import { Button } from "antd";
|
||||
import React, { useCallback, useContext, useEffect, useMemo, useState } from "react";
|
||||
import { notify } from "./../utils/notifications";
|
||||
import { useConnectionConfig } from "./connection";
|
||||
import { useLocalStorageState } from "../utils/utils";
|
||||
import { PhantomWalletAdapter } from "../wallet-adapters/phantom";
|
||||
import { useLocation } from "react-router";
|
||||
import { MetaplexModal } from "../components/MetaplexModal";
|
||||
import Wallet from '@project-serum/sol-wallet-adapter';
|
||||
import { Button } from 'antd';
|
||||
import React, {
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { notify } from './../utils/notifications';
|
||||
import { useConnectionConfig } from './connection';
|
||||
import { useLocalStorageState } from '../utils/utils';
|
||||
import { PhantomWalletAdapter } from '../wallet-adapters/phantom';
|
||||
import { useLocation } from 'react-router';
|
||||
import { MetaplexModal } from '../components/MetaplexModal';
|
||||
|
||||
import './wallet.css'
|
||||
import { TorusWalletAdapter } from "../wallet-adapters/torus";
|
||||
import { TorusWalletAdapter } from '../wallet-adapters/torus';
|
||||
|
||||
|
||||
const ASSETS_URL = 'https://raw.githubusercontent.com/solana-labs/oyster/main/assets/wallets/';
|
||||
const ASSETS_URL =
|
||||
'https://raw.githubusercontent.com/solana-labs/oyster/main/assets/wallets/';
|
||||
export const WALLET_PROVIDERS = [
|
||||
{
|
||||
name: "Phantom",
|
||||
url: "https://www.phantom.app",
|
||||
name: 'Phantom',
|
||||
url: 'https://www.phantom.app',
|
||||
icon: `https://www.phantom.app/img/logo.png`,
|
||||
adapter: PhantomWalletAdapter,
|
||||
},
|
||||
{
|
||||
name: "Sollet",
|
||||
url: "https://www.sollet.io",
|
||||
name: 'Sollet',
|
||||
url: 'https://www.sollet.io',
|
||||
icon: `${ASSETS_URL}sollet.svg`,
|
||||
},
|
||||
{
|
||||
name: "MathWallet",
|
||||
url: "https://mathwallet.org",
|
||||
name: 'MathWallet',
|
||||
url: 'https://mathwallet.org',
|
||||
icon: `${ASSETS_URL}mathwallet.svg`,
|
||||
},
|
||||
{
|
||||
|
@ -37,34 +42,45 @@ export const WALLET_PROVIDERS = [
|
|||
url: 'https://tor.us',
|
||||
icon: `${ASSETS_URL}torus.svg`,
|
||||
adapter: TorusWalletAdapter,
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const WalletContext = React.createContext<{
|
||||
wallet: WalletAdapter | undefined,
|
||||
connected: boolean,
|
||||
select: () => void,
|
||||
provider: typeof WALLET_PROVIDERS[number] | undefined,
|
||||
wallet: WalletAdapter | undefined;
|
||||
connected: boolean;
|
||||
select: () => void;
|
||||
provider: typeof WALLET_PROVIDERS[number] | undefined;
|
||||
}>({
|
||||
wallet: undefined,
|
||||
connected: false,
|
||||
select() { },
|
||||
select() {},
|
||||
provider: undefined,
|
||||
});
|
||||
|
||||
export function WalletProvider({ children = null as any }) {
|
||||
const { endpoint } = useConnectionConfig();
|
||||
const location = useLocation();
|
||||
const [autoConnect, setAutoConnect] = useState(location.pathname.indexOf('result=') >= 0 || false);
|
||||
const [providerUrl, setProviderUrl] = useLocalStorageState("walletProvider");
|
||||
const [autoConnect, setAutoConnect] = useState(
|
||||
location.pathname.indexOf('result=') >= 0 || false,
|
||||
);
|
||||
const [providerUrl, setProviderUrl] = useLocalStorageState('walletProvider');
|
||||
|
||||
const provider = useMemo(() => WALLET_PROVIDERS.find(({ url }) => url === providerUrl), [providerUrl]);
|
||||
const provider = useMemo(
|
||||
() => WALLET_PROVIDERS.find(({ url }) => url === providerUrl),
|
||||
[providerUrl],
|
||||
);
|
||||
|
||||
const wallet = useMemo(function () {
|
||||
if (provider) {
|
||||
return new (provider.adapter || Wallet)(providerUrl, endpoint) as WalletAdapter;
|
||||
}
|
||||
}, [provider, providerUrl, endpoint]);
|
||||
const wallet = useMemo(
|
||||
function () {
|
||||
if (provider) {
|
||||
return new (provider.adapter || Wallet)(
|
||||
providerUrl,
|
||||
endpoint,
|
||||
) as WalletAdapter;
|
||||
}
|
||||
},
|
||||
[provider, providerUrl, endpoint],
|
||||
);
|
||||
|
||||
const [connected, setConnected] = useState(false);
|
||||
|
||||
|
@ -74,31 +90,30 @@ export function WalletProvider({ children = null as any }) {
|
|||
const keyToDisplay =
|
||||
walletPublicKey.length > 20
|
||||
? `${walletPublicKey.substring(0, 7)}.....${walletPublicKey.substring(
|
||||
walletPublicKey.length - 7,
|
||||
walletPublicKey.length
|
||||
)}`
|
||||
walletPublicKey.length - 7,
|
||||
walletPublicKey.length,
|
||||
)}`
|
||||
: walletPublicKey;
|
||||
notify({
|
||||
message: "Wallet update",
|
||||
description: "Connected to wallet " + keyToDisplay,
|
||||
message: 'Wallet update',
|
||||
description: 'Connected to wallet ' + keyToDisplay,
|
||||
});
|
||||
}
|
||||
|
||||
}, [connected])
|
||||
}, [connected]);
|
||||
|
||||
useEffect(() => {
|
||||
if (wallet) {
|
||||
wallet.on("connect", () => {
|
||||
wallet.on('connect', () => {
|
||||
if (wallet.publicKey) {
|
||||
setConnected(true);
|
||||
}
|
||||
});
|
||||
|
||||
wallet.on("disconnect", () => {
|
||||
wallet.on('disconnect', () => {
|
||||
setConnected(false);
|
||||
notify({
|
||||
message: "Wallet update",
|
||||
description: "Disconnected from wallet",
|
||||
message: 'Wallet update',
|
||||
description: 'Disconnected from wallet',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -117,7 +132,7 @@ export function WalletProvider({ children = null as any }) {
|
|||
setAutoConnect(false);
|
||||
}
|
||||
|
||||
return () => { }
|
||||
return () => {};
|
||||
}, [wallet, autoConnect]);
|
||||
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
|
@ -125,11 +140,11 @@ export function WalletProvider({ children = null as any }) {
|
|||
|
||||
const select = useCallback(() => setIsModalVisible(true), []);
|
||||
const close = useCallback(() => {
|
||||
setIsModalVisible(false)
|
||||
setShowProviders(false)
|
||||
setIsModalVisible(false);
|
||||
setShowProviders(false);
|
||||
}, []);
|
||||
|
||||
const pp = WALLET_PROVIDERS.find(wp => wp.name === "Phantom")
|
||||
const pp = WALLET_PROVIDERS.find(wp => wp.name === 'Phantom');
|
||||
|
||||
return (
|
||||
<WalletContext.Provider
|
||||
|
@ -141,80 +156,99 @@ export function WalletProvider({ children = null as any }) {
|
|||
}}
|
||||
>
|
||||
{children}
|
||||
<MetaplexModal
|
||||
visible={isModalVisible}
|
||||
onCancel={close}
|
||||
>
|
||||
<div style={{
|
||||
background: 'linear-gradient(180deg, #D329FC 0%, #8F6DDE 49.48%, #19E6AD 100%)',
|
||||
borderRadius: 36,
|
||||
width: 50,
|
||||
height: 50,
|
||||
textAlign: 'center',
|
||||
verticalAlign: 'middle',
|
||||
fontWeight: 700,
|
||||
fontSize: '1.3rem',
|
||||
lineHeight: 2.4,
|
||||
marginBottom: 10,
|
||||
}}>M</div>
|
||||
<MetaplexModal visible={isModalVisible} onCancel={close}>
|
||||
<div
|
||||
style={{
|
||||
background:
|
||||
'linear-gradient(180deg, #D329FC 0%, #8F6DDE 49.48%, #19E6AD 100%)',
|
||||
borderRadius: 36,
|
||||
width: 50,
|
||||
height: 50,
|
||||
textAlign: 'center',
|
||||
verticalAlign: 'middle',
|
||||
fontWeight: 700,
|
||||
fontSize: '1.3rem',
|
||||
lineHeight: 2.4,
|
||||
marginBottom: 10,
|
||||
}}
|
||||
>
|
||||
M
|
||||
</div>
|
||||
|
||||
<h2>{provider ? 'Change provider' : 'Welcome to Metaplex'}</h2>
|
||||
<p>{provider ? 'Feel free to switch wallet provider' : 'You must be signed in to place a bid'}</p>
|
||||
<p>
|
||||
{provider
|
||||
? 'Feel free to switch wallet provider'
|
||||
: 'You must be signed in to place a bid'}
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
{(provider || showProviders) ? <>
|
||||
{WALLET_PROVIDERS.map((provider, idx) => {
|
||||
if (providerUrl === provider.url) return null
|
||||
|
||||
const onClick = function () {
|
||||
setProviderUrl(provider.url);
|
||||
setAutoConnect(true);
|
||||
close();
|
||||
}
|
||||
return (
|
||||
<Button
|
||||
key={idx}
|
||||
size="large"
|
||||
type={providerUrl === provider.url ? "primary" : "ghost"}
|
||||
onClick={onClick}
|
||||
icon={
|
||||
<img
|
||||
alt={`${provider.name}`}
|
||||
width={20}
|
||||
height={20}
|
||||
src={provider.icon}
|
||||
style={{ marginRight: 8 }} />
|
||||
}
|
||||
style={{
|
||||
display: "block",
|
||||
width: "100%",
|
||||
textAlign: "left",
|
||||
marginBottom: 8,
|
||||
}}>{provider.name}</Button>
|
||||
)
|
||||
})}
|
||||
</> : <>
|
||||
<Button
|
||||
className="metaplex-button"
|
||||
style={{
|
||||
width: '80%',
|
||||
fontWeight: 'unset',
|
||||
}}
|
||||
onClick={_ => {
|
||||
setProviderUrl(pp?.url);
|
||||
setAutoConnect(true);
|
||||
close();
|
||||
}}
|
||||
>
|
||||
<span><img src={pp?.icon} style={{ width: '1.2rem' }} /> Sign in with Phantom</span>
|
||||
<span>></span>
|
||||
</Button>
|
||||
<p onClick={_ => setShowProviders(true)} style={{ cursor: 'pointer', marginTop: 10 }}>
|
||||
Select a different Solana wallet
|
||||
</p>
|
||||
</>}
|
||||
{provider || showProviders ? (
|
||||
<>
|
||||
{WALLET_PROVIDERS.map((provider, idx) => {
|
||||
if (providerUrl === provider.url) return null;
|
||||
|
||||
const onClick = function () {
|
||||
setProviderUrl(provider.url);
|
||||
setAutoConnect(true);
|
||||
close();
|
||||
};
|
||||
return (
|
||||
<Button
|
||||
key={idx}
|
||||
size="large"
|
||||
type={providerUrl === provider.url ? 'primary' : 'ghost'}
|
||||
onClick={onClick}
|
||||
icon={
|
||||
<img
|
||||
alt={`${provider.name}`}
|
||||
width={20}
|
||||
height={20}
|
||||
src={provider.icon}
|
||||
style={{ marginRight: 8 }}
|
||||
/>
|
||||
}
|
||||
style={{
|
||||
display: 'block',
|
||||
width: '100%',
|
||||
textAlign: 'left',
|
||||
marginBottom: 8,
|
||||
}}
|
||||
>
|
||||
{provider.name}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Button
|
||||
className="metaplex-button"
|
||||
style={{
|
||||
width: '80%',
|
||||
fontWeight: 'unset',
|
||||
}}
|
||||
onClick={_ => {
|
||||
setProviderUrl(pp?.url);
|
||||
setAutoConnect(true);
|
||||
close();
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
<img src={pp?.icon} style={{ width: '1.2rem' }} />
|
||||
Sign in with Phantom
|
||||
</span>
|
||||
<span>></span>
|
||||
</Button>
|
||||
<p
|
||||
onClick={_ => setShowProviders(true)}
|
||||
style={{ cursor: 'pointer', marginTop: 10 }}
|
||||
>
|
||||
Select a different Solana wallet
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
</MetaplexModal>
|
||||
</WalletContext.Provider>
|
||||
);
|
||||
|
@ -234,4 +268,4 @@ export const useWallet = () => {
|
|||
wallet?.disconnect();
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
@import './contexts/wallet.less';
|
||||
@import './components/AppBar/style.less';
|
||||
@import './components/ActionConfirmation/style.less';
|
||||
@import './components/Identicon/style.less';
|
||||
@import './components/MetaplexModal/index.less';
|
||||
@import './components/CurrentUserBadge/styles.less';
|
|
@ -1 +0,0 @@
|
|||
GENERATE_SOURCEMAP=false
|
|
@ -1 +1,3 @@
|
|||
target
|
||||
.next
|
||||
.env.local
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
const CracoLessPlugin = require('craco-less');
|
||||
const CracoAlias = require('craco-alias');
|
||||
const CracoBabelLoader = require('craco-babel-loader');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
//console.log('qualified', pnp.resolveRequest('@babel/preset-typescript'), path.resolve(__dirname, '/') + 'src/');
|
||||
|
||||
// Handle relative paths to sibling packages
|
||||
const appDirectory = fs.realpathSync(process.cwd());
|
||||
const resolvePackage = relativePath => path.resolve(appDirectory, relativePath);
|
||||
|
||||
module.exports = {
|
||||
webpack: {
|
||||
configure: (webpackConfig, { env, paths }) => {
|
||||
paths.appBuild = webpackConfig.output.path = path.resolve(
|
||||
'./../../build/web',
|
||||
);
|
||||
return webpackConfig;
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
/*{
|
||||
plugin: CracoBabelLoader,
|
||||
options: {
|
||||
includes: [
|
||||
// No "unexpected token" error importing components from these lerna siblings:
|
||||
resolvePackage('../packages'),
|
||||
],
|
||||
},
|
||||
},*/
|
||||
/*{
|
||||
plugin: CracoAlias,
|
||||
options: {
|
||||
source: 'tsconfig',
|
||||
// baseUrl SHOULD be specified
|
||||
// plugin does not take it from tsconfig
|
||||
baseUrl: '../../',
|
||||
// tsConfigPath should point to the file where "baseUrl" and "paths" are specified
|
||||
tsConfigPath: '../../tsconfig.json',
|
||||
},
|
||||
},*/
|
||||
{
|
||||
plugin: CracoLessPlugin,
|
||||
options: {
|
||||
lessLoaderOptions: {
|
||||
lessOptions: {
|
||||
modifyVars: {
|
||||
'@primary-color': '#768BF9',
|
||||
'@text-color': 'rgba(255, 255, 255)'
|
||||
},
|
||||
javascriptEnabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
/// <reference types="next" />
|
||||
/// <reference types="next/types/global" />
|
||||
/// <reference types="next/image-types/global" />
|
|
@ -0,0 +1,41 @@
|
|||
const withPlugins = require('next-compose-plugins');
|
||||
const withLess = require('next-with-less');
|
||||
const nextEnv = require('next-env');
|
||||
const dotenvLoad = require('dotenv-load');
|
||||
|
||||
dotenvLoad();
|
||||
|
||||
const plugins = [
|
||||
nextEnv({
|
||||
publicPrefix: 'REACT_APP_',
|
||||
}),
|
||||
[
|
||||
withLess,
|
||||
{
|
||||
lessLoaderOptions: {
|
||||
lessOptions: {
|
||||
modifyVars: {
|
||||
'@primary-color': '#768BF9',
|
||||
'@text-color': 'rgba(255, 255, 255)',
|
||||
},
|
||||
javascriptEnabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
];
|
||||
|
||||
module.exports = withPlugins(plugins, {
|
||||
reactStrictMode: true,
|
||||
eslint: {
|
||||
ignoreDuringBuilds: true,
|
||||
},
|
||||
async rewrites() {
|
||||
return [
|
||||
{
|
||||
source: '/:any*',
|
||||
destination: '/',
|
||||
},
|
||||
];
|
||||
},
|
||||
});
|
|
@ -5,7 +5,6 @@
|
|||
"@ant-design/icons": "^4.4.0",
|
||||
"@babel/preset-typescript": "^7.12.13",
|
||||
"@cloudflare/stream-react": "^1.1.0",
|
||||
"@craco/craco": "^5.7.0",
|
||||
"@oyster/common": "0.0.1",
|
||||
"@project-serum/serum": "^0.13.34",
|
||||
"@project-serum/sol-wallet-adapter": "^0.2.0",
|
||||
|
@ -25,25 +24,31 @@
|
|||
"bs58": "^4.0.1",
|
||||
"buffer-layout": "^1.2.0",
|
||||
"canvas-confetti": "^1.4.0",
|
||||
"dotenv-load": "^2.0.0",
|
||||
"eventemitter3": "^4.0.7",
|
||||
"less": "^4.1.1",
|
||||
"less-loader": "^10.0.1",
|
||||
"lodash": "^4.17.20",
|
||||
"next": "^11.0.1",
|
||||
"next-compose-plugins": "^2.2.1",
|
||||
"next-env": "^1.1.1",
|
||||
"next-with-less": "^1.0.0",
|
||||
"react": "16.13.1",
|
||||
"react-content-loader": "^6.0.3",
|
||||
"react-dom": "16.13.1",
|
||||
"react-intersection-observer": "^8.32.0",
|
||||
"react-masonry-css": "^1.0.16",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-scripts": "3.4.3",
|
||||
"react-virtualized": "^9.22.3",
|
||||
"three": "^0.128.0",
|
||||
"use-wallet": "^0.8.1"
|
||||
},
|
||||
"scripts": {
|
||||
"prestart": "npm-link-shared ../common/node_modules/ . react",
|
||||
"start": "craco start --verbose",
|
||||
"build": "craco build",
|
||||
"test": "craco test",
|
||||
"eject": "react-scripts eject",
|
||||
"start": "next dev",
|
||||
"build": "next build",
|
||||
"start:prod": "next start",
|
||||
"test": "jest",
|
||||
"deploy:ar": "arweave deploy-dir ../../build/web --key-file ",
|
||||
"deploy": "gh-pages -d ../../build/web --repo https://github.com/metaplex-foundation/metaplex",
|
||||
"format:fix": "prettier --write \"**/*.+(js|jsx|ts|tsx|json|css|md)\""
|
||||
|
@ -82,19 +87,18 @@
|
|||
"@types/testing-library__react": "^10.2.0",
|
||||
"@types/three": "^0.128.0",
|
||||
"arweave-deploy": "^1.9.1",
|
||||
"craco-alias": "^2.1.1",
|
||||
"craco-babel-loader": "^0.1.4",
|
||||
"craco-less": "^1.17.0",
|
||||
"gh-pages": "^3.1.0",
|
||||
"npm-link-shared": "0.5.6",
|
||||
"prettier": "^2.1.2",
|
||||
"typescript": "^4.1.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"next": "*",
|
||||
"react": "*",
|
||||
"react-dom": "*"
|
||||
},
|
||||
"resolutions": {
|
||||
"next": "11.0.1",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2"
|
||||
},
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="loadforge-site-verification" content="2056680d2883a8b910880d53b9cb2ebf16e7b8f91e169cceddce62c4c4ef8fe6240748c08c2e3769e554e12dafcd5bfc62028638e6524a0efd7d729efd762d42" />
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="%PUBLIC_URL%/apple-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="%PUBLIC_URL%/apple-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="%PUBLIC_URL%/apple-icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="%PUBLIC_URL%/apple-icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="%PUBLIC_URL%/apple-icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="%PUBLIC_URL%/apple-icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="%PUBLIC_URL%/apple-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="%PUBLIC_URL%/apple-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="%PUBLIC_URL%/apple-icon-180x180.png">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="%PUBLIC_URL%/android-icon-192x192.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="%PUBLIC_URL%/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="%PUBLIC_URL%/favicon-96x96.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="%PUBLIC_URL%/favicon-16x16.png">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" content="Metaplex NFT Marketplace" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>Metaplex NFT Marketplace</title>
|
||||
<style type="text/css">
|
||||
html {
|
||||
overflow-y: scroll;
|
||||
width: 100vw;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
#root {
|
||||
height: 100%;
|
||||
font-family: 'Graphik Web', sans-serif;
|
||||
}
|
||||
|
||||
#root::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
filter: grayscale(100%);
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.App {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
min-width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: black;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"
|
||||
integrity="sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA=="
|
||||
crossorigin="anonymous" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
|
||||
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
<script>
|
||||
(function () {
|
||||
var s = document.createElement("script");
|
||||
s.src = "https://stackpile.io/stack_162299.js"; s.async = true;
|
||||
var e = document.getElementsByTagName("script")[0]; e.parentNode.insertBefore(s, e);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,46 +1,25 @@
|
|||
{
|
||||
"short_name": "Metaplex NFT Marketplace",
|
||||
"name": "Metaplex NFT Marketplace",
|
||||
"short_name": "Metaplex NFT Marketplace",
|
||||
"display": "standalone",
|
||||
"start_url": "./",
|
||||
"theme_color": "#002140",
|
||||
"background_color": "#001529",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-icon-36x36.png",
|
||||
"sizes": "36x36",
|
||||
"type": "image/png",
|
||||
"density": "0.75"
|
||||
"src": "/favicon-16x16.png",
|
||||
"sizes": "16x16",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-icon-48x48.png",
|
||||
"sizes": "48x48",
|
||||
"type": "image/png",
|
||||
"density": "1.0"
|
||||
"src": "/favicon-32x32.png",
|
||||
"sizes": "32x32",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-icon-72x72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image/png",
|
||||
"density": "1.5"
|
||||
},
|
||||
{
|
||||
"src": "/android-icon-96x96.png",
|
||||
"src": "/favicon-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image/png",
|
||||
"density": "2.0"
|
||||
},
|
||||
{
|
||||
"src": "/android-icon-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png",
|
||||
"density": "3.0"
|
||||
},
|
||||
{
|
||||
"src": "/android-icon-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"density": "4.0"
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,9 +1,30 @@
|
|||
|
||||
@import '~antd/es/style/themes/dark.less';
|
||||
@import "~antd/dist/antd.dark.less";
|
||||
@import '~antd/dist/antd.dark.less';
|
||||
|
||||
@solana-green: #3d4844;
|
||||
|
||||
html {
|
||||
overflow-y: scroll;
|
||||
width: 100vw;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
#root {
|
||||
height: 100%;
|
||||
font-family: 'Graphik Web', sans-serif;
|
||||
}
|
||||
|
||||
#root::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
filter: grayscale(100%);
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
body {
|
||||
--row-highlight: @background-color-base;
|
||||
margin: 0;
|
||||
|
@ -27,21 +48,6 @@ img:not([src]) {
|
|||
visibility: hidden;
|
||||
}
|
||||
|
||||
.App {
|
||||
background: #101010 !important;
|
||||
padding: 0px 30px;
|
||||
|
||||
> section {
|
||||
max-width: 1280px;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.square div {
|
||||
position: relative;
|
||||
padding-top: 100% !important;
|
||||
|
@ -55,7 +61,7 @@ code {
|
|||
}
|
||||
|
||||
.app-logo {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjZDgzYWViIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMTAwIDEwMCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHBhdGggZD0iTTQwLjM2LDUwLjkxYzAuMDA3LTguMTc0LDMuODM2LTExLjUyNSw3LjA0OC0xMi44OThjNi41NTEtMi44MDEsMTYuNzksMC4xNDEsMjMuODA5LDYuODQyICBjMS4yNDYsMS4xODksMi4zNjEsMi4zMDksMy4zNjUsMy4zNjhjLTUuNjg0LTguMzcyLTE1LjAyNS0xNy41NjYtMjkuMDY0LTE4Ljg1OWMtNy43OTQtMC43MTYtMTMuNzk0LDIuNzk5LTE2LjAzMyw5LjQwOCAgYy0yLjY0OSw3LjgyMSwwLjM0MSwxOS4zMDUsMTEuMTgxLDI2LjEyMmM2LjE1MywzLjg2OSwxMi4zLDYuODY5LDE3LjM0MSw5LjA0NWMtMC41NTEtMC4zNTQtMS4xMDUtMC43MTYtMS42Ni0xLjA5MSAgQzQ1LjczMyw2NS42NjIsNDAuMzU0LDU4LjI4MSw0MC4zNiw1MC45MXoiPjwvcGF0aD48cGF0aCBkPSJNNjAuMDI3LDYzLjc2MWMtMC4wNzgtNC43MTUsMS44OTgtOC4yNSw1LjQyMi05LjY5OGM0LjEzOS0xLjcsOS40OS0wLjAwNCwxMy42MzMsNC4zMjMgIGMwLjY5MSwwLjcyMywxLjMwMywxLjQ1MywxLjg3NSwyLjE4NGMtMS42NzQtMy42OTktNC41MS03Ljk1OC0xMS4xMjEtMTQuMjY5Yy02LjM3MS02LjA4MS0xNS44NzktOC45MTItMjEuNjQyLTYuNDUgIGMtMy44MTIsMS42MjktNS44MjksNS40NTQtNS44MzQsMTEuMDYxYy0wLjAxLDExLjgxNSwxNi4zMTIsMjEuNjQ2LDI1LjA3MiwyNi4wNzJDNjMuNzc1LDczLjc0Niw2MC4xMTUsNjkuMTY4LDYwLjAyNyw2My43NjF6Ij48L3BhdGg+PHBhdGggZD0iTTI3LjU5MSwzOC4xM2MyLjU1Ni03LjU0NSw5LjMzMS0xMS41NjgsMTguMTExLTEwLjc1OGMxMS41MjksMS4wNjEsMjAuMDE1LDcuMTQ4LDI2LjAxMywxMy45MiAgQzYxLjUsMjYuMDU0LDQ4Ljk2MywyMC4zMzksNDguODE3LDIwLjI3NGMtMy4yOTYtMS42ODgtNi43OTctMi41MzEtMTAuNDU3LTIuNTMxYy0xMi43NzQsMC0yMy4xNjcsMTAuNTgtMjMuMTY3LDIzLjU4MyAgYzAsNy45NjEsNC4yMDEsMTUuNTIxLDExLjIzOCwyMC4yMjJjMy43ODksMi41MywxMS40ODgsNS44MjQsMjAuMDQ2LDkuMDM4Yy0yLjI1NC0xLjIxNS00LjU2NC0yLjU0Ny02Ljg3NS00ICBDMjcuODg1LDU5LjIxOSwyNC42OSw0Ni42OTQsMjcuNTkxLDM4LjEzeiI+PC9wYXRoPjxwYXRoIGQ9Ik03Ny42MzcsNTkuNzY5Yy0zLjU2OC0zLjcyOS04LjA1Ny01LjI0Mi0xMS40MjgtMy44NTVjLTIuNzIxLDEuMTE4LTQuMjQ2LDMuOTY3LTQuMTgyLDcuODE0ICBjMC4xNDgsOS4wMzUsMTEuMzEzLDE1LjMxOCwxMy41ODgsMTYuNTkyYzMuNDg5LDEuOTU0LDcuNjI1LDIuMDg3LDcuOTA0LDEuOTM4czAuMjc5LTAuMTQ5LDAuNTMxLTAuNjUxICBjMC42Ni0xLjMwOSwxLjA1My00LjI3NSwwLjM2MS04Ljk2NkM4My43NzcsNjkuNDg5LDgyLjA5Niw2NC40MjcsNzcuNjM3LDU5Ljc2OXoiPjwvcGF0aD48L3N2Zz4=");
|
||||
background-image: url('data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjZDgzYWViIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMTAwIDEwMCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHBhdGggZD0iTTQwLjM2LDUwLjkxYzAuMDA3LTguMTc0LDMuODM2LTExLjUyNSw3LjA0OC0xMi44OThjNi41NTEtMi44MDEsMTYuNzksMC4xNDEsMjMuODA5LDYuODQyICBjMS4yNDYsMS4xODksMi4zNjEsMi4zMDksMy4zNjUsMy4zNjhjLTUuNjg0LTguMzcyLTE1LjAyNS0xNy41NjYtMjkuMDY0LTE4Ljg1OWMtNy43OTQtMC43MTYtMTMuNzk0LDIuNzk5LTE2LjAzMyw5LjQwOCAgYy0yLjY0OSw3LjgyMSwwLjM0MSwxOS4zMDUsMTEuMTgxLDI2LjEyMmM2LjE1MywzLjg2OSwxMi4zLDYuODY5LDE3LjM0MSw5LjA0NWMtMC41NTEtMC4zNTQtMS4xMDUtMC43MTYtMS42Ni0xLjA5MSAgQzQ1LjczMyw2NS42NjIsNDAuMzU0LDU4LjI4MSw0MC4zNiw1MC45MXoiPjwvcGF0aD48cGF0aCBkPSJNNjAuMDI3LDYzLjc2MWMtMC4wNzgtNC43MTUsMS44OTgtOC4yNSw1LjQyMi05LjY5OGM0LjEzOS0xLjcsOS40OS0wLjAwNCwxMy42MzMsNC4zMjMgIGMwLjY5MSwwLjcyMywxLjMwMywxLjQ1MywxLjg3NSwyLjE4NGMtMS42NzQtMy42OTktNC41MS03Ljk1OC0xMS4xMjEtMTQuMjY5Yy02LjM3MS02LjA4MS0xNS44NzktOC45MTItMjEuNjQyLTYuNDUgIGMtMy44MTIsMS42MjktNS44MjksNS40NTQtNS44MzQsMTEuMDYxYy0wLjAxLDExLjgxNSwxNi4zMTIsMjEuNjQ2LDI1LjA3MiwyNi4wNzJDNjMuNzc1LDczLjc0Niw2MC4xMTUsNjkuMTY4LDYwLjAyNyw2My43NjF6Ij48L3BhdGg+PHBhdGggZD0iTTI3LjU5MSwzOC4xM2MyLjU1Ni03LjU0NSw5LjMzMS0xMS41NjgsMTguMTExLTEwLjc1OGMxMS41MjksMS4wNjEsMjAuMDE1LDcuMTQ4LDI2LjAxMywxMy45MiAgQzYxLjUsMjYuMDU0LDQ4Ljk2MywyMC4zMzksNDguODE3LDIwLjI3NGMtMy4yOTYtMS42ODgtNi43OTctMi41MzEtMTAuNDU3LTIuNTMxYy0xMi43NzQsMC0yMy4xNjcsMTAuNTgtMjMuMTY3LDIzLjU4MyAgYzAsNy45NjEsNC4yMDEsMTUuNTIxLDExLjIzOCwyMC4yMjJjMy43ODksMi41MywxMS40ODgsNS44MjQsMjAuMDQ2LDkuMDM4Yy0yLjI1NC0xLjIxNS00LjU2NC0yLjU0Ny02Ljg3NS00ICBDMjcuODg1LDU5LjIxOSwyNC42OSw0Ni42OTQsMjcuNTkxLDM4LjEzeiI+PC9wYXRoPjxwYXRoIGQ9Ik03Ny42MzcsNTkuNzY5Yy0zLjU2OC0zLjcyOS04LjA1Ny01LjI0Mi0xMS40MjgtMy44NTVjLTIuNzIxLDEuMTE4LTQuMjQ2LDMuOTY3LTQuMTgyLDcuODE0ICBjMC4xNDgsOS4wMzUsMTEuMzEzLDE1LjMxOCwxMy41ODgsMTYuNTkyYzMuNDg5LDEuOTU0LDcuNjI1LDIuMDg3LDcuOTA0LDEuOTM4czAuMjc5LTAuMTQ5LDAuNTMxLTAuNjUxICBjMC42Ni0xLjMwOSwxLjA1My00LjI3NSwwLjM2MS04Ljk2NkM4My43NzcsNjkuNDg5LDgyLjA5Niw2NC40MjcsNzcuNjM3LDU5Ljc2OXoiPjwvcGF0aD48L3N2Zz4=');
|
||||
height: 32px;
|
||||
pointer-events: none;
|
||||
background-repeat: no-repeat;
|
||||
|
@ -81,14 +87,15 @@ code {
|
|||
.ant-card-cover {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
.ant-image-img, video {
|
||||
.ant-image-img,
|
||||
video {
|
||||
height: 300px;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.placebid {
|
||||
color: #BBA8E3;
|
||||
color: #bba8e3;
|
||||
}
|
||||
|
||||
.card-close-button {
|
||||
|
@ -112,10 +119,6 @@ code {
|
|||
margin-right: auto;
|
||||
}
|
||||
|
||||
.ant-tabs-tab-active {
|
||||
|
||||
}
|
||||
|
||||
.ant-upload.ant-upload-drag {
|
||||
border-radius: 8px;
|
||||
border-color: transparent;
|
||||
|
@ -160,7 +163,7 @@ code {
|
|||
.creators {
|
||||
// display: flex;
|
||||
@media (max-width: 475px) {
|
||||
flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react';
|
||||
import './App.less';
|
||||
import { Routes } from './routes';
|
||||
|
||||
function App() {
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
@import url("https://fonts.googleapis.com/css?family=Roboto:400");
|
|
@ -1,8 +1,7 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { Statistic } from 'antd'
|
||||
import { useSolPrice } from '../../contexts'
|
||||
import { formatUSD } from '@oyster/common'
|
||||
import './index.less';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Statistic } from 'antd';
|
||||
import { useSolPrice } from '../../contexts';
|
||||
import { formatUSD } from '@oyster/common';
|
||||
|
||||
interface IAmountLabel {
|
||||
amount: number | string;
|
||||
|
@ -13,34 +12,45 @@ interface IAmountLabel {
|
|||
}
|
||||
|
||||
export const AmountLabel = (props: IAmountLabel) => {
|
||||
const { amount: _amount, displayUSD = true, title = "", style = {}, containerStyle = {} } = props
|
||||
const amount = typeof _amount === "string" ? parseFloat(_amount) : _amount
|
||||
const {
|
||||
amount: _amount,
|
||||
displayUSD = true,
|
||||
title = '',
|
||||
style = {},
|
||||
containerStyle = {},
|
||||
} = props;
|
||||
const amount = typeof _amount === 'string' ? parseFloat(_amount) : _amount;
|
||||
|
||||
const solPrice = useSolPrice()
|
||||
const solPrice = useSolPrice();
|
||||
|
||||
const [priceUSD, setPriceUSD] = useState<number | undefined>(undefined)
|
||||
const [priceUSD, setPriceUSD] = useState<number | undefined>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
setPriceUSD(solPrice * amount)
|
||||
}, [amount, solPrice])
|
||||
setPriceUSD(solPrice * amount);
|
||||
}, [amount, solPrice]);
|
||||
|
||||
const PriceNaN = isNaN(amount);
|
||||
|
||||
return <div style={{ display: 'flex', ...containerStyle }}>
|
||||
{PriceNaN === false &&
|
||||
(<Statistic
|
||||
style={style}
|
||||
className="create-statistic"
|
||||
title={title || ""}
|
||||
value={amount}
|
||||
prefix="◎"
|
||||
/>)
|
||||
}
|
||||
{displayUSD &&
|
||||
<div className="usd">
|
||||
{PriceNaN === false ? formatUSD.format(priceUSD || 0) :
|
||||
<div className="placebid">Place Bid</div>}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
return (
|
||||
<div style={{ display: 'flex', ...containerStyle }}>
|
||||
{PriceNaN === false && (
|
||||
<Statistic
|
||||
style={style}
|
||||
className="create-statistic"
|
||||
title={title || ''}
|
||||
value={amount}
|
||||
prefix="◎"
|
||||
/>
|
||||
)}
|
||||
{displayUSD && (
|
||||
<div className="usd">
|
||||
{PriceNaN === false ? (
|
||||
formatUSD.format(priceUSD || 0)
|
||||
) : (
|
||||
<div className="placebid">Place Bid</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import "_colors";
|
||||
@import '../../_colors.less';
|
||||
|
||||
.App-Bar {
|
||||
padding: 0px;
|
||||
|
@ -29,7 +29,7 @@
|
|||
align-items: center;
|
||||
text-align: center;
|
||||
|
||||
color: #FFFFFF;
|
||||
color: #ffffff;
|
||||
padding: 10px 14px 10px 6px;
|
||||
|
||||
margin-bottom: 0px;
|
||||
|
@ -69,5 +69,3 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import './index.less';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Button, Dropdown, Menu } from 'antd';
|
||||
import { ConnectButton, CurrentUserBadge, useWallet } from '@oyster/common';
|
||||
|
@ -14,11 +13,12 @@ const UserActions = () => {
|
|||
const pubkey = wallet?.publicKey?.toBase58() || '';
|
||||
|
||||
const canCreate = useMemo(() => {
|
||||
return store &&
|
||||
return (
|
||||
store &&
|
||||
store.info &&
|
||||
(store.info.public ||
|
||||
whitelistedCreatorsByCreator[pubkey]?.info
|
||||
?.activated);
|
||||
whitelistedCreatorsByCreator[pubkey]?.info?.activated)
|
||||
);
|
||||
}, [pubkey, whitelistedCreatorsByCreator, store]);
|
||||
|
||||
return (
|
||||
|
@ -26,11 +26,15 @@ const UserActions = () => {
|
|||
{/* <Link to={`#`}>
|
||||
<Button className="app-btn">Bids</Button>
|
||||
</Link> */}
|
||||
{canCreate ? (<Link to={`/art/create`}>
|
||||
<Button className="app-btn">Create</Button>
|
||||
</Link>) : null}
|
||||
{canCreate ? (
|
||||
<Link to={`/art/create`}>
|
||||
<Button className="app-btn">Create</Button>
|
||||
</Link>
|
||||
) : null}
|
||||
<Link to={`/auction/create/0`}>
|
||||
<Button className="connector" type="primary" >Sell</Button>
|
||||
<Button className="connector" type="primary">
|
||||
Sell
|
||||
</Button>
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
|
@ -39,56 +43,67 @@ const UserActions = () => {
|
|||
const DefaultActions = ({ vertical = false }: { vertical?: boolean }) => {
|
||||
const { connected } = useWallet();
|
||||
return (
|
||||
<div style={{
|
||||
display: "flex",
|
||||
flexDirection: vertical ? "column" : "row",
|
||||
}}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: vertical ? 'column' : 'row',
|
||||
}}
|
||||
>
|
||||
<Link to={`/`}>
|
||||
<Button className="app-btn">Explore</Button>
|
||||
</Link>
|
||||
<Link to={`/artworks`}>
|
||||
<Button className="app-btn">{connected ? "My Items" : "Artworks"}</Button>
|
||||
<Button className="app-btn">
|
||||
{connected ? 'My Items' : 'Artworks'}
|
||||
</Button>
|
||||
</Link>
|
||||
<Link to={`/artists`}>
|
||||
<Button className="app-btn">Creators</Button>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const MetaplexMenu = () => {
|
||||
const { width } = useWindowDimensions();
|
||||
const { connected } = useWallet();
|
||||
|
||||
if (width < 768) return <>
|
||||
<Dropdown
|
||||
arrow
|
||||
placement="bottomLeft"
|
||||
trigger={['click']}
|
||||
overlay={<Menu>
|
||||
<Menu.Item>
|
||||
<Link to={`/`}>
|
||||
<Button className="app-btn">Explore</Button>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<Link to={`/artworks`}>
|
||||
<Button className="app-btn">{connected ? "My Items" : "Artworks"}</Button>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<Link to={`/artists`}>
|
||||
<Button className="app-btn">Creators</Button>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
</Menu>}
|
||||
>
|
||||
<MenuOutlined style={{ fontSize: "1.4rem" }} />
|
||||
</Dropdown>
|
||||
</>
|
||||
if (width < 768)
|
||||
return (
|
||||
<>
|
||||
<Dropdown
|
||||
arrow
|
||||
placement="bottomLeft"
|
||||
trigger={['click']}
|
||||
overlay={
|
||||
<Menu>
|
||||
<Menu.Item>
|
||||
<Link to={`/`}>
|
||||
<Button className="app-btn">Explore</Button>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<Link to={`/artworks`}>
|
||||
<Button className="app-btn">
|
||||
{connected ? 'My Items' : 'Artworks'}
|
||||
</Button>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<Link to={`/artists`}>
|
||||
<Button className="app-btn">Creators</Button>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
<MenuOutlined style={{ fontSize: '1.4rem' }} />
|
||||
</Dropdown>
|
||||
</>
|
||||
);
|
||||
|
||||
return <DefaultActions />
|
||||
}
|
||||
return <DefaultActions />;
|
||||
};
|
||||
|
||||
export const AppBar = () => {
|
||||
const { connected } = useWallet();
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import React from 'react';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import { Button } from 'antd';
|
||||
import './searchBox.less';
|
||||
|
||||
export const SearchBox = ({}) => {
|
||||
return <Button className="search-btn" shape="circle" icon={<SearchOutlined />}>
|
||||
</Button>;
|
||||
}
|
||||
return (
|
||||
<Button
|
||||
className="search-btn"
|
||||
shape="circle"
|
||||
icon={<SearchOutlined />}
|
||||
></Button>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -2,7 +2,6 @@ import React from 'react';
|
|||
import { Card, CardProps, Button, Badge } from 'antd';
|
||||
import { MetadataCategory } from '@oyster/common';
|
||||
import { ArtContent } from './../ArtContent';
|
||||
import './index.less';
|
||||
import { useArt } from '../../hooks';
|
||||
import { PublicKey } from '@solana/web3.js';
|
||||
import { Artist, ArtType } from '../../types';
|
||||
|
@ -81,11 +80,9 @@ export const ArtCard = (props: ArtCardProps) => {
|
|||
)}
|
||||
<ArtContent
|
||||
pubkey={pubkey}
|
||||
|
||||
uri={image}
|
||||
animationURL={animationURL}
|
||||
category={category}
|
||||
|
||||
preview={preview}
|
||||
height={height}
|
||||
width={width}
|
||||
|
@ -94,7 +91,7 @@ export const ArtCard = (props: ArtCardProps) => {
|
|||
}
|
||||
{...rest}
|
||||
>
|
||||
<Meta
|
||||
<Meta
|
||||
title={`${name}`}
|
||||
description={
|
||||
<>
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
import React, { useState } from 'react'
|
||||
import { Card } from 'antd'
|
||||
import React, { useState } from 'react';
|
||||
import { Card } from 'antd';
|
||||
|
||||
import { Artist } from '../../types'
|
||||
import { Artist } from '../../types';
|
||||
|
||||
import './index.less'
|
||||
import { shortenAddress } from '@oyster/common'
|
||||
import { shortenAddress } from '@oyster/common';
|
||||
import { MetaAvatar } from '../MetaAvatar';
|
||||
|
||||
export const ArtistCard = ({artist}: {artist: Artist}) => {
|
||||
|
||||
export const ArtistCard = ({ artist }: { artist: Artist }) => {
|
||||
return (
|
||||
<Card
|
||||
hoverable={true}
|
||||
|
@ -17,9 +15,11 @@ export const ArtistCard = ({artist}: {artist: Artist}) => {
|
|||
>
|
||||
<div>
|
||||
<MetaAvatar creators={[artist]} size={100} />
|
||||
<div className="artist-card-name">{artist.name || shortenAddress(artist.address || '')}</div>
|
||||
<div className="artist-card-name">
|
||||
{artist.name || shortenAddress(artist.address || '')}
|
||||
</div>
|
||||
<div className="artist-card-description">{artist.about}</div>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
|
|
@ -2,7 +2,6 @@ import React, { useMemo, useState } from 'react';
|
|||
import { Col, Button, InputNumber, Spin } from 'antd';
|
||||
import { MemoryRouter, Route, Redirect, Link } from 'react-router-dom';
|
||||
|
||||
import './index.less';
|
||||
import {
|
||||
useConnection,
|
||||
useUserAccounts,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Row, Col } from 'antd';
|
||||
|
||||
import './../AuctionCard/index.less';
|
||||
import {
|
||||
formatTokenAmount,
|
||||
useMint,
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Card, CardProps } from 'antd';
|
||||
import { formatTokenAmount, CountdownState, PriceFloorType, fromLamports, useMint } from '@oyster/common';
|
||||
import {
|
||||
formatTokenAmount,
|
||||
CountdownState,
|
||||
PriceFloorType,
|
||||
fromLamports,
|
||||
useMint,
|
||||
} from '@oyster/common';
|
||||
import { ArtContent } from '../ArtContent';
|
||||
import './index.less';
|
||||
import { AuctionView, AuctionViewState, useArt, useBidsForAuction } from '../../hooks';
|
||||
import {
|
||||
AuctionView,
|
||||
AuctionViewState,
|
||||
useArt,
|
||||
useBidsForAuction,
|
||||
} from '../../hooks';
|
||||
import { AmountLabel } from '../AmountLabel';
|
||||
import { useHighestBidForAuction } from '../../hooks';
|
||||
|
||||
|
@ -38,20 +48,20 @@ export const AuctionRenderCard = (props: AuctionCard) => {
|
|||
|
||||
let currentBid: number | string = 0;
|
||||
let label = '';
|
||||
if(isUpcoming || bids) {
|
||||
if (isUpcoming || bids) {
|
||||
label = ended ? 'Ended' : 'Starting bid';
|
||||
currentBid = fromLamports(
|
||||
participationOnly ? participationFixedPrice : priceFloor,
|
||||
mintInfo,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!isUpcoming && bids.length > 0) {
|
||||
label = ended ? 'Winning bid' : 'Current bid';
|
||||
currentBid = winningBid &&
|
||||
Number.isFinite(winningBid.info.lastBid?.toNumber())
|
||||
currentBid =
|
||||
winningBid && Number.isFinite(winningBid.info.lastBid?.toNumber())
|
||||
? formatTokenAmount(winningBid.info.lastBid)
|
||||
: 'No Bid'
|
||||
: 'No Bid';
|
||||
}
|
||||
|
||||
const auction = auctionView.auction.info;
|
||||
|
@ -77,9 +87,7 @@ export const AuctionRenderCard = (props: AuctionCard) => {
|
|||
<ArtContent
|
||||
className="auction-image no-events"
|
||||
preview={false}
|
||||
|
||||
pubkey={id}
|
||||
|
||||
allowMeshRender={false}
|
||||
/>
|
||||
</>
|
||||
|
@ -89,9 +97,7 @@ export const AuctionRenderCard = (props: AuctionCard) => {
|
|||
title={`${name}`}
|
||||
description={
|
||||
<>
|
||||
<h4 style={{ marginBottom: 0 }}>
|
||||
{label}
|
||||
</h4>
|
||||
<h4 style={{ marginBottom: 0 }}>{label}</h4>
|
||||
<div className="bids">
|
||||
<AmountLabel
|
||||
style={{ marginBottom: 10 }}
|
||||
|
|
|
@ -2,8 +2,6 @@ import React from 'react';
|
|||
import { GithubOutlined, TwitterOutlined } from '@ant-design/icons';
|
||||
import { Button } from 'antd';
|
||||
|
||||
import './index.less';
|
||||
|
||||
export const Footer = () => {
|
||||
return (
|
||||
<div className={'footer'}>
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import React from 'react';
|
||||
import { Layout } from 'antd';
|
||||
|
||||
import './../../App.less';
|
||||
import './index.less';
|
||||
import { LABELS } from '../../constants';
|
||||
import { AppBar } from '../AppBar';
|
||||
import useWindowDimensions from '../../utils/layout';
|
||||
|
@ -10,19 +8,22 @@ import useWindowDimensions from '../../utils/layout';
|
|||
const { Header, Content } = Layout;
|
||||
|
||||
const paddingForLayout = (width: number) => {
|
||||
if (width <= 768) return "5px 10px"
|
||||
if (width > 768) return "10px 30px"
|
||||
}
|
||||
if (width <= 768) return '5px 10px';
|
||||
if (width > 768) return '10px 30px';
|
||||
};
|
||||
|
||||
export const AppLayout = React.memo((props: any) => {
|
||||
const { width } = useWindowDimensions();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Layout title={LABELS.APP_TITLE} style={{
|
||||
padding: paddingForLayout(width),
|
||||
maxWidth: 1000,
|
||||
}}>
|
||||
<Layout
|
||||
title={LABELS.APP_TITLE}
|
||||
style={{
|
||||
padding: paddingForLayout(width),
|
||||
maxWidth: 1000,
|
||||
}}
|
||||
>
|
||||
<Header className="App-Bar">
|
||||
<AppBar />
|
||||
</Header>
|
||||
|
|
|
@ -24,7 +24,6 @@ import { settle } from '../../actions/settle';
|
|||
import { QUOTE_MINT } from '../../constants';
|
||||
import { useMeta } from '../../contexts';
|
||||
import { AuctionViewState, useAuctions } from '../../hooks';
|
||||
import './index.less';
|
||||
import { WalletAdapter } from '@solana/wallet-base';
|
||||
interface NotificationCard {
|
||||
id: string;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React from 'react';
|
||||
import { Col, Row, Button, Skeleton } from 'antd';
|
||||
|
||||
import './index.less';
|
||||
import { AuctionView, useArt } from '../../hooks';
|
||||
import { ArtContent } from '../ArtContent';
|
||||
import { AuctionCard } from '../AuctionCard';
|
||||
|
@ -31,33 +30,33 @@ export const PreSaleBanner = ({ auction }: IPreSaleBanner) => {
|
|||
/>
|
||||
</Col>
|
||||
<Col md={12} className="presale-info">
|
||||
<h2 className="art-title">
|
||||
{art.title}
|
||||
</h2>
|
||||
{auction && <AuctionCard
|
||||
auctionView={auction}
|
||||
style={{
|
||||
background: 'transparent',
|
||||
width: '100%',
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
}}
|
||||
hideDefaultAction={true}
|
||||
action={
|
||||
<>
|
||||
<Link to={`/auction/${auction.auction.pubkey.toBase58()}`}>
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
className="action-btn"
|
||||
style={{ maxWidth: 290 }}
|
||||
>
|
||||
Go to auction
|
||||
</Button>
|
||||
</Link>
|
||||
</>
|
||||
}
|
||||
/>}
|
||||
<h2 className="art-title">{art.title}</h2>
|
||||
{auction && (
|
||||
<AuctionCard
|
||||
auctionView={auction}
|
||||
style={{
|
||||
background: 'transparent',
|
||||
width: '100%',
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
}}
|
||||
hideDefaultAction={true}
|
||||
action={
|
||||
<>
|
||||
<Link to={`/auction/${auction.auction.pubkey.toBase58()}`}>
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
className="action-btn"
|
||||
style={{ maxWidth: 290 }}
|
||||
>
|
||||
Go to auction
|
||||
</Button>
|
||||
</Link>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
|
|
|
@ -4,7 +4,6 @@ import { SelectProps } from 'antd/es/select';
|
|||
import debounce from 'lodash/debounce';
|
||||
import React, { useMemo, useRef, useState } from 'react';
|
||||
import { useMeta } from '../../contexts';
|
||||
import './styles.less';
|
||||
|
||||
export interface DebounceSelectProps<ValueType = any>
|
||||
extends Omit<SelectProps<ValueType>, 'options' | 'children'> {
|
||||
|
@ -74,18 +73,16 @@ export const UserSearch = (props: { setCreators: Function }) => {
|
|||
size="large"
|
||||
value={value}
|
||||
placeholder="Select creator"
|
||||
fetchOptions={async (search: string) =>
|
||||
{
|
||||
const items = Object.values(whitelistedCreatorsByCreator)
|
||||
fetchOptions={async (search: string) => {
|
||||
const items = Object.values(whitelistedCreatorsByCreator)
|
||||
.filter(c => c.info.activated)
|
||||
.map(a => ({
|
||||
label: a.info.name || shortenAddress(a.info.address.toBase58()),
|
||||
value: a.info.address.toBase58()
|
||||
value: a.info.address.toBase58(),
|
||||
}));
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}}
|
||||
onChange={newValue => {
|
||||
props.setCreators(newValue);
|
||||
setValue(newValue);
|
||||
|
|
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
This font software is the property of Commercial Type.
|
||||
|
||||
You may not modify the font software, use it on another website, or install it on a computer.
|
||||
|
||||
License information is available at http://commercialtype.com/eula
|
||||
For more information please visit Commercial Type at http://commercialtype.com or email us at info[at]commercialtype.com
|
||||
|
||||
Copyright (C) 2021 Schwartzco Inc.
|
||||
License: 2105-CXPNNW
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-SuperItalic-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-SuperItalic-Web.woff') format('woff');
|
||||
font-weight: 900;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-SuperItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 900;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-Super-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-Super-Web.woff') format('woff');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Super-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-BlackItalic-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-BlackItalic-Web.woff') format('woff');
|
||||
font-weight: 800;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-BlackItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 800;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-Black-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-Black-Web.woff') format('woff');
|
||||
font-weight: 800;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Black-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 800;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-BoldItalic-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-BoldItalic-Web.woff') format('woff');
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-BoldItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-Bold-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-Bold-Web.woff') format('woff');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Bold-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-SemiboldItalic-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-SemiboldItalic-Web.woff') format('woff');
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-SemiboldItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-Semibold-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-Semibold-Web.woff') format('woff');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Semibold-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-MediumItalic-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-MediumItalic-Web.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-MediumItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-Medium-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-Medium-Web.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Medium-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-RegularItalic-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-RegularItalic-Web.woff') format('woff');
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-RegularItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-Regular-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-Regular-Web.woff') format('woff');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Regular-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-LightItalic-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-LightItalic-Web.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-LightItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-Light-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-Light-Web.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Light-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-ExtralightItalic-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-ExtralightItalic-Web.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-ExtralightItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-Extralight-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-Extralight-Web.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Extralight-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-ThinItalic-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-ThinItalic-Web.woff') format('woff');
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-ThinItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('/font/Graphik-Thin-Web.woff2') format('woff2'),
|
||||
url('/font/Graphik-Thin-Web.woff') format('woff');
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Thin-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
|
@ -1,318 +0,0 @@
|
|||
/*
|
||||
This font software is the property of Commercial Type.
|
||||
|
||||
You may not modify the font software, use it on another website, or install it on a computer.
|
||||
|
||||
License information is available at http://commercialtype.com/eula
|
||||
For more information please visit Commercial Type at http://commercialtype.com or email us at info[at]commercialtype.com
|
||||
|
||||
Copyright (C) 2021 Schwartzco Inc.
|
||||
License: 2105-CXPNNW
|
||||
*/
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-SuperItalic-Web.woff2') format('woff2'),
|
||||
url('Graphik-SuperItalic-Web.woff') format('woff');
|
||||
font-weight: 900;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-SuperItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 900;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-Super-Web.woff2') format('woff2'),
|
||||
url('Graphik-Super-Web.woff') format('woff');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Super-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-BlackItalic-Web.woff2') format('woff2'),
|
||||
url('Graphik-BlackItalic-Web.woff') format('woff');
|
||||
font-weight: 800;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-BlackItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 800;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-Black-Web.woff2') format('woff2'),
|
||||
url('Graphik-Black-Web.woff') format('woff');
|
||||
font-weight: 800;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Black-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 800;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-BoldItalic-Web.woff2') format('woff2'),
|
||||
url('Graphik-BoldItalic-Web.woff') format('woff');
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-BoldItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-Bold-Web.woff2') format('woff2'),
|
||||
url('Graphik-Bold-Web.woff') format('woff');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Bold-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-SemiboldItalic-Web.woff2') format('woff2'),
|
||||
url('Graphik-SemiboldItalic-Web.woff') format('woff');
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-SemiboldItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-Semibold-Web.woff2') format('woff2'),
|
||||
url('Graphik-Semibold-Web.woff') format('woff');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Semibold-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-MediumItalic-Web.woff2') format('woff2'),
|
||||
url('Graphik-MediumItalic-Web.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-MediumItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-Medium-Web.woff2') format('woff2'),
|
||||
url('Graphik-Medium-Web.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Medium-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-RegularItalic-Web.woff2') format('woff2'),
|
||||
url('Graphik-RegularItalic-Web.woff') format('woff');
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-RegularItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-Regular-Web.woff2') format('woff2'),
|
||||
url('Graphik-Regular-Web.woff') format('woff');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Regular-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-LightItalic-Web.woff2') format('woff2'),
|
||||
url('Graphik-LightItalic-Web.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-LightItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-Light-Web.woff2') format('woff2'),
|
||||
url('Graphik-Light-Web.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Light-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-ExtralightItalic-Web.woff2') format('woff2'),
|
||||
url('Graphik-ExtralightItalic-Web.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-ExtralightItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-Extralight-Web.woff2') format('woff2'),
|
||||
url('Graphik-Extralight-Web.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Extralight-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-ThinItalic-Web.woff2') format('woff2'),
|
||||
url('Graphik-ThinItalic-Web.woff') format('woff');
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-ThinItalic-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'GraphikWeb';
|
||||
src: url('Graphik-Thin-Web.woff2') format('woff2'),
|
||||
url('Graphik-Thin-Web.woff') format('woff');
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
||||
.Graphik-Thin-Web {
|
||||
font-family: 'GraphikWeb';
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
import './wdyr';
|
||||
|
||||
import './fonts/fonts.less';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './App';
|
||||
import * as serviceWorker from './serviceWorker';
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root'),
|
||||
);
|
||||
|
||||
// If you want your app to work offline and load faster, you can change
|
||||
// unregister() to register() below. Note this comes with some pitfalls.
|
||||
// Learn more about service workers: https://bit.ly/CRA-PWA
|
||||
serviceWorker.unregister();
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"name": "Metaplex NFT Marketplace",
|
||||
"short_name": "Metaplex NFT Marketplace",
|
||||
"display": "standalone",
|
||||
"start_url": "./",
|
||||
"theme_color": "#002140",
|
||||
"background_color": "#001529",
|
||||
"icons": [
|
||||
{
|
||||
"src": "icons/icon-192x192.png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "icons/icon-128x128.png",
|
||||
"sizes": "128x128"
|
||||
},
|
||||
{
|
||||
"src": "icons/icon-512x512.png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import type { AppProps } from 'next/app';
|
||||
import Head from 'next/head';
|
||||
|
||||
import '../styles.less';
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Metaplex NFT Marketplace</title>
|
||||
</Head>
|
||||
{typeof window === 'undefined' ? null : <Component {...pageProps} />}
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
import Document, {
|
||||
Html,
|
||||
Head,
|
||||
Main,
|
||||
NextScript,
|
||||
DocumentContext,
|
||||
} from 'next/document';
|
||||
|
||||
export default class MetaplexDocument extends Document {
|
||||
static async getInitialProps(ctx: DocumentContext) {
|
||||
const initialProps = await Document.getInitialProps(ctx);
|
||||
return { ...initialProps };
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta
|
||||
name="loadforge-site-verification"
|
||||
content="2056680d2883a8b910880d53b9cb2ebf16e7b8f91e169cceddce62c4c4ef8fe6240748c08c2e3769e554e12dafcd5bfc62028638e6524a0efd7d729efd762d42"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="/favicon-32x32.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="96x96"
|
||||
href="/favicon-96x96.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="16x16"
|
||||
href="/favicon-16x16.png"
|
||||
/>
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" content="Metaplex NFT Marketplace" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"
|
||||
integrity="sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA=="
|
||||
crossOrigin="anonymous"
|
||||
/>
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
<script
|
||||
async
|
||||
src="https://platform.twitter.com/widgets.js"
|
||||
charSet="utf-8"
|
||||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
(function () {
|
||||
var s = document.createElement("script");
|
||||
s.src = "https://stackpile.io/stack_162299.js"; s.async = true;
|
||||
var e = document.getElementsByTagName("script")[0]; e.parentNode.insertBefore(s, e);
|
||||
})();
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
const CreateReactAppEntryPoint = dynamic(() => import('../App'), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
function App() {
|
||||
const [isMounted, setIsMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsMounted(true);
|
||||
}, []);
|
||||
|
||||
if (!isMounted) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <CreateReactAppEntryPoint />;
|
||||
}
|
||||
|
||||
export default App;
|
|
@ -1 +0,0 @@
|
|||
/// <reference types="react-scripts" />
|
|
@ -1,146 +0,0 @@
|
|||
// This optional code is used to register a service worker.
|
||||
// register() is not called by default.
|
||||
|
||||
// This lets the app load faster on subsequent visits in production, and gives
|
||||
// it offline capabilities. However, it also means that developers (and users)
|
||||
// will only see deployed updates on subsequent visits to a page, after all the
|
||||
// existing tabs open on the page have been closed, since previously cached
|
||||
// resources are updated in the background.
|
||||
|
||||
// To learn more about the benefits of this model and instructions on how to
|
||||
// opt-in, read https://bit.ly/CRA-PWA
|
||||
|
||||
const isLocalhost = Boolean(
|
||||
window.location.hostname === 'localhost' ||
|
||||
// [::1] is the IPv6 localhost address.
|
||||
window.location.hostname === '[::1]' ||
|
||||
// 127.0.0.0/8 are considered localhost for IPv4.
|
||||
window.location.hostname.match(
|
||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/,
|
||||
),
|
||||
);
|
||||
|
||||
type Config = {
|
||||
onSuccess?: (registration: ServiceWorkerRegistration) => void;
|
||||
onUpdate?: (registration: ServiceWorkerRegistration) => void;
|
||||
};
|
||||
|
||||
export function register(config?: Config) {
|
||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
// The URL constructor is available in all browsers that support SW.
|
||||
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
|
||||
if (publicUrl.origin !== window.location.origin) {
|
||||
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||
// from what our page is served on. This might happen if a CDN is used to
|
||||
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||
|
||||
if (isLocalhost) {
|
||||
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||
checkValidServiceWorker(swUrl, config);
|
||||
|
||||
// Add some additional logging to localhost, pointing developers to the
|
||||
// service worker/PWA documentation.
|
||||
navigator.serviceWorker.ready.then(() => {
|
||||
console.log(
|
||||
'This web app is being served cache-first by a service ' +
|
||||
'worker. To learn more, visit https://bit.ly/CRA-PWA',
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// Is not localhost. Just register service worker
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function registerValidSW(swUrl: string, config?: Config) {
|
||||
navigator.serviceWorker
|
||||
.register(swUrl)
|
||||
.then(registration => {
|
||||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing;
|
||||
if (installingWorker === null) {
|
||||
return;
|
||||
}
|
||||
installingWorker.onstatechange = () => {
|
||||
if (installingWorker.state === 'installed') {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
// At this point, the updated precached content has been fetched,
|
||||
// but the previous service worker will still serve the older
|
||||
// content until all client tabs are closed.
|
||||
console.log(
|
||||
'New content is available and will be used when all ' +
|
||||
'tabs for this page are closed. See https://bit.ly/CRA-PWA.',
|
||||
);
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onUpdate) {
|
||||
config.onUpdate(registration);
|
||||
}
|
||||
} else {
|
||||
// At this point, everything has been precached.
|
||||
// It's the perfect time to display a
|
||||
// "Content is cached for offline use." message.
|
||||
console.log('Content is cached for offline use.');
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onSuccess) {
|
||||
config.onSuccess(registration);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during service worker registration:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function checkValidServiceWorker(swUrl: string, config?: Config) {
|
||||
// Check if the service worker can be found. If it can't reload the page.
|
||||
fetch(swUrl, {
|
||||
headers: { 'Service-Worker': 'script' },
|
||||
})
|
||||
.then(response => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (
|
||||
response.status === 404 ||
|
||||
(contentType !== null && contentType.indexOf('javascript') === -1)
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Service worker found. Proceed as normal.
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.log(
|
||||
'No internet connection found. App is running in offline mode.',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function unregister() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.ready
|
||||
.then(registration => {
|
||||
registration.unregister();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error.message);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
@import './fonts.less';
|
||||
@import './App.less';
|
||||
|
||||
@import '@oyster/common/styles.css';
|
||||
|
||||
@import './views/home/index.less';
|
||||
@import './views/styles.less';
|
||||
@import './views/auction/billing.less';
|
||||
@import './views/auction/index.less';
|
||||
@import './views/art/index.less';
|
||||
@import './views/admin/index.less';
|
||||
|
||||
@import './components/AuctionRenderCard/index.less';
|
||||
@import './components/AppBar/index.less';
|
||||
@import './components/AppBar/searchBox.less';
|
||||
@import './components/Footer/index.less';
|
||||
@import './components/AmountLabel/index.less';
|
||||
@import './components/Layout/index.less';
|
||||
@import './components/UserSearch/styles.less';
|
||||
@import './components/PreSaleBanner/index.less';
|
||||
@import './components/AuctionCard/index.less';
|
||||
@import './components/ArtCard/index.less';
|
||||
@import './components/ArtistCard/index.less';
|
||||
@import './components/Notifications/index.less';
|
|
@ -22,7 +22,6 @@ import {
|
|||
import { Connection, PublicKey } from '@solana/web3.js';
|
||||
import { saveAdmin } from '../../actions/saveAdmin';
|
||||
import { WalletAdapter } from '@solana/wallet-base';
|
||||
import './index.less';
|
||||
|
||||
const { Content } = Layout;
|
||||
export const AdminView = () => {
|
||||
|
@ -84,8 +83,8 @@ function ArtistModal({
|
|||
} catch {
|
||||
notify({
|
||||
message: 'Only valid Solana addresses are supported',
|
||||
type: 'error'
|
||||
})
|
||||
type: 'error',
|
||||
});
|
||||
}
|
||||
}}
|
||||
onCancel={() => {
|
||||
|
@ -117,12 +116,13 @@ function InnerAdminView({
|
|||
connection: Connection;
|
||||
wallet: WalletAdapter;
|
||||
}) {
|
||||
const [newStore, setNewStore] = useState(store && store.info && new Store(store.info));
|
||||
const [newStore, setNewStore] = useState(
|
||||
store && store.info && new Store(store.info),
|
||||
);
|
||||
const [updatedCreators, setUpdatedCreators] = useState<
|
||||
Record<string, WhitelistedCreator>
|
||||
>({});
|
||||
|
||||
|
||||
if (!store || !newStore) {
|
||||
return <p>Store is not defined</p>;
|
||||
}
|
||||
|
@ -234,8 +234,12 @@ function InnerAdminView({
|
|||
key,
|
||||
address: uniqueCreatorsWithUpdates[key].address,
|
||||
activated: uniqueCreatorsWithUpdates[key].activated,
|
||||
name: uniqueCreatorsWithUpdates[key].name || shortenAddress(uniqueCreatorsWithUpdates[key].address.toBase58()),
|
||||
image: uniqueCreatorsWithUpdates[key].image
|
||||
name:
|
||||
uniqueCreatorsWithUpdates[key].name ||
|
||||
shortenAddress(
|
||||
uniqueCreatorsWithUpdates[key].address.toBase58(),
|
||||
),
|
||||
image: uniqueCreatorsWithUpdates[key].image,
|
||||
}))}
|
||||
></Table>
|
||||
</Row>
|
||||
|
|
|
@ -3,7 +3,6 @@ import { Row, Col, Divider, Layout, Tag, Button, Skeleton } from 'antd';
|
|||
import { useParams } from 'react-router-dom';
|
||||
import { useArt, useExtendedArt } from './../../hooks';
|
||||
|
||||
import './index.less';
|
||||
import { ArtContent } from '../../components/ArtContent';
|
||||
import { shortenAddress, useConnection, useWallet } from '@oyster/common';
|
||||
import { MetaAvatar } from '../../components/MetaAvatar';
|
||||
|
@ -74,7 +73,9 @@ export const ArtView = () => {
|
|||
style={{ textAlign: 'left', fontSize: '1.4rem' }}
|
||||
>
|
||||
<Row>
|
||||
<div style={{ fontWeight: 700, fontSize: '4rem' }}>{art.title || <Skeleton paragraph={{ rows: 0 }} />}</div>
|
||||
<div style={{ fontWeight: 700, fontSize: '4rem' }}>
|
||||
{art.title || <Skeleton paragraph={{ rows: 0 }} />}
|
||||
</div>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col span={6}>
|
||||
|
@ -91,16 +92,20 @@ export const ArtView = () => {
|
|||
<Col>
|
||||
<h6 style={{ marginTop: 5 }}>Created By</h6>
|
||||
<div className="creators">
|
||||
{(art.creators || [])
|
||||
.map(creator => {
|
||||
{(art.creators || []).map(creator => {
|
||||
return (
|
||||
<div
|
||||
style={{ display: 'flex', alignItems: 'center', marginBottom: 5 }}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginBottom: 5,
|
||||
}}
|
||||
>
|
||||
<MetaAvatar creators={[creator]} size={64} />
|
||||
<div>
|
||||
<span className="creator-name">
|
||||
{creator.name || shortenAddress(creator.address || '')}
|
||||
{creator.name ||
|
||||
shortenAddress(creator.address || '')}
|
||||
</span>
|
||||
<div style={{ marginLeft: 10 }}>
|
||||
{!creator.verified &&
|
||||
|
|
|
@ -17,7 +17,6 @@ import {
|
|||
import { ArtCard } from './../../components/ArtCard';
|
||||
import { UserSearch, UserValue } from './../../components/UserSearch';
|
||||
import { Confetti } from './../../components/Confetti';
|
||||
import './../styles.less';
|
||||
import { mintNFT } from '../../actions';
|
||||
import {
|
||||
MAX_METADATA_LEN,
|
||||
|
@ -285,16 +284,18 @@ const CategoryStep = (props: {
|
|||
const UploadStep = (props: {
|
||||
attributes: IMetadataExtension;
|
||||
setAttributes: (attr: IMetadataExtension) => void;
|
||||
files: File[],
|
||||
setFiles: (files: File[]) => void,
|
||||
files: File[];
|
||||
setFiles: (files: File[]) => void;
|
||||
confirm: () => void;
|
||||
}) => {
|
||||
const [coverFile, setCoverFile] = useState<File | undefined>(props.files?.[0]);
|
||||
const [coverFile, setCoverFile] = useState<File | undefined>(
|
||||
props.files?.[0],
|
||||
);
|
||||
const [mainFile, setMainFile] = useState<File | undefined>(props.files?.[1]);
|
||||
|
||||
const [customURL, setCustomURL] = useState<string>('');
|
||||
const [customURLErr, setCustomURLErr] = useState<string>('');
|
||||
const disableContinue = (!coverFile) || !!customURLErr;
|
||||
const disableContinue = !coverFile || !!customURLErr;
|
||||
|
||||
useEffect(() => {
|
||||
props.setAttributes({
|
||||
|
@ -349,62 +350,64 @@ const UploadStep = (props: {
|
|||
</p>
|
||||
</Row>
|
||||
<Row className="content-action">
|
||||
<h3>
|
||||
Upload a cover image (PNG, JPG, GIF)
|
||||
</h3>
|
||||
<h3>Upload a cover image (PNG, JPG, GIF)</h3>
|
||||
<Dragger
|
||||
accept=".png,.jpg,.gif,.mp4"
|
||||
style={{ padding: 20 }}
|
||||
multiple={false}
|
||||
customRequest={info => {
|
||||
// dont upload files here, handled outside of the control
|
||||
info?.onSuccess?.({}, null as any);
|
||||
}}
|
||||
fileList={coverFile ? [coverFile as any] : []}
|
||||
onChange={async info => {
|
||||
const file = info.file.originFileObj;
|
||||
if (file) setCoverFile(file);
|
||||
}}
|
||||
>
|
||||
<div className="ant-upload-drag-icon">
|
||||
<h3 style={{ fontWeight: 700 }}>
|
||||
Upload your cover image (PNG, JPG, GIF)
|
||||
</h3>
|
||||
</div>
|
||||
<p className="ant-upload-text">Drag and drop, or click to browse</p>
|
||||
</Dragger>
|
||||
</Row>
|
||||
{props.attributes.properties?.category !== MetadataCategory.Image && (
|
||||
<Row
|
||||
className="content-action"
|
||||
style={{ marginBottom: 5, marginTop: 30 }}
|
||||
>
|
||||
<h3>{uploadMsg(props.attributes.properties?.category)}</h3>
|
||||
<Dragger
|
||||
accept=".png,.jpg,.gif,.mp4"
|
||||
style={{ padding: 20 }}
|
||||
accept={acceptableFiles(props.attributes.properties?.category)}
|
||||
style={{ padding: 20, background: 'rgba(255, 255, 255, 0.08)' }}
|
||||
multiple={false}
|
||||
customRequest={info => {
|
||||
// dont upload files here, handled outside of the control
|
||||
info?.onSuccess?.({}, null as any);
|
||||
}}
|
||||
fileList={coverFile ? [coverFile as any] : []}
|
||||
fileList={mainFile ? [mainFile as any] : []}
|
||||
onChange={async info => {
|
||||
const file = info.file.originFileObj;
|
||||
if (file) setCoverFile(file);
|
||||
|
||||
// Reset image URL
|
||||
setCustomURL('');
|
||||
setCustomURLErr('');
|
||||
|
||||
if (file) setMainFile(file);
|
||||
}}
|
||||
onRemove={() => {
|
||||
setMainFile(undefined);
|
||||
}}
|
||||
>
|
||||
<div className="ant-upload-drag-icon">
|
||||
<h3 style={{ fontWeight: 700 }}>
|
||||
Upload your cover image (PNG, JPG, GIF)
|
||||
</h3>
|
||||
<h3 style={{ fontWeight: 700 }}>Upload your creation</h3>
|
||||
</div>
|
||||
<p className="ant-upload-text">Drag and drop, or click to browse</p>
|
||||
</Dragger>
|
||||
</Row>
|
||||
{(props.attributes.properties?.category !== MetadataCategory.Image) && (
|
||||
<Row className="content-action" style={{ marginBottom: 5, marginTop: 30 }}>
|
||||
<h3>{uploadMsg(props.attributes.properties?.category)}</h3>
|
||||
<Dragger
|
||||
accept={acceptableFiles(props.attributes.properties?.category)}
|
||||
style={{ padding: 20, background: 'rgba(255, 255, 255, 0.08)' }}
|
||||
multiple={false}
|
||||
customRequest={info => {
|
||||
// dont upload files here, handled outside of the control
|
||||
info?.onSuccess?.({}, null as any);
|
||||
}}
|
||||
fileList={mainFile ? [mainFile as any] : []}
|
||||
onChange={async info => {
|
||||
const file = info.file.originFileObj;
|
||||
|
||||
// Reset image URL
|
||||
setCustomURL('');
|
||||
setCustomURLErr('');
|
||||
|
||||
if (file) setMainFile(file);
|
||||
}}
|
||||
onRemove={() => {
|
||||
setMainFile(undefined);
|
||||
}}
|
||||
>
|
||||
<div className="ant-upload-drag-icon">
|
||||
<h3 style={{ fontWeight: 700 }}>Upload your creation</h3>
|
||||
</div>
|
||||
<p className="ant-upload-text">Drag and drop, or click to browse</p>
|
||||
</Dragger>
|
||||
</Row>)}
|
||||
)}
|
||||
<Form.Item
|
||||
style={{
|
||||
width: '100%',
|
||||
|
@ -453,18 +456,20 @@ const UploadStep = (props: {
|
|||
properties: {
|
||||
...props.attributes.properties,
|
||||
files: [coverFile, mainFile, customURL]
|
||||
.filter(f => f)
|
||||
.map(
|
||||
f => {
|
||||
const uri = typeof f === 'string' ? f : (cleanName(f?.name) || '');
|
||||
const type = typeof f === 'string' || !f ? 'unknown' : f.type || (getLast(f.name.split('.')) || 'unknown');
|
||||
.filter(f => f)
|
||||
.map(f => {
|
||||
const uri =
|
||||
typeof f === 'string' ? f : cleanName(f?.name) || '';
|
||||
const type =
|
||||
typeof f === 'string' || !f
|
||||
? 'unknown'
|
||||
: f.type || getLast(f.name.split('.')) || 'unknown';
|
||||
|
||||
return ({
|
||||
uri,
|
||||
type
|
||||
}) as MetadataFile;
|
||||
},
|
||||
),
|
||||
return {
|
||||
uri,
|
||||
type,
|
||||
} as MetadataFile;
|
||||
}),
|
||||
},
|
||||
image: cleanName(coverFile?.name) || '',
|
||||
animation_url: cleanName(mainFile && mainFile.name),
|
||||
|
@ -488,35 +493,38 @@ interface Royalty {
|
|||
}
|
||||
|
||||
const useArtworkFiles = (files: File[], attributes: IMetadataExtension) => {
|
||||
const [data, setData] = useState<{ image: string, animation_url: string }>({ image: '', animation_url: '' });
|
||||
const [data, setData] = useState<{ image: string; animation_url: string }>({
|
||||
image: '',
|
||||
animation_url: '',
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if(attributes.image) {
|
||||
if (attributes.image) {
|
||||
const file = files.find(f => f.name === attributes.image);
|
||||
if(file) {
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (event) {
|
||||
setData((data: any) => {
|
||||
return {
|
||||
...(data || {}),
|
||||
image: (event.target?.result as string) || '',
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
if (file) reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
|
||||
if(attributes.animation_url) {
|
||||
if (attributes.animation_url) {
|
||||
const file = files.find(f => f.name === attributes.animation_url);
|
||||
if(file) {
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (event) {
|
||||
setData((data: any) => {
|
||||
return {
|
||||
...(data || {}),
|
||||
animation_url: (event.target?.result as string) || '',
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
if (file) reader.readAsDataURL(file);
|
||||
|
@ -525,17 +533,20 @@ const useArtworkFiles = (files: File[], attributes: IMetadataExtension) => {
|
|||
}, [files, attributes]);
|
||||
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
const InfoStep = (props: {
|
||||
attributes: IMetadataExtension;
|
||||
files: File[],
|
||||
files: File[];
|
||||
setAttributes: (attr: IMetadataExtension) => void;
|
||||
confirm: () => void;
|
||||
}) => {
|
||||
const [creators, setCreators] = useState<Array<UserValue>>([]);
|
||||
const [royalties, setRoyalties] = useState<Array<Royalty>>([]);
|
||||
const { image, animation_url } = useArtworkFiles(props.files, props.attributes);
|
||||
const { image, animation_url } = useArtworkFiles(
|
||||
props.files,
|
||||
props.attributes,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setRoyalties(
|
||||
|
@ -921,11 +932,14 @@ const RoyaltiesStep = (props: {
|
|||
const LaunchStep = (props: {
|
||||
confirm: () => void;
|
||||
attributes: IMetadataExtension;
|
||||
files: File[],
|
||||
files: File[];
|
||||
connection: Connection;
|
||||
}) => {
|
||||
const [cost, setCost] = useState(0);
|
||||
const { image, animation_url } = useArtworkFiles(props.files, props.attributes);
|
||||
const { image, animation_url } = useArtworkFiles(
|
||||
props.files,
|
||||
props.attributes,
|
||||
);
|
||||
const files = props.files;
|
||||
const metadata = props.attributes;
|
||||
useEffect(() => {
|
||||
|
|
|
@ -31,7 +31,6 @@ import {
|
|||
PayoutTicket,
|
||||
WinningConstraint,
|
||||
} from '../../models/metaplex';
|
||||
import './billing.less';
|
||||
import { WalletAdapter } from '@solana/wallet-base';
|
||||
import { Connection, PublicKey } from '@solana/web3.js';
|
||||
import { settle } from '../../actions/settle';
|
||||
|
|
|
@ -13,7 +13,6 @@ import {
|
|||
} from '../../hooks';
|
||||
import { ArtContent } from '../../components/ArtContent';
|
||||
|
||||
import './index.less';
|
||||
import {
|
||||
formatTokenAmount,
|
||||
Identicon,
|
||||
|
@ -81,8 +80,7 @@ export const AuctionView = () => {
|
|||
const nftCount = auction?.items.flat().length;
|
||||
const winnerCount = auction?.items.length;
|
||||
|
||||
|
||||
const hasDescription = data === undefined || data.description === undefined
|
||||
const hasDescription = data === undefined || data.description === undefined;
|
||||
const description = data?.description;
|
||||
|
||||
const items = [
|
||||
|
@ -115,7 +113,6 @@ export const AuctionView = () => {
|
|||
<Row justify="space-around" ref={ref}>
|
||||
<Col span={24} md={12} className="pr-4">
|
||||
<div className="auction-view" style={{ minHeight: 300 }}>
|
||||
|
||||
<Carousel
|
||||
autoplay={false}
|
||||
afterChange={index => setCurrentIndex(index)}
|
||||
|
@ -124,17 +121,30 @@ export const AuctionView = () => {
|
|||
</Carousel>
|
||||
</div>
|
||||
<h6>Number Of Winners</h6>
|
||||
<h1>{winnerCount === undefined ? <Skeleton paragraph={{ rows: 0 }} /> : winnerCount}</h1>
|
||||
<h1>
|
||||
{winnerCount === undefined ? (
|
||||
<Skeleton paragraph={{ rows: 0 }} />
|
||||
) : (
|
||||
winnerCount
|
||||
)}
|
||||
</h1>
|
||||
<h6>Number Of NFTs</h6>
|
||||
<h1>{nftCount === undefined ? <Skeleton paragraph={{ rows: 0 }} /> : nftCount}</h1>
|
||||
<h1>
|
||||
{nftCount === undefined ? (
|
||||
<Skeleton paragraph={{ rows: 0 }} />
|
||||
) : (
|
||||
nftCount
|
||||
)}
|
||||
</h1>
|
||||
<h6>About this {nftCount === 1 ? 'NFT' : 'Collection'}</h6>
|
||||
<p>
|
||||
{hasDescription && <Skeleton paragraph={{ rows: 3 }} />}
|
||||
{description || (
|
||||
winnerCount !== undefined && <div style={{ fontStyle: 'italic' }}>
|
||||
No description provided.
|
||||
</div>
|
||||
)}
|
||||
{description ||
|
||||
(winnerCount !== undefined && (
|
||||
<div style={{ fontStyle: 'italic' }}>
|
||||
No description provided.
|
||||
</div>
|
||||
))}
|
||||
</p>
|
||||
{/* {auctionData[id] && (
|
||||
<>
|
||||
|
@ -145,7 +155,9 @@ export const AuctionView = () => {
|
|||
</Col>
|
||||
|
||||
<Col span={24} md={12}>
|
||||
<h2 className="art-title">{art.title || <Skeleton paragraph={{ rows: 0 }} />}</h2>
|
||||
<h2 className="art-title">
|
||||
{art.title || <Skeleton paragraph={{ rows: 0 }} />}
|
||||
</h2>
|
||||
<Row gutter={[50, 0]} style={{ marginRight: 'unset' }}>
|
||||
<Col>
|
||||
<h6>Edition</h6>
|
||||
|
@ -248,7 +260,7 @@ const BidLine = (props: { bid: any; index: number; mint?: MintInfo, isCancelled?
|
|||
</Col>
|
||||
<Col span={6} style={{ textAlign: 'right' }}>
|
||||
<span title={fromLamports(bid.info.lastBid, mint).toString()}>
|
||||
◎{formatTokenAmount(bid.info.lastBid, mint)}
|
||||
◎{formatTokenAmount(bid.info.lastBid, mint)}
|
||||
</span>
|
||||
</Col>
|
||||
</Row>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useMemo, useState } from 'react';
|
||||
import { Row, Button, Modal, ButtonProps } from 'antd';
|
||||
import { ArtCard } from './../../components/ArtCard';
|
||||
import './../styles.less';
|
||||
import { useUserArts } from '../../hooks';
|
||||
import Masonry from 'react-masonry-css';
|
||||
import { SafetyDepositDraft } from '../../actions/createAuctionManager';
|
||||
|
@ -98,7 +97,10 @@ export const ArtSelector = (props: ArtSelectorProps) => {
|
|||
Select the NFT that you want to sell copy/copies of.
|
||||
</p>
|
||||
</Row>
|
||||
<Row className="content-action" style={{ overflowY: 'auto', height: "50vh" }}>
|
||||
<Row
|
||||
className="content-action"
|
||||
style={{ overflowY: 'auto', height: '50vh' }}
|
||||
>
|
||||
<Masonry
|
||||
breakpointCols={breakpointColumnsObj}
|
||||
className="my-masonry-grid"
|
||||
|
|
|
@ -18,7 +18,6 @@ import { ArtCard } from './../../components/ArtCard';
|
|||
import { QUOTE_MINT } from './../../constants';
|
||||
import { Confetti } from './../../components/Confetti';
|
||||
import { ArtSelector } from './artSelector';
|
||||
import './../styles.less';
|
||||
import {
|
||||
MAX_METADATA_LEN,
|
||||
useConnection,
|
||||
|
@ -32,11 +31,7 @@ import {
|
|||
PriceFloorType,
|
||||
IPartialCreateAuctionArgs,
|
||||
} from '@oyster/common';
|
||||
import {
|
||||
Connection,
|
||||
LAMPORTS_PER_SOL,
|
||||
PublicKey,
|
||||
} from '@solana/web3.js';
|
||||
import { Connection, LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
|
||||
import { MintLayout } from '@solana/spl-token';
|
||||
import { useHistory, useParams } from 'react-router-dom';
|
||||
import { capitalize } from 'lodash';
|
||||
|
@ -55,7 +50,7 @@ import {
|
|||
SafetyDepositDraft,
|
||||
} from '../../actions/createAuctionManager';
|
||||
import BN from 'bn.js';
|
||||
import { ZERO } from '@oyster/common/dist/lib/constants';
|
||||
import { constants } from '@oyster/common';
|
||||
import { DateTimePicker } from '../../components/DateTimePicker';
|
||||
import { AmountLabel } from '../../components/AmountLabel';
|
||||
import { useMeta } from '../../contexts';
|
||||
|
@ -64,6 +59,7 @@ import { PlusCircleOutlined } from '@ant-design/icons';
|
|||
|
||||
const { Option } = Select;
|
||||
const { Step } = Steps;
|
||||
const { ZERO } = constants;
|
||||
|
||||
export enum AuctionCategory {
|
||||
Limited,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
@import '_colors';
|
||||
|
||||
@import '../../_colors.less';
|
||||
|
||||
section.ant-layout {
|
||||
width: 100%;
|
||||
|
@ -52,7 +51,8 @@ a:active {
|
|||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
.my-masonry-grid_column > div { /* change div to reference your elements you put in <Masonry> */
|
||||
.my-masonry-grid_column > div {
|
||||
/* change div to reference your elements you put in <Masonry> */
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import Masonry from 'react-masonry-css';
|
|||
import { PreSaleBanner } from '../../components/PreSaleBanner';
|
||||
import { AuctionViewState, useAuctions } from '../../hooks';
|
||||
|
||||
import './index.less';
|
||||
import { AuctionRenderCard } from '../../components/AuctionRenderCard';
|
||||
import { Link, useHistory } from 'react-router-dom';
|
||||
import { CardLoader } from '../../components/MyLoader';
|
||||
|
@ -44,8 +43,12 @@ export const HomeView = () => {
|
|||
[auctions],
|
||||
);
|
||||
|
||||
const liveAuctions = auctions
|
||||
.sort((a, b) => a.auction.info.endedAt?.sub(b.auction.info.endedAt || new BN(0)).toNumber() || 0);
|
||||
const liveAuctions = auctions.sort(
|
||||
(a, b) =>
|
||||
a.auction.info.endedAt
|
||||
?.sub(b.auction.info.endedAt || new BN(0))
|
||||
.toNumber() || 0,
|
||||
);
|
||||
|
||||
const liveAuctionsView = (
|
||||
<Masonry
|
||||
|
@ -55,17 +58,17 @@ export const HomeView = () => {
|
|||
>
|
||||
{!isLoading
|
||||
? liveAuctions.map((m, idx) => {
|
||||
if (m === heroAuction) {
|
||||
return;
|
||||
}
|
||||
if (m === heroAuction) {
|
||||
return;
|
||||
}
|
||||
|
||||
const id = m.auction.pubkey.toBase58();
|
||||
return (
|
||||
<Link to={`/auction/${id}`} key={idx}>
|
||||
<AuctionRenderCard key={id} auctionView={m} />
|
||||
</Link>
|
||||
);
|
||||
})
|
||||
const id = m.auction.pubkey.toBase58();
|
||||
return (
|
||||
<Link to={`/auction/${id}`} key={idx}>
|
||||
<AuctionRenderCard key={id} auctionView={m} />
|
||||
</Link>
|
||||
);
|
||||
})
|
||||
: [...Array(10)].map((_, idx) => <CardLoader key={idx} />)}
|
||||
</Masonry>
|
||||
);
|
||||
|
@ -98,50 +101,81 @@ export const HomeView = () => {
|
|||
|
||||
return (
|
||||
<Layout style={{ margin: 0, marginTop: 30, alignItems: 'center' }}>
|
||||
{!store && !isLoading && <>
|
||||
{!CURRENT_STORE && <p>Store has not been configured please set <em>REACT_APP_STORE_OWNER_ADDRESS_ADDRESS</em> to admin wallet inside <em>packages/web/.env</em> and restart yarn</p>}
|
||||
{CURRENT_STORE && !wallet?.publicKey && <p><Button type="primary" className="app-btn" onClick={connect}>Connect</Button> to configure store.</p>}
|
||||
{CURRENT_STORE && wallet?.publicKey && <>
|
||||
<p>Initializing store will allow you to control list of creators.</p>
|
||||
{!store && !isLoading && (
|
||||
<>
|
||||
{!CURRENT_STORE && (
|
||||
<p>
|
||||
Store has not been configured please set{' '}
|
||||
<em>REACT_APP_STORE_OWNER_ADDRESS_ADDRESS</em> to admin wallet
|
||||
inside <em>packages/web/.env</em> and restart yarn
|
||||
</p>
|
||||
)}
|
||||
{CURRENT_STORE && !wallet?.publicKey && (
|
||||
<p>
|
||||
<Button type="primary" className="app-btn" onClick={connect}>
|
||||
Connect
|
||||
</Button>{' '}
|
||||
to configure store.
|
||||
</p>
|
||||
)}
|
||||
{CURRENT_STORE && wallet?.publicKey && (
|
||||
<>
|
||||
<p>
|
||||
Initializing store will allow you to control list of creators.
|
||||
</p>
|
||||
|
||||
<Button className="app-btn" type="primary" loading={isInitalizingStore} disabled={!CURRENT_STORE} onClick={async () => {
|
||||
if(!wallet?.publicKey) {
|
||||
return;
|
||||
}
|
||||
<Button
|
||||
className="app-btn"
|
||||
type="primary"
|
||||
loading={isInitalizingStore}
|
||||
disabled={!CURRENT_STORE}
|
||||
onClick={async () => {
|
||||
if (!wallet?.publicKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsInitalizingStore(true);
|
||||
setIsInitalizingStore(true);
|
||||
|
||||
await saveAdmin(connection, wallet, false, [new WhitelistedCreator({
|
||||
address: wallet?.publicKey,
|
||||
activated: true,
|
||||
})]);
|
||||
await saveAdmin(connection, wallet, false, [
|
||||
new WhitelistedCreator({
|
||||
address: wallet?.publicKey,
|
||||
activated: true,
|
||||
}),
|
||||
]);
|
||||
|
||||
history.push('/admin');
|
||||
history.push('/admin');
|
||||
|
||||
window.location.reload();
|
||||
}}>Init Store</Button>
|
||||
</>}
|
||||
</>}
|
||||
window.location.reload();
|
||||
}}
|
||||
>
|
||||
Init Store
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<PreSaleBanner auction={heroAuction} />
|
||||
<Layout>
|
||||
<Content style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
<Col style={{ width: '100%', marginTop: 10 }}>
|
||||
{liveAuctions.length > 1 && (<Row>
|
||||
<Tabs>
|
||||
<TabPane>
|
||||
<h2>Live Auctions</h2>
|
||||
{liveAuctionsView}
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</Row>)}
|
||||
{liveAuctions.length > 1 && (
|
||||
<Row>
|
||||
<Tabs>
|
||||
<TabPane>
|
||||
<h2>Live Auctions</h2>
|
||||
{liveAuctionsView}
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</Row>
|
||||
)}
|
||||
<Row>
|
||||
{auctionsEnded.length > 0 && (
|
||||
<Tabs>
|
||||
<TabPane>
|
||||
<h2>Ended Auctions</h2>
|
||||
{endedAuctions}
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
<Tabs>
|
||||
<TabPane>
|
||||
<h2>Ended Auctions</h2>
|
||||
{endedAuctions}
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
)}
|
||||
<br />
|
||||
</Row>
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
// const whyDidYouRender = require('@welldone-software/why-did-you-render');
|
||||
// whyDidYouRender(React, {
|
||||
// trackAllPureComponents: true,
|
||||
// });
|
||||
}
|
|
@ -19,12 +19,15 @@
|
|||
"isolatedModules": true,
|
||||
"downlevelIteration": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"jsx": "preserve",
|
||||
"typeRoots": [
|
||||
"../../types"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
// declaration.d.ts
|
||||
declare module '*.module.less' {
|
||||
const content: Record<string, string>;
|
||||
export default content;
|
||||
}
|
4997
js/yarn.lock
4997
js/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue