#3912 #3775 #3996 User profile secondary nav dropdown menu [acadia] (#3968)

* Add dropdown menu on enterprise and legacy mode
This commit is contained in:
Erin Song 2025-07-29 11:42:12 -07:00 committed by GitHub
parent ef0c9e700f
commit c2bb07e976
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 407 additions and 102 deletions

View file

@ -2,6 +2,34 @@
@use "cisa_colors" as *;
@use "base" as *;
$-add-icon: (
"name": "add",
"svg-height": 24,
"svg-width": 24,
"height": units(2),
);
$-remove-icon: (
"name": "remove",
"svg-height": 24,
"svg-width": 24,
"height": units(2),
);
$-expand-more-icon: (
"name": "expand_more",
"svg-height": 24,
"svg-width": 24,
"height": units(2.5),
);
$-expand-less-icon: (
"name": "expand_less",
"svg-height": 24,
"svg-width": 24,
"height": units(2.5),
);
// Define some styles for the .gov header/logo
.usa-logo button {
color: #{$dhs-dark-gray-85};
@ -65,6 +93,13 @@
transform: translateY(-50%);
}
}
button {
padding-top: 0;
padding-bottom: 0;
padding-left: 0;
color: #{$dhs-blue};
}
}
.usa-header--extended {
@ -117,10 +152,19 @@
.usa-nav-link,
.usa-nav-link:hover,
.usa-nav-link:active {
font-weight: font-weight('bold');
color: color('primary-lighter');
font-weight: bold;
font-size: 16px;
color: color('white');
}
// Submenu nav links have normal font weight
.usa-nav__submenu-item {
.usa-nav-link,
.usa-nav-link:hover,
.usa-nav-link:active {
font-weight: normal;
}
}
transform: translateY(20%); // shift secondary nav down to accommodate button dropdowns
}
> .usa-navbar {
// This is a dangerous override to USWDS, necessary because we have a tooltip on the logo
@ -134,3 +178,238 @@
.usa-nav-container--widescreen {
max-width: $widescreen-max-width !important;
}
.usa-nav__secondary-links {
line-height: line-height($theme-navigation-font-family, 2);
// Remove column gap to account for padding in secondary nav buttons
@include at-media($theme-header-min-width) {
column-gap: 0;
// Add divider between secondary nav items
li + li {
&::marker {
content: "|";
}
}
}
}
.usa-nav__secondary-item {
@include at-media($theme-header-min-width) {
.usa-nav-link-text {
vertical-align: middle;
}
a {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
}
// Override USWDS defaults
& + .usa-nav__secondary-item {
// Increase padding of secondary links to match button padding
padding-left: units(2) !important;
// Replace USWDS default border to accommodate button heights
border-left: 0 !important;
}
}
@include at-media-max($theme-header-min-width) {
@include nav-list("nav");
a {
@include u-padding-y(1.5);
}
}
}
// Dropdown menus on secondary nav
.usa-nav__secondary-menu {
// Until the $theme-header-width,
// use the usa-nav-list styles for the slide-in nav
@include at-media-max($theme-header-min-width) {
@include nav-list("nav");
a {
@include u-padding-y(1.5);
line-height: line-height($theme-navigation-font-family, 2);
}
}
// At $theme-header-width and wider...
@include at-media($theme-header-min-width) {
display: flex;
align-items: stretch;
}
// all nav items in the nav
.usa-nav__secondary-item {
a {
text-decoration: none;
}
}
// ...and their direct links
> a {
@include at-media($theme-header-min-width) {
line-height: line-height($theme-navigation-font-family, 2) !important;
padding: units(2);
align-items: center;
display: flex;
font-weight: font-weight("bold");
}
}
> button,
> a {
@include at-media($theme-header-min-width) {
height: 100%;
}
}
@include at-media($theme-header-min-width) {
span {
@include place-icon($-add-icon, "after");
font-weight: font-weight('bold');
color: color('white');
}
}
a {
@include at-media($theme-header-min-width) {
@include u-padding-y(1.5);
line-height: 1.1;
}
}
button,
.usa-accordion__button {
$button-vertical-offset: 53%; // XXX: Magic number
background-color: transparent;
color: var(--close-button-bg);
position: relative; // Anchor spans chevron pseudo element
font-weight: font-weight("normal");
font-size: 1rem;
line-height: 1.2;
margin-right: 0;
padding: units(1.5) units(2);
text-decoration: none;
width: 100%;
border-radius: 0;
@include at-media-max($theme-header-min-width) {
justify-content: flex-start;
&:hover {
background-color: var(--border-color);
color: #{$theme-color-primary};
}
a {
@include u-padding-y(1.5);
}
}
// Remove icon set from usa-accordion.
// Also removed in _usa-banner.scss.
&[aria-expanded],
&[aria-expanded]:hover {
background-image: none;
@media (forced-colors: active) {
&::before {
content: none;
}
}
}
span {
@include at-media($theme-header-min-width) {
display: inline-block;
margin-right: 0;
padding-right: units(2);
}
}
&[aria-expanded] {
span {
&::after {
position: absolute;
top: 50%;
right: 0;
transform: translateY(-50%);
}
}
}
&[aria-expanded="false"] {
span {
@include place-icon($-add-icon, "after");
&::after:hover {
background-color: color('white');
}
}
&::after:hover {
background-color: color('white');
}
@include at-media($theme-header-min-width) {
span {
@include place-icon($-expand-more-icon, "after");
&::after {
background-color: color('white');
right: units(1.5);
}
}
}
&:hover {
@include at-media($theme-header-min-width) {
span::after {
background-color: color('white');
@media (forced-colors: active) {
background-color: color('white');
}
}
}
}
}
&[aria-expanded="true"] {
span {
@include place-icon($-remove-icon, "after");
&::after {
position: absolute;
right: 0;
@media (forced-colors: active) {
background-color: white;
}
}
}
@include at-media($theme-header-min-width) {
background-image: none;
background-color: color("primary-darker");
color: white;
@include at-media($theme-header-min-width) {
span {
@include place-icon($-expand-less-icon, "after");
&::after {
right: units(1.5);
background-color: white;
@media (forced-colors: active) {
background-color: white;
}
}
}
}
}
}
}
}

View file

@ -14,14 +14,24 @@
<ul class="usa-nav__primary usa-accordion">
<li class="usa-nav__primary-item">
{% if user.is_authenticated %}
<span class="usa-nav__username ellipsis">{{ user.email }}</span>
</li>
<li class="usa-nav__primary-item">
{% url 'user-profile' as user_profile_url %}
{% url 'finish-user-profile-setup' as finish_setup_url %}
<a class="usa-nav-link {% if request.path == user_profile_url or request.path == finish_setup_url %}usa-current{% endif %}" href="{{ user_profile_url }}">
<span class="text-primary">Your profile</span>
</a>
<button
type="button"
class="usa-accordion__button usa-nav__link"
aria-expanded="false"
aria-controls="basic-nav-section-one"
aria-label="user-profile-menu"
>
<span class="usa-nav__username ellipsis">{{ user.email }}</span>
</button>
<ul id="basic-nav-section-one" class="usa-nav__submenu">
<li class="usa-nav__submenu-item">
{% url 'user-profile' as user_profile_url %}
{% url 'finish-user-profile-setup' as finish_setup_url %}
<a class="usa-nav-link {% if request.path == user_profile_url or request.path == finish_setup_url %}usa-current{% endif %}" href="{{ user_profile_url }}">
Your profile
</a>
</li>
</ul>
</li>
<li class="usa-nav__primary-item">
<a href="{% url 'logout' %}"><span class="text-primary">Sign out</span></a>

View file

@ -4,114 +4,130 @@
<header class="usa-header usa-header--extended">
<div class="usa-navbar usa-navbar--widescreen padding-x--widescreen">
{% include "includes/gov_extended_logo.html" with logo_clickable=logo_clickable %}
<button type="button" class="usa-menu-btn">Menu</button>
<button type="button" class="usa-menu-btn">Menu</button>
</div>
{% block usa_nav %}
<nav class="usa-nav" aria-label="Primary navigation">
<div class="usa-nav__inner usa-nav__inner--widescreen padding-x--widescreen">
<button type="button" class="usa-nav__close">
<img src="{%static 'img/usa-icons/close.svg'%}" role="img" alt="Close" />
</button>
<div class="usa-nav__secondary">
<ul class="usa-nav__secondary-links">
<li class="usa-nav__secondary-item">
<div class="usa-nav__inner usa-nav__inner--widescreen padding-x--widescreen">
<button type="button" class="usa-nav__close">
<img src="{%static 'img/usa-icons/close.svg'%}" role="img" alt="Close" />
</button>
<div class="usa-nav__secondary">
<ul class="usa-nav__secondary-links">
{% if user.is_authenticated %}
<span class="ellipsis usa-nav__username">{{ user.email }}</span>
</li>
<li class="usa-nav__secondary-item">
{% url 'user-profile' as user_profile_url %}
{% url 'finish-user-profile-setup' as finish_setup_url %}
<a class="usa-nav-link {% if path == user_profile_url or path == finish_setup_url %}usa-current{% endif %}" href="{{ user_profile_url }}">
Your profile
<li class="usa-nav__secondary-item">
<div class="usa-accordion">
<div class="usa-accordion__heading usa-nav__secondary-menu">
<button
class="usa-button usa-nav__link usa-accordion__button navmenu-dropdown-button"
id="user-profile-menu"
aria-controls="user-profile-submenu"
aria-expanded="false"
aria-label="user-profile-menu"
>
<span class="ellipsis usa-nav__username">{{ user.email }}</span>
</button>
</div>
<div id="user-profile-submenu" class="usa-nav__submenu">
<div class="usa-nav__submenu-item">
{% url 'user-profile' as user_profile_url %}
{% url 'finish-user-profile-setup' as finish_setup_url %}
<a class="usa-nav-link {% if path == user_profile_url or path == finish_setup_url %}usa-current{% endif %}" href="{{ user_profile_url }}">
Your profile
</a>
</div>
</div>
</div>
</li>
<li class="usa-nav__secondary-item">
<a class="usa-nav-link" href="{% url 'logout' %}">Sign out</a>
</li>
{% else %}
<li class="usa-nav__secondary-item">
<a class="usa-nav-link" href="{% url 'login' %}">Sign in</a>
</li>
{% endif %}
</ul>
</div>
<ul class="usa-nav__primary usa-accordion">
<li class="usa-nav__primary-item">
{% if has_any_domains_portfolio_permission %}
{% url 'domains' as url %}
{% else %}
{% url 'no-portfolio-domains' as url %}
{% endif %}
<a href="{{ url }}" class="usa-nav-link{% if path|is_domain_subpage %} usa-current{% endif %}">
Domains
</a>
</li>
<li class="usa-nav__secondary-item">
<a class="usa-nav-link" href="{% url 'logout' %}">Sign out</a>
{% else %}
<a class="usa-nav-link" href="{% url 'login' %}">Sign in</a>
{% endif %}
</li>
</ul>
</div>
<ul class="usa-nav__primary usa-accordion">
<li class="usa-nav__primary-item">
{% if has_any_domains_portfolio_permission %}
{% url 'domains' as url %}
{% else %}
{% url 'no-portfolio-domains' as url %}
{% endif %}
<a href="{{ url }}" class="usa-nav-link{% if path|is_domain_subpage %} usa-current{% endif %}">
Domains
</a>
</li>
<!-- <li class="usa-nav__primary-item">
<a href="#" class="usa-nav-link">
Domain groups
</a>
</li> -->
{% if has_organization_requests_flag %}
<li class="usa-nav__primary-item">
<!-- user has one of the view permissions plus the edit permission, show the dropdown -->
{% if has_edit_request_portfolio_permission %}
{% url 'domain-requests' as url %}
<button
type="button"
class="usa-accordion__button usa-nav__link{% if path|is_domain_request_subpage %} usa-current{% endif %}"
aria-expanded="false"
aria-controls="basic-nav-section-two"
>
<span>Domain requests</span>
</button>
<ul id="basic-nav-section-two" class="usa-nav__submenu">
<li class="usa-nav__submenu-item">
<a href="{{ url }}"
><span>Domain requests</span></a
>
</li>
<li class="usa-nav__submenu-item">
<a href="{% url 'domain-request:start' %}"
><span>Start a new domain request</span></a
>
</li>
</ul>
<!-- user has view but no edit permissions -->
{% elif has_any_requests_portfolio_permission %}
{% url 'domain-requests' as url %}
<a href="{{ url }}" class="usa-nav-link{% if path|is_domain_request_subpage %} usa-current{% endif %}">
Domain requests
</a>
<!-- user does not have permissions -->
{% else %}
{% url 'no-portfolio-requests' as url %}
<a href="{{ url }}" class="usa-nav-link{% if path|is_domain_request_subpage %} usa-current{% endif %}">
Domain requests
</a>
{% endif %}
</li>
{% endif %}
{% if has_organization_members_flag %}
{% if has_view_members_portfolio_permission %}
{% if has_organization_requests_flag %}
<li class="usa-nav__primary-item">
<a href="{% url 'members' %}" class="usa-nav-link {% if path|is_members_subpage %} usa-current{% endif %}">
Members
</a>
<!-- user has one of the view permissions plus the edit permission, show the dropdown -->
{% if has_edit_request_portfolio_permission %}
{% url 'domain-requests' as url %}
<button
type="button"
class="usa-accordion__button usa-nav__link{% if path|is_domain_request_subpage %} usa-current{% endif %}"
aria-expanded="false"
aria-controls="basic-nav-section-two"
>
<span>Domain requests</span>
</button>
<ul id="basic-nav-section-two" class="usa-nav__submenu">
<li class="usa-nav__submenu-item">
<a href="{{ url }}"
><span>Domain requests</span></a
>
</li>
<li class="usa-nav__submenu-item">
<a href="{% url 'domain-request:start' %}"
><span>Start a new domain request</span></a
>
</li>
</ul>
<!-- user has view but no edit permissions -->
{% elif has_any_requests_portfolio_permission %}
{% url 'domain-requests' as url %}
<a href="{{ url }}" class="usa-nav-link{% if path|is_domain_request_subpage %} usa-current{% endif %}">
Domain requests
</a>
<!-- user does not have permissions -->
{% else %}
{% url 'no-portfolio-requests' as url %}
<a href="{{ url }}" class="usa-nav-link{% if path|is_domain_request_subpage %} usa-current{% endif %}">
Domain requests
</a>
{% endif %}
</li>
{% endif %}
{% endif %}
<li class="usa-nav__primary-item">
{% url 'organization' as url %}
<!-- Move the padding from the a to the span so that the descenders do not get cut off -->
<a href="{{ url }}" class="usa-nav-link padding-y-0 {% if path|is_portfolio_subpage %} usa-current{% endif %}">
<span class="ellipsis ellipsis--23 ellipsis--desktop-50 padding-y-1 desktop:padding-y-2">
{{ portfolio.organization_name }}
</span>
</a>
</li>
</ul>
</div>
{% if has_organization_members_flag %}
{% if has_view_members_portfolio_permission %}
<li class="usa-nav__primary-item">
<a href="{% url 'members' %}" class="usa-nav-link {% if path|is_members_subpage %} usa-current{% endif %}">
Members
</a>
</li>
{% endif %}
{% endif %}
<li class="usa-nav__primary-item">
{% url 'organization' as url %}
<!-- Move the padding from the a to the span so that the descenders do not get cut off -->
<a href="{{ url }}" class="usa-nav-link padding-y-0 {% if path|is_portfolio_subpage %} usa-current{% endif %}">
<span class="ellipsis ellipsis--23 ellipsis--desktop-50 padding-y-1 desktop:padding-y-2">
{{ portfolio.organization_name }}
</span>
</a>
</li>
</ul>
</div>
</nav>
{% endblock %}
</header>