Merge pull request #3 from nickorlow/done

Fixed mobile navbar + new comparisons page
This commit is contained in:
Nicholas Orlowsky 2023-01-23 20:52:07 -06:00 committed by GitHub
commit d95635541b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 543 additions and 80 deletions

View file

@ -3,8 +3,8 @@
<component name="ChangeListManager">
<list default="true" id="03fafda4-e2c1-4602-a731-a2f96e84badd" name="Default Changelist" comment="">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/CreateCruisePage.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/CreateCruisePage.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/UptimeCard.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/UptimeCard.tsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/App.css" beforeDir="false" afterPath="$PROJECT_DIR$/src/App.css" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/components/UptimeComparisonCard.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/src/components/UptimeComparisonCard.tsx" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -33,15 +33,14 @@
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"ts.external.directory.path": "/home/nickorlow/programmming/personal/nws-site/node_modules/typescript/lib"
}
}]]></component>
<component name="PropertiesComponent">
<property name="last_opened_file_path" value="$PROJECT_DIR$/src/components" />
<property name="ts.external.directory.path" value="$PROJECT_DIR$/node_modules/typescript/lib" />
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/src/static/images" />
<recent name="$PROJECT_DIR$/src/components" />
<recent name="$PROJECT_DIR$/src/static/images" />
</key>
</component>
<component name="RunManager">

273
package-lock.json generated
View file

