feat: interest over time graph (#127)

* api

* ui

* test

* add margin to prevent clipping
This commit is contained in:
Gabe Farrell 2026-01-12 16:20:31 -05:00 committed by GitHub
parent e45099c71a
commit 231eb1b0fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 1097 additions and 4 deletions

View file

@ -7,6 +7,7 @@ import PeriodSelector from "~/components/PeriodSelector";
import MediaLayout from "./MediaLayout";
import ActivityGrid from "~/components/ActivityGrid";
import { timeListenedString } from "~/utils/utils";
import InterestGraph from "~/components/InterestGraph";
export async function clientLoader({ params }: LoaderFunctionArgs) {
const res = await fetch(`/apis/web/v1/album?id=${params.id}`);
@ -69,7 +70,10 @@ export default function Album() {
<div className="flex flex-wrap gap-20 mt-10">
<LastPlays limit={30} albumId={album.id} />
<TopTracks limit={12} period={period} albumId={album.id} />
<ActivityGrid configurable albumId={album.id} />
<div className="flex flex-col items-start gap-4">
<ActivityGrid configurable albumId={album.id} />
<InterestGraph albumId={album.id} />
</div>
</div>
</MediaLayout>
);

View file

@ -8,6 +8,7 @@ import MediaLayout from "./MediaLayout";
import ArtistAlbums from "~/components/ArtistAlbums";
import ActivityGrid from "~/components/ActivityGrid";
import { timeListenedString } from "~/utils/utils";
import InterestGraph from "~/components/InterestGraph";
export async function clientLoader({ params }: LoaderFunctionArgs) {
const res = await fetch(`/apis/web/v1/artist?id=${params.id}`);
@ -76,7 +77,10 @@ export default function Artist() {
<div className="flex gap-15 mt-10 flex-wrap">
<LastPlays limit={20} artistId={artist.id} />
<TopTracks limit={8} period={period} artistId={artist.id} />
<ActivityGrid configurable artistId={artist.id} />
<div className="flex flex-col items-start gap-4">
<ActivityGrid configurable artistId={artist.id} />
<InterestGraph artistId={artist.id} />
</div>
</div>
<ArtistAlbums period={period} artistId={artist.id} name={artist.name} />
</div>

View file

@ -6,6 +6,7 @@ import PeriodSelector from "~/components/PeriodSelector";
import MediaLayout from "./MediaLayout";
import ActivityGrid from "~/components/ActivityGrid";
import { timeListenedString } from "~/utils/utils";
import InterestGraph from "~/components/InterestGraph";
export async function clientLoader({ params }: LoaderFunctionArgs) {
let res = await fetch(`/apis/web/v1/track?id=${params.id}`);
@ -73,7 +74,10 @@ export default function Track() {
</div>
<div className="flex flex-wrap gap-20 mt-10">
<LastPlays limit={20} trackId={track.id} />
<ActivityGrid trackId={track.id} configurable />
<div className="flex flex-col items-start gap-4">
<ActivityGrid configurable trackId={track.id} />
<InterestGraph trackId={track.id} />
</div>
</div>
</MediaLayout>
);