techdocs expandable nav addon

Signed-off-by: Anders Näsman <andersn@spotify.com>
This commit is contained in:
Anders Näsman
2022-04-29 11:44:21 +02:00
parent 490d663a55
commit 8767710f1f
7 changed files with 142 additions and 0 deletions
+2
View File
@@ -71,6 +71,7 @@ import {
} from '@backstage/plugin-techdocs';
import { TechDocsAddons } from '@backstage/plugin-techdocs-react';
import {
ExpandableNavigation,
ReportIssue,
TextSize,
} from '@backstage/plugin-techdocs-module-addons-contrib';
@@ -185,6 +186,7 @@ const routes = (
>
{techDocsPage}
<TechDocsAddons>
<ExpandableNavigation />
<ReportIssue />
<TextSize />
</TechDocsAddons>
@@ -7,6 +7,9 @@
import { BackstagePlugin } from '@backstage/core-plugin-api';
// @public
export const ExpandableNavigation: (props: unknown) => JSX.Element | null;
// @public
export const ReportIssue: (props: ReportIssueProps) => JSX.Element | null;
@@ -43,6 +43,7 @@
"@material-ui/core": "^4.9.13",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.57",
"@react-hookz/web": "^13.0.0",
"git-url-parse": "^11.6.0",
"react-use": "^17.2.4"
},
@@ -0,0 +1,103 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { useEffect, useState } from 'react';
import { useLocalStorageValue } from '@react-hookz/web';
import { Button, withStyles } from '@material-ui/core';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import { useShadowRoot } from '@backstage/plugin-techdocs-react';
const NESTED_LIST_TOGGLE = '.md-nav__item--nested .md-toggle';
const EXPANDABLE_NAVIGATION_LOCAL_STORAGE =
'@backstage/techdocs-addons/nav-expanded';
const StyledButton = withStyles({
root: {
position: 'absolute',
left: '220px',
top: '19px',
padding: 0,
minWidth: 0,
},
})(Button);
const CollapsedIcon = withStyles({
root: {
height: '20px',
width: '20px',
},
})(ChevronRightIcon);
const ExpandedIcon = withStyles({
root: {
height: '20px',
width: '20px',
},
})(ExpandMoreIcon);
type expandableNavigationLocalStorage = {
navExpanded: boolean;
};
export const ExpandableNavigationAddon = () => {
const shadowRoot = useShadowRoot();
const defaultValue = { navExpanded: false };
const [expanded, setExpanded] =
useLocalStorageValue<expandableNavigationLocalStorage>(
EXPANDABLE_NAVIGATION_LOCAL_STORAGE,
defaultValue,
);
const [hasNavSubLevels, setHasNavSubLevels] = useState<boolean>(false);
useEffect(() => {
const checkboxToggles =
shadowRoot?.querySelectorAll<HTMLInputElement>(NESTED_LIST_TOGGLE);
if (!checkboxToggles || (checkboxToggles && checkboxToggles.length === 0))
return;
setHasNavSubLevels(true);
checkboxToggles.forEach(item => {
if (
(expanded?.navExpanded && !item.checked) ||
(!expanded?.navExpanded && item.checked)
) {
item.click();
}
});
}, [shadowRoot, expanded]);
const handleState = () => {
setExpanded(prevState => ({
navExpanded: !prevState?.navExpanded,
}));
};
return (
<>
{hasNavSubLevels ? (
<StyledButton
size="small"
onClick={handleState}
aria-label={expanded?.navExpanded ? 'collapse-nav' : 'expand-nav'}
>
{expanded?.navExpanded ? <ExpandedIcon /> : <CollapsedIcon />}
</StyledButton>
) : null}
</>
);
};
@@ -0,0 +1,17 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './ExpandableNavigation';
@@ -22,6 +22,7 @@
export {
techdocsModuleAddonsContribPlugin,
ExpandableNavigation,
ReportIssue,
TextSize,
} from './plugin';
@@ -19,6 +19,7 @@ import {
createTechDocsAddonExtension,
TechDocsAddonLocations,
} from '@backstage/plugin-techdocs-react';
import { ExpandableNavigationAddon } from './ExpandableNavigation';
import { ReportIssueAddon, ReportIssueProps } from './ReportIssue';
import { TextSizeAddon } from './TextSize';
@@ -32,6 +33,20 @@ export const techdocsModuleAddonsContribPlugin = createPlugin({
id: 'techdocsModuleAddonsContrib',
});
/**
* TechDocs addon that lets you expand/collapse the TechDocs main navigation.
*
* @public
*/
export const ExpandableNavigation = techdocsModuleAddonsContribPlugin.provide(
createTechDocsAddonExtension({
name: 'ExpandableNavigation',
location: TechDocsAddonLocations.PrimarySidebar,
component: ExpandableNavigationAddon,
}),
);
/**
* TechDocs addon that lets you select text and open GitHub/Gitlab issues
*