@octopusdeploy/design-system-components
Version:
The design systems component library.
96 lines (95 loc) • 5.29 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PageSideNav = PageSideNav;
exports.isPageSideNavLink = isPageSideNavLink;
const jsx_runtime_1 = require("react/jsx-runtime");
const css_1 = require("@emotion/css");
const design_system_tokens_1 = require("@octopusdeploy/design-system-tokens");
const routing_1 = require("../../routing");
const Divider_1 = require("../Divider");
function PageSideNav({ items, tourProgress, description, isSticky }) {
return ((0, jsx_runtime_1.jsxs)("nav", { "data-amplitude-unmask": true, className: (0, css_1.cx)(pageSideNavStyles, { [pageSideNavStickyStyles]: isSticky }), children: [tourProgress, (0, jsx_runtime_1.jsx)("div", { className: pageSideNavLinksContainerStyles, children: items.map((item, index) => ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(PageSideNavItem, { item: item }) }, index))) }), description && (0, jsx_runtime_1.jsx)("div", { className: descriptionStyles, children: description })] }));
}
function PageSideNavItem({ item }) {
return isPageSideNavLink(item) ? ((0, jsx_runtime_1.jsx)(PageSideNavLink, { item: item })) : ((0, jsx_runtime_1.jsx)("div", { className: dividerWrapper, children: (0, jsx_runtime_1.jsx)(Divider_1.Divider, {}) }));
}
function PageSideNavLink({ item }) {
const Link = (0, routing_1.useOctopusLinkComponent)();
const isUrlActive = (0, routing_1.useIsUrlActive)();
const urlIsActive = isUrlActive(item.path, item.exact ? "if path matches exactly" : "if path partially matches");
const handleClick = (event) => {
const target = event.currentTarget;
const label = target.innerText ?? target.getAttribute("aria-label") ?? "";
const href = target.href;
item?.onClick(label, href);
};
return ((0, jsx_runtime_1.jsx)(Link, { href: item.path, className: urlIsActive ? selectedLinkStyles : linkStyles, onClick: handleClick, disableImplicitEventTracking: true, children: item.label }));
}
function isPageSideNavLink(item) {
return item !== "divider";
}
const pageSideNavStyles = (0, css_1.css)({
color: design_system_tokens_1.themeTokens.color.text.primary,
font: design_system_tokens_1.text.body.regular.medium,
display: "flex",
flexDirection: "column",
flexShrink: 0,
gap: design_system_tokens_1.space[16],
padding: `${design_system_tokens_1.space[16]} ${design_system_tokens_1.space[16]} ${design_system_tokens_1.space[24]} ${design_system_tokens_1.space[32]}`,
width: "15rem",
});
const pageSideNavStickyStyles = (0, css_1.css)({
position: "sticky",
top: 0,
alignSelf: "flex-start",
maxHeight: "100vh",
overflowY: "auto",
});
const pageSideNavLinksContainerStyles = (0, css_1.css)({
display: "flex",
flexDirection: "column",
gap: design_system_tokens_1.space[2],
});
const dividerWrapper = (0, css_1.css)({
padding: `${design_system_tokens_1.space[16]} 0`,
marginLeft: design_system_tokens_1.space[8],
maxWidth: "5.125rem",
});
const descriptionStyles = (0, css_1.css)({
padding: `${design_system_tokens_1.space[24]} ${design_system_tokens_1.space[8]} ${design_system_tokens_1.space[24]} ${design_system_tokens_1.space[8]}`,
overflowWrap: "break-word", // The description can contain words that are too long to fit in the sidebar, we should break these words to avoid overflowing
font: design_system_tokens_1.text.body.regular.small,
});
const linkStyles = (0, css_1.css)({
color: design_system_tokens_1.themeTokens.color.navList.text.default,
height: "2rem",
display: "flex",
alignItems: "center",
padding: `0 ${design_system_tokens_1.space[8]} 0 ${design_system_tokens_1.space[12]}`,
borderRadius: design_system_tokens_1.borderRadius.small,
":hover": {
color: design_system_tokens_1.themeTokens.color.navList.text.hover,
backgroundColor: design_system_tokens_1.themeTokens.color.navList.background.hover,
},
":active": {
color: design_system_tokens_1.themeTokens.color.navList.text.active,
background: design_system_tokens_1.themeTokens.color.navList.background.active,
},
":focus-visible": {
boxShadow: design_system_tokens_1.themeTokens.shadow.focused,
outline: "none",
},
});
const selectedLinkStyles = (0, css_1.cx)(linkStyles, (0, css_1.css)({
color: design_system_tokens_1.themeTokens.color.navList.text.active,
background: buildBackgroundGradient(design_system_tokens_1.themeTokens.color.border.selected, design_system_tokens_1.themeTokens.color.navList.background.active),
":hover": {
// We need to re-apply the same styles here because we have global css trying to style this hover state
color: design_system_tokens_1.themeTokens.color.navList.text.active,
background: buildBackgroundGradient(design_system_tokens_1.themeTokens.color.border.selected, design_system_tokens_1.themeTokens.color.navList.background.active),
},
}));
// This creates a background with a solid border on the left edge
function buildBackgroundGradient(borderColor, backgroundColor) {
return `linear-gradient(90deg, ${borderColor} 0%, ${borderColor} ${design_system_tokens_1.space[4]}, ${backgroundColor} ${design_system_tokens_1.space[4]}, ${backgroundColor} 100%)`;
}