= ({link, generativeSuggestOnClick}) => {
+ const {t} = useTranslation('search-suggest');
+
+ return (
+ (generativeSuggestOnClick ? generativeSuggestOnClick(link) : undefined)}
+ >
+
+
+
+
{t('search-suggest-generative_title')}
+
{t('search-suggest-generative_subtitle')}
+
+
+
+ );
+};
+
const SuggestLoader = memo(() => {
return (
@@ -45,25 +70,38 @@ type SuggestListProps = {
fromKeyboard?: boolean,
) => boolean | void;
onChangeActive: (index?: number) => void;
+ queryLink: string;
+ generativeSuggestOnClick?: (link: string) => void;
};
const SuggestList = memo(
forwardRef, SuggestListProps>((props, ref) => {
- const {id, items, renderItem, onItemClick, onChangeActive} = props;
+ const {
+ id,
+ items,
+ renderItem,
+ onItemClick,
+ onChangeActive,
+ queryLink,
+ generativeSuggestOnClick,
+ } = props;
return (
-
+ <>
+
+
+ >
);
}),
);
@@ -74,11 +112,11 @@ type SuggestProps = {
id: string;
query: string;
provider: SearchProvider;
-} & Omit;
+} & Omit;
export const Suggest = memo(
forwardRef, SuggestProps>((props, ref) => {
- const {query, provider} = props;
+ const {query, provider, generativeSuggestOnClick} = props;
const [items, suggest] = useProvider(provider);
useEffect(() => suggest(query), [query, suggest]);
@@ -91,15 +129,24 @@ export const Suggest = memo(
return ;
}
+ const queryLink = provider.link(`/search?query=${query}`);
+
if (Array.isArray(items) && !items.length) {
- return ;
+ return (
+ <>
+
+
+ >
+ );
}
return (
);
}),
diff --git a/src/components/SearchSuggest/index.scss b/src/components/SearchSuggest/index.scss
index bff85603..6388215b 100644
--- a/src/components/SearchSuggest/index.scss
+++ b/src/components/SearchSuggest/index.scss
@@ -149,4 +149,47 @@
}
}
}
+
+ &__generative-search {
+ @include link();
+ text-decoration: none;
+
+ padding: 20px;
+ border: 1px solid transparent;
+ border-bottom: 1px solid var(--g-color-line-generic);
+
+ display: flex;
+ align-items: flex-start;
+ gap: 8px;
+
+ &:hover {
+ border: 1px solid rgba(88, 86, 214, 1);
+ cursor: pointer;
+ }
+
+ &:active {
+ border: 1px solid rgba(88, 86, 214, 1);
+ }
+ }
+
+ &__generative-search-text {
+ display: inline-block;
+ vertical-align: top;
+
+ > h1 {
+ color: var(--g-color-text-link);
+ font-size: 18px;
+ font-weight: 700;
+ line-height: 22px;
+ margin: 0;
+ }
+ > p {
+ color: var(--g-color-text-secondary);
+
+ font-size: 12px;
+ font-weight: 400;
+ line-height: 16px;
+ margin: 0;
+ }
+ }
}
diff --git a/src/components/SearchSuggest/index.tsx b/src/components/SearchSuggest/index.tsx
index 6c3f2565..e6be0742 100644
--- a/src/components/SearchSuggest/index.tsx
+++ b/src/components/SearchSuggest/index.tsx
@@ -38,6 +38,7 @@ export interface SearchSuggestProps {
onFocus?: () => void;
onBlur?: () => void;
endContent?: React.ReactNode;
+ generativeSuggestOnClick?: (link: string) => void;
}
export interface SearchSuggestApi {
@@ -47,7 +48,8 @@ export interface SearchSuggestApi {
}
export const SearchSuggest = forwardRef((props, api) => {
- const {provider, className, placeholder, endContent, containerClass} = props;
+ const {provider, className, placeholder, endContent, containerClass, generativeSuggestOnClick} =
+ props;
const href = useRef(null);
const input = useRef(null);
const suggest = useRef>(null);
@@ -137,6 +139,7 @@ export const SearchSuggest = forwardRef((p
renderItem={SuggestItem}
onItemClick={onSubmit}
onChangeActive={setActive}
+ {...generativeSuggestOnClick}
/>
)}
diff --git a/src/hooks/useCarousel.tsx b/src/hooks/useCarousel.tsx
new file mode 100644
index 00000000..8f2c417b
--- /dev/null
+++ b/src/hooks/useCarousel.tsx
@@ -0,0 +1,54 @@
+import {useEffect, useRef, useState} from 'react';
+
+export const useCarousel = () => {
+ const containerRef = useRef(null);
+ const [showPrevButton, setShowPrevButton] = useState(false);
+ const [showNextButton, setShowNextButton] = useState(false);
+
+ const updateButtonsVisibility = () => {
+ if (containerRef.current) {
+ const {scrollLeft, scrollWidth, clientWidth} = containerRef.current;
+ setShowPrevButton(scrollLeft > 0);
+ setShowNextButton(scrollLeft < scrollWidth - clientWidth);
+ }
+ };
+
+ const nextSlide = () => {
+ if (containerRef.current) {
+ containerRef.current.scrollBy({
+ left: containerRef.current.clientWidth / 3,
+ behavior: 'smooth',
+ });
+ setTimeout(updateButtonsVisibility, 300);
+ }
+ };
+
+ const prevSlide = () => {
+ if (containerRef.current) {
+ containerRef.current.scrollBy({
+ left: -containerRef.current.clientWidth / 3,
+ behavior: 'smooth',
+ });
+ setTimeout(updateButtonsVisibility, 300);
+ }
+ };
+
+ useEffect(() => {
+ updateButtonsVisibility();
+ const handleResize = () => {
+ updateButtonsVisibility();
+ };
+
+ window.addEventListener('resize', handleResize);
+ return () => window.removeEventListener('resize', handleResize);
+ }, []);
+
+ return {
+ containerRef,
+ showPrevButton,
+ showNextButton,
+ nextSlide,
+ prevSlide,
+ updateButtonsVisibility,
+ };
+};
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 17c9638d..5d342062 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -112,10 +112,24 @@
"search_mark_dislike": "dislike",
"search_mark-result-text": "Thank you for your rating!"
},
+ "generative-search": {
+ "generative-search_expand": "Expand",
+ "generative-search_sources_title": "Sources",
+ "generative-search_bad_response": "Bad answer",
+ "generative-search_good_response": "Good answer",
+ "generative-search_loading_title": "Quick answer...",
+ "generative-search_feedback_answer": "Thank you for contributing in technology improvement",
+ "generative-search_something_went_wrong": "Something went wrong. Please try again or refresh the page.",
+ "generative-search_header_title": "Quick answer",
+ "generative-search_header_text": "Generated by",
+ "generative-search_disclaimer": "The answer was generated by YandexGPT based on the service documentation. There may be inaccuracies in it, you can verify the information by referring to the sources."
+ },
"search-suggest": {
"search-suggest_all-results": "All results",
"search-suggest_not-found": "No results found for «{{query}}» request",
"search-suggest_error-text": "Something went wrong. Try again.",
+ "search-suggest-generative_title": "Click to get a quick answer",
+ "search-suggest-generative_subtitle": "generated by YandexGPT",
"search-item_type-all": "All",
"search-item_type-doc": "Documentation",
"search-item_type-main": "Main"
diff --git a/src/i18n/ru.json b/src/i18n/ru.json
index 386a17a2..97d8bfeb 100644
--- a/src/i18n/ru.json
+++ b/src/i18n/ru.json
@@ -112,10 +112,24 @@
"search_mark_dislike": "вообще не про то",
"search_mark-result-text": "Спасибо за оценку!"
},
+ "generative-search": {
+ "generative-search_expand": "Развернуть",
+ "generative-search_sources_title": "Источники",
+ "generative-search_bad_response": "Плохой ответ",
+ "generative-search_good_response": "Хороший ответ",
+ "generative-search_loading_title": "Быстрый ответ...",
+ "generative-search_feedback_answer": "Спасибо, что помогаете делать технологию лучше",
+ "generative-search_something_went_wrong": "Что-то пошло не так. Попробуйте ещё раз или обновите страницу.",
+ "generative-search_header_title": "Быстрый ответ",
+ "generative-search_header_text": "Создан с помощью нейросети",
+ "generative-search_disclaimer": "Ответ сформирован нейросетью YandexGPT на основе документации сервиса. В нём могут быть неточности, проверить информацию можно поссылкам на источники."
+ },
"search-suggest": {
"search-suggest_all-results": "Все результаты",
"search-suggest_not-found": "По запросу «{{query}}» ничего не найдено.",
"search-suggest_error-text": "Что-то пошло не так. Попробуйте ещё раз.",
+ "search-suggest-generative_title": "Нажмите, чтобы получить быстрый ответ",
+ "search-suggest-generative_subtitle": "С помощью нейросети YandexGPT",
"search-item_type-all": "Всё",
"search-item_type-doc": "Документация",
"search-item_type-main": "Главная"
diff --git a/src/themes/common/index.scss b/src/themes/common/index.scss
index d8cc549a..504f6710 100644
--- a/src/themes/common/index.scss
+++ b/src/themes/common/index.scss
@@ -25,7 +25,11 @@
&_theme_light {
@include g-colors-private-light;
+ --g-color-neutral-background: rgb(255, 255, 255);
+ --g-color-base-fill-color: var(--g-color-text-primary);
--g-color-base-background: rgb(255, 255, 255);
+ --g-color-second-background: rgba(241, 244, 249, 1);
+ --g-color-second-background-300: rgba(241, 244, 249, 0.3);
--g-color-base-brand: var(--g-color-private-blue-550-solid);
--g-color-base-brand-hover: var(--g-color-private-blue-600-solid);
--g-color-base-selection: var(--g-color-private-blue-100);
@@ -59,7 +63,11 @@
--dc-text-highlight-selected: var(--g-color-text-inverted-primary);
+ --g-color-neutral-background: rgba(41, 42, 45);
+ --g-color-base-fill-color: var(--g-color-text-primary);
--g-color-base-background: rgb(45, 44, 51);
+ --g-color-second-background: rgba(32, 33, 36);
+ --g-color-second-background-300: rgba(32, 33, 36, 0.3);
--g-color-base-brand: var(--g-color-private-blue-550-solid);
--g-color-base-brand-hover: var(--g-color-private-blue-600-solid);
--g-color-base-selection: var(--g-color-private-blue-150);
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 09041043..f5fe8f0a 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -137,3 +137,8 @@ export function getPageType({
return DocumentType.Base;
}
+
+export const simplifyUrl = (url: string) => {
+ const match = url.match(/^https?:\/\/[^/]+(\/.*)$/);
+ return match ? `...${match[1]}` : url;
+};