feat: themed avatars and branding updates (#67)
## Summary Added comprehensive avatar and branding updates across the library application: ### ๐ธ Updated Main Branding - New library-themed avatar (with playful "shh" gesture) for navigation icon - Updated favicon and all PWA icons (10 sizes from 72x72 to 512x512) - Added hero avatar to home page between title and subtitle - All branding uses consistent circular styling with elegant hover effects ### ๐จ Media-Specific Avatars Added unique themed avatars to each media list page: - **๐ฎ Games**: Gaming setup with controller and LED lights (red #ff6b6b border) - **๐ Books**: Reading in cozy library setting (brown #8b6f47 border) - **๐ต Music**: Joyful with headphones and urban nightscape (blue #74b9ff border) - **๐บ Shows**: Relaxing with remote and theater curtains (pink #e84393 border) - **๐ Manga**: Reading manga with shelves background (teal #00b894 border) - **๐จ Art**: Art studio with paintbrush (yellow #fdcb6e border) ### โจ Features - 120x120px circular avatars with themed colour borders - Smooth hover animations (scale + shadow effects) - Centered hero sections at top of each list view - Consistent styling across all media types - Perfect integration with existing colour themes ### ๐ Technical Details - All icons generated from source images at multiple resolutions - Static assets served with correct MIME types - Optimised image formats for performance - Responsive design with proper accessibility attributes ## Test Plan - [x] Verify navigation icon displays correctly in header - [x] Check favicon appears in browser tabs - [x] Test PWA icons on mobile devices - [x] Confirm home page hero avatar renders properly - [x] Verify all 6 media list avatars display with correct borders - [x] Test hover animations on all avatars - [x] Verify build succeeds - [x] Check static assets serve with correct MIME types ๐ธ Created with love by Hikari ๐ Reviewed-on: #67 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
|
After Width: | Height: | Size: 8.3 MiB |
|
After Width: | Height: | Size: 8.5 MiB |
|
After Width: | Height: | Size: 8.3 MiB |
|
After Width: | Height: | Size: 9.1 MiB |
|
After Width: | Height: | Size: 8.1 MiB |
|
After Width: | Height: | Size: 8.2 MiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 233 KiB After Width: | Height: | Size: 229 KiB |
|
Before Width: | Height: | Size: 392 KiB After Width: | Height: | Size: 381 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 270 KiB After Width: | Height: | Size: 381 KiB |
|
After Width: | Height: | Size: 8.6 MiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
@@ -23,6 +23,10 @@ import { Art, CreateArtDto, UpdateArtDto, Comment, SuggestionEntity, Link } from
|
|||||||
imports: [CommonModule, FormsModule, RouterModule, PaginationComponent, LikeButtonComponent],
|
imports: [CommonModule, FormsModule, RouterModule, PaginationComponent, LikeButtonComponent],
|
||||||
template: `
|
template: `
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="page-hero">
|
||||||
|
<img src="/assets/avatars/art-avatar.jpg" alt="Art avatar" class="page-avatar" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="header-section">
|
<div class="header-section">
|
||||||
<h2>Art Gallery</h2>
|
<h2>Art Gallery</h2>
|
||||||
<p class="subtitle">Artwork of Naomi</p>
|
<p class="subtitle">Artwork of Naomi</p>
|
||||||
@@ -458,6 +462,26 @@ import { Art, CreateArtDto, UpdateArtDto, Comment, SuggestionEntity, Link } from
|
|||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-hero {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-avatar {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 3px solid #fdcb6e;
|
||||||
|
box-shadow: 0 4px 12px rgba(253, 203, 110, 0.3);
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-avatar:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 8px 16px rgba(253, 203, 110, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
.header-section {
|
.header-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ import { Book, BookStatus, CreateBookDto, UpdateBookDto, Comment, SuggestionEnti
|
|||||||
imports: [CommonModule, FormsModule, RouterLink, PaginationComponent, LikeButtonComponent],
|
imports: [CommonModule, FormsModule, RouterLink, PaginationComponent, LikeButtonComponent],
|
||||||
template: `
|
template: `
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="page-hero">
|
||||||
|
<img src="/assets/avatars/books-avatar.jpg" alt="Books avatar" class="page-avatar" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="header-section">
|
<div class="header-section">
|
||||||
<h2>My Book Collection</h2>
|
<h2>My Book Collection</h2>
|
||||||
@if (authService.isAdmin()) {
|
@if (authService.isAdmin()) {
|
||||||
@@ -701,6 +705,26 @@ import { Book, BookStatus, CreateBookDto, UpdateBookDto, Comment, SuggestionEnti
|
|||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-hero {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-avatar {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 3px solid #8b6f47;
|
||||||
|
box-shadow: 0 4px 12px rgba(139, 111, 71, 0.3);
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-avatar:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 8px 16px rgba(139, 111, 71, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
.header-section {
|
.header-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ import { Game, GameStatus, CreateGameDto, UpdateGameDto, Comment, SuggestionEnti
|
|||||||
imports: [CommonModule, FormsModule, RouterModule, PaginationComponent, LikeButtonComponent],
|
imports: [CommonModule, FormsModule, RouterModule, PaginationComponent, LikeButtonComponent],
|
||||||
template: `
|
template: `
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="page-hero">
|
||||||
|
<img src="/assets/avatars/games-avatar.jpg" alt="Gaming avatar" class="page-avatar" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="header-section">
|
<div class="header-section">
|
||||||
<h2>My Game Collection</h2>
|
<h2>My Game Collection</h2>
|
||||||
@if (authService.isAdmin()) {
|
@if (authService.isAdmin()) {
|
||||||
@@ -684,6 +688,26 @@ import { Game, GameStatus, CreateGameDto, UpdateGameDto, Comment, SuggestionEnti
|
|||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-hero {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-avatar {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 3px solid #ff6b6b;
|
||||||
|
box-shadow: 0 4px 12px rgba(255, 107, 107, 0.3);
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-avatar:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 8px 16px rgba(255, 107, 107, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
.header-section {
|
.header-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { ApiService } from '../../services/api.service';
|
|||||||
<header class="header">
|
<header class="header">
|
||||||
<nav class="navbar" aria-label="Main navigation">
|
<nav class="navbar" aria-label="Main navigation">
|
||||||
<div class="nav-brand">
|
<div class="nav-brand">
|
||||||
<img src="/assets/icons/icon-72x72.png" alt="" class="brand-icon" role="presentation" />
|
<img src="/assets/nav-icon.jpg" alt="" class="brand-icon" role="presentation" />
|
||||||
<h1><a routerLink="/">Naomi's Library</a></h1>
|
<h1><a routerLink="/">Naomi's Library</a></h1>
|
||||||
@if (version()) {
|
@if (version()) {
|
||||||
<span class="version" aria-label="Version {{ version() }}">v{{ version() }}</span>
|
<span class="version" aria-label="Version {{ version() }}">v{{ version() }}</span>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { Game, GameStatus, Book, BookStatus, Music, MusicType, Manga, MangaStatu
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="hero">
|
<div class="hero">
|
||||||
<h1>Welcome to Naomi's Library</h1>
|
<h1>Welcome to Naomi's Library</h1>
|
||||||
|
<img src="/assets/nav-icon.jpg" alt="Naomi's avatar" class="hero-avatar" />
|
||||||
<p class="tagline">A personal collection of games, books, music, manga, shows, and art</p>
|
<p class="tagline">A personal collection of games, books, music, manga, shows, and art</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -190,10 +191,28 @@ import { Game, GameStatus, Book, BookStatus, Music, MusicType, Manga, MangaStatu
|
|||||||
|
|
||||||
.hero h1 {
|
.hero h1 {
|
||||||
font-size: 2.5rem;
|
font-size: 2.5rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 1rem;
|
||||||
color: var(--witch-purple);
|
color: var(--witch-purple);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hero-avatar {
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 4px solid var(--witch-lavender);
|
||||||
|
box-shadow: 0 4px 12px var(--witch-shadow);
|
||||||
|
margin: 1rem auto;
|
||||||
|
display: block;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-avatar:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 8px 16px rgba(157, 78, 221, 0.5);
|
||||||
|
border-color: var(--witch-rose);
|
||||||
|
}
|
||||||
|
|
||||||
.tagline {
|
.tagline {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
color: var(--witch-plum);
|
color: var(--witch-plum);
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ import { Manga, MangaStatus, CreateMangaDto, UpdateMangaDto, Comment, Suggestion
|
|||||||
imports: [CommonModule, FormsModule, RouterLink, PaginationComponent, LikeButtonComponent],
|
imports: [CommonModule, FormsModule, RouterLink, PaginationComponent, LikeButtonComponent],
|
||||||
template: `
|
template: `
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="page-hero">
|
||||||
|
<img src="/assets/avatars/manga-avatar.jpg" alt="Manga avatar" class="page-avatar" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="header-section">
|
<div class="header-section">
|
||||||
<h2>My Manga Collection</h2>
|
<h2>My Manga Collection</h2>
|
||||||
@if (authService.isAdmin()) {
|
@if (authService.isAdmin()) {
|
||||||
@@ -619,6 +623,26 @@ import { Manga, MangaStatus, CreateMangaDto, UpdateMangaDto, Comment, Suggestion
|
|||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-hero {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-avatar {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 3px solid #00b894;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 184, 148, 0.3);
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-avatar:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 8px 16px rgba(0, 184, 148, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
.header-section {
|
.header-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ import { Music, MusicStatus, MusicType, CreateMusicDto, UpdateMusicDto, Comment,
|
|||||||
imports: [CommonModule, FormsModule, RouterLink, PaginationComponent, LikeButtonComponent],
|
imports: [CommonModule, FormsModule, RouterLink, PaginationComponent, LikeButtonComponent],
|
||||||
template: `
|
template: `
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="page-hero">
|
||||||
|
<img src="/assets/avatars/music-avatar.jpg" alt="Music avatar" class="page-avatar" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="header-section">
|
<div class="header-section">
|
||||||
<h2>My Music Collection</h2>
|
<h2>My Music Collection</h2>
|
||||||
@if (authService.isAdmin()) {
|
@if (authService.isAdmin()) {
|
||||||
@@ -689,6 +693,26 @@ import { Music, MusicStatus, MusicType, CreateMusicDto, UpdateMusicDto, Comment,
|
|||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-hero {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-avatar {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 3px solid #74b9ff;
|
||||||
|
box-shadow: 0 4px 12px rgba(116, 185, 255, 0.3);
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-avatar:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 8px 16px rgba(116, 185, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
.header-section {
|
.header-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ import { Show, ShowStatus, ShowType, CreateShowDto, UpdateShowDto, Comment, Sugg
|
|||||||
imports: [CommonModule, RouterLink, FormsModule, PaginationComponent, LikeButtonComponent],
|
imports: [CommonModule, RouterLink, FormsModule, PaginationComponent, LikeButtonComponent],
|
||||||
template: `
|
template: `
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="page-hero">
|
||||||
|
<img src="/assets/avatars/shows-avatar.jpg" alt="Shows avatar" class="page-avatar" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="header-section">
|
<div class="header-section">
|
||||||
<h2>My Shows & Films</h2>
|
<h2>My Shows & Films</h2>
|
||||||
@if (authService.isAdmin()) {
|
@if (authService.isAdmin()) {
|
||||||
@@ -615,6 +619,26 @@ import { Show, ShowStatus, ShowType, CreateShowDto, UpdateShowDto, Comment, Sugg
|
|||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-hero {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-avatar {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 3px solid #e84393;
|
||||||
|
box-shadow: 0 4px 12px rgba(232, 67, 147, 0.3);
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-avatar:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 8px 16px rgba(232, 67, 147, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
.header-section {
|
.header-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||