@redocly/theme 0.21.1 → 0.21.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/lib/components/Catalog/CatalogCard.d.ts +1 -0
  2. package/lib/components/Catalog/CatalogCard.js +2 -1
  3. package/lib/components/Menu/MenuGroup.js +15 -5
  4. package/lib/components/Menu/MenuItem.js +1 -0
  5. package/lib/components/Menu/MobileMenuGroup.js +10 -4
  6. package/lib/components/Menu/styledVariables.js +2 -0
  7. package/lib/components/OpenApiDocs/ScorecardBadges.d.ts +10 -0
  8. package/lib/components/OpenApiDocs/ScorecardBadges.js +36 -0
  9. package/lib/components/OpenApiDocs/index.d.ts +1 -0
  10. package/lib/components/OpenApiDocs/index.js +1 -0
  11. package/lib/components/PageNavigation/NextButton.js +1 -0
  12. package/lib/components/PageNavigation/PreviousButton.js +1 -0
  13. package/lib/components/Sidebar/ApiCallItem.js +1 -0
  14. package/lib/components/Sidebar/styledVariables.js +2 -0
  15. package/lib/globalStyle.js +3 -0
  16. package/lib/layouts/OIDCForbidden.d.ts +2 -0
  17. package/lib/layouts/OIDCForbidden.js +95 -0
  18. package/lib/layouts/index.d.ts +1 -0
  19. package/lib/layouts/index.js +1 -0
  20. package/package.json +1 -1
  21. package/src/components/Catalog/CatalogCard.tsx +1 -1
  22. package/src/components/Menu/MenuGroup.tsx +22 -4
  23. package/src/components/Menu/MenuItem.tsx +1 -0
  24. package/src/components/Menu/MobileMenuGroup.tsx +22 -6
  25. package/src/components/Menu/styledVariables.ts +2 -0
  26. package/src/components/OpenApiDocs/ScorecardBadges.tsx +55 -0
  27. package/src/components/OpenApiDocs/index.ts +1 -0
  28. package/src/components/PageNavigation/NextButton.tsx +1 -0
  29. package/src/components/PageNavigation/PreviousButton.tsx +1 -0
  30. package/src/components/Sidebar/ApiCallItem.tsx +1 -0
  31. package/src/components/Sidebar/styledVariables.ts +2 -0
  32. package/src/globalStyle.ts +3 -0
  33. package/src/layouts/OIDCForbidden.tsx +89 -0
  34. package/src/layouts/index.ts +1 -0
@@ -3,3 +3,4 @@ import type { CatalogItem } from '../../types/portal/src/shared/types/catalog';
3
3
  export declare function CatalogCard({ item }: {
4
4
  item: CatalogItem;
5
5
  }): JSX.Element;
6
+ export declare function statusToColor(status: string): "error" | "" | "warning" | "success";
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.CatalogCard = void 0;
29
+ exports.statusToColor = exports.CatalogCard = void 0;
30
30
  const React = __importStar(require("react"));
31
31
  const styled_components_1 = __importDefault(require("styled-components"));
32
32
  const Link_1 = require("../../mocks/Link");
@@ -68,6 +68,7 @@ function statusToColor(status) {
68
68
  return '';
69
69
  }
70
70
  }
71
+ exports.statusToColor = statusToColor;
71
72
  const SelectButton = styled_components_1.default.div `
72
73
  border: 1px solid var(--catalog-card-button-border-color);
73
74
  border-radius: 100%;
@@ -55,10 +55,11 @@ function MenuGroup({ item, isExpanded, toggleExpanded, children, className, }) {
55
55
  }, [isExpanded]);
56
56
  return (react_1.default.createElement(Wrapper, { "data-component-name": "Menu/MenuGroup", className: className },
57
57
  react_1.default.createElement(MenuLinkItem_1.MenuLinkItem, { item: item },
58
- react_1.default.createElement(MenuGroupLabel, { onClick: toggleExpanded, isAlwaysExpanded: item.expanded === 'always', active: item.active, role: !item.link ? 'link' : 'none', expanded: isExpanded },
59
- item.icon ? react_1.default.createElement(SidebarItemIcon_1.SidebarItemIcon, { src: item.icon }) : null,
60
- translate(item.labelTranslationKey, item.label),
61
- !!item.items.length && (react_1.default.createElement(ArrowIcon_1.ArrowIcon, { direction: isExpanded ? 'down' : 'right', weight: "thin" })))),
58
+ react_1.default.createElement(MenuGroupLabel, { onClick: toggleExpanded, isAlwaysExpanded: item.expanded === 'always', active: item.active, role: !item.link ? 'link' : 'none', expanded: isExpanded, withArrow: !!item.items.length },
59
+ !!item.items.length && (react_1.default.createElement(ArrowIcon_1.ArrowIcon, { direction: isExpanded ? 'down' : 'right', weight: "thin" })),
60
+ react_1.default.createElement(LabelWrapper, null,
61
+ item.icon ? react_1.default.createElement(SidebarItemIcon_1.SidebarItemIcon, { src: item.icon }) : null,
62
+ translate(item.labelTranslationKey, item.label)))),
62
63
  react_1.default.createElement(MenuWrapper, { isExpanded: isExpanded }, showChildren ? children : null),
63
64
  item.separatorLine ? react_1.default.createElement(SeparatorLine_1.SeparatorLine, null) : null));
64
65
  }
@@ -82,7 +83,8 @@ const MenuGroupLabel = (0, styled_components_1.default)(MenuItemLabel_1.MenuItem
82
83
  color: var(--sidebar-item-group-text-color);
83
84
  background: var(--sidebar-item-group-background-color);
84
85
  display: flex;
85
- justify-content: space-between;
86
+ justify-content: flex-start;
87
+ gap: var(--sidebar-item-group-gap);
86
88
 
87
89
  ${({ active }) => active
88
90
  ? `color: var(--sidebar-item-group-active-text-color);
