@redocly/theme 0.59.0-next.0 → 0.59.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.
Files changed (76) hide show
  1. package/lib/components/Accordion/Accordion.d.ts +12 -0
  2. package/lib/components/Accordion/Accordion.js +75 -0
  3. package/lib/components/Accordion/AccordionBody.d.ts +8 -0
  4. package/lib/components/Accordion/AccordionBody.js +63 -0
  5. package/lib/components/Accordion/AccordionHeader.d.ts +10 -0
  6. package/lib/components/Accordion/AccordionHeader.js +37 -0
  7. package/lib/components/Accordion/AccordionTitle.d.ts +6 -0
  8. package/lib/components/Accordion/AccordionTitle.js +20 -0
  9. package/lib/components/Accordion/variables.d.ts +1 -0
  10. package/lib/components/Accordion/variables.js +59 -0
  11. package/lib/components/Buttons/AIAssistantButton.d.ts +2 -0
  12. package/lib/components/Buttons/AIAssistantButton.js +125 -0
  13. package/lib/components/Buttons/variables.d.ts +1 -0
  14. package/lib/components/Buttons/variables.dark.d.ts +1 -0
  15. package/lib/components/Buttons/variables.dark.js +10 -0
  16. package/lib/components/Buttons/variables.js +51 -0
  17. package/lib/components/Catalog/Catalog.js +3 -3
  18. package/lib/components/Catalog/CatalogFilter/CatalogFilter.d.ts +6 -0
  19. package/lib/components/Catalog/CatalogFilter/CatalogFilter.js +35 -0
  20. package/lib/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.d.ts +6 -0
  21. package/lib/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.js +142 -0
  22. package/lib/components/Catalog/CatalogFilter/CatalogFilterContent.d.ts +13 -0
  23. package/lib/components/Catalog/CatalogFilter/CatalogFilterContent.js +92 -0
  24. package/lib/components/Catalog/CatalogFilter/CatalogFilterDateRange.d.ts +6 -0
  25. package/lib/components/Catalog/CatalogFilter/CatalogFilterDateRange.js +111 -0
  26. package/lib/components/Catalog/CatalogFilter/CatalogFilterSelect.d.ts +6 -0
  27. package/lib/components/Catalog/CatalogFilter/CatalogFilterSelect.js +116 -0
  28. package/lib/components/Catalog/CatalogSelector.js +0 -1
  29. package/lib/components/Catalog/variables.js +0 -1
  30. package/lib/components/Filter/FilterInput.d.ts +1 -0
  31. package/lib/components/Filter/FilterInput.js +2 -2
  32. package/lib/components/Filter/FilterOptions.js +2 -0
  33. package/lib/components/Filter/variables.js +7 -4
  34. package/lib/components/Search/SearchAiDialog.js +2 -3
  35. package/lib/components/Search/SearchAiResponse.js +2 -3
  36. package/lib/components/Search/SearchDialog.d.ts +2 -1
  37. package/lib/components/Search/SearchDialog.js +2 -2
  38. package/lib/components/Tag/variables.dark.js +2 -2
  39. package/lib/core/styles/dark.js +29 -26
  40. package/lib/core/styles/global.js +64 -59
  41. package/lib/core/types/l10n.d.ts +1 -1
  42. package/lib/icons/RedoclyIcon/RedoclyIcon.d.ts +9 -0
  43. package/lib/icons/RedoclyIcon/RedoclyIcon.js +27 -0
  44. package/lib/index.d.ts +2 -0
  45. package/lib/index.js +2 -0
  46. package/lib/layouts/RootLayout.js +6 -1
  47. package/package.json +1 -1
  48. package/src/components/Accordion/Accordion.tsx +100 -0
  49. package/src/components/Accordion/AccordionBody.tsx +65 -0
  50. package/src/components/Accordion/AccordionHeader.tsx +68 -0
  51. package/src/components/Accordion/AccordionTitle.tsx +26 -0
  52. package/src/components/Accordion/variables.ts +56 -0
  53. package/src/components/Buttons/AIAssistantButton.tsx +141 -0
  54. package/src/components/Buttons/variables.dark.ts +7 -0
  55. package/src/components/Buttons/variables.ts +48 -0
  56. package/src/components/Catalog/Catalog.tsx +3 -2
  57. package/src/components/Catalog/CatalogFilter/CatalogFilter.tsx +56 -0
  58. package/src/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.tsx +169 -0
  59. package/src/components/Catalog/CatalogFilter/CatalogFilterContent.tsx +121 -0
  60. package/src/components/Catalog/CatalogFilter/CatalogFilterDateRange.tsx +147 -0
  61. package/src/components/Catalog/CatalogFilter/CatalogFilterSelect.tsx +136 -0
  62. package/src/components/Catalog/CatalogSelector.tsx +0 -1
  63. package/src/components/Catalog/variables.ts +0 -1
  64. package/src/components/Filter/FilterInput.tsx +3 -2
  65. package/src/components/Filter/FilterOptions.tsx +2 -0
  66. package/src/components/Filter/variables.ts +7 -4
  67. package/src/components/Search/SearchAiDialog.tsx +2 -2
  68. package/src/components/Search/SearchAiResponse.tsx +2 -2
  69. package/src/components/Search/SearchDialog.tsx +7 -2
  70. package/src/components/Tag/variables.dark.ts +2 -2
  71. package/src/core/styles/dark.ts +11 -8
  72. package/src/core/styles/global.ts +7 -2
  73. package/src/core/types/l10n.ts +1 -0
  74. package/src/icons/RedoclyIcon/RedoclyIcon.tsx +44 -0
  75. package/src/index.ts +2 -0
  76. package/src/layouts/RootLayout.tsx +6 -0
