/**
* @copyright 2026 NHCarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Component, OnInit, inject, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { GamesService } from '../../services/games.service';
import { BooksService } from '../../services/books.service';
import { MusicService } from '../../services/music.service';
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({
selector: 'app-home',
standalone: true,
imports: [CommonModule, RouterModule],
template: `
Welcome to Naomi's Library
A personal collection of games, books, music, manga, shows, and art
Recent Additions
@if (recentGames().length > 0) {
🎮 Latest Games
@for (game of recentGames(); track game.id) {
-
{{ game.title }}
@if (game.platform) {
({{ game.platform }})
}
}
}
@if (recentBooks().length > 0) {
📚 Latest Books
@for (book of recentBooks(); track book.id) {
-
{{ book.title }}
by {{ book.author }}
}
}
@if (recentMusic().length > 0) {
🎵 Latest Music
@for (music of recentMusic(); track music.id) {
-
{{ music.title }}
by {{ music.artist }}
}
}
@if (recentManga().length > 0) {
📖 Latest Manga
@for (manga of recentManga(); track manga.id) {
-
{{ manga.title }}
by {{ manga.author }}
}
}
@if (recentShows().length > 0) {
📺 Latest Shows
@for (show of recentShows(); track show.id) {
-
{{ show.title }}
{{ formatShowType(show.type) }}
}
}
@if (recentArt().length > 0) {
🎨 Latest Art
@for (art of recentArt(); track art.id) {
-
{{ art.title }}
by {{ art.artist }}
}
}
`,
styles: [`
.container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.hero {
text-align: center;
padding: 3rem 0;
margin-bottom: 3rem;
}
.hero h1 {
font-size: 2.5rem;
margin-bottom: 0.5rem;
color: var(--witch-purple);
}
.tagline {
font-size: 1.2rem;
color: var(--witch-plum);
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1.5rem;
margin-bottom: 3rem;
}
.stat-card {
display: flex;
align-items: center;
gap: 1.5rem;
padding: 1.5rem;
background: rgba(255, 255, 255, 0.95);
border: 2px solid var(--witch-mauve);
border-radius: 12px;
text-decoration: none;
color: inherit;
transition: all 0.3s;
backdrop-filter: blur(10px);
}
.stat-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 16px var(--witch-shadow);
background: var(--witch-moon);
}
.games-card:hover { border-color: #ff6b6b; }
.books-card:hover { border-color: #8b6f47; }
.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 {
font-size: 3rem;
flex-shrink: 0;
}
.stat-info h3 {
margin: 0 0 0.5rem 0;
font-size: 1.1rem;
color: var(--witch-plum);
}
.count {
font-size: 2.5rem;
font-weight: bold;
line-height: 1;
margin-bottom: 0.5rem;
}
.games-card .count { color: #ff6b6b; }
.books-card .count { color: #8b6f47; }
.music-card .count { color: #74b9ff; }
.manga-card .count { color: #00b894; }
.shows-card .count { color: #e84393; }
.art-card .count { color: #fdcb6e; }
.stat-info p {
margin: 0;
color: var(--witch-plum);
font-size: 0.9rem;
}
.recent-section {
background: rgba(255, 255, 255, 0.95);
padding: 2rem;
border-radius: 12px;
border: 2px solid var(--witch-lavender);
backdrop-filter: blur(10px);
}
.recent-section h2 {
margin: 0 0 1.5rem 0;
font-size: 1.5rem;
}
.recent-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
}
.recent-category h3 {
margin: 0 0 1rem 0;
font-size: 1.1rem;
color: var(--witch-purple);
}
.recent-list {
list-style: none;
padding: 0;
margin: 0;
}
.recent-list li {
padding: 0.5rem 0;
border-bottom: 1px solid var(--witch-lavender);
}
.recent-list li:last-child {
border-bottom: none;
}
.recent-list a {
color: var(--witch-rose);
text-decoration: none;
font-weight: 500;
}
.recent-list a:hover {
color: var(--witch-plum);
text-decoration: underline;
}
.platform,
.author,
.artist,
.show-type {
display: block;
font-size: 0.85rem;
color: var(--witch-plum);
margin-top: 0.25rem;
}
`]
})
export class HomeComponent implements OnInit {
gamesService = inject(GamesService);
booksService = inject(BooksService);
musicService = inject(MusicService);
mangaService = inject(MangaService);
showsService = inject(ShowsService);
artService = inject(ArtService);
games = signal([]);
books = signal([]);
music = signal([]);
manga = signal([]);
shows = signal([]);
art = signal([]);
ngOnInit() {
// Load all data
this.gamesService.getAllGames().subscribe(games => this.games.set(games));
this.booksService.getAllBooks().subscribe(books => this.books.set(books));
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
gamesCount() {
return this.games().length;
}
currentlyPlayingCount() {
return this.games().filter(g => g.status === GameStatus.playing).length;
}
recentGames() {
return this.games().slice(0, 5);
}
// Books stats
booksCount() {
return this.books().length;
}
currentlyReadingCount() {
return this.books().filter(b => b.status === BookStatus.reading).length;
}
recentBooks() {
return this.books().slice(0, 5);
}
// Music stats
musicCount() {
return this.music().length;
}
albumsCount() {
return this.music().filter(m => m.type === MusicType.album).length;
}
singlesCount() {
return this.music().filter(m => m.type === MusicType.single).length;
}
recentMusic() {
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);
}
}