Add popovers with descriptions for each single parameter

This commit is contained in:
dapplion 2019-08-10 18:04:58 +02:00
parent 1c993642af
commit cce04ea80e
8 changed files with 225 additions and 108 deletions

View File

@ -15,6 +15,12 @@ import SupplyVsDemandChart from "./SupplyVsDemandChart";
import ResultParams from "./ResultParams";
import PriceSimulationChart from "./PriceSimulationChart";
import HelpText from "./HelpText";
// Text content
import {
parameterDescriptions,
simulationParameterDescriptions,
resultParameterDescriptions
} from "./parametersDescriptions";
// Utils
import { getLast, getAvg, pause } from "./utils";
import {
@ -122,11 +128,10 @@ const useStyles = makeStyles((theme: Theme) =>
}
},
descriptionTitle: {
fontWeight: theme.typography.fontWeightBold,
padding: theme.spacing(0.5)
},
descriptionName: {
fontWeight: theme.typography.fontWeightBold
descriptionBody: {
color: "#dbdfe4"
},
descriptionPadding: {
padding: theme.spacing(0.5)
@ -134,73 +139,6 @@ const useStyles = makeStyles((theme: Theme) =>
})
);
const parameterDescriptions = [
{
name: "Initial raise",
text: "Total funds raised in the hatch period of the ABC launch"
},
{
name: "Allocation to funding pool",
text:
"The percentage of the funds raised in the Hatch sale that go directly into the project funding pool to compensate future work done in the project"
},
{
name: "Hatch price",
text:
"The price paid per 'ABC token' by community members involved in hatching the project"
},
{
name: "Post-hatch price",
text:
"The price of the 'ABC token' when the curve enters the open phase and is live for public participation"
},
{
name: "Exit tribute",
text:
"The percentage of funds that are diverted to the project funding pool from community members who exit funds from the project by burning 'ABC tokens' in exchange for collateral"
}
];
const simulationParameterDescriptions = [
{
name: "Price",
text: "Price of the token over time."
},
{
name: "Floor price",
text:
"Lower bound of the price guaranteed by the vesting of hatch tokens. It decreases over time as more hatch tokens are allowed to be traded"
},
{
name: "Total exit tributes",
text:
"Cumulative sum of exit tributes collected from only exit /sell transactions"
}
];
const resultParameterDescriptions = [
{
name: "Total reserve",
text:
"Total DAI in the smart contract reserve at the end of the simulated period"
},
{
name: "Funds generated from initial hatch",
text:
"Fraction of the funds (theta) raised during the hatch that go directly to the cause (analytic result)"
},
{
name: "Funds generated from exit tributes",
text:
"Cumulative sum of exit tributes collected from only exit /sell transactions"
},
{
name: "Average slippage",
text:
"Average of the slippage of each transaction occured during the simulation period"
}
];
export default function App() {
const [curveParams, setCurveParams] = useState({
theta: 0.35, // fraction allocated to reserve (.)
@ -386,14 +324,17 @@ export default function App() {
const resultFields = [
{
label: `Total reserve`,
description: resultParameterDescriptions.totalReserve.text,
value: (+totalReserve.toPrecision(3)).toLocaleString() + " DAI"
},
{
label: `Funds generated from initial hatch`,
description: resultParameterDescriptions.initialHatchFunds.text,
value: Math.round(d0 * theta).toLocaleString() + " DAI"
},
{
label: `Funds generated from exit tributes (${withdrawCount} txs)`,
description: resultParameterDescriptions.exitTributes.text,
value:
(+getLast(withdrawFeeTimeseries).toPrecision(3)).toLocaleString() +
" DAI"
@ -402,6 +343,7 @@ export default function App() {
label: `Average slippage (avg tx size ${Math.round(
avgTxSize
).toLocaleString()} DAI)`,
description: resultParameterDescriptions.slippage.text,
value: +(100 * avgSlippage).toFixed(3) + "%"
}
];
@ -432,15 +374,21 @@ export default function App() {
</div>
<table>
<tbody>
{parameterDescriptions.map(({ name, text }) => (
{[
parameterDescriptions.theta,
parameterDescriptions.p0,
parameterDescriptions.p1,
parameterDescriptions.wFee,
parameterDescriptions.d0
].map(({ name, text }) => (
<tr key={name}>
<td>
<Typography className={classes.descriptionName}>
{name}
</Typography>
<Typography>{name}</Typography>
</td>
<td>
<Typography>{text}</Typography>
<Typography className={classes.descriptionBody}>
{text}
</Typography>
</td>
</tr>
))}
@ -478,7 +426,7 @@ export default function App() {
<HelpText
text={
<div className={classes.descriptionPadding}>
<Typography>
<Typography className={classes.descriptionBody}>
Visualization of the token bonding curve analytic
function on a specific range of reserve [0, 4 * R0].
This result is deterministic given the current set of
@ -533,7 +481,7 @@ export default function App() {
text={
<div className={classes.descriptionContainer}>
<div className={classes.descriptionPadding}>
<Typography>
<Typography className={classes.descriptionBody}>
This chart shows a 52 week simulation of discrete
transactions interacting with the token bonding
curve. Each transaction adds or substract reserve
@ -546,22 +494,22 @@ export default function App() {
<table>
<tbody>
{simulationParameterDescriptions.map(
({ name, text }) => (
<tr key={name}>
<td>
<Typography
className={classes.descriptionName}
>
{name}
</Typography>
</td>
<td>
<Typography>{text}</Typography>
</td>
</tr>
)
)}
{Object.values(
simulationParameterDescriptions
).map(({ name, text }) => (
<tr key={name}>
<td>
<Typography>{name}</Typography>
</td>
<td>
<Typography
className={classes.descriptionBody}
>
{text}
</Typography>
</td>
</tr>
))}
</tbody>
</table>
</div>
@ -595,18 +543,18 @@ export default function App() {
</div>
<table>
<tbody>
{resultParameterDescriptions.map(
{Object.values(resultParameterDescriptions).map(
({ name, text }) => (
<tr key={name}>
<td>
<Typography
className={classes.descriptionName}
>
{name}
</Typography>
<Typography>{name}</Typography>
</td>
<td>
<Typography>{text}</Typography>
<Typography
className={classes.descriptionBody}
>
{text}
</Typography>
</td>
</tr>
)

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect } from "react";
import { InputFieldInterface, CurveParamsInterface } from "./types";
import InputParams from "./InputParams";
import { parameterDescriptions } from "./parametersDescriptions";
export default function CurveDesignInputParams({
curveParams,
@ -42,6 +43,7 @@ export default function CurveDesignInputParams({
const inputFields: InputFieldInterface[] = [
{
label: "Allocation to funding pool",
description: parameterDescriptions.theta.text,
value: theta,
setter: setTheta,
min: 0,
@ -54,6 +56,7 @@ export default function CurveDesignInputParams({
},
{
label: "Hatch price (DAI/token)",
description: parameterDescriptions.p0.text,
value: p0,
setter: _setP0,
min: 0.01,
@ -65,6 +68,7 @@ export default function CurveDesignInputParams({
},
{
label: "Post-hatch price (DAI/token)",
description: parameterDescriptions.p1.text,
value: p1,
setter: setP1,
min: p0 || 0.1,
@ -76,6 +80,7 @@ export default function CurveDesignInputParams({
},
{
label: "Exit tribute",
description: parameterDescriptions.wFee.text,
value: wFee,
setter: setWFee,
min: 0,

View File

@ -1,11 +1,11 @@
import React from "react";
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import Grid from "@material-ui/core/Grid";
import TextField from "@material-ui/core/TextField";
import NumberFormat from "react-number-format";
import { InputFieldInterface } from "./types";
import PrettoSlider from "./PrettoSlider";
import TextWithPopover from "./TextWithPopover";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@ -81,6 +81,7 @@ export default function InputParams({
{inputFields.map(
({
label,
description,
value,
setter,
min,
@ -103,9 +104,7 @@ export default function InputParams({
return (
<Grid key={label} container spacing={0} className={classes.listBox}>
<Grid item xs={6} className={classes.leftContainer}>
<Typography id={label} gutterBottom>
{label}
</Typography>
<TextWithPopover content={label} popoverText={description} />
</Grid>
<Grid item xs={2} className={classes.centerContainer}>

View File

@ -2,6 +2,7 @@ import React from "react";
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import Grid from "@material-ui/core/Grid";
import TextWithPopover from "./TextWithPopover";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@ -45,6 +46,7 @@ export default function ResultParams({
}: {
resultFields: {
label: string;
description: string;
value: number | string;
}[];
}) {
@ -52,12 +54,10 @@ export default function ResultParams({
return (
<div className={classes.listBoxContainer}>
{resultFields.map(({ label, value }) => (
{resultFields.map(({ label, description, value }) => (
<Grid key={label} container spacing={0} className={classes.listBox}>
<Grid item xs={8} className={classes.leftContainer}>
<Typography id={label} gutterBottom>
{label}
</Typography>
<TextWithPopover content={label} popoverText={description} />
</Grid>
<Grid item xs={4} className={classes.centerContainer}>

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect } from "react";
import { InputFieldInterface, CurveParamsInterface } from "./types";
import InputParams from "./InputParams";
import { parameterDescriptions } from "./parametersDescriptions";
export default function CurveDesignInputParams({
curveParams,
@ -25,6 +26,7 @@ export default function CurveDesignInputParams({
const inputFields: InputFieldInterface[] = [
{
label: "Initial raise (DAI)",
description: parameterDescriptions.d0.text,
value: d0,
setter: setD0,
min: 0.1e6,

93
src/TextWithPopover.tsx Normal file
View File

@ -0,0 +1,93 @@
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Popover from "@material-ui/core/Popover";
import Typography from "@material-ui/core/Typography";
import Box from "@material-ui/core/Box";
const useStyles = makeStyles(theme => ({
container: {
color: theme.palette.text.secondary,
display: "flex",
marginLeft: "6px",
fontSize: "0.9rem",
cursor: "pointer",
transition: "color ease 150ms",
"&:hover": {
color: "#c3c9d0"
}
},
popoverContainer: {
padding: theme.spacing(2),
"& > p:not(:last-child)": {
paddingBottom: theme.spacing(1),
marginBottom: theme.spacing(1),
borderBottom: "1px solid #3f5463"
}
},
paper: {
backgroundColor: "#384b59",
maxWidth: theme.breakpoints.values.md * 0.9,
[`@media screen and (max-width: ${theme.breakpoints.values.md}px)`]: {
maxWidth: "90vw"
},
padding: theme.spacing(0.5)
},
descriptionBody: {
color: "#dbdfe4"
}
}));
export default function TextWithPopover({
content,
popoverText
}: {
content: string;
popoverText: string;
}) {
const classes = useStyles();
const [anchorEl, setAnchorEl] = React.useState(null);
function handleClick(event: any) {
setAnchorEl(event.currentTarget);
}
function handleClose() {
setAnchorEl(null);
}
const open = Boolean(anchorEl);
const id = open ? "simple-popover" : undefined;
return (
<div className={classes.container}>
<div aria-describedby={id} onClick={handleClick}>
<Typography gutterBottom>{content}</Typography>
</div>
<Popover
PaperProps={{
className: classes.paper
}}
id={id}
open={open}
anchorEl={anchorEl}
onClose={handleClose}
onClick={handleClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "center"
}}
transformOrigin={{
vertical: "top",
horizontal: "center"
}}
>
<Box className={classes.popoverContainer}>
<Typography>{content}</Typography>
<Typography className={classes.descriptionBody}>
{popoverText}
</Typography>
</Box>
</Popover>
</div>
);
}

View File

@ -0,0 +1,69 @@
export interface DescriptionObject {
[key: string]: { name: string; text: string };
}
export const parameterDescriptions: DescriptionObject = {
theta: {
name: "Allocation to funding pool",
text:
"The percentage of the funds raised in the Hatch sale that go directly into the project funding pool to compensate future work done in the project"
},
p0: {
name: "Hatch price",
text:
"The price paid per 'ABC token' by community members involved in hatching the project"
},
p1: {
name: "Post-hatch price",
text:
"The price of the 'ABC token' when the curve enters the open phase and is live for public participation"
},
wFee: {
name: "Exit tribute",
text:
"The percentage of funds that are diverted to the project funding pool from community members who exit funds from the project by burning 'ABC tokens' in exchange for collateral"
},
d0: {
name: "Initial raise",
text: "Total funds raised in the hatch period of the ABC launch"
}
};
export const simulationParameterDescriptions: DescriptionObject = {
price: {
name: "Price",
text: "Price of the token over time."
},
floorPrice: {
name: "Floor price",
text:
"Lower bound of the price guaranteed by the vesting of hatch tokens. It decreases over time as more hatch tokens are allowed to be traded"
},
exitTributes: {
name: "Total exit tributes",
text:
"Cumulative sum of exit tributes collected from only exit /sell transactions"
}
};
export const resultParameterDescriptions: DescriptionObject = {
totalReserve: {
name: "Total reserve",
text:
"Total DAI in the smart contract reserve at the end of the simulated period"
},
initialHatchFunds: {
name: "Funds generated from initial hatch",
text:
"Fraction of the funds (theta) raised during the hatch that go directly to the cause (analytic result)"
},
exitTributes: {
name: "Funds generated from exit tributes",
text: simulationParameterDescriptions.exitTributes.text
},
slippage: {
name: "Average slippage",
text:
"Average of the slippage of each transaction occured during the simulation period"
}
};

View File

@ -1,5 +1,6 @@
export interface InputFieldInterface {
label: string;
description: string;
value: number;
setter(newValue: any): void;
min: number;