We have quite a lot of issues related to sections configuration, especially the new sectionDepth option. It seems hard to understand (and honestly I don't understand it too).
@okonet @bebraw @rafaesc How can we improve this API? It would probably make more sense to have an option on each section that will define whether this section should be rendered with all subsections or not. But I don't have enough experience with pagePerSection option to say much.
Related issues: #1139 #1137 #1058
My suggestion still stands: https://github.com/styleguidist/react-styleguidist/issues/892#issuecomment-381612404
Although I'd probably change the name to something more clear. Ideas?
@okonet's approach looks good. The nice thing is that although it's verbose, the users can program a lot of that away in their config. That's what I've ended up doing myself.
I wonder if recursive definition would make sense. Then you could do sections inside sections.
Yeah, I like it too! I think codeSamples and propsMethods are already working this way, so we should make separatePage work the same way.
After thinking about it a bit more I think the root problem is with naming of sections. Also the fact that components property "generates" sections per component makes the whole more complex.
What if instead of bolting this on top of current structure we would introduce pages concept to styleguidist? Pages would become distinguished and uniq URLs automatically. Example:
module.exports = {
// Each page gets its own URL
pages: [{
name: 'Documentation & Examples',
slug: 'documentation', // optional
// Sections are just anchors inside the page?
sections: [
{
name: 'Design tokens',
content: 'docs/tokens.md',
codeSamples: 'hide',
propsMethods: 'hide',
},
{
name: 'UI Components',
components: '...',
},
{
name: 'UI Patterns',
components: '...',
}
]
}, {
name: 'About',
content: './about.md'
}]
}
Another thing I'm not sure in current design is also the difference between content and components which is very implicit (components will be added to content if both are provided).
To me the problem we're trying to solve is to make styleguidist into a web-site generator on steroids. Ultimately we could even use some other generator (like https://github.com/antwarjs/antwar) instead and only handle steroids part (components rendering, resoving etc.)?
Probably we should start with the ideal API and think this through?
I like the idea of starting from an ideal API, if we're going to make a breaking change anyway.
@sapegin do you have something in mind? What about my proposal with pages and sections? One problem I can see already is that it can be tricky to mix pages and sections inside one page for example...
I'm not really sure what's the difference between page and section ;-/
We can change the names if we feel they don’t fit but my idea was to distinguish between isolated pages and parts of one page (anchors)
I agree with separatePage approach, it will be easier to understand with a boolean flag.
Although I would like to standard the name of pages, sections, content and components.
@okonet So your idea is that the page is a separate route with a separate URL and pages can have sections inside and sections are headings with anchors inside a page? And we're replacing sections config option with pages? If my understanding is correct, then I like the idea ;-)
We'll need to fit external links somehow into this model.
I guess nicely implemented href option will do job well. Like that:
sections: [
{
name: 'Home',
content: './home.md',
href: '/' // Back to component's root
},
{
name: 'Visual',
href: '#visual', // Just in-document navigation
components: ...
},
{
name: 'Just a text, no action on click',
href: false // No action on click
}
]
So, href may be:
@yakunins What issues do you see with the current implementation of the href option?
@sapegin This sounds like a good idea. Even though I’ve been now using sectionDepth option extensively (or I think so at least) on Vue Design System, I still don’t always quite understand what it is supposed to do as using f.ex. the components option always anyway adds another level of “depth” even when I don’t want it to.
@sapegin These are not issues, looks more like features... Tested!
Just to illustrate the idea:
export function LinkRenderer(_ref2) {
...
return React.createElement(
props.href ? "a" : "span",
_extends...
...
@yakunins I like the idea with href especially the fact it already exists and doesn't need a breaking change. Am I correct in thinking that it will cover all edge cases? Can you post an example config?
Privet, @okonet!
That what I wish to have:
...
pagePerSection: true,
sections: [
{
name: 'All components',
href: '/',
content: './src/readme.md',
pagePerSection: false
},
{
name: 'Visual',
href: false,
sectionDepth: 2,
components: () => ([
path.resolve(__dirname, './src/visual/Text/', 'Text.tsx')
])
},
{
name: 'Layout',
href: false,
sectionDepth: 2,
components: () => ([
path.resolve(__dirname, './src/layout/Grid/', 'Grid.tsx'),
path.resolve(__dirname, './src/layout/Grid/', 'GridColumn.tsx'),
path.resolve(__dirname, './src/layout/Grid/', 'GridRow.tsx')
])
},
...
Some examples of plain text sections:
Collapsable sections headers:
First of all, I don't like the presence of pagePerSection and sectionDepth. That's exactly the reason this issue exist.
Try answering the following question: What would be your preferred way of doing this if you could start from scratch?
To me, this still feels ambiguous: what exactly href: false is affecting? The page Visual? So how do I navigate there?
@okonet If I am understanding @yakunins correctly, href: false would mean that the section title 'Visual' would still appear in the sidebar with various components listed under it, but clicking on the word 'Visual' wouldn't do anything since 'Visual' itself doesn't have any content of it's own other than the Components listed under it which in this case seem to each have pages of their own.
I personally like Okonet's suggestion to clearly distinguish between pages and sections, where pages each have their own individual page and url, and sections simply become anchored section headers that exist on a page.
I also like Yakuni's use of the href property to customize what actually happens when you click on an item in the sidebar.
Something like this:
{
name: 'Components', // is required
href: '/Components',
content: './readme.md',
sections: [ ... ],
pages: [ ... ],
...
}
They way I see it, you would use this same object template for both pages and sections and it would be interpreted in the following manner:
name | string : required |
Represents what is displayed in the sidebar and on the page or section header.
href | false, string, undefined |
If false, clicking on this item in the sidebar should do nothing and it should look visually different from other clickable links in the sidebar.
If undefined the href will be <parentURL>/${name} for pages or <parentURL>#${name} for sections.
If a string is specified then that string would be appended to it's parent's URL instead of the name attribute unless it begins with http:// or https:// in which case it would be treated as an external link.
content | string, undefined |
A string would represent the path to the .md file that should be used to populate the content of this page or section.
If content, sections, and href are all undefined then the sidebar link for this item should not be clickable, the same as if href were set to false.
sections | string, glob, object, array, undefined |
Sections should be displayed on a page below the specified content for that page (if any). If no content is defined then the content for the page should simply be a list of the specified sections. Each section should have a section header that matches the name of the Component or the name attribute of the section object. Each section header should have a page anchor that is determined by the href attribute (or the default case if the href attribute is undefined). Optionally (but ideally in my opinion) the contents of each section should be collapsible when the section header is clicked on. Perhaps another attribute could be included on a section object that indicates whether a particular section should start off in a collapsed state or not. |
When sections is a string it would represent the path to a single component which would be displayed as a section on it's parent's page.
When sections is a glob it would represent a glob pattern that identifies a list of components that should be displayed as sections on the parent's page.
When sections is an object it should take the same shape as the proposed format above and would be displayed as a single section on it's parent's page.
Alternatively sections could be an array of _strings, globs, or objects_ that are compiled into a list of sections to be displayed on it's parent's page.
pages | string, glob, object, array, undefined |
The pages attribute would contain similar data to sections. Items listed under the pages attribute would still show up in the sidebar as nested items of the parent, but they would not be displayed on the parent's page but would be given a unique URL and page of their own instead.
Hi, guys! Here short example how we try to manage our sections:
{
pagePerSection: true,
sections: [
{
name: 'Components',
sectionDepth: 1,
description: 'Component',
href: false, // want to disable this link.
components: [
resolve(__dirname, 'src', 'Button', 'Button.jsx'),
resolve(__dirname, 'src', 'Input', 'Input.jsx'),
],
},
],
}
Current state:
So, as you can see from config it will put all components on separate page. Also when we click 'Components' we will get empty page.
Desire state:
If
false, clicking on this item in the sidebar should do nothing and it should look visually different from other clickable links in the sidebar.
Hi! I have a problem using pagePerSection. If I want to have one section and components-function under that - it is not showing them per page. But if put another section under the first section is working properly (and adding sectionDepth: 2 that cannot be added for top level sections-array). So I end up having empty sub-sections with name-link and url-paths for nothing.
https://codesandbox.io/s/orlprkkk5?fontsize=14&moduleview=1
pagePerSection: true,
sections: [
{
name: 'Testing with section',
content: './src/testing.md',
components: () => {
return glob.sync(path.resolve(__dirname, 'src/**/*.js'));
},
// Where do i put the sectionDepth for components?
},
{
name: 'Testing with section again',
content: './src/testing.md',
sections: [
{
name: 'But needs an empty sub section',
components: () => {
return glob.sync(path.resolve(__dirname, 'src/**/*.js'));
},
},
],
sectionDepth: 2,
// Oh here we can have it, but I don't need the sub-section
},
],
Most helpful comment
I like the idea of starting from an ideal API, if we're going to make a breaking change anyway.