docs: improve accessibility of toh-pt6 (#40805)

PR Close #40805
This commit is contained in:
Kapunahele Wong 2021-02-08 10:05:25 -05:00 committed by atscott
parent 596dfb88a6
commit edd26a2b79
15 changed files with 167 additions and 162 deletions

View File

@ -53,7 +53,7 @@ describe('Tutorial part 6', () => {
appDashboardHref: navElts.get(0),
appDashboard: element(by.css('app-root app-dashboard')),
topHeroes: element.all(by.css('app-root app-dashboard > div h4')),
topHeroes: element.all(by.css('app-root app-dashboard > div a')),
appHeroesHref: navElts.get(1),
appHeroes: element(by.css('app-root app-heroes')),
@ -176,7 +176,7 @@ describe('Tutorial part 6', () => {
const numHeroes = heroesBefore.length;
await element(by.css('input')).sendKeys(addedHeroName);
await element(by.buttonText('add')).click();
await element(by.buttonText('Add hero')).click();
const page = getPageElts();
const heroesAfter = await toHeroArray(page.allHeroes);
@ -195,18 +195,18 @@ describe('Tutorial part 6', () => {
// Inherited styles from styles.css
expect(await button.getCssValue('font-family')).toBe('Arial, sans-serif');
expect(await button.getCssValue('border')).toContain('none');
expect(await button.getCssValue('padding')).toBe('5px 10px');
expect(await button.getCssValue('padding')).toBe('1px 10px 3px');
expect(await button.getCssValue('border-radius')).toBe('4px');
// Styles defined in heroes.component.css
expect(await button.getCssValue('left')).toBe('194px');
expect(await button.getCssValue('top')).toBe('-32px');
expect(await button.getCssValue('left')).toBe('210px');
expect(await button.getCssValue('top')).toBe('5px');
}
const addButton = element(by.buttonText('add'));
const addButton = element(by.buttonText('Add hero'));
// Inherited styles from styles.css
expect(await addButton.getCssValue('font-family')).toBe('Arial, sans-serif');
expect(await addButton.getCssValue('border')).toContain('none');
expect(await addButton.getCssValue('padding')).toBe('5px 10px');
expect(await addButton.getCssValue('padding')).toBe('8px 24px');
expect(await addButton.getCssValue('border-radius')).toBe('4px');
});

View File

@ -1,23 +1,20 @@
/* AppComponent's private CSS styles */
h1 {
font-size: 1.2em;
margin-bottom: 0;
}
nav a {
padding: 5px 10px;
padding: 1rem;
text-decoration: none;
margin-top: 10px;
display: inline-block;
background-color: #eee;
background-color: #e8e8e8;
color: #3d3d3d;
border-radius: 4px;
}
nav a:visited, a:link {
color: #334953;
}
nav a:hover {
color: #039be5;
background-color: #CFD8DC;
color: white;
background-color: #42545C;
}
nav a.active {
color: #039be5;
background-color: black;
}

View File

@ -1,61 +1,54 @@
/* DashboardComponent's private CSS styles */
[class*='col-'] {
float: left;
padding-right: 20px;
padding-bottom: 20px;
h2 {
text-align: center;
}
[class*='col-']:last-of-type {
padding-right: 0;
.heroes-menu {
padding: 0;
margin: auto;
max-width: 1000px;
/* flexbox */
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-around;
align-content: flex-start;
align-items: flex-start;
}
a {
text-decoration: none;
}
*, *::after, *::before {
box-sizing: border-box;
}
h3 {
text-align: center;
margin-bottom: 0;
}
h4 {
position: relative;
}
.grid {
margin: 0;
}
.col-1-4 {
width: 25%;
}
.module {
padding: 20px;
text-align: center;
color: #eee;
max-height: 120px;
min-width: 120px;
background-color: #3f525c;
border-radius: 2px;
padding: 1rem;
font-size: 1.2rem;
text-decoration: none;
display: inline-block;
color: #fff;
text-align: center;
width: 100%;
min-width: 70px;
margin: .5rem auto;
box-sizing: border-box;
/* flexbox */
order: 0;
flex: 0 1 auto;
align-self: auto;
}
.module:hover {
background-color: #EEE;
cursor: pointer;
color: #607d8b;
}
.grid-pad {
padding: 10px 0;
}
.grid-pad > [class*='col-']:last-of-type {
padding-right: 20px;
}
@media (max-width: 600px) {
.module {
font-size: 10px;
max-height: 75px; }
}
@media (max-width: 1024px) {
.grid {
margin: 0;
}
.module {
min-width: 60px;
@media (min-width: 600px) {
a {
width: 18%;
box-sizing: content-box;
}
}
a:hover {
background-color: black;
}

View File

@ -1,10 +1,8 @@
<h3>Top Heroes</h3>
<div class="grid grid-pad">
<a *ngFor="let hero of heroes" class="col-1-4"
<h2>Top Heroes</h2>
<div class="heroes-menu">
<a *ngFor="let hero of heroes"
routerLink="/detail/{{hero.id}}">
<div class="module hero">
<h4>{{hero.name}}</h4>
</div>
{{hero.name}}
</a>
</div>

View File

@ -37,7 +37,7 @@ describe('DashboardComponent', () => {
});
it('should display "Top Heroes" as headline', () => {
expect(fixture.nativeElement.querySelector('h3').textContent).toEqual('Top Heroes');
expect(fixture.nativeElement.querySelector('h2').textContent).toEqual('Top Heroes');
});
it('should call heroService', waitForAsync(() => {

View File

@ -1,24 +1,19 @@
/* HeroDetailComponent's private CSS styles */
label {
display: inline-block;
width: 3em;
margin: .5em 0;
color: #607D8B;
color: #435960;
font-weight: bold;
}
input {
height: 2em;
font-size: 1em;
padding-left: .4em;
padding: .5rem;
}
button {
margin-top: 20px;
font-family: Arial, sans-serif;
margin-right: .5rem;
background-color: #eee;
border: none;
padding: 5px 10px;
padding: 1rem;
border-radius: 4px;
cursor: pointer;
font-size: 1rem;
}
button:hover {
background-color: #cfd8dc;

View File

@ -2,9 +2,8 @@
<h2>{{hero.name | uppercase}} Details</h2>
<div><span>id: </span>{{hero.id}}</div>
<div>
<label>name:
<input [(ngModel)]="hero.name" placeholder="name"/>
</label>
<label for="hero-name">Hero name: </label>
<input id="hero-name" [(ngModel)]="hero.name" placeholder="Hero name"/>
</div>
<button (click)="goBack()">go back</button>
<!-- #docregion save -->

View File

@ -1,37 +1,45 @@
/* HeroSearch private styles */
.search-result li {
label {
display: block;
font-weight: bold;
font-size: 1.2rem;
margin-top: 1rem;
margin-bottom: .5rem;
}
input {
padding: .5rem;
width: 100%;
max-width: 600px;
box-sizing: border-box;
display: block;
}
input:focus {
outline: #336699 auto 1px;
}
li {
list-style-type: none;
}
.search-result li a {
border-bottom: 1px solid gray;
border-left: 1px solid gray;
border-right: 1px solid gray;
width: 195px;
height: 16px;
padding: 5px;
background-color: white;
cursor: pointer;
list-style-type: none;
}
.search-result li:hover {
background-color: #607D8B;
}
.search-result li a {
color: #888;
display: block;
display: inline-block;
width: 100%;
max-width: 600px;
padding: .5rem;
box-sizing: border-box;
text-decoration: none;
color: black;
}
.search-result li a:hover {
background-color: #435A60;
color: white;
}
.search-result li a:active {
color: white;
}
#search-box {
width: 200px;
height: 20px;
}
ul.search-result {
margin-top: 0;

View File

@ -1,6 +1,5 @@
<div id="search-component">
<h4><label for="search-box">Hero Search</label></h4>
<label for="search-box">Hero Search</label>
<!-- #docregion input -->
<input #searchBox id="search-box" (input)="search(searchBox.value)" />
<!-- #enddocregion input -->

View File

@ -5,32 +5,44 @@
padding: 0;
width: 15em;
}
input {
display: block;
width: 100%;
padding: .5rem;
margin: 1rem 0;
box-sizing: border-box;
}
.heroes li {
position: relative;
cursor: pointer;
background-color: #EEE;
margin: .5em;
padding: .3em 0;
height: 1.6em;
border-radius: 4px;
}
.heroes li:hover {
color: #607D8B;
background-color: #DDD;
left: .1em;
}
.heroes a {
color: #333;
text-decoration: none;
position: relative;
background-color: #EEE;
margin: .5em;
padding: .3em 0;
height: 1.6em;
border-radius: 4px;
display: block;
width: 250px;
width: 100%;
}
.heroes a:hover {
color: #607D8B;
color: #2c3a41;
background-color: #e6e6e6;
}
.heroes a:active {
background-color: #525252;
color: #fafafa;
}
.heroes .badge {
@ -50,23 +62,28 @@
border-radius: 4px 0 0 4px;
}
button {
background-color: #eee;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
font-family: Arial, sans-serif;
.add-button {
padding: .5rem 1.5rem;
font-size: 1rem;
margin-bottom: 2rem;
}
button:hover {
background-color: #cfd8dc;
.add-button:hover {
color: white;
background-color: #42545C;
}
button.delete {
position: relative;
left: 194px;
top: -32px;
background-color: gray !important;
position: absolute;
left: 210px;
top: 5px;
background-color: white;
color: #525252;
font-size: 1.1rem;
padding: 1px 10px 3px 10px;
}
button.delete:hover {
background-color: #525252;
color: white;
}

View File

@ -2,12 +2,12 @@
<!-- #docregion add -->
<div>
<label>Hero name:
<input #heroName />
</label>
<label id="new-hero">Hero name: </label>
<input for="new-hero" #heroName />
<!-- (click) passes input value to add() and then clears the input -->
<button (click)="add(heroName.value); heroName.value=''">
add
<button class="add-button" (click)="add(heroName.value); heroName.value=''">
Add hero
</button>
</div>
<!-- #enddocregion add -->

View File

@ -1,20 +1,19 @@
/* MessagesComponent's private CSS styles */
h2 {
color: red;
color: #A80000;
font-family: Arial, Helvetica, sans-serif;
font-weight: lighter;
}
button.clear {
font-family: Arial, sans-serif;
.clear {
color: #333;
background-color: #eee;
margin-bottom: 12px;
border: none;
padding: 5px 10px;
padding: 1rem;
border-radius: 4px;
cursor: pointer;
font-size: 1rem;
}
button:hover {
background-color: #cfd8dc;
.clear:hover {
color: #fff;
background-color: #42545C;
}

View File

@ -2,7 +2,7 @@
<h2>Messages</h2>
<button class="clear"
(click)="messageService.clear()">clear</button>
(click)="messageService.clear()">Clear messages</button>
<div *ngFor='let message of messageService.messages'> {{message}} </div>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -9,7 +9,7 @@ Angular's `HttpClient`.
<div class="alert is-helpful">
For the sample app that this page describes, see the <live-example></live-example>.
For the sample application that this page describes, see the <live-example></live-example>.
</div>
@ -17,7 +17,7 @@ Angular's `HttpClient`.
`HttpClient` is Angular's mechanism for communicating with a remote server over HTTP.
Make `HttpClient` available everywhere in the app in two steps. First, add it to the root `AppModule` by importing it:
Make `HttpClient` available everywhere in the application in two steps. First, add it to the root `AppModule` by importing it:
<code-example path="toh-pt6/src/app/app.module.ts" region="import-http-client" header="src/app/app.module.ts (HttpClientModule import)">
</code-example>
@ -33,7 +33,7 @@ Next, still in the `AppModule`, add `HttpClient` to the `imports` array:
This tutorial sample mimics communication with a remote data server by using the
[In-memory Web API](https://github.com/angular/angular/tree/master/packages/misc/angular-in-memory-web-api "In-memory Web API") module.
After installing the module, the app will make requests to and receive responses from the `HttpClient`
After installing the module, the application will make requests to and receive responses from the `HttpClient`
without knowing that the *In-memory Web API* is intercepting those requests,
applying them to an in-memory data store, and returning simulated responses.
@ -127,7 +127,7 @@ Convert that method to use `HttpClient` as follows:
Refresh the browser. The hero data should successfully load from the
mock server.
You've swapped `of()` for `http.get()` and the app keeps working without any other changes
You've swapped `of()` for `http.get()` and the application keeps working without any other changes
because both functions return an `Observable<Hero[]>`.
### `HttpClient` methods return one value
@ -197,10 +197,10 @@ has configured with both the name of the operation that failed and a safe return
</code-example>
After reporting the error to the console, the handler constructs
a user friendly message and returns a safe value to the app so the app can keep working.
a user friendly message and returns a safe value to the application so the application can keep working.
Because each service method returns a different kind of `Observable` result,
`handleError()` takes a type parameter so it can return the safe value as the type that the app expects.
`handleError()` takes a type parameter so it can return the safe value as the type that the application expects.
### Tap into the Observable
@ -283,7 +283,7 @@ The hero now appears in the list with the changed name.
## Add a new hero
To add a hero, this app only needs the hero's name. You can use an `<input>`
To add a hero, this application only needs the hero's name. You can use an `<input>`
element paired with an add button.
Insert the following into the `HeroesComponent` template, just after
@ -506,7 +506,7 @@ It cancels and discards previous search observables, returning only the latest s
Note that canceling a previous `searchHeroes()` Observable
doesn't actually abort a pending HTTP request.
Unwanted results are simply discarded before they reach your application code.
Unwanted results are discarded before they reach your application code.
</div>
@ -515,11 +515,11 @@ That's the job of the [`AsyncPipe`](#asyncpipe) in the template.
#### Try it
Run the app again. In the *Dashboard*, enter some text in the search box.
Run the application again. In the *Dashboard*, enter some text in the search box.
If you enter characters that match any existing hero names, you'll see something like this.
<div class="lightbox">
<img src='generated/images/guide/toh/toh-hero-search.png' alt="Hero Search Component">
<img src='generated/images/guide/toh/toh-hero-search.gif' alt="Hero Search field with the letters 'm' and 'a' along with four search results that match the query displayed in a list beneath the search input">
</div>
## Final code review