add debug panel
This commit is contained in:
parent
d163192572
commit
083398f82b
|
@ -10,15 +10,27 @@ export interface LayoutFlipCardAction {
|
||||||
flipped: boolean
|
flipped: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const LAYOUT_TOGGLE_DEBUG = "LAYOUT_TOGGLE_DEBUG";
|
||||||
|
export interface LayoutToggleDebugAction {
|
||||||
|
type: typeof LAYOUT_TOGGLE_DEBUG
|
||||||
|
open: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export type LayoutActions =
|
export type LayoutActions =
|
||||||
LayoutToggleSidebarAction |
|
LayoutToggleSidebarAction |
|
||||||
LayoutFlipCardAction;
|
LayoutFlipCardAction |
|
||||||
|
LayoutToggleDebugAction;
|
||||||
|
|
||||||
export const toggleSidebar = (open: boolean): LayoutToggleSidebarAction => ({
|
export const toggleSidebar = (open: boolean): LayoutToggleSidebarAction => ({
|
||||||
type: LAYOUT_TOGGLE_SIDEBAR,
|
type: LAYOUT_TOGGLE_SIDEBAR,
|
||||||
open,
|
open,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const toggleDebug = (open: boolean): LayoutToggleDebugAction => ({
|
||||||
|
type: LAYOUT_TOGGLE_DEBUG,
|
||||||
|
open,
|
||||||
|
});
|
||||||
|
|
||||||
export const flipCard = (flipped: boolean): LayoutFlipCardAction => ({
|
export const flipCard = (flipped: boolean): LayoutFlipCardAction => ({
|
||||||
type: LAYOUT_FLIP_CARD,
|
type: LAYOUT_FLIP_CARD,
|
||||||
flipped,
|
flipped,
|
||||||
|
|
|
@ -6,12 +6,7 @@ import { sha3 } from "web3-utils";
|
||||||
import { recoverTypedSignature } from 'eth-sig-util';
|
import { recoverTypedSignature } from 'eth-sig-util';
|
||||||
import { Web3Type } from "../actions/web3";
|
import { Web3Type } from "../actions/web3";
|
||||||
import { KECCAK_EMPTY_STRING } from '../utils';
|
import { KECCAK_EMPTY_STRING } from '../utils';
|
||||||
|
import { debug } from "./debug";
|
||||||
const sleep = (ms: number) => {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
window.setTimeout(resolve, ms);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RedeemMessage {
|
interface RedeemMessage {
|
||||||
receiver: string
|
receiver: string
|
||||||
|
@ -22,7 +17,7 @@ interface RedeemMessage {
|
||||||
|
|
||||||
interface SignRedeemResponse {
|
interface SignRedeemResponse {
|
||||||
sig: string
|
sig: string
|
||||||
address: string
|
signer: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ERROR_REDEEMING = "ERROR_REDEEMING";
|
export const ERROR_REDEEMING = "ERROR_REDEEMING";
|
||||||
|
@ -105,6 +100,11 @@ export const redeem = (bucketAddress: string, recipientAddress: string, cleanCod
|
||||||
|
|
||||||
const bucket = newBucketContract(bucketAddress);
|
const bucket = newBucketContract(bucketAddress);
|
||||||
const account = state.web3.account;
|
const account = state.web3.account;
|
||||||
|
if (account === undefined) {
|
||||||
|
//FIXME: show error?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const block = await config.web3!.eth.getBlock("latest");
|
const block = await config.web3!.eth.getBlock("latest");
|
||||||
|
|
||||||
const message = {
|
const message = {
|
||||||
|
@ -182,7 +182,7 @@ async function signRedeem(web3Type: Web3Type, contractAddress: string, signer: s
|
||||||
};
|
};
|
||||||
|
|
||||||
if (web3Type === Web3Type.Status) {
|
if (web3Type === Web3Type.Status) {
|
||||||
return signWithKeycard(signer, data);
|
return signWithKeycard(data);
|
||||||
} else {
|
} else {
|
||||||
return signWithWeb3(signer, data);
|
return signWithWeb3(signer, data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { RootState } from '../reducers';
|
import { RootState } from '../reducers';
|
||||||
|
import ERC20BucketFactory from '../embarkArtifacts/contracts/ERC20BucketFactory';
|
||||||
|
import NFTBucketFactory from '../embarkArtifacts/contracts/NFTBucketFactory';
|
||||||
import ERC20Bucket from '../embarkArtifacts/contracts/ERC20Bucket';
|
import ERC20Bucket from '../embarkArtifacts/contracts/ERC20Bucket';
|
||||||
import Bucket from '../embarkArtifacts/contracts/Bucket';
|
import Bucket from '../embarkArtifacts/contracts/Bucket';
|
||||||
import IERC20Detailed from '../embarkArtifacts/contracts/IERC20Detailed';
|
import IERC20Detailed from '../embarkArtifacts/contracts/IERC20Detailed';
|
||||||
|
@ -6,6 +8,7 @@ import IERC721Metadata from '../embarkArtifacts/contracts/IERC721Metadata';
|
||||||
import { config } from "../config";
|
import { config } from "../config";
|
||||||
import { Dispatch } from 'redux';
|
import { Dispatch } from 'redux';
|
||||||
import { ZERO_ADDRESS } from "../utils";
|
import { ZERO_ADDRESS } from "../utils";
|
||||||
|
import { debug } from "./debug";
|
||||||
|
|
||||||
export const ERROR_REDEEMABLE_NOT_FOUND = "ERROR_REDEEMABLE_NOT_FOUND";
|
export const ERROR_REDEEMABLE_NOT_FOUND = "ERROR_REDEEMABLE_NOT_FOUND";
|
||||||
export interface ErrRedeemableNotFound {
|
export interface ErrRedeemableNotFound {
|
||||||
|
@ -176,6 +179,10 @@ export const newERC20BucketContract = (address: string) => {
|
||||||
|
|
||||||
export const loadRedeemable = (bucketAddress: string, recipientAddress: string) => {
|
export const loadRedeemable = (bucketAddress: string, recipientAddress: string) => {
|
||||||
return async (dispatch: Dispatch, getState: () => RootState) => {
|
return async (dispatch: Dispatch, getState: () => RootState) => {
|
||||||
|
dispatch(debug(`erc20 factory address: ${ERC20BucketFactory.address}`));
|
||||||
|
dispatch(debug(`nft factory address: ${NFTBucketFactory.address}`));
|
||||||
|
dispatch(debug(`bucket address: ${bucketAddress}`));
|
||||||
|
dispatch(debug(`recipient address: ${recipientAddress}`));
|
||||||
dispatch(loadingRedeemable(bucketAddress, recipientAddress));
|
dispatch(loadingRedeemable(bucketAddress, recipientAddress));
|
||||||
const bucket = newBucketContract(bucketAddress);
|
const bucket = newBucketContract(bucketAddress);
|
||||||
bucket.methods.expirationTime().call().then((expirationTime: number) => {
|
bucket.methods.expirationTime().call().then((expirationTime: number) => {
|
||||||
|
@ -231,9 +238,11 @@ export const loadERC20Token = (bucket: any, data: string, recipient: string) =>
|
||||||
|
|
||||||
const symbol = await erc20.methods.symbol().call();
|
const symbol = await erc20.methods.symbol().call();
|
||||||
const decimals = parseInt(await erc20.methods.decimals().call());
|
const decimals = parseInt(await erc20.methods.decimals().call());
|
||||||
|
dispatch(debug(`erc20 token: ${symbol} ${address}`));
|
||||||
dispatch(tokenLoaded({symbol, decimals}));
|
dispatch(tokenLoaded({symbol, decimals}));
|
||||||
}).catch((err: string) => {
|
}).catch((err: string) => {
|
||||||
//FIXME: manage error
|
//FIXME: manage error
|
||||||
|
dispatch(debug(`error loading token: ${err})`));
|
||||||
console.error("ERROR: ", err);
|
console.error("ERROR: ", err);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -251,6 +260,8 @@ export const loadNFTToken = (bucket: any, data: string, recipient: string) => {
|
||||||
dispatch(tokenLoaded({symbol, tokenURI, metadata: undefined}));
|
dispatch(tokenLoaded({symbol, tokenURI, metadata: undefined}));
|
||||||
dispatch(loadingTokenMetadata(address, recipient))
|
dispatch(loadingTokenMetadata(address, recipient))
|
||||||
|
|
||||||
|
dispatch(debug(`nft token: ${symbol} ${address}`));
|
||||||
|
|
||||||
fetch(tokenURI)
|
fetch(tokenURI)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
|
@ -261,10 +272,12 @@ export const loadNFTToken = (bucket: any, data: string, recipient: string) => {
|
||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
.catch((err: string) => {
|
.catch((err: string) => {
|
||||||
|
dispatch(debug(`error loading metadata: ${err})`));
|
||||||
//FIXME: manage error
|
//FIXME: manage error
|
||||||
console.error("ERROR: ", err);
|
console.error("ERROR: ", err);
|
||||||
});
|
});
|
||||||
}).catch((err: string) => {
|
}).catch((err: string) => {
|
||||||
|
dispatch(debug(`error loading token: ${err})`));
|
||||||
//FIXME: manage error
|
//FIXME: manage error
|
||||||
console.error("ERROR: ", err);
|
console.error("ERROR: ", err);
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {
|
||||||
Dispatch,
|
Dispatch,
|
||||||
} from 'redux';
|
} from 'redux';
|
||||||
import { RootState } from '../reducers';
|
import { RootState } from '../reducers';
|
||||||
|
import { debug } from "./debug";
|
||||||
|
|
||||||
export const VALID_NETWORK_NAME = "Ropsten";
|
export const VALID_NETWORK_NAME = "Ropsten";
|
||||||
export const VALID_NETWORK_ID = 3;
|
export const VALID_NETWORK_ID = 3;
|
||||||
|
@ -86,6 +87,7 @@ export const initializeWeb3 = () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dispatch(debug(`network id: ${id}`))
|
||||||
dispatch(web3NetworkIDLoaded(id))
|
dispatch(web3NetworkIDLoaded(id))
|
||||||
dispatch<any>(loadAddress());
|
dispatch<any>(loadAddress());
|
||||||
});
|
});
|
||||||
|
@ -98,6 +100,7 @@ export const initializeWeb3 = () => {
|
||||||
const t: Web3Type = w.ethereum.isStatus ? Web3Type.Status : Web3Type.Generic;
|
const t: Web3Type = w.ethereum.isStatus ? Web3Type.Status : Web3Type.Generic;
|
||||||
dispatch(web3Initialized(t));
|
dispatch(web3Initialized(t));
|
||||||
config.web3!.eth.net.getId().then((id: number) => {
|
config.web3!.eth.net.getId().then((id: number) => {
|
||||||
|
dispatch(debug(`network id: ${id}`))
|
||||||
dispatch(web3NetworkIDLoaded(id))
|
dispatch(web3NetworkIDLoaded(id))
|
||||||
dispatch<any>(loadAddress());
|
dispatch<any>(loadAddress());
|
||||||
})
|
})
|
||||||
|
@ -114,6 +117,7 @@ export const initializeWeb3 = () => {
|
||||||
const loadAddress = () => {
|
const loadAddress = () => {
|
||||||
return (dispatch: Dispatch, getState: () => RootState) => {
|
return (dispatch: Dispatch, getState: () => RootState) => {
|
||||||
config.web3!.eth.getAccounts().then((accounts: string[]) => {
|
config.web3!.eth.getAccounts().then((accounts: string[]) => {
|
||||||
|
dispatch(debug(`current account: ${accounts[0]}`));
|
||||||
dispatch(accountLoaded(accounts[0]));
|
dispatch(accountLoaded(accounts[0]));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,19 +9,6 @@ import {
|
||||||
import { Web3Type } from "../actions/web3";
|
import { Web3Type } from "../actions/web3";
|
||||||
import "../styles/Layout.scss";
|
import "../styles/Layout.scss";
|
||||||
|
|
||||||
const web3Type = (t: Web3Type) => {
|
|
||||||
switch (t) {
|
|
||||||
case Web3Type.None:
|
|
||||||
return "not a web3 browser";
|
|
||||||
case Web3Type.Generic:
|
|
||||||
return "generic web3 browser";
|
|
||||||
case Web3Type.Remote:
|
|
||||||
return "remote web3 node";
|
|
||||||
case Web3Type.Status:
|
|
||||||
return "status web3 browser";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function(ownProps: any) {
|
export default function(ownProps: any) {
|
||||||
const props = useSelector((state: RootState) => {
|
const props = useSelector((state: RootState) => {
|
||||||
return {
|
return {
|
||||||
|
@ -40,20 +27,11 @@ export default function(ownProps: any) {
|
||||||
});
|
});
|
||||||
|
|
||||||
return <div className="main">
|
return <div className="main">
|
||||||
<div className={sidebarClass}>
|
|
||||||
<div className="inner">
|
|
||||||
Network ID: {props.networkID} <br />
|
|
||||||
Factory: {ERC20BucketFactory.address} <br />
|
|
||||||
Account: {props.account} <br />
|
|
||||||
Web3 Type: {web3Type(props.type)} <br />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{props.error && <div className={classNames({ paper: true, error: true })}>
|
{props.error && <div className={classNames({ paper: true, error: true })}>
|
||||||
{props.error}
|
{props.error}
|
||||||
</div>}
|
</div>}
|
||||||
|
|
||||||
{!props.initialized && <div className={classNames({ paper: true })}>
|
{!props.error && !props.initialized && <div className={classNames({ paper: true })}>
|
||||||
initializing...
|
initializing...
|
||||||
</div>}
|
</div>}
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,17 @@ import {
|
||||||
ERROR_REDEEMING,
|
ERROR_REDEEMING,
|
||||||
ERROR_WRONG_SIGNER,
|
ERROR_WRONG_SIGNER,
|
||||||
} from '../actions/redeem';
|
} from '../actions/redeem';
|
||||||
import { flipCard } from "../actions/layout";
|
import {
|
||||||
|
flipCard,
|
||||||
|
toggleDebug,
|
||||||
|
} from "../actions/layout";
|
||||||
import "../styles/Redeemable.scss";
|
import "../styles/Redeemable.scss";
|
||||||
|
import "../styles/Debug.scss";
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import {
|
import {
|
||||||
faUndo as flipIcon,
|
faUndo as flipIcon,
|
||||||
faUndo as unflipIcon,
|
faUndo as unflipIcon,
|
||||||
|
faWrench as debugIcon,
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,7 +60,7 @@ const redeemErrorMessage = (error: RedeemErrors): string => {
|
||||||
return `wrong signer. expected signature from ${error.expected}, got signature from ${error.actual}`;
|
return `wrong signer. expected signature from ${error.expected}, got signature from ${error.actual}`;
|
||||||
|
|
||||||
case ERROR_REDEEMING:
|
case ERROR_REDEEMING:
|
||||||
return `redeem error: ${error.message}`;
|
return error.message;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return "something went wrong";
|
return "something went wrong";
|
||||||
|
@ -99,6 +104,8 @@ export default function(ownProps: any) {
|
||||||
redeemError: state.redeem.error,
|
redeemError: state.redeem.error,
|
||||||
redeemTxHash: state.redeem.txHash,
|
redeemTxHash: state.redeem.txHash,
|
||||||
cardFlipped: state.layout.cardFlipped,
|
cardFlipped: state.layout.cardFlipped,
|
||||||
|
debugLines: state.debug.lines,
|
||||||
|
debugOpen: state.layout.debugOpen,
|
||||||
}
|
}
|
||||||
}, shallowEqual);
|
}, shallowEqual);
|
||||||
|
|
||||||
|
@ -179,7 +186,8 @@ export default function(ownProps: any) {
|
||||||
|
|
||||||
const backClass = classNames({ side: true, back: true });
|
const backClass = classNames({ side: true, back: true });
|
||||||
|
|
||||||
return <div className={cardClass}>
|
return <div>
|
||||||
|
<div className={cardClass}>
|
||||||
<div className={frontClass}>
|
<div className={frontClass}>
|
||||||
<div className="header">
|
<div className="header">
|
||||||
<button className="flip" onClick={ () => { dispatch(flipCard(true)) } }>
|
<button className="flip" onClick={ () => { dispatch(flipCard(true)) } }>
|
||||||
|
@ -195,7 +203,7 @@ export default function(ownProps: any) {
|
||||||
{tokenContent}
|
{tokenContent}
|
||||||
</div>
|
</div>
|
||||||
{props.redeemError && <div className="error">
|
{props.redeemError && <div className="error">
|
||||||
Error: {redeemErrorMessage(props.redeemError)}
|
{redeemErrorMessage(props.redeemError)}
|
||||||
</div>}
|
</div>}
|
||||||
{props.redeemTxHash && <div className="success">
|
{props.redeemTxHash && <div className="success">
|
||||||
Done! Tx Hash: {props.redeemTxHash}
|
Done! Tx Hash: {props.redeemTxHash}
|
||||||
|
@ -241,5 +249,17 @@ export default function(ownProps: any) {
|
||||||
<div className="footer">
|
<div className="footer">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="debug">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
onClick={() => dispatch(toggleDebug(!props.debugOpen)) }
|
||||||
|
icon={debugIcon}
|
||||||
|
className="btn" />
|
||||||
|
{props.debugOpen && <ul>
|
||||||
|
{props.debugLines.map((text: string, i: number) => (<li key={i}>
|
||||||
|
{text}
|
||||||
|
</li>))}
|
||||||
|
</ul>}
|
||||||
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,17 @@ import {
|
||||||
LayoutState,
|
LayoutState,
|
||||||
layoutReducer,
|
layoutReducer,
|
||||||
} from './layout';
|
} from './layout';
|
||||||
|
import {
|
||||||
|
DebugState,
|
||||||
|
debugReducer,
|
||||||
|
} from './debug';
|
||||||
|
|
||||||
export interface RootState {
|
export interface RootState {
|
||||||
web3: Web3State,
|
web3: Web3State,
|
||||||
redeemable: RedeemableState,
|
redeemable: RedeemableState,
|
||||||
redeem: RedeemState,
|
redeem: RedeemState,
|
||||||
layout: LayoutState,
|
layout: LayoutState,
|
||||||
|
debug: DebugState,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function(history: History) {
|
export default function(history: History) {
|
||||||
|
@ -32,5 +37,6 @@ export default function(history: History) {
|
||||||
redeemable: redeemableReducer,
|
redeemable: redeemableReducer,
|
||||||
redeem: redeemReducer,
|
redeem: redeemReducer,
|
||||||
layout: layoutReducer,
|
layout: layoutReducer,
|
||||||
|
debug: debugReducer,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
import {
|
import {
|
||||||
LayoutActions,
|
LayoutActions,
|
||||||
LAYOUT_TOGGLE_SIDEBAR,
|
LAYOUT_TOGGLE_SIDEBAR,
|
||||||
|
LAYOUT_TOGGLE_DEBUG,
|
||||||
LAYOUT_FLIP_CARD,
|
LAYOUT_FLIP_CARD,
|
||||||
} from "../actions/layout";
|
} from "../actions/layout";
|
||||||
|
|
||||||
export interface LayoutState {
|
export interface LayoutState {
|
||||||
sidebarOpen: boolean,
|
sidebarOpen: boolean,
|
||||||
cardFlipped: boolean,
|
cardFlipped: boolean,
|
||||||
|
debugOpen: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: LayoutState = {
|
const initialState: LayoutState = {
|
||||||
sidebarOpen: false,
|
sidebarOpen: false,
|
||||||
cardFlipped: false,
|
cardFlipped: false,
|
||||||
|
debugOpen: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const layoutReducer = (state: LayoutState = initialState, action: LayoutActions): LayoutState => {
|
export const layoutReducer = (state: LayoutState = initialState, action: LayoutActions): LayoutState => {
|
||||||
|
@ -22,6 +25,12 @@ export const layoutReducer = (state: LayoutState = initialState, action: LayoutA
|
||||||
sidebarOpen: action.open,
|
sidebarOpen: action.open,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case LAYOUT_TOGGLE_DEBUG:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
debugOpen: action.open,
|
||||||
|
};
|
||||||
|
|
||||||
case LAYOUT_FLIP_CARD:
|
case LAYOUT_FLIP_CARD:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|
|
@ -16,53 +16,6 @@ body {
|
||||||
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
|
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
z-index: 9999;
|
|
||||||
background: #fff;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: -100vw;
|
|
||||||
min-height: 100vh;
|
|
||||||
width: 100vw;
|
|
||||||
|
|
||||||
&.open {
|
|
||||||
animation-duration: 0.2s;
|
|
||||||
animation-name: slidein;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.closed {
|
|
||||||
animation-duration: 0.2s;
|
|
||||||
animation-name: slideout;
|
|
||||||
left: -100vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inner {
|
|
||||||
padding: 24px;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes slidein {
|
|
||||||
from {
|
|
||||||
left: -100vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes slideout {
|
|
||||||
from {
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
left: -100vw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
margin-top: 50px;
|
margin-top: 50px;
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,10 @@
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
perspective:1000px;
|
perspective:1000px;
|
||||||
|
|
||||||
|
border-radius: 8px;
|
||||||
position: relative;
|
position: relative;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
box-shadow: 0px 2px 1px -1px rgba(0,0,0,0.2), 0px 1px 1px 0px rgba(0,0,0,0.14), 0px 1px 3px 0px rgba(0,0,0,0.12);
|
box-shadow: 0px 2px 1px -1px rgba(0,0,0,0.2), 0px 1px 1px 0px rgba(0,0,0,0.14), 0px 1px 3px 0px rgba(0,0,0,0.12);
|
||||||
border-radius: 8px;
|
|
||||||
transform-style: preserve-3d;
|
transform-style: preserve-3d;
|
||||||
transition: transform 1.0s;
|
transition: transform 1.0s;
|
||||||
height: 500px;
|
height: 500px;
|
||||||
|
@ -43,6 +43,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.side {
|
.side {
|
||||||
|
border-radius: 8px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
Loading…
Reference in New Issue