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

Option to automatically list sub-directory in the sidebar #613

Closed
mrleblanc101 opened this issue Jun 26, 2018 · 14 comments
Closed

Option to automatically list sub-directory in the sidebar #613

mrleblanc101 opened this issue Jun 26, 2018 · 14 comments

Comments

@mrleblanc101
Copy link

@mrleblanc101 mrleblanc101 commented Jun 26, 2018

Feature request

Hi,

I would like to suggest a new feature for the sidebar component. Here's a brief description of my issue. I would like to have an index page for a directory (called 'Projects') which contains sub-directory ('Project A', 'Project B', 'Project C', etc...) which each can contain multiple page of documentation ('index.md', 'deploy.md', 'contribute.md', 'wiki.md', 'faq.md' ,etc...). The index of 'Projects' (README.md) has a description of how to use this tool and how to contribute and other important information my company would like to give them and it also has a sidebar which in theory would list all the active projects in from my company like in the screenshot bellow.

capture d ecran 2018-06-25 a 10 33 40 pm

What would make this even better is if it would still respect the sidebarDepth: 2 and collapsable: true option already available in vuepress. For example, I could take my first example further and group all my project in a client repository. If the sidebar depth is specified, I could even see sub-sub-directory and they would be visible depending on the value of collapsable.

capture d ecran 2018-06-25 a 9 54 46 pm

It would be great if we could list those directory in the sidebar automatically similarly to the sidebar: 'auto' feature, but instead of displaying the headers of the current page, it would display the sub-directory of the current directory.

The first thing I tried is using a custom layout but after extracting the default theme using vuepress eject to check how the default layout works, I realized it wouldn't work as the sidebar is outside the layout component. I also initially considered making a custom theme for this but the way the sidebar is handled with a helper would need me to rework a lot of the code and it would also prevent me from getting any vuepress default theme update in the future and as the project is very young, I don't wan to lose this ability as it already is evolving quite quickly which would probably require me to restart everything in a few months if a I want to update.

Finaly, I think I've found a way to do something similar using the multiple-sidebar option https://vuepress.vuejs.org/default-theme-config/#multiple-sidebars, but it require me to hardcode all the value which is cumbersome because we add projects/clients on a regular basis.

The way I suggest it would works is that it would automatically list the sub-directory if you add one. No need to go and edit you .vuepress/config.js every time. Clicking the directory name would take you to the README.md or index.html depending on your structure.

Something similar could be added to the nav-bar at the top of the page. Initially I wanted to list the sub-directory in a dropdown in the nav-bar but decided it would be better to have an index for my 'Project' directory with some instruction/explanation but the problem is the same! We would need to hardcode the value for the dropdown and it wouldn't be as flexible as there is no way of adding a second level inside the dropdown.

capture d ecran 2018-06-25 a 10 17 35 pm

How should this be implemented in your opinion?

I suggest using 'directory, 'sub-directory' or 'folder' String as value of sidebar in .vuepress/config.js or in the page front-matter just like 'auto' String already works for headings in the sidebar.

Are you willing to work on this yourself?**

I can help, but I'm not sure my experience with Vue and VuePress is big enough to make this myself from scratch.

@mrleblanc101

This comment has been minimized.

Copy link
Author

@mrleblanc101 mrleblanc101 commented Jun 26, 2018

Might have found something.
In config.js add:

const dirTree = require('directory-tree');
const path = require('path');

const projets = dirTree(path.join(__dirname, '../projets'), {extensions:/\.md/});

module.exports = {
    [...] // Shortened for lisibility
    themeConfig: {
        sidebar: {
          '/projets/': projets.children.map(children => path.parse(children.name).name !== 'README' ? path.parse(children.name).name : '' ),
        },
    }
};
@mrleblanc101

This comment has been minimized.

Copy link
Author

@mrleblanc101 mrleblanc101 commented Jun 26, 2018

Still need a lot of work and some cleanup but here's what i have right now for recursive directory:

var projets = [];
dirTree(path.join(__dirname, '../projets'), {extensions:/\.md/}, (item, PATH) => projets.push(item));
projets = projets.map(children => {
    return path.parse(children.name).name  !== 'README' ? path.join.apply(null, children.path.split(path.sep).slice(7)) : path.join.apply(null, children.path.split(path.sep).slice(7)).replace('README.md', '');
});

The two major hurdle i have right now are:

  1. Sidebar can't resolve current directory if path = 'README.md' or 'index.html', it need to be empty String which seems weird, maybe we could change only that and forget about the rest of the issue ?
  2. I'm not super familiar with Node.js path so my code to transform the path from /Users/mrleblanc/GitHub/alexandrie/docs/projets/client-b/test.md to /projets/client-b/test.md is probably extremely ugly
  3. I might have to change how I'm doing this if i want to nest 'Projects' under their appropriate 'Client'
  4. Using my multiple sidebar method force me to have a 'directory' sidebar even in sub-page because sidebar: auto in the file does not overwrite it
@ulivz

This comment has been minimized.

Copy link
Member

@ulivz ulivz commented Jun 26, 2018

Thank you for your interest in vuepress. and I also read your requirement carefully but I still cannot clearly get what you really want.

In my opinion, I think that you want something that helps you to generate the config automatically according to the file structure, but this is not a common need and different people may have different generation needs, in addition, it also can be done in user-land.

BTW, If you are not familiar to Node.js, sorry but I cannot help you.

@ulivz ulivz closed this Jun 26, 2018
@MartinMuzatko

This comment has been minimized.

Copy link
Contributor

@MartinMuzatko MartinMuzatko commented Aug 27, 2018

