FormidableLabs / formidable-oss-landers

MIT License
2 stars 0 forks source link

Architecture Discussion #12

Open boygirl opened 4 years ago

boygirl commented 4 years ago

How will library authors put this all together?

Goals

Flexibility - library authors should be able to add pages and data without breaking things. The landers all have slightly different data architecture, and the tool should be flexible enough to accomodate it.

Ease of use - From a small number of configuration files and helpers, library authors should be able to assemble a static site that just works without too many gotchas.

boygirl commented 4 years ago

proposed solution

This tool will expose a set of page templates that have consistent, clear data requirements and let library authors provide the data they need. This tool will also provide a set of markdown helpers that library authors can use in the majority of cases.

Library authors will be responsible for gluing all the pieces together in static.config.js, and will use getRoutes directly rather than relying on plugins. So something like this:

import path from "path";

import Document from "./src/html";
import metadata from "./src/constants";
import config from "./src/config"

import { IndexPage, DocsPage, getMarkdownPages, createTOC } from "formidable-oss-landers"

export default {
  paths: {
    src: "src",
    ...
  },
  plugins: [
    require.resolve("react-static-plugin-styled-components"),
    require.resolve("react-static-plugin-react-router"),
  ],
  Document,
  getRoutes: async () => {
    const docsPages = getMarkdownPages("./content/docs");
    const recipePages = getMarkdownPages("./content/recipes");
    const TOC = createTOC([...docsPages, ...recipePages]);
    return [
      {
        path: "/",
        template: IndexPage, // might need to have an intermediate copy
        getData: () => ({ config })
      },
      {
        path: "/docs",
        template: DocsPage,
        getData: () => ({ data: docsPages[0].data, config, TOC }),
        children: docsPages.slice(1).map((doc, i) => {
          return {
            path: `/${doc.title}`,
            getData: () => ({ data: doc.data, config, TOC }),
            template: DocsPage
          };
        })
      }
    ]
  },
  getSiteData: () => ({
    title: metadata.title,
  }),
};
treyhoover commented 4 years ago

@paulathevalley and @boygirl

Any thoughts on how we should structure the TOC object? I found this library, which seems promising. Not sure if we'd want something like that to handle the rendering as well or if we just want the json.

paulathevalley commented 4 years ago

@treyhoover I don't have any ideas on the structure. I'm sure it's possible to create a component that can turn whatever structure it is into nested lists. Just need to know what nests where.

I'm not really sure how to evaluate a library. What are the pros/cons? Does it make your life easier? How does it handle various types of nested directories? Would it help to look up examples of how markdown files are currently nested and mimic them in your example? idk if this is all stuff you already know or if it's helping...

treyhoover commented 4 years ago

@paulathevalley It seems promising so far. I'm basically just using it to parse a single document with various headings and subheadings into some structured json. I'll keep playing with it and see how it handles a real-world example.

boygirl commented 4 years ago

Here's a kind of ugly thing we did with remark for victory-docs, but this is more for the headings TOC than the file / directory based TOC. https://github.com/FormidableLabs/victory/blob/main/docs/static-config-helpers/get-md-files.js#L40

boygirl commented 4 years ago

In general I think whatever we use should just be for handling the data, and leave the rendering up to the component. I think the TOC is one of the places where the docs might diverge the most, and it would be great to give library authors the change to mutate the TOC data early. What do you think about a format like this:

[
  { title: "Components", depth: 2 }, // I'm not a link, just a heading
  { title: "VictoryArea", slug: "/docs/victory-area", depth: 3 },
  ...
]
treyhoover commented 4 years ago

My only concern with that structure is it might be a little tricky to render. I was leaning toward something like this:

{
  "name": "file-name.md",
  "depth": 0,
  "slug": "file-name",
  "link": "/docs/file-name",
  "children": [
    {
      "name": "An H1 Heading",
      "depth": 1,
      "slug": "an-h1-heading",
      "link": "/docs/file-name#an-h1-heading",
      "children": [
        {
          "name": "An H2 Heading",
          "depth": 2,
          "slug": "an-h2-heading",
          "link": "/docs/file-name#an-h2-heading",
          "children": []
        },
        {
          "name": "Another H2 Heading",
          "depth": 2,
          "slug": "another-h2-heading",
          "link": "/docs/file-name#another-h2-heading",
          "children": []
        },
        {
          "name": "A Third H2 Heading",
          "depth": 2,
          "slug": "a-third-h2-heading",
          "link": "/docs/file-name#a-third-h2-heading",
          "children": []
        }
      ]
    },
    {
      "name": "Another H1 Heading",
      "depth": 1,
      "slug": "another-h1-heading",
      "link": "/docs/file-name#another-h1-heading",
      "children": [
        {
          "name": "An H2 Heading",
          "depth": 2,
          "slug": "an-h2-heading",
          "link": "/docs/file-name#an-h2-heading",
          "children": []
        }
      ]
    }
  ]
}

I threw together a quick parser that generates that structure without any libraries, since I think a recursive List component might be simpler with this nested structure than working with a flat array. What do you think, @paulathevalley ?

boygirl commented 4 years ago

You're right, that looks better. Two other mior things to consider. 1) there should be a way to limit the depth of what ends up in the sidebar 2) There should be a way to alter the order of the children, maybe via a field in the yaml?

treyhoover commented 4 years ago

Setting a max depth should be easy enough! This structure is just for the individual file, so that order should be fine based on the order of the headings themselves. But when combining multiple markdown files, I just have it sorting via the order property in the yaml front-matter of each file 🙂

boygirl commented 4 years ago

Perfect!