@ -18,6 +18,7 @@
"bootstrap": "^5.1.3",
"react": "^18.2.0",
"react-bootstrap": "^2.4.0",
"react-copy-code": "^2.1.2",
"react-dom": "^18.2.0",
"react-markdown": "^8.0.3",
"react-modal": "^3.16.1",
@ -1929,6 +1930,33 @@
"postcss": "^8.3"
}
},
"node_modules/@emotion/is-prop-valid": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz",
"integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==",
"peer": true,
"dependencies": {
"@emotion/memoize": "^0.8.0"
}
},
"node_modules/@emotion/memoize": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz",
"integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==",
"peer": true
},
"node_modules/@emotion/stylis": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz",
"integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==",
"peer": true
},
"node_modules/@emotion/unitless": {
"version": "0.7.5",
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
"integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==",
"peer": true
},
"node_modules/@eslint/eslintrc": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz",
@ -4777,6 +4805,28 @@
"@babel/core": "^7.0.0-0"
}
},
"node_modules/babel-plugin-styled-components": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.7.tgz",
"integrity": "sha512-i7YhvPgVqRKfoQ66toiZ06jPNA3p6ierpfUuEWxNF+fV27Uv5gxBkf8KZLHUCc1nFA9j6+80pYoIpqCeyW3/bA==",
"peer": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.16.0",
"@babel/helper-module-imports": "^7.16.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"lodash": "^4.17.11",
"picomatch": "^2.3.0"
},
"peerDependencies": {
"styled-components": ">= 2"
}
},
"node_modules/babel-plugin-syntax-jsx": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
"integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==",
"peer": true
},
"node_modules/babel-plugin-transform-react-remove-prop-types": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz",
@ -5110,6 +5160,15 @@
"node": ">= 6"
}
},
"node_modules/camelize": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
"integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/caniuse-api": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
@ -5601,6 +5660,15 @@
"postcss": "^8.3"
}
},
"node_modules/css-color-keywords": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
"integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
"peer": true,
"engines": {
"node": ">=4"
}
},
"node_modules/css-declaration-sorter": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.1.4.tgz",
@ -5785,6 +5853,17 @@
"resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
"integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w=="
},
"node_modules/css-to-react-native": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.1.0.tgz",
"integrity": "sha512-AryfkFA29b4I3vG7N4kxFboq15DxwSXzhXM37XNEjwJMgjYIc8BcqfiprpAqX0zadI5PMByEIwAMzXxk5Vcc4g==",
"peer": true,
"dependencies": {
"camelize": "^1.0.0",
"css-color-keywords": "^1.0.0",
"postcss-value-parser": "^4.0.2"
}
},
"node_modules/css-tree": {
"version": "1.0.0-alpha.37",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz",
@ -8156,6 +8235,30 @@
"he": "bin/he"
}
},
"node_modules/highlight.js": {
"version": "11.7.0",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz",
"integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==",
"peer": true,
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
"peer": true,
"dependencies": {
"react-is": "^16.7.0"
}
},
"node_modules/hoist-non-react-statics/node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"peer": true
},
"node_modules/hoopy": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
@ -13789,6 +13892,17 @@
}
}
},
"node_modules/react-copy-code": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/react-copy-code/-/react-copy-code-2.1.2.tgz",
"integrity": "sha512-soeQmbEIBYnfbn5NJLoG5smuNA1azh5Mwwpls4Ay+Sc4ipi4DXKDCMNiuqr/Ecf/+7HHcYh7V1wvPDzmXPeRTg==",
"peerDependencies": {
"highlight.js": ">=9",
"react": ">=16.6",
"react-dom": ">=16.6",
"styled-components": ">=4"
}
},
"node_modules/react-dev-utils": {
"version": "12.0.0",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz",
@ -14824,6 +14938,12 @@
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"node_modules/shallowequal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==",
"peer": true
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -15258,6 +15378,37 @@
"inline-style-parser": "0.1.1"
}
},
"node_modules/styled-components": {
"version": "5.3.6",
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.6.tgz",
"integrity": "sha512-hGTZquGAaTqhGWldX7hhfzjnIYBZ0IXQXkCYdvF1Sq3DsUaLx6+NTHC5Jj1ooM2F68sBiVz3lvhfwQs/S3l6qg==",
"hasInstallScript": true,
"peer": true,
"dependencies": {
"@babel/helper-module-imports": "^7.0.0",
"@babel/traverse": "^7.4.5",
"@emotion/is-prop-valid": "^1.1.0",
"@emotion/stylis": "^0.8.4",
"@emotion/unitless": "^0.7.4",
"babel-plugin-styled-components": ">= 1.12.0",
"css-to-react-native": "^3.0.0",
"hoist-non-react-statics": "^3.0.0",
"shallowequal": "^1.1.0",
"supports-color": "^5.5.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/styled-components"
},
"peerDependencies": {
"react": ">= 16.8.0",
"react-dom": ">= 16.8.0",
"react-is": ">= 16.8.0"
}
},
"node_modules/stylehacks": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.2.tgz",
@ -18466,6 +18617,33 @@
"postcss-value-parser": "^4.2.0"
}
},
"@emotion/is-prop-valid": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz",
"integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==",
"peer": true,
"requires": {
"@emotion/memoize": "^0.8.0"
}
},
"@emotion/memoize": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz",
"integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==",
"peer": true
},
"@emotion/stylis": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz",
"integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==",
"peer": true
},
"@emotion/unitless": {
"version": "0.7.5",
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
"integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==",
"peer": true
},
"@eslint/eslintrc": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz",
@ -20573,6 +20751,25 @@
"@babel/helper-define-polyfill-provider": "^0.3.1"
}
},
"babel-plugin-styled-components": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.7.tgz",
"integrity": "sha512-i7YhvPgVqRKfoQ66toiZ06jPNA3p6ierpfUuEWxNF+fV27Uv5gxBkf8KZLHUCc1nFA9j6+80pYoIpqCeyW3/bA==",
"peer": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.16.0",
"@babel/helper-module-imports": "^7.16.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"lodash": "^4.17.11",
"picomatch": "^2.3.0"
}
},
"babel-plugin-syntax-jsx": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
"integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==",
"peer": true
},
"babel-plugin-transform-react-remove-prop-types": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz",
@ -20834,6 +21031,12 @@
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="
},
"camelize": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
"integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
"peer": true
},
"caniuse-api": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
@ -21209,6 +21412,12 @@
"postcss-selector-parser": "^6.0.8"
}
},
"css-color-keywords": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
"integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
"peer": true
},
"css-declaration-sorter": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.1.4.tgz",
@ -21318,6 +21527,17 @@
"resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
"integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w=="
},
"css-to-react-native": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.1.0.tgz",
"integrity": "sha512-AryfkFA29b4I3vG7N4kxFboq15DxwSXzhXM37XNEjwJMgjYIc8BcqfiprpAqX0zadI5PMByEIwAMzXxk5Vcc4g==",
"peer": true,
"requires": {
"camelize": "^1.0.0",
"css-color-keywords": "^1.0.0",
"postcss-value-parser": "^4.0.2"
}
},
"css-tree": {
"version": "1.0.0-alpha.37",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz",
@ -23040,6 +23260,29 @@
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
},
"highlight.js": {
"version": "11.7.0",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz",
"integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==",
"peer": true
},
"hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
"peer": true,
"requires": {
"react-is": "^16.7.0"
},
"dependencies": {
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"peer": true
}
}
},
"hoopy": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
@ -26879,6 +27122,12 @@
"warning": "^4.0.3"
}
},
"react-copy-code": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/react-copy-code/-/react-copy-code-2.1.2.tgz",
"integrity": "sha512-soeQmbEIBYnfbn5NJLoG5smuNA1azh5Mwwpls4Ay+Sc4ipi4DXKDCMNiuqr/Ecf/+7HHcYh7V1wvPDzmXPeRTg==",
"requires": {}
},
"react-dev-utils": {
"version": "12.0.0",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz",
@ -27638,6 +27887,12 @@
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"shallowequal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==",
"peer": true
},
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -27965,6 +28220,24 @@
"inline-style-parser": "0.1.1"
}
},
"styled-components": {
"version": "5.3.6",
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.6.tgz",
"integrity": "sha512-hGTZquGAaTqhGWldX7hhfzjnIYBZ0IXQXkCYdvF1Sq3DsUaLx6+NTHC5Jj1ooM2F68sBiVz3lvhfwQs/S3l6qg==",
"peer": true,
"requires": {
"@babel/helper-module-imports": "^7.0.0",
"@babel/traverse": "^7.4.5",
"@emotion/is-prop-valid": "^1.1.0",
"@emotion/stylis": "^0.8.4",
"@emotion/unitless": "^0.7.4",
"babel-plugin-styled-components": ">= 1.12.0",
"css-to-react-native": "^3.0.0",
"hoist-non-react-statics": "^3.0.0",
"shallowequal": "^1.1.0",
"supports-color": "^5.5.0"
}
},
"stylehacks": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.2.tgz",