@@ -93,5 +95,13 @@ const MenuGroupLabel = (0, styled_components_1.default)(MenuItemLabel_1.MenuItem
93
95
  `
94
96
  color: var(--sidebar-item-group-active-text-color);
95
97
  `}
98
+
99
+ ${({ withArrow }) => !withArrow &&
100
+ `
101
+ padding-left: var(--sidebar-item-label-padding);
102
+ `}
103
+ `;
104
+ const LabelWrapper = styled_components_1.default.div `
105
+ display: flex;
96
106
  `;
97
107
  //# sourceMappingURL=MenuGroup.js.map
@@ -25,6 +25,7 @@ function MenuItem({ item, className }) {
25
25
  exports.MenuItem = MenuItem;
26
26
  const Wrapper = styled_components_1.default.div ``;
27
27
  const Label = (0, styled_components_1.default)(MenuItemLabel_1.MenuItemLabel) `
28
+ padding-left: var(--sidebar-item-label-padding);
28
29
  color: var(--mobile-menu-item-text-color);
29
30
 
30
31
  ${({ theme }) => theme.mediaQueries.medium} {
@@ -16,11 +16,11 @@ function MobileMenuGroup({ item, isExpanded, toggleExpanded, children, }) {
16
16
  const { translate } = (0, hooks_1.useTranslate)();
17
17
  return (react_1.default.createElement(Wrapper, { "data-component-name": "Menu/MobileMenuGroup" },
18
18
  react_1.default.createElement(MenuLinkItem_1.MenuLinkItem, { item: item },
19
- react_1.default.createElement(MenuGroupLabel, { onClick: toggleExpanded, active: item.active, expanded: isExpanded },
19
+ react_1.default.createElement(MenuGroupLabel, { onClick: toggleExpanded, active: item.active, expanded: isExpanded, withArrow: !!item.items.length },
20
+ !!item.items.length && (react_1.default.createElement(icons_1.ArrowIcon, { direction: isExpanded ? 'down' : 'right', weight: "thin" })),
20
21
  react_1.default.createElement(LabelContainer, null,
21
22
  item.icon ? react_1.default.createElement(SidebarItemIcon_1.SidebarItemIcon, { src: item.icon }) : null,
22
- react_1.default.createElement(Label, null, translate(item.labelTranslationKey, item.label))),
23
- !!item.items.length && (react_1.default.createElement(icons_1.ArrowIcon, { direction: isExpanded ? 'down' : 'right', weight: "thin" })))),
23
+ react_1.default.createElement(Label, null, translate(item.labelTranslationKey, item.label))))),
24
24
  react_1.default.createElement(MenuWrapper, { isExpanded: isExpanded }, children),
25
25
  item.separatorLine ? react_1.default.createElement(SeparatorLine_1.SeparatorLine, null) : null));
26
26
  }
