generated from nhcarrigan/template
feat: category colour schemes, add stats to home page
This commit is contained in:
@@ -500,18 +500,18 @@ import { Art, CreateArtDto, UpdateArtDto, Comment } from '@library/shared-types'
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
background: var(--witch-rose);
|
background: #fdcb6e;
|
||||||
color: var(--witch-moon);
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-secondary {
|
.btn-secondary {
|
||||||
background: var(--witch-mauve);
|
background: #6b7280;
|
||||||
color: var(--witch-purple);
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-danger {
|
.btn-danger {
|
||||||
background: var(--witch-plum);
|
background: #ef4444;
|
||||||
color: var(--witch-moon);
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-sm {
|
.btn-sm {
|
||||||
|
|||||||
@@ -482,8 +482,8 @@ import { Book, BookStatus, CreateBookDto, UpdateBookDto, Comment } from '@librar
|
|||||||
}
|
}
|
||||||
|
|
||||||
.filter-btn.active {
|
.filter-btn.active {
|
||||||
background: var(--witch-plum);
|
background: #8b6f47;
|
||||||
color: var(--witch-moon);
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading {
|
.loading {
|
||||||
@@ -623,33 +623,33 @@ import { Book, BookStatus, CreateBookDto, UpdateBookDto, Comment } from '@librar
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
background: var(--witch-rose);
|
background: #8b6f47;
|
||||||
color: var(--witch-moon);
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary:hover {
|
.btn-primary:hover {
|
||||||
background: var(--witch-plum);
|
background: #725a3a;
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 4px 8px var(--witch-shadow);
|
box-shadow: 0 4px 8px var(--witch-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-secondary {
|
.btn-secondary {
|
||||||
background: var(--witch-mauve);
|
background: #6b7280;
|
||||||
color: var(--witch-purple);
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-secondary:hover {
|
.btn-secondary:hover {
|
||||||
background: var(--witch-rose);
|
background: #4b5563;
|
||||||
color: var(--witch-moon);
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-danger {
|
.btn-danger {
|
||||||
background: var(--witch-plum);
|
background: #ef4444;
|
||||||
color: var(--witch-moon);
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-danger:hover {
|
.btn-danger:hover {
|
||||||
background: var(--witch-purple);
|
background: #dc2626;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-sm { padding: 0.25rem 0.75rem; font-size: 0.85rem; }
|
.btn-sm { padding: 0.25rem 0.75rem; font-size: 0.85rem; }
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ import { Game, GameStatus, CreateGameDto, UpdateGameDto, Comment } from '@librar
|
|||||||
}
|
}
|
||||||
|
|
||||||
.filter-btn.active {
|
.filter-btn.active {
|
||||||
background: #3b82f6;
|
background: #ff6b6b;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,7 +539,7 @@ import { Game, GameStatus, CreateGameDto, UpdateGameDto, Comment } from '@librar
|
|||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary { background: #3b82f6; color: white; }
|
.btn-primary { background: #ff6b6b; color: white; }
|
||||||
.btn-secondary { background: #6b7280; color: white; }
|
.btn-secondary { background: #6b7280; color: white; }
|
||||||
.btn-danger { background: #ef4444; color: white; }
|
.btn-danger { background: #ef4444; color: white; }
|
||||||
.btn-sm { padding: 0.25rem 0.75rem; font-size: 0.85rem; }
|
.btn-sm { padding: 0.25rem 0.75rem; font-size: 0.85rem; }
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ import { RouterModule } from '@angular/router';
|
|||||||
import { GamesService } from '../../services/games.service';
|
import { GamesService } from '../../services/games.service';
|
||||||
import { BooksService } from '../../services/books.service';
|
import { BooksService } from '../../services/books.service';
|
||||||
import { MusicService } from '../../services/music.service';
|
import { MusicService } from '../../services/music.service';
|
||||||
import { Game, GameStatus, Book, BookStatus, Music, MusicType } from '@library/shared-types';
|
import { MangaService } from '../../services/manga.service';
|
||||||
|
import { ShowsService } from '../../services/shows.service';
|
||||||
|
import { ArtService } from '../../services/art.service';
|
||||||
|
import { Game, GameStatus, Book, BookStatus, Music, MusicType, Manga, MangaStatus, Show, ShowStatus, ShowType, Art } from '@library/shared-types';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home',
|
selector: 'app-home',
|
||||||
@@ -20,7 +23,7 @@ import { Game, GameStatus, Book, BookStatus, Music, MusicType } from '@library/s
|
|||||||
<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>
|
||||||
<p class="tagline">A personal collection of games, books, and music</p>
|
<p class="tagline">A personal collection of games, books, music, manga, shows, and art</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="stats-grid">
|
<div class="stats-grid">
|
||||||
@@ -50,6 +53,33 @@ import { Game, GameStatus, Book, BookStatus, Music, MusicType } from '@library/s
|
|||||||
<p>{{ albumsCount() }} albums, {{ singlesCount() }} singles</p>
|
<p>{{ albumsCount() }} albums, {{ singlesCount() }} singles</p>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<a routerLink="/manga" class="stat-card manga-card">
|
||||||
|
<div class="icon">📖</div>
|
||||||
|
<div class="stat-info">
|
||||||
|
<h3>Manga</h3>
|
||||||
|
<div class="count">{{ mangaCount() }}</div>
|
||||||
|
<p>{{ currentlyReadingMangaCount() }} currently reading</p>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a routerLink="/shows" class="stat-card shows-card">
|
||||||
|
<div class="icon">📺</div>
|
||||||
|
<div class="stat-info">
|
||||||
|
<h3>Shows</h3>
|
||||||
|
<div class="count">{{ showsCount() }}</div>
|
||||||
|
<p>{{ animeCount() }} anime, {{ filmsCount() }} films</p>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a routerLink="/art" class="stat-card art-card">
|
||||||
|
<div class="icon">🎨</div>
|
||||||
|
<div class="stat-info">
|
||||||
|
<h3>Art</h3>
|
||||||
|
<div class="count">{{ artCount() }}</div>
|
||||||
|
<p>commissioned pieces</p>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="recent-section">
|
<div class="recent-section">
|
||||||
@@ -99,6 +129,48 @@ import { Game, GameStatus, Book, BookStatus, Music, MusicType } from '@library/s
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@if (recentManga().length > 0) {
|
||||||
|
<div class="recent-category">
|
||||||
|
<h3>📖 Latest Manga</h3>
|
||||||
|
<ul class="recent-list">
|
||||||
|
@for (manga of recentManga(); track manga.id) {
|
||||||
|
<li>
|
||||||
|
<a routerLink="/manga">{{ manga.title }}</a>
|
||||||
|
<span class="author">by {{ manga.author }}</span>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (recentShows().length > 0) {
|
||||||
|
<div class="recent-category">
|
||||||
|
<h3>📺 Latest Shows</h3>
|
||||||
|
<ul class="recent-list">
|
||||||
|
@for (show of recentShows(); track show.id) {
|
||||||
|
<li>
|
||||||
|
<a routerLink="/shows">{{ show.title }}</a>
|
||||||
|
<span class="show-type">{{ formatShowType(show.type) }}</span>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (recentArt().length > 0) {
|
||||||
|
<div class="recent-category">
|
||||||
|
<h3>🎨 Latest Art</h3>
|
||||||
|
<ul class="recent-list">
|
||||||
|
@for (art of recentArt(); track art.id) {
|
||||||
|
<li>
|
||||||
|
<a routerLink="/art">{{ art.title }}</a>
|
||||||
|
<span class="artist">by {{ art.artist }}</span>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -154,9 +226,12 @@ import { Game, GameStatus, Book, BookStatus, Music, MusicType } from '@library/s
|
|||||||
background: var(--witch-moon);
|
background: var(--witch-moon);
|
||||||
}
|
}
|
||||||
|
|
||||||
.games-card:hover { border-color: var(--witch-rose); }
|
.games-card:hover { border-color: #ff6b6b; }
|
||||||
.books-card:hover { border-color: var(--witch-plum); }
|
.books-card:hover { border-color: #8b6f47; }
|
||||||
.music-card:hover { border-color: var(--witch-purple); }
|
.music-card:hover { border-color: #74b9ff; }
|
||||||
|
.manga-card:hover { border-color: #00b894; }
|
||||||
|
.shows-card:hover { border-color: #e84393; }
|
||||||
|
.art-card:hover { border-color: #fdcb6e; }
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
@@ -176,9 +251,12 @@ import { Game, GameStatus, Book, BookStatus, Music, MusicType } from '@library/s
|
|||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.games-card .count { color: var(--witch-rose); }
|
.games-card .count { color: #ff6b6b; }
|
||||||
.books-card .count { color: var(--witch-plum); }
|
.books-card .count { color: #8b6f47; }
|
||||||
.music-card .count { color: var(--witch-purple); }
|
.music-card .count { color: #74b9ff; }
|
||||||
|
.manga-card .count { color: #00b894; }
|
||||||
|
.shows-card .count { color: #e84393; }
|
||||||
|
.art-card .count { color: #fdcb6e; }
|
||||||
|
|
||||||
.stat-info p {
|
.stat-info p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -239,7 +317,8 @@ import { Game, GameStatus, Book, BookStatus, Music, MusicType } from '@library/s
|
|||||||
|
|
||||||
.platform,
|
.platform,
|
||||||
.author,
|
.author,
|
||||||
.artist {
|
.artist,
|
||||||
|
.show-type {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
color: var(--witch-plum);
|
color: var(--witch-plum);
|
||||||
@@ -251,16 +330,25 @@ export class HomeComponent implements OnInit {
|
|||||||
gamesService = inject(GamesService);
|
gamesService = inject(GamesService);
|
||||||
booksService = inject(BooksService);
|
booksService = inject(BooksService);
|
||||||
musicService = inject(MusicService);
|
musicService = inject(MusicService);
|
||||||
|
mangaService = inject(MangaService);
|
||||||
|
showsService = inject(ShowsService);
|
||||||
|
artService = inject(ArtService);
|
||||||
|
|
||||||
games = signal<Game[]>([]);
|
games = signal<Game[]>([]);
|
||||||
books = signal<Book[]>([]);
|
books = signal<Book[]>([]);
|
||||||
music = signal<Music[]>([]);
|
music = signal<Music[]>([]);
|
||||||
|
manga = signal<Manga[]>([]);
|
||||||
|
shows = signal<Show[]>([]);
|
||||||
|
art = signal<Art[]>([]);
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
// Load all data
|
// Load all data
|
||||||
this.gamesService.getAllGames().subscribe(games => this.games.set(games));
|
this.gamesService.getAllGames().subscribe(games => this.games.set(games));
|
||||||
this.booksService.getAllBooks().subscribe(books => this.books.set(books));
|
this.booksService.getAllBooks().subscribe(books => this.books.set(books));
|
||||||
this.musicService.getAllMusic().subscribe(music => this.music.set(music));
|
this.musicService.getAllMusic().subscribe(music => this.music.set(music));
|
||||||
|
this.mangaService.getAllManga().subscribe(manga => this.manga.set(manga));
|
||||||
|
this.showsService.getAllShows().subscribe(shows => this.shows.set(shows));
|
||||||
|
this.artService.getAllArt().subscribe(art => this.art.set(art));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Games stats
|
// Games stats
|
||||||
@@ -305,4 +393,58 @@ export class HomeComponent implements OnInit {
|
|||||||
recentMusic() {
|
recentMusic() {
|
||||||
return this.music().slice(0, 5);
|
return this.music().slice(0, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Manga stats
|
||||||
|
mangaCount() {
|
||||||
|
return this.manga().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentlyReadingMangaCount() {
|
||||||
|
return this.manga().filter(m => m.status === MangaStatus.reading).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
recentManga() {
|
||||||
|
return this.manga().slice(0, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shows stats
|
||||||
|
showsCount() {
|
||||||
|
return this.shows().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
animeCount() {
|
||||||
|
return this.shows().filter(s => s.type === ShowType.anime).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
filmsCount() {
|
||||||
|
return this.shows().filter(s => s.type === ShowType.film).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
recentShows() {
|
||||||
|
return this.shows().slice(0, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
formatShowType(type: ShowType): string {
|
||||||
|
switch (type) {
|
||||||
|
case ShowType.tvSeries:
|
||||||
|
return 'TV Series';
|
||||||
|
case ShowType.anime:
|
||||||
|
return 'Anime';
|
||||||
|
case ShowType.film:
|
||||||
|
return 'Film';
|
||||||
|
case ShowType.documentary:
|
||||||
|
return 'Documentary';
|
||||||
|
default:
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Art stats
|
||||||
|
artCount() {
|
||||||
|
return this.art().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
recentArt() {
|
||||||
|
return this.art().slice(0, 5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -432,7 +432,7 @@ import { Manga, MangaStatus, CreateMangaDto, UpdateMangaDto, Comment } from '@li
|
|||||||
}
|
}
|
||||||
|
|
||||||
.filter-btn.active {
|
.filter-btn.active {
|
||||||
background: #ec4899;
|
background: #00b894;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,7 +541,7 @@ import { Manga, MangaStatus, CreateMangaDto, UpdateMangaDto, Comment } from '@li
|
|||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary { background: #ec4899; color: white; }
|
.btn-primary { background: #00b894; color: white; }
|
||||||
.btn-secondary { background: #6b7280; color: white; }
|
.btn-secondary { background: #6b7280; color: white; }
|
||||||
.btn-danger { background: #ef4444; color: white; }
|
.btn-danger { background: #ef4444; color: white; }
|
||||||
.btn-sm { padding: 0.25rem 0.75rem; font-size: 0.85rem; }
|
.btn-sm { padding: 0.25rem 0.75rem; font-size: 0.85rem; }
|
||||||
|
|||||||
@@ -533,8 +533,8 @@ import { Music, MusicStatus, MusicType, CreateMusicDto, UpdateMusicDto, Comment
|
|||||||
}
|
}
|
||||||
|
|
||||||
.filter-btn.active {
|
.filter-btn.active {
|
||||||
background: var(--witch-rose);
|
background: #74b9ff;
|
||||||
color: var(--witch-moon);
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading {
|
.loading {
|
||||||
@@ -695,33 +695,33 @@ import { Music, MusicStatus, MusicType, CreateMusicDto, UpdateMusicDto, Comment
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
background: var(--witch-rose);
|
background: #74b9ff;
|
||||||
color: var(--witch-moon);
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary:hover {
|
.btn-primary:hover {
|
||||||
background: var(--witch-plum);
|
background: #4a9ff5;
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 4px 8px var(--witch-shadow);
|
box-shadow: 0 4px 8px var(--witch-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-secondary {
|
.btn-secondary {
|
||||||
background: var(--witch-mauve);
|
background: #6b7280;
|
||||||
color: var(--witch-purple);
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-secondary:hover {
|
.btn-secondary:hover {
|
||||||
background: var(--witch-rose);
|
background: #4b5563;
|
||||||
color: var(--witch-moon);
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-danger {
|
.btn-danger {
|
||||||
background: var(--witch-plum);
|
background: #ef4444;
|
||||||
color: var(--witch-moon);
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-danger:hover {
|
.btn-danger:hover {
|
||||||
background: var(--witch-purple);
|
background: #dc2626;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-sm {
|
.btn-sm {
|
||||||
|
|||||||
@@ -428,7 +428,7 @@ import { Show, ShowStatus, ShowType, CreateShowDto, UpdateShowDto, Comment } fro
|
|||||||
}
|
}
|
||||||
|
|
||||||
.filter-btn.active {
|
.filter-btn.active {
|
||||||
background: #8b5cf6;
|
background: #e84393;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,7 +536,7 @@ import { Show, ShowStatus, ShowType, CreateShowDto, UpdateShowDto, Comment } fro
|
|||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary { background: #8b5cf6; color: white; }
|
.btn-primary { background: #e84393; color: white; }
|
||||||
.btn-secondary { background: #6b7280; color: white; }
|
.btn-secondary { background: #6b7280; color: white; }
|
||||||
.btn-danger { background: #ef4444; color: white; }
|
.btn-danger { background: #ef4444; color: white; }
|
||||||
.btn-sm { padding: 0.25rem 0.75rem; font-size: 0.85rem; }
|
.btn-sm { padding: 0.25rem 0.75rem; font-size: 0.85rem; }
|
||||||
|
|||||||
Reference in New Issue
Block a user