@ulivz I think the goal is an automated sidebar. The above script is a workaround to generate this.

@hello-sunbaixin

This comment has been minimized.

Copy link

@hello-sunbaixin hello-sunbaixin commented Sep 4, 2018

I have the same requirement, but the above answer needs to be run in the node environment

@HerrBertling

This comment has been minimized.

Copy link
Contributor

@HerrBertling HerrBertling commented Nov 20, 2018

I like this idea, too. To be honest, that's what I expected to happen.

I've got a docs/components folder for some components. I automatically create a subfolder for each component and put a README.md file into this folder since I thought that would be the way to go to generate the page tree automatically. Currently, I need to update the sidebar pages manually each time I add a new component.

With the folder structure already in place, an option to automatically render the navigation as described here would be awesome.

@andyk1989

This comment has been minimized.

Copy link

@andyk1989 andyk1989 commented Feb 20, 2019

For future reference for anyone who stumbles upon this for a similar use case.

I used the following code to generate a list of all markdown files in reverse order. I use my VuePress instance as my notes viewer app.

Aside: My files start with a YYYYMMDD-*.md pattern so I personally added a .reverse() in the markdownFiles line for easier reference.

Note: 1 new NPM dependency (glob)

  1. npm install glob
  2. insert the following code in your /.vuepress/config.js
const glob = require('glob');

let markdownFiles = glob.sync('docs/**/*.md').map(f => '/' + f); 
// update the docs/**/*.md pattern with your folder structure 

module.exports = {
  ......
  themeConfig: {
    sidebar: markdownFiles
  },
};

Hope this helps someone!

@ladislavsulc

This comment has been minimized.

Copy link

@ladislavsulc ladislavsulc commented Feb 24, 2019

Why is this closed and why do we have to manually create the tree in the config? It is not very handy...

@benjivm

This comment has been minimized.

Copy link

@benjivm benjivm commented May 24, 2019

I took what Prefect does and added functionality for reading the order value of the YAML metadata if it exists, otherwise it sorts by filename:

const _ = require('lodash');
const fs = require('fs');
const glob = require('glob');
const markdownIt = require('markdown-it');
const meta = require('markdown-it-meta');

// Load all MD files in a specified directory and order by metadata 'order' value
const getChildren = function(parent_path, dir) {
    files = glob
        .sync(parent_path + (dir ? `/${dir}` : '') + '/**/*.md')
        .map(path => {
            // Instantiate MarkdownIt
            md = new markdownIt();
            // Add markdown-it-meta
            md.use(meta);
            // Get the order value
            file = fs.readFileSync(path, 'utf8');
            md.render(file);
            order = md.meta.order;
            // Remove "parent_path" and ".md"
            path = path.slice(parent_path.length + 1, -3);
            // Remove "README", making it the de facto index page
            if (path.endsWith('README')) {
                path = path.slice(0, -6);
            }

            return {
                path,
                order
            };
        });

    // Return the ordered list of files, sort by 'order' then 'path'
    return _.sortBy(files, ['order', 'path'])
        .map(file => file.path);
};

module.exports = {
    getChildren,
};

Usage:

sidebar: {
        '/get-children/': [{
            title: 'Example 1',
            collapsable: true,
            children: getChildren('docs/example-1'),
        }, {
            title: 'Example 2',
            collapsable: true,
            children: getChildren('docs/example-2'),
        }],
       // if more than three 2 dirs deep add a second parameter for target subdirectory
       '/example3/': getChildren('docs/another/location', 'subdirectory')
}

I'm sure this can be simplified, please let me know if you clean it up or spot problems. Make sure there are no trailing or leading slashes in your directory calls.

@MartinMuzatko

This comment has been minimized.

Copy link
Contributor

@MartinMuzatko MartinMuzatko commented May 25, 2019

@a-teammate I think we can perfectly use this for our website :)

@ozum

This comment has been minimized.

Copy link

@ozum ozum commented Jun 20, 2019

Give it a try: https://www.npmjs.com/package/vuepress-bar

I know this is a closed case. I came here to find a solution and liked @benjivm solution. Then I developed the idea of @benjivm a little further to create both navbar and sidebar for directory structure and add sort feature to directories too.

In hope helping others, I shared it by publishing above node module.

Thanks for the idea.

@wsdo

This comment has been minimized.

Copy link

@wsdo wsdo commented Aug 20, 2019

const getFileName = name => {
let arr = []
fs.readdirSync(${RDOCS}${name})
.filter(function(file) {
return /.(js|md)$/i.test(file)
})
.map(function(file) {
s1 = file.substring(0, file.indexOf('.'))
let res = ''
if (s1 === 'readme' || s1 === 'README') {
res = ADOCS + name + '/'
} else {
res = ADOCS + name + '/' + s1
}
arr.push(res)
})
return arr
}

@Mister-Hope

This comment has been minimized.

Copy link
Contributor

@Mister-Hope Mister-Hope commented Sep 16, 2019

I do not think it is a personal need, many people dose need this!
A situation where someone wants a specific folder auto generated is very common. As you receive 28 disagree and none agree , I really think you should consider open it. @ulivz

@JessicaSachs

This comment has been minimized.

Copy link

@JessicaSachs JessicaSachs commented Sep 17, 2019

Just adding my voice to those that think this is a valuable feature... Downloading the third party package to do it (thank you @ozum)

@ulivz, OP gave you an amazing write-up, attempted his own solutions, said he didn't understand node PATHs, and then you chided him about not being able to write javascript and closed his issue. Not cool.

I'm happy to submit a PR if you'd like. I much prefer supporting features to using third-party plugins.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.