@@ -1,3 +1,15 @@
|
|
1 |
<main>
|
2 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
</main>
|
|
|
1 |
<main>
|
2 |
+
<nav>
|
3 |
+
<ul>
|
4 |
+
<li>
|
5 |
+
<a routerLink="/home" routerLinkActive="active"
|
6 |
+
ariaCurrentWhenActive="page">Home</a>
|
7 |
+
</li>
|
8 |
+
<li>
|
9 |
+
<a routerLink="/books" routerLinkActive="active"
|
10 |
+
ariaCurrentWhenActive="page">Books</a>
|
11 |
+
</li>
|
12 |
+
</ul>
|
13 |
+
</nav>
|
14 |
+
<router-outlet />
|
15 |
</main>
|
@@ -1,3 +1,10 @@
|
|
1 |
import { Routes } from '@angular/router';
|
2 |
|
3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import { Routes } from '@angular/router';
|
2 |
|
3 |
+
import { HomePage } from './home-page/home-page';
|
4 |
+
import { booksPortalRoutes } from './books-portal/books-portal.routes';
|
5 |
+
|
6 |
+
export const routes: Routes = [
|
7 |
+
{ path: '', redirectTo: 'home', pathMatch: 'full' },
|
8 |
+
{ path: 'home', component: HomePage, title: 'BookMonkey' },
|
9 |
+
...booksPortalRoutes
|
10 |
+
];
|
@@ -1,10 +1,9 @@
|
|
1 |
import { Component } from '@angular/core';
|
2 |
-
|
3 |
-
import { BookList } from './books-portal/book-list/book-list';
|
4 |
|
5 |
@Component({
|
6 |
selector: 'app-root',
|
7 |
-
imports: [
|
8 |
templateUrl: './app.ng.html',
|
9 |
styleUrl: './app.scss'
|
10 |
})
|
|
|
1 |
import { Component } from '@angular/core';
|
2 |
+
import { RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router';
|
|
|
3 |
|
4 |
@Component({
|
5 |
selector: 'app-root',
|
6 |
+
imports: [RouterOutlet, RouterLink, RouterLinkActive],
|
7 |
templateUrl: './app.ng.html',
|
8 |
styleUrl: './app.scss'
|
9 |
})
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@if (book(); as b) {
|
2 |
+
<article>
|
3 |
+
<header>
|
4 |
+
<h1>{{ b.title }}</h1>
|
5 |
+
@if (b.subtitle) {
|
6 |
+
<p role="doc-subtitle">{{ b.subtitle }}</p>
|
7 |
+
}
|
8 |
+
<div class="grid">
|
9 |
+
<div>
|
10 |
+
<h2>Authors</h2>
|
11 |
+
<ul>
|
12 |
+
@for (author of b.authors; track $index) {
|
13 |
+
<li>{{ author }}</li>
|
14 |
+
}
|
15 |
+
</ul>
|
16 |
+
</div>
|
17 |
+
<div>
|
18 |
+
<h2>ISBN</h2>
|
19 |
+
{{ b.isbn }}
|
20 |
+
</div>
|
21 |
+
<div>
|
22 |
+
<h2>Created at</h2>
|
23 |
+
{{ b.createdAt }}
|
24 |
+
</div>
|
25 |
+
</div>
|
26 |
+
</header>
|
27 |
+
<p>{{ b.description }}</p>
|
28 |
+
<img [src]="b.imageUrl" alt="Cover" />
|
29 |
+
<footer>
|
30 |
+
<a routerLink="/books">Back to list</a>
|
31 |
+
</footer>
|
32 |
+
</article>
|
33 |
+
}
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Component, inject, signal } from '@angular/core';
|
2 |
+
import { ActivatedRoute, RouterLink } from '@angular/router';
|
3 |
+
|
4 |
+
import { Book } from '../../shared/book';
|
5 |
+
import { BookStore } from '../../shared/book-store';
|
6 |
+
|
7 |
+
@Component({
|
8 |
+
selector: 'app-book-details',
|
9 |
+
imports: [RouterLink],
|
10 |
+
templateUrl: './book-details.ng.html',
|
11 |
+
styleUrl: './book-details.scss'
|
12 |
+
})
|
13 |
+
export class BookDetails {
|
14 |
+
#store = inject(BookStore);
|
15 |
+
#route = inject(ActivatedRoute);
|
16 |
+
|
17 |
+
readonly book = signal<Book | undefined>(undefined);
|
18 |
+
|
19 |
+
constructor() {
|
20 |
+
const isbn = this.#route.snapshot.paramMap.get('isbn');
|
21 |
+
if (isbn) {
|
22 |
+
this.book.set(this.#store.getOneBook(isbn));
|
23 |
+
}
|
24 |
+
}
|
25 |
+
}
|
@@ -12,6 +12,7 @@
|
|
12 |
ISBN: {{ b.isbn }}
|
13 |
</div>
|
14 |
<footer>
|
|
|
15 |
<button type="button" class="secondary" (click)="likeBook()">Like</button>
|
16 |
</footer>
|
17 |
</article>
|
|
|
12 |
ISBN: {{ b.isbn }}
|
13 |
</div>
|
14 |
<footer>
|
15 |
+
<a [routerLink]="['details', b.isbn]">Details</a>
|
16 |
<button type="button" class="secondary" (click)="likeBook()">Like</button>
|
17 |
</footer>
|
18 |
</article>
|
@@ -1,10 +1,11 @@
|
|
1 |
import { Component, input, output } from '@angular/core';
|
|
|
2 |
|
3 |
import { Book } from '../../shared/book';
|
4 |
|
5 |
@Component({
|
6 |
selector: 'app-book-item',
|
7 |
-
imports: [],
|
8 |
templateUrl: './book-item.ng.html',
|
9 |
styleUrl: './book-item.scss'
|
10 |
})
|
|
|
1 |
import { Component, input, output } from '@angular/core';
|
2 |
+
import { RouterLink } from '@angular/router';
|
3 |
|
4 |
import { Book } from '../../shared/book';
|
5 |
|
6 |
@Component({
|
7 |
selector: 'app-book-item',
|
8 |
+
imports: [RouterLink],
|
9 |
templateUrl: './book-item.ng.html',
|
10 |
styleUrl: './book-item.scss'
|
11 |
})
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Routes } from '@angular/router';
|
2 |
+
|
3 |
+
import { BookList } from './book-list/book-list';
|
4 |
+
import { BookDetails } from './book-details/book-details';
|
5 |
+
|
6 |
+
export const booksPortalRoutes: Routes = [
|
7 |
+
{ path: 'books', component: BookList, title: 'Books' },
|
8 |
+
{ path: 'books/details/:isbn', component: BookDetails, title: 'Book Details' },
|
9 |
+
];
|
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
<h1>Welcome to the BookMonkey!</h1>
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Component } from '@angular/core';
|
2 |
+
|
3 |
+
@Component({
|
4 |
+
selector: 'app-home-page',
|
5 |
+
imports: [],
|
6 |
+
templateUrl: './home-page.ng.html',
|
7 |
+
styleUrl: './home-page.scss'
|
8 |
+
})
|
9 |
+
export class HomePage {
|
10 |
+
|
11 |
+
}
|
@@ -31,4 +31,8 @@ export class BookStore {
|
|
31 |
getBookList(): Book[] {
|
32 |
return this.#books;
|
33 |
}
|
|
|
|
|
|
|
|
|
34 |
}
|
|
|
31 |
getBookList(): Book[] {
|
32 |
return this.#books;
|
33 |
}
|
34 |
+
|
35 |
+
getOneBook(isbn: string): Book | undefined {
|
36 |
+
return this.#books.find(book => book.isbn === isbn);
|
37 |
+
}
|
38 |
}
|