Skip to content

Commit

Permalink
feat(menu): highlight active items (mdn#9940)
Browse files Browse the repository at this point in the history
* fix(plus): add hash to Plus url

* feat(menu): highlight current item

* chore(ui): introduce --text-active + use for active menu items

* chore(submenu): revert highlighting active item

* feat(menu): add isActive prop to override state

* fix(plus-menu): exclude AI Help from isActive state

* fix(main-menu): remove trailing slash from AI Help

* fix(menu): use category color on hover/active
  • Loading branch information
caugner authored Nov 24, 2023
1 parent 223e2a0 commit ecc9f54
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 7 deletions.
2 changes: 1 addition & 1 deletion client/src/plus/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export function usePlusUrl(): string {
let target = `/${locale}/plus`;

if (normalizedUrl(target) === normalizedUrl(pathname)) {
target = "#subscribe";
target += "#subscribe";
}

return target;
Expand Down
2 changes: 2 additions & 0 deletions client/src/ui/_vars.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions client/src/ui/base/_themes.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
9 changes: 7 additions & 2 deletions client/src/ui/molecules/main-menu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -83,7 +84,7 @@ export default function MainMenu({ isOpenOnMobile }) {
)}
<TopLevelMenuLink to="/en-US/blog/">Blog</TopLevelMenuLink>
<TopLevelMenuLink to={`/${locale}/play`}>Play</TopLevelMenuLink>
<TopLevelMenuLink to="/en-US/plus/ai-help/">
<TopLevelMenuLink to="/en-US/plus/ai-help">
AI Help <sup className="new beta">Beta</sup>
</TopLevelMenuLink>
</ul>
Expand All @@ -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 (
<li className="top-level-entry-container">
<li className={`top-level-entry-container ${isActive ? "active" : ""}`}>
<a
className="top-level-entry menu-link"
href={to}
Expand Down
12 changes: 12 additions & 0 deletions client/src/ui/molecules/menu/index.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
.top-level-entry-container {
&.active > 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);
Expand Down
19 changes: 17 additions & 2 deletions client/src/ui/molecules/menu/index.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,39 @@
import { useLocation } from "react-router";
import { MENU } from "../../../telemetry/constants";
import { useGleanClick } from "../../../telemetry/glean-context";
import { MenuEntry, Submenu } from "../submenu";
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 (
<li key={menu.id} className="top-level-entry-container">
<li
key={menu.id}
className={`top-level-entry-container ${isActive ? "active" : ""}`}
>
{hasAnyDot && (
<span className="visually-hidden top-level-entry-dot"></span>
)}
Expand Down
19 changes: 17 additions & 2 deletions client/src/ui/molecules/plus-menu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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",
Expand All @@ -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
? [
Expand Down Expand Up @@ -75,5 +83,12 @@ export const PlusMenu = ({ visibleSubMenuId, toggleMenu }) => {
};
const isOpen = visibleSubMenuId === plusMenu.id;

return <Menu menu={plusMenu} isOpen={isOpen} toggle={toggleMenu} />;
return (
<Menu
menu={plusMenu}
isActive={isActive}
isOpen={isOpen}
toggle={toggleMenu}
/>
);
};

0 comments on commit ecc9f54

Please sign in to comment.