mirror of
https://github.com/Redocly/redoc.git
synced 2025-03-10 12:55:47 +03:00
feat: add option sideNavLayout
Add support for theme option `sideNavLayout`. If set to `factored`, the side-nav menu will group items that share a common path prefix. For example, if the default layout for side-nav looked like this: /config > /config/alert > /config/bacnet > /config/modbus > /log > Then the factored side-nav would look like this: /config > /log > and after expanding /config, you'd see: /config v GET /config PUT /config …/alert > …/bacnet > …/modbus > /log > Note that this commit also updates the styling to show a vertical line to the left of all side-bar <ul> lists that are not at the root level. This probably should be configurable.
This commit is contained in:
parent
639fd2c32c
commit
2d461f41a9
|
@ -26,6 +26,7 @@ export class MenuItems extends React.Component<MenuItemsProps> {
|
||||||
className={className}
|
className={className}
|
||||||
style={this.props.style}
|
style={this.props.style}
|
||||||
$expanded={expanded}
|
$expanded={expanded}
|
||||||
|
root={root || false}
|
||||||
{...(root ? { role: 'menu' } : {})}
|
{...(root ? { role: 'menu' } : {})}
|
||||||
>
|
>
|
||||||
{items.map((item, idx) => (
|
{items.map((item, idx) => (
|
||||||
|
|
|
@ -84,7 +84,7 @@ function menuItemActive(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MenuItemUl = styled.ul<{ $expanded: boolean }>`
|
export const MenuItemUl = styled.ul<{ $expanded: boolean; root: boolean }>`
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
|
@ -97,6 +97,8 @@ export const MenuItemUl = styled.ul<{ $expanded: boolean }>`
|
||||||
}
|
}
|
||||||
|
|
||||||
${props => (props.$expanded ? '' : 'display: none;')};
|
${props => (props.$expanded ? '' : 'display: none;')};
|
||||||
|
${props => (props.root ? '' : 'margin-left: 8px;')};
|
||||||
|
${props => (props.root ? '' : 'border-left: 1px solid lightblue;')}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const MenuItemLi = styled.li<{ depth: number }>`
|
export const MenuItemLi = styled.li<{ depth: number }>`
|
||||||
|
|
|
@ -28,7 +28,41 @@ export class MenuBuilder {
|
||||||
} else {
|
} else {
|
||||||
items.push(...MenuBuilder.getTagsItems(parser, tagsMap, undefined, undefined, options));
|
items.push(...MenuBuilder.getTagsItems(parser, tagsMap, undefined, undefined, options));
|
||||||
}
|
}
|
||||||
return items;
|
|
||||||
|
if (options.sideNavLayout !== 'factored') return items;
|
||||||
|
|
||||||
|
return MenuBuilder.factorByPrefix(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
static factorByPrefix(items: ContentItemModel[]): ContentItemModel[] {
|
||||||
|
const newItems: ContentItemModel[] = [];
|
||||||
|
let newChildren: ContentItemModel[] = [];
|
||||||
|
let parent: GroupModel | null = null;
|
||||||
|
let prefix = '';
|
||||||
|
for (const item of items) {
|
||||||
|
if (parent && item.name.startsWith(prefix)) {
|
||||||
|
item.parent = parent;
|
||||||
|
item.depth = parent.depth + 1;
|
||||||
|
newChildren.push(item);
|
||||||
|
} else {
|
||||||
|
if (newChildren.length > 0) {
|
||||||
|
for (const child of MenuBuilder.factorByPrefix(newChildren)) {
|
||||||
|
if (child.sidebarLabel.startsWith(prefix)) {
|
||||||
|
child.sidebarLabel = '…' + child.sidebarLabel.slice(prefix.length - 1);
|
||||||
|
}
|
||||||
|
parent!.items.push(child);
|
||||||
|
}
|
||||||
|
newChildren = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
newItems.push(item);
|
||||||
|
if (item instanceof GroupModel) {
|
||||||
|
parent = item;
|
||||||
|
prefix = item.name + '/';
|
||||||
|
} else parent = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -27,6 +27,7 @@ export interface RedocRawOptions {
|
||||||
onlyRequiredInSamples?: boolean | string;
|
onlyRequiredInSamples?: boolean | string;
|
||||||
showExtensions?: boolean | string | string[];
|
showExtensions?: boolean | string | string[];
|
||||||
sideNavStyle?: SideNavStyleEnum;
|
sideNavStyle?: SideNavStyleEnum;
|
||||||
|
sideNavLayout?: 'default' | 'factored';
|
||||||
hideSingleRequestSampleTab?: boolean | string;
|
hideSingleRequestSampleTab?: boolean | string;
|
||||||
hideRequestPayloadSample?: boolean;
|
hideRequestPayloadSample?: boolean;
|
||||||
menuToggle?: boolean | string;
|
menuToggle?: boolean | string;
|
||||||
|
@ -180,6 +181,10 @@ export class RedocNormalizedOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static normalizeSideNavLayout(value: RedocRawOptions['sideNavLayout']): 'default' | 'factored' {
|
||||||
|
return value === 'factored' ? value : 'default';
|
||||||
|
}
|
||||||
|
|
||||||
static normalizePayloadSampleIdx(value: RedocRawOptions['payloadSampleIdx']): number {
|
static normalizePayloadSampleIdx(value: RedocRawOptions['payloadSampleIdx']): number {
|
||||||
if (typeof value === 'number') {
|
if (typeof value === 'number') {
|
||||||
return Math.max(0, value); // always greater or equal than 0
|
return Math.max(0, value); // always greater or equal than 0
|
||||||
|
@ -231,6 +236,7 @@ export class RedocNormalizedOptions {
|
||||||
onlyRequiredInSamples: boolean;
|
onlyRequiredInSamples: boolean;
|
||||||
showExtensions: boolean | string[];
|
showExtensions: boolean | string[];
|
||||||
sideNavStyle: SideNavStyleEnum;
|
sideNavStyle: SideNavStyleEnum;
|
||||||
|
sideNavLayout: 'default' | 'factored';
|
||||||
hideSingleRequestSampleTab: boolean;
|
hideSingleRequestSampleTab: boolean;
|
||||||
hideRequestPayloadSample: boolean;
|
hideRequestPayloadSample: boolean;
|
||||||
menuToggle: boolean;
|
menuToggle: boolean;
|
||||||
|
@ -303,6 +309,7 @@ export class RedocNormalizedOptions {
|
||||||
this.onlyRequiredInSamples = argValueToBoolean(raw.onlyRequiredInSamples);
|
this.onlyRequiredInSamples = argValueToBoolean(raw.onlyRequiredInSamples);
|
||||||
this.showExtensions = RedocNormalizedOptions.normalizeShowExtensions(raw.showExtensions);
|
this.showExtensions = RedocNormalizedOptions.normalizeShowExtensions(raw.showExtensions);
|
||||||
this.sideNavStyle = RedocNormalizedOptions.normalizeSideNavStyle(raw.sideNavStyle);
|
this.sideNavStyle = RedocNormalizedOptions.normalizeSideNavStyle(raw.sideNavStyle);
|
||||||
|
this.sideNavLayout = RedocNormalizedOptions.normalizeSideNavLayout(raw.sideNavLayout);
|
||||||
this.hideSingleRequestSampleTab = argValueToBoolean(raw.hideSingleRequestSampleTab);
|
this.hideSingleRequestSampleTab = argValueToBoolean(raw.hideSingleRequestSampleTab);
|
||||||
this.hideRequestPayloadSample = argValueToBoolean(raw.hideRequestPayloadSample);
|
this.hideRequestPayloadSample = argValueToBoolean(raw.hideRequestPayloadSample);
|
||||||
this.menuToggle = argValueToBoolean(raw.menuToggle, true);
|
this.menuToggle = argValueToBoolean(raw.menuToggle, true);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user