parent
facc9faabf
commit
ea58cf1615
@ -0,0 +1,23 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "web",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.7.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||
"@testing-library/dom": "^10.4.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "^16.18.126",
|
||||
"@types/react": "^19.1.3",
|
||||
"@types/react-dom": "^19.1.3",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"typescript": "^4.9.5",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 3.8 KiB |
@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="UnitCommitment.jl Case Builder"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<title>Case Builder - UnitCommitment.jl</title>
|
||||
<style>
|
||||
:root {
|
||||
--site-max-width: 1200px;
|
||||
--site-min-width: 900px;
|
||||
--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;
|
||||
--primary: #0d6efd;
|
||||
|
||||
--contrast-100: #202020;
|
||||
--contrast-80: #606060;
|
||||
--contrast-60: #909090;
|
||||
--contrast-10: #f6f6f6;
|
||||
--contrast-0: #fefefe;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: var(--contrast-10)
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 9.4 KiB |
@ -0,0 +1,25 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
@ -0,0 +1,11 @@
|
||||
import Header from "./Header/Header";
|
||||
import Parameters from "./Parameters/Parameters";
|
||||
|
||||
function CaseBuilder() {
|
||||
return <div>
|
||||
<Header/>
|
||||
<Parameters/>
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default CaseBuilder;
|
@ -0,0 +1,36 @@
|
||||
.HeaderBox {
|
||||
background-color: var(--contrast-0);
|
||||
border-bottom: var(--box-border);
|
||||
box-shadow: var(--box-shadow);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.HeaderContent {
|
||||
margin: 0 auto;
|
||||
max-width: var(--site-max-width);
|
||||
min-width: var(--site-min-width);
|
||||
}
|
||||
|
||||
.HeaderContent h1, h2 {
|
||||
color: var(--contrast-100);
|
||||
display: inline-block;
|
||||
line-height: 48px;
|
||||
font-size: 28px;
|
||||
margin: 0;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.HeaderContent h2 {
|
||||
display: inline-block;
|
||||
font-size: 22px;
|
||||
color: var(--contrast-80);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
float: right;
|
||||
padding: 16px 12px;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
import styles from "./Header.module.css"
|
||||
import Button from "../../Common/Buttons/Button";
|
||||
|
||||
function Header() {
|
||||
return (
|
||||
<div className={styles.HeaderBox}>
|
||||
<div className={styles.HeaderContent}>
|
||||
<h1>UnitCommitment.jl</h1>
|
||||
<h2>Case Builder</h2>
|
||||
<div className={styles.buttonContainer}>
|
||||
<Button title="Clear"/>
|
||||
<Button title="Load"/>
|
||||
<Button title="Save"/>
|
||||
<Button title="Submit"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Header;
|
@ -0,0 +1,36 @@
|
||||
import SectionHeader from "../../Common/SectionHeader/SectionHeader";
|
||||
import Form from "../../Common/Forms/Form";
|
||||
import TextInputRow from "../../Common/Forms/TextInputRow";
|
||||
|
||||
function Parameters() {
|
||||
return (
|
||||
<div>
|
||||
<SectionHeader title="Parameters" />
|
||||
<Form>
|
||||
<TextInputRow
|
||||
label="Time horizon"
|
||||
unit="h"
|
||||
tooltip="Length of the planning horizon (in hours)."
|
||||
currentValue="48"
|
||||
defaultValue="24"
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Time step"
|
||||
unit="min"
|
||||
tooltip="Length of each time step (in minutes). Must be a divisor of 60 (e.g. 60, 30, 20, 15, etc)."
|
||||
currentValue=""
|
||||
defaultValue="60"
|
||||
/>
|
||||
<TextInputRow
|
||||
label="Power balance penalty"
|
||||
unit="$/MW"
|
||||
tooltip="Penalty for system-wide shortage or surplus in production (in /MW). This is charged per time step. For example, if there is a shortage of 1 MW for three time steps, three times this amount will be charged."
|
||||
currentValue=""
|
||||
defaultValue="1000.0"
|
||||
/>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Parameters;
|
@ -0,0 +1,22 @@
|
||||
.Button {
|
||||
padding: 6px 36px;
|
||||
margin: 0 0 0 8px;
|
||||
line-height: 24px;
|
||||
border: var(--box-border);
|
||||
box-shadow: var(--box-shadow);
|
||||
border-radius: var(--border-radius);
|
||||
cursor: pointer;
|
||||
color: var(--contrast-80);
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
background: linear-gradient(var(--contrast-0) 25%, var(--contrast-10) 100%);
|
||||
}
|
||||
|
||||
.Button:hover {
|
||||
background: rgb(245, 245, 245);
|
||||
}
|
||||
|
||||
.Button:active {
|
||||
background: rgba(220, 220, 220);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
import styles from "./Button.module.css"
|
||||
|
||||
function Button({title}: {title: string}) {
|
||||
return <button className={styles.Button}>{title}</button>
|
||||
}
|
||||
|
||||
export default Button;
|
@ -0,0 +1,35 @@
|
||||
.Form {
|
||||
background-color: var(--contrast-0);
|
||||
border: var(--box-border);
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: var(--box-shadow);
|
||||
min-height: 48px;
|
||||
margin: 0 auto;
|
||||
min-width: var(--site-min-width);
|
||||
max-width: var(--site-max-width);
|
||||
padding: 12px 0;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
import { ReactNode } from 'react';
|
||||
import styles from "./Form.module.css"
|
||||
|
||||
function Form({ children }: { children: ReactNode }) {
|
||||
return <div className={styles.Form}>{children}</div>
|
||||
}
|
||||
|
||||
export default Form;
|
@ -0,0 +1,36 @@
|
||||
.tooltip {
|
||||
visibility: hidden;
|
||||
background-color: var(--contrast-80);
|
||||
color: var(--contrast-10);
|
||||
opacity: 0;
|
||||
width: 250px;
|
||||
margin-top: 36px;
|
||||
margin-left: -250px;
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
font-size: 14px;
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: var(--box-shadow);
|
||||
line-height: 20px;
|
||||
transition: opacity 0.5s;
|
||||
font-weight: normal;
|
||||
text-align: left;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: var(--contrast-60);
|
||||
font-size: 16px;
|
||||
padding: 8px 8px 8px 0;
|
||||
}
|
||||
|
||||
.HelpButton {
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.HelpButton:hover .tooltip {
|
||||
visibility: visible;
|
||||
opacity: 100%;
|
||||
transition: opacity 0.5s;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
import styles from "./HelpButton.module.css"
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'
|
||||
import {faCircleQuestion} from '@fortawesome/free-regular-svg-icons'
|
||||
|
||||
|
||||
function HelpButton({text}: { text: String }) {
|
||||
return (
|
||||
<button className={styles.HelpButton}>
|
||||
<span className={styles.tooltip}>{text}</span>
|
||||
<span className={styles.icon}>
|
||||
<FontAwesomeIcon icon={faCircleQuestion}/>
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default HelpButton;
|
@ -0,0 +1,27 @@
|
||||
import formStyles from "./Form.module.css";
|
||||
import HelpButton from "./HelpButton";
|
||||
|
||||
function TextInputRow({label, unit, tooltip, currentValue, defaultValue}: {
|
||||
label: string,
|
||||
unit: string,
|
||||
tooltip: string,
|
||||
currentValue: string,
|
||||
defaultValue: string,
|
||||
}) {
|
||||
return (
|
||||
<div className={formStyles.FormRow}>
|
||||
<label>
|
||||
{label}
|
||||
<span className={formStyles.FormRow_unit}> ({unit})</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={defaultValue}
|
||||
value={currentValue}
|
||||
/>
|
||||
<HelpButton text={tooltip} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TextInputRow;
|
@ -0,0 +1,13 @@
|
||||
.SectionHeader {
|
||||
max-width: var(--site-max-width);
|
||||
min-width: var(--site-min-width);
|
||||
margin: 0 auto;
|
||||
color: var(--contrast-100);
|
||||
}
|
||||
|
||||
.SectionHeader h1 {
|
||||
margin: 0;
|
||||
padding: 0 12px;
|
||||
font-size: 16px;
|
||||
line-height: 64px;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
import styles from "./SectionHeader.module.css"
|
||||
|
||||
function SectionHeader({title}: {title: string}) {
|
||||
return (
|
||||
<div className={styles.SectionHeader}>
|
||||
<h1>{title}</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SectionHeader;
|
@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
import CaseBuilder from "./components/CaseBuilder/CaseBuilder";
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById('root') as HTMLElement
|
||||
);
|
||||
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<CaseBuilder/>
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
reportWebVitals();
|
After Width: | Height: | Size: 2.6 KiB |
@ -0,0 +1 @@
|
||||
/// <reference types="react-scripts" />
|
@ -0,0 +1,15 @@
|
||||
import { ReportHandler } from 'web-vitals';
|
||||
|
||||
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
@ -0,0 +1 @@
|
||||
import '@testing-library/jest-dom';
|
@ -0,0 +1,41 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"alwaysStrict": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"noEmit": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"strictFunctionTypes": true,
|
||||
"strictNullChecks": true,
|
||||
"strictPropertyInitialization": true,
|
||||
"allowUnusedLabels": false,
|
||||
"allowUnreachableCode": false,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"checkJs": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
Loading…
Reference in new issue