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

feat(theme-classic): new navbar item linking to a sidebar #6139

Merged
merged 26 commits into from
Jan 6, 2022

Conversation

lmpham1
Copy link
Contributor

@lmpham1 lmpham1 commented Dec 21, 2021

Motivation

This PR resolves #6117

Have you read the Contributing Guidelines on pull requests?

Yes.

Implementations

For the plugin-content-doc, I wrote 2 functions:

  • getFirstDocIdOfSidebar in plugin-content-doc/src/sidebars/utils.ts, which receives a Sidebar object and returns the docId of that object. If it's a category with autogenerated index, the slug of that index page will be returned instead.
  • toGlobalSidebar in plugin-content-doc/src/globalData.ts, which map the sidebar name and docId returned from getFirstDocIdOfSidebar function to a GlobalSidebar object, which is then attached to a GlobalVersion object in toGlobalVersion function

For theme-classic/src/theme/NavbarItem, I added a new item called DocSidebarNavbarItem that handle the new navbar item type. It does so by fetching the GlobalVersion object, and retrieve its GlobalSidebar data that already contain a GlobalSidebarLink pointing to its first document

Test Plan

To test my changes, I modified the sidebar and navbar objects in the docusaurus.config.js and sidebar.js files in /website/. These changes are not included in this PR, but I have created a separate test branch on my fork with these changes so that you can test it there.

The detailed changes:

//docusaurus.config.js
navbar: {
  ...
  items: [
    { // test sidebar with a category as first item
      type: 'docSidebar',
      position: 'left',
      id: 'docs',
      label: 'Docs',
    },
    { // test sidebar with a doc as first item
       type: 'docSidebar',
       position: 'left',
       id: 'api',
       label: 'API',
    },
  ...
  ]
}
//sidebar.js
const sidebars = {
  docs: [
    // 'introduction', commented out so that first item would be category with generated-index link
    {
      type: 'category',
      label: 'Getting Started',
      link: {
        type: 'generated-index',
      },
      collapsed: false,
      items: [
        ...
      ],
    },
  api: [ //no changes here, first item is a doc
    'cli',
    'docusaurus-core',
    {
      type: 'autogenerated',
      dirName: 'api',
    },
  ],
}

I also created a demo video with the exact changes above: https://youtu.be/BtJ3306urjI

I also tested category with a doc link, as well as without a category link object, and they also seem to be working.

Related PRs

Might require updating the documentation to include this new feature if this PR is merged.

Feel free to let me know if you want any changes to be made!

…lSidebar() function and getFirstDocIdOfSidebar() function, modified GlobalVersion and toGlobalVersion
…em with 'docSidebar' type, added validation in validateThemeConfig.ts
…where it didn't work with undefined category link object
@facebook-github-bot facebook-github-bot added the CLA Signed Signed Facebook CLA label Dec 21, 2021
@netlify
Copy link

netlify bot commented Dec 21, 2021

✔️ [V2]
Built without sensitive environment variables

🔨 Explore the source changes: bcd01a9

🔍 Inspect the deploy log: https://app.netlify.com/sites/docusaurus-2/deploys/61d6b982fd35090007725ff4

😎 Browse the preview: https://deploy-preview-6139--docusaurus-2.netlify.app

@github-actions
Copy link

github-actions bot commented Dec 21, 2021

⚡️ Lighthouse report for the changes in this PR:

Category Score
🟠 Performance 81
🟢 Accessibility 98
🟢 Best practices 100
🟢 SEO 100
🟢 PWA 95

Lighthouse ran on https://deploy-preview-6139--docusaurus-2.netlify.app/

@Josh-Cena Josh-Cena changed the title <feat>(theme-classic, content-docs): Link a navbar item to a sidebar's first item feat(theme-classic): new navbar item linking to a sidebar Dec 21, 2021
@Josh-Cena Josh-Cena added the pr: new feature This PR adds a new API or behavior. label Dec 21, 2021
Copy link
Collaborator

@Josh-Cena Josh-Cena left a comment

Choose a reason for hiding this comment

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

Hey, thanks for the amazing work done! The tests you've made have made the review so much easier. The comments are mostly about code style.

Could you also add unit tests for the getFirstDocIdOfSidebar function, and update the existing test snapshots?

Also, we can test this on our website. The API item can be linking to the api sidebar.

I'll be working on this for now

@Josh-Cena Josh-Cena added the status: awaiting review This PR is ready for review, will be merged after maintainers' approval label Dec 21, 2021
@Josh-Cena
Copy link
Collaborator

Our current implementation differs slightly from what @slorber envisioned in that issue. The global data is set as {[sidebarId: string]: {link: string}} because the label can be set on every navbar item and fall back to the sidebar ID, so a plain string would work.

@Josh-Cena
Copy link
Collaborator

@lmpham1 Thanks! Now it's just docs left. You can just go add docs in this PR instead of creating a new one.

@lmpham1
Copy link
Contributor Author

lmpham1 commented Dec 22, 2021

@Josh-Cena hey, I just added the documentation for our new navbar item type in website/docs/api/themes/theme-configuration. Feel free to let me know if I need to change anything, or if I should add more examples for category cases.

Copy link
Collaborator

@Josh-Cena Josh-Cena left a comment

Choose a reason for hiding this comment

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

LGTM! Waiting on @slorber since I did change the API design a bit

Copy link
Collaborator

@slorber slorber left a comment

Choose a reason for hiding this comment

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

Thanks, that looks like a good first version!

There are a few issues that we should fix before merging.

What about dogfooding this feature on our own site? We can replace our docs/api tabs by this new navbar items, this would help to review/validate it works fine

packages/docusaurus-plugin-content-docs/src/globalData.ts Outdated Show resolved Hide resolved
@@ -266,6 +276,45 @@ Available document ids are:
}
}

