├── .gitignore
├── not-now.json
├── package.json
├── public
├── favicon.ico
├── index.html
└── manifest.json
├── readme.md
├── scripts
└── build.js
├── src
├── App.js
├── Modal.js
├── StockChart.js
├── StockTable.js
├── index.css
└── index.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/not-now.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 2,
3 | "name": "react-lazy-preload-demo",
4 | "builds": [{ "src": "package.json", "use": "@now/static-build" }],
5 | "routes": [
6 | { "src": "^/static/(.*)", "dest": "/static/$1" },
7 | { "src": "/report", "dest": "/report.html" },
8 | { "src": ".*", "dest": "/index.html" }
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lazy-preload",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "moment": "^2.22.2",
7 | "react": "^16.6.1",
8 | "react-dom": "^16.6.1",
9 | "react-scripts": "2.1.1",
10 | "victory": "^30.6.0"
11 | },
12 | "scripts": {
13 | "start": "react-scripts start",
14 | "build": "node scripts/build",
15 | "now-build": "npm run build && mv build dist",
16 | "test": "react-scripts test",
17 | "eject": "react-scripts eject"
18 | },
19 | "eslintConfig": {
20 | "extends": "react-app"
21 | },
22 | "browserslist": [
23 | ">0.2%",
24 | "not dead",
25 | "not ie <= 11",
26 | "not op_mini all"
27 | ],
28 | "devDependencies": {
29 | "webpack-bundle-analyzer": "^3.0.3"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pomber/react-lazy-preload-demo/938502f89f00d7e97e193244c40f5ff7b48ea3be/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {
25 | event.stopPropagation();
26 | onClose();
27 | }}
28 | />
29 | );
30 |
31 | const Content = ({ children, onClose }) => (
32 |
{
34 | event.stopPropagation();
35 | }}
36 | style={{
37 | background: "white",
38 | outline: "none",
39 | position: "relative",
40 | borderRadius: "10px"
41 | }}
42 | aria-modal="true"
43 | tabIndex="-1"
44 | >
45 |
46 | {children}
47 |
48 | );
49 |
50 | const CloseButton = ({ onClick }) => (
51 |
66 | );
67 |
68 | export default Modal;
69 |
--------------------------------------------------------------------------------
/src/StockChart.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import {
3 | VictoryLine,
4 | VictoryChart,
5 | VictoryContainer,
6 | VictoryLabel,
7 | VictoryAxis
8 | } from "victory";
9 | import Modal from "./Modal";
10 | import moment from "moment";
11 |
12 | export default function Chart({ stock, onClose }) {
13 | const [first, ...rest] = Object.values(stock.data);
14 | const [last] = rest.reverse();
15 | const up = last.y >= first.y;
16 | const { width, height } = getDimentions();
17 | return (
18 |
19 | }
24 | >
25 |
32 | d.y}
35 | x={d => moment(d.x).format("MMM D")}
36 | style={{
37 | labels: { opacity: 0.75 },
38 | data: { stroke: up ? "darkgreen" : "darkred", strokeWidth: 3 }
39 | }}
40 | />
41 |
47 |
48 |
49 | );
50 | }
51 |
52 | function getDimentions() {
53 | const viewportWidth = Math.max(
54 | document.documentElement.clientWidth,
55 | window.innerWidth || 0
56 | );
57 | const viewportHeight = Math.max(
58 | document.documentElement.clientHeight,
59 | window.innerHeight || 0
60 | );
61 |
62 | const maxWidth = 600;
63 | const mobileViewportWidth = 500;
64 | let width = viewportWidth;
65 | width *= viewportWidth > mobileViewportWidth ? 0.9 : 1;
66 | width = Math.round(Math.min(width, maxWidth));
67 |
68 | const maxHeight = viewportHeight * 0.95;
69 | let height = width / 1.62;
70 | height = Math.round(Math.min(height, maxHeight));
71 |
72 | return { width, height };
73 | }
74 |
--------------------------------------------------------------------------------
/src/StockTable.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | export default function StockTable({ stocks, onSelect }) {
4 | return (
5 |
6 | Stocks
7 |
8 | {stocks.map(stock => (
9 | onSelect(stock)} />
10 | ))}
11 |
12 |
13 | );
14 | }
15 |
16 | function Row({ stock, onClick }) {
17 | return (
18 |
19 | {stock.name} |
20 | {stock.today} |
21 |
22 | {stock.change < 0 ? stock.change : "+" + stock.change}%
23 | |
24 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | font-size: 1.1rem;
10 | }
11 |
12 | table {
13 | border-collapse: collapse;
14 | }
15 |
16 | caption {
17 | font-size: 2rem;
18 | padding-bottom: 20px;
19 | }
20 |
21 | td:first-child {
22 | font-weight: bold;
23 | padding-right: 30px;
24 | padding-left: 5px;
25 | }
26 |
27 | tr td + td {
28 | text-align: right;
29 | padding: 8px 5px 8px 35px;
30 | }
31 |
32 | tr {
33 | cursor: pointer;
34 | padding: 0px 10px;
35 | }
36 |
37 | tr:hover {
38 | background: hsla(0, 0%, 0%, 0.075);
39 | }
40 |
41 | html,
42 | body,
43 | #root {
44 | height: 100%;
45 | }
46 |
47 | #root {
48 | display: flex;
49 | height: 100%;
50 | align-items: center;
51 | justify-content: center;
52 | }
53 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import "./index.css";
4 | import App from "./App";
5 |
6 | function randomValue() {
7 | return Math.round(1000 + Math.random() * 1000) / 10;
8 | }
9 |
10 | function daysAgo(days) {
11 | return new Date(Date.now() - days * 24 * 60 * 60 * 1000);
12 | }
13 |
14 | function fakeStock(name) {
15 | const today = randomValue();
16 | const yesterday = randomValue();
17 | const change = Math.round((1000 * (today - yesterday)) / yesterday) / 10;
18 | return {
19 | name,
20 | today,
21 | change,
22 | data: [
23 | { x: daysAgo(4), y: randomValue() },
24 | { x: daysAgo(3), y: randomValue() },
25 | { x: daysAgo(2), y: randomValue() },
26 | { x: daysAgo(1), y: yesterday },
27 | { x: daysAgo(0), y: today }
28 | ]
29 | };
30 | }
31 |
32 | const stocks = [
33 | fakeStock("Apple"),
34 | fakeStock("Citigroup"),
35 | fakeStock("General Electric"),
36 | fakeStock("Google"),
37 | fakeStock("Microsoft")
38 | ];
39 |
40 | ReactDOM.render(
, document.getElementById("root"));
41 |
--------------------------------------------------------------------------------