Merge branch 'feature/search-menu#VEGA-5235' into 'main'

VEGA-5236 Адаптация результатов поиска в документации

See merge request common/vega/beecloud-docs!35
This commit is contained in:
Речкина Елена Валерьевна
2025-10-14 08:06:15 +00:00
6 changed files with 104 additions and 146 deletions
+1 -1
View File
@@ -80,7 +80,7 @@ export default defineConfig({
buttonAriaLabel: 'Поиск' buttonAriaLabel: 'Поиск'
}, },
modal: { modal: {
noResultsText: 'Нет результатов для', noResultsText: 'Не удалось загрузить данные',
resetButtonTitle: 'Сбросить', resetButtonTitle: 'Сбросить',
displayDetails: 'Показать расширенный список', displayDetails: 'Показать расширенный список',
footer: { footer: {
@@ -22,8 +22,7 @@ type ItemFeature = {
const style = useCssModule() const style = useCssModule()
const classes = computed(() => ({ const classes = computed(() => ({
[style.CustomFeature]: true, [style.CustomFeature]: true,
[style.CustomFeatureDisabled]: disabled || !link, [style.CustomFeatureDisabled]: disabled || !link && !scrollTo,
[style.CustomFeatureWithScroll]: scrollTo && !disabled
})) }))
const handleClick = (event: Event) => { const handleClick = (event: Event) => {
@@ -51,7 +50,11 @@ const handleClick = (event: Event) => {
</Component> </Component>
<div :class="$style.CustomFeatureContainer"> <div :class="$style.CustomFeatureContainer">
<div v-for="(item, i) in items" :key="i"> <div v-for="(item, i) in items" :key="i">
<Component :is="!disabled && item.link ? VPLink : 'article'" v-bind="{ ...(!disabled && item.link && { href: item.link }) }"> <Component
:is="!disabled && item.link ? VPLink : 'article'"
v-bind="{ ...(!disabled && item.link && { href: item.link }) }"
:class="{ [style.CustomFeatureDisabled]: disabled || !item.link }"
>
<p :class="$style.CustomFeatureSubtitle">{{ item.title }}</p> <p :class="$style.CustomFeatureSubtitle">{{ item.title }}</p>
</Component> </Component>
</div> </div>
@@ -94,16 +97,12 @@ const handleClick = (event: Event) => {
color: themes.$color-text-active; color: themes.$color-text-active;
&:hover { &:hover {
color: themes.$color-text-link !important; color: themes.$color-text-link;
} }
#{$el}Disabled & { #{$el}Disabled & {
color: themes.$color-text-disabled; color: themes.$color-text-disabled;
} }
#{$el}WithScroll & {
color: themes.$color-text-active;
}
} }
&Subtitle { &Subtitle {
@@ -20,6 +20,7 @@ import {
nextTick, nextTick,
onBeforeUnmount, onBeforeUnmount,
onMounted, onMounted,
Raw,
ref, ref,
shallowRef, shallowRef,
watch, watch,
@@ -132,6 +133,7 @@ watchEffect(() => {
const results: Ref<(SearchResult & Result)[]> = shallowRef([]) const results: Ref<(SearchResult & Result)[]> = shallowRef([])
const enableNoResults = ref(false) const enableNoResults = ref(false)
const loadig = ref(true)
watch(filterText, () => { watch(filterText, () => {
enableNoResults.value = false enableNoResults.value = false
@@ -160,11 +162,7 @@ debouncedWatch(
if (!index) return if (!index) return
// Search // Search
results.value = index retrySearch(index, filterTextValue)
.search(filterTextValue)
.slice(0, 16) as (SearchResult & Result)[]
enableNoResults.value = true
// Highlighting // Highlighting
const mods = showDetailedListValue const mods = showDetailedListValue
? await Promise.all(results.value.map((r) => fetchExcerpt(r.id))) ? await Promise.all(results.value.map((r) => fetchExcerpt(r.id)))
@@ -268,6 +266,16 @@ function focusSearchInput(select = true) {
select && searchInput.value?.select() select && searchInput.value?.select()
} }
const retrySearch = (index: Raw<MiniSearch<Result>>, filter: string) => {
if (!index) return
results.value = index
.search(filter)
.slice(0, 16) as (SearchResult & Result)[]
enableNoResults.value = true
}
onMounted(() => { onMounted(() => {
focusSearchInput() focusSearchInput()
}) })
@@ -481,33 +489,6 @@ function formMarkRegex(terms: Set<string>) {
class="search-input" class="search-input"
/> />
<div class="search-actions"> <div class="search-actions">
<button
v-if="!disableDetailedView"
class="toggle-layout-button"
type="button"
:class="{ 'detailed-list': showDetailedList }"
:title="$t('modal.displayDetails')"
@click="
selectedIndex > -1 && (showDetailedList = !showDetailedList)
"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M3 14h7v7H3zM3 3h7v7H3zm11 1h7m-7 5h7m-7 6h7m-7 5h7"
/>
</svg>
</button>
<button <button
class="clear-button" class="clear-button"
type="reset" type="reset"
@@ -535,6 +516,7 @@ function formMarkRegex(terms: Set<string>) {
</form> </form>
<ul <ul
v-if="!!results.length"
ref="resultsEl" ref="resultsEl"
:id="results?.length ? 'localsearch-list' : undefined" :id="results?.length ? 'localsearch-list' : undefined"
:role="results?.length ? 'listbox' : undefined" :role="results?.length ? 'listbox' : undefined"
@@ -561,29 +543,21 @@ function formMarkRegex(terms: Set<string>) {
> >
<div> <div>
<div class="titles"> <div class="titles">
<span class="title-icon">#</span>
<span <span
v-for="(t, index) in p.titles" v-for="(t, index) in p.titles"
:key="index" :key="index"
class="title" class="title"
> >
<span class="text" v-html="t" /> <span class="text" v-html="t" />
<svg width="18" height="18" viewBox="0 0 24 24"> <span class="text"> > </span>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="m9 18l6-6l-6-6"
/>
</svg>
</span> </span>
<span class="title main"> <span class="title main">
<span class="text" v-html="p.title" /> <span class="text" v-html="p.title" />
</span> </span>
</div> </div>
<span v-html="p.title" />
<div v-if="showDetailedList" class="excerpt-wrapper"> <div v-if="showDetailedList" class="excerpt-wrapper">
<div v-if="p.text" class="excerpt" inert> <div v-if="p.text" class="excerpt" inert>
<div class="vp-doc" v-html="p.text" /> <div class="vp-doc" v-html="p.text" />
@@ -594,65 +568,21 @@ function formMarkRegex(terms: Set<string>) {
</div> </div>
</a> </a>
</li> </li>
<li </ul>
v-if="filterText && !results.length && enableNoResults" <ul
v-else-if="filterText && !results.length && enableNoResults"
class="no-results" class="no-results"
> >
{{ $t('modal.noResultsText') }} "<strong>{{ filterText }}</strong <p class="no-results-text">
>" {{ $t('modal.noResultsText') }}
</li> </p>
</ul> <button
class="no-results-button"
<div class="search-keyboard-shortcuts"> @click="retrySearch(searchIndex, filterText)"
<span>
<kbd :aria-label="$t('modal.footer.navigateUpKeyAriaLabel')">
<svg width="14" height="14" viewBox="0 0 24 24">
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 19V5m-7 7l7-7l7 7"
/>
</svg>
</kbd>
<kbd :aria-label="$t('modal.footer.navigateDownKeyAriaLabel')">
<svg width="14" height="14" viewBox="0 0 24 24">
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 5v14m7-7l-7 7l-7-7"
/>
</svg>
</kbd>
{{ $t('modal.footer.navigateText') }}
</span>
<span>
<kbd :aria-label="$t('modal.footer.selectKeyAriaLabel')">
<svg width="14" height="14" viewBox="0 0 24 24">
<g
fill="none"
stroke="currentcolor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
> >
<path d="m9 10l-5 5l5 5" /> Попробовать еще раз
<path d="M20 4v7a4 4 0 0 1-4 4H4" /> </button>
</g> </ul>
</svg>
</kbd>
{{ $t('modal.footer.selectText') }}
</span>
<span>
<kbd :aria-label="$t('modal.footer.closeKeyAriaLabel')">esc</kbd>
{{ $t('modal.footer.closeText') }}
</span>
</div>
</div> </div>
</div> </div>
</Teleport> </Teleport>
@@ -675,16 +605,13 @@ function formMarkRegex(terms: Set<string>) {
.shell { .shell {
position: relative; position: relative;
padding: 12px; padding: 24px;
margin: 64px auto; margin: 64px auto;
display: flex;
flex-direction: column;
gap: 16px;
background: var(--vp-local-search-bg); background: var(--vp-local-search-bg);
width: min(100vw - 60px, 900px); width: min(100vw - 60px, 900px);
height: min-content; height: min-content;
max-height: min(100vh - 128px, 900px); max-height: min(100vh - 128px, 900px);
border-radius: 6px; border-radius: 12px;
} }
@media (max-width: 767px) { @media (max-width: 767px) {
@@ -698,7 +625,7 @@ function formMarkRegex(terms: Set<string>) {
} }
.search-bar { .search-bar {
border: 1px solid var(--vp-c-divider); border: 1px solid rgb(32, 33, 35);
border-radius: 12px; border-radius: 12px;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -712,10 +639,6 @@ function formMarkRegex(terms: Set<string>) {
} }
} }
.search-bar:focus-within {
border-color: var(--vp-c-brand-1);
}
.search-icon { .search-icon {
margin: 8px; margin: 8px;
} }
@@ -802,27 +725,31 @@ function formMarkRegex(terms: Set<string>) {
} }
.results { .results {
display: flex;
flex-direction: column;
gap: 6px;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
overscroll-behavior: contain; overscroll-behavior: contain;
box-shadow: var(--vp-c-shadow-3);
border-radius: 12px;
border: 1px solid rgba(25, 28, 52, 0.18);
padding: 8px 0;
max-height: min(100vh - 214px, 900px);
li:hover {
background-color: rgba(25, 28, 52, 0.08);
}
} }
.result { .result {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
border-radius: 12px;
transition: none; transition: none;
line-height: 1rem;
border: solid 2px var(--vp-local-search-result-border);
outline: none; outline: none;
height: 66px;
} }
.result > div { .result > div {
margin: 12px; margin: 12px 16px;
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
} }
@@ -840,6 +767,13 @@ function formMarkRegex(terms: Set<string>) {
position: relative; position: relative;
z-index: 1001; z-index: 1001;
padding: 2px 0; padding: 2px 0;
font-size: 13px !important;
line-height: 16px !important;
}
:deep(mark) {
background-color: transparent;
color: none;
} }
.title { .title {
@@ -852,21 +786,10 @@ function formMarkRegex(terms: Set<string>) {
font-weight: 500; font-weight: 500;
} }
.title-icon {
opacity: 0.5;
font-weight: 500;
color: var(--vp-c-brand-1);
}
.title svg { .title svg {
opacity: 0.5; opacity: 0.5;
} }
.result.selected {
--vp-local-search-result-bg: var(--vp-local-search-result-selected-bg);
border-color: var(--vp-local-search-result-selected-border);
}
.excerpt-wrapper { .excerpt-wrapper {
position: relative; position: relative;
} }
@@ -892,10 +815,7 @@ function formMarkRegex(terms: Set<string>) {
.titles :deep(mark), .titles :deep(mark),
.excerpt :deep(mark) { .excerpt :deep(mark) {
background-color: var(--vp-local-search-highlight-bg); background-color: transparent;
color: var(--vp-local-search-highlight-text);
border-radius: 2px;
padding: 0 2px;
} }
.excerpt :deep(.vp-code-group) .tabs { .excerpt :deep(.vp-code-group) .tabs {
@@ -932,12 +852,42 @@ function formMarkRegex(terms: Set<string>) {
} }
.no-results { .no-results {
font-size: 0.9rem; padding: 28px 0;
text-align: center; display: flex;
padding: 12px; flex-direction: column;
gap: 24px;
align-items: center;
z-index: 100;
box-shadow: 0 0 10 0 rgba(0, 0, 0, 0.16);
border-radius: 12px;
border: 1px solid rgba(25, 28, 52, 0.18);
background-color: rgb(255, 255, 255);
}
.no-results-text {
font-weight: 700;
font-size: 17px;
line-height: 22px;
letter-spacing: 0.2px;
}
.no-results-button {
border-radius: 12px;
border: 1px solid rgba(25, 28, 52, 0.18);
padding: 13px 20px;
font-weight: 500;
font-size: 17px;
line-height: 22px;
letter-spacing: 0.2px;
} }
svg { svg {
flex: none; flex: none;
} }
.text {
font-size: 13px !important;
line-height: 16px !important;
color: rgba(25, 28, 52, 0.48);
}
</style> </style>
@@ -1,4 +1,5 @@
@use '@beeline/design-tokens/scss/tokens/components/navigationDrawer'; @use '@beeline/design-tokens/scss/tokens/components/navigationDrawer';
@use "@beeline/design-tokens/scss/tokens/globals/colors";
.VPDocAside { .VPDocAside {
.outline-link { .outline-link {
@@ -9,10 +10,12 @@
padding-top: 8px; padding-top: 8px;
padding-bottom: 8px; padding-bottom: 8px;
white-space: unset; white-space: unset;
color: colors.$color-text-grey-inactive;
} }
.outline-link.active { .outline-link.active {
font-weight: 500 !important; font-weight: 500 !important;
color: colors.$color-text-black-active;
} }
.outline-title { .outline-title {
@@ -1,5 +1,6 @@
@use '@beeline/design-tokens/scss/tokens/components/navigationDrawer'; @use '@beeline/design-tokens/scss/tokens/components/navigationDrawer';
@use '@beeline/design-tokens/scss/tokens/themes/theme-variables' as theme; @use '@beeline/design-tokens/scss/tokens/themes/theme-variables' as theme;
@use 'src/assets/scss/app/helpers/media';
.VPSidebar { .VPSidebar {
--vp-sidebar-bg-color: var(--vp-c-bg); --vp-sidebar-bg-color: var(--vp-c-bg);
@@ -109,5 +110,7 @@
} }
.VPLocalNav.has-sidebar { .VPLocalNav.has-sidebar {
padding-left: 320px !important; @include media.max(sm) {
padding-left: 0px;
}
} }
+3
View File
@@ -203,3 +203,6 @@
--docsearch-primary-color: var(--vp-c-brand-1) !important; --docsearch-primary-color: var(--vp-c-brand-1) !important;
} }
:root {
--vp-sidebar-width: 320px;
}