@@ -0,0 +1,121 @@
1
+ import React from 'react';
2
+ import styled, { css } from 'styled-components';
3
+
4
+ import type { JSX } from 'react';
5
+ import type { ResolvedFilter } from '@redocly/theme/core/types';
6
+ import type { RedoclyConfig } from '@redocly/theme/config';
7
+
8
+ import { FilterInput } from '@redocly/theme/components/Filter/FilterInput';
9
+ import { useThemeHooks } from '@redocly/theme/core/hooks';
10
+ import { Button } from '@redocly/theme/components/Button/Button';
11
+ import { CatalogFilter } from '@redocly/theme/components/Catalog/CatalogFilter/CatalogFilter';
12
+ import { isFromToSelectedOptions } from '@redocly/theme/core/utils';
13
+
14
+ export type CatalogFilterContentProps = {
15
+ setFilterTerm: (value: string) => void;
16
+ filters: ResolvedFilter[];
17
+ filterTerm: string;
18
+ filterValuesCasing?:
19
+ | NonNullable<RedoclyConfig['catalog']>[string]['filterValuesCasing']
20
+ | ((str: string) => string);
21
+ hideSearch?: boolean;
22
+ showCounter?: boolean;
23
+ className?: string;
24
+ };
25
+
26
+ export function CatalogFilterContent({
27
+ setFilterTerm,
28
+ filters,
29
+ filterTerm,
30
+ filterValuesCasing,
31
+ hideSearch,
32
+ showCounter = true,
33
+ className,
34
+ }: CatalogFilterContentProps): JSX.Element | null {
35
+ const { useTranslate } = useThemeHooks();
36
+ const { translate } = useTranslate();
37
+
38
+ const hasActiveFilters = filters.some((filter) => {
39
+ if (filterTerm) return true;
40
+ if (filter.selectedOptions && filter.selectedOptions instanceof Set) {
41
+ return filter.selectedOptions.size;
42
+ } else if (
43
+ isFromToSelectedOptions(filter.selectedOptions) &&
44
+ filter.selectedOptions.from &&
45
+ filter.selectedOptions.to
46
+ ) {
47
+ return true;
48
+ }
49
+ });
50
+
51
+ const handleClearAll = (): void => {
52
+ filters.forEach((filter) => filter.selectOption(''));
53
+ setFilterTerm('');
54
+ };
55
+
56
+ if (!filters.length) {
57
+ return null;
58
+ }
59
+
60
+ return (
61
+ <CatalogFilterContentWrapper
62
+ className={className}
63
+ data-component-name="Catalog/CatalogFilterContent"
64
+ >
65
+ <FiltersHeader>
66
+ <FiltersTitle data-translation-key="catalog.filters.title">
67
+ {translate('catalog.filters.title', 'Filters')}
68
+ </FiltersTitle>
69
+ {hasActiveFilters ? (
70
+ <Button size="medium" tone="danger" variant="ghost" onClick={handleClearAll}>
71
+ {translate('catalog.filters.clearAll', 'Clear filters')}
72
+ </Button>
73
+ ) : null}
74
+ </FiltersHeader>
75
+ {!hideSearch && (
76
+ <FilterInput value={filterTerm} onChange={(updatedTerm) => setFilterTerm(updatedTerm)} />
77
+ )}
78
+ <FilterItems hideSearch={hideSearch}>
79
+ {filters.map((filter, idx) => (
80
+ <CatalogFilter
81
+ filter={filter}
82
+ key={filter.property + '-' + idx}
83
+ filterValuesCasing={filterValuesCasing}
84
+ showCounter={showCounter}
85
+ />
86
+ ))}
87
+ </FilterItems>
88
+ </CatalogFilterContentWrapper>
89
+ );
90
+ }
91
+
92
+ const CatalogFilterContentWrapper = styled.div`
93
+ padding: 0 0 var(--filter-content-padding-vertical) 0;
94
+ display: flex;
95
+ flex-direction: column;
96
+ `;
97
+
98
+ const FiltersHeader = styled.div`
99
+ display: flex;
100
+ padding: var(--filter-content-header-padding-vertical)
101
+ var(--filter-content-header-padding-horizontal);
102
+ `;
103
+
104
+ const FiltersTitle = styled.div`
105
+ margin-right: auto;
106
+ font-size: var(--filter-content-title-font-size);
107
+ font-weight: var(--filter-content-title-font-weight);
108
+ line-height: var(--filter-content-title-line-height);
109
+ `;
110
+
111
+ const FilterItems = styled.div<{ hideSearch?: boolean }>`
112
+ height: 100%;
113
+ display: flex;
114
+ flex-direction: column;
115
+ border-top: 1px solid var(--border-color-secondary);
116
+ ${({ hideSearch }) =>
117
+ hideSearch &&
118
+ css`
119
+ border-top: none;
120
+ `}
121
+ `;
@@ -0,0 +1,147 @@
1
+ import React, { useMemo } from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { JSX } from 'react';
5
+ import type { FilterProps } from '@redocly/theme/core/types';
6
+
7
+ import { FilterOptions } from '@redocly/theme/components/Filter/FilterOptions';
8
+ import { DatePicker } from '@redocly/theme/components/DatePicker/DatePicker';
9
+ import { CounterTag } from '@redocly/theme/components/Tags/CounterTag';
10
+ import { useThemeHooks } from '@redocly/theme/core/hooks';
11
+ import { formatDateWithoutTimeZone } from '@redocly/theme/core/utils';
12
+ import { Accordion } from '@redocly/theme/components/Accordion/Accordion';
13
+
14
+ export type CatalogFilterDateRangeProps = FilterProps & {
15
+ className?: string;
16
+ };
17
+
18
+ export function CatalogFilterDateRange({
19
+ filter,
20
+ className,
21
+ }: CatalogFilterDateRangeProps): JSX.Element {
22
+ const { useTranslate } = useThemeHooks();
23
+ const { translate } = useTranslate();
24
+
25
+ const from = useMemo(
26
+ () => (filter.selectedOptions.from ? new Date(filter.selectedOptions.from) : undefined),
27
+ [filter.selectedOptions.from],
28
+ );
29
+ const to = useMemo(
30
+ () => (filter.selectedOptions.to ? new Date(filter.selectedOptions.to) : undefined),
31
+ [filter.selectedOptions.to],
32
+ );
33
+
34
+ const selectedCount = useMemo(() => {
35
+ return from && to ? 1 : 0;
36
+ }, [from, to]);
37
+
38
+ const headerContent = (
39
+ <AccordionHeaderContent>
40
+ <span>{translate(filter.titleTranslationKey, filter.title)}</span>
41
+ {selectedCount > 0 && <CounterTag borderless>{selectedCount}</CounterTag>}
42
+ </AccordionHeaderContent>
43
+ );
44
+
45
+ return (
46
+ <AccordionWrapper
47
+ className={className}
48
+ $hasSelection={selectedCount > 0}
49
+ data-component-name="Catalog/CatalogFilterDateRange"
50
+ >
51
+ <Accordion expanded={false} header={headerContent}>
52
+ <FilterOptions>
53
+ <DateRangeWrapper>
54
+ <DateRangeRow>
55
+ <span>From:</span>
56
+ <DatePicker
57
+ closeCalendar={true}
58
+ format="y-MM-dd"
59
+ dayPlaceholder="DD"
60
+ monthPlaceholder="MM"
61
+ yearPlaceholder="YYYY"
62
+ value={from}
63
+ maxDate={new Date()}
64
+ onChange={(from) => {
65
+ if (Array.isArray(from)) return;
66
+ filter.selectOption({
67
+ ...filter.selectedOptions,
68
+ from: formatDateWithoutTimeZone(from),
69
+ to: formatDateWithoutTimeZone(to),
70
+ });
71
+ }}
72
+ />
73
+ </DateRangeRow>
74
+ <DateRangeRow>
75
+ <span>To:</span>
76
+ <DatePicker
77
+ closeCalendar={true}
78
+ dayPlaceholder="DD"
79
+ monthPlaceholder="MM"
80
+ yearPlaceholder="YYYY"
81
+ format="y-MM-dd"
82
+ minDate={from}
83
+ value={to}
84
+ onChange={(to) => {
85
+ if (Array.isArray(to)) return;
86
+ filter.selectOption({
87
+ ...filter.selectedOptions,
88
+ from: formatDateWithoutTimeZone(from),
89
+ to: formatDateWithoutTimeZone(to),
90
+ });
91
+ }}
92
+ />
93
+ </DateRangeRow>
94
+ </DateRangeWrapper>
95
+ </FilterOptions>
96
+ </Accordion>
97
+ </AccordionWrapper>
98
+ );
99
+ }
100
+
101
+ const AccordionWrapper = styled.div<{ $hasSelection: boolean }>`
102
+ position: relative;
103
+ border-right: 4px solid transparent;
104
+
105
+ ${({ $hasSelection }) =>
106
+ $hasSelection &&
107
+ `border-right-color: var(--color-blueberry-6);
108
+
109
+ &::after {
110
+ content: '';
111
+ position: absolute;
112
+ bottom: -1px;
113
+ right: -4px;
114
+ width: 4px;
115
+ height: 1px;
116
+ background-color: var(--color-blueberry-6);
117
+ z-index: 1;
118
+ }
119
+ `}
120
+ `;
121
+
122
+ const AccordionHeaderContent = styled.div`
123
+ display: flex;
124
+ align-items: center;
125
+ gap: var(--spacing-xs);
126
+ width: 100%;
127
+ `;
128
+
129
+ const DateRangeWrapper = styled.div`
130
+ display: flex;
131
+ flex-direction: column;
132
+ gap: var(--filter-options-gap);
133
+ `;
134
+
135
+ const DateRangeRow = styled.div`
136
+ color: var(--filter-date-picker-color);
137
+ display: flex;
138
+ flex-direction: row;
139
+
140
+ align-items: center;
141
+ gap: var(--filter-date-picker-gap);
142
+
143
+ > span {
144
+ width: var(--filter-date-picker-width);
145
+ color: var(--filter-option-label-color);
146
+ }
147
+ `;
@@ -0,0 +1,136 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { JSX } from 'react';
5
+ import type { FilterProps, SelectProps, SelectOption } from '@redocly/theme/core/types';
6
+
7
+ import { FilterOption } from '@redocly/theme/components/Filter/FilterOption';
8
+ import { FilterOptionLabel } from '@redocly/theme/components/Filter/FilterOptionLabel';
9
+ import { Select } from '@redocly/theme/components/Select/Select';
10
+ import { CounterTag } from '@redocly/theme/components/Tags/CounterTag';
11
+ import { changeTextCasing } from '@redocly/theme/core/utils';
12
+ import { useThemeHooks } from '@redocly/theme/core/hooks';
13
+ import { Accordion } from '@redocly/theme/components/Accordion/Accordion';
14
+
15
+ export type CatalogFilterSelectProps = FilterProps & {
16
+ className?: string;
17
+ };
18
+
19
+ export function CatalogFilterSelect({
20
+ filter,
21
+ filterValuesCasing,
22
+ showCounter = true,
23
+ className,
24
+ }: CatalogFilterSelectProps): JSX.Element {
25
+ const { useTranslate } = useThemeHooks();
26
+ const { translate } = useTranslate();
27
+ const [isExpanded, setIsExpanded] = useState(false);
28
+
29
+ const selectedCount = useMemo(() => {
30
+ if (filter.selectedOptions instanceof Set) {
31
+ const firstValue = filter.selectedOptions.values().next()?.value;
32
+
33
+ return firstValue && firstValue !== '' ? 1 : 0;
34
+ }
35
+ return 0;
36
+ }, [filter.selectedOptions]);
37
+
38
+ let selectOptions: SelectOption<string>[] = [];
39
+
40
+ const defaultOptionCount = filter.options.reduce((acc, option) => acc + option.count, 0);
41
+
42
+ selectOptions = [
43
+ {
44
+ value: '',
45
+ element: (
46
+ <FilterOption key="all" onClick={() => filter.selectOption('')}>
47
+ <FilterOptionLabel data-translation-key="catalog.filters.select.all">
48
+ {translate('catalog.filters.select.all', 'All')}
49
+ </FilterOptionLabel>
50
+ <CounterTag borderless>{defaultOptionCount}</CounterTag>
51
+ </FilterOption>
52
+ ),
53
+ },
54
+ ...filter.options.map((option) => ({
55
+ value: option.value,
56
+ element: (
57
+ <FilterOption key={option.value}>
58
+ <FilterOptionLabel data-translation-key={option.value}>
59
+ {changeTextCasing(translate(option.value), filterValuesCasing)}
60
+ </FilterOptionLabel>
61
+ {showCounter && <CounterTag borderless>{option.count}</CounterTag>}
62
+ </FilterOption>
63
+ ),
64
+ })),
65
+ ];
66
+
67
+ const headerContent = (
68
+ <AccordionHeaderContent>
69
+ <span>{translate(filter.titleTranslationKey, filter.title)}</span>
70
+ {selectedCount > 0 && <CounterTag borderless>{selectedCount}</CounterTag>}
71
+ </AccordionHeaderContent>
72
+ );
73
+
74
+ return (
75
+ <AccordionWrapper
76
+ className={className}
77
+ $hasSelection={selectedCount > 0 && !isExpanded}
78
+ data-component-name="Catalog/CatalogFilterSelect"
79
+ >
80
+ <Accordion expanded={isExpanded} header={headerContent} onToggle={setIsExpanded}>
81
+ <StyledSelect
82
+ value={
83
+ (filter.selectedOptions instanceof Set ? filter.selectedOptions : new Set())
84
+ .values()
85
+ .next()?.value || ''
86
+ }
87
+ onChange={(value) => filter.selectOption(value)}
88
+ options={selectOptions}
89
+ />
90
+ </Accordion>
91
+ </AccordionWrapper>
92
+ );
93
+ }
94
+
95
+ const AccordionWrapper = styled.div<{ $hasSelection: boolean }>`
96
+ position: relative;
97
+ border-right: 4px solid transparent;
98
+
99
+ ${({ $hasSelection }) =>
100
+ $hasSelection &&
101
+ `border-right-color: var(--color-blueberry-6);
102
+
103
+ &::after {
104
+ content: '';
105
+ position: absolute;
106
+ bottom: -1px;
107
+ right: -4px;
108
+ width: 4px;
109
+ height: 1px;
110
+ background-color: var(--color-blueberry-6);
111
+ z-index: 1;
112
+ }
113
+ `}
114
+ `;
115
+
116
+ const AccordionHeaderContent = styled.div`
117
+ display: flex;
118
+ align-items: center;
119
+ gap: var(--spacing-xs);
120
+ width: 100%;
121
+ `;
122
+
123
+ const StyledSelect = styled(Select)<SelectProps>`
124
+ --select-list-max-width: var(--filter-select-max-width);
125
+
126
+ min-height: var(--filter-select-min-height);
127
+ --select-text-color: var(--filter-select-color);
128
+ border: 1px solid var(--filter-select-border-color);
129
+ --select-border-radius: var(--filter-select-border-radius);
130
+ padding: var(--filter-select-padding);
131
+
132
+ :hover {
133
+ border-color: var(--filter-select-border-color-hover);
134
+ }
135
+ --filter-option-margin: var(--filter-select-option-margin);
136
+ `;
@@ -52,7 +52,6 @@ export function CatalogSelector({
52
52
 
53
53
  export const CatalogSelectWrapper = styled.div`
54
54
  margin-top: var(--catalog-select-wrapper-margin-top);
55
- margin-bottom: var(--catalog-select-wrapper-margin-bottom);
56
55
  `;
57
56
 
58
57
  export const CatalogSelectLabel = styled.label`
@@ -80,7 +80,6 @@ export const catalog = css`
80
80
  * @tokens Catalog selector
81
81
  */
82
82
  --catalog-select-wrapper-margin-top: var(--spacing-xxs);
83
- --catalog-select-wrapper-margin-bottom: var(--spacing-base);
84
83
  --catalog-select-label-margin-bottom: var(--spacing-xxs);
85
84
  --catalog-select-label-font-weight: var(--filter-title-font-weight);
86
85
  --catalog-select-label-font-size: var(--filter-title-font-size);
@@ -9,10 +9,11 @@ import { SearchIcon } from '@redocly/theme/icons/SearchIcon/SearchIcon';
9
9
  export type FilterInputProps = {
10
10
  value: string;
11
11
  onChange: (newValue: string) => void;
12
+ dataTestId?: string;
12
13
  };
13
14
 
14
15
  export function FilterInput(props: FilterInputProps): JSX.Element {
15
- const { value: initialValue, onChange } = props;
16
+ const { value: initialValue, onChange, dataTestId } = props;
16
17
 
17
18
  const [value, setValue] = useState(initialValue);
18
19
 
@@ -30,7 +31,7 @@ export function FilterInput(props: FilterInputProps): JSX.Element {
30
31
  const { translate } = useTranslate();
31
32
 
32
33
  return (
33
- <InputWrapper data-component-name="Filter/FilterInput">
34
+ <InputWrapper data-component-name="Filter/FilterInput" data-testid={dataTestId}>
34
35
  <InputIcon />
35
36
  <Input
36
37
  value={value}
@@ -16,4 +16,6 @@ const FilterOptionsComponent = styled.div`
16
16
  display: flex;
17
17
  flex-direction: column;
18
18
  gap: var(--filter-options-gap);
19
+ max-height: var(--filter-options-max-height);
20
+ overflow-y: scroll;
19
21
  `;
@@ -15,6 +15,7 @@ export const filter = css`
15
15
  --filter-options-padding-vertical: 0;
16
16
  --filter-options-padding-horizontal: 0;
17
17
  --filter-options-gap: var(--spacing-sm);
18
+ --filter-options-max-height: 350px;
18
19
 
19
20
  --filter-option-font-size: var(--font-size-base);
20
21
  --filter-option-gap: var(--spacing-xs);
@@ -25,12 +26,14 @@ export const filter = css`
25
26
 
26
27
  --filter-option-checkbox-padding-left: var(--spacing-xs);
27
28
 
28
- --filter-content-header-padding-vertical: 5px;
29
- --filter-content-header-padding-horizontal: 0;
29
+ --filter-content-header-padding-vertical: var(--spacing-xs) var(--spacing-sm);
30
+ --filter-content-header-padding-horizontal: var(--spacing-base);
30
31
 
31
- --filter-content-title-font-size: var(--font-size-base);
32
- --filter-content-title-line-height: var(--line-height-base);
32
+ --filter-content-title-font-size: var(--font-size-lg);
33
+ --filter-content-title-line-height: var(--line-height-lg);
33
34
  --filter-content-title-font-weight: var(--font-weight-semibold);
35
+
36
+ --filter-content-search-padding: 0 var(--spacing-xs) var(--spacing-sm);
34
37
 
35
38
  --filter-content-padding-vertical: var(--spacing-sm);
36
39
  --filter-content-padding-horizontal: var(--spacing-base);
@@ -43,12 +43,12 @@ export function SearchAiDialog({
43
43
  setConversation,
44
44
  }: SearchAiDialogProps): JSX.Element {
45
45
  const { useTranslate } = useThemeHooks();
46
- const { search } = useThemeConfig();
46
+ const { aiAssistant } = useThemeConfig();
47
47
  const { translate } = useTranslate();
48
48
 
49
49
  const conversationEndRef = React.useRef<HTMLDivElement>(null);
50
50
 
51
- const suggestions = search?.ai?.suggestions;
51
+ const suggestions = aiAssistant?.suggestions;
52
52
 
53
53
  const placeholder = isGeneratingResponse
54
54
  ? translate('search.ai.generatingResponse', 'Generating response...')
@@ -34,7 +34,7 @@ export function SearchAiResponse(props: SearchAiResponseProps): JSX.Element {
34
34
  const { useMarkdownText } = useThemeHooks();
35
35
  const { question, response, isGeneratingResponse, resources, error, onSuggestionClick } = props;
36
36
 
37
- const { search } = useThemeConfig();
37
+ const { aiAssistant } = useThemeConfig();
38
38
  const { useTranslate } = useThemeHooks();
39
39
 
40
40
  const { translate } = useTranslate();
@@ -42,7 +42,7 @@ export function SearchAiResponse(props: SearchAiResponseProps): JSX.Element {
42
42
 
43
43
  let responseContainer = null;
44
44
 
45
- const suggestions = search?.ai?.suggestions;
45
+ const suggestions = aiAssistant?.suggestions;
46
46
 
47
47
  const hasPendingOrReceivedResponse = response || isGeneratingResponse || error;
48
48
  if (hasPendingOrReceivedResponse) {
@@ -34,16 +34,21 @@ import { AiStarsGradientIcon } from '@redocly/theme/icons/AiStarsGradientIcon/Ai
34
34
  export type SearchDialogProps = {
35
35
  onClose: () => void;
36
36
  className?: string;
37
+ initialMode?: 'search' | 'ai-dialog';
37
38
  };
38
39
 
39
- export function SearchDialog({ onClose, className }: SearchDialogProps): JSX.Element {
40
+ export function SearchDialog({
41
+ onClose,
42
+ className,
43
+ initialMode = 'search',
44
+ }: SearchDialogProps): JSX.Element {
40
45
  const { useTranslate, useCurrentProduct, useSearch, useProducts, useAiSearch, useTelemetry } =
41
46
  useThemeHooks();
42
47
  const telemetry = useTelemetry();
43
48
  const products = useProducts();
44
49
  const currentProduct = useCurrentProduct();
45
50
  const [product, setProduct] = useState(currentProduct);
46
- const [mode, setMode] = useState<'search' | 'ai-dialog'>('search');
51
+ const [mode, setMode] = useState<'search' | 'ai-dialog'>(initialMode);
47
52
  const autoSearchDisabled = mode !== 'search';
48
53
  const {
49
54
  query,
@@ -55,10 +55,10 @@ export const tagDarkMode = css`
55
55
  }
56
56
 
57
57
  .tag-green {
58
- --tag-color: var(--color-green-6); // @presenter Color
58
+ --tag-color: var(--color-green-7); // @presenter Color
59
59
  --tag-bg-color: var(--color-green-1); // @presenter Color
60
60
  --tag-border-color: var(--color-green-3); // @presenter Color
61
- --tag-border-color-hover: var(--color-green-4); // @presenter Color
61
+ --tag-border-color-hover: var(--color-green-5); // @presenter Color
62
62
  --tag-bg-color-hover: var(--color-green-2); // @presenter Color
63
63
  }
64
64
 
@@ -4,6 +4,7 @@ import { scorecardDarkMode } from '@redocly/theme/components/Scorecard/variables
4
4
  import { mermaidDarkMode } from '@redocly/theme/markdoc/components/Mermaid/variables.dark'
5
5
  import { menuDarkMode } from '@redocly/theme/components/Menu/variables.dark';
6
6
  import { buttonDarkMode } from '@redocly/theme/components/Button/variables.dark';
7
+ import { aiAssistantButtonDarkMode } from '@redocly/theme/components/Buttons/variables.dark';
7
8
  import { segmentedButtonsDarkMode } from '@redocly/theme/components/Segmented/variables.dark';
8
9
  import { checkboxDarkMode } from '@redocly/theme/icons/CheckboxIcon/variables.dark';
9
10
  import { tagDarkMode } from '@redocly/theme/components/Tag/variables.dark';
@@ -137,14 +138,15 @@ export const darkMode = css`
137
138
 
138
139
  --color-green-1: #1a4d40;
139
140
  --color-green-2: #195848;
140
- --color-green-3: #0e8450;
141
- --color-green-4: #149e53;
142
- --color-green-5: #1cb854;
143
- --color-green-6: #4dd470;
144
- --color-green-7: #72e985;
145
- --color-green-8: #a3f7a9;
146
- --color-green-9: #d2fbd0;
147
- --color-green-10: #edfbec;
141
+ --color-green-3: #136a4d;
142
+ --color-green-4: #0e8450;
143
+ --color-green-5: #149e53;
144
+ --color-green-6: #1cb854;
145
+ --color-green-7: #4dd470;
146
+ --color-green-8: #72e985;
147
+ --color-green-9: #a3f7a9;
148
+ --color-green-10: #d2fbd0;
149
+ --color-green-11: #edfbec;
148
150
 
149
151
  --color-grass-1: #1f4d2d;
150
152
  --color-grass-2: #164f29;
@@ -309,6 +311,7 @@ export const darkMode = css`
309
311
 
310
312
  ${segmentedButtonsDarkMode}
311
313
  ${buttonDarkMode}
314
+ ${aiAssistantButtonDarkMode}
312
315
  ${checkboxDarkMode}
313
316
  ${tagDarkMode}
314
317
  ${statusCodeDarkMode}
@@ -11,6 +11,7 @@ import { catalog } from '@redocly/theme/components/Catalog/variables';
11
11
  import { filter } from '@redocly/theme/components/Filter/variables';
12
12
  import { catalogClassic } from '@redocly/theme/components/CatalogClassic/variables';
13
13
  import { apiReferencePanels, responsePanelColors } from '@redocly/theme/components/Panel/variables';
14
+ import { accordion } from '@redocly/theme/components/Accordion/variables';
14
15
  import { select } from '@redocly/theme/components/Select/variables';
15
16
  import { dropdown } from '@redocly/theme/components/Dropdown/variables';
16
17
  import { tooltip } from '@redocly/theme/components/Tooltip/variables';
@@ -18,6 +19,7 @@ import { checkbox } from '@redocly/theme/icons/CheckboxIcon/variables';
18
19
  import { admonition } from '@redocly/theme/components/Admonition/variables';
19
20
  import { footer } from '@redocly/theme/components/Footer/variables';
20
21
  import { button } from '@redocly/theme/components/Button/variables';
22
+ import { aiAssistantButton } from '@redocly/theme/components/Buttons/variables';
21
23
  import { navbar } from '@redocly/theme/components/Navbar/variables';
22
24
  import { search } from '@redocly/theme/components/Search/variables';
23
25
  import { menu, mobileMenu } from '@redocly/theme/components/Menu/variables';
@@ -141,8 +143,9 @@ const themeColors = css`
141
143
  --color-green-6: #1cb854;
142
144
  --color-green-7: #149e53;
143
145
  --color-green-8: #0e8450;
144
- --color-green-9: #195848;
145
- --color-green-10: #1a4d40;
146
+ --color-green-9: #136a4d;
147
+ --color-green-10: #195848;
148
+ --color-green-11: #1a4d40;
146
149
 
147
150
  --color-grass-1: #f0faeb;
148
151
  --color-grass-2: #e3fad6;
@@ -1227,6 +1230,7 @@ const replay = css`
1227
1230
 
1228
1231
  export const styles = css`
1229
1232
  :root {
1233
+ ${accordion}
1230
1234
  ${admonition}
1231
1235
  ${apiReferenceDocs}
1232
1236
  ${apiReferencePanels}
@@ -1234,6 +1238,7 @@ export const styles = css`
1234
1238
  ${borders}
1235
1239
  ${breadcrumbs}
1236
1240
  ${button}
1241
+ ${aiAssistantButton}
1237
1242
  ${cards}
1238
1243
  ${catalog}
1239
1244
  ${catalogClassic}
@@ -103,6 +103,7 @@ export type TranslationKey =
103
103
  | 'search.ai.error.header'
104
104
  | 'search.ai.error.header.forbidden'
105
105
  | 'search.ai.error.header.unauthorized'
106
+ | 'aiAssistant.trigger'
106
107
  | 'toc.header'
107
108
  | 'footer.copyrightText'
108
109
  | 'page.homeButton'