feat: redesign web interface to match aonsoku layout

Replace the early prototype UI with a darker Aonsoku-inspired shell featuring a compact top bar, library sidebar, command palette, settings overlay, dense track list, artists table, albums grid, and a bottom player bar. Add a supporting albums browse endpoint so the frontend can render the same navigation shape without faking data.
This commit is contained in:
2026-04-02 22:53:13 +03:00
parent 2f7034fae2
commit 2e7283baad
16 changed files with 1201 additions and 242 deletions

View File

@@ -173,6 +173,34 @@ func (s *Service) RecentAlbums(ctx context.Context, limit int) ([]Album, error)
return albums, rows.Err()
}
func (s *Service) Albums(ctx context.Context, limit int) ([]Album, error) {
rows, err := s.db.QueryContext(
ctx,
`SELECT al.id, al.artist_id, a.name, al.title, COALESCE(al.year, 0), COUNT(t.id) AS track_count, COALESCE(al.cover_art_id, '')
FROM albums al
JOIN artists a ON a.id = al.artist_id
LEFT JOIN tracks t ON t.album_id = al.id
GROUP BY al.id, al.artist_id, a.name, al.title, al.year, al.cover_art_id
ORDER BY al.year DESC, al.title ASC
LIMIT ?`,
limit,
)
if err != nil {
return nil, fmt.Errorf("query all albums: %w", err)
}
defer rows.Close()
var albums []Album
for rows.Next() {
var album Album
if err := rows.Scan(&album.ID, &album.ArtistID, &album.ArtistName, &album.Title, &album.Year, &album.TrackCount, &album.CoverArtID); err != nil {
return nil, fmt.Errorf("scan all albums: %w", err)
}
albums = append(albums, album)
}
return albums, rows.Err()
}
func (s *Service) AlbumByID(ctx context.Context, id string) (AlbumDetail, error) {
var album AlbumDetail