diff --git a/frontend/src/components/ReportTopAlbums.tsx b/frontend/src/components/ReportTopAlbums.tsx index 479bcaa..22031cb 100644 --- a/frontend/src/components/ReportTopAlbums.tsx +++ b/frontend/src/components/ReportTopAlbums.tsx @@ -5,6 +5,7 @@ import { TimeOptions } from "../api/entities/time-options"; import { TimePreset } from "../api/entities/time-preset.enum"; import { useTopAlbums } from "../hooks/use-api"; import { useAuth } from "../hooks/use-auth"; +import { getMaxCount } from "../util/getMaxCount"; import { ReportTimeOptions } from "./ReportTimeOptions"; import { TopListItem } from "./TopListItem"; @@ -27,6 +28,7 @@ export const ReportTopAlbums: React.FC = () => { const { topAlbums, isLoading } = useTopAlbums(options); const reportHasItems = !isLoading && topAlbums.length !== 0; + const maxCount = getMaxCount(topAlbums); if (!user) { return ; @@ -55,7 +57,12 @@ export const ReportTopAlbums: React.FC = () => { )} {reportHasItems && topAlbums.map(({ album, count }) => ( - + ))} @@ -66,7 +73,8 @@ export const ReportTopAlbums: React.FC = () => { const ReportItem: React.FC<{ album: Album; count: number; -}> = ({ album, count }) => { + maxCount: number; +}> = ({ album, count, maxCount }) => { const artists = album.artists?.map((artist) => artist.name).join(", ") || ""; return ( @@ -75,6 +83,7 @@ const ReportItem: React.FC<{ title={album.name} subTitle={artists} count={count} + maxCount={maxCount} /> ); }; diff --git a/frontend/src/components/ReportTopArtists.tsx b/frontend/src/components/ReportTopArtists.tsx index f58153a..abe37df 100644 --- a/frontend/src/components/ReportTopArtists.tsx +++ b/frontend/src/components/ReportTopArtists.tsx @@ -4,6 +4,7 @@ import { TimeOptions } from "../api/entities/time-options"; import { TimePreset } from "../api/entities/time-preset.enum"; import { useTopArtists } from "../hooks/use-api"; import { useAuth } from "../hooks/use-auth"; +import { getMaxCount } from "../util/getMaxCount"; import { ReportTimeOptions } from "./ReportTimeOptions"; import { TopListItem } from "./TopListItem"; @@ -26,6 +27,7 @@ export const ReportTopArtists: React.FC = () => { const { topArtists, isLoading } = useTopArtists(options); const reportHasItems = !isLoading && topArtists.length !== 0; + const maxCount = getMaxCount(topArtists); if (!user) { return ; @@ -54,7 +56,12 @@ export const ReportTopArtists: React.FC = () => { )} {reportHasItems && topArtists.map(({ artist, count }) => ( - + ))} diff --git a/frontend/src/components/ReportTopTracks.tsx b/frontend/src/components/ReportTopTracks.tsx index e3ef730..3a8ec27 100644 --- a/frontend/src/components/ReportTopTracks.tsx +++ b/frontend/src/components/ReportTopTracks.tsx @@ -5,6 +5,7 @@ import { TimePreset } from "../api/entities/time-preset.enum"; import { Track } from "../api/entities/track"; import { useTopTracks } from "../hooks/use-api"; import { useAuth } from "../hooks/use-auth"; +import { getMaxCount } from "../util/getMaxCount"; import { ReportTimeOptions } from "./ReportTimeOptions"; import { TopListItem } from "./TopListItem"; @@ -32,6 +33,8 @@ export const ReportTopTracks: React.FC = () => { return ; } + const maxCount = getMaxCount(topTracks); + return (
@@ -55,7 +58,7 @@ export const ReportTopTracks: React.FC = () => { )} {reportHasItems && topTracks.map(({ track, count }) => ( - + ))}
@@ -66,7 +69,8 @@ export const ReportTopTracks: React.FC = () => { const ReportItem: React.FC<{ track: Track; count: number; -}> = ({ track, count }) => { + maxCount: number; +}> = ({ track, count, maxCount }) => { const artists = track.artists?.map((artist) => artist.name).join(", ") || ""; return ( @@ -75,6 +79,7 @@ const ReportItem: React.FC<{ title={track.name} subTitle={artists} count={count} + maxCount={maxCount} /> ); }; diff --git a/frontend/src/components/TopListItem.tsx b/frontend/src/components/TopListItem.tsx index 2727796..c678610 100644 --- a/frontend/src/components/TopListItem.tsx +++ b/frontend/src/components/TopListItem.tsx @@ -1,23 +1,55 @@ import React from "react"; -export const TopListItem: React.FC<{ +export interface TopListItemProps { key: string; title: string; subTitle?: string; count: number; -}> = ({ key, title, subTitle, count }) => { + + /** + * Highest Number that is displayed in the top list. Used to display a "progress bar". + */ + maxCount?: number; +} + +export const TopListItem: React.FC = ({ + key, + title, + subTitle, + count, + maxCount, +}) => { return (
-
-
- {title} +
+
+
+ {title} +
+ {subTitle &&
{subTitle}
}
- {subTitle &&
{subTitle}
} +
{count}
-
{count}
+ {maxCount && isMaxCountValid(maxCount) && ( +
+
+
+ )}
); }; + +const isMaxCountValid = (maxCount: number) => + !(Number.isNaN(maxCount) || maxCount === 0); + +const numberToPercent = (ratio: number) => + ratio.toLocaleString(undefined, { + style: "percent", + minimumFractionDigits: 2, + }); diff --git a/frontend/src/util/getMaxCount.ts b/frontend/src/util/getMaxCount.ts new file mode 100644 index 0000000..f37d440 --- /dev/null +++ b/frontend/src/util/getMaxCount.ts @@ -0,0 +1,11 @@ +interface TopListItemEntity { + count: number; +} + +/** + * Get max count for top list. Returns at least 1 to make sure we do not run into issues + * with empty list (would normally return -Infinity) or 0 (could cause divide by zero error). + */ +export function getMaxCount(items: TopListItemEntity[]): number { + return Math.max(1, ...items.map(({ count }) => count)); +} diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index dc896ec..8c3ab91 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -39,6 +39,8 @@ module.exports = { }, yellow: colors.yellow, + teal: colors.teal, + violet: colors.violet, }, }, };