feat(docs-infra): add useful links if landed on 404 page and no search results found (#34978)

Added additional links which can help user find the things they are
looking for when there are no search results (when searching or on a 404
page).

Note:
This commit increases the main bundle's payload size due to the extra
content of the `aio-search-results` component.

Fixes #31532

PR Close #34978
This commit is contained in:
ajitsinghkaler 2020-02-26 23:39:12 +05:30 committed by atscott
parent aec463c606
commit 01ab168774
5 changed files with 104 additions and 34 deletions

View File

@ -3,7 +3,7 @@
"master": {
"uncompressed": {
"runtime-es2015": 2987,
"main-es2015": 449683,
"main-es2015": 450612,
"polyfills-es2015": 52195
}
}
@ -12,7 +12,7 @@
"master": {
"uncompressed": {
"runtime-es2015": 2987,
"main-es2015": 450541,
"main-es2015": 451469,
"polyfills-es2015": 52195
}
}
@ -21,7 +21,7 @@
"master": {
"uncompressed": {
"runtime-es2015": 3097,
"main-es2015": 427026,
"main-es2015": 429230,
"polyfills-es2015": 52195
}
}

View File

@ -1,30 +1,57 @@
<div class="search-results">
<div *ngIf="searchAreas.length; then searchResults; else notFound"></div>
<div class="search-results" [ngSwitch]="searchState">
<ng-container *ngSwitchCase="'in-progress'">
<p class="no-results">Searching ...</p>
</ng-container>
<ng-container *ngSwitchCase="'results-found'">
<h2 class="visually-hidden">Search Results</h2>
<div class="search-area" *ngFor="let area of searchAreas">
<h3 class="search-section-header">{{area.name}} ({{area.pages.length + area.priorityPages.length}})</h3>
<ul class="priority-pages" >
<li class="search-page" *ngFor="let page of area.priorityPages">
<a class="search-result-item" href="{{ page.path }}" (click)="onResultSelected(page, $event)">
<span class="symbol {{page.type}}" *ngIf="area.name === 'api'"></span>
<span [class.deprecated-api-item]="page.deprecated">{{ page.title }}</span>
</a>
</li>
</ul>
<ul>
<li class="search-page" *ngFor="let page of area.pages">
<a class="search-result-item" href="{{ page.path }}" (click)="onResultSelected(page, $event)">
<span class="symbol {{page.type}}" *ngIf="area.name === 'api'"></span>
<span [class.deprecated-api-item]="page.deprecated">{{ page.title }}</span>
</a>
</li>
</ul>
</div>
</ng-container>
<ng-container *ngSwitchCase="'no-results-found'">
<div class="search-area">
<p class="no-results">
No results found.<br>
Here are a few links that might be helpful in finding what you are looking for:
</p>
<ul class="priority-pages">
<li class="search-page">
<a class="search-result-item" href="api">API reference</a>
</li>
<li class="search-page">
<a class="search-result-item" href="resources">Resources</a>
</li>
<li class="search-page">
<a class="search-result-item" href="guide/glossary">Glossary</a>
</li>
<li class="search-page">
<a class="search-result-item" href="guide/cheatsheet">Cheat-sheet</a>
</li>
<li class="search-page">
<a class="search-result-item" href="https://blog.angular.io/">Angular blog</a>
</li>
</ul>
</div>
</ng-container>
</div>
<ng-template #searchResults>
<h2 class="visually-hidden">Search Results</h2>
<div class="search-area" *ngFor="let area of searchAreas">
<h3 class="search-section-header">{{area.name}} ({{area.pages.length + area.priorityPages.length}})</h3>
<ul class="priority-pages" >
<li class="search-page" *ngFor="let page of area.priorityPages">
<a class="search-result-item" href="{{ page.path }}" (click)="onResultSelected(page, $event)">
<span class="symbol {{page.type}}" *ngIf="area.name === 'api'"></span>
<span [class.deprecated-api-item]="page.deprecated">{{ page.title }}</span>
</a>
</li>
</ul>
<ul>
<li class="search-page" *ngFor="let page of area.pages">
<a class="search-result-item" href="{{ page.path }}" (click)="onResultSelected(page, $event)">
<span class="symbol {{page.type}}" *ngIf="area.name === 'api'"></span>
<span [class.deprecated-api-item]="page.deprecated">{{ page.title }}</span>
</a>
</li>
</ul>
</div>
</ng-template>
<ng-template #notFound>
<p class="not-found">{{notFoundMessage}}</p>
</ng-template>

View File

@ -170,6 +170,12 @@ describe('SearchResultsComponent', () => {
expect(getText()).toContain('Searching ...');
});
it('should not display default links while searching', () => {
fixture.detectChanges();
const resultLinks = fixture.debugElement.queryAll(By.css('.search-page a'));
expect(resultLinks.length).toEqual(0);
});
describe('when a search result anchor is clicked', () => {
let searchResult: SearchResult;
let selected: SearchResult|null;
@ -214,9 +220,25 @@ describe('SearchResultsComponent', () => {
});
describe('when no query results', () => {
it('should display "not found" message', () => {
beforeEach(() => {
setSearchResults('something', []);
});
it('should display "not found" message', () => {
expect(getText()).toContain('No results');
});
it('should contain reference links', () => {
const resultLinks = fixture.debugElement.queryAll(By.css('.search-page a'));
const resultHrefs = resultLinks.map(a => a.nativeNode.getAttribute('href'));
expect(resultHrefs.length).toEqual(5);
expect(resultHrefs).toEqual([
'api',
'resources',
'guide/glossary',
'guide/cheatsheet',
'https://blog.angular.io/',
]);
});
});
});

View File

@ -1,6 +1,12 @@
import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core';
import { SearchResult, SearchResults, SearchArea } from 'app/search/interfaces';
enum SearchState {
InProgress = 'in-progress',
ResultsFound = 'results-found',
NoResultsFound = 'no-results-found'
}
/**
* A component to display search results in groups
*/
@ -23,11 +29,18 @@ export class SearchResultsComponent implements OnChanges {
resultSelected = new EventEmitter<SearchResult>();
readonly defaultArea = 'other';
notFoundMessage = 'Searching ...';
searchState: SearchState = SearchState.InProgress;
readonly topLevelFolders = ['guide', 'tutorial'];
searchAreas: SearchArea[] = [];
ngOnChanges() {
if (this.searchResults === null) {
this.searchState = SearchState.InProgress;
} else if (this.searchResults.results.length) {
this.searchState = SearchState.ResultsFound;
} else {
this.searchState = SearchState.NoResultsFound;
}
this.searchAreas = this.processSearchResults(this.searchResults);
}
@ -43,7 +56,6 @@ export class SearchResultsComponent implements OnChanges {
if (!search) {
return [];
}
this.notFoundMessage = 'No results found.';
const searchAreaMap: { [key: string]: SearchResult[] } = {};
search.results.forEach(result => {
if (!result.title) { return; } // bad data; should fix

View File

@ -67,12 +67,17 @@ aio-search-results {
}
}
.not-found {
.no-results {
color: $white;
text-align: center;
margin: 16px;
}
a {
color: $white;
font-weight: 500;
}
@media (max-width: 600px) {
display: block;
}
@ -104,6 +109,10 @@ aio-search-results {
.not-found {
color: $darkgray;
}
a {
color: $blue;
}
}
}
}