Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Persistent Menu Navigation a Sidebar #35142

Open
wants to merge 9 commits into
base: es/2sticky2furious
Choose a base branch
from

Conversation

AddisonDunn
Copy link
Contributor

Product Description

Jira: one and two.

This PR:

  • Turns the persistent menu navigation into a sidebar when on desktop, but remaining an overlay on mobile
  • To accomplish the bullet above, I needed to "lock" the main content container, so that scrolling happens on the content container instead of the entire page. This way the persistent menu and the other content can be separately scrollable.
  • Removes the data preview bar on mobile
  • Removes the gray background around forms on mobile

To see what I mean by "locked" and "separately scrollable", see this video:
https://github.com/user-attachments/assets/eed7edaf-1036-4fb0-a705-16e4f3847a57

Gray background removed on mobile:
Screenshot 2024-09-18 at 4 03 01 PM

Technical Summary

I made some key changes to margins and the underlying DOM layout of web apps that I am hoping will be more of a boon than a burden.

Safety Assurance

Safety story

  • Everything looks good with testing locally: main app selection screen, case list screen with case tiles and map, form screen
  • This will go through QA

QA Plan

Going to go through QA, ticket TBD

Rollback instructions

  • This PR can be reverted after deploy with no further considerations

Labels & Review

  • Risk label is set correctly
  • The set of people pinged as reviewers is appropriate for the level of risk of the change

@dimagimon dimagimon added Risk: High Change affects files that have been flagged as high risk. Risk: Medium Change affects files that have been flagged as medium risk. labels Sep 18, 2024
@dimagimon dimagimon removed the Risk: High Change affects files that have been flagged as high risk. label Sep 18, 2024
Copy link
Contributor

@nospame nospame left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you consider leaving the persistent nav as a regular Bootstrap offcanvas element and explicitly pushing over the main content on larger screens? Bootstrap provides options for the offcanvas both to not darken the background and to allow scrolling under it that could help make it possible. (demo and options)

The current implementation seems like it will probably work, but it's a pretty good chunk of code that might be mostly doable with built-in Bootstrap functionality.