View file

@ -13,6 +13,7 @@
"bootstrap": "^5.1.3",
"react": "^18.2.0",
"react-bootstrap": "^2.4.0",
"react-copy-code": "^2.1.2",
"react-dom": "^18.2.0",
"react-markdown": "^8.0.3",
"react-modal": "^3.16.1",

View file

@ -9,10 +9,9 @@ input {
border-color: #000;
border-width: 1px;
border-style: solid;
margin-bottom: 1px;
display: block;
padding: 3px;
}
button {
@ -59,6 +58,15 @@ p {
padding-bottom: 5px;
}
@media only screen
and (max-width: 992px) {
.nws-card-md {
border-radius: 20px;
background-color: #eee;
padding: .75rem;
}
}
.nws-card {
border-radius: 20px;
background-color: #eee;

View file

@ -0,0 +1,32 @@
.pill {
padding: 1px;
transition: .5s;
text-align: center;
}
.pill-selected{
font-weight: bold;
border-radius: 20px;
background-color: #ffffff;
}
.pill-container {
padding: 2px;
border-radius: 20px;
background-color: #aaaa;
}
button {
padding: 5px;
}
.help-text {
font-style: italic;
margin: 0;
font-size: .9em;
}
.label-text{
margin: 1em 0 0;
}

View file

@ -3,6 +3,7 @@ import URI from "urijs";
import {Namespace} from "../nws-api/types";
import {useNWSAccount, useNWSAuthKey} from "../nws-api/hooks";
import {useSearchParams} from "react-router-dom";
import './CreateCruisePage.css';
export default function CreateCruisePage() {
const [page, setPage] = useState('info');
@ -44,7 +45,13 @@ export default function CreateCruisePage() {
return (
<div className={"App"}>
<h1>Create Container Deployment</h1>
<h1 className={"mb-5 mt-3 fw-bolder"}>Create Container Deployment</h1>
<div className={"pill-container row justify-content-evenly mb-5"} style={{width: "80%"}}>
<p className={"pill col-md-2 " + (page === 'info' ? "pill-selected" : "")}>About</p>
<p className={"pill col-md-2 " + (page === 'framework-hostname' ? "pill-selected" : "")}>Deployment Info</p>
<p className={"pill col-md-2 " + (page === 'scriptgen' ? "pill-selected" : "")}>Repo Setup</p>
<p className={"pill col-md-2 " + (page === 'dns' ? "pill-selected" : "")}>DNS Configuration</p>
</div>
<div style={{width: "75vw"}}>
{
page === 'info' &&
@ -65,33 +72,34 @@ export default function CreateCruisePage() {
fall of organized civilization.
</li>
</ul>
<button onClick={()=>setPage('framework-hostname')}>I understand, continue</button>
<button className={"float-end"} onClick={()=>setPage('framework-hostname')}>I Understand, Continue</button>
</div>
}
{
page === 'framework-hostname' &&
<div>
<h5>What is this deployment's name?</h5>
<i>May only be lowercase letters and dashes, max 20 chars</i>
<br/>
<h5 className={"label-text"}>What is this deployment's name?</h5>
<p className={"help-text"}>May only be lowercase letters and dashes, max 20 chars</p>
<input value={name} onChange={(e)=>{setName(e.currentTarget.value)}}/>
<br/>
<h5>How did you create your website?</h5>
<p>Don't see your technology/framework? Email me: <a href={"mailto:nws-support@nickorlow.com"}>nws-support@nickorlow.com</a></p>
<h5 className={"label-text"}>How did you create your website?</h5>
<p className={"help-text"}>Don't see your technology/framework? Email me: <a href={"mailto:nws-support@nickorlow.com"}>nws-support@nickorlow.com</a></p>
<select value={strat}>
<option id={"raw-html"} onClick={()=>setStrat('raw-html')}>Raw HTML</option>
<option id={"react-js"} onClick={()=>setStrat('react-js')}>React JS</option>
</select>
<br/>
<h5>What is the url of the github repo where your code is hosted? (e.g. https://github.com/nickorlow/personal-site)</h5>
<p>Other git hosting providers are not currently supported through the Web UI</p>
<p>The repo must be public to create it through the Web UI</p>
<input value={gitUriInput} onInput={(e)=>{setGUI(e.currentTarget.value)}}/>
<br/>
<h5>What domain name will you use with your website? (e.g. nickorlow.com)</h5>
<input value={hostUriInput} onChange={(e)=>{setHUI(e.currentTarget.value)}}/>
<br/>
<button onClick={()=>{
<h5 className={"label-text"}>What is the url of the GitHub repo where your code is hosted?</h5>
<p className={"help-text"}>Other git hosting providers are not currently supported through the Web UI</p>
<p className={"help-text"}>The repo must be public to create it through the Web UI</p>
<input placeholder={"https://github.com/nickorlow/personal-site"} value={gitUriInput} onInput={(e)=>{setGUI(e.currentTarget.value)}}/>
<h5 className={"label-text"}>What domain name will you use with your website?</h5>
<input placeholder={"nws.nickorlow.com"} value={hostUriInput} onChange={(e)=>{setHUI(e.currentTarget.value)}}/>
<button onClick={()=>{setPage('info')}}>Back</button>
<button className={"float-end"} onClick={()=>{
try {
let git_url = new URL(gitUriInput);
@ -120,32 +128,34 @@ export default function CreateCruisePage() {
alert('may only be lowercase and dashes and under 20 chars')
return;
}
setHUI("https://"+hostUriInput);
setPage('scriptgen')
}}>Continue</button>
<button onClick={()=>{setPage('info')}}>Back</button>
</div>
}
{
page === 'scriptgen' &&
<div>
<h4>Copy & Paste the below into your terminal to add NWS deployment scripts to your webapp</h4>
<code style={{backgroundColor: "black", padding: 5, borderRadius: 10}}> curl -s https://raw.githubusercontent.com/nickorlow/nws-ghactions-templates/main/add-nws.sh | bash -s {strat} {owner} {repo}</code>
<code lang={"shell"} style={{backgroundColor: "black", padding: 5, borderRadius: 10}}>
curl -s https://raw.githubusercontent.com/nickorlow/nws-ghactions-templates/main/add-nws.sh | bash -s {strat} {owner} {repo}
</code>
<br/><span>Ensure the script finishes running before continuing</span>
<br/>
<button onClick={()=>{
<button onClick={()=>setPage('framework-hostname')}>Back</button>
<button className={"float-end"} onClick={()=>{
deploy();
setPage('dns');
}}>Continue</button>
<button onClick={()=>setPage('framework-hostname')}>Back</button>
</div>
}
{
page === 'dns' &&
<div>
<h4>Add the following DNS entry to {new URI(hostUriInput).hostname()}</h4>
<h4>Add the following DNS entry to {new URI("https://"+hostUriInput).hostname()}</h4>
{
new URI(hostUriInput).subdomain().length == 0 &&
new URI("https://"+hostUriInput).subdomain().length == 0 &&
<div>
<p>If your DNS provider is:</p>
<ul>
@ -159,7 +169,7 @@ export default function CreateCruisePage() {
</div>
}
{
new URI(hostUriInput).subdomain().length > 0 &&
new URI("https://"+hostUriInput).subdomain().length > 0 &&
<div>
<p>Type: CNAME</p>
<p>Name: {new URI(hostUriInput).subdomain()} ({new URI(hostUriInput).hostname()})</p>

View file

@ -1,4 +1,4 @@
import NWSLogo from "../static/images/NWS_Logo.png";
import NWSLogo from "../static/images/NWS_Logo_Transparent.png";
import UptimeCard from "./UptimeCard";
import IncidentCard from "./IncidentCard";
import Footer from "./Footer";
@ -6,6 +6,8 @@ import React, {useEffect, useState} from "react";
import {Incident, UptimeResponse} from "../nws-api/types";
import {getIncidents, getUptime} from "../nws-api/calls";
import "../App.css";
import UptimeComparisonCard from "./UptimeComparisonCard";
import UptimeLabelCard from "./UptimeLabelCard";
export default function HomePage() {
@ -30,7 +32,6 @@ export default function HomePage() {
return(
<div className="App">
<div className={"w-100 row"}>
<div className={"col-md-6 d-flex justify-content-center flex-column align-items-center"}>
<img src={NWSLogo} alt="nws-logo" style={{width: "70%"}}/>
@ -45,7 +46,10 @@ export default function HomePage() {
</p>
</div>
</div>
<div className={"w-100 mt-2 flex justify-content-center align-content-center text-center"}>
<h3><i>Better uptime than GitHub Pages!</i></h3>
<h4><a href={"https://youtu.be/WHdXWMFHuqA"} target="_blank" rel="noopener noreferrer">Watch the NWS Deployment Demo</a></h4>
</div>
<div style={{width: '75vw'}}>
<hr/>
</div>
@ -53,10 +57,11 @@ export default function HomePage() {
<div className={"text-left row"} style={{width: '75vw'}}>
<h2>Compare us to our competitors</h2>
<p>Last updated at {new Date(uptime.lastUpdated).toLocaleString()}</p>
<div className={"col-12 row w-100 m-0"}>
<div className={"col-12 row w-100 m-0 align-content-center d-flex justify-content-center pt-2"}>
<UptimeLabelCard/>
{uptime.competitors.sort((a,b)=>{return b.uptimeMonth === a.uptimeMonth ? (a.name === "NWS" ? -1000 : b.name.localeCompare(a.name)) : b.uptimeMonth - a.uptimeMonth}).map((e) => {
return (
<UptimeCard uptime={e} isService={false}/>
<UptimeComparisonCard uptime={e} isService={false}/>
);
})}
</div>

View file

@ -26,3 +26,16 @@
width: 500px;
max-width: 100vw;
}
.stat-perfect {
font-weight: bold;
color: #069D06
}
.stat-middle {
color: #877E1C
}
.stat-bad {
color: #921111
}

View file

@ -0,0 +1,80 @@
import {UptimeRecord} from "../nws-api/types";
import React, {useState} from "react";
import '../App.css';
import "./UptimeCard.css"
import Modal from "react-modal";
function getUptimeClass(uptime: number) {
if(uptime === 100) {
return "stat-perfect";
}
if(uptime >= 95) {
return "stat-middle";
}
return "stat-bad";
}
function getResponseTimeClass(respTime: number) {
// https://www.littledata.io/average/server-response-time
if(respTime < 205) {
return "stat-perfect";
}
if(respTime < 495) {
return "stat-middle";
}
return "stat-bad";
}
export default function UptimeComparisonCard(props: {uptime: UptimeRecord, isService: boolean}) {
const [isModalOpen, setModalOpen] = useState(false);
return(
<div className={"col-12 col-md-2 mb-2 p-0 m-0 text-center nws-card-md"}>
<div style={{height: 25, margin: 0}} className={"pt-2 pt-md-0"}>
<h4 className={"uptime-lnk"} onClick={()=>setModalOpen(true)}>{props.uptime.name}</h4>
</div>
<hr/>
<p className={"fw-bold d-md-none"}>Uptime (Last Month)</p>
<p className={getUptimeClass(props.uptime.uptimeMonth)}>{props.uptime.uptimeMonth}%</p>
<hr className={"d-md-block d-none"}/>
<p className={"fw-bold d-md-none"}>Uptime ({new Date().getFullYear()} YTD)</p>
<p className={getUptimeClass(props.uptime.uptimeYtd)}>{props.uptime.uptimeYtd}%</p>
<hr className={"d-md-block d-none"}/>
<p className={"fw-bold d-md-none"}>Avg Response Time (24hr)</p>
<p className={getResponseTimeClass(props.uptime.averageResponseTime)}>{props.uptime.averageResponseTime}ms</p>
<hr className={"d-md-block d-none"}/>
<p className={"fw-bold d-md-none"}>Current Status</p>
<div className={`p-1 d-flex justify-content-start w-100`}>
<p className={`fw-bold severity-label w-100
${props.uptime.isUp ? 'low' : (props.uptime.undergoingMaintenance ? 'med' : 'high')}-severity`}
>
{props.uptime.isUp ? 'Up' : (props.uptime.undergoingMaintenance ? 'Maintenance' : 'Down')}
</p>
</div>
<Modal className={"uptime-modal"} isOpen={isModalOpen}>
<div className={"mb-3"}>
<h1 className={"mb-0"}>{props.uptime.name}</h1>
{props.uptime.url && <p>(<a href={props.uptime.url}>{props.uptime.url}</a>)</p>}
</div>
<div className={"mb-3"}>
<p>Monitoring since {props.uptime.monitorStart}</p>
<p><b>{new Date().getFullYear()} Uptime (YTD):</b> {props.uptime.uptimeYtd}%</p>
<p><b>Last Month Uptime:</b> {props.uptime.uptimeMonth}%</p>
<p><b>All-Time Uptime:</b> {props.uptime.uptimeAllTime}%</p>
<p><b>Average Response Time:</b> {props.uptime.averageResponseTime}ms</p>
</div>
{
props.isService &&
<div className={"mb-3"}>
<i>Note that the uptime and performance of services hosted on NWS may be affected by factors not controlled by NWS such as bad bad optimization or buggy software.</i>
</div>
}
<button className={"w-100"} onClick={()=>setModalOpen(false)}>Close</button>
</Modal>
</div>
);
}

View file

@ -0,0 +1,24 @@
import {UptimeRecord} from "../nws-api/types";
import React, {useState} from "react";
import '../App.css';
import "./UptimeCard.css"
import Modal from "react-modal";
export default function UptimeLabelCard() {
return(
<div className={"col-2 p-0 d-none d-md-block mb-2 m-0 text-center"}>
<div style={{height: 25, margin: 0}}>
<p className={"fw-bold"}>Service Name</p>
</div>
<hr/>
<p className={"fw-bold"}>Uptime (Last Month)</p>
<hr/>
<p className={"fw-bold"}>Uptime ({new Date().getFullYear()} YTD)</p>
<hr/>
<p className={"fw-bold"}>Avg Response Time (24hr)</p>
<hr/>
<p className={"fw-bold"}>Current Status</p>
</div>
);
}

View file

@ -20,26 +20,39 @@ import VerifyPage from "./components/VerifyPage";
import DashboardPage from "./components/DashboardPage";
import CreateCruisePage from "./components/CreateCruisePage";
import HomePage from "./components/HomePage";
import NavbarCollapse from "react-bootstrap/NavbarCollapse";
import NavbarOffcanvas from "react-bootstrap/NavbarOffcanvas";
function Layout (props: {children: any}) {
return (
<div>
<Navbar sticky={"top"} style={{height: "8vh", backgroundColor: "#eee", paddingLeft: "5vw", paddingRight: "5vw", maxWidth:"100%"}} className={"row m-0"}>
<div className={"col-10"}>
<NavbarBrand>
<img src={NWSLogo} alt="nws-logo" style={{width: 120}}/>
</NavbarBrand>
<NavLink className={"nav-lnk"} to={"/"}>
Home
</NavLink>
<NavLink className={"nav-lnk"} to={"/status"}>
Status
</NavLink>
<header className={"w-100 sticky-top"}>
<div className={"w-100"}>
<Navbar sticky={"top"} expand="lg" className={"row justify-content-center m-0 p-0"} style={{backgroundColor: "#eee"}}>
<div className={"row w-100"}>
<div className="row w-100 d-md-none d-sm-block">
<div className={"col-9"}>
<Navbar.Brand href="/">
<img src={NWSLogo} width={150}/>
</Navbar.Brand>
</div>
{/*<NavLink className={"nav-lnk"} to={"/blogs"}>*/}
{/* Blog*/}
{/*</NavLink>*/}
<div className={"col-2 d-none d-md-block"}>
<div className={"col-2 ml-3 d-flex align-content-center justify-content-center"}>
<Navbar.Toggle className={"h-50 align-self-center"} aria-controls="basic-navbar-nav"/>
</div>
</div>
<div className={"d-md-block d-none col-2"}>
<Navbar.Brand href="/">
<img src={NWSLogo} width={150}/>
</Navbar.Brand>
</div>
<Navbar.Collapse id="basic-navbar-nav" className={"col-10"}>
<Nav className="row w-100 ml-5">
<div className="col-md-4 row">
<NavLink className="col-sm-12 col-md-3 nav-lnk align-self-center" to={"/"}>Home</NavLink>
<NavLink className="col-sm-12 col-md-3 nav-lnk align-self-center" to={"/status"}>Status</NavLink>
</div>
<div className="col-md-6"/>
<div className={"col-md-2 d-md-block d-none"}>
{ localStorage.getItem("session_key") === null &&
(
<NavLink className={"nav-lnk"} to={"/login"}>
@ -62,7 +75,12 @@ function Layout (props: {children: any}) {
)
}
</div>
</Nav>
</Navbar.Collapse>
</div>
</Navbar>
</div>
</header>
<div style={{minHeight: "92vh"}}>
{props.children}
</div>