<aside> 💡 Update: The priority is changed to low because I think that it's not a good idea anymore. First, nested sub-pages are outside of Notablog table, so it doesn't have properties that those pages in the table have, making it not manageable. Second, recursive traversal is dirty, since we don't know when will it stop and there is no consensus for on what condition it should stop. To keep Notablog's concept and consistent, it comes to me that, it's important to encourage users to consciously separate what's inside Notablog's scope and what's not. Therefore, a better model is that we require users to put the pages they want to be rendered in the table, and use "link to page" blocks, inline mention pages, or inline links to link to them, creating a "web of pages" inside one table.
</aside>
This feature requires changes in both Notablog and NAST, which effects the whole architecture, so it is considered a core change and must be planned carefully.
For context, Notablog now uses getOnePageAsTree()
from nast-util-from-notionapi
to get an intermediate representation (IR) of a Notion page, and renders that IR to HTML with renderToHTML()
from nast-util-to-react
.
nast-util-from-notionapi
In order to support nested sub-pages, first we need to know if there're other pages in a page. To get that information, we would modify getOnePageAsTree()
. Instead of returning only the IR, it would also return the id
s of the sub-pages inside the page it's processing.
For example, change the return value of getOnePageAsTree()
from NAST.Block
to
{
content: [NAST.Block](<https://github.com/dragonman225/nast/blob/04a345f334f8232c2627bc47d2db0141b199036a/packages/nast-types/index.d.ts#L12>),
subPages: [NAST.UUID](<https://github.com/dragonman225/nast/blob/04a345f334f8232c2627bc47d2db0141b199036a/packages/nast-types/util.d.ts#L34>)[]
}
To get the id
s of the sub-pages, one could collect them when converting the raw Notion page tree to the NAST IR (refer to this).
Once we can get the id
s of sub-pages, we can use getOnePageAsTree()
with the id
s to get IR of sub-pages. (Bonus: use TaskManager2
from @dnpr/task-manager
to queue the function calls and execute them concurrently, since inside getOnePageAsTree()
it makes many requests to Notion API so it is sloooow.) After getting IR of all top-level pages and their sub-pages, we use renderToHTML()
as usual to render them.
Finally, there is one last thing to do — handle the links between pages. In Notion, when we click a page block, Notion will bring us to that page. Likewise, when we click a page block in a static HTML generated by Notablog, we jump to another static HTML. Therefore, the goal is to map the links in Notion to the links in Notablog. We need a map. (Notablog should prepare such a map)
In Notion, internally it uses id
to link pages, and in Notablog, we use <a>
element with href
attribute to link two HTML files. So, the map would be in the form of
Map<NAST.UUID, string>
, where the string
is a path to the HTML file generated from the Notion page NAST.UUID
.
Then, we need to modify renderToHTML()
in nast-util-to-react
so that it is able to use the map to fill in correct href
attribute for the <a>
element in the Page
component.
The benefit of this approach is that renderToHTML()
would be flexible. For example, if someone not using Notablog wants to use renderToHTML()
to generate a single page and keep the sub-pages blocks linked to their original Notion pages, he/she would just need to provide a map in the same format as the above map, but where the string
is an URL of the Notion page NAST.UUID
.
Beside page blocks, inline links also can link to other Notion pages. However, handling them is more tricky. Inline links are part of SemanticString
, and it is used in so many blocks. Currently I'm not clear enough about how much the work is if we want to modify such a fundamental stuff, and I'm not confident enough to make the change now. So, it may be better that we just treat all these links as external links and keep them untouched for now.