Comment on lines +10 to +11
},
visible: !smallScreenIsEnabled(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this bit be done with Bootstrap using classes on the div instead? Something like:

<div id="instance-xml-home" class="debugger d-none d-lg-block"

Based on the examples here: https://getbootstrap.com/docs/5.0/utilities/display/#hiding-elements

@@ -47,7 +47,7 @@ <h1 class="title" data-bind="text: title, visible: !showInFormNavigation()"></h1
visible: showSubmitButton,
css: { 'sticky-submit': isAnchoredSubmitStyle },
style: {
'bottom':isAnchoredSubmitStyle && {{ request.couch_user.can_edit_data|yesno:'true,false' }} {% if environment != "web-apps" %} && false {% endif %} ? '30px' : '0' {# data preview bar #}
'bottom':isAnchoredSubmitStyle && !isAppPreview && !smallScreenIsEnabled && {{ request.couch_user.can_edit_data|yesno:'true,false' }}? '30px' : '0' {# data preview bar #}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to tie this to a single variable that gets at the point, if possible. So instead of all this logic the conditional would look something like isAnchoredSubmitStyle && showDataPreviewBar ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I faced a similar problem in #35069

The issue there is that breadcrumbs may or may not be present, and if they are, other elements need to be offset accordingly. What I ended up doing was having the breadcrumbs component set a has-breadcrumbs class on #cloudcare-main:

https://github.com/dimagi/commcare-hq/pull/35069/files#diff-59204083f0efa0e7d40586e28666900ebf9970de0550b5ffad1cd9f8fbc2c918R1329-R1335

Then I can offset other elements with just CSS without needing to replicate the set of circumstances that indicate whether that element is present:

https://github.com/dimagi/commcare-hq/pull/35069/files#diff-ff9b57d6462c3e8f90a3b6dbb35f575bd199ba487691cbeeca5a1b0d686dc986R7-R9

I was really hoping I'd be able to find a JS-free solution to that problem - where the element just takes up space on the page and automatically offsets the other element, based on the DOM structure. Couldn't find anything online that made it sound like that was possible with position: sticky; though.

Another perk of that approach is that this line could be replaced with SCSS, and you could use a reference to $minimized-debugger-height instead of a hardcoded 30px

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to tie this to a single variable that gets at the point, if possible. So instead of all this logic the conditional would look something like isAnchoredSubmitStyle && showDataPreviewBar ?

Yeah I agree, it's messy. My rationale for not doing what you suggested was that I'd have to import initial page data on the JS side to access the couch user data (I'm guessing you can access couch user data in JS?) so the messiness would just be in JS instead of HTML.

Comment on lines 111 to 112
<div id="sidebar-region" class="noprint-sub-container mt-3"></div>
<div id="content-container" class="container mt-3">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem equivalent to the margin removed from .case-tile-container, which I as far as I can tell would only have affected a single div as previously written (the <div id="persistent-case-tile" class="print-container">). Is that intentional?

Also noting that the separate print bottom margin for case-tile-container would probably give different results with this change, since the margin is applied differently.

@@ -11,6 +11,8 @@ formplayer, please make changes to the cloudcare styles.
**/

$breadcrumb-height-cloudcare: 36px;
$cloudcare-nav-height: 30px;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: know you didn't name this one, but it seems like we'd want to follow convention with $breadcrumb-height-cloudcare and call it $nav-height-cloudcare (or rename the breadcrumb variable if that seems better). Maybe a similar change for $minimized-debugger-height.

Comment on lines +4 to +5
<a id="persistent-menu-arrow-toggle"
type="button"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could this just be a button element instead?

@@ -42,6 +42,12 @@ body {
height: calc(100vh - #{$cloudcare-nav-height} - $breadcrumb-height-cloudcare);
}

#sidebar-and-content.remove-padding-on-mobile {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the class would be more accurately named remove-margins-on-mobile

@AddisonDunn
Copy link
Contributor Author

Did you consider leaving the persistent nav as a regular Bootstrap offcanvas element and explicitly pushing over the main content on larger screens?

@nospame "Pushing over the main content" is the approach currently taken in the codebase for the SSCS sidebar. Ethan proposes shifting from the more manual "push" approach to a flexbox approach instead in this PR (applying flex grow to the main content div, so that it naturally expands/contracts in response to changes in width of other elements in the same row). This PR sort of doubles-down on that idea, by making the persistent menu part of that flexbox layout instead of being an overlay. Since the desire of the request is to make the sidebar by default shown and to "take up space" in the DOM, this seemed best to me, instead of giving the sidebar an absolute position and "pushing the content over" like we were previously doing for the SSCS sidebar. Thus the choice of collapse over offcanvas, which seems more suitable for something that takes up space in the DOM.

Copy link
Contributor

@esoergel esoergel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a bunch of comments, mostly raising for discussion since I'm not certain how best to do a lot of this stuff - please don't take those as meaning "you must fix this."

@@ -7,7 +7,8 @@
'debugger-minimized': isMinimized,
'debugger-maximized': !isMinimized(),
'debugger-updating': updating
}
},
visible: !smallScreenIsEnabled(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is doable with bootstrap classes rather than needing JS:
https://getbootstrap.com/docs/5.0/utilities/display/#hiding-elements
Like, if you add d-none d-lg-block to the class a few lines up, I believe that will behave the same.

@@ -47,7 +47,7 @@ <h1 class="title" data-bind="text: title, visible: !showInFormNavigation()"></h1
visible: showSubmitButton,
css: { 'sticky-submit': isAnchoredSubmitStyle },
style: {
'bottom':isAnchoredSubmitStyle && {{ request.couch_user.can_edit_data|yesno:'true,false' }} {% if environment != "web-apps" %} && false {% endif %} ? '30px' : '0' {# data preview bar #}
'bottom':isAnchoredSubmitStyle && !isAppPreview && !smallScreenIsEnabled && {{ request.couch_user.can_edit_data|yesno:'true,false' }}? '30px' : '0' {# data preview bar #}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this style offsets the submit button if the data preview bar is present? That seems brittle (I know you didn't add it) - any idea how tricky it'd be to structure the DOM such that this is unnecessary?

@@ -82,7 +82,7 @@

<div id="cloudcare-main" class="cloudcare-home-content">
<section id="cases"></section>
<div id="menu-container">
<div id="main-container">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -47,7 +47,7 @@ <h1 class="title" data-bind="text: title, visible: !showInFormNavigation()"></h1
visible: showSubmitButton,
css: { 'sticky-submit': isAnchoredSubmitStyle },
style: {
'bottom':isAnchoredSubmitStyle && {{ request.couch_user.can_edit_data|yesno:'true,false' }} {% if environment != "web-apps" %} && false {% endif %} ? '30px' : '0' {# data preview bar #}
'bottom':isAnchoredSubmitStyle && !isAppPreview && !smallScreenIsEnabled && {{ request.couch_user.can_edit_data|yesno:'true,false' }}? '30px' : '0' {# data preview bar #}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I faced a similar problem in #35069

The issue there is that breadcrumbs may or may not be present, and if they are, other elements need to be offset accordingly. What I ended up doing was having the breadcrumbs component set a has-breadcrumbs class on #cloudcare-main:

https://github.com/dimagi/commcare-hq/pull/35069/files#diff-59204083f0efa0e7d40586e28666900ebf9970de0550b5ffad1cd9f8fbc2c918R1329-R1335

Then I can offset other elements with just CSS without needing to replicate the set of circumstances that indicate whether that element is present:

https://github.com/dimagi/commcare-hq/pull/35069/files#diff-ff9b57d6462c3e8f90a3b6dbb35f575bd199ba487691cbeeca5a1b0d686dc986R7-R9

I was really hoping I'd be able to find a JS-free solution to that problem - where the element just takes up space on the page and automatically offsets the other element, based on the DOM structure. Couldn't find anything online that made it sound like that was possible with position: sticky; though.

Another perk of that approach is that this line could be replaced with SCSS, and you could use a reference to $minimized-debugger-height instead of a hardcoded 30px

<div class="offcanvas-header persistent-menu-max-width d-flex align-items-center justify-content-between">
<div id="persistent-menu-container" class="bg-white h-100 position-relative overflow-scroll"
aria-labelledby="persistent-menu-label">
<button type="button" id="close-button" class="btn-close text-reset position-absolute"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#close-button might be too generic a term, risking conflict with other elements on the page

Comment on lines +1579 to +1580
onDomRefresh: function () {
this.handleSmallScreenChange(cloudcareUtils.smallScreenIsEnabled());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of curiosity, why is this in onDomRefresh rather than onRender or initialize?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the HTML elements can be referenced using jQuery in onRender or initialize, at least that was the case with my testing. But actually onAttach might be more appropriate, being just earlier in the lifecycle, and I see that it being used in such a way elsewhere in the file.

<section id="cloudcare-notifications" class="container notifications-container"></section>
<div class="container case-tile-container">
<div id="persistent-case-tile" class="print-container"></div>
</div>
<div class="d-lg-flex">
<div id="sidebar-region" class="noprint-sub-container mt-3"></div>
<div id="content-container" class="container mt-3">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this container is necessary to prevent wide elements from overflowing the div. That was the issue addressed by 177ccc7

I see you put a max-width on the element, which should probably address that, though does that also work well on smaller screen sizes?

@@ -306,6 +307,7 @@ hqDefine("cloudcare/js/formplayer/app", [
var sess = WebFormSession.WebFormSession(data);
sess.renderFormXml(data, $('#webforms'));
$('.menu-scrollable-container').addClass("d-none");
$('#sidebar-and-content').addClass('remove-padding-on-mobile');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this really have to apply only to form entry? Wondering if we could instead remove the padding on mobile for everything. Or if say menus do need padding, then maybe that could be part of the menu definition.

@@ -1561,6 +1561,9 @@ hqDefine("cloudcare/js/formplayer/menus/views", [
} else {
$('#persistent-menu-container').removeClass(containerMobileClasses);
$('#persistent-menu-container').addClass(containerDesktopClasses);
if (sessionStorage.showPersistentMenu !== 'false') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nospame
Copy link
Contributor

nospame commented Oct 1, 2024

This PR sort of doubles-down on that idea, by making the persistent menu part of that flexbox layout instead of being an overlay. Since the desire of the request is to make the sidebar by default shown and to "take up space" in the DOM, this seemed best to me, instead of giving the sidebar an absolute position and "pushing the content over" like we were previously doing for the SSCS sidebar.

This makes sense within the existing context, but I think it's worth considering/remembering that Bootstrap is really explicitly mobile-first. So by designing this as a web-first feature, this approach is basically working against Bootstrap instead of using it to our advantage. I don't know enough about the particular feature to say if I think it's the wrong way to go about things here, but I think it's important to have the discussion about whether it is the right approach (and maybe USH devs have already done that and I'm late to the party).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Risk: Medium Change affects files that have been flagged as medium risk.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants