@redocly/theme 0.54.3 → 0.55.0-next.1
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.
- package/lib/components/Breadcrumbs/Breadcrumbs.js +3 -3
- package/lib/components/Button/Button.d.ts +0 -1
- package/lib/components/Buttons/EditPageButton.js +3 -3
- package/lib/components/CatalogClassic/CatalogClassicActions.js +3 -3
- package/lib/components/CatalogClassic/CatalogClassicCard.js +3 -3
- package/lib/components/CatalogClassic/CatalogClassicInfoBlock.js +3 -3
- package/lib/components/CodeBlock/CodeBlockControls.js +3 -3
- package/lib/components/Feedback/Feedback.js +3 -3
- package/lib/components/Feedback/ReportDialog.js +3 -3
- package/lib/components/Filter/FilterCheckboxes.js +3 -3
- package/lib/components/Footer/FooterItem.js +7 -4
- package/lib/components/LanguagePicker/LanguagePicker.js +3 -3
- package/lib/components/Logo/Logo.js +3 -3
- package/lib/components/Menu/MenuItem.js +3 -3
- package/lib/components/Navbar/Navbar.js +4 -4
- package/lib/components/Navbar/NavbarItem.js +3 -3
- package/lib/components/Search/SearchDialog.js +5 -5
- package/lib/components/Search/SearchInput.js +3 -3
- package/lib/components/Search/SearchRecent.js +3 -3
- package/lib/components/Search/SearchTrigger.js +4 -2
- package/lib/components/SidebarActions/SidebarActions.js +5 -5
- package/lib/components/TableOfContent/TableOfContent.js +3 -3
- package/lib/components/UserMenu/LoginButton.js +3 -3
- package/lib/components/UserMenu/LogoutMenuItem.js +3 -3
- package/lib/core/hooks/__mocks__/use-theme-hooks.d.ts +0 -3
- package/lib/core/hooks/__mocks__/use-theme-hooks.js +0 -3
- package/lib/core/hooks/index.d.ts +2 -0
- package/lib/core/hooks/index.js +2 -0
- package/lib/core/hooks/search/use-search-dialog.js +5 -5
- package/lib/core/hooks/use-color-switcher.js +3 -3
- package/lib/core/hooks/use-input-key-commands.js +2 -1
- package/lib/core/hooks/use-page-active-version.d.ts +1 -0
- package/lib/core/hooks/use-page-active-version.js +11 -0
- package/lib/core/hooks/use-page-versions.d.ts +7 -0
- package/lib/core/hooks/use-page-versions.js +15 -0
- package/lib/core/hooks/use-product-picker.js +3 -3
- package/lib/core/hooks/use-theme-hooks.js +4 -1
- package/lib/core/styles/dark.js +14 -3
- package/lib/core/styles/global.js +9 -6
- package/lib/core/types/hooks.d.ts +0 -5
- package/lib/core/types/l10n.d.ts +1 -1
- package/lib/core/utils/get-user-agent.d.ts +4 -0
- package/lib/core/utils/get-user-agent.js +15 -0
- package/lib/core/utils/index.d.ts +1 -0
- package/lib/core/utils/index.js +1 -0
- package/lib/markdoc/components/Tabs/TabList.d.ts +4 -1
- package/lib/markdoc/components/Tabs/TabList.js +36 -16
- package/lib/markdoc/components/Tabs/Tabs.js +7 -3
- package/package.json +3 -3
- package/src/components/Breadcrumbs/Breadcrumbs.tsx +3 -3
- package/src/components/Button/Button.tsx +1 -1
- package/src/components/Buttons/EditPageButton.tsx +3 -3
- package/src/components/CatalogClassic/CatalogClassicActions.tsx +3 -3
- package/src/components/CatalogClassic/CatalogClassicCard.tsx +3 -3
- package/src/components/CatalogClassic/CatalogClassicInfoBlock.tsx +3 -3
- package/src/components/CodeBlock/CodeBlockControls.tsx +3 -3
- package/src/components/Feedback/Feedback.tsx +3 -3
- package/src/components/Feedback/ReportDialog.tsx +3 -3
- package/src/components/Filter/FilterCheckboxes.tsx +3 -3
- package/src/components/Footer/FooterItem.tsx +12 -4
- package/src/components/LanguagePicker/LanguagePicker.tsx +3 -3
- package/src/components/Logo/Logo.tsx +3 -3
- package/src/components/Menu/MenuItem.tsx +3 -3
- package/src/components/Navbar/Navbar.tsx +4 -4
- package/src/components/Navbar/NavbarItem.tsx +3 -3
- package/src/components/Search/SearchDialog.tsx +5 -5
- package/src/components/Search/SearchInput.tsx +3 -3
- package/src/components/Search/SearchRecent.tsx +3 -3
- package/src/components/Search/SearchTrigger.tsx +9 -3
- package/src/components/SidebarActions/SidebarActions.tsx +5 -5
- package/src/components/TableOfContent/TableOfContent.tsx +3 -3
- package/src/components/UserMenu/LoginButton.tsx +3 -3
- package/src/components/UserMenu/LogoutMenuItem.tsx +3 -3
- package/src/core/hooks/__mocks__/use-theme-hooks.ts +0 -3
- package/src/core/hooks/index.ts +2 -0
- package/src/core/hooks/search/use-search-dialog.ts +5 -5
- package/src/core/hooks/use-color-switcher.ts +3 -3
- package/src/core/hooks/use-input-key-commands.ts +3 -1
- package/src/core/hooks/use-page-active-version.ts +9 -0
- package/src/core/hooks/use-page-versions.ts +20 -0
- package/src/core/hooks/use-product-picker.ts +3 -3
- package/src/core/hooks/use-theme-hooks.ts +4 -1
- package/src/core/styles/dark.ts +15 -3
- package/src/core/styles/global.ts +9 -6
- package/src/core/types/hooks.ts +1 -4
- package/src/core/types/l10n.ts +1 -1
- package/src/core/utils/get-user-agent.ts +13 -0
- package/src/core/utils/index.ts +1 -0
- package/src/markdoc/components/Tabs/TabList.tsx +69 -38
- package/src/markdoc/components/Tabs/Tabs.tsx +7 -3
- package/src/settings.yaml +1 -0
|
@@ -20,8 +20,8 @@ export type LanguagePickerProps = {
|
|
|
20
20
|
|
|
21
21
|
export function LanguagePicker(props: LanguagePickerProps): JSX.Element | null {
|
|
22
22
|
const { currentLocale, locales, setLocale } = useLanguagePicker();
|
|
23
|
-
const {
|
|
24
|
-
const
|
|
23
|
+
const { useTelemetry } = useThemeHooks();
|
|
24
|
+
const telemetry = useTelemetry();
|
|
25
25
|
|
|
26
26
|
if (locales.length < 2 || !currentLocale) {
|
|
27
27
|
return null;
|
|
@@ -40,7 +40,7 @@ export function LanguagePicker(props: LanguagePickerProps): JSX.Element | null {
|
|
|
40
40
|
onAction: () => {
|
|
41
41
|
setLocale(locale.code);
|
|
42
42
|
props.onChangeLanguage(locale.code);
|
|
43
|
-
|
|
43
|
+
telemetry.send({
|
|
44
44
|
type: 'language_picker_locale.changed',
|
|
45
45
|
payload: { locale: locale.code },
|
|
46
46
|
});
|
|
@@ -14,8 +14,8 @@ export type LogoProps = {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
export function Logo({ config, className, ...otherProps }: LogoProps): JSX.Element | null {
|
|
17
|
-
const {
|
|
18
|
-
const
|
|
17
|
+
const { useTelemetry } = useThemeHooks();
|
|
18
|
+
const telemetry = useTelemetry();
|
|
19
19
|
|
|
20
20
|
if (!config?.image && !config?.srcSet) {
|
|
21
21
|
return null;
|
|
@@ -27,7 +27,7 @@ export function Logo({ config, className, ...otherProps }: LogoProps): JSX.Eleme
|
|
|
27
27
|
return (
|
|
28
28
|
<LogoWrapper data-component-name="Logo/Logo" className={className} {...otherProps}>
|
|
29
29
|
{config.link ? (
|
|
30
|
-
<Link to={config.link} onClick={() =>
|
|
30
|
+
<Link to={config.link} onClick={() => telemetry.send({ type: 'logo.clicked' })}>
|
|
31
31
|
{image}
|
|
32
32
|
</Link>
|
|
33
33
|
) : (
|
|
@@ -17,7 +17,7 @@ import { Badge } from '@redocly/theme/components/Badge/Badge';
|
|
|
17
17
|
|
|
18
18
|
export function MenuItem(props: React.PropsWithChildren<MenuItemProps>): JSX.Element {
|
|
19
19
|
const { item, depth, className, onClick } = props;
|
|
20
|
-
const { useTranslate,
|
|
20
|
+
const { useTranslate, useTelemetry } = useThemeHooks();
|
|
21
21
|
const { translate } = useTranslate();
|
|
22
22
|
const type = getMenuItemType(item);
|
|
23
23
|
const nestedMenuRef = useRef<HTMLDivElement>(null);
|
|
@@ -28,7 +28,7 @@ export function MenuItem(props: React.PropsWithChildren<MenuItemProps>): JSX.Ele
|
|
|
28
28
|
labelRef,
|
|
29
29
|
nestedMenuRef,
|
|
30
30
|
});
|
|
31
|
-
const
|
|
31
|
+
const telemetry = useTelemetry();
|
|
32
32
|
const isDrilldown = type === MenuItemType.DrillDown;
|
|
33
33
|
const isSeparator = type === MenuItemType.Separator;
|
|
34
34
|
const isNested = type === MenuItemType.Group;
|
|
@@ -36,7 +36,7 @@ export function MenuItem(props: React.PropsWithChildren<MenuItemProps>): JSX.Ele
|
|
|
36
36
|
const hasHttpTag = !!item.httpVerb || type === MenuItemType.Operation;
|
|
37
37
|
|
|
38
38
|
const handleOnClick = () => {
|
|
39
|
-
|
|
39
|
+
telemetry.send({
|
|
40
40
|
type: 'sidebar.item_clicked',
|
|
41
41
|
payload: {
|
|
42
42
|
label: item.label,
|
|
@@ -25,9 +25,9 @@ export type NavbarProps = {
|
|
|
25
25
|
export function Navbar({ className }: NavbarProps): JSX.Element | null {
|
|
26
26
|
const { isOpen, closeMobileMenu, openMobileMenu } = useMobileMenu(false);
|
|
27
27
|
const themeConfig = useThemeConfig();
|
|
28
|
-
const { useL10n,
|
|
28
|
+
const { useL10n, useTelemetry } = useThemeHooks();
|
|
29
29
|
const { changeLanguage } = useL10n();
|
|
30
|
-
const
|
|
30
|
+
const telemetry = useTelemetry();
|
|
31
31
|
|
|
32
32
|
const menu = themeConfig.navbar?.items;
|
|
33
33
|
|
|
@@ -58,11 +58,11 @@ export function Navbar({ className }: NavbarProps): JSX.Element | null {
|
|
|
58
58
|
isOpen
|
|
59
59
|
? () => {
|
|
60
60
|
closeMobileMenu();
|
|
61
|
-
|
|
61
|
+
telemetry.send({ type: 'mobile_menu_button_close.clicked' });
|
|
62
62
|
}
|
|
63
63
|
: () => {
|
|
64
64
|
openMobileMenu();
|
|
65
|
-
|
|
65
|
+
telemetry.send({ type: 'mobile_menu_button_open.clicked' });
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
icon={isOpen ? <CloseIcon /> : <MenuIcon />}
|
|
@@ -25,10 +25,10 @@ export type NavbarItemProps = {
|
|
|
25
25
|
|
|
26
26
|
export function NavbarItem({ navItem, className }: NavbarItemProps): JSX.Element | null {
|
|
27
27
|
const { pathname } = useLocation();
|
|
28
|
-
const { useTranslate, useL10nConfig,
|
|
28
|
+
const { useTranslate, useL10nConfig, useTelemetry } = useThemeHooks();
|
|
29
29
|
const { translate } = useTranslate();
|
|
30
30
|
const { defaultLocale, currentLocale, locales } = useL10nConfig();
|
|
31
|
-
const
|
|
31
|
+
const telemetry = useTelemetry();
|
|
32
32
|
|
|
33
33
|
if (navItem.type !== 'link' && !navItem.items) return null;
|
|
34
34
|
|
|
@@ -46,7 +46,7 @@ export function NavbarItem({ navItem, className }: NavbarItemProps): JSX.Element
|
|
|
46
46
|
active={isActive}
|
|
47
47
|
className={className}
|
|
48
48
|
onClick={() =>
|
|
49
|
-
|
|
49
|
+
telemetry.send({ type: 'navbar.menu_item_clicked', payload: { type: item.type } })
|
|
50
50
|
}
|
|
51
51
|
external={item.external}
|
|
52
52
|
target={item.target}
|
|
@@ -37,9 +37,9 @@ export type SearchDialogProps = {
|
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
export function SearchDialog({ onClose, className }: SearchDialogProps): JSX.Element {
|
|
40
|
-
const { useTranslate, useCurrentProduct, useSearch, useProducts, useAiSearch,
|
|
40
|
+
const { useTranslate, useCurrentProduct, useSearch, useProducts, useAiSearch, useTelemetry } =
|
|
41
41
|
useThemeHooks();
|
|
42
|
-
const
|
|
42
|
+
const telemetry = useTelemetry();
|
|
43
43
|
const products = useProducts();
|
|
44
44
|
const currentProduct = useCurrentProduct();
|
|
45
45
|
const [product, setProduct] = useState(currentProduct);
|
|
@@ -139,7 +139,7 @@ export function SearchDialog({ onClose, className }: SearchDialogProps): JSX.Ele
|
|
|
139
139
|
innerRef={innerRef}
|
|
140
140
|
onClick={() => {
|
|
141
141
|
addSearchHistoryItem(query);
|
|
142
|
-
|
|
142
|
+
telemetry.send({
|
|
143
143
|
type: 'search.result.clicked',
|
|
144
144
|
payload: {
|
|
145
145
|
query,
|
|
@@ -154,7 +154,7 @@ export function SearchDialog({ onClose, className }: SearchDialogProps): JSX.Ele
|
|
|
154
154
|
/>
|
|
155
155
|
);
|
|
156
156
|
},
|
|
157
|
-
[onClose, product, products, addSearchHistoryItem, query,
|
|
157
|
+
[onClose, product, products, addSearchHistoryItem, query, telemetry, mode],
|
|
158
158
|
);
|
|
159
159
|
|
|
160
160
|
const showLoadMore = useCallback(
|
|
@@ -381,7 +381,7 @@ export function SearchDialog({ onClose, className }: SearchDialogProps): JSX.Ele
|
|
|
381
381
|
<>
|
|
382
382
|
<SearchRecent
|
|
383
383
|
onSelect={(query, index) => {
|
|
384
|
-
|
|
384
|
+
telemetry.send({
|
|
385
385
|
type: 'search.recent.clicked',
|
|
386
386
|
payload: {
|
|
387
387
|
query,
|
|
@@ -33,9 +33,9 @@ export function SearchInput({
|
|
|
33
33
|
onSubmit,
|
|
34
34
|
className,
|
|
35
35
|
}: SearchInputProps): JSX.Element {
|
|
36
|
-
const {
|
|
36
|
+
const { useTelemetry } = useThemeHooks();
|
|
37
37
|
const { addSearchHistoryItem } = useRecentSearches();
|
|
38
|
-
const
|
|
38
|
+
const telemetry = useTelemetry();
|
|
39
39
|
|
|
40
40
|
const { onKeyDown } = useInputKeyCommands({
|
|
41
41
|
onEnter: (event) => onSubmit?.(event),
|
|
@@ -51,7 +51,7 @@ export function SearchInput({
|
|
|
51
51
|
const handleOnReset = () => {
|
|
52
52
|
onChange('');
|
|
53
53
|
addSearchHistoryItem(value);
|
|
54
|
-
|
|
54
|
+
telemetry.send({ type: 'search_input_reset_button.clicked' });
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
return (
|
|
@@ -16,16 +16,16 @@ export type SearchRecentProps = {
|
|
|
16
16
|
|
|
17
17
|
export function SearchRecent({ onSelect, className }: SearchRecentProps): JSX.Element | null {
|
|
18
18
|
const { items, removeSearchHistoryItem } = useRecentSearches();
|
|
19
|
-
const { useTranslate,
|
|
19
|
+
const { useTranslate, useTelemetry } = useThemeHooks();
|
|
20
20
|
const { translate } = useTranslate();
|
|
21
|
-
const
|
|
21
|
+
const telemetry = useTelemetry();
|
|
22
22
|
|
|
23
23
|
if (!items || !items.length) return null;
|
|
24
24
|
|
|
25
25
|
const handleOnRemove = (e: React.MouseEvent<SVGSVGElement, MouseEvent>, item: string) => {
|
|
26
26
|
e.stopPropagation();
|
|
27
27
|
removeSearchHistoryItem(item);
|
|
28
|
-
|
|
28
|
+
telemetry.send({ type: 'search_recent_remove_button.clicked' });
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>, item: string, index: number) => {
|
|
@@ -6,7 +6,7 @@ import type { JSX } from 'react';
|
|
|
6
6
|
import { useThemeConfig, useThemeHooks } from '@redocly/theme/core/hooks';
|
|
7
7
|
import { Button } from '@redocly/theme/components/Button/Button';
|
|
8
8
|
import { SearchIcon } from '@redocly/theme/icons/SearchIcon/SearchIcon';
|
|
9
|
-
import { breakpoints } from '@redocly/theme/core/utils';
|
|
9
|
+
import { breakpoints, getUserAgent } from '@redocly/theme/core/utils';
|
|
10
10
|
|
|
11
11
|
export type SearchTriggerProps = {
|
|
12
12
|
onClick: () => void;
|
|
@@ -18,7 +18,8 @@ export function SearchTrigger({ onClick, className }: SearchTriggerProps): JSX.E
|
|
|
18
18
|
const { useTranslate } = useThemeHooks();
|
|
19
19
|
const { translate } = useTranslate();
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const defaultKeyShortcut = '⌘+K,CTRL+K';
|
|
22
|
+
const keyShortcuts = themeSettings?.search?.shortcuts ?? [defaultKeyShortcut];
|
|
22
23
|
let mainShortcutKey: string | null | undefined = null;
|
|
23
24
|
|
|
24
25
|
if (keyShortcuts) {
|
|
@@ -30,6 +31,7 @@ export function SearchTrigger({ onClick, className }: SearchTriggerProps): JSX.E
|
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
mainShortcutKey = mainShortcutKey?.toUpperCase();
|
|
34
|
+
const isMac = getUserAgent().includes('Mac');
|
|
33
35
|
|
|
34
36
|
return (
|
|
35
37
|
<SearchTriggerWrapper
|
|
@@ -49,7 +51,11 @@ export function SearchTrigger({ onClick, className }: SearchTriggerProps): JSX.E
|
|
|
49
51
|
>
|
|
50
52
|
<SearchIcon />
|
|
51
53
|
{translate('search.navbar.label', 'Search')}
|
|
52
|
-
{mainShortcutKey
|
|
54
|
+
{mainShortcutKey === defaultKeyShortcut ? (
|
|
55
|
+
<span>{isMac ? '⌘K' : 'Ctrl+K'}</span>
|
|
56
|
+
) : (
|
|
57
|
+
<span>{mainShortcutKey}</span>
|
|
58
|
+
)}
|
|
53
59
|
</SearchTriggerInput>
|
|
54
60
|
</SearchTriggerWrapper>
|
|
55
61
|
);
|
|
@@ -34,9 +34,9 @@ export const SidebarActions = ({
|
|
|
34
34
|
requestAccessButton,
|
|
35
35
|
className,
|
|
36
36
|
}: SidebarActionsProps) => {
|
|
37
|
-
const {
|
|
37
|
+
const { useTelemetry, useTranslate } = useThemeHooks();
|
|
38
38
|
const { translate } = useTranslate();
|
|
39
|
-
const
|
|
39
|
+
const telemetry = useTelemetry();
|
|
40
40
|
return (
|
|
41
41
|
<ControlsWrap
|
|
42
42
|
className={className}
|
|
@@ -48,9 +48,9 @@ export const SidebarActions = ({
|
|
|
48
48
|
onClick={() => {
|
|
49
49
|
onChangeCollapseSidebarClick();
|
|
50
50
|
if (collapsedSidebar) {
|
|
51
|
-
|
|
51
|
+
telemetry.send({ type: 'sidebar.item_expanded' });
|
|
52
52
|
} else {
|
|
53
|
-
|
|
53
|
+
telemetry.send({ type: 'sidebar.item_collapsed' });
|
|
54
54
|
}
|
|
55
55
|
}}
|
|
56
56
|
title={
|
|
@@ -70,7 +70,7 @@ export const SidebarActions = ({
|
|
|
70
70
|
layout={layout}
|
|
71
71
|
onClick={() => {
|
|
72
72
|
onChangeViewClick();
|
|
73
|
-
|
|
73
|
+
telemetry.send({ type: 'change_layout_button.clicked' });
|
|
74
74
|
}}
|
|
75
75
|
/>
|
|
76
76
|
</ControlsWrapChangeLayoutButtons>
|
|
@@ -25,9 +25,9 @@ export type TableOfContentProps = {
|
|
|
25
25
|
|
|
26
26
|
export function TableOfContent(props: TableOfContentProps): JSX.Element | null {
|
|
27
27
|
const { headings, contentWrapper, className } = props;
|
|
28
|
-
const { useTranslate,
|
|
28
|
+
const { useTranslate, useTelemetry } = useThemeHooks();
|
|
29
29
|
const { translate } = useTranslate();
|
|
30
|
-
const
|
|
30
|
+
const telemetry = useTelemetry();
|
|
31
31
|
|
|
32
32
|
const sidebar = React.useRef<HTMLDivElement | null>(null);
|
|
33
33
|
useFullHeight(sidebar);
|
|
@@ -66,7 +66,7 @@ export function TableOfContent(props: TableOfContentProps): JSX.Element | null {
|
|
|
66
66
|
className={activeHeadingId === heading.id ? 'active' : ''}
|
|
67
67
|
dangerouslySetInnerHTML={{ __html: heading.value || '' }}
|
|
68
68
|
data-testid={`toc-${heading.value}`}
|
|
69
|
-
onClick={() =>
|
|
69
|
+
onClick={() => telemetry.send({ type: 'toc_item.clicked' })}
|
|
70
70
|
/>
|
|
71
71
|
);
|
|
72
72
|
})}
|
|
@@ -11,16 +11,16 @@ export type LoginButtonProps = {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
export function LoginButton({ href, className }: LoginButtonProps): JSX.Element {
|
|
14
|
-
const { useTranslate,
|
|
14
|
+
const { useTranslate, useTelemetry } = useThemeHooks();
|
|
15
15
|
const { translate } = useTranslate();
|
|
16
|
-
const
|
|
16
|
+
const telemetry = useTelemetry();
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
19
|
<div data-component-name="UserMenu/LoginButton" className={className}>
|
|
20
20
|
<Button
|
|
21
21
|
data-translation-key="userMenu.login"
|
|
22
22
|
to={href}
|
|
23
|
-
onClick={() =>
|
|
23
|
+
onClick={() => telemetry.send({ type: 'login_button.clicked' })}
|
|
24
24
|
data-testid="login-btn"
|
|
25
25
|
extraClass={className}
|
|
26
26
|
variant="primary"
|
|
@@ -12,13 +12,13 @@ export type LogoutMenuItemProps = {
|
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export function LogoutMenuItem({ iconOnly, className }: LogoutMenuItemProps): JSX.Element {
|
|
15
|
-
const { useTranslate,
|
|
15
|
+
const { useTranslate, useTelemetry, useUserMenu } = useThemeHooks();
|
|
16
16
|
const { handleLogout } = useUserMenu();
|
|
17
|
-
const
|
|
17
|
+
const telemetry = useTelemetry();
|
|
18
18
|
const { translate } = useTranslate();
|
|
19
19
|
|
|
20
20
|
const handleClick = () => {
|
|
21
|
-
|
|
21
|
+
telemetry.send({ type: 'logout_menu_item.clicked' });
|
|
22
22
|
handleLogout();
|
|
23
23
|
};
|
|
24
24
|
|
|
@@ -11,9 +11,6 @@ export const useThemeHooks = jest.fn(() => ({
|
|
|
11
11
|
useTelemetry: jest.fn(() => ({
|
|
12
12
|
send: jest.fn(),
|
|
13
13
|
})),
|
|
14
|
-
useOtelTelemetry: jest.fn(() => ({
|
|
15
|
-
send: jest.fn(),
|
|
16
|
-
})),
|
|
17
14
|
useBreadcrumbs: jest.fn().mockReturnValue([]),
|
|
18
15
|
usePageSharedData: jest.fn().mockReturnValue({}),
|
|
19
16
|
useCatalogClassic: jest.fn(() => ({
|
package/src/core/hooks/index.ts
CHANGED
|
@@ -36,3 +36,5 @@ export * from '@redocly/theme/core/hooks/code-walkthrough/use-renderable-files';
|
|
|
36
36
|
export * from '@redocly/theme/core/hooks/use-element-size';
|
|
37
37
|
export * from '@redocly/theme/core/hooks/use-time-ago';
|
|
38
38
|
export * from '@redocly/theme/core/hooks/use-input-key-commands';
|
|
39
|
+
export * from '@redocly/theme/core/hooks/use-page-active-version';
|
|
40
|
+
export * from '@redocly/theme/core/hooks/use-page-versions';
|
|
@@ -8,16 +8,16 @@ export function useSearchDialog() {
|
|
|
8
8
|
const [isOpen, setIsOpen] = useState(false);
|
|
9
9
|
const themeSettings = useThemeConfig();
|
|
10
10
|
const location = useLocation();
|
|
11
|
-
const {
|
|
12
|
-
const
|
|
13
|
-
const keyShortcuts = themeSettings?.search?.shortcuts ?? ['
|
|
11
|
+
const { useTelemetry } = useThemeHooks();
|
|
12
|
+
const telemetry = useTelemetry();
|
|
13
|
+
const keyShortcuts = themeSettings?.search?.shortcuts ?? ['⌘+K,CTRL+K'];
|
|
14
14
|
const hotKeys = keyShortcuts?.join(',');
|
|
15
15
|
|
|
16
16
|
useEffect(() => {
|
|
17
17
|
if (hotKeys) {
|
|
18
18
|
hotkeys(hotKeys, (ev) => {
|
|
19
19
|
setIsOpen(true);
|
|
20
|
-
|
|
20
|
+
telemetry.send({ type: 'search.opened', payload: { method: 'shortcut' } });
|
|
21
21
|
ev.preventDefault();
|
|
22
22
|
});
|
|
23
23
|
|
|
@@ -27,7 +27,7 @@ export function useSearchDialog() {
|
|
|
27
27
|
}, [hotKeys]);
|
|
28
28
|
|
|
29
29
|
const onOpen = useCallback(function () {
|
|
30
|
-
|
|
30
|
+
telemetry.send({ type: 'search.opened', payload: { method: 'click' } });
|
|
31
31
|
setIsOpen(true);
|
|
32
32
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
33
33
|
}, []);
|
|
@@ -4,8 +4,8 @@ import { useThemeConfig, useThemeHooks } from '@redocly/theme/core/hooks';
|
|
|
4
4
|
|
|
5
5
|
export const useColorSwitcher = () => {
|
|
6
6
|
const themeSettings = useThemeConfig();
|
|
7
|
-
const {
|
|
8
|
-
const
|
|
7
|
+
const { useTelemetry } = useThemeHooks();
|
|
8
|
+
const telemetry = useTelemetry();
|
|
9
9
|
const colorMode = themeSettings.colorMode;
|
|
10
10
|
const modes = colorMode?.modes || ['light', 'dark'];
|
|
11
11
|
const defaultColor = modes[0] || 'light';
|
|
@@ -33,7 +33,7 @@ export const useColorSwitcher = () => {
|
|
|
33
33
|
window.requestAnimationFrame(() => {
|
|
34
34
|
document.documentElement.classList.remove('notransition');
|
|
35
35
|
});
|
|
36
|
-
|
|
36
|
+
telemetry.send({
|
|
37
37
|
type: 'color_mode.switched',
|
|
38
38
|
payload: { from: activeColorMode, to: newMode },
|
|
39
39
|
});
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { useCallback, useMemo } from 'react';
|
|
2
2
|
|
|
3
|
+
import { getUserAgent } from '@redocly/theme/core/utils';
|
|
4
|
+
|
|
3
5
|
type Action = 'selectAll' | 'escape' | 'clear' | 'enter' | 'paste';
|
|
4
6
|
type ActionHandlers = {
|
|
5
7
|
[key in `on${Capitalize<Action>}`]?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
@@ -11,7 +13,7 @@ type KeyboardCommand = {
|
|
|
11
13
|
|
|
12
14
|
export function useInputKeyCommands(actionHandlers?: ActionHandlers) {
|
|
13
15
|
// MacOS uses Command key instead of Ctrl
|
|
14
|
-
const ctrlKey = useMemo(() => (
|
|
16
|
+
const ctrlKey = useMemo(() => (getUserAgent().includes('Mac') ? 'metaKey' : 'ctrlKey'), []);
|
|
15
17
|
|
|
16
18
|
const isSelectAll = useCallback(
|
|
17
19
|
(event: React.KeyboardEvent<HTMLInputElement>) => {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { useThemeHooks } from '@redocly/theme/core/hooks';
|
|
2
|
+
|
|
3
|
+
export function usePageActiveVersion(): string | undefined {
|
|
4
|
+
const { usePageVersions } = useThemeHooks();
|
|
5
|
+
const { versions } = usePageVersions();
|
|
6
|
+
const activeVersion = versions.find((version) => version.active);
|
|
7
|
+
|
|
8
|
+
return activeVersion?.version;
|
|
9
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useThemeHooks } from '@redocly/theme/core/hooks';
|
|
2
|
+
|
|
3
|
+
export type PageVersion = {
|
|
4
|
+
active: boolean;
|
|
5
|
+
default: boolean;
|
|
6
|
+
label: string;
|
|
7
|
+
version: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function usePageVersions(): PageVersion[] {
|
|
11
|
+
const { usePageVersions } = useThemeHooks();
|
|
12
|
+
const pageVersions = usePageVersions();
|
|
13
|
+
|
|
14
|
+
return pageVersions.versions.map((version) => ({
|
|
15
|
+
active: version.active,
|
|
16
|
+
default: version.default,
|
|
17
|
+
label: version.label,
|
|
18
|
+
version: version.version,
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
@@ -3,15 +3,15 @@ import { useNavigate } from 'react-router-dom';
|
|
|
3
3
|
import { useThemeHooks } from '@redocly/theme/core/hooks';
|
|
4
4
|
|
|
5
5
|
export function useProductPicker() {
|
|
6
|
-
const { useCurrentProduct, useProducts,
|
|
6
|
+
const { useCurrentProduct, useProducts, useTelemetry, useLoadAndNavigate } = useThemeHooks();
|
|
7
7
|
const currentProduct = useCurrentProduct();
|
|
8
8
|
const products = useProducts();
|
|
9
|
-
const
|
|
9
|
+
const telemetry = useTelemetry();
|
|
10
10
|
const navigate = useNavigate();
|
|
11
11
|
const loadAndNavigate = useLoadAndNavigate();
|
|
12
12
|
function setProduct(product: typeof currentProduct) {
|
|
13
13
|
if (!product) return;
|
|
14
|
-
|
|
14
|
+
telemetry.send({ type: 'product.picked', payload: { product: product.slug } });
|
|
15
15
|
loadAndNavigate({ navigate, to: product.link });
|
|
16
16
|
}
|
|
17
17
|
return {
|
|
@@ -10,7 +10,10 @@ const fallbacks = {
|
|
|
10
10
|
(typeof options === 'string' ? options : options?.defaultValue) || value || '',
|
|
11
11
|
}),
|
|
12
12
|
useSubmitFeedback: () => ({ submitFeedback: () => {} }),
|
|
13
|
-
useTelemetry: () => ({
|
|
13
|
+
useTelemetry: () => ({ send: () => {} }),
|
|
14
|
+
/**
|
|
15
|
+
* @deprecated use `useTelemetry` instead
|
|
16
|
+
**/
|
|
14
17
|
useOtelTelemetry: () => ({ send: () => {} }),
|
|
15
18
|
useBreadcrumbs: () => [],
|
|
16
19
|
useCodeHighlight: () => ({ highlight: (rawContent: string) => rawContent }),
|
package/src/core/styles/dark.ts
CHANGED
|
@@ -11,15 +11,27 @@ import { statusCodeDarkMode } from '@redocly/theme/components/StatusCode/variabl
|
|
|
11
11
|
import { switcherDarkMode } from '@redocly/theme/components/Switch/variables.dark';
|
|
12
12
|
import { cardsDarkMode } from '@redocly/theme/markdoc/components/Cards/variables.dark';
|
|
13
13
|
|
|
14
|
+
|
|
14
15
|
const replayDarkMode = css`
|
|
15
16
|
/**
|
|
16
17
|
* @tokens Replay Colors
|
|
17
18
|
* @presenter Color
|
|
18
19
|
*/
|
|
19
20
|
|
|
20
|
-
--replay-undefined-variable-
|
|
21
|
-
--replay-defined-variable-
|
|
22
|
-
--replay-server-variable-
|
|
21
|
+
--replay-undefined-variable-color: rgb(255, 138, 162); // @presenter Color
|
|
22
|
+
--replay-defined-variable-color: rgb(110, 171, 250); // @presenter Color
|
|
23
|
+
--replay-server-variable-color: rgb(179, 166, 249); // @presenter Color
|
|
24
|
+
--replay-path-parameter-color: rgb(8, 199, 224); // @presenter Color
|
|
25
|
+
|
|
26
|
+
--replay-undefined-variable-bg-color: rgba(82, 10, 24, 0.16); // @presenter Color
|
|
27
|
+
--replay-defined-variable-bg-color: rgba(12, 76, 158, 0.16); // @presenter Color
|
|
28
|
+
--replay-server-variable-bg-color: rgba(31, 10, 144, 0.16); // @presenter Color
|
|
29
|
+
--replay-path-parameter-bg-color: rgba(5, 88, 99, 0.16); // @presenter Color
|
|
30
|
+
|
|
31
|
+
--replay-undefined-variable-bg-color-hover: rgba(82, 10, 24, 0.4); // @presenter Color
|
|
32
|
+
--replay-defined-variable-bg-color-hover: rgba(12, 76, 158, 0.4); // @presenter Color
|
|
33
|
+
--replay-server-variable-bg-color-hover: rgba(31, 10, 144, 0.4); // @presenter Color
|
|
34
|
+
--replay-path-parameter-bg-color-hover: rgba(5, 88, 99, 0.4); // @presenter Color
|
|
23
35
|
|
|
24
36
|
// @tokens End
|
|
25
37
|
`;
|
|
@@ -1182,17 +1182,20 @@ const replay = css`
|
|
|
1182
1182
|
* @presenter Color
|
|
1183
1183
|
*/
|
|
1184
1184
|
|
|
1185
|
-
--replay-undefined-variable-color:
|
|
1186
|
-
--replay-defined-variable-color:
|
|
1187
|
-
--replay-server-variable-color:
|
|
1185
|
+
--replay-undefined-variable-color: rgb(249, 49, 109); // @presenter Color
|
|
1186
|
+
--replay-defined-variable-color: rgb(31, 124, 255); // @presenter Color
|
|
1187
|
+
--replay-server-variable-color: rgb(91, 76, 204); // @presenter Color
|
|
1188
|
+
--replay-path-parameter-color: rgb(4, 117, 161); // @presenter Color
|
|
1188
1189
|
|
|
1189
1190
|
--replay-undefined-variable-bg-color: rgba(249, 49, 109, 0.08); // @presenter Color
|
|
1190
1191
|
--replay-defined-variable-bg-color: rgba(31, 124, 255, 0.08); // @presenter Color
|
|
1191
1192
|
--replay-server-variable-bg-color: rgba(119, 45, 240, 0.08); // @presenter Color
|
|
1193
|
+
--replay-path-parameter-bg-color: rgba(4, 117, 161, 0.08); // @presenter Color
|
|
1192
1194
|
|
|
1193
|
-
--replay-undefined-variable-bg-color-hover:
|
|
1194
|
-
--replay-defined-variable-bg-color-hover:
|
|
1195
|
-
--replay-server-variable-bg-color-hover:
|
|
1195
|
+
--replay-undefined-variable-bg-color-hover: rgba(249, 49, 109, 0.16); // @presenter Color
|
|
1196
|
+
--replay-defined-variable-bg-color-hover: rgba(31, 124, 255, 0.16); // @presenter Color
|
|
1197
|
+
--replay-server-variable-bg-color-hover: rgba(119, 45, 240, 0.16); // @presenter Color
|
|
1198
|
+
--replay-path-parameter-bg-color-hover: rgba(4, 117, 161, 0.16); // @presenter Color
|
|
1196
1199
|
|
|
1197
1200
|
// @tokens End
|
|
1198
1201
|
`;
|
package/src/core/types/hooks.ts
CHANGED
|
@@ -119,8 +119,7 @@ export type ThemeHooks = {
|
|
|
119
119
|
}
|
|
120
120
|
| undefined;
|
|
121
121
|
useCatalogClassic: (config: CatalogConfig) => FilteredCatalog;
|
|
122
|
-
useTelemetry: () => {
|
|
123
|
-
useOtelTelemetry: () => {
|
|
122
|
+
useTelemetry: () => {
|
|
124
123
|
send(data: AsyncApiRealm.Messages): void;
|
|
125
124
|
};
|
|
126
125
|
useUserTeams: () => string[];
|
|
@@ -145,5 +144,3 @@ export type L10nConfig = {
|
|
|
145
144
|
defaultLocale: string;
|
|
146
145
|
locales: { code: string; name: string }[];
|
|
147
146
|
};
|
|
148
|
-
|
|
149
|
-
type TelemetryEvent = unknown;
|
package/src/core/types/l10n.ts
CHANGED
|
@@ -214,7 +214,7 @@ export type TranslationKey =
|
|
|
214
214
|
| 'openapi.showExample'
|
|
215
215
|
| 'openapi.expandAll'
|
|
216
216
|
| 'openapi.collapseAll'
|
|
217
|
-
| 'openapi.
|
|
217
|
+
| 'openapi.viewSecurityDetails'
|
|
218
218
|
| 'openapi.noResponseExample'
|
|
219
219
|
| 'openapi.noResponseContent'
|
|
220
220
|
| 'openapi.noRequestPayload'
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns user agent. Handles SSR and browser.
|
|
3
|
+
*/
|
|
4
|
+
export function getUserAgent() {
|
|
5
|
+
const ssrUserAgent = (globalThis as any)['SSR_USER_AGENT'];
|
|
6
|
+
|
|
7
|
+
if (ssrUserAgent) {
|
|
8
|
+
return ssrUserAgent;
|
|
9
|
+
}
|
|
10
|
+
const browserUserAgent = typeof navigator !== 'undefined' ? navigator.userAgent : '';
|
|
11
|
+
|
|
12
|
+
return browserUserAgent;
|
|
13
|
+
}
|
package/src/core/utils/index.ts
CHANGED
|
@@ -31,3 +31,4 @@ export * from '@redocly/theme/core/utils/get-file-icon';
|
|
|
31
31
|
export * from '@redocly/theme/core/utils/match-code-walkthrough-conditions';
|
|
32
32
|
export * from '@redocly/theme/core/utils/replace-inputs-with-value';
|
|
33
33
|
export * from '@redocly/theme/core/utils/find-closest-common-directory';
|
|
34
|
+
export * from '@redocly/theme/core/utils/get-user-agent';
|