diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c7af572bd0..fe1ff5ee72 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -33,7 +33,7 @@ jobs: with: eslint: true prettier: true - auto_fix: true + auto_fix: false - name: Run separate lint command run: yarn lint diff --git a/backend/core/src/auth/services/user.service.spec.ts b/backend/core/src/auth/services/user.service.spec.ts index 60378860a8..f2973d0d38 100644 --- a/backend/core/src/auth/services/user.service.spec.ts +++ b/backend/core/src/auth/services/user.service.spec.ts @@ -258,11 +258,9 @@ describe("UserService", () => { }) describe("forgotPassword", () => { - it("should return 400 if email is not found", async () => { + it("should return undefined if email is not found", async () => { mockUserRepo.findOne = jest.fn().mockResolvedValue(null) - await expect(service.forgotPassword({ email: "abc@xyz.com" })).rejects.toThrow( - new HttpException(USER_ERRORS.NOT_FOUND.message, USER_ERRORS.NOT_FOUND.status) - ) + await expect(service.forgotPassword({ email: "abc@xyz.com" })).resolves.toBeUndefined() }) it("should set resetToken", async () => { diff --git a/backend/core/src/auth/services/user.service.ts b/backend/core/src/auth/services/user.service.ts index 55fb6ba9ee..b93d89e757 100644 --- a/backend/core/src/auth/services/user.service.ts +++ b/backend/core/src/auth/services/user.service.ts @@ -436,16 +436,14 @@ export class UserService { public async forgotPassword(dto: ForgotPasswordDto) { const user = await this.findByEmail(dto.email) - if (!user) { - throw new HttpException(USER_ERRORS.NOT_FOUND.message, USER_ERRORS.NOT_FOUND.status) + if (user) { + // Token expires in 1 hour + const payload = { id: user.id, exp: Number.parseInt(dayjs().add(1, "hour").format("X")) } + user.resetToken = encode(payload, process.env.APP_SECRET) + await this.userRepository.save(user) + await this.emailService.forgotPassword(user, dto.appUrl) + return user } - - // Token expires in 1 hour - const payload = { id: user.id, exp: Number.parseInt(dayjs().add(1, "hour").format("X")) } - user.resetToken = encode(payload, process.env.APP_SECRET) - await this.userRepository.save(user) - await this.emailService.forgotPassword(user, dto.appUrl) - return user } public async updatePassword(dto: UpdatePasswordDto) { diff --git a/detroit-ui-components/index.ts b/detroit-ui-components/index.ts index f1b9bb90bb..16ba8c32f3 100644 --- a/detroit-ui-components/index.ts +++ b/detroit-ui-components/index.ts @@ -22,7 +22,6 @@ export * from "./src/global/vendor/AgPagination" /* Headers */ export * from "./src/headers/Hero" export * from "./src/headers/PageHeader" -export * from "./src/headers/SiteHeader" export * from "./src/headers/Heading" export * from "./src/headers/HeadingGroup" export * from "./src/headers/StepHeader" diff --git a/detroit-ui-components/package.json b/detroit-ui-components/package.json index cf746c3f01..11654787db 100644 --- a/detroit-ui-components/package.json +++ b/detroit-ui-components/package.json @@ -72,7 +72,7 @@ }, "dependencies": { "@bloom-housing/backend-core": "^4.4.0", - "@bloom-housing/ui-components": "^8.0.0", + "@bloom-housing/ui-components": "^8.2.0", "@bloom-housing/shared-helpers": "^4.4.0", "@fortawesome/fontawesome-svg-core": "^6.1.1", "@fortawesome/free-regular-svg-icons": "^6.1.1", diff --git a/detroit-ui-components/src/global/tokens/sizes.scss b/detroit-ui-components/src/global/tokens/sizes.scss index 268c0f7c4a..70a1c28914 100644 --- a/detroit-ui-components/src/global/tokens/sizes.scss +++ b/detroit-ui-components/src/global/tokens/sizes.scss @@ -5,7 +5,7 @@ --bloom-s2: 0.5rem; --bloom-s2_5: 0.625rem; --bloom-s3: 0.75rem; - --bloom-s3_5: 0.875; + --bloom-s3_5: 0.875rem; --bloom-s4: 1rem; --bloom-s5: 1.25rem; --bloom-s6: 1.5rem; diff --git a/detroit-ui-components/src/headers/PageHeader.scss b/detroit-ui-components/src/headers/PageHeader.scss index 158eea8990..e5d9834f30 100644 --- a/detroit-ui-components/src/headers/PageHeader.scss +++ b/detroit-ui-components/src/headers/PageHeader.scss @@ -49,6 +49,7 @@ font-size: var(--title-font-size); text-align: left; } + word-break: break-word; } .page-header__lead { diff --git a/detroit-ui-components/src/headers/SiteHeader.scss b/detroit-ui-components/src/headers/SiteHeader.scss deleted file mode 100644 index 8afc8af221..0000000000 --- a/detroit-ui-components/src/headers/SiteHeader.scss +++ /dev/null @@ -1,398 +0,0 @@ -.site-header { - .navbar-mobile-dropdown-container { - background-color: white; - .navbar-mobile-dropdown { - @apply border-b; - @apply border-gray-450; - @apply w-full; - @apply flex; - @apply flex-col; - .navbar-mobile-dropdown-item { - @apply w-full; - @apply flex; - @apply text-gray-750; - @apply pt-3; - @apply pb-3; - @apply pl-4; - @apply pr-4; - @apply border-t; - @apply border-gray-450; - font-size: 14px; - &:hover, - &:focus { - @apply bg-gray-400; - } - } - - .navbar-mobile-dropdown-item-sublink { - @apply pl-8; - } - } - } - - .navbar-mobile-drawer-dropdown-container { - position: fixed; - top: 0; - right: 0; - background-color: white; - z-index: 10; - @apply h-full; - .navbar-mobile-drawer-dropdown { - @apply border-b; - @apply border-gray-450; - @apply w-full; - @apply flex; - @apply flex-col; - - .navbar-mobile-drawer-close-row { - @apply bg-primary; - @apply pt-3; - @apply pb-3; - @apply pr-2; - @apply pl-2; - @apply flex; - } - - .navbar-mobile-drawer-dropdown-item { - @apply flex; - @apply text-gray-750; - @apply pt-3; - @apply pb-3; - @apply pl-4; - @apply pr-24; - @apply border-t; - @apply border-l; - @apply border-gray-450; - font-size: 14px; - @apply w-full; - &:hover, - &:focus { - @apply bg-gray-400; - } - } - - .navbar-mobile-drawer-dropdown-item-sublink { - @apply pl-8; - @apply pr-2; - } - } - } - - .navbar-container { - display: flex; - @apply w-full; - align-items: center; - justify-content: center; - - .navbar-width-base { - width: 1025px; - } - - .navbar-width-wide { - width: 1230px; - } - - .navbar { - height: 75px; - max-height: 75px; - display: flex; - flex-direction: row; - justify-content: space-between; - z-index: 10; - max-width: 100%; - - .navbar-logo { - min-width: fit-content; - @apply flex; - @apply items-center; - justify-content: center; - flex-grow: 1; - @screen md { - flex-shrink: 0; - flex-grow: initial; - } - - .logo { - @apply cursor-pointer; - @apply text-black; - @apply block; - @apply text-center; - @apply z-10; - width: 100%; - height: 95%; - display: flex; - align-items: center; - justify-content: center; - - .logo-content { - @apply p-1; - } - - .navbar-image-only-container { - @apply p-0; - width: 100%; - height: 100%; - // 75px - .5rem of padding from the container around it - @screen md { - height: 67px; - height: 120px; - display: flex; - justify-content: center; - align-items: center; - img { - margin: 0; - } - } - .navbar-image-only { - max-height: 90%; - max-width: 100%; - } - } - - @screen md { - height: 120px; - box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.25); - margin-bottom: -0.75rem; - margin-top: -2.4rem; - @apply pt-1; - @apply pb-1; - @apply pl-3; - @apply pr-3; - - &:focus { - box-shadow: 0 0 3px 4px $tailwind-accent-cool; - } - } - - @screen print { - margin-top: 0; - } - - @apply bg-white; - @apply border-b-0; - - @apply flex; - - .logo__image { - @apply inline-block; - @apply mt-0; - @apply mb-1; - max-height: 1.5rem; - @apply hidden; - - @screen md { - @apply mt-0; - @apply mb-2; - max-height: 2rem; - @apply inline-block; - } - } - - .logo__title { - @apply uppercase; - @apply font-bold; - @apply text-gray-900; - @apply font-alt-sans; - @apply tracking-wider; - @apply text-sm; - - @screen md { - @apply text-tiny; - } - } - } - - .navbar-custom-width { - @screen md { - @apply flex; - @apply items-center; - @apply justify-center; - @apply flex-col; - } - } - } - - .navbar-menu { - @apply flex; - justify-content: flex-end; - min-width: 110px; - - @screen md { - height: 75px; - } - - .navbar-mobile-menu-button { - @apply relative; - @apply rounded; - @apply px-2; - @apply text-lg; - @apply text-center; - @apply uppercase; - @apply font-alt-sans; - @apply inline-block; - @apply tracking-widest; - @apply text-sm; - @apply font-bold; - @apply leading-snug; - @apply border-primary; - @apply border-2; - text-decoration: none; - @apply mx-2; - } - - .navbar-dropdown-title { - flex-shrink: 0; - } - - .navbar-link { - text-transform: uppercase; - @apply text-sm; - @apply pr-3; - @apply pl-3; - @apply text-gray-750; - @apply h-full; - @apply pb-4; - @apply pt-1; - @apply flex; - @apply items-end; - border-bottom: 3px solid transparent; - - @media (min-width: 840px) { - @apply pr-4; - @apply pl-4; - } - - &:focus { - box-shadow: 0 0 3px 4px $tailwind-accent-cool; - outline: none; - } - - &:hover { - border-bottom: 3px solid; - @apply border-primary; - @apply cursor-pointer; - } - - div { - text-align: center; - } - } - - .desktop-header-button { - @apply pt-7; - border-bottom: 3px solid transparent; - } - - .navbar-dropdown-container { - background-color: white; - position: absolute; - margin-left: -127px; - margin-top: 38.5px; - @apply border-gray-450; - @apply border; - border-top: none; - width: 143px; - .navbar-dropdown { - display: flex; - flex-direction: column; - .navbar-dropdown-item { - @apply flex; - @apply flex-row; - @apply items-center; - justify-content: left; - @apply text-gray-750; - @apply pt-3; - @apply pb-3; - @apply pl-3; - @apply pr-3; - @apply border-t; - @apply border-gray-450; - @apply normal-case; - font-size: 14px; - text-align: left; - @apply w-full; - &:hover, - &:focus { - @apply bg-gray-400; - } - } - } - } - } - } - } - - .navbar-notice { - @apply w-full; - @apply bg-primary; - @screen md { - @apply text-right; - } - @apply text-left; - @apply text-white; - @apply block; - } - - .navbar-notice-hide { - display: none; - - @screen md { - display: block; - } - } - - .navbar-notice__text { - @apply max-w-5xl; - @apply text-sm; - @apply py-2; - @apply px-3; - margin: auto; - - a, - a:hover { - @apply underline; - color: inherit; - } - } -} - -.drawer-transition-enter { - transition: all 400ms; - transform: translateX(100%); -} -.drawer-transition-enter-active { - transition: all 400ms; - transform: translateX(0%); -} -.drawer-transition-exit { - transition: all 500ms; - transform: translateX(100%); -} -.drawer-transition-exit-active { - transform: translateX(100%); - transition: all 500ms; -} - -.navbar-logo-width-slim { - @screen md { - width: 100px; - } -} - -.navbar-logo-width-base { - @screen md { - width: 200px; - } -} - -.navbar-logo-width-med { - @screen md { - width: 255px; - } -} - -.navbar-logo-width-wide { - @screen md { - width: 350px; - } -} diff --git a/detroit-ui-components/src/headers/SiteHeader.stories.tsx b/detroit-ui-components/src/headers/SiteHeader.stories.tsx deleted file mode 100644 index 5c12fa883b..0000000000 --- a/detroit-ui-components/src/headers/SiteHeader.stories.tsx +++ /dev/null @@ -1,394 +0,0 @@ -import * as React from "react" - -import { SiteHeader } from "./SiteHeader" - -export default { - title: "Headers/Site Header", -} - -export const basic = () => ( - console.log("Clicked English"), active: true }]} - logoSrc="/images/logo_glyph.svg" - // notice="This is a preview of our new website. We're just getting started. We'd love to get your feedback." - title="Alameda County Housing Portal" - menuLinks={[]} - /> -) - -export const withLanguage = () => ( - console.log("Clicked English"), active: true }, - { label: "Español", onClick: () => console.log("Clicked Español"), active: false }, - { label: "中文", onClick: () => console.log("Clicked 中文"), active: false }, - ]} - languageNavLabel="Choose a Language" - logoSrc="/images/logo_glyph.svg" - title="Alameda County Housing Portal" - menuLinks={[]} - /> -) - -export const withLanguageAndMobileNotice = () => ( - console.log("Clicked English"), active: true }, - { label: "Español", onClick: () => console.log("Clicked Español"), active: false }, - { label: "中文", onClick: () => console.log("Clicked 中文"), active: false }, - ]} - noticeMobile={true} - notice="We're just getting started. We'd love to get your feedback." - logoSrc="/images/logo_glyph.svg" - title="Alameda County Housing Portal" - menuLinks={[]} - /> -) - -export const slimLogo = () => ( - console.log("Clicked English"), active: true }, - { label: "Español", onClick: () => console.log("Clicked Español"), active: false }, - { label: "中文", onClick: () => console.log("Clicked 中文"), active: false }, - ]} - logoWidth={"slim"} - notice="We're just getting started. We'd love to get your feedback." - logoSrc="/images/logo_glyph.svg" - title="Housing Portal" - menuLinks={[]} - /> -) - -export const mediumLogo = () => ( - console.log("Clicked English"), active: true }, - { label: "Español", onClick: () => console.log("Clicked Español"), active: false }, - { label: "中文", onClick: () => console.log("Clicked 中文"), active: false }, - ]} - logoWidth={"medium"} - notice="We're just getting started. We'd love to get your feedback." - logoSrc="/images/logo_glyph.svg" - title="Housing Portal" - menuLinks={[]} - /> -) - -export const wideLogo = () => ( - console.log("Clicked English"), active: true }, - { label: "Español", onClick: () => console.log("Clicked Español"), active: false }, - { label: "中文", onClick: () => console.log("Clicked 中文"), active: false }, - ]} - logoWidth={"wide"} - notice="We're just getting started. We'd love to get your feedback." - logoSrc="/images/logo_glyph.svg" - title="Housing Portal" - menuLinks={[]} - /> -) - -export const withMenuLinks = () => ( - console.log("Clicked English"), active: true }, - { label: "Español", onClick: () => console.log("Clicked Español"), active: false }, - { label: "中文", onClick: () => console.log("Clicked 中文"), active: false }, - ]} - notice="We're just getting started. We'd love to get your feedback." - logoSrc="/images/logo_glyph.svg" - title="Alameda County Housing Portal" - menuLinks={[ - { - title: "Listings", - href: "/", - }, - { - title: "Get Assistance", - href: "/", - }, - { - title: "Sign In", - href: "/", - }, - ]} - /> -) - -export const withMenuDropdowns = () => ( - console.log("Clicked English"), active: true }, - { label: "Español", onClick: () => console.log("Clicked Español"), active: false }, - { label: "中文", onClick: () => console.log("Clicked 中文"), active: false }, - ]} - notice="We're just getting started. We'd love to get your feedback." - logoSrc="/images/logo_glyph.svg" - title="Alameda County Housing Portal" - menuLinks={[ - { - title: "My Account", - subMenuLinks: [ - { - title: "My Dashboard", - href: "/account/dashboard", - }, - { - title: "My Applications", - href: "/account/dashboard", - }, - { - title: "Account Settings", - href: "/account/edit", - }, - { - title: "Sign Out", - onClick: () => {}, - }, - ], - }, - ]} - /> -) - -export const withMobileDrawer = () => ( - console.log("Clicked English"), active: true }, - { label: "Español", onClick: () => console.log("Clicked Español"), active: false }, - { label: "中文", onClick: () => console.log("Clicked 中文"), active: false }, - ]} - notice="We're just getting started. We'd love to get your feedback." - logoSrc="/images/logo_glyph.svg" - title="Alameda County Housing Portal" - menuLinks={[ - { - title: "Listings", - href: "/", - }, - { - title: "Get Assistance", - href: "/", - }, - { - title: "Sign In", - href: "/", - }, - ]} - mobileDrawer={true} - /> -) - -export const withMobileText = () => ( - console.log("Clicked English"), active: true }, - { label: "Español", onClick: () => console.log("Clicked Español"), active: false }, - { label: "中文", onClick: () => console.log("Clicked 中文"), active: false }, - ]} - mobileText={true} - notice="We're just getting started. We'd love to get your feedback." - logoSrc="/images/logo_glyph.svg" - title="Alameda County Housing Portal" - menuLinks={[ - { - title: "Listings", - href: "/", - }, - { - title: "Get Assistance", - href: "/", - }, - { - title: "Sign In", - href: "/", - }, - ]} - mobileDrawer={true} - /> -) - -export const withNoticeOnMobile = () => ( - -) - -export const withFlattenedMobileSubMenus = () => ( - console.log("Clicked English"), active: true }, - { label: "Español", onClick: () => console.log("Clicked Español"), active: false }, - { label: "中文", onClick: () => console.log("Clicked 中文"), active: false }, - ]} - flattenSubMenus={true} - notice="We're just getting started. We'd love to get your feedback." - logoSrc="/images/logo_glyph.svg" - title="Alameda County Housing Portal" - menuLinks={[ - { - title: "My Account", - subMenuLinks: [ - { - title: "My Dashboard", - href: "/account/dashboard", - }, - { - title: "My Applications", - href: "/account/dashboard", - }, - { - title: "Account Settings", - href: "/account/edit", - }, - { - title: "Sign Out", - onClick: () => {}, - }, - ], - }, - ]} - /> -) - -export const withDropdownIcons = () => ( - console.log("Clicked English"), active: true }, - { label: "Español", onClick: () => console.log("Clicked Español"), active: false }, - { label: "中文", onClick: () => console.log("Clicked 中文"), active: false }, - ]} - notice="We're just getting started. We'd love to get your feedback." - logoSrc="/images/logo_glyph.svg" - title="Alameda County Housing Portal" - dropdownItemClassName={"text-xs"} - menuLinks={[ - { - title: "My Account", - subMenuLinks: [ - { - title: "My Dashboard", - href: "/account/dashboard", - iconSrc: "https://bit.ly/2YoHrxA", - iconClassName: "w-6 pr-2", - }, - { - title: "My Applications", - href: "/account/dashboard", - iconSrc: "https://bit.ly/2YoHrxA", - iconClassName: "w-6 pr-2", - }, - { - title: "Account Settings", - href: "/account/edit", - iconSrc: "https://bit.ly/2YoHrxA", - iconClassName: "w-6 pr-2", - }, - { - title: "Sign Out", - onClick: () => {}, - iconSrc: "https://bit.ly/2YoHrxA", - iconClassName: "w-6 pr-2", - }, - ], - }, - ]} - /> -) -export const imageOnlyLogo = () => ( - console.log("Clicked English"), active: true }, - { label: "Español", onClick: () => console.log("Clicked Español"), active: false }, - { label: "中文", onClick: () => console.log("Clicked 中文"), active: false }, - ]} - imageOnly - logoWidth={"medium"} - notice="We're just getting started. We'd love to get your feedback." - logoSrc="https://bit.ly/3me4iUC" - menuLinks={[]} - /> -) - -export const DAHLIAToggleSet = () => ( - console.log("Clicked English"), active: true }, - { label: "Español", onClick: () => console.log("Clicked Español"), active: false }, - { label: "中文", onClick: () => console.log("Clicked 中文"), active: false }, - ]} - notice="We'd love to get your feedback." - noticeMobile={true} - mobileDrawer={true} - flattenSubMenus={true} - imageOnly={true} - mobileText={true} - logoWidth={"medium"} - logoSrc="https://bit.ly/3me4iUC" - dropdownItemClassName={"text-xs"} - menuLinks={[ - { - title: "Some longer links", - href: "/", - }, - { - title: "Some longer links", - href: "/", - }, - { - title: "Some longer links", - href: "/", - }, - { - title: "My Account", - subMenuLinks: [ - { - title: "My Dashboard", - href: "/account/dashboard", - iconSrc: "https://bit.ly/2YoHrxA", - iconClassName: "w-6 pr-2", - }, - { - title: "My Applications", - href: "/account/dashboard", - iconSrc: "https://bit.ly/2YoHrxA", - iconClassName: "w-6 pr-2", - }, - { - title: "Account Settings", - href: "/account/edit", - iconSrc: "https://bit.ly/2YoHrxA", - iconClassName: "w-6 pr-2", - }, - { - title: "Sign Out", - onClick: () => {}, - iconSrc: "https://bit.ly/2YoHrxA", - iconClassName: "w-6 pr-2", - }, - ], - }, - ]} - /> -) diff --git a/detroit-ui-components/src/headers/SiteHeader.tsx b/detroit-ui-components/src/headers/SiteHeader.tsx deleted file mode 100644 index 9ac61862ec..0000000000 --- a/detroit-ui-components/src/headers/SiteHeader.tsx +++ /dev/null @@ -1,470 +0,0 @@ -import React, { useState, useEffect, useContext } from "react" -import { CSSTransition } from "react-transition-group" -import { LanguageNav, LangItem } from "../navigation/LanguageNav" -import { Icon } from "../icons/Icon" -import { Button } from "../actions/Button" -import { AppearanceSizeType } from "../global/AppearanceTypes" -import { t, NavigationContext } from "@bloom-housing/ui-components" -import "./SiteHeader.scss" - -type LogoWidth = "slim" | "base" | "medium" | "wide" -type SiteHeaderWidth = "base" | "wide" - -export interface MenuLink { - href?: string - iconClassName?: string - iconSrc?: string - onClick?: () => void - subMenuLinks?: MenuLink[] - class?: string - title: string -} - -export interface SiteHeaderProps { - dropdownItemClassName?: string - homeURL: string - imageOnly?: boolean - languageNavLabel?: string - languages?: LangItem[] - logoClass?: string - logoSrc: string - logoWidth?: LogoWidth - menuItemClassName?: string - menuLinks: MenuLink[] - mobileDrawer?: boolean - mobileText?: boolean - flattenSubMenus?: boolean - notice?: string | React.ReactNode - noticeMobile?: boolean - siteHeaderWidth?: SiteHeaderWidth - title?: string - subtitle?: string - desktopMinWidth?: number -} - -const SiteHeader = (props: SiteHeaderProps) => { - const [activeMenus, setActiveMenus] = useState([]) - const [activeMobileMenus, setActiveMobileMenus] = useState([]) - const [isDesktop, setIsDesktop] = useState(true) - const [mobileDrawer, setMobileDrawer] = useState(false) - const [mobileMenu, setMobileMenu] = useState(false) - - const { LinkComponent } = useContext(NavigationContext) - - const DESKTOP_MIN_WIDTH = props.desktopMinWidth || 767 // @screen md - // Enables toggling off navbar links when entering mobile - useEffect(() => { - if (window.innerWidth > DESKTOP_MIN_WIDTH) { - setIsDesktop(true) - } else { - setIsDesktop(false) - } - - const updateMedia = () => { - if (window.innerWidth > DESKTOP_MIN_WIDTH) { - setIsDesktop(true) - } else { - setIsDesktop(false) - } - } - window.addEventListener("resize", updateMedia) - return () => window.removeEventListener("resize", updateMedia) - }, []) - - const getLogoWidthClass = () => { - if (props.logoWidth === "slim") return "navbar-logo-width-slim" - if (!props.logoWidth || props.logoWidth === "base") return "navbar-logo-width-base" - if (props.logoWidth === "medium") return "navbar-logo-width-med" - if (props.logoWidth === "wide") return "navbar-logo-width-wide" - return "" - } - - const menuAction = (menuOnClick?: () => void) => { - if (menuOnClick) { - menuOnClick() - } - } - - // Render set of styled menu links - const getDropdownOptions = ( - options: MenuLink[], - buttonClassName: string, - parentMenu?: string - ) => { - const dropdownOptionKeyDown = (event: React.KeyboardEvent, index: number) => { - // Close menu when tabbing out backwards - if (event.shiftKey && event.key === "Tab" && isDesktop && index === 0 && parentMenu) { - changeMenuShow(parentMenu, activeMenus, setActiveMenus) - } - // Close menu when tabbing out forwards - if (event.key === "Tab" && isDesktop && index === options.length - 1 && parentMenu) { - changeMenuShow(parentMenu, activeMenus, setActiveMenus) - } - } - - const dropdownOptionContent = (option: MenuLink) => { - return ( - <> - {option.iconSrc && isDesktop && ( - - )} - {option.title} - - ) - } - - const dropdownOptionClassname = `${buttonClassName} ${ - props.dropdownItemClassName ? props.dropdownItemClassName : "" - }` - - return options.map((option, index) => { - return ( -
- {option.href ? ( - { - dropdownOptionKeyDown(event, index) - }} - > - {dropdownOptionContent(option)} - - ) : ( - - )} -
- ) - }) - } - - // Render the desktop dropdown that opens on mouse hover - const getDesktopDropdown = (menuTitle: string, subMenus: MenuLink[]) => { - return ( - - {menuTitle} - - {activeMenus.indexOf(menuTitle) >= 0 && ( - -
- {getDropdownOptions(subMenus, "navbar-dropdown-item", menuTitle)} -
-
- )} -
- ) - } - - // Build styled mobile menu options - const buildMobileMenuOptions = ( - menuLinks: MenuLink[], - dropdownSublinkOptionClassName: string, - dropdownOptionClassName: string, - dropdownContainerClassName?: string - ) => { - return ( - <> - {menuLinks.map((menuLink, index) => { - if (menuLink.subMenuLinks && !props.flattenSubMenus) { - return ( -
- - {activeMobileMenus.indexOf(menuLink.title) >= 0 && ( -
- {getDropdownOptions( - menuLink.subMenuLinks, - dropdownSublinkOptionClassName ?? "" - )} -
- )} -
- ) - } else { - return ( -
- {props.flattenSubMenus && menuLink.subMenuLinks - ? getDropdownOptions(menuLink.subMenuLinks, dropdownOptionClassName ?? "") - : getDropdownOptions([menuLink], dropdownOptionClassName ?? "")} -
- ) - } - })} - - ) - } - - // Render the mobile drawer that opens on menu press when prop mobileDrawer is set - const getMobileDrawer = () => { - return ( - - -
- - {buildMobileMenuOptions( - props.menuLinks, - "navbar-mobile-drawer-dropdown-item navbar-mobile-drawer-dropdown-item-sublink", - "navbar-mobile-drawer-dropdown-item" - )} -
-
-
- ) - } - - // Renders the default mobile dropdown that opens on menu press - const getMobileDropdown = () => { - return ( - <> - {!props.mobileDrawer && ( - -
- {buildMobileMenuOptions( - props.menuLinks, - "navbar-mobile-dropdown-item navbar-mobile-dropdown-item-sublink", - "navbar-mobile-dropdown-item", - "navbar-mobile-dropdown-links" - )} -
-
- )} - - ) - } - const changeMenuShow = ( - title: string, - menus: string[], - setMenus: React.Dispatch> - ) => { - const indexOfTitle = menus.indexOf(title) - setMenus(indexOfTitle >= 0 ? menus.filter((menu) => menu !== title) : [...menus, title]) - } - - const getDesktopHeader = () => { - return ( - <> - {props.menuLinks.map((menuLink, index) => { - let menuContent: JSX.Element - if (menuLink.subMenuLinks) { - menuContent = getDesktopDropdown(menuLink.title, menuLink.subMenuLinks) - } else { - menuContent =
{menuLink.title}
- } - - if (!menuLink.subMenuLinks) { - if (menuLink.href) { - return ( - - {menuContent} - - ) - } else { - return ( - - ) - } - } else { - return ( - { - if (event.key === "Enter") { - changeMenuShow(menuLink.title, activeMenus, setActiveMenus) - } - }} - onMouseEnter={() => changeMenuShow(menuLink.title, activeMenus, setActiveMenus)} - onMouseLeave={() => changeMenuShow(menuLink.title, activeMenus, setActiveMenus)} - data-test-id={`${menuLink.title}-${index}`} - > - {menuContent} - - ) - } - })} - - ) - } - - const getMobileHeader = () => { - const mobileHeaderAction = () => { - if (!props.mobileDrawer) { - setMobileMenu(!mobileMenu) - } else { - setMobileDrawer(!mobileDrawer) - } - setActiveMobileMenus([]) - } - - return ( - <> - {props.mobileText ? ( - - ) : ( - - )} - - ) - } - - const getLogo = () => { - let titleHtml - if (props.title && props.subtitle) { - titleHtml = ( -
- {props.title} -
{props.subtitle}
-
- ) - } else if (props.title) { - titleHtml =
{props.title}
- } - - return ( -
- -
- {"Site - {props.title &&
{titleHtml}
} -
-
-
- ) - } - - return ( -
- {props.languages && ( - - )} - -
-
{props.notice ?? ""}
-
- - - {!isDesktop && mobileMenu && getMobileDropdown()} - {getMobileDrawer()} -
- ) -} - -export { SiteHeader as default, SiteHeader } diff --git a/detroit-ui-components/src/locales/ar.json b/detroit-ui-components/src/locales/ar.json index 88b70f7bff..28360d1d87 100644 --- a/detroit-ui-components/src/locales/ar.json +++ b/detroit-ui-components/src/locales/ar.json @@ -432,8 +432,8 @@ "flags.resolveFlag": "حل العلم", "flags.markedAsDuplicate": "تم وضع علامة على٪ {quantity} من التطبيقات على أنها مكررة", "authentication.forgotPassword.changePassword": "تغيير كلمة السر", + "authentication.forgotPassword.message": "إذا كان هناك حساب تم إنشاؤه باستخدام هذا البريد الإلكتروني ، فستتلقى بريدًا إلكترونيًا به ارتباط لإعادة تعيين كلمة المرور الخاصة بك.", "authentication.forgotPassword.sendEmail": "ارسل بريد الكتروني", - "authentication.forgotPassword.success": "لقد أرسلنا لك بريدًا إلكترونيًا. ستتلقى بريدًا إلكترونيًا يحتوي على رابط لإعادة تعيين كلمة المرور الخاصة بك.", "authentication.forgotPassword.errors.tokenExpired": "انتهت صلاحية رمز إعادة تعيين كلمة المرور. الرجاء طلب واحدة جديدة.", "authentication.forgotPassword.errors.tokenMissing": "لم يتم العثور على الرمز. الرجاء طلب واحدة جديدة.", "authentication.forgotPassword.errors.generic": "كان هناك خطأ. يرجى المحاولة مرة أخرى ، أو الاتصال بالدعم للمساعدة.", @@ -1155,7 +1155,6 @@ "whatToExpect.default": "سيتم الاتصال بالمتقدمين من قبل وكيل الملكية بترتيب الترتيب حتى يتم ملء الشواغر. سيتم التحقق من جميع المعلومات التي قدمتها وتأكيد أهليتك. ستتم إزالة طلبك من قائمة الانتظار إذا قدمت أي بيانات احتيالية. إذا لم نتمكن من التحقق من تفضيل السكن الذي طالبت به ، فلن تحصل على الأفضلية ولكن لن يتم معاقبتك بطريقة أخرى. إذا تم اختيار طلبك ، فكن مستعدًا لملء طلب أكثر تفصيلاً وتقديم المستندات الداعمة المطلوبة.", "listingFilters.allRentals": "جميع الإيجارات", "listingFilters.buttonTitle": "منقي", - "listingFilters.buttonTitleWithNumber": "فلتر (%{number})", "listingFilters.buttonTitleExtended": "البحث عن أماكن للإيجار لك", "listingFilters.loading": "جار التحميل...", "listingFilters.rentalsFound": "تم العثور على %{smart_count} إيجار |||| تم العثور على %{smart_count} إيجارات", diff --git a/detroit-ui-components/src/locales/bn.json b/detroit-ui-components/src/locales/bn.json index 06365f5227..b1666b3942 100644 --- a/detroit-ui-components/src/locales/bn.json +++ b/detroit-ui-components/src/locales/bn.json @@ -432,8 +432,8 @@ "flags.resolveFlag": "পতাকা সমাধান করুন", "flags.markedAsDuplicate": "%{amount} অ্যাপ্লিকেশনগুলি সদৃশ হিসাবে চিহ্নিত", "authentication.forgotPassword.changePassword": "পাসওয়ার্ড পরিবর্তন করুন", + "authentication.forgotPassword.message": "যদি সেই ইমেল দিয়ে একটি অ্যাকাউন্ট তৈরি করা হয়, তাহলে আপনি আপনার পাসওয়ার্ড রিসেট করার জন্য একটি লিঙ্ক সহ একটি ইমেল পাবেন।", "authentication.forgotPassword.sendEmail": "ইমেইল পাঠান", - "authentication.forgotPassword.success": "আমরা আপনাকে একটি ইমেল পাঠিয়েছি। আপনি আপনার পাসওয়ার্ড রিসেট করার জন্য একটি লিঙ্ক সহ একটি ইমেল পাবেন৷", "authentication.forgotPassword.errors.tokenExpired": "পাসওয়ার্ড টোকেনের মেয়াদ শেষ হয়ে গেছে। অনুগ্রহ করে নতুনের জন্য অনুরোধ করুন।", "authentication.forgotPassword.errors.tokenMissing": "টোকেন পাওয়া যায়নি। অনুগ্রহ করে নতুনের জন্য অনুরোধ করুন।", "authentication.forgotPassword.errors.generic": "সেখানে একটা ভুল ছিল. অনুগ্রহ করে আবার চেষ্টা করুন, অথবা সাহায্যের জন্য সহায়তার সাথে যোগাযোগ করুন।", @@ -1157,7 +1157,6 @@ "whatToExpect.default": "শূন্যপদ পূরণ না হওয়া পর্যন্ত আবেদনকারীরা র agent্যাঙ্ক ক্রমে সম্পত্তি এজেন্টের সাথে যোগাযোগ করবে। আপনার দেওয়া সমস্ত তথ্য যাচাই করা হবে এবং আপনার যোগ্যতা নিশ্চিত করা হবে। যদি আপনি কোন প্রতারণামূলক বিবৃতি দিয়ে থাকেন তাহলে আপনার আবেদনটি প্রতীক্ষার তালিকা থেকে সরিয়ে দেওয়া হবে। যদি আমরা আপনার দাবি করা আবাসন পছন্দ যাচাই করতে না পারি, তাহলে আপনি অগ্রাধিকার পাবেন না কিন্তু অন্যথায় শাস্তি পাবেন না। আপনার আবেদন নির্বাচন করা উচিত, আরো বিস্তারিত আবেদন পূরণ এবং প্রয়োজনীয় সহায়ক নথি প্রদান করার জন্য প্রস্তুত থাকুন।", "listingFilters.allRentals": "সমস্ত ভাড়া", "listingFilters.buttonTitle": "ছাঁকনি", - "listingFilters.buttonTitleWithNumber": "ফিল্টার (%{number})", "listingFilters.buttonTitleExtended": "আপনার জন্য ভাড়া বাড়ি খুঁজুন", "listingFilters.loading": "লোড হচ্ছে...", "listingFilters.rentalsFound": "%{smart_count} ভাড়া পাওয়া গেছে |||| %{smart_count} ভাড়া পাওয়া গেছে", diff --git a/detroit-ui-components/src/locales/es.json b/detroit-ui-components/src/locales/es.json index e8dcc513b2..ae0012d60e 100644 --- a/detroit-ui-components/src/locales/es.json +++ b/detroit-ui-components/src/locales/es.json @@ -307,7 +307,7 @@ "authentication.createAccount.reEnterEmail": "Vuelva a introducir la dirección de correo electrónico", "authentication.createAccount.reEnterPassword": "Reingresa tu contraseña", "authentication.createAccount.resendTheEmail": "Volver a enviar el email", - "authentication.forgotPassword.success": "Te hemos enviado un correo electrónico. Recibirás un correo electrónico con un enlace para restablecer tu contraseña.", + "authentication.forgotPassword.message": "Si hay una cuenta creada con ese correo electrónico, recibirá un correo electrónico con un enlace para restablecer su contraseña.", "authentication.forgotPassword.sendEmail": "Inscribirse", "authentication.signIn.error": "Hubo un error cuando usted inició sesión", "authentication.signIn.errorGenericMessage": "Por favor inténtelo de nuevo, o comuníquese con servicio al cliente para recibir asistencia.", @@ -381,6 +381,7 @@ "leasingAgent.dueToHighCallVolume": "Debido al alto volumen de llamadas, usted podría escuchar un mensaje.", "leasingAgent.officeHours": "Horario de oficina", "listingFilters.allRentals": "Todos los alquileres", + "listingFilters.buttonTitle": "Filtrar", "listingFilters.program.Seniors 55+": "Adultos mayores de 55 años", "listingFilters.program.Seniors 62+": "Adultos mayores de 62 años", "listingFilters.program.Residents with Disabilities": "Residentes con discapacidades", diff --git a/detroit-ui-components/src/locales/general.json b/detroit-ui-components/src/locales/general.json index 9f21f8e0d0..27acf86c6b 100644 --- a/detroit-ui-components/src/locales/general.json +++ b/detroit-ui-components/src/locales/general.json @@ -598,7 +598,7 @@ "flags.markedAsDuplicate": "%{quantity} applications marked as duplicate", "authentication.forgotPassword.changePassword": "Change Password", "authentication.forgotPassword.sendEmail": "Send email", - "authentication.forgotPassword.success": "We've sent you an email. You'll receive an email with a link to reset your password.", + "authentication.forgotPassword.message": "If there is an account made with that email, you'll receive an email with a link to reset your password.", "authentication.forgotPassword.errors.tokenExpired": "Reset password token expired. Please request for a new one.", "authentication.forgotPassword.errors.tokenMissing": "Token not found. Please request for a new one.", "authentication.forgotPassword.errors.generic": "There was an error. Please try again, or contact support for help.", @@ -1329,6 +1329,7 @@ "t.n/a": "n/a", "t.name": "Name", "t.neighborhood": "Neighborhood", + "t.newPage": "New Page", "t.next": "Next", "t.no": "No", "t.none": "None", @@ -1445,7 +1446,7 @@ "whatToExpect.default": "Applicants will be contacted by the property agent in rank order until vacancies are filled. All of the information that you have provided will be verified and your eligibility confirmed. Your application will be removed from the waitlist if you have made any fraudulent statements. If we cannot verify a housing preference that you have claimed, you will not receive the preference but will not be otherwise penalized. Should your application be chosen, be prepared to fill out a more detailed application and provide required supporting documents.", "listingFilters.allRentals": "All rentals", "listingFilters.buttonTitle": "Filter", - "listingFilters.buttonTitleWithNumber": "Filter (%{number})", + "listingFilters.buttonTitleWithNumber": "Filter - %{number} Filters Applied", "listingFilters.buttonTitleExtended": "Find rentals for you", "listingFilters.loading": "Loading...", "listingFilters.rentalsFound": "%{smart_count} rental found |||| %{smart_count} rentals found", @@ -1588,9 +1589,12 @@ "publicFilter.bedRoomSize": "Bedroom Size", "publicFilter.rentRange": "Monthly Rent Range", "publicFilter.rentRangeMin": "No Min Rent", + "publicFilter.rentRangeMinReader": "Enter the dollar amount of your minimum rent", "publicFilter.rentRangeMax": "No Max Rent", + "publicFilter.rentRangeMaxReader": "Enter the dollar amount of your maximum rent", "publicFilter.communityTypes": "Community Types", "publicFilter.waitlist.open": "Open Waitlist", "publicFilter.waitlist.closed": "Closed Waitlist", - "account.noFavorites": "It looks like you haven't favorited any listings yet." + "account.noFavorites": "It looks like you haven't favorited any listings yet.", + "sr.pageTitle": "Page Title:" } diff --git a/detroit-ui-components/src/text/Description.scss b/detroit-ui-components/src/text/Description.scss index 277b53af19..1dbba85adb 100644 --- a/detroit-ui-components/src/text/Description.scss +++ b/detroit-ui-components/src/text/Description.scss @@ -1,65 +1,55 @@ @import "../global/mixins.scss"; -.description__container { - @apply w-full; - @apply flex; - @apply flex-col; - @apply mb-3; - @screen md { - @apply flex-row; - } -} - -// Description -.description__title { - @apply font-serif; - @apply text-xl; -} - -.description__body { - @apply mb-4; - @apply flex; - @apply items-center; - - @screen md { - padding-top: 0.4em; - } -} - -// Data lists +// Description grid .column-definition-list { @include clearfix; + --title-font-family: var(--bloom-font-serif); + --title-font-size-desktop: var(--bloom-font-size-xl); + --title-font-size-mobile: var(--bloom-font-size-lg); + --title-text-color: var(--bloom-color-gray-800); + --body-font-size: var(--bloom-font-size-sm); + --border-color: var(--bloom-color-gray-450); + --last-row-grid: span 2 / span 2; + + @media (min-width: $screen-md) { + display: grid; + grid-template-columns: 1fr 1fr; + column-gap: var(--bloom-s4); + grid-row-gap: 0.15rem; + } + .description__title { - @apply text-lg; - @apply text-gray-800; + font-family: var(--title-font-family); + font-size: var(--title-font-size-mobile); + color: var(--title-text-color); + margin-bottom: var(--bloom-s1); clear: left; - width: 170px; - min-width: 170px; - - @screen md { - @apply pl-4; - @apply border-l-2; - @apply border-gray-450; - @apply float-left; - @apply pr-3; - margin-top: 0.15rem; + height: auto; + width: 100%; + + @media (min-width: $screen-md) { + padding-left: var(--bloom-s4); + border-left: 2px solid var(--border-color); + float: left; + margin-bottom: var(--bloom-s3); + font-size: var(--title-font-size-desktop); } } .description__body { - @apply text-tiny; - @apply mb-5; - @apply ml-2; - - @screen md { - @apply mb-0; - @apply float-left; - @apply w-2/3; - } - - &:last-of-type { - @apply w-full; + font-size: var(--body-font-size); + margin-bottom: var(--bloom-s5); + width: 100%; + + @media (min-width: $screen-md) { + margin-bottom: 0; + float: left; + padding-top: 0.4em; + + &:last-of-type { + grid-column: var(--last-row-grid); + } } } } diff --git a/detroit-ui-components/src/text/Description.tsx b/detroit-ui-components/src/text/Description.tsx index 976aa0e8ce..2632e02114 100644 --- a/detroit-ui-components/src/text/Description.tsx +++ b/detroit-ui-components/src/text/Description.tsx @@ -5,23 +5,27 @@ import Markdown from "markdown-to-jsx" export interface DescriptionProps { term: string description: string | React.ReactNode + dtClassName?: string markdown?: boolean } export const Description = (props: DescriptionProps) => { + const dtClasses = ["description__body"] + if (props.dtClassName) dtClasses.push(props.dtClassName) + return ( -
-
{props.term}
+ <> +
{props.term}
{props.markdown ? ( -
+
- +
) : ( -
{props.description}
+
{props.description}
)} -
+ ) } diff --git a/shared-helpers/package.json b/shared-helpers/package.json index 7cf1f4da54..21545997e4 100644 --- a/shared-helpers/package.json +++ b/shared-helpers/package.json @@ -17,7 +17,7 @@ }, "dependencies": { "@bloom-housing/backend-core": "^4.4.0", - "@bloom-housing/ui-components": "^8.0.1", + "@bloom-housing/ui-components": "^8.2.0", "axios": "0.21.2" }, "devDependencies": { diff --git a/sites/partners/package.json b/sites/partners/package.json index f02aabec7a..2abbad2b32 100644 --- a/sites/partners/package.json +++ b/sites/partners/package.json @@ -28,7 +28,7 @@ "dependencies": { "@bloom-housing/backend-core": "^4.4.0", "@bloom-housing/shared-helpers": "^4.4.0", - "@bloom-housing/ui-components": "^8.0.1", + "@bloom-housing/ui-components": "^8.2.0", "@mapbox/mapbox-sdk": "^0.13.0", "@zeit/next-sass": "^1.0.1", "ag-grid-community": "^26.0.0", diff --git a/sites/partners/src/components/listings/PaperListingForm/sections/SelectAndOrder.tsx b/sites/partners/src/components/listings/PaperListingForm/sections/SelectAndOrder.tsx index 6f9e252b0f..dc1fd09ecd 100644 --- a/sites/partners/src/components/listings/PaperListingForm/sections/SelectAndOrder.tsx +++ b/sites/partners/src/components/listings/PaperListingForm/sections/SelectAndOrder.tsx @@ -132,7 +132,9 @@ const SelectAndOrder = ({ if (draftListingData.length > 0 && dragOrder.length > 0) { const newDragOrder = [] dragOrder.forEach((item) => { - newDragOrder.push(draftListingData.filter((draftItem) => draftItem.title === item.name)[0]) + newDragOrder.push( + draftListingData.filter((draftItem) => draftItem.title === item.name.content)[0] + ) }) setDraftListingData(newDragOrder) } diff --git a/sites/partners/src/layouts/index.tsx b/sites/partners/src/layouts/index.tsx index 85d234f4c5..98a6ce311e 100644 --- a/sites/partners/src/layouts/index.tsx +++ b/sites/partners/src/layouts/index.tsx @@ -7,9 +7,9 @@ import { t, MenuLink, setSiteAlertMessage, + SiteHeader, } from "@bloom-housing/ui-components" import { AuthContext } from "@bloom-housing/shared-helpers" -import { SiteHeader } from "../../../../detroit-ui-components/src/headers/SiteHeader" import { FooterNav } from "../../../../detroit-ui-components/src/navigation/FooterNav" const Layout = (props) => { @@ -54,9 +54,16 @@ const Layout = (props) => { siteHeaderWidth={"wide"} homeURL={"/"} logoClass={"md:h-36 md:mt-0"} + strings={{ + skipToMainContent: t("nav.skip"), + menu: t("t.menu"), + close: t("t.close"), + logoAriaLable: "City of Detroit logo", + }} + mainContentId={"main-content"} /> -
{props.children}
+
{props.children}
diff --git a/sites/partners/src/pages/forgot-password.tsx b/sites/partners/src/pages/forgot-password.tsx index 08c5b6d403..532a22b73e 100644 --- a/sites/partners/src/pages/forgot-password.tsx +++ b/sites/partners/src/pages/forgot-password.tsx @@ -21,12 +21,12 @@ const ForgotPassword = () => { try { await forgotPassword(email) - setSiteAlertMessage(t(`authentication.forgotPassword.success`), "success") - await router.push("/") } catch (error) { const { status } = error.response || {} determineNetworkError(status, error) } + setSiteAlertMessage(t(`authentication.forgotPassword.message`), "notice") + await router.push("/sign-in") } return ( diff --git a/sites/partners/styles/overrides.scss b/sites/partners/styles/overrides.scss index 459b925325..ca65268e5a 100644 --- a/sites/partners/styles/overrides.scss +++ b/sites/partners/styles/overrides.scss @@ -1,21 +1,38 @@ /* Overrides the default ui-components styles with Detroit-specific styles. */ @import url("https://fonts.googleapis.com/css?family=Montserrat:400,600,700"); -.navbar-logo .logo .logo__image { - min-height: 4rem; - max-height: 5rem; - @screen md { - min-height: 6rem; - max-height: 7rem; - } -} +#__next { + .site-header { + --logo-title-font-size-desktop: var(--bloom-font-size-tiny); + --logo-title-font-size-mobile: var(--bloom-font-size-sm); + --logo-image-desktop-max-height: var(--bloom-s20); + --logo-image-desktop-min-height: var(--bloom-s20); + --mobile-menu-font-size: var(--bloom-font-size-sm); + --mobile-dropdown-item-font-size: var(--bloom-font-size-tiny); + --logo-image-mobile-display: none; + --notice-display-mobile: none; + --link-text-hover-color: var(--bloom-color-gray-750); + --link-text-color: var(--bloom-color-gray-750); + --link-font-size: var(--bloom-font-size-sm); -.navbar-logo .logo { - max-height: 15rem; - max-width: 100%; + .button { + text-transform: uppercase; + font-weight: 700; + text-decoration: none; + letter-spacing: var(--bloom-letter-spacing-widest); + font-size: var(--bloom-font-size-sm); + svg { + rect { + fill: var(--bloom-color-primary); + } + } + } - .logo__title { - @apply text-sm; + .site-header__logo-container { + a:hover { + color: var(--bloom-color-gray-950); + } + } } } diff --git a/sites/public/cypress/integration/navigation.spec.ts b/sites/public/cypress/integration/navigation.spec.ts index d1736435d6..3629e81eb5 100644 --- a/sites/public/cypress/integration/navigation.spec.ts +++ b/sites/public/cypress/integration/navigation.spec.ts @@ -31,17 +31,17 @@ describe("Navigating around the site", () => { cy.contains("Terms and Conditions") // Click on the listings page link in the header nav - cy.get(".navbar").contains("Sign in").click() + cy.get(".site-header__base").contains("Sign in").click() // Should be on the listings page cy.location("pathname").should("equal", "/sign-in") cy.contains("Sign in") // Click on the navbar logo to go to the homepage - cy.get(".navbar") + cy.get(".site-header__base") .first() .within(() => { - cy.get(".logo").click() + cy.get(".site-header__logo").click() }) // Check that the homepage banner text is present on the page diff --git a/sites/public/package.json b/sites/public/package.json index bfb8e75aef..d78c6a378e 100644 --- a/sites/public/package.json +++ b/sites/public/package.json @@ -28,7 +28,7 @@ "dependencies": { "@bloom-housing/backend-core": "^4.4.0", "@bloom-housing/shared-helpers": "^4.4.0", - "@bloom-housing/ui-components": "^8.0.1", + "@bloom-housing/ui-components": "^8.2.0", "autoprefixer": "^10.3.4", "axios": "^0.21.1", "dayjs": "^1.10.7", diff --git a/sites/public/src/components/filters/FilterForm.tsx b/sites/public/src/components/filters/FilterForm.tsx index 1388df13a2..8917469173 100644 --- a/sites/public/src/components/filters/FilterForm.tsx +++ b/sites/public/src/components/filters/FilterForm.tsx @@ -249,7 +249,7 @@ const FilterForm = (props: FilterFormProps) => { name={FrontendListingFilterStateKeys.minRent} type="number" placeholder={t("publicFilter.rentRangeMin")} - label={t("publicFilter.rentRangeMin")} + label={t("publicFilter.rentRangeMinReader")} register={register} prepend={"$"} defaultValue={localFilterState?.minRent} @@ -276,7 +276,7 @@ const FilterForm = (props: FilterFormProps) => { type="number" name={FrontendListingFilterStateKeys.maxRent} placeholder={t("publicFilter.rentRangeMax")} - label={t("publicFilter.rentRangeMax")} + label={t("publicFilter.rentRangeMaxReader")} register={register} prepend={"$"} defaultValue={localFilterState?.maxRent} diff --git a/sites/public/src/layouts/application.tsx b/sites/public/src/layouts/application.tsx index 06e770e3e8..139c4b706d 100644 --- a/sites/public/src/layouts/application.tsx +++ b/sites/public/src/layouts/application.tsx @@ -1,15 +1,23 @@ -import React, { useContext } from "react" +import React, { useContext, useEffect, useRef, useState } from "react" import { useRouter } from "next/router" import Link from "next/link" import Head from "next/head" -import { SiteFooter, FooterSection, t, setSiteAlertMessage } from "@bloom-housing/ui-components" +import { + SiteFooter, + FooterSection, + t, + setSiteAlertMessage, + SiteHeader, + MenuLink, +} from "@bloom-housing/ui-components" import { AuthContext } from "@bloom-housing/shared-helpers" -import { SiteHeader, MenuLink } from "../../../../detroit-ui-components/src/headers/SiteHeader" import { FooterNav } from "../../../../detroit-ui-components/src/navigation/FooterNav" import Markdown from "markdown-to-jsx" const Layout = (props) => { const { profile, signOut } = useContext(AuthContext) + const srAnnouncement = useRef(null) + const [srAnnouncementMessage, setSRAnnouncementMessage] = useState() const router = useRouter() const languages = @@ -62,14 +70,21 @@ const Layout = (props) => { menuLinks.push({ title: t("nav.signIn"), href: "/sign-in", - class: "navbar-link__sign-in", + className: "navbar-link__sign-in", }) menuLinks.push({ title: t("nav.signUp"), href: "/create-account", - class: "navbar-link__sign-up", + className: "navbar-link__sign-up", }) } + useEffect(() => { + const pageName = document?.querySelector("h1")?.innerText + pageName + ? setSRAnnouncementMessage(`${t("sr.pageTitle")} ${pageName}`) + : setSRAnnouncementMessage(t("t.newPage")) + srAnnouncement.current.focus() + }, [router.asPath, router.locale]) return (
@@ -77,6 +92,9 @@ const Layout = (props) => { {t("nav.siteTitle")} +
+ {srAnnouncementMessage} +
{ })} menuLinks={menuLinks} desktopMinWidth={1024} + strings={{ + skipToMainContent: t("nav.skip"), + menu: t("t.menu"), + close: t("t.close"), + logoAriaLable: "City of Detroit logo", + }} + mainContentId={"main-content"} />
{props.children} diff --git a/sites/public/src/page_content/locale_overrides/ar.json b/sites/public/src/page_content/locale_overrides/ar.json index 8efe944f84..e54f6211a5 100644 --- a/sites/public/src/page_content/locale_overrides/ar.json +++ b/sites/public/src/page_content/locale_overrides/ar.json @@ -16,7 +16,7 @@ "footer.contactInfo": "أرسل بريدًا إلكترونيًا إلى إدارة الإسكان والتنشيط بمدينة ديترويت على detroithomeconnect@detroitmi.gov أو اتصل على 6380-224-313.", "leasingAgent.contact": "معلومات الاتصال الخاصة بالتأجير", "leasingAgent.dueToHighCallVolume": "", - "listingFilters.resetButton": "انظر جميع القوائم", + "listingFilters.resetButton": "إعادة ضبط", "pageTitle.additionalResources": "موارد سكن إضافية", "pageDescription.resources": "قامت دائرة الإسكان والتنشيط بمدينة ديترويت بتجميع قائمة بالموارد لمساعدتك في العثور على مسكنك والمحافظة عليه. في نهاية هذه الصفحة ، ستجد أيضًا أربعة مقاطع فيديو قصيرة حيث يمكنك معرفة المزيد حول عملية التقديم للحصول على سكن ميسور التكلفة.", "pageDescription.additionalResources": "نشجعك على تصفح الموارد الإضافية في رحلة بحثك عن السكن", diff --git a/sites/public/src/page_content/locale_overrides/bn.json b/sites/public/src/page_content/locale_overrides/bn.json index fb38fdcc2a..aa030450f7 100644 --- a/sites/public/src/page_content/locale_overrides/bn.json +++ b/sites/public/src/page_content/locale_overrides/bn.json @@ -16,7 +16,7 @@ "footer.contactInfo": "detroithomeconnect@detroitmi.gov-এ সিটি অফ ডেট্রয়েট হাউজিং অ্যান্ড রিভাইটালাইজেশন ডিপার্টমেন্টকে ইমেল করুন বা 313-224-6380 নম্বরে কল করুন।", "leasingAgent.contact": "লিজিং যোগাযোগের তথ্য", "leasingAgent.dueToHighCallVolume": "", - "listingFilters.resetButton": "সমস্ত তালিকা দেখুন", + "listingFilters.resetButton": "রিসেট", "pageTitle.additionalResources": "আবাসন সংক্রান্ত অতিরিক্ত রিসোর্সসমূহ", "pageDescription.resources": "সিটি অফ ডেট্রয়েট হাউজিং অ্যান্ড রিভাইটালাইজেশন ডিপার্টমেন্ট আপনাকে আপনার আবাসন খুঁজে পেতে এবং বজায় রাখতে সহায়তা করার জন্য সংস্থানগুলির একটি তালিকা তৈরি করেছে। এই পৃষ্ঠার শেষে, আপনি চারটি ছোট ভিডিওও পাবেন যেখানে আপনি সাশ্রয়ী মূল্যের আবাসনের জন্য আবেদন প্রক্রিয়া সম্পর্কে আরও জানতে পারবেন।", "pageDescription.additionalResources": "আমরা আপনাকে আবাসনের জন্য আপনার অনুসন্ধানে অতিরিক্ত সম্পদ ব্রাউজ করতে উৎসাহিত করি", diff --git a/sites/public/src/page_content/locale_overrides/es.json b/sites/public/src/page_content/locale_overrides/es.json index 95628e7957..310b4aa083 100644 --- a/sites/public/src/page_content/locale_overrides/es.json +++ b/sites/public/src/page_content/locale_overrides/es.json @@ -16,7 +16,7 @@ "footer.contactInfo": "envíe un correo electrónico al Departamento de Vivienda y Revitalización de la ciudad de Detroit a detroithomeconnect@detroitmi.gov o llame al 313-224-6380.", "leasingAgent.contact": "Información de contacto de arrendamiento", "leasingAgent.dueToHighCallVolume": "", - "listingFilters.resetButton": "Ver Todos los Listados", + "listingFilters.resetButton": "Reinicializar", "pageDescription.resources": "El Departamento de Vivienda y Revitalización de la Ciudad de Detroit ha compilado una lista de recursos para ayudarlo a encontrar y mantener su vivienda. Al final de esta página, también encontrará cuatro videos breves donde podrá obtener más información sobre el proceso de solicitud de vivienda asequible.", "pageDescription.additionalResources": "El Departamento de Vivienda y Revitalización de la ciudad de Detroit ha compilado una lista de recursos para ayudarle a encontrar y mantener su vivienda.", "pageTitle.additionalResources": "Recursos de vivienda adicionales", diff --git a/sites/public/src/page_content/locale_overrides/general.json b/sites/public/src/page_content/locale_overrides/general.json index cb3409b4ee..472b23ecbc 100644 --- a/sites/public/src/page_content/locale_overrides/general.json +++ b/sites/public/src/page_content/locale_overrides/general.json @@ -16,7 +16,7 @@ "footer.contactInfo": "email the City of Detroit Housing and Revitalization Department at [detroithomeconnect@detroitmi.gov](mailto:detroithomeconnect@detroitmi.gov) or call [313-224-6380](tel:313-224-6380).", "leasingAgent.contact": "Leasing Contact Information", "leasingAgent.dueToHighCallVolume": "", - "listingFilters.resetButton": "Show all listings", + "listingFilters.resetButton": "Reset", "pageTitle.additionalResources": "Additional Housing Resources", "pageDescription.resources": "The City of Detroit Housing and Revitalization Department has compiled a list of resources to help you find and maintain your housing. At the end of this page, you will also find four short videos where you can learn more about the application process for affordable housing.", "pageDescription.additionalResources": "We encourage you to browse additional resources in your search for housing.", diff --git a/sites/public/src/pages/create-account.tsx b/sites/public/src/pages/create-account.tsx index 64e0532058..80acefdf8b 100644 --- a/sites/public/src/pages/create-account.tsx +++ b/sites/public/src/pages/create-account.tsx @@ -154,6 +154,8 @@ export default () => { @@ -212,6 +214,8 @@ export default () => { type="password" name="passwordConfirmation" placeholder={t("authentication.createAccount.mustBe8Chars")} + label={t("authentication.createAccount.reEnterPassword")} + readerOnly validation={{ validate: (value) => value === password.current || diff --git a/sites/public/src/pages/finder.tsx b/sites/public/src/pages/finder.tsx index 3b6842e510..adf22e8ab7 100644 --- a/sites/public/src/pages/finder.tsx +++ b/sites/public/src/pages/finder.tsx @@ -14,7 +14,7 @@ import { import axios from "axios" import router from "next/router" -import React, { useEffect, useRef, useState } from "react" +import React, { forwardRef, useEffect, useRef, useState } from "react" import { useForm } from "react-hook-form" import Layout from "../layouts/application" import FinderDisclaimer from "../components/finder/FinderDisclaimer" @@ -28,6 +28,12 @@ interface FinderField { type?: string } +interface ProgressHeaderProps { + isDisclaimer: boolean + sectionNumber: number + stepLabels: string[] +} + export interface FinderQuestion { formSection: string fieldGroupName: string @@ -37,12 +43,49 @@ export interface FinderQuestion { subtitle: string } +const ProgressHeader = forwardRef( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (props: ProgressHeaderProps, ref: React.MutableRefObject) => { + return ( +
+
+

+ {t("listingFilters.buttonTitleExtended")} +

+
+ {!props.isDisclaimer && ( + + )} +
+
+
+ +
+
+ ) + } +) + const Finder = () => { // eslint-disable-next-line @typescript-eslint/unbound-method const { register, handleSubmit, trigger, errors, watch } = useForm() const [questionIndex, setQuestionIndex] = useState(0) const [formData, setFormData] = useState([]) const [isDisclaimer, setIsDisclaimer] = useState(false) + const finderSectionQuestion = useRef(null) const finderSectionHeader = useRef(null) const minRent = watch("minRent") const maxRent = watch("maxRent") @@ -190,37 +233,6 @@ const Finder = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []) - const ProgressHeader = () => { - return ( -
-
-

- {t("listingFilters.buttonTitleExtended")} -

- {!isDisclaimer && ( - - )} -
-
- -
-
- ) - } - const nextQuestion = () => { if (!Object.keys(errors).length) { const formCopy = [...formData] @@ -236,35 +248,61 @@ const Finder = () => { }) } setFormData(formCopy) - if (questionIndex >= formData.length - 1) setIsDisclaimer(true) - setQuestionIndex(questionIndex + 1) - finderSectionHeader.current.focus() + // check for disclaimer case + if (questionIndex >= formData.length - 1) { + setIsDisclaimer(true) + setQuestionIndex(questionIndex + 1) + finderSectionQuestion.current.focus() + } + // set focus on stepheader if section change + else if (formData[questionIndex]?.formSection !== formData[questionIndex + 1]?.formSection) { + setQuestionIndex(questionIndex + 1) + finderSectionHeader.current.focus() + } + // otherwise set focus on question + else { + setQuestionIndex(questionIndex + 1) + finderSectionQuestion.current.focus() + } } } const previousQuestion = () => { setIsDisclaimer(false) - setQuestionIndex(questionIndex - 1) - finderSectionHeader.current.focus() + // set focus on stepheader if section change + if (formData[questionIndex]?.formSection !== formData[questionIndex - 1]?.formSection) { + setQuestionIndex(questionIndex - 1) + finderSectionHeader.current.focus() + } + // otherwise set focus on question + else { + setQuestionIndex(questionIndex - 1) + finderSectionQuestion.current.focus() + } } const skipToListings = () => { setIsDisclaimer(true) setQuestionIndex(formData.length) - finderSectionHeader.current.focus() + finderSectionQuestion.current.focus() } return (
- + {formData?.length > 0 && (
{/* Deconstructed header group to support ref */}
-

+

{!isDisclaimer ? activeQuestion.question : t("finder.disclaimer.header")}

diff --git a/sites/public/src/pages/forgot-password.tsx b/sites/public/src/pages/forgot-password.tsx index 9ccc962ba0..b4deb518ce 100644 --- a/sites/public/src/pages/forgot-password.tsx +++ b/sites/public/src/pages/forgot-password.tsx @@ -35,12 +35,12 @@ const ForgotPassword = () => { try { await forgotPassword(email) - setSiteAlertMessage(t(`authentication.forgotPassword.success`), "success") - await router.push("/") } catch (error) { const { status } = error.response || {} determineNetworkError(status, error) } + setSiteAlertMessage(t(`authentication.forgotPassword.message`), "notice") + await router.push("/sign-in") } return ( diff --git a/sites/public/src/pages/listings/filtered.tsx b/sites/public/src/pages/listings/filtered.tsx index 7de05b4f33..aafa3f5e31 100644 --- a/sites/public/src/pages/listings/filtered.tsx +++ b/sites/public/src/pages/listings/filtered.tsx @@ -132,6 +132,11 @@ const FilteredListingsPage = () => { icon={faSliders} iconPlacement="left" iconSize="md-large" + ariaLabel={ + numberOfFilters + ? t("listingFilters.buttonTitleWithNumber", { number: numberOfFilters }) + : t("listingFilters.buttonTitle") + } onClick={() => setFilterModalVisible(true)} > {t("listingFilters.buttonTitle")} diff --git a/sites/public/styles/headers.scss b/sites/public/styles/headers.scss index c50dbb1e7a..3c9fd0336f 100644 --- a/sites/public/styles/headers.scss +++ b/sites/public/styles/headers.scss @@ -1,247 +1,201 @@ -/** Headers */ - .site-header { - .navbar-notice-hide { - display: none; + --base-align-items: center; + --base-desktop-padding: 0 0 0 var(--bloom-s3); + --base-desktop-width: 100% !important; + --base-height: auto; + --base-max-height: none; + --base-mobile-padding: var(--bloom-s6) 0 var(--bloom-s6) var(--bloom-s4); + --base-mobile-width: 100%; + --dropdown-item-font-size: var(--bloom-s3_5); + --link-align-items: center; + --link-bottom-border: none; + --link-font-size: 0.95rem; + --link-font-weight: 700; + --link-height: var(--bloom-s10); + --link-hover-bottom-border: none; + --link-padding: var(--bloom-s4); + --link-text-color: var(--bloom-color-primary); + --link-text-desktop-color: var(--bloom-color-gray-750); + --link-text-hover-color: var(--bloom-color-primary-dark); + --link-text-transform: none; + --logo-container-min-width: fit-content; + --logo-content-display: flex; + --logo-content-padding: 0; + --logo-desktop-height: 100%; + --logo-desktop-padding: 0; + --logo-image-desktop-height: 57px; + --logo-image-desktop-margin: -0.75rem 0 0 -0.25rem; + --logo-image-desktop-max-height: 6rem; + --logo-image-mobile-display: none; + --logo-image-mobile-height: 57px; + --logo-image-mobile-margin: 0; + --logo-margin: 0; + --logo-mobile-height: 100%; + --logo-mobile-padding: 0; + --logo-subtitle-desktop-font-size: var(--bloom-font-size-sm); + --logo-subtitle-mobile-font-size: var(--bloom-font-size-sm); + --logo-title-font-size-desktop: var(--bloom-font-size-base); + --logo-title-font-size-mobile: var(--bloom-font-size-base); + --logo-title-letter-spacing: normal; + --logo-title-margin-desktop: 0 0 0 var(--bloom-s2); + --logo-title-text-align: left; + --logo-title-text-color: var(--bloom-color-primary-dark); + --logo-title-text-transform: none; + --mobile-dropdown-item-font-size: var(--bloom-s3_5); + --mobile-dropdown-margin: 0 0 var(--bloom-s6) 0; + --mobile-menu-button-margin: 0; + --mobile-menu-button-padding: 0 var(--bloom-s1) 0 0; + --mobile-menu-button-text-display: none; + --navbar-menu-desktop-height: var(--bloom-s12); + --navbar-menu-desktop-margin: var(--bloom-s6) 0 var(--bloom-s6); + --navbar-menu-desktop-width: 100%; + --navbar-menu-mobile-height: var(--bloom-s12); + --navbar-menu-mobile-width: 100%; + --notice-display-desktop: none; + --notice-display-mobile: none; +} + +.site-header__link { + @screen lg { + font-size: 1.125rem; + } +} + +.site-header__logo { + margin: 0; + box-shadow: none; +} + +.site-header__logo-title { + @media (min-width: $header-desktop-min-size) { + font-size: var(--bloom-font-size-2xl); + } + [dir="rtl"] & { + margin-right: var(--bloom-s4); + } +} + +.site-header__logo-image { + @media (min-width: $header-desktop-min-size) { + height: 77px; + } + + @screen xl { + height: 77px; } +} + +.site-header__navbar-menu { + .button { + padding: 0 var(--bloom-s1) 0 var(--bloom-s3); + height: var(--bloom-s12); + margin-top: 0; + margin-right: var(--bloom-s3); + } + + padding: 0 0 0 var(--bloom-s8); + [dir="rtl"] & { + padding-left: 0; + } + + @media (min-width: $header-desktop-min-size) { + margin: var(--bloom-s12) 0 var(--bloom-s8); + padding: 0 var(--bloom-s2) 0 var(--bloom-s8); + [dir="rtl"] & { + padding-left: var(--bloom-s4); + } + } + + @screen lg { + padding: 0 var(--bloom-s10) var(--bloom-s8); + } +} + +.language-bar__inner { + max-width: inherit; + padding-right: 0; + @screen md { + padding-right: var(--bloom-s3); - .navbar-container { - border: none; - - .navbar { - align-items: center; - height: auto; - max-height: none; - padding: var(--bloom-s6) 0; - - @media (min-width: $header-desktop-min-size) { - padding: 0 12px; - width: 100%; - } - - @screen lg { - padding: 0 50px; - width: 100%; - } - - @screen xl { - justify-content: center; - } - - .navbar-menu { - height: 48px; - margin-right: 12px; - min-width: 48px; - width: 48px; - - @media (min-width: $header-desktop-min-size) { - margin: 40px 0 24px; - width: 100%; - } - - @screen xl { - margin: 48px 0 32px; - } - - .button.navbar-mobile-menu-button { - align-items: center; - justify-content: center; - margin: 0; - padding: 0; - } - - .button { - width: 60px; - } - - .button__content { - display: none; - } - - .button__icon { - margin: 0; - } - - .ui-base svg { - height: 18px; - width: 21px; - } - - .navbar-link { - @apply text-primary; - align-items: center; - display: flex; - font-size: 0.95rem; - @screen lg { - font-size: 1.125rem; - } - font-weight: 700; - height: 40px; - padding: 1rem; - text-transform: none; - border: none; - } - - .navbar-link__sign-in { - margin-inline-start: 1rem; - padding-inline-start: 2rem; - position: relative; - min-width: max-content; - } - - // This is a little hacky to get the divider line to the left of the "sign in" link, but - // this is the simplest way to do it without making significant changes to the SiteHeader - // component - .navbar-link__sign-in:before { - border-inline-start: 3px solid $tailwind-primary; - content: ""; - height: 18px; - inset-inline-start: 0; - position: absolute; - } - - .navbar-link__sign-up { - border: 2px solid $tailwind-primary; - border-radius: 44px; - min-width: max-content; - } - - .navbar-link.navbar-link__sign-up:hover { - @apply text-white; - background-color: $tailwind-primary; - border: 2px solid $tailwind-primary; - border-radius: 44px; - } - - .navbar-link:hover { - @apply text-primary-dark; - border: none; - } - - .navbar-dropdown-container { - display: flex; - margin-left: 0px; - border-top: 1px transparent; - margin-top: 7px; - width: auto; - .navbar-dropdown { - .navbar-dropdown-item-container { - display: flex; - } - .navbar-dropdown-item { - flex: 1 1 auto; - font-size: 0.75rem; - } - } - } - - .navbar-mobile-menu-button { - @apply flex; - border: none; - margin: 2.75rem 0.5rem 0; - padding: 0 0.5rem 0.75rem; - } - - .ui-icon svg rect { - fill: $tailwind-primary; - } - } - - .navbar-logo { - @media (min-width: $header-desktop-min-size) { - padding: 48px 0 32px 0; - } - - @screen xl { - padding: 48px 0 32px; - } - - .logo { - background-color: initial; - box-shadow: none; - height: 100%; - margin: 0; - max-height: 15rem; - max-width: 100%; - padding: 0; - width: 100%; - - .logo-content { - align-items: center; - display: flex; - padding: 0; - } - - .logo__title { - @apply text-primary-dark; - @apply text-base; - letter-spacing: initial; - margin-left: 4px; - text-align: left; - text-transform: none; - - @media (min-width: $header-desktop-min-size) { - @apply text-2xl; - margin-left: 8px; - } - - @screen xl { - @apply text-2xl; - } - } - - .logo__subtitle { - font-size: 0.625rem; - font-weight: 400; - - @media (min-width: $header-desktop-min-size) { - @apply text-sm; - } - } - - .logo__image { - height: 57px; - margin: -12px 0 0 12px; - // The header logo should allow for a larger maximum height than the default - // logo. - max-height: 5rem; - - @media (min-width: $header-desktop-min-size) { - height: 77px; - // Negative margin to center around the shield - margin: -16px 0 0; - max-height: 6rem; - } - - @screen xl { - max-height: 7rem; - } - } - } - - .navbar-custom-width { - align-items: initial; - display: initial; - flex-direction: initial; - justify-content: initial; - } - } + [dir="rtl"] & { + padding-left: var(--bloom-s3); } } - .navbar-mobile-dropdown { - margin-bottom: 1.5rem; + + @screen lg { + padding-right: var(--bloom-s12); + } +} + +.site-header__logo-container { + @screen lg { + padding: var(--bloom-s9) 0 var(--bloom-s9) var(--bloom-s8); + } +} + +.site-header__logo-title { + @media (min-width: $header-desktop-min-size) { + margin-left: var(--bloom-s4); + } +} + +.site-header__logo-image { + @media (min-width: $header-desktop-min-size) { + margin: -1rem 0 0; + } +} + +.site-header__base { + [dir="rtl"] & { + padding-right: var(--bloom-s3); + padding-left: 0; } - .navbar-mobile-dropdown-container .navbar-mobile-dropdown .navbar-mobile-dropdown-item { - @screen md { - @apply text-primary; - font-size: 1.125rem; - font-weight: 700; - text-transform: none; + @media (min-width: $header-desktop-min-size) { + padding-right: var(--bloom-s2_5); + } + + @screen xl { + padding-right: var(--bloom-s2); + } +} + +.site-header__mobile-dropdown-item { + color: var(--bloom-color-gray-750); +} + +.site-header__mobile-menu-button { + svg { + rect { + fill: var(--bloom-color-primary); } + height: 1.125rem; + width: 1.313rem; } } +// This is a little hacky to get the divider line to the left of the "sign in" link, but +// this is the simplest way to do it without making significant changes to the SiteHeader +// component +.navbar-link__sign-in:before { + border-inline-start: 3px solid $tailwind-primary; + content: ""; + height: 1.125rem; + inset-inline-start: 0; + padding-right: var(--bloom-s8); +} + +.navbar-link__sign-in { + padding-left: 0; + margin-left: var(--bloom-s4); +} + +.navbar-link__sign-up { + border: var(--bloom-s0_5) solid $tailwind-primary; + border-radius: var(--bloom-s11); + min-width: max-content; +} + .hero { @apply font-bold; @apply mx-2; diff --git a/sites/public/styles/listings.scss b/sites/public/styles/listings.scss index 0c8352f2ce..3ff07bb2e4 100644 --- a/sites/public/styles/listings.scss +++ b/sites/public/styles/listings.scss @@ -146,3 +146,9 @@ border-radius: 24px 24px 0 0; } } + +.column-definition-list { + --body-font-size: var(--bloom-font-size-tiny); + --last-row-grid: auto; + --title-font-size-desktop: var(--bloom-font-size-lg); +} diff --git a/sites/public/tailwind.config.js b/sites/public/tailwind.config.js index a128d14a79..4fe7183e9e 100644 --- a/sites/public/tailwind.config.js +++ b/sites/public/tailwind.config.js @@ -47,6 +47,8 @@ module.exports = { "./src/**/*.tsx", "./layouts/**/*.tsx", "../../detroit-ui-components/src/**/*.tsx", + "../../shared-helpers/src/**/*.tsx", + "../../node_modules/@bloom-housing/ui-components/src/**/*.tsx", ], safelist: [/grid-cols-/, /md:col-span-/], }, diff --git a/yarn.lock b/yarn.lock index fbd2fdbcfd..8c8db0bfe4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3764,10 +3764,10 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@bloom-housing/ui-components@^8.0.0", "@bloom-housing/ui-components@^8.0.1": - version "8.0.1" - resolved "https://registry.yarnpkg.com/@bloom-housing/ui-components/-/ui-components-8.0.1.tgz#23351b9be6a2f57bbdca6d9a6c1e7850975d37c6" - integrity sha512-3BzvQls9N949XE3Df6pQVD3WMhFK+EZNyD8ZjYnGUas04l+3oY7em5/PnSBtISaXRL3CT3o8IympV3T+stsw+A== +"@bloom-housing/ui-components@^8.2.0": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@bloom-housing/ui-components/-/ui-components-8.2.0.tgz#bf36c24ec11eba64e13ed3b62bb2e8d30a76758c" + integrity sha512-1RsscXxOynumWXCBKGKlHkvtHhLwSncP+kM3xpHb+Fr5lX+T7sPcGdeMAmkPY12IT3CudtPScj8sX0Od19wDMQ== dependencies: "@fortawesome/fontawesome-svg-core" "^6.1.1" "@fortawesome/free-regular-svg-icons" "^6.1.1"