From 8c32fbb8c4488424cf7a17d8d3d47ac563ae94d6 Mon Sep 17 00:00:00 2001 From: "Chongyang Adrian, Ke" Date: Fri, 19 Mar 2021 15:43:34 +0800 Subject: [PATCH] Add sticky sidebars and footer nav in Techdocs Reader Signed-off-by: Chongyang Adrian, Ke --- .changeset/nervous-plants-carry.md | 5 +++ .../techdocs/src/reader/components/Reader.tsx | 41 +++++++++++++++++-- 2 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 .changeset/nervous-plants-carry.md diff --git a/.changeset/nervous-plants-carry.md b/.changeset/nervous-plants-carry.md new file mode 100644 index 0000000000..59d45b2b88 --- /dev/null +++ b/.changeset/nervous-plants-carry.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': minor +--- + +Add sticky sidebars and footer navigation links to TechDocs Reader diff --git a/plugins/techdocs/src/reader/components/Reader.tsx b/plugins/techdocs/src/reader/components/Reader.tsx index 2231476869..4f3a52a522 100644 --- a/plugins/techdocs/src/reader/components/Reader.tsx +++ b/plugins/techdocs/src/reader/components/Reader.tsx @@ -17,7 +17,7 @@ import { EntityName } from '@backstage/catalog-model'; import { useApi } from '@backstage/core'; import { BackstageTheme } from '@backstage/theme'; import { useTheme } from '@material-ui/core'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { useAsync } from 'react-use'; import { techdocsStorageApiRef } from '../../api'; @@ -47,12 +47,32 @@ export const Reader = ({ entityId, onReady }: Props) => { const techdocsStorageApi = useApi(techdocsStorageApiRef); const [shadowDomRef, shadowRoot] = useShadowDom(); + const [sidebars, setSidebars] = useState(); const navigate = useNavigate(); const { value, loading, error } = useAsync(async () => { return techdocsStorageApi.getEntityDocs({ kind, namespace, name }, path); }, [techdocsStorageApi, kind, namespace, name, path]); + useEffect(() => { + const updateSidebarPosition = () => { + if (!!shadowRoot && !!shadowDomRef.current && !!sidebars) { + sidebars!.forEach(sidebar => { + const newTop = Math.max( + shadowDomRef.current!.getBoundingClientRect().top, + 0, + ); + sidebar.style.top = `${newTop}px`; + }); + } + }; + updateSidebarPosition(); + document.addEventListener('scroll', updateSidebarPosition); + return () => { + document.removeEventListener('scroll', updateSidebarPosition); + }; + }, [shadowDomRef, shadowRoot, sidebars]); + React.useEffect(() => { if (!shadowRoot || loading || error) { return; // Shadow DOM isn't ready / It's not ready / Docs was not found @@ -82,10 +102,15 @@ export const Reader = ({ entityId, onReady }: Props) => { --md-code-bg-color: ${theme.palette.background.paper}; } .md-main__inner { margin-top: 0; } - .md-sidebar { top: 0; width: 20rem; } + .md-sidebar { position: fixed; bottom: 100px; width: 20rem; } + .md-sidebar--secondary { right: 2rem; } + .md-content { margin-bottom: 50px } + .md-footer { position: fixed; bottom: 0px; width: 100vw; } + .md-footer-nav__link { width: 20rem;} + .md-content { margin-left: 20rem; max-width: calc(100% - 20rem * 2 - 3rem); } .md-typeset { font-size: 1rem; } .md-nav { font-size: 1rem; } - .md-grid { max-width: 80vw; } + .md-grid { max-width: 90vw; margin: 0 } `, }), ]); @@ -135,6 +160,16 @@ export const Reader = ({ entityId, onReady }: Props) => { }, onLoaded: (dom: Element) => { (dom as HTMLElement).style.removeProperty('opacity'); + const sideDivs: HTMLElement[] = Array.from( + shadowRoot!.querySelectorAll('.md-sidebar'), + ); + setSidebars(sideDivs); + // set sidebar height so they don't initially render in wrong position + const docTopPosition = (dom as HTMLElement).getBoundingClientRect() + .top; + sideDivs!.forEach(sidebar => { + sidebar.style.top = `${docTopPosition}px`; + }); }, }), ]);