This commit is contained in:
dmosberger 2025-01-17 01:36:42 +08:00 committed by GitHub
commit 138731c2f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 57 additions and 4 deletions

View File

@ -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) => (

View File

@ -38,8 +38,12 @@ export class SideMenu extends React.Component<{ menu: MenuStore; className?: str
} }
activate = (item: IMenuItem) => { activate = (item: IMenuItem) => {
if (item && item.active && this.context.menuToggle) { if (item && this.context.menuToggle) {
return item.expanded ? item.collapse() : item.expand(); if (item.expanded) {
item.collapse();
return;
}
if (item.active) item.expand();
} }
this.props.menu.activateAndScroll(item, true); this.props.menu.activateAndScroll(item, true);
setTimeout(() => { setTimeout(() => {

View File

@ -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 }>`

View File

@ -8,6 +8,15 @@ import type { ContentItemModel, TagGroup, TagInfo, TagsInfoMap } from './types';
export const GROUP_DEPTH = 0; export const GROUP_DEPTH = 0;
function appendChildren(parent: ContentItemModel, children: ContentItemModel[], prefix: string) {
for (const child of MenuBuilder.factorByPrefix(children)) {
if (child.sidebarLabel.startsWith(prefix)) {
child.sidebarLabel = '…' + child.sidebarLabel.slice(prefix.length - 1);
}
parent.items.push(child);
}
}
export class MenuBuilder { export class MenuBuilder {
/** /**
* Builds page content structure based on tags * Builds page content structure based on tags
@ -28,7 +37,37 @@ 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) {
appendChildren(parent!, newChildren, prefix);
newChildren = [];
}
newItems.push(item);
if (item instanceof GroupModel) {
parent = item;
prefix = item.name + '/';
} else parent = null;
}
}
if (newChildren.length > 0) appendChildren(parent!, newChildren, prefix);
return newItems;
} }
/** /**

View File

@ -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);