function getFirstDocOfSidebar(sidebar: Sidebar):
Copy link
Collaborator

Choose a reason for hiding this comment

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

What about refactor to following signature?

function findFirstLink(sidebar: Sidebar): {label: string, path: string} | undefined

Copy link
Contributor Author

@lmpham1 lmpham1 Dec 30, 2021

Choose a reason for hiding this comment

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

So to make this function return the doc's path, I passed into it a LoadedVersion object to look up the doc's permalink:

function findFirstLink(sidebar: Sidebar, version: LoadedVersion): { label: string; path: string } | undefined

I just refactored the function in my recent commit. Let me know if you think this is a good approach, or if you think it's a bit overkill to pass LoadedVersion into this function.

Copy link
Collaborator

@Josh-Cena Josh-Cena Jan 2, 2022

Choose a reason for hiding this comment

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

I think it's overkill. Passing in such a big entity makes this function very hard to reason about and optimize in the future. I prefer the initial implementation: the return type is a bit complicated, but it's lightweight and easy to be piped into other processing.

I reverted that refactor commit. Sorry for this but I do have some opinions on what sidebarUtils should do. It should strictly be a pure function operating on the sidebar and nothing else. Hooking into the version information is always overkill and should be done where it's actually needed.

packages/docusaurus-plugin-content-docs/src/types.ts Outdated Show resolved Hide resolved
packages/docusaurus-plugin-content-docs/src/globalData.ts Outdated Show resolved Hide resolved
{...props}
className={clsx(props.className, {
[activeDocInfimaClassName]:
activeDoc?.sidebar && activeDoc.sidebar === sidebarId,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
activeDoc?.sidebar && activeDoc.sidebar === sidebarId,
activeDoc?.sidebar === sidebarId,

Should be fine considering sidebarId is mandatory

Copy link
Collaborator

Choose a reason for hiding this comment

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

Wonder if the item would be highlighted when we browse a category index 🤪

@@ -15,11 +15,19 @@ import {useDocsPreferredVersion, uniq} from '@docusaurus/theme-common';
import type {GlobalDataVersion} from '@docusaurus/plugin-content-docs';

function getSidebarInVersion(versions: GlobalDataVersion[], sidebarId: string) {
const allSidebars = versions.flatMap((version) => version.sidebars);
const allSidebars = versions.map((version) => version.sidebars);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd rather use a flat 1-level array here. You can create an array of sidebar entries [sidebarId,sidebar]

  const allSidebars = versions.flatMap((version) => Object.entries(version.sidebars));

This makes the following code simpler:

const sidebarEntry = allSidebars.find((sidebarEntry) => sidebarEntry[0] === sidebarId)

return sidebarItem ? sidebarItem[1] : undefined;
}
return undefined;
})[0];
Copy link
Collaborator

Choose a reason for hiding this comment

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

that does not look like a good algo to me (result might not be at index 0, at least you'd want to "compact" the array and remove undefined values) and this is too complex to read. See my suggestion above

@Josh-Cena Josh-Cena removed the status: awaiting review This PR is ready for review, will be merged after maintainers' approval label Dec 30, 2021
Copy link
Collaborator

@slorber slorber left a comment

Choose a reason for hiding this comment

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

Looks almost good, just minor changes 👍

exact
{...props}
className={clsx(props.className, {
[activeDocInfimaClassName]: activeDoc?.sidebar === sidebarId,
Copy link
Collaborator

Choose a reason for hiding this comment

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

oops, this does not work with "generated index", but it's not a problem with current PR, see #6268

We can solve this separately

website/docs/api/themes/theme-configuration.md Outdated Show resolved Hide resolved
@slorber
Copy link
Collaborator

slorber commented Jan 6, 2022

LGTM, thanks !

@slorber slorber merged commit eade41a into facebook:main Jan 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed Signed Facebook CLA pr: new feature This PR adds a new API or behavior.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Ability to link navbar to a given sidebar
4 participants