mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
docs(docs-infra): always include fragment in search results (#63866)
Always include page fragment/sub-title in the search dialog results. PR Close #63866
This commit is contained in:
@@ -12,35 +12,49 @@
|
|||||||
@if (searchResults().length) {
|
@if (searchResults().length) {
|
||||||
<ul class="docs-search-results docs-mini-scroll-track">
|
<ul class="docs-search-results docs-mini-scroll-track">
|
||||||
@for (result of searchResults(); track result.id) {
|
@for (result of searchResults(); track result.id) {
|
||||||
<li docsSearchItem [item]="result">
|
<li docsSearchItem [item]="result" class="docs-search-result">
|
||||||
<a
|
<a
|
||||||
[routerLink]="'/' + result.url | relativeLink: 'pathname'"
|
[routerLink]="'/' + result.url | relativeLink: 'pathname'"
|
||||||
[fragment]="result.url | relativeLink: 'hash'"
|
[fragment]="result.url | relativeLink: 'hash'"
|
||||||
(click)="history.addItem(result)"
|
(click)="history.addItem(result)"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<div class="docs-result-icon-and-type">
|
<p class="docs-search-result__label">
|
||||||
<!-- Icon -->
|
<!-- Icon -->
|
||||||
<span class="docs-search-result-icon" aria-hidden="true">
|
<span class="docs-search-result-icon" aria-hidden="true">
|
||||||
<i role="presentation" class="material-symbols-outlined docs-icon-small">
|
<i role="presentation" class="material-symbols-outlined docs-icon-small">
|
||||||
{{ result.type === 'code' ? 'code' : 'description'}}
|
{{ result.type === 'code' ? 'code' : 'description'}}
|
||||||
</i>
|
</i>
|
||||||
</span>
|
</span>
|
||||||
<!-- Results type -->
|
|
||||||
<span class="docs-search-results__type" [innerHtml]="result.labelHtml"></span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if (result.subLabelHtml) {
|
|
||||||
<span
|
|
||||||
class="docs-search-results__type docs-search-results__lvl2"
|
|
||||||
[innerHtml]="result.subLabelHtml"
|
|
||||||
>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Page title -->
|
<!-- Page title -->
|
||||||
<span class="docs-result-page-title">{{ result.category }}</span>
|
<span [innerHtml]="result.labelHtml"></span>
|
||||||
|
@if (result.package) {
|
||||||
|
<span
|
||||||
|
[innerHTML]="result.package"
|
||||||
|
class="docs-search-result__label__package"
|
||||||
|
></span>
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
@if (result.subLabelHtml) {
|
||||||
|
<p class="docs-search-result__sub-label">
|
||||||
|
<span class="docs-search-result-icon" aria-hidden="true">
|
||||||
|
<i role="presentation" class="material-symbols-outlined docs-icon-small">
|
||||||
|
grid_3x3
|
||||||
|
</i>
|
||||||
|
</span>
|
||||||
|
<span [innerHtml]="result.subLabelHtml"></span>
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (result.contentHtml) {
|
||||||
|
<p class="docs-search-result__content" [innerHtml]="result.contentHtml"></p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<p class="docs-search-result__category">
|
||||||
|
{{ result.category }}
|
||||||
|
</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,11 +38,21 @@ dialog {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
border-block-end: 1px solid var(--senary-contrast);
|
border-block-end: 1px solid var(--senary-contrast);
|
||||||
|
|
||||||
li {
|
.docs-search-result {
|
||||||
border-inline-start: 2px solid var(--senary-contrast);
|
border-inline-start: 2px solid var(--senary-contrast);
|
||||||
margin-inline-start: 1rem;
|
margin-inline-start: 1rem;
|
||||||
padding-inline-end: 1rem;
|
display: block;
|
||||||
padding-block: 0.25rem;
|
font-size: 0.875rem;
|
||||||
|
|
||||||
|
.docs-search-result-icon {
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
i {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This rule needs ng-deep to be applied to elements that are created via a [innerHTML] binding
|
* This rule needs ng-deep to be applied to elements that are created via a [innerHTML] binding
|
||||||
@@ -61,15 +71,48 @@ dialog {
|
|||||||
color: var(--secondary-contrast);
|
color: var(--secondary-contrast);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
padding: 1rem;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.docs-search-result-icon {
|
&__label,
|
||||||
i {
|
&__sub-label,
|
||||||
|
&__content {
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label,
|
||||||
|
&__sub-label {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 1.2rem;
|
gap: 0.75rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-weight: 600;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
&__package {
|
||||||
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__content,
|
||||||
|
&__category {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__sub-label,
|
||||||
|
&__content {
|
||||||
|
margin-block-start: 0.375rem;
|
||||||
|
margin-inline-start: 2rem;
|
||||||
|
color: var(--quaternary-contrast);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__category {
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--quaternary-contrast);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
@@ -80,45 +123,15 @@ dialog {
|
|||||||
&.active {
|
&.active {
|
||||||
background-color: var(--octonary-contrast); // stylelint-disable-line
|
background-color: var(--octonary-contrast); // stylelint-disable-line
|
||||||
border-inline-start: 2px solid var(--primary-contrast);
|
border-inline-start: 2px solid var(--primary-contrast);
|
||||||
a {
|
|
||||||
span:not(.docs-result-page-title),
|
.docs-search-result__label,
|
||||||
.docs-search-results__type {
|
.docs-search-result__sub-label,
|
||||||
color: var(--primary-contrast);
|
.docs-search-result__content {
|
||||||
i {
|
|
||||||
color: var(--primary-contrast);
|
color: var(--primary-contrast);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.docs-search-result-icon,
|
|
||||||
.docs-search-results__type,
|
|
||||||
.docs-result-page-title {
|
|
||||||
color: var(--quaternary-contrast);
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
transition: color 0.3s ease;
|
|
||||||
padding: 0.75rem;
|
|
||||||
padding-inline-end: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.docs-search-results__lvl2 {
|
|
||||||
display: inline-block;
|
|
||||||
margin-inline-start: 2rem;
|
|
||||||
padding-block-start: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.docs-search-results__lvl3 {
|
|
||||||
margin-inline-start: 2rem;
|
|
||||||
padding-block-start: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.docs-result-page-title {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.docs-search-results__start-typing,
|
.docs-search-results__start-typing,
|
||||||
@@ -127,14 +140,6 @@ dialog {
|
|||||||
color: var(--gray-400);
|
color: var(--gray-400);
|
||||||
}
|
}
|
||||||
|
|
||||||
.docs-result-icon-and-type {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.docs-search-results__type {
|
|
||||||
padding-inline-start: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.docs-search-footer {
|
.docs-search-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ export interface SearchResultItem {
|
|||||||
type: 'doc' | 'code';
|
type: 'doc' | 'code';
|
||||||
labelHtml: string | null;
|
labelHtml: string | null;
|
||||||
subLabelHtml: string | null;
|
subLabelHtml: string | null;
|
||||||
|
contentHtml: string | null;
|
||||||
|
package: string | null;
|
||||||
url: string;
|
url: string;
|
||||||
|
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -144,13 +144,8 @@ export class Search {
|
|||||||
return this.getUniqueSearchResultItems(items).map((hitItem: SearchResult): SearchResultItem => {
|
return this.getUniqueSearchResultItems(items).map((hitItem: SearchResult): SearchResultItem => {
|
||||||
const content = hitItem._snippetResult.content;
|
const content = hitItem._snippetResult.content;
|
||||||
const hierarchy = hitItem._snippetResult.hierarchy;
|
const hierarchy = hitItem._snippetResult.hierarchy;
|
||||||
const type = hitItem.hierarchy.lvl0 === 'Tutorials' ? 'code' : 'doc';
|
|
||||||
const category = hitItem.hierarchy?.lvl0 ?? null;
|
const category = hitItem.hierarchy?.lvl0 ?? null;
|
||||||
const hasSubLabel = content || hierarchy?.lvl2 || hierarchy?.lvl3 || hierarchy?.lvl4;
|
const hasSubLabel = hierarchy?.lvl2 || hierarchy?.lvl3 || hierarchy?.lvl4;
|
||||||
const subLabelHtml =
|
|
||||||
category === 'Reference'
|
|
||||||
? extractPackageNameFromUrl(hitItem.url)
|
|
||||||
: this.parseLabelToHtml(hasSubLabel ? this.getBestSnippetForMatch(hitItem) : null);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: hitItem.objectID,
|
id: hitItem.objectID,
|
||||||
@@ -158,18 +153,18 @@ export class Search {
|
|||||||
url: hitItem.url,
|
url: hitItem.url,
|
||||||
|
|
||||||
labelHtml: this.parseLabelToHtml(hitItem._snippetResult.hierarchy?.lvl1?.value ?? ''),
|
labelHtml: this.parseLabelToHtml(hitItem._snippetResult.hierarchy?.lvl1?.value ?? ''),
|
||||||
subLabelHtml,
|
subLabelHtml: this.parseLabelToHtml(
|
||||||
|
hasSubLabel ? this.getBestSnippetForMatch(hitItem) : null,
|
||||||
|
),
|
||||||
|
contentHtml: content ? this.parseLabelToHtml(content.value) : null,
|
||||||
|
package: category === 'Reference' ? extractPackageNameFromUrl(hitItem.url) : null,
|
||||||
|
|
||||||
category: hitItem.hierarchy?.lvl0 ?? null,
|
category: hitItem.hierarchy?.lvl0 ?? null,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getBestSnippetForMatch(result: SearchResult): string {
|
private getBestSnippetForMatch(result: SearchResult): string {
|
||||||
// if there is content, return it
|
|
||||||
if (result._snippetResult.content !== undefined) {
|
|
||||||
return result._snippetResult.content.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hierarchy = result._snippetResult.hierarchy;
|
const hierarchy = result._snippetResult.hierarchy;
|
||||||
if (hierarchy === undefined) {
|
if (hierarchy === undefined) {
|
||||||
return '';
|
return '';
|
||||||
@@ -242,5 +237,5 @@ function extractPackageNameFromUrl(url: string): string | null {
|
|||||||
if (extractedSegment == null) {
|
if (extractedSegment == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return `From <code>@angular/${extractedSegment[1]}</code>`;
|
return `<code>@angular/${extractedSegment[1]}</code>`;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user