facebook / docusaurus

Easy to maintain open source documentation websites.
https://docusaurus.io
MIT License
55.03k stars 8.25k forks source link

Allow access to frontmatter in child pages from a category index page. #6590

Closed cassieevans closed 2 years ago

cassieevans commented 2 years ago

Have you read the Contributing Guidelines on issues?

Description

Ability to access frontmatter data from within child pages in order to dynamically create detailed tables or lists in category index pages.

Has this been requested on Canny?

https://docusaurus.io/feature-requests/p/access-to-docs-metadata-from-individual-doc-pages

Motivation

When creating docs it's common for libraries to have lists of properties and methods that they wish to detail on an overview page as well as in their own individual pages.

It would allow for the markdown files to be a single source of truth for each method or property and for the details to be surfaced elsewhere without duplication and fear of accidental documentation errors.

example documentation table

API design

We would add arbitrary frontmatter in markdown files. The name doesn't matter as much as the values returned.

Example of child frontmatter

---
title: .data
params: boolean:string
summary: some details
---

Then access that data in a parent markdown file (much like useCurrentSidebarCategory)

import {useChildData} from '@docusaurus/theme-common';

// use data in component
<Table items={useChildData().items}/>

// example of custom component
export default function Table({ items }) {
  console.log(items);
  return (
    <tbody>
      {items.map((item) => (
        <tr>
          <td>{item.title}</td>
          <td>{item.params}</td>
          <td>{item.summary}</td>
        </tr>
      ))}
    </tbody>
  );
}

To create tables of data from children.

Screenshot 2022-02-02 at 18 51 19

In an ideal world we would be able to access pages in subfolders as well as direct children.

example structure

index.md

properties folder property.md property2.md property3.md methods folder method.md method2.md method3.md

Have you tried building it?

I attempted using the useCurrentSidebarCategory hook, but it doesn't provide any frontmatter data for the items returned. In addition it only allows for access to direct children.

(apologies if this is the wrong place for this issue - I will happily move to canny, following instructions from @slorber on this issue but I may have misunderstood where to raise it.

Self-service

slorber commented 2 years ago

@cassieevans the thing is we want to keep the size of the pages small, so we don't necessarily want ALL metadatas of ALL docs to be available everywhere

Some Docusaurus sites have thousands of docs (for example: https://xsoar.pan.dev/docs/reference/index) and we don't want that any doc page can access all the frontmatter of all the docs everywhere, at least not by default because this would be an additional perf problem for those very large sites.

Something that is already shared between a whole set of docs: the sidebar. It's also what defines the order (and you probably need an order for your table, similar to the order in which items appear in the sidebar)

That's why I suggested that we use something more explicit, based on the customProps attribute of each sidebar items:

---
title: Set
description: The Set method API

sidebar_custom_props: 
  method: set
  params: boolean:string
  summary: xyz
---

If you don't explicitly define the front matter that is relevant to be shared, this means we need to share all frontmatter by default. IE many Docusaurus sites will become heavier while they won't necessarily need this feature. Unlike Eleventy, we are not building just HTML files at build time. We use React/SPA and need to send some JS bundles with those data to the client.

Note that it may not be a big deal for you in the future because we are preparing an API to create/transform the existing frontmatter.

https://github.com/facebook/docusaurus/issues/5568 https://github.com/facebook/docusaurus/pull/5972

Somehow you'd be able to automatically copy frontMatter.description to frontMatter.customProps.description if this makes sense to be able to retrieve the description in category index, without the need to write customProps in the real md file.

Considering this, I don't think we need a new useChildData(), and useCurrentSidebarCategory() remains good enough

In addition it only allows for access to direct children.

That's not totally true, each item returned has an items: [subitems] attribute that you can use recursively if you want to render the whole tree depth. We only render the 1st level but all the tree is available in this data.

cassieevans commented 2 years ago

That's why I suggested that we use something more explicit, based on the customProps attribute of each sidebar items:

---

title: Set
description: The Set method API

sidebar_customProps: 
  method: set
  params: boolean:string
  summary: xyz
---

This looks ideal. I also see how to access further down the tree now! Apologies for not picking up on that sooner.

I'm quite new to raising issues like this - does this exchange mean it's something that you may add? How do I follow the progress?

Thanks so much for your time Sébastien. Much appreciated

slorber commented 2 years ago

This looks ideal.

great 👍 let's do this then

I'm quite new to raising issues like this - does this exchange mean it's something that you may add? How do I follow the progress?

This is a feature request and can generally take some time to implement. You can track the linked PR as soon as someone opens it.

This feature request looks particularly easy to handle so it is likely to be done quite soon and we can assign it to someone willing to contribute. You should be able to test it as soon as the PR is merged, using the canary release.


Possible technical solution:

packages/docusaurus-plugin-content-docs/src/props.ts#toSidebarsProp

  const convertDocLink = (item: SidebarItemDoc): PropSidebarItemLink => {
    const docMetadata = getDocById(item.id);
    const {
      title,
      permalink,
      frontMatter: {sidebar_label: sidebarLabel},
    } = docMetadata;
    return {
      type: 'link',
      label: sidebarLabel || item.label || title,
      href: permalink,
      className: item.className,
--    customProps: item.customProps,
++    customProps: item.customProps ?? docMetadata.frontMatter.sidebar_custom_props,
      docId: docMetadata.unversionedId,
    };
  };
TheCatLady commented 2 years ago

I can take a swing at this!

cassieevans commented 2 years ago

Thanks so much folks. This has been a really lovely experience. I'm really looking forward to building our docs with docusaurus now.

slorber commented 2 years ago

can be tested in canary channel, let us know if it works fine