-
Notifications
You must be signed in to change notification settings - Fork 133
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
Use portals for mobile site and page nav #1556
Conversation
@wxwxwxwx9 @jonahtanjz your reviews would be great here! Especially on possible alternative approaches. Per #1534 (comment), the old retrieval method won't work with ssr as the page is ssr-rendered (template / app information is lost). The overall approach is changed to use portals, powered by the portal-vue library. The main upside would be no network requests => html parsing, etc. Some alternatives considered:
Not too sure if there are methods to do this without backend coupling 🤔 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @ang-zeyu!
Just a brief review. I believe using portals is a good approach. I do not have any objection with that. I've noticed some regressions with the current implementation regarding the site and page navigation.
}; | ||
}, | ||
computed: { | ||
showPageNav() { | ||
return this.show && this.hasPageNav; | ||
return this.show && this.portalName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we need a separate variable to check for page nav as the identifier page-nav
can exist without a page nav.
For exmaple,
<nav id="page-nav" class="fixed-header-padding">
<div class="nav-component slim-scroll">
{{ pageNav }}
</div>
</nav>
The nav
element will always be present even if {{pageNav}}
is empty.
This is causing the page-nav-button
to show up on pages without page nav.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reverted temporarily
getPageNavContent() { | ||
const wrapper = document.createElement('div'); | ||
const pageNavTitle = document.getElementsByClassName('page-nav-title')[0]; | ||
const pageNavLinks = document.getElementById('mb-page-nav'); | ||
if (pageNavTitle) { | ||
wrapper.appendChild(pageNavTitle.cloneNode(true)); | ||
} | ||
if (pageNavLinks) { | ||
wrapper.appendChild(pageNavLinks.cloneNode(true)); | ||
} | ||
return wrapper; | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this method is still needed so that we can still pull in the page nav if the page-nav
identifier is not present? As discussed here, we should pull in the identifier first if they exist and if not, we should find the page nav and then pull that in.
Alternatively, we can also change the requirement such that users will have to explicitly specify the page nav with the identifier if that makes it better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this method is still needed so that we can still pull in the page nav if the page-nav identifier is not present? As discussed here, we should pull in the identifier first if they exist and if not, we should find the page nav and then pull that in.
I standardised this to a portal implementation as well
this.hasPageNav = document.getElementById('mb-page-nav') !== null; | ||
if (document.getElementById('page-nav') !== null) { | ||
this.portalName = 'page-nav'; | ||
} else if (document.getElementById('mb-page-nav') !== null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned above, page-nav
if present will always exist. As mb-page-nav
will only be present if a page nav is present, we can use this instead to check if the page-nav-button
should be shown.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reverted temporarily
}; | ||
}, | ||
computed: { | ||
showSiteNav() { | ||
return this.show && this.hasSiteNav; | ||
return this.show && this.portalName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to page nav
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also reverted temporarily
getSiteNavContent() { | ||
return document.getElementsByClassName('site-nav-root')[0]; | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to page nav (Should pull the first site nav if the identifier is not present).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also now using the portal implementation (more important here as <site-nav>
can contain interactive vue components)
this.hasSiteNav = document.getElementsByClassName('site-nav-root').length !== 0; | ||
if (document.getElementById('site-nav') !== null) { | ||
this.portalName = 'site-nav'; | ||
} else if (document.getElementsByClassName('site-nav-root').length !== 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to page nav
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reverted temporarily
const navMenu = this.$refs.navigationMenu; | ||
const buildNav = (navMenuItems) => { | ||
if (!navMenuItems) { return; } | ||
for (let i = 0; i < navMenuItems.childNodes.length; i += 1) { | ||
navMenu.appendChild(navMenuItems.childNodes[i].cloneNode(true)); | ||
} | ||
this.navMenuLoaded(); | ||
}; | ||
|
||
if (!this.hasIdentifier) { | ||
buildNav(this.getNavMenuContent()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the comment for page nav, we will need this to manually pull in the first site nav or the page nav if their identifiers are not present.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shifted to portals as well!
Thanks for the speedy review! @jonahtanjz ahh, my bad, I understand why that part of the code was structured as such now 🤣; I also missed the root issue with #1445 (comment) you brought up previously. I went with the spec described in the docs and the original post in implementing it this time. i.e. using MarkBind's auto generated
One option is to create new layouts in our docs without the empty Another is to add this to the spec. i.e.
This is also an option, and can simplify the implementation quite a bit. The downside is the user would then have to be aware of the additional need for Likewise for the site-nav. What do you think? @jonahtanjz |
Case-by-case illustration: Option 1: (my interpretation)
More work in that need to configure two layout sets. Option 2: (your interpretation)
More restrictive in that user must use MarkBind's auto generated Option 3: (new suggestion above)
Need to configure two layout sets. Simpler, implementation wise. Slightly less convenient (author must be aware of Likewise for the sitenav, but between |
@ang-zeyu is there any change from the user's POV? Is there a corresponding update to the user guide? |
The current PR goes by the user guide's description (option 1), but will need a restructure of the layouts (e.g. below). e.g. (option 1)
The netlify preview here shows what happens if one layout is stuck to -- mobile page nav button is still present even with an empty The previous implementation in #1445 abides by option 2 (I missed while reviewing the earlier PR); That will need a ug update of the feature description. It is more convenient however; Case in point the entire user guide is currently using only one layout file (https://raw.githubusercontent.com/MarkBind/markbind/master/docs/_markbind/layouts/userGuide.md). This is possible because empty The downside is MarkBind's site/auto generated page-nav ( |
One more alternative: Check if the This should bring the best of both options 1 & 2. |
Not sure if I understand the picture fully. I'll leave you guys to consider the author's POV as well and choose the best option. |
@ang-zeyu Option 1 seems to allow users to have more control and flexibility but also more things for them to take note of. This may be a little inconvenient on the user side?
This alternative sounds good as it reduces the need for the user to do extra work. I think the benefits of abstracting this process from the user exceed the downside (since it only occurs in rare situation and if we are clear in the ug, should be sufficient). |
Agreed! I wonder if there's an even more intuitive solution than looking for text though. 🤔 Documenting It also dosen't take care of such cases nicely. In this case option 2 might be even better:
Should we look So the documentation becomes: |
I think this is the most intuitive approach as a site nav and page nav should contain anchor tags. Having a mobile site nav or page nav that contains no links will not add much value to the users and will most likely not make a big difference if it is hidden from them.
How about |
👍, let's go with this then.
oops, meant I'll put this change up in a separate PR however so its clear this PR / commit is just for changing the background implemention.
I'll add back in the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just found a few more edge cases which may be causing some issues.
@@ -297,6 +297,8 @@ class NodeProcessor { | |||
|
|||
this.postProcessNode(node); | |||
|
|||
addSitePageNavPortal(node); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is not working when it is using the MarkBind's auto generated variable {{ pageNav }}
without the identifier, id="page-nav"
.
For example:
<nav class="fixed-header-padding">
<div class="nav-component slim-scroll">
{{ pageNav }}
</div>
</nav>
The links do not appear in the mobile page nav. It's showing a blank page nav.
I believe this is due to adding the site and page nav portal before the page nav is built. Inside index.js
of Page, the NodeProcessor's process method which contains addSitePageNavPortal
is called before the buildPageNav method, which means it will not be picked up by the portals method. Perhaps can shift addSitePageNavPortal
to after the page nav is built?
this.$nextTick(() => { | ||
$(this.$refs.navMenuContainer).find('a').on('click', this.toggleNavMenu); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've also noticed this strange behaviour where after clicking on a page nav's link, the overlay does not close.
For example on the Using Components page:
MarkBind.-.User.Guide_.Using.Components.-.Google.Chrome.2021-05-01.11-54-29.mp4
Notice how after clicking on some of the links, the url changes but the overlay does not close (only after 2-3 clicks then it closes). I'm not sure if this method is the one causing this issue.
Thanks for the catches! I've fixed both issues -- the first was a problem with where I found another undiscussed point with the previous implementation around the forwarding of styles / attributes however.
Adding 55cf54d alone which forwards said things makes the site nav go poof, as there is a media query for I wonder if we should
This can really go both ways. e.g. With forwarding, our user guide adds a thin grey bar on the right as expected, but might not be suitable for the mobile site nav. The author then has to override this by compositing Without, it breaks descendent selectors and the actual element's selectors. Wdyt? @jonahtanjz |
I think going with forwarding would make more sense as this will preserve as much of the original navigations as possible. We can add more default overrides if needed (so normal users would need to do as little work as possible) and the more advance users can customise the styling etc. I feel if we go without forwarding it will make it too restrictive and also break some of the selectors as mentioned. That's just my thought on this.
We can also remove this for the mobile navigations by default. |
toggleNavMenu() { | ||
if (!this.show) { | ||
toggleNavMenu(ev) { | ||
if (ev.target.tagName.toLowerCase() === 'a' || this.show) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (ev.target.tagName.toLowerCase() === 'a' || this.show) { | |
if (ev.target.tagName.toLowerCase() === 'a' && this.show) { |
I think this should be &&
so that the site nav title does not close the overlay when it is clicked?
MarkBind.-.User.Guide.-.Getting.Started.-.Google.Chrome.2021-05-01.19-11-21.mp4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed! Still ||
, but added some extra checks, &&
would disable the closing button.
👍, that's my preference as well. I've reverted those two commits for moving to another pr. The auto generated site/pagenav without the wrapper |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one more question. Other than that LGTM 👍
docs/_markbind/layouts/userGuide.md
Outdated
@@ -2,6 +2,7 @@ | |||
|
|||
<div id="flex-body"> | |||
<nav id="site-nav" class="fixed-header-padding"> | |||
<panel header="To test interactivity">Expanding and closing should work</panel> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
almost forgot 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
What is the purpose of this pull request?
4th item in #1534 (comment)
Overview of changes:
Change the retrieval to use portals https://portal-vue.linusb.org/guide/getting-started.html
<site-nav> / {{pageNav}} / id="site/page-nav"
)OverlaySource
(new) vue componentOverlay
retrieval to use portals instead, for<site-nav> / {{pageNav}} / id="site/page-nav"
Anything you'd like to highlight / discuss:
Testing instructions:
Manual testing needed
Proposed commit message: (wrap lines at 72 characters)
Use portals for mobile site and page nav
With Vue SSR implemented, site and page nav mobile overlays are unable
to retrieve the original page source describing the respective
navigation components.
This results in being unable to mount an interactive copy of said
components.
Let's change the mobile site and page nav overlays to use portals as
the content source instead.
Portal sources (site / page nav) are identified and created during
build time.
Checklist: ☑️