From 96c377dddfc5a4fed44fd4f0f46cec0e9c474ed0 Mon Sep 17 00:00:00 2001 From: Brett Heath-Wlaz Date: Thu, 14 Nov 2024 14:24:37 -0500 Subject: [PATCH] introduce CSS modules --- .../new-pa-message/new-pa-message-page.scss | 362 ------------------ .../new-pa-message/new-pa-message.scss | 1 - assets/css/pa-messages.module.scss | 204 ++++++++++ assets/index.d.ts | 1 + assets/js/components/Dashboard/DaysPicker.tsx | 17 +- .../components/Dashboard/IntervalPicker.tsx | 12 +- .../components/Dashboard/MessageTextBox.tsx | 8 +- .../Dashboard/PaMessageForm/MainForm.tsx | 160 ++++---- .../components/Dashboard/PriorityPicker.tsx | 15 +- assets/tsconfig.json | 1 + assets/webpack.config.js | 1 + 11 files changed, 342 insertions(+), 440 deletions(-) delete mode 100644 assets/css/dashboard/new-pa-message/new-pa-message-page.scss create mode 100644 assets/css/pa-messages.module.scss diff --git a/assets/css/dashboard/new-pa-message/new-pa-message-page.scss b/assets/css/dashboard/new-pa-message/new-pa-message-page.scss deleted file mode 100644 index 18a66522a..000000000 --- a/assets/css/dashboard/new-pa-message/new-pa-message-page.scss +++ /dev/null @@ -1,362 +0,0 @@ -.new-pa-message-page { - padding: 24px 40px; - max-width: 900px; - - form { - margin: 0; - } - - &__associate-alert-subtext { - color: $text-secondary; - } - - &__form-buttons { - padding: 18px 24px; - - .btn { - height: 38px; - - &:focus { - box-shadow: 0px 0px 0px 4px #8ecdff80; - } - } - } - - .when-card, - .where-card, - .message-card { - margin-top: 24px; - padding: 18px 24px; - background-color: $cool-gray-20; - color: white; - - .title { - margin-bottom: 16px; - font-weight: 500; - font-size: 24px; - } - - .text-input, - .interval, - .dropdown-toggle, - .date-picker, - .time-picker { - background-color: $dark-bg; - height: 38px; - color: $text-secondary; - font-weight: 400; - border: 1px solid $border-primary; - - &:focus, - &:focus-within { - border: 1px solid #a5d7ff; - box-shadow: 0px 0px 0px 4px #0d6efd40; - } - } - } - - .when-card { - .label { - margin-top: 16px; - margin-bottom: 8px; - color: $text-secondary; - } - - .start-datetime, - .end-datetime { - width: 100%; - - .effect-period-switch { - margin-bottom: 8px; - .form-check-input:not(:checked) { - background-color: $dark-bg; - border-color: $border-primary; - background-image: url("data:image/svg+xml,"); - } - } - - .datetime-picker-group { - display: flex; - - .validation-group, - .date-picker, - .time-picker { - flex: 0 1 250px; - margin-right: 16px; - } - - .date-picker, - .time-picker { - max-height: 38px; - } - - .service-time-link { - height: fit-content; - color: $text-link-primary; - padding-left: 0; - } - } - } - - .days { - .dropdown { - width: 250px; - - .dropdown-toggle { - width: 100%; - display: flex; - align-items: center; - justify-content: space-between; - } - } - - .days-form { - height: 36px; - padding-top: 8px; - margin: 0px; - margin-right: 16px; - } - } - - .dropdown-menu { - background-color: $cool-gray-30; - } - - .dropdown-item { - color: $text-primary; - &:hover, - &:focus { - background-color: $cool-gray-20; - } - - &.active { - background-color: $button-primary; - color: $text-primary; - } - - .item-value { - font-size: 16px; - } - - .item-label { - font-size: 14px; - } - } - - .interval { - width: 80px; - height: 38px; - .form-control { - padding: 7px 13px; - text-align: end; - - border: 1px solid $border-primary; - } - } - - input::-webkit-outer-spin-button, - input::-webkit-inner-spin-button { - /* display: none; <- Crashes Chrome on hover */ - -webkit-appearance: none; - margin: 0; - } - - input[type="number"] { - -moz-appearance: textfield; /* Firefox */ - appearance: textfield; - } - } - - .where-card { - .select-stations-and-zones-button-group { - display: flex; - flex-wrap: wrap; - gap: 8px; - - .add-stations-zones-button { - background-color: transparent; - color: $button-primary; - border: 1px dashed $button-primary; - width: fit-content; - height: fit-content; - } - } - } - - .message-card { - .copy-button-col { - margin-top: 141px; - - .copy-text-button { - background-color: $bg-border-disabled; - width: 38px; - height: 38px; - - &:focus { - border: 1px solid #a5d7ff; - box-shadow: 0px 0px 0px 4px #0d6efd40; - } - - .bi-arrow-right-short { - fill: $text-disabled; - } - } - } - - .text-input { - height: 250px; - resize: none; - } - - .audio-reviewed-text { - color: $text-primary; - margin-top: auto; - margin-bottom: auto; - align-self: center; - - span { - vertical-align: middle; - margin-right: 16px; - } - } - - .review-audio-button { - color: $button-primary; - margin: auto; - padding: 0; - height: fit-content; - width: fit-content; - - .bi { - margin-right: 8px; - } - - &:focus { - box-shadow: 0px 0px 0px 4px #8ecdff80; - } - - &--audio-playing { - color: $text-primary; - text-decoration: none; - } - - &:disabled { - color: $text-secondary; - text-decoration: none; - } - } - - .review-audio-card { - height: 250px; - background-color: $cool-gray-15; - } - - .message-text-box { - &:not(:only-child) { - margin-bottom: 8px; - } - } - } - - .unassociated-alert-header { - margin-top: 40px; - font-size: 20px; - font-weight: 500; - - button { - font-size: 20px; - margin-bottom: 14px; - } - } - - .associated-alert-header { - margin: 40px 0px 0px 16px; - font-size: 20px; - font-weight: 500; - - button { - color: $text-secondary; - margin-left: 16px; - margin-bottom: 6px; - width: auto; - padding: 0px; - height: 24px; - } - - .effect-period, - .alert-ended { - margin-top: 4px; - font-size: 14px; - font-weight: 400; - width: 100%; - } - - .alert-ended { - color: $text-error; - } - } - - .associate-alert-button { - color: $text-link-primary; - font-family: Inter; - font-size: 20; - font-weight: 500; - height: 30px; - margin-bottom: 8px; - } - - .unassociated-alert-header { - margin-top: 40px; - font-size: 20px; - font-weight: 500; - - button { - font-size: 20px; - margin-bottom: 14px; - } - } - - .associated-alert-header { - margin: 40px 0px 0px 16px; - font-size: 20px; - font-weight: 500; - - button { - color: $text-secondary; - margin-left: 16px; - margin-bottom: 6px; - width: auto; - padding: 0px; - height: 24px; - } - - .effect-period { - margin-top: 4px; - font-size: 14px; - font-weight: 400; - width: 100%; - } - } - - .associate-alert-button { - color: $text-link-primary; - font-family: Inter; - font-size: 20; - font-weight: 500; - height: 30px; - margin-bottom: 8px; - } - - input[type="time"], - input[type="date"] { - position: relative; - &::-webkit-calendar-picker-indicator { - filter: invert(0.75); - - position: absolute; - right: 0; - margin-right: 8px; - color: $text-secondary; - } - } -} diff --git a/assets/css/dashboard/new-pa-message/new-pa-message.scss b/assets/css/dashboard/new-pa-message/new-pa-message.scss index accf012f9..6d28f77e5 100644 --- a/assets/css/dashboard/new-pa-message/new-pa-message.scss +++ b/assets/css/dashboard/new-pa-message/new-pa-message.scss @@ -1,4 +1,3 @@ -@import "./new-pa-message-page.scss"; @import "./select-stations-page.scss"; @import "./selected-stations-summary.scss"; @import "./select-zones-page.scss"; diff --git a/assets/css/pa-messages.module.scss b/assets/css/pa-messages.module.scss new file mode 100644 index 000000000..1fe5ea656 --- /dev/null +++ b/assets/css/pa-messages.module.scss @@ -0,0 +1,204 @@ +@import "./variables.scss"; + +@mixin flat-button { + --bs-btn-active-color: var(--bs-btn-color); + --bs-btn-hover-color: var(--bs-btn-color); + --bs-btn-active-bg: var(--bs-btn-bg); + --bs-btn-hover-bg: var(--bs-btn-bg); + --bs-btn-active-border-color: var(--bs-btn-border-color); + --bs-btn-hover-border-color: var(--bs-btn-border-color); +} + +.editPage { + padding: 24px 40px; + max-width: 900px; +} + +.associateAlertSubtext { + color: $text-secondary; +} + +.formButtons { + padding: 18px 24px; +} + +.formButton { + --bs-btn-focus-box-shadow: 0px 0px 0px 4px #8ecdff80; +} + +.card { + margin-top: 24px; + padding: 18px 24px; + background-color: $cool-gray-20; + color: white; +} + +.cardTitle { + margin-bottom: 16px; + font-weight: 500; + font-size: 24px; +} + +.formLabel { + margin-top: 16px; + margin-bottom: 8px; + color: $text-secondary; +} + +.larger { + font-size: 20px; + font-weight: 500; +} + +.smaller { + font-size: 14px; +} + +.alertHeader { + margin-top: 40px; +} + +.alertEndedText { + color: $text-error; +} + +.associateAlertButton { + @include flat-button; + --bs-btn-color: #{$text-link-primary}; + font-size: 20px; + font-weight: 500; + padding-left: 0; +} + +.copyTextButton { + width: 38px; + height: 38px; + --bs-btn-color: #{$text-disabled}; + --bs-btn-active-color: var(--bs-btn-color); + --bs-btn-hover-color: var(--bs-btn-color); + --bs-btn-bg: #{$bg-border-disabled}; + --bs-btn-active-bg: var(--bs-btn-bg); + --bs-btn-hover-bg: var(--bs-btn-bg); + --bs-btn-focus-box-shadow: 0px 0px 0px 4px #0d6efd40; + &:focus-visible { + --bs-btn-hover-border-color: #a5d7ff; + } +} + +.copyButtonCol { + margin-top: 141px; +} + +.audioText { + height: 250px; + resize: none; +} + +.reviewAudioCard { + height: 250px; + background-color: $cool-gray-15; +} + +.clearAlertButton { + @include flat-button; + --bs-btn-color: #{$text-secondary}; + margin-left: 16px; + padding: 0px; +} + +.addStationsZonesButton { + @include flat-button; + --bs-btn-color: #{$button-primary}; + --bs-btn-bg: transparent; + --bs-btn-border-color: #{$button-primary}; + border: 1px dashed; +} + +.reviewAudioButton { + @include flat-button; + --bs-btn-color: #{$button-primary}; + margin: auto; + padding: 0; + --bs-btn-focus-box-shadow: 0px 0px 0px 4px #8ecdff80; + &.playing { + --bs-btn-color: #{$text-primary}; + text-decoration: none; + } + &:disabled { + --bs-btn-disabled-color: #{$text-secondary}; + text-decoration: none; + } +} + +.serviceTimeButton { + @include flat-button; + --bs-btn-color: #{$text-link-primary}; + padding-left: 0; +} + +.audioReviewedText { + color: $text-primary; +} + +.daysDropdown { + width: 250px; +} + +.intervalInput { + width: 80px; +} + +.inputField { + --bs-body-bg: #{$dark-bg}; + --bs-body-color: #{$text-secondary}; + --bs-border-color: #{$border-primary}; + &[type="number"] { + -moz-appearance: textfield; /* Firefox */ + appearance: textfield; + &::-webkit-outer-spin-button, + &::-webkit-inner-spin-button { + /* display: none; <- Crashes Chrome on hover */ + -webkit-appearance: none; + margin: 0; + } + } + &[type="time"], + &[type="date"] { + position: relative; + &::-webkit-calendar-picker-indicator { + filter: invert(0.75); + position: absolute; + right: 0; + margin-right: 8px; + color: $text-secondary; + } + } +} + +.startEndItem { + flex: 0 1 250px; +} + +.dropdown { + :global(.dropdown-toggle) { + @include flat-button; + --bs-btn-bg: #{$dark-bg}; + --bs-btn-color: #{$text-secondary}; + --bs-btn-border-color: #{$border-primary}; + --bs-btn-focus-box-shadow: 0px 0px 0px 4px #0d6efd40; + &:focus-visible { + --bs-btn-hover-border-color: #86b7fe; + } + } + :global(.dropdown-menu) { + --bs-dropdown-bg: #{$cool-gray-30}; + --bs-dropdown-link-color: #{$text-primary}; + --bs-dropdown-link-hover-color: #{$text-primary}; + --bs-dropdown-link-hover-bg: #{$cool-gray-20}; + --bs-dropdown-link-active-bg: #{$button-primary}; + } +} + +.switch :global(.form-check-input) { + --bs-form-switch-bg: url("data:image/svg+xml,"); +} diff --git a/assets/index.d.ts b/assets/index.d.ts index 3a51ad6d5..a4934c121 100644 --- a/assets/index.d.ts +++ b/assets/index.d.ts @@ -1,3 +1,4 @@ declare module "*.png"; declare module "*.jpg"; declare module "*.svg"; +declare module "*.module.scss"; diff --git a/assets/js/components/Dashboard/DaysPicker.tsx b/assets/js/components/Dashboard/DaysPicker.tsx index c2206040a..4cec0f888 100644 --- a/assets/js/components/Dashboard/DaysPicker.tsx +++ b/assets/js/components/Dashboard/DaysPicker.tsx @@ -1,6 +1,8 @@ import React, { useState } from "react"; import { Col, Dropdown, Form, Row } from "react-bootstrap"; import fp from "lodash/fp"; +import cx from "classnames"; +import * as paMessageStyles from "Styles/pa-messages.module.scss"; enum DayItem { All = "All days", @@ -50,12 +52,16 @@ const DaysPicker = ({ days, onChangeDays }: Props) => { return ( - + Days { if (eventKey === null) return; @@ -67,7 +73,12 @@ const DaysPicker = ({ days, onChangeDays }: Props) => { ); }} > - {dayLabel} + + {dayLabel} + {Object.values(DayItem).map((dayItem) => { return ( @@ -89,7 +100,7 @@ const DaysPicker = ({ days, onChangeDays }: Props) => { {DAYS_OF_WEEK.map(({ label, value }) => { return ( { return ( - + Interval (min) void; disabled?: boolean; + className?: string; label: string; id: string; maxLength: number; @@ -17,6 +20,7 @@ const MessageTextBox = ({ text, onChangeText, disabled, + className, label, id, maxLength, @@ -25,12 +29,12 @@ const MessageTextBox = ({ validated, }: Props) => { return ( - + {label} -
+
+
{title} {paused &&
Paused
} @@ -154,20 +155,20 @@ const MainForm = ({ navigateTo={navigateTo} setEndWithEffectPeriod={setEndWithEffectPeriod} /> - -
When
- - + +
When
+ + Start -
-
+
+
setStartDateTime( @@ -202,7 +207,7 @@ const MainForm = ({ } />
- - + + End @@ -224,7 +229,7 @@ const MainForm = ({ {associatedAlert && ( { @@ -237,10 +242,10 @@ const MainForm = ({ /> )} {!endWithEffectPeriod && endDateTime !== null && ( -
-
+
+
setEndDateTime( @@ -275,7 +284,7 @@ const MainForm = ({ } />
)} - -
Message
+ +
Message
- + - @@ -453,27 +469,31 @@ const ReviewAudioButton = ({ }: ReviewAudioButtonProps) => { const audioPlaying = audioState === AudioPreview.Playing; return audioState === AudioPreview.Reviewed ? ( -
- +
+ Audio reviewed -
) : ( @@ -496,42 +516,52 @@ const NewPaMessageHeader = ({ const formatActivePeriod = (activePeriods: ActivePeriod[]) => { const [start, end] = getAlertEarliestStartLatestEnd(activePeriods); return ( -
+
Alert effect period: {start} – {end}
); }; return associatedAlert ? ( - -
- Associated Alert: Alert ID{" "} - {typeof associatedAlert === "string" - ? associatedAlert - : associatedAlert.id} + <> +
+ + Associated Alert: Alert ID{" "} + {typeof associatedAlert === "string" + ? associatedAlert + : associatedAlert.id} + - {typeof associatedAlert === "string" ? ( -
- Alert has ended and is no longer available. -
- ) : ( - formatActivePeriod(associatedAlert.active_period) - )}
- + {typeof associatedAlert === "string" ? ( +
+ Alert has ended and is no longer available. +
+ ) : ( + formatActivePeriod(associatedAlert.active_period) + )} + ) : ( <> - +
- (Optional) - - -
- Linking will allow you to share end time with alert, and import - location and message. -
-
+ (Optional) +
+
+ Linking will allow you to share end time with alert, and import location + and message. +
); }; diff --git a/assets/js/components/Dashboard/PriorityPicker.tsx b/assets/js/components/Dashboard/PriorityPicker.tsx index e083cb3c3..b1ef2a0ca 100644 --- a/assets/js/components/Dashboard/PriorityPicker.tsx +++ b/assets/js/components/Dashboard/PriorityPicker.tsx @@ -1,5 +1,6 @@ import React from "react"; import { Dropdown, Form, Row } from "react-bootstrap"; +import * as paMessageStyles from "Styles/pa-messages.module.scss"; interface Props { priority: number; @@ -8,11 +9,17 @@ interface Props { const PriorityPicker = ({ priority, onSelectPriority }: Props) => { return ( - + Priority - onSelectPriority(Number(eventKey))}> + onSelectPriority(Number(eventKey))} + > {priority} {[ @@ -30,8 +37,8 @@ const PriorityPicker = ({ priority, onSelectPriority }: Props) => { eventKey={priorityIndex} active={priority === priorityIndex} > -
{priorityIndex}
-
{label}
+
{priorityIndex}
+
{label}
); })} diff --git a/assets/tsconfig.json b/assets/tsconfig.json index a5fab6968..df8647006 100644 --- a/assets/tsconfig.json +++ b/assets/tsconfig.json @@ -52,6 +52,7 @@ "Models/*": ["models/*"], "Utils/*": ["utils/*"], "Constants/*": ["constants/*"], + "Styles/*": ["../css/*"], }, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ diff --git a/assets/webpack.config.js b/assets/webpack.config.js index 8e040a93f..5d5fd69c0 100644 --- a/assets/webpack.config.js +++ b/assets/webpack.config.js @@ -62,6 +62,7 @@ module.exports = (env, options) => ({ Models: path.resolve(__dirname, "js/models"), Utils: path.resolve(__dirname, "js/utils"), Constants: path.resolve(__dirname, "js/constants"), + Styles: path.resolve(__dirname, "css"), // Fix issue with React JSX rutime export // https://github.com/facebook/react/issues/20235#issuecomment-732205073 // This is fixed in later versions of react so this can be removed when