From b1eb6b832fb13f5e436061be439a8d3aceef5a50 Mon Sep 17 00:00:00 2001 From: Won Song Date: Mon, 16 Sep 2024 19:57:05 -0400 Subject: [PATCH] Dark theme, telemetry, spinner, refactoring --- Client/package-lock.json | 132 ++++++++++ Client/package.json | 5 +- .../src/components/Form/Button/BaseButton.tsx | 22 ++ .../components/Form/Button/DefaultButton.tsx | 13 +- .../components/Form/Button/PrimaryButton.tsx | 9 +- Client/src/components/Form/Button/button.scss | 10 +- .../components/Form/Button/button.types.ts | 2 + .../components/Form/TextField/TextField.scss | 20 ++ .../components/Form/TextField/TextField.tsx | 12 +- .../src/components/Layout/Footer/Footer.scss | 10 +- .../src/components/Layout/Header/Header.scss | 37 ++- .../src/components/Layout/Header/Header.tsx | 4 +- Client/src/components/Layout/Layout.tsx | 5 +- Client/src/components/Layout/Nav/Nav.scss | 8 +- Client/src/components/Layout/Nav/Nav.tsx | 8 +- .../Layout/SkipToMain/SkipToMain.scss | 42 ++-- .../Layout/SkipToMain/SkipToMain.tsx | 8 +- Client/src/components/Spinner/Spinner.scss | 41 +++ Client/src/components/Spinner/Spinner.tsx | 17 ++ Client/src/components/Spinner/index.ts | 1 + Client/src/hooks/usePageTracking.ts | 16 +- Client/src/hooks/usePrompts.ts | 17 +- Client/src/hooks/useScreenRouting.ts | 15 -- Client/src/index.scss | 149 ++--------- Client/src/index.tsx | 1 + Client/src/models/ScreenType.ts | 5 - Client/src/reset.scss | 237 ++++++++++++++++++ .../src/screens/AdminScreen/AdminScreen.tsx | 21 +- Client/src/screens/GameScreen/GameScreen.tsx | 11 +- .../src/screens/ResultScreen/ResultScreen.tsx | 3 + .../src/screens/StartScreen/StartScreen.tsx | 37 ++- Client/src/services/Http.ts | 2 + Client/src/services/Telemetry.ts | 53 ++++ Client/src/variables.scss | 15 ++ README.md | 3 - 35 files changed, 740 insertions(+), 251 deletions(-) create mode 100644 Client/src/components/Form/Button/BaseButton.tsx create mode 100644 Client/src/components/Spinner/Spinner.scss create mode 100644 Client/src/components/Spinner/Spinner.tsx create mode 100644 Client/src/components/Spinner/index.ts delete mode 100644 Client/src/hooks/useScreenRouting.ts delete mode 100644 Client/src/models/ScreenType.ts create mode 100644 Client/src/reset.scss create mode 100644 Client/src/variables.scss diff --git a/Client/package-lock.json b/Client/package-lock.json index 641edfb..0a90e2f 100644 --- a/Client/package-lock.json +++ b/Client/package-lock.json @@ -2112,6 +2112,138 @@ "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==" }, + "@microsoft/applicationinsights-analytics-js": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-analytics-js/-/applicationinsights-analytics-js-3.3.2.tgz", + "integrity": "sha512-btFX0IfmKfIZRWQVIRMfYqvLSmsYUTQhx3hcbAgPhNSfLlm1AXko4+dIiE5uBKdXa0iGcHXM4g95/SwKFVd2+w==", + "requires": { + "@microsoft/applicationinsights-common": "3.3.2", + "@microsoft/applicationinsights-core-js": "3.3.2", + "@microsoft/applicationinsights-shims": "3.0.1", + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-utils": ">= 0.11.3 < 2.x" + } + }, + "@microsoft/applicationinsights-cfgsync-js": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-cfgsync-js/-/applicationinsights-cfgsync-js-3.3.2.tgz", + "integrity": "sha512-ns6QjGyHT82EZ+LXnisAKyrZW3JcHfkhV9f810c0TF0SlRcyJKxMRoLTtaVIz4FHnKS9Jp/O2DeM6F2xL009lg==", + "requires": { + "@microsoft/applicationinsights-common": "3.3.2", + "@microsoft/applicationinsights-core-js": "3.3.2", + "@microsoft/applicationinsights-shims": "3.0.1", + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.2 < 2.x", + "@nevware21/ts-utils": ">= 0.11.3 < 2.x" + } + }, + "@microsoft/applicationinsights-channel-js": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-channel-js/-/applicationinsights-channel-js-3.3.2.tgz", + "integrity": "sha512-ic1oCQgGzitCLMYMHOgGuQvqd8G81s8R7ynI0NBgXc7pkzGiatCkLGx2lDiIYTYWV+Cd/3+cJwPB+3N8/yTGew==", + "requires": { + "@microsoft/applicationinsights-common": "3.3.2", + "@microsoft/applicationinsights-core-js": "3.3.2", + "@microsoft/applicationinsights-shims": "3.0.1", + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.2 < 2.x", + "@nevware21/ts-utils": ">= 0.11.3 < 2.x" + } + }, + "@microsoft/applicationinsights-common": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-common/-/applicationinsights-common-3.3.2.tgz", + "integrity": "sha512-RR6LpIC9JLQGTcgUaAXhuIZW69W00T6sF7GC6LvLy5PRjvg4m3MqflpQfNHt7yGy72ZHFG/TpLH5zJIghrNRew==", + "requires": { + "@microsoft/applicationinsights-core-js": "3.3.2", + "@microsoft/applicationinsights-shims": "3.0.1", + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-utils": ">= 0.11.3 < 2.x" + } + }, + "@microsoft/applicationinsights-core-js": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-3.3.2.tgz", + "integrity": "sha512-Jo3Mkl6zPswjS90SBbe+TxAOjQqHbwpD00VPca1ZeICc+31dbVNIBgkK42G0DbMB/ml1kqwkFV2/kpAH8QJCrw==", + "requires": { + "@microsoft/applicationinsights-shims": "3.0.1", + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.2 < 2.x", + "@nevware21/ts-utils": ">= 0.11.3 < 2.x" + } + }, + "@microsoft/applicationinsights-dependencies-js": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-dependencies-js/-/applicationinsights-dependencies-js-3.3.2.tgz", + "integrity": "sha512-Zd3BI7vQ96kIGiDOxX7tmNUnpSVBmx1OG8Vi3vappo3oswyiQWdOI3cwEfEeQil1qiODZOYTr8WRMSuTC9zQWg==", + "requires": { + "@microsoft/applicationinsights-common": "3.3.2", + "@microsoft/applicationinsights-core-js": "3.3.2", + "@microsoft/applicationinsights-shims": "3.0.1", + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.2 < 2.x", + "@nevware21/ts-utils": ">= 0.11.3 < 2.x" + } + }, + "@microsoft/applicationinsights-properties-js": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-properties-js/-/applicationinsights-properties-js-3.3.2.tgz", + "integrity": "sha512-tG96jiVwD5Z+b684O8hYdqXtEMEAev84kE7P35uYzHPmBKHgCJ4y6rmZQOyxaqTkpGZ8ahcFNzcxJgh+p0ahvQ==", + "requires": { + "@microsoft/applicationinsights-common": "3.3.2", + "@microsoft/applicationinsights-core-js": "3.3.2", + "@microsoft/applicationinsights-shims": "3.0.1", + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-utils": ">= 0.11.3 < 2.x" + } + }, + "@microsoft/applicationinsights-shims": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-shims/-/applicationinsights-shims-3.0.1.tgz", + "integrity": "sha512-DKwboF47H1nb33rSUfjqI6ryX29v+2QWcTrRvcQDA32AZr5Ilkr7whOOSsD1aBzwqX0RJEIP1Z81jfE3NBm/Lg==", + "requires": { + "@nevware21/ts-utils": ">= 0.9.4 < 2.x" + } + }, + "@microsoft/applicationinsights-web": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-web/-/applicationinsights-web-3.3.2.tgz", + "integrity": "sha512-qixMWKoymNtqvEzHkxpD6brABbejjUA/pFS9FRSeYAzGpNY0pfEWmlmuFfenqasphXl+5R+81TG0fS+n6fGWmQ==", + "requires": { + "@microsoft/applicationinsights-analytics-js": "3.3.2", + "@microsoft/applicationinsights-cfgsync-js": "3.3.2", + "@microsoft/applicationinsights-channel-js": "3.3.2", + "@microsoft/applicationinsights-common": "3.3.2", + "@microsoft/applicationinsights-core-js": "3.3.2", + "@microsoft/applicationinsights-dependencies-js": "3.3.2", + "@microsoft/applicationinsights-properties-js": "3.3.2", + "@microsoft/applicationinsights-shims": "3.0.1", + "@microsoft/dynamicproto-js": "^2.0.3", + "@nevware21/ts-async": ">= 0.5.2 < 2.x", + "@nevware21/ts-utils": ">= 0.11.3 < 2.x" + } + }, + "@microsoft/dynamicproto-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@microsoft/dynamicproto-js/-/dynamicproto-js-2.0.3.tgz", + "integrity": "sha512-JTWTU80rMy3mdxOjjpaiDQsTLZ6YSGGqsjURsY6AUQtIj0udlF/jYmhdLZu8693ZIC0T1IwYnFa0+QeiMnziBA==", + "requires": { + "@nevware21/ts-utils": ">= 0.10.4 < 2.x" + } + }, + "@nevware21/ts-async": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@nevware21/ts-async/-/ts-async-0.5.2.tgz", + "integrity": "sha512-Zf2vUNjCw2vJsiVKhWXA9hCNHsn59AOSGa5jGP4tWrp/vTH9XrI4eG/65khuoAgrS83migj0Xv5/j6fUAz69Zw==", + "requires": { + "@nevware21/ts-utils": ">= 0.11.3 < 2.x" + } + }, + "@nevware21/ts-utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@nevware21/ts-utils/-/ts-utils-0.11.3.tgz", + "integrity": "sha512-oipW+tyKN68bREjoESYAzOZiatM+1LF+ez1TX3BaeinhCkI18xsLgmpH9tvwHaVgKf1Tsth25sdbXVtYmgRYvQ==" + }, "@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", diff --git a/Client/package.json b/Client/package.json index da0ca54..c90eabb 100644 --- a/Client/package.json +++ b/Client/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@microsoft/applicationinsights-web": "^3.3.2", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -12,10 +13,10 @@ "@types/react-dom": "^18.3.0", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-router-dom": "^6.2.1", "react-scripts": "5.0.1", "typescript": "^4.9.5", - "web-vitals": "^2.1.4", - "react-router-dom": "^6.2.1" + "web-vitals": "^2.1.4" }, "scripts": { "start": "react-scripts start", diff --git a/Client/src/components/Form/Button/BaseButton.tsx b/Client/src/components/Form/Button/BaseButton.tsx new file mode 100644 index 0000000..b815840 --- /dev/null +++ b/Client/src/components/Form/Button/BaseButton.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import "./button.scss"; +import { ButtonProps } from "./button.types"; +import { Telemetry } from "../../../services/Telemetry"; + +export function BaseButton(props: ButtonProps): React.ReactElement { + const { onClick, classNames } = props; + + const handleButtonClicked = () => { + Telemetry.getInstance().event("ButtonClicked", { + buttonName: props.label, + }); + + onClick(); + }; + + return ( + + ); +} diff --git a/Client/src/components/Form/Button/DefaultButton.tsx b/Client/src/components/Form/Button/DefaultButton.tsx index e7f91fe..86c2780 100644 --- a/Client/src/components/Form/Button/DefaultButton.tsx +++ b/Client/src/components/Form/Button/DefaultButton.tsx @@ -1,15 +1,8 @@ import React from "react"; import "./button.scss"; import { ButtonProps } from "./button.types"; +import { BaseButton } from "./BaseButton"; -export function DefaultButton( - props: React.PropsWithChildren -): React.ReactElement { - const { onClick, children } = props; - - return ( - - ); +export function DefaultButton(props: ButtonProps): React.ReactElement { + return ; } diff --git a/Client/src/components/Form/Button/PrimaryButton.tsx b/Client/src/components/Form/Button/PrimaryButton.tsx index 7faf13b..8e4a1b6 100644 --- a/Client/src/components/Form/Button/PrimaryButton.tsx +++ b/Client/src/components/Form/Button/PrimaryButton.tsx @@ -1,15 +1,10 @@ import React from "react"; import "./button.scss"; import { ButtonProps } from "./button.types"; +import { BaseButton } from "./BaseButton"; export function PrimaryButton( props: React.PropsWithChildren ): React.ReactElement { - const { onClick, children } = props; - - return ( - - ); + return ; } diff --git a/Client/src/components/Form/Button/button.scss b/Client/src/components/Form/Button/button.scss index 48d6f8d..136e08b 100644 --- a/Client/src/components/Form/Button/button.scss +++ b/Client/src/components/Form/Button/button.scss @@ -1,3 +1,5 @@ +@import "../../../variables.scss"; + @mixin base-button-style { display: inline-block; padding: 0.5rem 1rem; @@ -12,8 +14,8 @@ .primary-button { @include base-button-style; - background-color: #007bff; - border: 2px solid #007bff; + background-color: $primary-color; + border: 2px solid $primary-color; color: white; } @@ -21,6 +23,6 @@ @include base-button-style; background-color: white; - border: 2px solid #007bff; - color: #007bff; + border: 2px solid $primary-color; + color: $primary-color; } diff --git a/Client/src/components/Form/Button/button.types.ts b/Client/src/components/Form/Button/button.types.ts index 2cb24d0..a6f1e4c 100644 --- a/Client/src/components/Form/Button/button.types.ts +++ b/Client/src/components/Form/Button/button.types.ts @@ -1,4 +1,6 @@ export type ButtonProps = { onClick(): void; title: string; + label: string; + classNames?: string; }; diff --git a/Client/src/components/Form/TextField/TextField.scss b/Client/src/components/Form/TextField/TextField.scss index eddc5f6..64cc02b 100644 --- a/Client/src/components/Form/TextField/TextField.scss +++ b/Client/src/components/Form/TextField/TextField.scss @@ -1,3 +1,5 @@ +@import "../../../variables.scss"; + .text-field-container { margin-bottom: 20px; } @@ -13,10 +15,28 @@ display: block; width: 100%; font-size: 1em; + padding: 12px; + border: 1px solid $border-color-light; + + @media (prefers-color-scheme: dark) { + background-color: $input-background-dark; + border: 1px solid $border-color-dark; + color: $font-text-dark; + } } .text-area { width: 100%; min-height: 200px; font-size: 1em; + line-height: 1.5; + padding: 12px; + border-radius: 4px; + border: 1px solid $border-color-light; + + @media (prefers-color-scheme: dark) { + background-color: $input-background-dark; + border: 1px solid $border-color-dark; + color: $font-text-dark; + } } diff --git a/Client/src/components/Form/TextField/TextField.tsx b/Client/src/components/Form/TextField/TextField.tsx index 9ccef2d..c6e6b28 100644 --- a/Client/src/components/Form/TextField/TextField.tsx +++ b/Client/src/components/Form/TextField/TextField.tsx @@ -14,9 +14,12 @@ export function TextField(props: TextFieldProps): React.ReactElement { return (
{props.label && ( - + )}