feat(v2): support external links and linking to docs from other sidebars (#1052)

* feat(sidebar): support external links and linking to docs from other sidebars

* Update styles.css
This commit is contained in:
Sviatoslav 2018-10-25 07:01:39 +03:00 committed by Yangshun Tay
parent edde297504
commit a2d3f26722
8 changed files with 466 additions and 139 deletions

View file

@ -2,6 +2,110 @@ const fs = require('fs-extra');
const path = require('path');
const {idx} = require('../utils');
/**
* Check that item contains only allowed keys
*
* @param {Object} item
* @param {Array<string>} keys
*/
function assertItem(item, keys) {
const unknownKeys = Object.keys(item).filter(
key => !keys.includes(key) && key !== 'type',
);
if (unknownKeys.length) {
throw new Error(
`Unknown sidebar item keys: ${unknownKeys}. Item: ${JSON.stringify(
item,
)}`,
);
}
}
/**
* Normalizes recursively category and all its children. Ensures, that at the end
* each item will be an object with the corresponding type
*
* @param {Array<Object>} category
* @param {number} [level=0]
*
* @return {Array<Object>}
*/
function normalizeCategory(category, level = 0) {
if (level === 2) {
throw new Error(
`Can not process ${
category.label
} category. Categories can be nested only one level deep.`,
);
}
assertItem(category, ['items', 'label']);
if (!Array.isArray(category.items)) {
throw new Error(
`Error loading ${category.label} category. Category items must be array.`,
);
}
const items = category.items.map(item => {
switch (item.type) {
case 'category':
return normalizeCategory(item, level + 1);
case 'link':
assertItem(item, ['href', 'label']);
break;
case 'ref':
assertItem(item, ['id', 'label']);
break;
default:
if (typeof item === 'string') {
return {
type: 'doc',
id: item,
};
}
if (item.type !== 'doc') {
throw new Error(`Unknown sidebar item type: ${item.type}`);
}
assertItem(item, ['id', 'label']);
break;
}
return item;
});
return {...category, items};
}
/**
* Converts sidebars object to mapping to arrays of sidebar item objects
*
* @param {{[key: string]: Object}} sidebars
*
* @return {{[key: string]: Array<Object>}}
*/
function normalizeSidebar(sidebars) {
return Object.entries(sidebars).reduce((acc, [sidebarId, sidebar]) => {
let normalizedSidebar = sidebar;
if (!Array.isArray(sidebar)) {
// convert sidebar to a more generic structure
normalizedSidebar = Object.entries(sidebar).map(([label, items]) => ({
type: 'category',
label,
items,
}));
}
acc[sidebarId] = normalizedSidebar.map(item => normalizeCategory(item));
return acc;
}, {});
}
module.exports = function loadSidebars({siteDir, env}, deleteCache = true) {
let allSidebars = {};
@ -34,5 +138,6 @@ module.exports = function loadSidebars({siteDir, env}, deleteCache = true) {
});
}
}
return allSidebars;
return normalizeSidebar(allSidebars);
};