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

feat: sub-categories in sidebar.json #892

Merged
merged 4 commits into from
Oct 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docs/guides-navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,29 @@ You should provide `directory/id` instead of `id` in `sidebars.json`.
}
```

### Adding Sub Categories

It is possibile to add sub categories to a sidebar. Instead of passing an array to the category like the previous examples you can pass an object where
the keys will be the sub category name. You can then pass an array of document ids to the sub category.

```js
{
"examples-sidebar" : {
"My Example Category" : {
"My Example Sub Category" : [
"my-examples",
...
],
"My Next Sub Category" : [
"some-other-examples"
]
...
},
...
}
}
```

### Adding New Sidebars

You can also put a document in a new sidebar. In the following example, we are creating an `examples-sidebar` sidebar within `sidebars.json` that has a category called `My Example Category` containing a document with an `id` of `my-examples`.
Expand Down
20 changes: 18 additions & 2 deletions v1/lib/core/DocsSidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,31 @@
*/

const React = require('react');
const fs = require('fs');
const Container = require('./Container.js');
const SideNav = require('./nav/SideNav.js');
const Metadata = require('../core/metadata.js');
const readCategories = require('../server/readCategories.js');

let languages;

if (fs.existsSync(`../server/languages.js`)) {
languages = require(`../server/languages.js`);
} else {
languages = [
{
enabled: true,
name: 'English',
tag: 'en',
},
];
}

class DocsSidebar extends React.Component {
render() {
const sidebar = this.props.metadata.sidebar;
const docsCategories = readCategories(sidebar);
const categoryName = docsCategories[this.props.metadata.language][0].name;
const docsCategories = readCategories(sidebar, Metadata, languages);
const categoryName = this.props.metadata.category;
if (!categoryName) {
return null;
}
Expand Down
17 changes: 16 additions & 1 deletion v1/lib/core/nav/SideNav.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,22 @@ class SideNav extends React.Component {
<h3 className="navGroupCategoryTitle">
{this.getLocalizedCategoryString(category.name)}
</h3>
<ul>{category.links.map(this.renderItemLink, this)}</ul>
<ul>
{category.links.map(this.renderItemLink, this)}
{category.sub_categories &&
category.sub_categories.map(this.renderSubCategory, this)}
</ul>
</div>
);
}

renderSubCategory(subCategory) {
return (
<div className="navGroup subNavGroup" key={subCategory.name}>
<h4 className="navGroupSubCategoryTitle">
{this.getLocalizedCategoryString(subCategory.name)}
</h4>
<ul>{subCategory.links.map(this.renderItemLink, this)}</ul>
</div>
);
}
Expand Down
65 changes: 65 additions & 0 deletions v1/lib/server/__tests__/__fixtures__/metadata-subcategories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
module.exports = {
'en-doc1': {
id: 'en-doc1',
title: 'Document 1',
source: 'doc1.md',
version: 'next',
permalink: 'docs/en/next/doc1.html',
localized_id: 'doc1',
language: 'en',
sidebar: 'docs',
category: 'Test',
next_id: 'doc2',
next: 'en-doc2',
next_title: 'Document 2',
sub_category: 'Sub Cat 1',
sort: 1,
},
'en-doc2': {
id: 'en-doc2',
title: 'Document 2',
source: 'doc2.md',
version: 'next',
permalink: 'docs/en/next/doc2.html',
localized_id: 'doc2',
language: 'en',
sidebar: 'docs',
category: 'Test',
previous_id: 'doc1',
previous: 'en-doc1',
previous_title: 'Document 1',
sub_category: 'Sub Cat 1',
sort: 2,
},
'en-doc3': {
id: 'en-doc3',
title: 'Document 3',
source: 'doc3.md',
version: 'next',
permalink: 'docs/en/next/doc3.html',
localized_id: 'doc3',
language: 'en',
sidebar: 'docs',
category: 'Test',
previous_id: 'doc2',
previous: 'en-doc2',
previous_title: 'Document 2',
sub_category: 'Sub Cat 2',
sort: 3,
},
'en-doc4': {
id: 'en-doc4',
title: 'Document 4',
source: 'doc4.md',
version: 'next',
permalink: 'docs/en/next/doc4.html',
localized_id: 'doc4',
language: 'en',
sidebar: 'docs',
category: 'Test 2',
previous_id: 'doc3',
previous: 'en-doc3',
previous_title: 'Document 3',
sort: 4,
},
};
17 changes: 17 additions & 0 deletions v1/lib/server/__tests__/__fixtures__/metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module.exports = {
next_id: 'doc2',
next: 'en-doc2',
next_title: 'Document 2',
sort: 1,
},
'en-doc2': {
id: 'en-doc2',
Expand All @@ -26,6 +27,22 @@ module.exports = {
previous_id: 'doc1',
previous: 'en-doc1',
previous_title: 'Document 1',
sort: 2,
},
'en-doc3': {
id: 'en-doc3',
title: 'Document 3',
source: 'doc3.md',
version: 'next',
permalink: 'docs/en/next/doc3.html',
localized_id: 'doc3',
language: 'en',
sidebar: 'docs',
category: 'Test 2',
previous_id: 'doc2',
previous: 'en-doc2',
previous_title: 'Document 2',
sort: 3,
},
'ko-doc1': {
id: 'ko-doc1',
Expand Down
11 changes: 11 additions & 0 deletions v1/lib/server/__tests__/__fixtures__/sidebar-subcategories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = {
docs: {
'First Category': {
'Sub Cat One': ['doc2', 'doc1'],
'Sub Cat Two': ['doc3', 'doc5'],
},
'Second Category': {
Hello: ['doc4'],
},
},
};
6 changes: 6 additions & 0 deletions v1/lib/server/__tests__/__fixtures__/sidebar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
docs: {
'First Category': ['doc1', 'doc2'],
'Second Category': ['doc4', 'doc3'],
},
};
91 changes: 91 additions & 0 deletions v1/lib/server/__tests__/readCategories.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

const readCategories = require('../readCategories');
const generalMetadata = require('./__fixtures__/metadata.js');
const subCategoryMetadata = require('./__fixtures__/metadata-subcategories.js');

const languages = [
{
enabled: true,
name: 'English',
tag: 'en',
},
{
enabled: true,
name: 'Foo',
tag: 'ko',
},
];

const languagesMultiple = [
{
enabled: false,
name: 'English',
tag: 'en',
},
{
enabled: true,
name: 'Foo',
tag: 'ko',
},
];

describe('readCategories', () => {
test('should return proper categories and their pages', () => {
const categories = readCategories('docs', generalMetadata, languages);

expect(categories.en).toBeDefined();
expect(categories.en.length).toBe(2);

expect(categories.en[0].name).toBe('Test');
expect(categories.en[0].links.length).toBe(2);
expect(categories.en[0].links[0].id).toBe('en-doc1');
expect(categories.en[0].links[1].id).toBe('en-doc2');

expect(categories.en[1].name).toBe('Test 2');
expect(categories.en[1].links.length).toBe(1);
expect(categories.en[1].links[0].id).toBe('en-doc3');
});

test('should return proper data with categories and sub categories', () => {
const categories = readCategories('docs', subCategoryMetadata, languages);

expect(categories.en).toBeDefined();
expect(categories.ko).toBeDefined();
expect(categories.en.length).toBe(2);

expect(categories.en[0].name).toBe('Test');
expect(categories.en[0].links.length).toBe(0);
expect(categories.en[0].sub_categories.length).toBe(2);

expect(categories.en[0].sub_categories[0].name).toBe('Sub Cat 1');
expect(categories.en[0].sub_categories[0].links.length).toBe(2);
expect(categories.en[0].sub_categories[0].links[0].id).toBe('en-doc1');
expect(categories.en[0].sub_categories[0].links[1].id).toBe('en-doc2');

expect(categories.en[0].sub_categories[1].name).toBe('Sub Cat 2');
expect(categories.en[0].sub_categories[1].links.length).toBe(1);
expect(categories.en[0].sub_categories[1].links[0].id).toBe('en-doc3');

expect(categories.en[1].name).toBe('Test 2');
expect(categories.en[1].links.length).toBe(1);
expect(categories.en[1].links[0].id).toBe('en-doc4');
expect(categories.en[1].sub_categories).not.toBeDefined();
});

test('should return proper languages when not enabled', () => {
const categories = readCategories(
'docs',
generalMetadata,
languagesMultiple,
);

expect(categories.en).not.toBeDefined();
expect(categories.ko).toBeDefined();
});
});
77 changes: 77 additions & 0 deletions v1/lib/server/__tests__/readMetadata.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

const {readSidebar} = require('../readMetadata');
const sidebar = require('./__fixtures__/sidebar');
const sidebarSubCategories = require('./__fixtures__/sidebar-subcategories');

jest.mock('../env', () => ({
translation: {
enabled: true,
enabledLanguages: () => [
{
enabled: true,
name: 'English',
tag: 'en',
},
{
enabled: true,
name: '한국어',
tag: 'ko',
},
],
},
versioning: {
enabled: true,
defaultVersion: '1.0.0',
},
}));

jest.mock(`${process.cwd()}/siteConfig.js`, () => true, {virtual: true});
jest.mock(`${process.cwd()}/sidebar.json`, () => true, {virtual: true});

describe('readMetadata', () => {
describe('readSidebar', () => {
it('should verify regular category data and verify sort', () => {
const order = readSidebar(sidebar);

// Put in this order to verify sort
['doc1', 'doc2', 'doc4', 'doc3'].forEach((id, index) => {
expect(order[id]).toBeDefined();
expect(order[id].sort).toBe(index + 1);
});

expect(order.doc1.previous).toBeUndefined();
expect(order.doc2.previous).toBe('doc1');

expect(order.doc1.next).toBe('doc2');
expect(order.doc2.next).toBe('doc4');

expect(order.doc1.sub_category).toBeFalsy();
});

test('should verify sub category data and verify sort', () => {
const order = readSidebar(sidebarSubCategories);

// Put in this order to verify sort
['doc2', 'doc1', 'doc3', 'doc5', 'doc4'].forEach((id, index) => {
expect(order[id]).toBeDefined();
expect(order[id].sort).toBe(index + 1);
});

expect(order.doc2.sidebar).toBe('docs');
expect(order.doc2.category).toBe('First Category');
expect(order.doc2.sub_category).toBe('Sub Cat One');

expect(order.doc1.category).toBe('First Category');
expect(order.doc1.sub_category).toBe('Sub Cat One');

expect(order.doc3.category).toBe('First Category');
expect(order.doc3.sub_category).toBe('Sub Cat Two');
});
});
});
Loading