Merge branch 'migrate-next' of https://github.com/exromany/metaplex into exromany-migrate-next

This commit is contained in:
bartosz-lipinski 2021-07-14 09:55:47 +02:00
commit 742fd11fa1
96 changed files with 1842 additions and 5572 deletions

View File

@ -1,4 +1,5 @@
node_modules
.git
.editorconfig
.gitignore
.gitignore
.next

View File

@ -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"]

View File

@ -43,6 +43,7 @@
]
},
"dependencies": {
"next": "^11.0.1",
"react": "17.0.2",
"react-dom": "17.0.2"
},

View File

@ -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": {

View File

@ -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;

View File

@ -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"

View File

@ -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>

View File

@ -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: {

View File

@ -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',

View File

@ -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' }} />&nbsp;Sign in with Phantom</span>
<span>&gt;</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' }} />
&nbsp;Sign in with Phantom
</span>
<span>&gt;</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();
},
};
}
};

View File

@ -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';

View File

@ -1 +0,0 @@
GENERATE_SOURCEMAP=false

View File

@ -1 +1,3 @@
target
.next
.env.local

View File

@ -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,
},
},
},
},
],
};

3
js/packages/web/next-env.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
/// <reference types="next/image-types/global" />

View File

@ -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: '/',
},
];
},
});

View File

@ -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"
},

View File

@ -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>

View File

@ -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"
]
}

View File

@ -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;
}
}

View File

@ -1,5 +1,4 @@
import React from 'react';
import './App.less';
import { Routes } from './routes';
function App() {

View File

@ -1 +0,0 @@
@import url("https://fonts.googleapis.com/css?family=Roboto:400");

View File

@ -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>
);
};

View File

@ -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 @@
}
}
}

View File

@ -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();

View File

@ -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>
);
};

View File

@ -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={
<>

View File

@ -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>
)
}
);
};

View File

@ -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,

View File

@ -1,7 +1,6 @@
import React, { useEffect, useState } from 'react';
import { Row, Col } from 'antd';
import './../AuctionCard/index.less';
import {
formatTokenAmount,
useMint,

View File

@ -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 }}

View File

@ -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'}>

View File

@ -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>

View File

@ -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;

View File

@ -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>
);

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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"
}
]
}

View File

@ -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} />}
</>
);
}

View File

@ -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>
);
}
}

View File

@ -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;

View File

@ -1 +0,0 @@
/// <reference types="react-scripts" />

View File

@ -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);
});
}
}

View File

@ -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';

View File

@ -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>

View File

@ -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 &&

View File

@ -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(() => {

View File

@ -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';

View File

@ -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>

View File

@ -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"

View File

@ -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,

View File

@ -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;
}

View File

@ -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>

View File

@ -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,
// });
}

View File

@ -19,12 +19,15 @@
"isolatedModules": true,
"downlevelIteration": true,
"noEmit": true,
"jsx": "react-jsx",
"jsx": "preserve",
"typeRoots": [
"../../types"
]
},
"include": [
"src"
],
"exclude": [
"node_modules"
]
}

5
js/packages/web/types/styles.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
// declaration.d.ts
declare module '*.module.less' {
const content: Record<string, string>;
export default content;
}

File diff suppressed because it is too large Load Diff