From 937417480e7a6951c60cb8e1dac7c98c6ecbab13 Mon Sep 17 00:00:00 2001 From: Alex Janousek Date: Wed, 5 Nov 2025 09:24:31 -0500 Subject: [PATCH] SCSS refactor, theme cleanup --- app/assets/javascripts/activityChart.js | 14 +- app/assets/javascripts/copyToClipboard.js | 6 +- .../javascripts/modules/uswds-modules.js | 3 +- app/assets/sass/uswds/_custom-overrides.scss | 25 +++ .../uswds/_data-visualization.scss.DEPRECATED | 148 ------------------ app/assets/sass/uswds/components/_charts.scss | 20 ++- .../sass/uswds/components/_file-upload.scss | 6 +- .../sass/uswds/components/_sms-message.scss | 12 +- .../sass/uswds/components/_spreadsheet.scss | 10 +- .../sass/uswds/overrides/_typography.scss | 52 ++++++ .../sass/uswds/overrides/_usa-header.scss | 28 ++++ app/assets/sass/uswds/overrides/_usa-nav.scss | 23 +++ app/assets/sass/uswds/settings/_tokens.scss | 16 +- app/assets/sass/uswds/styles.scss | 12 ++ .../sass/uswds/utilities/_utilities.scss | 38 +++++ app/main/views/organizations.py | 8 +- app/templates/base.html | 2 +- app/templates/components/header.html | 2 +- .../templates/guidance-formatting.html | 2 +- app/templates/views/choose-account.html | 2 +- .../views/find-users/user-information.html | 2 +- app/templates/views/manage-users.html | 2 +- app/templates/views/signedout.html | 2 +- app/templates/views/templates/copy.html | 2 +- backstop.config.js | 2 +- .../views/accounts/test_choose_accounts.py | 2 +- .../views/organizations/test_organizations.py | 31 +++- tests/app/main/views/test_add_service.py | 2 +- tests/end_to_end/conftest.py | 2 +- tests/end_to_end/test_accounts_page.py | 4 +- tests/end_to_end/test_create_new_template.py | 4 +- .../test_invite_team_member_to_service.py | 4 +- ...est_send_message_from_existing_template.py | 4 +- 33 files changed, 269 insertions(+), 223 deletions(-) create mode 100644 app/assets/sass/uswds/_custom-overrides.scss delete mode 100644 app/assets/sass/uswds/_data-visualization.scss.DEPRECATED create mode 100644 app/assets/sass/uswds/overrides/_typography.scss create mode 100644 app/assets/sass/uswds/overrides/_usa-nav.scss create mode 100644 app/assets/sass/uswds/utilities/_utilities.scss diff --git a/app/assets/javascripts/activityChart.js b/app/assets/javascripts/activityChart.js index 61e320b9e..533985bdf 100644 --- a/app/assets/javascripts/activityChart.js +++ b/app/assets/javascripts/activityChart.js @@ -228,9 +228,9 @@ var userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone; - var url = type === 'service' - ? `/services/${currentServiceId}/daily-stats.json?timezone=${encodeURIComponent(userTimezone)}` - : `/services/${currentServiceId}/daily-stats-by-user.json?timezone=${encodeURIComponent(userTimezone)}`; + var url = (type === 'service' ? + `/services/${currentServiceId}/daily-stats.json?timezone=${encodeURIComponent(userTimezone)}` : + `/services/${currentServiceId}/daily-stats-by-user.json?timezone=${encodeURIComponent(userTimezone)}`); try { const response = await fetch(url); @@ -292,20 +292,20 @@ } }; - function startPolling() { + var startPolling = function() { fetchData(currentType); pollInterval = setInterval(() => { fetchData(currentType); }, POLL_INTERVAL_MS); - } + }; - function stopPolling() { + var stopPolling = function() { if (pollInterval) { clearInterval(pollInterval); pollInterval = null; } - } + }; document.addEventListener('visibilitychange', () => { if (document.hidden) { diff --git a/app/assets/javascripts/copyToClipboard.js b/app/assets/javascripts/copyToClipboard.js index c4d10b4f7..39d668892 100644 --- a/app/assets/javascripts/copyToClipboard.js +++ b/app/assets/javascripts/copyToClipboard.js @@ -28,9 +28,9 @@ // Determine button label const isMultiple = name !== thing; - const buttonLabel = isMultiple - ? `Copy ${thing}` - : `Copy ${thing} to clipboard`; + const buttonLabel = (isMultiple ? + `Copy ${thing}` : + `Copy ${thing} to clipboard`); const srSuffix = isMultiple ? ` for ${name}` : ''; // Create simple HTML structure diff --git a/app/assets/javascripts/modules/uswds-modules.js b/app/assets/javascripts/modules/uswds-modules.js index 0274eee41..a39e5eb59 100644 --- a/app/assets/javascripts/modules/uswds-modules.js +++ b/app/assets/javascripts/modules/uswds-modules.js @@ -27,10 +27,11 @@ var modules = this.find(container); for (var i = 0, l = modules.length; i < l; i++) { + var type; try { var module; var element = modules[i]; - var type = this.camelCaseAndCapitalise(element.dataset.module); + type = this.camelCaseAndCapitalise(element.dataset.module); var started = element.dataset.moduleStarted; if (typeof window.NotifyModules[type] === 'function' && !started) { diff --git a/app/assets/sass/uswds/_custom-overrides.scss b/app/assets/sass/uswds/_custom-overrides.scss new file mode 100644 index 000000000..3b55c6131 --- /dev/null +++ b/app/assets/sass/uswds/_custom-overrides.scss @@ -0,0 +1,25 @@ +@use 'uswds-core' as *; +.usa-banner__header-action { + font-size: size('body', 2); +} + +.usa-nav__primary > .usa-nav__primary-item > a.usa-nav__link { + font-weight: 400; +} + +h1 { + font-weight: bold; +} + +.usa-section--dark h1 { + color: color('blue-30v'); + @include at-media-max('desktop') { + font-size: size('body', 12); + } +} + +p, +.list li { + font-family: family('sans'); + font-size: size('body', 6); +} diff --git a/app/assets/sass/uswds/_data-visualization.scss.DEPRECATED b/app/assets/sass/uswds/_data-visualization.scss.DEPRECATED deleted file mode 100644 index 8cb9b1cdd..000000000 --- a/app/assets/sass/uswds/_data-visualization.scss.DEPRECATED +++ /dev/null @@ -1,148 +0,0 @@ -@use "uswds-core" as *; - -$delivered: color('blue-50v'); -$pending: color('green-cool-40v'); -$failed: color('gray-cool-20'); - -.chart-container { - display: flex; - &.usage { - height: units(4); - } - svg { - overflow: visible; - } -} - -#totalMessageChartContainer { - max-width: 600px; -} - -.bar { - border-radius: units(0.5); - &.delivered, &.usage { - background-color: $delivered; - margin-right: 1px; - } - &.pending{ - background-color: $pending; - margin-right: 1px; - } - &.failed, &.remaining { - background-color: $failed; - } -} - -.legend { - display: flex; - margin: units(1) 0; - .legend-item { - display: flex; - align-items: flex-start; - margin-right: units(2); - } - .legend-color { - width: units(3); - height: units(3); - margin-right: 0; - padding: 0; - border-radius: 2px; - background-color: $delivered; - &.pending { - background-color: $pending; - } - &.failed, &.remaining { - background-color: $failed; - } - } - .legend-value { - margin: 0 units(1); - } -} - -.progress-bar { - width: 300px; - height: 20px; - background-color: #eee; - border-radius: 5px; - margin-bottom: 10px; -} - -.progress-bar-inner { - height: 100%; - background-color: #007bff; - border-radius: inherit; -} - -.chart { - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; -} - -.chart-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: units(1) units(1) 0; -} - -.chart-subtitle { - font-size: size("body", 6); - font-weight: bold; - text-align: left; - width: 100%; - padding: 0; - margin: 0; -} - -.axis text { - font-size: size("body", 1); -} - -.axis line, -.axis path { - shape-rendering: crispEdges; - stroke: #000; - fill: none; -} - -.bar { - fill-opacity: 0.8; -} - -.chart-container { - width: 100%; - position: relative; -} - -.chart-legend { - display: flex; - align-items: center; -} - -.legend-item { - display: flex; - align-items: center; - margin-right: units(2); - .legend-rect { - width: units(2); - height: units(2); - margin-right: units(1); - } -} - -#tooltip { - position: absolute; - display: none; - background: color('ink'); - color: #FFF; - border: 1px solid #ccc; - padding: units(1); - border-radius: units(1); - pointer-events: none; - z-index: 100; - font-size: size("body", 3); - line-height: 1.3; -} diff --git a/app/assets/sass/uswds/components/_charts.scss b/app/assets/sass/uswds/components/_charts.scss index dfec9a22b..8d41c6040 100644 --- a/app/assets/sass/uswds/components/_charts.scss +++ b/app/assets/sass/uswds/components/_charts.scss @@ -4,7 +4,7 @@ display: flex; &.usage { - height: units(4); + height: units(5); } svg { @@ -17,7 +17,7 @@ } .bar { - border-radius: units(0.5); + border-radius: units(1); &.delivered, &.usage { @@ -42,12 +42,6 @@ display: flex; margin: units(1) 0; - .legend-item { - display: flex; - align-items: flex-start; - margin-right: units(2); - } - .legend-color { width: units(3); height: units(3); @@ -88,10 +82,14 @@ } } +.legend .legend-item { + align-items: flex-start; +} + .progress-bar { - width: 300px; - height: 20px; // Specific design requirement - background-color: color('gray-5'); + width: units('card'); + height: units(3); // Specific design requirement + background-color: color('gray-cool-5'); border-radius: units(1); margin-bottom: units(2); } diff --git a/app/assets/sass/uswds/components/_file-upload.scss b/app/assets/sass/uswds/components/_file-upload.scss index 5c73d28df..575c03039 100644 --- a/app/assets/sass/uswds/components/_file-upload.scss +++ b/app/assets/sass/uswds/components/_file-upload.scss @@ -26,7 +26,7 @@ &-alternate-link { display: inline-block; - line-height: 35px; // Specific design requirement + line-height: units(4); // Specific design requirement a { font-weight: bold; @@ -36,10 +36,10 @@ .page-footer { position: relative; - margin-bottom: 30px; // Specific design requirement + margin-bottom: units(4); // Specific design requirement &-link { - line-height: 40px; // Specific design requirement + line-height: units(5); // Specific design requirement padding: 1px 0 0 units(2); font-weight: normal; diff --git a/app/assets/sass/uswds/components/_sms-message.scss b/app/assets/sass/uswds/components/_sms-message.scss index 6c1215b90..a8dc63434 100644 --- a/app/assets/sass/uswds/components/_sms-message.scss +++ b/app/assets/sass/uswds/components/_sms-message.scss @@ -9,7 +9,7 @@ padding: units(2); background: color('gray-cool-10'); border: 1px solid color('gray-cool-10'); - border-radius: units(0.5); + border-radius: units(1); white-space: normal; margin: 0 0 units(1) 0; clear: both; @@ -49,17 +49,17 @@ .sms-message-file-name, .sms-message-scheduler, .sms-message-template { - margin: units(0.5) 0 0; + margin: units(1) 0 0; } .sms-message-recipient { color: color('gray-cool-90'); - margin: units(0.5) 0 units(2); + margin: units(1) 0 units(2); } .sms-message-status { color: color('gray-cool-90'); - margin: -20px units(1) 20px units(1); // Specific spacing requirement + margin: units('neg-205') units(1) units('205') units(1); // Specific spacing requirement } .sms-message-status-outbound { @@ -67,7 +67,7 @@ } h2.sms-message-header { - margin-bottom: units(0.5); + margin-bottom: units(1); } .usa-prose > * + h2.message-header { @@ -75,7 +75,7 @@ h2.sms-message-header { } h2.recipient-list { - margin-bottom: units(0.5); + margin-bottom: units(1); } .sms-message-row { diff --git a/app/assets/sass/uswds/components/_spreadsheet.scss b/app/assets/sass/uswds/components/_spreadsheet.scss index 32d0f2ef6..3bd2843e4 100644 --- a/app/assets/sass/uswds/components/_spreadsheet.scss +++ b/app/assets/sass/uswds/components/_spreadsheet.scss @@ -28,7 +28,7 @@ td { border-top: 0; - min-width: $spreadsheet-column-width - $spreadsheet-column-padding; + min-width: calc(#{$spreadsheet-column-width} - #{$spreadsheet-column-padding}); &:first-child { min-width: auto; @@ -76,7 +76,7 @@ position: absolute; top: 0; right: 0; - width: units(0.5); + width: units(1); height: 100%; z-index: $z-index-fullscreen-shadow; @@ -153,7 +153,7 @@ } &-scrolled-table { - padding-bottom: 20px; // Specific design requirement + padding-bottom: units(3); // Specific design requirement .table-field-heading-first, .table-field-index { @@ -168,11 +168,11 @@ width: 100%; position: relative; z-index: 9; - margin-bottom: 30px; // Specific design requirement + margin-bottom: units(4); // Specific design requirement pointer-events: none; & + .table-show-more-link { - margin-top: -20px; // Specific design requirement + margin-top: units('neg-3'); // Specific design requirement } } } diff --git a/app/assets/sass/uswds/overrides/_typography.scss b/app/assets/sass/uswds/overrides/_typography.scss new file mode 100644 index 000000000..51f101d8f --- /dev/null +++ b/app/assets/sass/uswds/overrides/_typography.scss @@ -0,0 +1,52 @@ +@use 'uswds-core' as *; +.usa-banner__header-action { + font-size: size('body', 2); +} + +.usa-nav__primary > .usa-nav__primary-item > a.usa-nav__link { + font-size: size('body', 5); + cursor: pointer; + font-weight: 400; +} +h1 { + font-weight: bold; +} + +.usa-section--dark h1 { + color: color('blue-30v'); + @include at-media-max('desktop') { + font-size: size('body', 12); + } +} + +p, +.list li { + font-family: family('sans'); + font-size: size('body', 6); +} + +.large-number { + font-size: size('body', 16); +} + +.template-footer .usa-link, +.template-content-count, +.table-empty-message, +td.table-empty-message { + font-size: size('body', 'sm'); +} + +.textbox-highlight-background, +.textbox-highlight-foreground, +.textbox-highlight-mask, +.textbox-highlight-textbox { + font-size: units(2); + line-height: 1.2; + padding: units(1); + font-family: family('sans'); +} + +.hint { + font-size: size('body', 'sm'); + font-weight: normal; +} diff --git a/app/assets/sass/uswds/overrides/_usa-header.scss b/app/assets/sass/uswds/overrides/_usa-header.scss index 6d50b4386..a2f7af48a 100644 --- a/app/assets/sass/uswds/overrides/_usa-header.scss +++ b/app/assets/sass/uswds/overrides/_usa-header.scss @@ -1,5 +1,33 @@ @use 'uswds-core' as *; +// Fix nav container to maintain content width but extend border +.usa-header--extended { + .usa-nav { + @include at-media('desktop') { + border-top: 1px solid color('gray-cool-10'); + position: relative; + + // Extend border beyond container + &::before { + content: ""; + position: absolute; + top: -1px; + left: 50%; + transform: translateX(-50%); + width: 100vw; + height: 1px; + background-color: color('gray-cool-10'); + z-index: -1; + } + } + } + + .usa-nav-container { + max-width: 100%; + padding: 0; + } +} + .usa-header--extended .usa-logo { font-family: family('sans'); margin: units(3) 0; diff --git a/app/assets/sass/uswds/overrides/_usa-nav.scss b/app/assets/sass/uswds/overrides/_usa-nav.scss new file mode 100644 index 000000000..7cdcd26ce --- /dev/null +++ b/app/assets/sass/uswds/overrides/_usa-nav.scss @@ -0,0 +1,23 @@ +@use 'uswds-core' as *; + +.usa-nav__primary { + & > .usa-nav__primary-item > a { + font-size: size('body', 5); + cursor: pointer; + + @include at-media('desktop') { + line-height: 1; + padding: units(2); + align-items: center; + color: color('gray-cool-60'); + display: flex; + } + } + + & > .usa-nav__primary-item { + @include at-media('desktop') { + font-size: size('body', 3); + line-height: 1; + } + } +} diff --git a/app/assets/sass/uswds/settings/_tokens.scss b/app/assets/sass/uswds/settings/_tokens.scss index 1264a4c58..cc86fd5f1 100644 --- a/app/assets/sass/uswds/settings/_tokens.scss +++ b/app/assets/sass/uswds/settings/_tokens.scss @@ -14,15 +14,15 @@ $z-index-fullscreen-header: 200; $z-index-spreadsheet-fixed: 1000; // SMS message bubbles -$sms-bubble-max-width: 464px; -$sms-bubble-arrow-size: 10px; -$sms-bubble-arrow-width: 13px; -$sms-bubble-arrow-offset: 20px; +$sms-bubble-max-width: units('mobile'); // ~464px +$sms-bubble-arrow-size: units('105'); // ~10px +$sms-bubble-arrow-width: units(2); // ~13px +$sms-bubble-arrow-offset: units('205'); // ~20px $sms-bubble-arrow-rotation: 17deg; // Spreadsheet viewer -$spreadsheet-column-width: 194px; -$spreadsheet-column-padding: 11px; -$spreadsheet-scrollbar-height: 11px; +$spreadsheet-column-width: 194px; // Keep as pixels for specific layout requirement +$spreadsheet-column-padding: 16px; // Keep as pixels for calc compatibility +$spreadsheet-scrollbar-height: units(2); // ~11px $spreadsheet-scrollbar-thumb-radius: units(1); -$spreadsheet-scrollbar-border: 2px; +$spreadsheet-scrollbar-border: 2px; // Keep as pixels for webkit scrollbar diff --git a/app/assets/sass/uswds/styles.scss b/app/assets/sass/uswds/styles.scss index e95ebe204..009e3cc68 100644 --- a/app/assets/sass/uswds/styles.scss +++ b/app/assets/sass/uswds/styles.scss @@ -1,15 +1,27 @@ +// Load USWDS theme configuration first @forward "uswds-theme"; +// Then load USWDS which will use the theme settings @forward "uswds"; +// Custom tokens @forward "settings/tokens"; +// Components @forward "components/sms-message"; @forward "components/file-upload"; @forward "components/spreadsheet"; @forward "components/charts"; +// Utilities +@forward "utilities/utilities"; + // USWDS overrides +@forward "overrides/typography"; @forward "overrides/usa-header"; +@forward "overrides/usa-nav"; @forward "overrides/usa-search"; @forward "overrides/modal"; + +// Custom overrides that MUST come last to override USWDS defaults +@use "custom-overrides"; diff --git a/app/assets/sass/uswds/utilities/_utilities.scss b/app/assets/sass/uswds/utilities/_utilities.scss new file mode 100644 index 000000000..6d58ebe4d --- /dev/null +++ b/app/assets/sass/uswds/utilities/_utilities.scss @@ -0,0 +1,38 @@ +@use 'uswds-core' as *; + +// Utility classes to replace inline styles +.text-error { + color: color('red-60v'); +} + +.width-half { + width: 50%; +} + +.width-quarter { + width: 25%; +} + +.no-js-toggle { + display: none; + + .no-js & { + display: block; + } +} + +.js-enabled-toggle { + display: none; + + .js-enabled & { + display: block; + } +} + +.visibility-hidden { + visibility: hidden; +} + +.text-spaced { + letter-spacing: 1px; +} diff --git a/app/main/views/organizations.py b/app/main/views/organizations.py index 51c8cb3fb..3e17937d3 100644 --- a/app/main/views/organizations.py +++ b/app/main/views/organizations.py @@ -78,7 +78,9 @@ def get_organization_message_allowance(org_id): def get_services_dashboard_data(organization, year): try: - dashboard_data = organizations_client.get_organization_dashboard(organization.id, year) + dashboard_data = organizations_client.get_organization_dashboard( + organization.id, year + ) services = dashboard_data.get("services", []) except Exception as e: current_app.logger.error(f"Error fetching dashboard data: {e}") @@ -100,7 +102,9 @@ def get_services_dashboard_data(organization, year): usage_parts.append(f"{emails_sent:,} emails") if sms_sent > 0 or sms_remainder > 0: if sms_cost > 0: - usage_parts.append(f"{sms_sent:,} sms ({sms_remainder:,} remaining, ${sms_cost:,.2f})") + usage_parts.append( + f"{sms_sent:,} sms ({sms_remainder:,} remaining, ${sms_cost:,.2f})" + ) else: usage_parts.append(f"{sms_sent:,} sms ({sms_remainder:,} remaining)") diff --git a/app/templates/base.html b/app/templates/base.html index 802881363..3e4c07916 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -21,7 +21,7 @@ {% block bodyStart %} {% block extra_javascripts_before_body %} + height="0" width="0" class="display-none visibility-hidden"> {% endblock %} {% endblock %} diff --git a/app/templates/components/header.html b/app/templates/components/header.html index 36082c11b..5d7acdc7c 100644 --- a/app/templates/components/header.html +++ b/app/templates/components/header.html @@ -62,7 +62,7 @@ {% endif %} {% endfor %} -
+