mirror of
https://github.com/ANL-CEEESA/RELOG.git
synced 2025-12-06 23:58:51 -06:00
Implement initial, static version of input GUI
This commit is contained in:
22
relog-web/src/Button.js
Normal file
22
relog-web/src/Button.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import styles from './Button.module.css'
|
||||
|
||||
const Button = (props) => {
|
||||
let className = styles.Button
|
||||
if (props.kind === "inline") {
|
||||
className += " " + styles.inline
|
||||
}
|
||||
|
||||
let tooltip = "";
|
||||
if (props.tooltip != undefined) {
|
||||
tooltip = <span className={styles.tooltip}>{props.tooltip}</span>
|
||||
}
|
||||
|
||||
return (
|
||||
<button className={className}>
|
||||
{tooltip}
|
||||
{props.label}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export default Button;
|
||||
65
relog-web/src/Button.module.css
Normal file
65
relog-web/src/Button.module.css
Normal file
@@ -0,0 +1,65 @@
|
||||
.Button {
|
||||
padding: 6px 36px;
|
||||
margin: 12px 6px;
|
||||
line-height: 24px;
|
||||
border: var(--box-border);
|
||||
/* background-color: white; */
|
||||
box-shadow: var(--box-shadow);
|
||||
border-radius: var(--border-radius);
|
||||
cursor: pointer;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
background: linear-gradient(
|
||||
rgb(255, 255, 255) 25%,
|
||||
rgb(245, 245, 245) 100%
|
||||
)
|
||||
}
|
||||
|
||||
.Button:hover {
|
||||
background: rgb(245, 245, 245);
|
||||
}
|
||||
|
||||
.Button:active {
|
||||
background: rgba(220, 220, 220);
|
||||
}
|
||||
|
||||
.inline {
|
||||
padding: 0 12px;
|
||||
margin: 2px 4px 2px 0;
|
||||
height: 32px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* .inline:last-child {
|
||||
margin: 2px 1px;
|
||||
} */
|
||||
|
||||
.tooltip {
|
||||
visibility: hidden;
|
||||
background-color: #333;
|
||||
color: white;
|
||||
opacity: 0%;
|
||||
width: 180px;
|
||||
margin-top: 36px;
|
||||
margin-left: -180px;
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
text-transform: none;
|
||||
font-size: 13px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.25);
|
||||
line-height: 18px;
|
||||
padding: 6px;
|
||||
transition: opacity .5s;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
.Button:hover .tooltip {
|
||||
visibility: visible;
|
||||
opacity: 100%;
|
||||
transition: opacity .5s;
|
||||
}
|
||||
7
relog-web/src/ButtonRow.js
Normal file
7
relog-web/src/ButtonRow.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import styles from './ButtonRow.module.css'
|
||||
|
||||
const ButtonRow = (props) => {
|
||||
return <div className={styles.ButtonRow}>{props.children}</div>
|
||||
}
|
||||
|
||||
export default ButtonRow;
|
||||
3
relog-web/src/ButtonRow.module.css
Normal file
3
relog-web/src/ButtonRow.module.css
Normal file
@@ -0,0 +1,3 @@
|
||||
.ButtonRow {
|
||||
text-align: center;
|
||||
}
|
||||
7
relog-web/src/Card.js
Normal file
7
relog-web/src/Card.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import styles from './Card.module.css'
|
||||
|
||||
const Card = (props) => {
|
||||
return (<div className={styles.Card}>{props.children}</div>)
|
||||
}
|
||||
|
||||
export default Card;
|
||||
22
relog-web/src/Card.module.css
Normal file
22
relog-web/src/Card.module.css
Normal file
@@ -0,0 +1,22 @@
|
||||
.Card {
|
||||
border: var(--box-border);
|
||||
box-shadow: var(--box-shadow);
|
||||
border-radius: var(--border-radius);
|
||||
background-color: white;
|
||||
padding: 12px;
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
.Card h1 {
|
||||
margin: 12px -12px 0px -12px;
|
||||
padding: 6px 12px 0px 12px;
|
||||
font-size: 14px;
|
||||
line-height: 35px;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.Card h1:first-child {
|
||||
margin: -12px -12px 0px -12px;
|
||||
border-top: none;
|
||||
background: none;
|
||||
}
|
||||
55
relog-web/src/DictInputRow.js
Normal file
55
relog-web/src/DictInputRow.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import form_styles from './Form.module.css'
|
||||
import Button from './Button'
|
||||
|
||||
const DictInputRow = (props) => {
|
||||
let unit = "";
|
||||
if (props.unit) {
|
||||
unit = <span className={form_styles.FormRow_unit}>({props.unit})</span>
|
||||
}
|
||||
|
||||
let tooltip = "";
|
||||
if (props.tooltip != undefined) {
|
||||
tooltip = <Button label="?" kind="inline" tooltip={props.tooltip} />
|
||||
}
|
||||
|
||||
let value = {}
|
||||
if (props.value != undefined) {
|
||||
value = props.value;
|
||||
}
|
||||
if (props.disableKeys === undefined) {
|
||||
value[""] = "";
|
||||
}
|
||||
|
||||
const form = []
|
||||
Object.keys(value).forEach((key, index) => {
|
||||
let label = <span>{props.label} {unit}</span>;
|
||||
if (index > 0) {
|
||||
label = "";
|
||||
}
|
||||
form.push(
|
||||
<div className={form_styles.FormRow} key={index}>
|
||||
<label>{label}</label>
|
||||
<input
|
||||
type="text"
|
||||
data-index={index}
|
||||
value={key}
|
||||
placeholder={props.keyPlaceholder}
|
||||
disabled={props.disableKeys}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
data-index={index}
|
||||
value={value[key]}
|
||||
placeholder={props.valuePlaceholder}
|
||||
/>
|
||||
{tooltip}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
return <>
|
||||
{form}
|
||||
</>;
|
||||
}
|
||||
|
||||
export default DictInputRow;
|
||||
21
relog-web/src/FileInputRow.js
Normal file
21
relog-web/src/FileInputRow.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import form_styles from './Form.module.css'
|
||||
import Button from './Button'
|
||||
|
||||
const FileInputRow = (props) => {
|
||||
|
||||
let tooltip = "";
|
||||
if (props.tooltip != undefined) {
|
||||
tooltip = <Button label="?" kind="inline" tooltip={props.tooltip} />
|
||||
}
|
||||
|
||||
return <div className={form_styles.FormRow}>
|
||||
<label>{props.label}</label>
|
||||
<input type="text" disabled="disabled" />
|
||||
<Button label="Upload" kind="inline" />
|
||||
<Button label="Clear" kind="inline" />
|
||||
<Button label="Template" kind="inline" />
|
||||
{tooltip}
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default FileInputRow;
|
||||
10
relog-web/src/Footer.js
Normal file
10
relog-web/src/Footer.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import styles from './Footer.module.css'
|
||||
|
||||
const Footer = () => {
|
||||
return <div className={styles.Footer}>
|
||||
<p>RELOG: Reverse Logistics Optimization</p>
|
||||
<p>Copyright © 2020—2022, UChicago Argonne, LLC. All Rights Reserved.</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default Footer;
|
||||
11
relog-web/src/Footer.module.css
Normal file
11
relog-web/src/Footer.module.css
Normal file
@@ -0,0 +1,11 @@
|
||||
.Footer {
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
padding: 24px;
|
||||
margin-top: 24px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
line-height: 8px;
|
||||
min-width: 900px;
|
||||
|
||||
}
|
||||
5
relog-web/src/Form.js
Normal file
5
relog-web/src/Form.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const Form = (props) => {
|
||||
return <>{props.children}</>;
|
||||
}
|
||||
|
||||
export default Form;
|
||||
23
relog-web/src/Form.module.css
Normal file
23
relog-web/src/Form.module.css
Normal file
@@ -0,0 +1,23 @@
|
||||
.FormRow {
|
||||
display: flex;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.FormRow label {
|
||||
width: 350px;
|
||||
padding: 6px 12px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.FormRow input {
|
||||
flex: 1;
|
||||
font-family: monospace;
|
||||
border: var(--box-border);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 4px;
|
||||
margin: 2px 3px;
|
||||
}
|
||||
|
||||
.FormRow_unit {
|
||||
color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
13
relog-web/src/Header.js
Normal file
13
relog-web/src/Header.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import styles from './Header.module.css'
|
||||
|
||||
const Header = () => {
|
||||
return (
|
||||
<div className={styles.HeaderBox}>
|
||||
<div className={styles.HeaderContent}>
|
||||
<h1>RELOG</h1>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Header;
|
||||
19
relog-web/src/Header.module.css
Normal file
19
relog-web/src/Header.module.css
Normal file
@@ -0,0 +1,19 @@
|
||||
.HeaderBox {
|
||||
background-color: white;
|
||||
border-bottom: var(--box-border);
|
||||
box-shadow: var(--box-shadow);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.HeaderContent {
|
||||
margin: 0 auto;
|
||||
max-width: var(--site-width);
|
||||
}
|
||||
|
||||
.HeaderContent h1 {
|
||||
line-height: 48px;
|
||||
font-size: 28px;
|
||||
padding: 12px;
|
||||
margin: 0;
|
||||
}
|
||||
26
relog-web/src/InputPage.js
Normal file
26
relog-web/src/InputPage.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import './index.css';
|
||||
import PipelineBlock from './PipelineBlock';
|
||||
import ParametersBlock from './ParametersBlock';
|
||||
import ProductBlock from './ProductBlock';
|
||||
import PlantBlock from './PlantBlock';
|
||||
import ButtonRow from './ButtonRow';
|
||||
import Button from './Button';
|
||||
|
||||
|
||||
const InputPage = () => {
|
||||
return <>
|
||||
<PipelineBlock />
|
||||
<ParametersBlock />
|
||||
<ProductBlock name="Battery" />
|
||||
<ProductBlock name="Nickel" />
|
||||
<ProductBlock name="Metal casing" />
|
||||
<PlantBlock name="Battery Recycling Plant" />
|
||||
<ButtonRow>
|
||||
<Button label="Load" />
|
||||
<Button label="Save" />
|
||||
</ButtonRow>
|
||||
</>
|
||||
}
|
||||
|
||||
export default InputPage;
|
||||
36
relog-web/src/ParametersBlock.js
Normal file
36
relog-web/src/ParametersBlock.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import Section from './Section'
|
||||
import Card from './Card'
|
||||
import Form from './Form'
|
||||
import TextInputRow from './TextInputRow'
|
||||
|
||||
const ParametersBlock = () => {
|
||||
return (
|
||||
<>
|
||||
<Section title="Parameters" />
|
||||
<Card>
|
||||
<Form>
|
||||
<TextInputRow
|
||||
label="Time horizon"
|
||||
unit="years"
|
||||
tooltip="Number of years in the simulation."
|
||||
default="1"
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Building period"
|
||||
unit="years"
|
||||
tooltip="List of years in which we are allowed to open new plants. For example, if this parameter is set to [1,2,3], we can only open plants during the first three years. By default, this equals [1]; that is, plants can only be opened during the first year."
|
||||
default="[1]"
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Annual inflation rate"
|
||||
unit="%"
|
||||
tooltip="Rate of inflation applied to all costs."
|
||||
default="0"
|
||||
/>
|
||||
</Form>
|
||||
</Card>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ParametersBlock;
|
||||
87
relog-web/src/PipelineBlock.js
Normal file
87
relog-web/src/PipelineBlock.js
Normal file
@@ -0,0 +1,87 @@
|
||||
import React from 'react';
|
||||
import ReactFlow, { Background } from 'react-flow-renderer';
|
||||
import Section from './Section';
|
||||
import Card from './Card';
|
||||
import Button from './Button';
|
||||
import styles from './PipelineBlock.module.css';
|
||||
|
||||
const elements = [
|
||||
{
|
||||
id: '1',
|
||||
data: { label: 'Battery' },
|
||||
sourcePosition: 'right',
|
||||
targetPosition: 'left',
|
||||
position: { x: 100, y: 200 },
|
||||
className: styles.ProductNode,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
data: { label: "Battery Recycling Plant" },
|
||||
sourcePosition: 'right',
|
||||
targetPosition: 'left',
|
||||
position: { x: 500, y: 150 },
|
||||
className: styles.PlantNode,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
data: { label: 'Nickel' },
|
||||
sourcePosition: 'right',
|
||||
targetPosition: 'left',
|
||||
position: { x: 900, y: 100 },
|
||||
className: styles.ProductNode,
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
data: { label: 'Metal casing' },
|
||||
sourcePosition: 'right',
|
||||
targetPosition: 'left',
|
||||
position: { x: 900, y: 300 },
|
||||
className: styles.ProductNode,
|
||||
},
|
||||
{
|
||||
id: 'e1-2',
|
||||
source: '1',
|
||||
target: '2',
|
||||
animated: true,
|
||||
selectable: false,
|
||||
style: { stroke: "black" },
|
||||
},
|
||||
{
|
||||
id: 'e2-3',
|
||||
source: '2',
|
||||
target: '3',
|
||||
animated: true,
|
||||
selectable: false,
|
||||
style: { stroke: "black" },
|
||||
},
|
||||
{
|
||||
id: 'e2-4',
|
||||
source: '2',
|
||||
target: '4',
|
||||
animated: true,
|
||||
selectable: false,
|
||||
style: { stroke: "black" },
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
const PipelineBlock = () => {
|
||||
return (
|
||||
<>
|
||||
<Section title="Pipeline" />
|
||||
<Card>
|
||||
<div className={styles.PipelineBlock}>
|
||||
<ReactFlow elements={elements}>
|
||||
<Background />
|
||||
</ReactFlow>
|
||||
</div>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Button label="Add product" kind="inline" />
|
||||
<Button label="Add plant" kind="inline" />
|
||||
</div>
|
||||
</Card>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default PipelineBlock;
|
||||
21
relog-web/src/PipelineBlock.module.css
Normal file
21
relog-web/src/PipelineBlock.module.css
Normal file
@@ -0,0 +1,21 @@
|
||||
.PipelineBlock {
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
.PlantNode, .ProductNode {
|
||||
border-color: rgba(0, 0, 0, 0.8);
|
||||
color: black;
|
||||
font-size: 13px;
|
||||
border-width: 1px;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0px 2px 4px -3px black;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.PlantNode {
|
||||
background-color: #0df;
|
||||
}
|
||||
|
||||
.ProductNode {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
142
relog-web/src/PlantBlock.js
Normal file
142
relog-web/src/PlantBlock.js
Normal file
@@ -0,0 +1,142 @@
|
||||
import Section from './Section'
|
||||
import Card from './Card'
|
||||
import Form from './Form'
|
||||
import TextInputRow from './TextInputRow'
|
||||
import FileInputRow from './FileInputRow'
|
||||
import DictInputRow from './DictInputRow'
|
||||
|
||||
const PlantBlock = (props) => {
|
||||
const emissions = {
|
||||
"CO2": "0.05",
|
||||
"CH4": "0.01",
|
||||
"N2O": "0.04",
|
||||
}
|
||||
const output = {
|
||||
"Nickel": "0.5",
|
||||
"Metal casing": "0.35",
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Section title={props.name} />
|
||||
<Card>
|
||||
<Form>
|
||||
<h1>General information</h1>
|
||||
<FileInputRow
|
||||
label="Candidate locations"
|
||||
tooltip="A dictionary mapping the name of the location to a dictionary which describes the site characteristics."
|
||||
/>
|
||||
|
||||
|
||||
<h1>Inputs & Outputs</h1>
|
||||
<TextInputRow
|
||||
label="Input"
|
||||
tooltip="The name of the product that this plant takes as input. Only one input is accepted per plant."
|
||||
disabled="disabled"
|
||||
value="Battery"
|
||||
/>
|
||||
<DictInputRow
|
||||
label="Outputs"
|
||||
unit="tonne/tonne"
|
||||
tooltip="A dictionary specifying how many tonnes of each product is produced for each tonnes of input. If the plant does not output anything, this key may be omitted."
|
||||
value={output}
|
||||
disableKeys={true}
|
||||
default="0"
|
||||
/>
|
||||
|
||||
<h1>Capacity & costs</h1>
|
||||
<TextInputRow
|
||||
label="Minimum capacity"
|
||||
unit="tonne"
|
||||
tooltip="The minimum size of the plant."
|
||||
default="0"
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Opening cost (min capacity)"
|
||||
unit="$"
|
||||
tooltip="The cost to open the plant at minimum capacity."
|
||||
default="0.00"
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Fixed operating cost (min capacity)"
|
||||
unit="$"
|
||||
tooltip="The cost to keep the plant open, even if the plant doesn't process anything."
|
||||
default="0.00"
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Maximum capacity"
|
||||
unit="tonne"
|
||||
tooltip="The maximum size of the plant."
|
||||
default="0"
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Opening cost (max capacity)"
|
||||
unit="$"
|
||||
tooltip="The cost to open a plant of this size."
|
||||
default="0.00"
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Fixed operating cost (max capacity)"
|
||||
unit="$"
|
||||
tooltip="The cost to keep the plant open, even if the plant doesn't process anything."
|
||||
default="0.00"
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Variable operating cost"
|
||||
unit="$"
|
||||
tooltip="The cost that the plant incurs to process each tonne of input."
|
||||
default="0.00"
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Energy expenditure"
|
||||
unit="GJ/tonne"
|
||||
tooltip="The energy required to process 1 tonne of the input."
|
||||
default="0"
|
||||
/>
|
||||
|
||||
<h1>Storage</h1>
|
||||
<TextInputRow
|
||||
label="Storage cost"
|
||||
unit="$/tonne"
|
||||
tooltip="The cost to store a tonne of input product for one time period."
|
||||
default="0.00"
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Storage limit"
|
||||
unit="tonne"
|
||||
tooltip="The maximum amount of input product this plant can have in storage at any given time."
|
||||
default="0"
|
||||
/>
|
||||
|
||||
<h1>Disposal</h1>
|
||||
<DictInputRow
|
||||
label="Disposal cost"
|
||||
unit="$/tonne"
|
||||
tooltip="The cost to dispose of the product."
|
||||
value={output}
|
||||
disableKeys={true}
|
||||
/>
|
||||
<DictInputRow
|
||||
label="Disposal limit"
|
||||
unit="tonne"
|
||||
tooltip="The maximum amount that can be disposed of. If an unlimited amount can be disposed, this key may be omitted."
|
||||
value={output}
|
||||
disableKeys={true}
|
||||
/>
|
||||
|
||||
<h1>Emissions</h1>
|
||||
<DictInputRow
|
||||
label="Emissions"
|
||||
unit="tonne/tonne"
|
||||
tooltip="A dictionary mapping the name of each greenhouse gas, produced to process each tonne of input, to the amount of gas produced (in tonne)."
|
||||
value={emissions}
|
||||
keyPlaceholder="Emission name"
|
||||
valuePlaceholder="0"
|
||||
/>
|
||||
|
||||
</Form>
|
||||
</Card>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default PlantBlock;
|
||||
64
relog-web/src/ProductBlock.js
Normal file
64
relog-web/src/ProductBlock.js
Normal file
@@ -0,0 +1,64 @@
|
||||
import Section from './Section'
|
||||
import Card from './Card'
|
||||
import Form from './Form'
|
||||
import TextInputRow from './TextInputRow'
|
||||
import FileInputRow from './FileInputRow'
|
||||
|
||||
const ProductBlock = (props) => {
|
||||
return (
|
||||
<>
|
||||
<Section title={props.name} />
|
||||
<Card>
|
||||
<Form>
|
||||
<h1>General information</h1>
|
||||
<FileInputRow
|
||||
label="Initial amounts"
|
||||
tooltip="A dictionary mapping the name of each location to its description (see below). If this product is not initially available, this key may be omitted."
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Acquisition cost"
|
||||
unit="$/tonne"
|
||||
tooltip="The cost to acquire one tonne of this product from collection centers. Does not apply to plant outputs."
|
||||
default="0.00"
|
||||
/>
|
||||
|
||||
<h1>Disposal</h1>
|
||||
<TextInputRow
|
||||
label="Disposal cost"
|
||||
unit="$/tonne"
|
||||
tooltip="The cost to dispose of one tonne of this product at a collection center, without further processing. Does not apply to plant outputs."
|
||||
default="0"
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Disposal limit"
|
||||
unit="tonne"
|
||||
tooltip="The maximum amount of this product that can be disposed of across all collection centers, without further processing."
|
||||
default="0"
|
||||
/>
|
||||
|
||||
<h1>Transportation</h1>
|
||||
<TextInputRow
|
||||
label="Transportation cost"
|
||||
unit="$/km/tonne"
|
||||
tooltip="The cost to transport this product."
|
||||
default="0.00"
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Transportation energy"
|
||||
unit="J/km/tonne"
|
||||
default="0"
|
||||
tooltip="The energy required to transport this product."
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Transportation emissions"
|
||||
unit="J/km/tonne"
|
||||
tooltip="A dictionary mapping the name of each greenhouse gas, produced to transport one tonne of this product along one kilometer, to the amount of gas produced (in tonnes)."
|
||||
default="0"
|
||||
/>
|
||||
</Form>
|
||||
</Card>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProductBlock;
|
||||
7
relog-web/src/Section.js
Normal file
7
relog-web/src/Section.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import styles from './Section.module.css'
|
||||
|
||||
const Section = (props) => {
|
||||
return <h2 className={styles.Section}>{props.title}</h2>
|
||||
}
|
||||
|
||||
export default Section;
|
||||
6
relog-web/src/Section.module.css
Normal file
6
relog-web/src/Section.module.css
Normal file
@@ -0,0 +1,6 @@
|
||||
.Section {
|
||||
line-height: 36px;
|
||||
margin: 12px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
29
relog-web/src/TextInputRow.js
Normal file
29
relog-web/src/TextInputRow.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import form_styles from './Form.module.css'
|
||||
import Button from './Button'
|
||||
|
||||
const TextInputRow = (props) => {
|
||||
let unit = "";
|
||||
if (props.unit) {
|
||||
unit = <span className={form_styles.FormRow_unit}>({props.unit})</span>
|
||||
}
|
||||
|
||||
let tooltip = "";
|
||||
if (props.tooltip != undefined) {
|
||||
tooltip = <Button label="?" kind="inline" tooltip={props.tooltip} />
|
||||
}
|
||||
|
||||
return <div className={form_styles.FormRow}>
|
||||
<label>
|
||||
{props.label} {unit}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={props.default}
|
||||
disabled={props.disabled}
|
||||
value={props.value}
|
||||
/>
|
||||
{tooltip}
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default TextInputRow;
|
||||
48
relog-web/src/index.css
Normal file
48
relog-web/src/index.css
Normal file
@@ -0,0 +1,48 @@
|
||||
:root {
|
||||
--site-width: 1200px;
|
||||
--box-border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
--box-shadow: 0px 2px 4px -3px rgba(0, 0, 0, 0.2);
|
||||
--border-radius: 4px;
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #f6f6f6;
|
||||
color: rgba(0, 0, 0, 0.95);
|
||||
}
|
||||
|
||||
#content {
|
||||
max-width: var(--site-width);
|
||||
min-width: 900px;
|
||||
margin: 0 auto;
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
.react-flow__node.selected {
|
||||
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2) !important;
|
||||
border-width: 2px !important;
|
||||
margin-top: -1px !important;
|
||||
margin-left: -1px !important;
|
||||
border-radius: 8px !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.react-flow__handle {
|
||||
width: 8px !important;
|
||||
height: 8px !important;
|
||||
background-color: white !important;
|
||||
border: 1px solid black !important;
|
||||
}
|
||||
|
||||
.react-flow__handle-right {
|
||||
right: -5px !important;
|
||||
}
|
||||
|
||||
.react-flow__handle-left {
|
||||
left: -5px !important;
|
||||
}
|
||||
17
relog-web/src/index.js
Normal file
17
relog-web/src/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './index.css';
|
||||
import Header from './Header';
|
||||
import InputPage from './InputPage';
|
||||
import Footer from './Footer'
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<Header />
|
||||
<div id="content">
|
||||
<InputPage />
|
||||
</div>
|
||||
<Footer />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
Reference in New Issue
Block a user