diff --git a/client/src/plus/utils.ts b/client/src/plus/utils.ts index 52ed78429820..3682e07f418d 100644 --- a/client/src/plus/utils.ts +++ b/client/src/plus/utils.ts @@ -16,7 +16,7 @@ export function usePlusUrl(): string { let target = `/${locale}/plus`; if (normalizedUrl(target) === normalizedUrl(pathname)) { - target = "#subscribe"; + target += "#subscribe"; } return target; diff --git a/client/src/ui/_vars.scss b/client/src/ui/_vars.scss index b65341b91088..bc2f8155f607 100644 --- a/client/src/ui/_vars.scss +++ b/client/src/ui/_vars.scss @@ -154,6 +154,7 @@ $mdn-color-ads: #00d0aa; $mdn-theme-light-text-primary: $mdn-color-neutral-90; $mdn-theme-light-text-secondary: $mdn-color-neutral-70; +$mdn-theme-light-text-active: #{$mdn-color-neutral-50}; $mdn-theme-light-text-inactive: #{$mdn-color-neutral-40}a6; $mdn-theme-light-text-link: $mdn-color-light-theme-blue-60; $mdn-theme-light-text-invert: $mdn-color-white; @@ -200,6 +201,7 @@ $mdn-theme-light-code-background-block: $mdn-color-neutral-light-80; $mdn-theme-dark-text-primary: $mdn-color-white; $mdn-theme-dark-text-secondary: $mdn-color-neutral-20; +$mdn-theme-dark-text-active: #{$mdn-color-neutral-50}; $mdn-theme-dark-text-inactive: #{$mdn-color-neutral-20}a6; $mdn-theme-dark-text-link: $mdn-color-dark-theme-blue-30; $mdn-theme-dark-text-invert: $mdn-color-neutral-90; diff --git a/client/src/ui/base/_themes.scss b/client/src/ui/base/_themes.scss index 1f9bfb7db77c..223831842e37 100644 --- a/client/src/ui/base/_themes.scss +++ b/client/src/ui/base/_themes.scss @@ -5,6 +5,7 @@ @mixin light-theme { --text-primary: #{$mdn-theme-light-text-primary}; --text-secondary: #{$mdn-theme-light-text-secondary}; + --text-active: #{$mdn-theme-light-text-active}; --text-inactive: #{$mdn-theme-light-text-inactive}; --text-link: #{$mdn-theme-light-text-link}; --text-visited: #551a8b; // Source: https://searchfox.org/mozilla-central/rev/02841791400cf7cf5760c0cfaf31f5d772624253/modules/libpref/init/StaticPrefList.yaml#1787-1790 @@ -204,6 +205,7 @@ @mixin dark-theme { --text-primary: #{$mdn-theme-dark-text-primary}; --text-secondary: #{$mdn-theme-dark-text-secondary}; + --text-active: #{$mdn-theme-dark-text-active}; --text-inactive: #{$mdn-theme-dark-text-inactive}; --text-link: #{$mdn-theme-dark-text-link}; --text-visited: #ffadff; // Source: https://searchfox.org/mozilla-central/rev/02841791400cf7cf5760c0cfaf31f5d772624253/modules/libpref/init/StaticPrefList.yaml#1794-1797 diff --git a/client/src/ui/molecules/main-menu/index.tsx b/client/src/ui/molecules/main-menu/index.tsx index 6af28855a65e..7a8b10e52e32 100644 --- a/client/src/ui/molecules/main-menu/index.tsx +++ b/client/src/ui/molecules/main-menu/index.tsx @@ -9,6 +9,7 @@ import { PLUS_IS_ENABLED } from "../../../env"; import { useLocale } from "../../../hooks"; import { useGleanClick } from "../../../telemetry/glean-context"; import { MENU } from "../../../telemetry/constants"; +import { useLocation } from "react-router"; export default function MainMenu({ isOpenOnMobile }) { const locale = useLocale(); @@ -83,7 +84,7 @@ export default function MainMenu({ isOpenOnMobile }) { )} Blog Play - + AI Help Beta @@ -98,9 +99,13 @@ function TopLevelMenuLink({ to: string; children: React.ReactNode; }) { + const { pathname } = useLocation(); const gleanClick = useGleanClick(); + + const isActive = pathname.startsWith(to.split("#", 2)[0]); + return ( -
  • +
  • a { + &:link, + &:visited { + color: var(--text-active); + } + + &:hover, + &:active { + color: var(--category-color); + } + } + .top-level-entry-dot ~ .top-level-entry::after { background: var(--text-primary-blue); border: 1px solid var(--background-primary); diff --git a/client/src/ui/molecules/menu/index.tsx b/client/src/ui/molecules/menu/index.tsx index 86a39ea5447a..f89f90ec1440 100644 --- a/client/src/ui/molecules/menu/index.tsx +++ b/client/src/ui/molecules/menu/index.tsx @@ -1,3 +1,4 @@ +import { useLocation } from "react-router"; import { MENU } from "../../../telemetry/constants"; import { useGleanClick } from "../../../telemetry/glean-context"; import { MenuEntry, Submenu } from "../submenu"; @@ -5,20 +6,34 @@ import "./index.scss"; interface MenuProps { menu: MenuEntry; + isActive?: boolean; isOpen: boolean; toggle: (id: string) => void; } -export const Menu = ({ menu, isOpen, toggle }: MenuProps) => { +export const Menu = ({ + menu, + isActive = undefined, + isOpen, + toggle, +}: MenuProps) => { + const { pathname } = useLocation(); const gleanClick = useGleanClick(); const buttonId = `${menu.id}-button`; const submenuId = `${menu.id}-menu`; + isActive = + isActive ?? + (typeof menu.to === "string" && + pathname.startsWith(menu.to.split("#", 2)[0])); const hasAnyDot = menu.items.some((item) => item.dot); return ( -
  • +
  • {hasAnyDot && ( )} diff --git a/client/src/ui/molecules/plus-menu/index.tsx b/client/src/ui/molecules/plus-menu/index.tsx index 9c3d4be8909a..9455dc5011cb 100644 --- a/client/src/ui/molecules/plus-menu/index.tsx +++ b/client/src/ui/molecules/plus-menu/index.tsx @@ -5,6 +5,7 @@ import { useIsServer, useLocale, useViewedState } from "../../../hooks"; import { useUserData } from "../../../user-context"; import { MenuEntry } from "../submenu"; import { FeatureId } from "../../../constants"; +import { useLocation } from "react-router"; export const PlusMenu = ({ visibleSubMenuId, toggleMenu }) => { const plusUrl = usePlusUrl(); @@ -15,6 +16,13 @@ export const PlusMenu = ({ visibleSubMenuId, toggleMenu }) => { const { isViewed } = useViewedState(); + // Avoid that "Plus" and "AI Help" are both active. + const { pathname } = useLocation(); + const aiHelpUrl = `/${locale}/plus/ai-help`; + const isActive = + pathname.startsWith(plusUrl.split("#", 2)[0]) && + !pathname.startsWith(aiHelpUrl); + const plusMenu: MenuEntry = { label: "Plus", id: "mdn-plus", @@ -32,7 +40,7 @@ export const PlusMenu = ({ visibleSubMenuId, toggleMenu }) => { hasIcon: true, iconClasses: "submenu-icon", label: "AI Help (beta)", - url: `/${locale}/plus/ai-help`, + url: aiHelpUrl, }, ...(!isServer && isAuthenticated ? [ @@ -75,5 +83,12 @@ export const PlusMenu = ({ visibleSubMenuId, toggleMenu }) => { }; const isOpen = visibleSubMenuId === plusMenu.id; - return ; + return ( + + ); };