@@ -39,7 +39,8 @@ const MenuGroupLabel = (0, styled_components_1.default)(MenuItemLabel_1.MenuItem
39
39
  color: var(--mobile-menu-item-text-color);
40
40
  background: var(--mobile-menu-background);
41
41
  display: flex;
42
- justify-content: space-between;
42
+ justify-content: flex-start;
43
+ gap: var(--mobile-menu-item-group-gap);
43
44
 
44
45
  ${({ active }) => active &&
45
46
  `
@@ -51,5 +52,10 @@ const MenuGroupLabel = (0, styled_components_1.default)(MenuItemLabel_1.MenuItem
51
52
  `
52
53
  color: var(--mobile-menu-item-active-text-color);
53
54
  `}
55
+
56
+ ${({ withArrow }) => !withArrow &&
57
+ `
58
+ padding-left: var(--mobile-menu-item-label-padding);
59
+ `}
54
60
  `;
55
61
  //# sourceMappingURL=MobileMenuGroup.js.map
@@ -40,6 +40,8 @@ exports.mobileMenu = (0, styled_components_1.css) `
40
40
  --mobile-menu-item-text-color: var(--text-secondary); // @presenter Color
41
41
  --mobile-menu-item-active-background-color: var(--bg-raised); // @presenter Color
42
42
  --mobile-menu-item-active-text-color: var(--text-primary); // @presenter Color
43
+ --mobile-menu-item-label-padding: var(--spacing-xl); // @presenter Spacing
44
+ --mobile-menu-item-group-gap: var(--spacing-xs); // @presenter Spacing
43
45
 
44
46
  /**
45
47
  * @tokens Mobile Menu control button
@@ -0,0 +1,10 @@
1
+ /// <reference types="react" />
2
+ interface ScorecardBadgesProps {
3
+ metadata?: {
4
+ scorecardLevel?: string;
5
+ scorecardStatus?: string;
6
+ scoreCardSlug?: string;
7
+ };
8
+ }
9
+ export declare function ScorecardBadges(props: ScorecardBadgesProps): JSX.Element | null;
10
+ export {};
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ScorecardBadges = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ const styled_components_1 = __importDefault(require("styled-components"));
9
+ const Tag_1 = require("../../components/Tag");
10
+ const Link_1 = require("../../mocks/Link");
11
+ const telemetry_1 = require("../../mocks/telemetry");
12
+ const CatalogCard_1 = require("../../components/Catalog/CatalogCard");
13
+ function ScorecardBadges(props) {
14
+ var _a, _b, _c;
15
+ return ((((_a = props.metadata) === null || _a === void 0 ? void 0 : _a.scorecardLevel) && (react_1.default.createElement(ScorecardBadgesWrapper, { "data-component-name": "OpenApiDocs/ScorecardBadges" },
16
+ react_1.default.createElement(ComplianceTag, { level: props.metadata.scorecardLevel, status: (_b = props.metadata) === null || _b === void 0 ? void 0 : _b.scorecardStatus, slug: (_c = props.metadata) === null || _c === void 0 ? void 0 : _c.scoreCardSlug })))) ||
17
+ null);
18
+ }
19
+ exports.ScorecardBadges = ScorecardBadges;
20
+ const ScorecardBadgesWrapper = styled_components_1.default.div `
21
+ display: flex;
22
+ flex-direction: row;
23
+
24
+ margin-top: var(--panel-gap-vertical);
25
+ position: absolute;
26
+ z-index: 1;
27
+ right: var(--panel-gap-horizontal);
28
+ `;
29
+ function ComplianceTag(props) {
30
+ const { level, status, slug } = props;
31
+ return (react_1.default.createElement(Link_1.Link, { to: slug },
32
+ react_1.default.createElement(Tag_1.Tag, { color: (0, CatalogCard_1.statusToColor)(status), size: "large", onClick: () => telemetry_1.telemetry.send('scorecard_link_clicked', { action: 'click' }) },
33
+ level,
34
+ " oops")));
35
+ }
36
+ //# sourceMappingURL=ScorecardBadges.js.map
@@ -7,3 +7,4 @@ export * from '../../components/OpenApiDocs/hooks/AfterOpenApiOperation';
7
7
  export * from '../../components/OpenApiDocs/hooks/AfterOpenApiOperationSummary';
8
8
  export * from '../../components/OpenApiDocs/hooks/BeforeOpenApiOperation';
9
9
  export * from '../../components/OpenApiDocs/hooks/BeforeOpenApiOperationSummary';
10
+ export * from '../../components/OpenApiDocs/ScorecardBadges';
@@ -23,4 +23,5 @@ __exportStar(require("../../components/OpenApiDocs/hooks/AfterOpenApiOperation")
23
23
  __exportStar(require("../../components/OpenApiDocs/hooks/AfterOpenApiOperationSummary"), exports);
24
24
  __exportStar(require("../../components/OpenApiDocs/hooks/BeforeOpenApiOperation"), exports);
25
25
  __exportStar(require("../../components/OpenApiDocs/hooks/BeforeOpenApiOperationSummary"), exports);
26
+ __exportStar(require("../../components/OpenApiDocs/ScorecardBadges"), exports);
26
27
  //# sourceMappingURL=index.js.map
@@ -48,5 +48,6 @@ function NextButton({ nextPage, className }) {
48
48
  exports.NextButton = NextButton;
49
49
  const StyledButton = (0, styled_components_1.default)(Button_1.Button) `
50
50
  font-family: var(--font-family-base);
51
+ text-wrap: wrap;
51
52
  `;
52
53
  //# sourceMappingURL=NextButton.js.map
@@ -28,5 +28,6 @@ function PreviousButton({ prevPage, className }) {
28
28
  exports.PreviousButton = PreviousButton;
29
29
  const StyledButton = (0, styled_components_1.default)(Button_1.Button) `
30
30
  font-family: var(--font-family-base);
31
+ text-wrap: wrap;
31
32
  `;
32
33
  //# sourceMappingURL=PreviousButton.js.map
@@ -23,6 +23,7 @@ const Label = (0, styled_components_1.default)(MenuItemLabel_1.MenuItemLabel) `
23
23
  display: flex;
24
24
  justify-content: space-between;
25
25
  color: var(--mobile-menu-item-text-color);
26
+ padding-left: var(--sidebar-item-label-padding);
26
27
 
27
28
  ${({ theme }) => theme.mediaQueries.medium} {
28
29
  color: var(--sidebar-item-text-color);
@@ -71,6 +71,7 @@ exports.sidebar = (0, styled_components_1.css) `
71
71
  --sidebar-margin-horizontal: var(--spacing-base); // @presenter Spacing
72
72
  --sidebar-item-padding-vertical: var(--spacing-xs); // @presenter Spacing
73
73
  --sidebar-item-padding-horizontal: var(--spacing-xs); // @presenter Spacing
74
+ --sidebar-item-label-padding: var(--spacing-xl); // @presenter Spacing
74
75
 
75
76
  /**
76
77
  * @tokens Sidebar item border
@@ -111,6 +112,7 @@ exports.sidebar = (0, styled_components_1.css) `
111
112
  --sidebar-item-group-background-color: var(--sidebar-background-color); // @presenter Color
112
113
  --sidebar-item-group-active-text-color: var(--sidebar-item-active-color); // @presenter Color
113
114
  --sidebar-item-group-active-background-color: var(--sidebar-item-active-background-color);
115
+ --sidebar-item-group-gap: var(--spacing-xs); // @presenter Spacing
114
116
 
115
117
  // we need a theme config for chevron-location: left (default), right-compact, right, none
116
118
  // we need another theme config for chevron-style: up-down, down-up, right-down, down-right
@@ -839,6 +839,9 @@ const pages = (0, styled_components_1.css) `
839
839
  --page-403-description-margin: 0; // @presenter Spacing
840
840
 
841
841
  --page-403-button-margin: 4em; // @presenter Spacing
842
+
843
+ --page-403-oidc-description-font-size: var(--font-size-lg);
844
+ --page-403-oidc-description-margin: var(--spacing-md) var(--spacing-sm);
842
845
 
843
846
  // @tokens End
844
847
  `;
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare function OIDCForbidden(): JSX.Element;
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.OIDCForbidden = void 0;
30
+ const react_1 = __importStar(require("react"));
31
+ const styled_components_1 = __importDefault(require("styled-components"));
32
+ const react_router_dom_1 = require("react-router-dom");
33
+ const hooks_1 = require("../mocks/hooks");
34
+ function OIDCForbidden() {
35
+ const { translate } = (0, hooks_1.useTranslate)();
36
+ const [searchParams, setSearchParams] = (0, react_router_dom_1.useSearchParams)();
37
+ const [errorDescription, setErrorDescription] = (0, react_1.useState)('');
38
+ const translationKeys = {
39
+ title: 'theme.page.forbidden.title',
40
+ };
41
+ // use whatever you want here
42
+ const URL_REGEX = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;
43
+ const renderText = (text) => text.split(' ').map((part) => URL_REGEX.test(part) ? (react_1.default.createElement(ErrorDescriptionLink, { key: part, href: part },
44
+ part,
45
+ ' ')) : (part + ' '));
46
+ (0, react_1.useEffect)(() => {
47
+ if (Array.from(searchParams).length) {
48
+ setErrorDescription(searchParams.get('error_description') || searchParams.get('error') || '');
49
+ setSearchParams({});
50
+ }
51
+ }, [searchParams, setSearchParams]);
52
+ return (react_1.default.createElement(Wrapper, { "data-component-name": "Pages/OIDCForbidden" },
53
+ react_1.default.createElement(Header, null, "403"),
54
+ react_1.default.createElement(Description, { "data-translation-key": translationKeys.title }, translate(translationKeys.title, 'Access forbidden')),
55
+ errorDescription && react_1.default.createElement(ErrorDescription, null, renderText(errorDescription))));
56
+ }
57
+ exports.OIDCForbidden = OIDCForbidden;
58
+ const Wrapper = styled_components_1.default.div `
59
+ display: flex;
60
+ flex-direction: column;
61
+ align-items: center;
62
+ justify-content: center;
63
+ margin: 25px auto;
64
+ font-family: var(--page-403-font-family);
65
+ text-align: center;
66
+ `;
67
+ const Header = styled_components_1.default.div `
68
+ color: var(--page-403-header-text-color);
69
+ margin: var(--page-403-header-margin);
70
+ font-size: var(--page-403-header-font-size);
71
+ line-height: var(--page-403-header-line-height);
72
+ font-weight: var(--page-403-header-font-weight);
73
+ `;
74
+ const Description = styled_components_1.default.div `
75
+ color: var(--page-403-description-text-color);
76
+ margin: var(--page-403-description-margin);
77
+ font-size: var(--page-403-description-font-size);
78
+ line-height: var(--page-403-description-line-height);
79
+ font-weight: var(--page-403-description-font-weight);
80
+ `;
81
+ const ErrorDescription = styled_components_1.default.div `
82
+ margin: var(--page-403-oidc-description-margin);
83
+ font-size: var(--page-403-oidc-description-font-size);
84
+ color: var(--page-403-description-text-color);
85
+ line-height: var(--page-403-description-line-height);
86
+ font-weight: var(--page-403-description-font-weight);
87
+ `;
88
+ const ErrorDescriptionLink = styled_components_1.default.a `
89
+ color: var(--link-text-color);
90
+
91
+ &:hover {
92
+ color: var(--link-hover-text-color);
93
+ }
94
+ `;
95
+ //# sourceMappingURL=OIDCForbidden.js.map
@@ -2,3 +2,4 @@ export * from '../layouts/RootLayout';
2
2
  export * from '../layouts/PageLayout';
3
3
  export * from '../layouts/NotFound';
4
4
  export * from '../layouts/Forbidden';
5
+ export * from '../layouts/OIDCForbidden';
@@ -18,4 +18,5 @@ __exportStar(require("../layouts/RootLayout"), exports);
18
18
  __exportStar(require("../layouts/PageLayout"), exports);
19
19
  __exportStar(require("../layouts/NotFound"), exports);
20
20
  __exportStar(require("../layouts/Forbidden"), exports);
21
+ __exportStar(require("../layouts/OIDCForbidden"), exports);
21
22
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/theme",
3
- "version": "0.21.1",
3
+ "version": "0.21.3",
4
4
  "description": "Shared UI components lib",
5
5
  "keywords": [
6
6
  "theme",
@@ -50,7 +50,7 @@ export function CatalogCard({ item }: { item: CatalogItem }): JSX.Element {
50
50
  );
51
51
  }
52
52
 
53
- function statusToColor(status: string) {
53
+ export function statusToColor(status: string) {
54
54
  switch (status) {
55
55
  case 'Below minimum':
56
56
  return 'error';
@@ -50,12 +50,15 @@ export function MenuGroup({
50
50
  active={item.active}
51
51
  role={!item.link ? 'link' : 'none'}
52
52
  expanded={isExpanded}
53
+ withArrow={!!item.items.length}
53
54
  >
54
- {item.icon ? <SidebarItemIcon src={item.icon} /> : null}
55
- {translate(item.labelTranslationKey, item.label)}
56
55
  {!!item.items.length && (
57
56
  <ArrowIcon direction={isExpanded ? 'down' : 'right'} weight="thin" />
58
57
  )}
58
+ <LabelWrapper>
59
+ {item.icon ? <SidebarItemIcon src={item.icon} /> : null}
60
+ {translate(item.labelTranslationKey, item.label)}
61
+ </LabelWrapper>
59
62
  </MenuGroupLabel>
60
63
  </MenuLinkItem>
61
64
 
@@ -79,7 +82,11 @@ const MenuWrapper = styled.div<{ isExpanded?: boolean }>`
79
82
  transition: max-height .8s cubic-bezier(0, 1, 0, 1) -.1s;`};
80
83
  `;
81
84
 
82
- const MenuGroupLabel = styled(MenuItemLabel)<{ isAlwaysExpanded?: boolean; expanded?: boolean }>`
85
+ const MenuGroupLabel = styled(MenuItemLabel)<{
86
+ isAlwaysExpanded?: boolean;
87
+ expanded?: boolean;
88
+ withArrow?: boolean;
89
+ }>`
83
90
  padding-left: var(--sidebar-item-padding-horizontal);
84
91
  cursor: ${(props) => (props.isAlwaysExpanded ? 'default' : 'pointer')};
85
92
  font-family: var(--sidebar-item-group-font-family);
@@ -88,7 +95,8 @@ const MenuGroupLabel = styled(MenuItemLabel)<{ isAlwaysExpanded?: boolean; expan
88
95
  color: var(--sidebar-item-group-text-color);
89
96
  background: var(--sidebar-item-group-background-color);
90
97
  display: flex;
91
- justify-content: space-between;
98
+ justify-content: flex-start;
99
+ gap: var(--sidebar-item-group-gap);
92
100
 
93
101
  ${({ active }) =>
94
102
  active
@@ -101,4 +109,14 @@ const MenuGroupLabel = styled(MenuItemLabel)<{ isAlwaysExpanded?: boolean; expan
101
109
  `
102
110
  color: var(--sidebar-item-group-active-text-color);
103
111
  `}
112
+
113
+ ${({ withArrow }) =>
114
+ !withArrow &&
115
+ `
116
+ padding-left: var(--sidebar-item-label-padding);
117
+ `}
118
+ `;
119
+
120
+ const LabelWrapper = styled.div`
121
+ display: flex;
104
122
  `;
@@ -29,6 +29,7 @@ export function MenuItem({ item, className }: MenuItemProps): JSX.Element {
29
29
  const Wrapper = styled.div``;
30
30
 
31
31
  const Label = styled(MenuItemLabel)<{ active?: boolean }>`
32
+ padding-left: var(--sidebar-item-label-padding);
32
33
  color: var(--mobile-menu-item-text-color);
33
34
 
34
35
  ${({ theme }) => theme.mediaQueries.medium} {
@@ -26,14 +26,19 @@ export function MobileMenuGroup({
26
26
  return (
27
27
  <Wrapper data-component-name="Menu/MobileMenuGroup">
28
28
  <MenuLinkItem item={item}>
29
- <MenuGroupLabel onClick={toggleExpanded} active={item.active} expanded={isExpanded}>
29
+ <MenuGroupLabel
30
+ onClick={toggleExpanded}
31
+ active={item.active}
32
+ expanded={isExpanded}
33
+ withArrow={!!item.items.length}
34
+ >
35
+ {!!item.items.length && (
36
+ <ArrowIcon direction={isExpanded ? 'down' : 'right'} weight="thin" />
37
+ )}
30
38
  <LabelContainer>
31
39
  {item.icon ? <SidebarItemIcon src={item.icon} /> : null}
32
40
  <Label>{translate(item.labelTranslationKey, item.label)}</Label>
33
41
  </LabelContainer>
34
- {!!item.items.length && (
35
- <ArrowIcon direction={isExpanded ? 'down' : 'right'} weight="thin" />
36
- )}
37
42
  </MenuGroupLabel>
38
43
  </MenuLinkItem>
39
44
  <MenuWrapper isExpanded={isExpanded}>{children}</MenuWrapper>
@@ -56,11 +61,16 @@ const MenuWrapper = styled.div<{ isExpanded?: boolean }>`
56
61
  ${(props) => !props.isExpanded && 'max-height: 0'}
57
62
  `;
58
63
 
59
- const MenuGroupLabel = styled(MenuItemLabel)<{ active?: boolean; expanded?: boolean }>`
64
+ const MenuGroupLabel = styled(MenuItemLabel)<{
65
+ active?: boolean;
66
+ expanded?: boolean;
67
+ withArrow?: boolean;
68
+ }>`
60
69
  color: var(--mobile-menu-item-text-color);
61
70
  background: var(--mobile-menu-background);
62
71
  display: flex;
63
- justify-content: space-between;
72
+ justify-content: flex-start;
73
+ gap: var(--mobile-menu-item-group-gap);
64
74
 
65
75
  ${({ active }) =>
66
76
  active &&
@@ -74,4 +84,10 @@ const MenuGroupLabel = styled(MenuItemLabel)<{ active?: boolean; expanded?: bool
74
84
  `
75
85
  color: var(--mobile-menu-item-active-text-color);
76
86
  `}
87
+
88
+ ${({ withArrow }) =>
89
+ !withArrow &&
90
+ `
91
+ padding-left: var(--mobile-menu-item-label-padding);
92
+ `}
77
93
  `;
@@ -38,6 +38,8 @@ export const mobileMenu = css`
38
38
  --mobile-menu-item-text-color: var(--text-secondary); // @presenter Color
39
39
  --mobile-menu-item-active-background-color: var(--bg-raised); // @presenter Color
40
40
  --mobile-menu-item-active-text-color: var(--text-primary); // @presenter Color
41
+ --mobile-menu-item-label-padding: var(--spacing-xl); // @presenter Spacing
42
+ --mobile-menu-item-group-gap: var(--spacing-xs); // @presenter Spacing
41
43
 
42
44
  /**
43
45
  * @tokens Mobile Menu control button
@@ -0,0 +1,55 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import { Tag } from '@theme/components/Tag';
5
+ import { Link } from '@portal/Link';
6
+ import { telemetry } from '@portal/telemetry';
7
+ import { statusToColor } from '@theme/components/Catalog/CatalogCard';
8
+
9
+ interface ScorecardBadgesProps {
10
+ metadata?: {
11
+ scorecardLevel?: string;
12
+ scorecardStatus?: string;
13
+ scoreCardSlug?: string;
14
+ };
15
+ }
16
+
17
+ export function ScorecardBadges(props: ScorecardBadgesProps) {
18
+ return (
19
+ (props.metadata?.scorecardLevel && (
20
+ <ScorecardBadgesWrapper data-component-name="OpenApiDocs/ScorecardBadges">
21
+ <ComplianceTag
22
+ level={props.metadata.scorecardLevel as string}
23
+ status={props.metadata?.scorecardStatus as string}
24
+ slug={props.metadata?.scoreCardSlug as string}
25
+ />
26
+ </ScorecardBadgesWrapper>
27
+ )) ||
28
+ null
29
+ );
30
+ }
31
+
32
+ const ScorecardBadgesWrapper = styled.div`
33
+ display: flex;
34
+ flex-direction: row;
35
+
36
+ margin-top: var(--panel-gap-vertical);
37
+ position: absolute;
38
+ z-index: 1;
39
+ right: var(--panel-gap-horizontal);
40
+ `;
41
+
42
+ function ComplianceTag(props: { level: string; status: string; slug: string }) {
43
+ const { level, status, slug } = props;
44
+ return (
45
+ <Link to={slug}>
46
+ <Tag
47
+ color={statusToColor(status)}
48
+ size="large"
49
+ onClick={() => telemetry.send('scorecard_link_clicked', { action: 'click' })}
50
+ >
51
+ {level} oops
52
+ </Tag>
53
+ </Link>
54
+ );
55
+ }
@@ -7,3 +7,4 @@ export * from '@theme/components/OpenApiDocs/hooks/AfterOpenApiOperation';
7
7
  export * from '@theme/components/OpenApiDocs/hooks/AfterOpenApiOperationSummary';
8
8
  export * from '@theme/components/OpenApiDocs/hooks/BeforeOpenApiOperation';
9
9
  export * from '@theme/components/OpenApiDocs/hooks/BeforeOpenApiOperationSummary';
10
+ export * from '@theme/components/OpenApiDocs/ScorecardBadges';
@@ -42,4 +42,5 @@ export function NextButton({ nextPage, className }: NextPageType): JSX.Element {
42
42
 
43
43
  const StyledButton = styled(Button)`
44
44
  font-family: var(--font-family-base);
45
+ text-wrap: wrap;
45
46
  `;
@@ -45,4 +45,5 @@ export function PreviousButton({ prevPage, className }: PreviousPageType): JSX.E
45
45
 
46
46
  const StyledButton = styled(Button)`
47
47
  font-family: var(--font-family-base);
48
+ text-wrap: wrap;
48
49
  `;
@@ -28,6 +28,7 @@ const Label = styled(MenuItemLabel)`
28
28
  display: flex;
29
29
  justify-content: space-between;
30
30
  color: var(--mobile-menu-item-text-color);
31
+ padding-left: var(--sidebar-item-label-padding);
31
32
 
32
33
  ${({ theme }) => theme.mediaQueries.medium} {
33
34
  color: var(--sidebar-item-text-color);
@@ -69,6 +69,7 @@ export const sidebar = css`
69
69
  --sidebar-margin-horizontal: var(--spacing-base); // @presenter Spacing
70
70
  --sidebar-item-padding-vertical: var(--spacing-xs); // @presenter Spacing
71
71
  --sidebar-item-padding-horizontal: var(--spacing-xs); // @presenter Spacing
72
+ --sidebar-item-label-padding: var(--spacing-xl); // @presenter Spacing
72
73
 
73
74
  /**
74
75
  * @tokens Sidebar item border
@@ -109,6 +110,7 @@ export const sidebar = css`
109
110
  --sidebar-item-group-background-color: var(--sidebar-background-color); // @presenter Color
110
111
  --sidebar-item-group-active-text-color: var(--sidebar-item-active-color); // @presenter Color
111
112
  --sidebar-item-group-active-background-color: var(--sidebar-item-active-background-color);
113
+ --sidebar-item-group-gap: var(--spacing-xs); // @presenter Spacing
112
114
 
113
115
  // we need a theme config for chevron-location: left (default), right-compact, right, none
114
116
  // we need another theme config for chevron-style: up-down, down-up, right-down, down-right
@@ -850,6 +850,9 @@ const pages = css`
850
850
  --page-403-description-margin: 0; // @presenter Spacing
851
851
 
852
852
  --page-403-button-margin: 4em; // @presenter Spacing
853
+
854
+ --page-403-oidc-description-font-size: var(--font-size-lg);
855
+ --page-403-oidc-description-margin: var(--spacing-md) var(--spacing-sm);
853
856
 
854
857
  // @tokens End
855
858
  `
@@ -0,0 +1,89 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import styled from 'styled-components';
3
+ import { useSearchParams } from 'react-router-dom';
4
+
5
+ import { useTranslate } from '@portal/hooks';
6
+
7
+ export function OIDCForbidden(): JSX.Element {
8
+ const { translate } = useTranslate();
9
+ const [searchParams, setSearchParams] = useSearchParams();
10
+ const [errorDescription, setErrorDescription] = useState<string>('');
11
+
12
+ const translationKeys = {
13
+ title: 'theme.page.forbidden.title',
14
+ };
15
+
16
+ // use whatever you want here
17
+ const URL_REGEX =
18
+ /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;
19
+
20
+ const renderText = (text: string) =>
21
+ text.split(' ').map((part: string) =>
22
+ URL_REGEX.test(part) ? (
23
+ <ErrorDescriptionLink key={part} href={part}>
24
+ {part}{' '}
25
+ </ErrorDescriptionLink>
26
+ ) : (
27
+ part + ' '
28
+ ),
29
+ );
30
+
31
+ useEffect(() => {
32
+ if (Array.from(searchParams).length) {
33
+ setErrorDescription(searchParams.get('error_description') || searchParams.get('error') || '');
34
+ setSearchParams({});
35
+ }
36
+ }, [searchParams, setSearchParams]);
37
+
38
+ return (
39
+ <Wrapper data-component-name="Pages/OIDCForbidden">
40
+ <Header>403</Header>
41
+ <Description data-translation-key={translationKeys.title}>
42
+ {translate(translationKeys.title, 'Access forbidden')}
43
+ </Description>
44
+ {errorDescription && <ErrorDescription>{renderText(errorDescription)}</ErrorDescription>}
45
+ </Wrapper>
46
+ );
47
+ }
48
+
49
+ const Wrapper = styled.div`
50
+ display: flex;
51
+ flex-direction: column;
52
+ align-items: center;
53
+ justify-content: center;
54
+ margin: 25px auto;
55
+ font-family: var(--page-403-font-family);
56
+ text-align: center;
57
+ `;
58
+
59
+ const Header = styled.div`
60
+ color: var(--page-403-header-text-color);
61
+ margin: var(--page-403-header-margin);
62
+ font-size: var(--page-403-header-font-size);
63
+ line-height: var(--page-403-header-line-height);
64
+ font-weight: var(--page-403-header-font-weight);
65
+ `;
66
+
67
+ const Description = styled.div`
68
+ color: var(--page-403-description-text-color);
69
+ margin: var(--page-403-description-margin);
70
+ font-size: var(--page-403-description-font-size);
71
+ line-height: var(--page-403-description-line-height);
72
+ font-weight: var(--page-403-description-font-weight);
73
+ `;
74
+
75
+ const ErrorDescription = styled.div`
76
+ margin: var(--page-403-oidc-description-margin);
77
+ font-size: var(--page-403-oidc-description-font-size);
78
+ color: var(--page-403-description-text-color);
79
+ line-height: var(--page-403-description-line-height);
80
+ font-weight: var(--page-403-description-font-weight);
81
+ `;
82
+
83
+ const ErrorDescriptionLink = styled.a`
84
+ color: var(--link-text-color);
85
+
86
+ &:hover {
87
+ color: var(--link-hover-text-color);
88
+ }
89
+ `;
@@ -2,3 +2,4 @@ export * from '@theme/layouts/RootLayout';
2
2
  export * from '@theme/layouts/PageLayout';
3
3
  export * from '@theme/layouts/NotFound';
4
4
  export * from '@theme/layouts/Forbidden';
5
+ export * from '@theme/layouts/OIDCForbidden';