[+] Display more info on user page

pull/10/head
Azalea 2024-02-12 01:48:28 -05:00
parent 85301c92ec
commit 7e198bd7a1
3 changed files with 199 additions and 52 deletions

View File

@ -6,13 +6,14 @@ import {
LineElement,
LinearScale,
PointElement,
CategoryScale, TimeScale,
CategoryScale, TimeScale, type ChartOptions, type LineOptions,
} from 'chart.js';
import moment from "moment/moment";
// @ts-ignore
import CalHeatmap from "cal-heatmap";
// @ts-ignore
import CalTooltip from 'cal-heatmap/plugins/Tooltip';
import type {Line} from "svelte-chartjs";
export function title(t: string) {
document.title = `AquaNet - ${t}`
@ -60,3 +61,32 @@ export function renderCal(el: HTMLElement, d: {date: any, value: any}[]) {
]);
}
export const CHARTJS_OPT: ChartOptions<"line"> = {
responsive: true,
maintainAspectRatio: false,
// TODO: Show point on hover
elements: {
point: {
radius: 0
}
},
scales: {
xAxis: {
type: 'time',
display: false
},
y: {
display: false,
}
},
plugins: {
legend: {
display: false
},
tooltip: {
mode: "index",
intersect: false
}
},
}

View File

@ -1,11 +1,9 @@
<script lang="ts">
import {registerChart, renderCal, title} from "../libs/ui";
import {getMaimai, getMaimaiTrend} from "../libs/maimai";
import type {MaiUserPreviewData} from "../libs/maimaiTypes";
import {CHARTJS_OPT, registerChart, renderCal, title} from "../libs/ui";
import {getMaimaiTrend, getMaimaiUser} from "../libs/maimai";
import type {MaimaiUserSummaryEntry} from "../libs/maimaiTypes";
import type {TrendEntry} from "../libs/generalTypes";
import {data_host} from "../libs/config";
// @ts-ignore
import CalHeatmap from 'cal-heatmap';
import 'cal-heatmap/cal-heatmap.css';
import { Line } from 'svelte-chartjs';
import moment from "moment";
@ -20,12 +18,12 @@
title(`User ${userId}`)
let d: {
user: MaiUserPreviewData,
user: MaimaiUserSummaryEntry,
trend: TrendEntry[]
} | null = null
Promise.all([
getMaimai('GetUserPreviewApi', {userId}),
getMaimaiUser(userId),
getMaimaiTrend(userId)
]).then(([user, trend]) => {
console.log(user)
@ -37,52 +35,171 @@
})
</script>
<main>
<main id="user-home">
{#if d !== null}
<img src={`${data_host}/maimai/assetbundle/icon/${d.user.iconId.toString().padStart(6, "0")}.png`} alt="" class="pfp">
<h1>{d.user.userName}</h1>
<div class="trend">
<Line data={{
datasets: [
{
label: 'Rating',
data: d.trend.map(it => {return {x: Date.parse(it.date), y: it.rating}}),
fill: false,
borderColor: 'rgb(75, 192, 192)',
tension: 0.1
}
]
}} options={{
// TODO: Show point on hover
elements: {
point: {
radius: 0
}
},
scales: {
xAxis: {
type: 'time',
display: false
},
y: {
display: false,
}
},
plugins: {
legend: {
display: false
},
tooltip: {
mode: "index",
intersect: false
}
},
}} />
<div class="user-pfp">
<img src={`${data_host}/maimai/assetbundle/icon/${d.user.iconId.toString().padStart(6, "0")}.png`} alt="" class="pfp">
<h1>{d.user.name}</h1>
</div>
<div class="scoring-info">
<div class="chart">
<div class="info-top">
<div class="rating">
<span>DX Rating</span>
<span>{d.user.rating.toLocaleString()}</span>
</div>
<div class="rank">
<span>Server Rank</span>
<span>#{d.user.serverRank.toLocaleString()}</span>
</div>
</div>
<div class="trend">
<Line data={{
datasets: [
{
label: 'Rating',
data: d.trend.map(it => {return {x: Date.parse(it.date), y: it.rating}}),
borderColor: '#646cff',
tension: 0.1,
// TODO: Set X axis span to 3 months
}
]
}} options={CHARTJS_OPT} />
</div>
<div class="info-bottom">
{#each d.user.ranks as r}
<div>
<span>{r.name}</span>
<span>{r.count}</span>
</div>
{/each}
</div>
</div>
<div class="other-info">
<div class="accuracy">
<span>Accuracy</span>
<span>{(d.user.accuracy / 10000).toFixed(2)}%</span>
</div>
<div class="max-combo">
<span>Max Combo</span>
<span>{d.user.maxCombo}</span>
</div>
<div class="full-combo">
<span>Full Combo</span>
<span>{d.user.fullCombo}</span>
</div>
<div class="all-perfect">
<span>All Perfect</span>
<span>{d.user.allPerfect}</span>
</div>
<div class="total-dx-score">
<span>DX Score</span>
<span>{d.user.totalDxScore.toLocaleString()}</span>
</div>
</div>
</div>
<div class="activity-info">
<div id="cal-heatmap" bind:this={calElement} />
<div class="info-bottom">
<div class="plays">
<span>Plays</span>
<span>{d.user.plays}</span>
</div>
<div class="time">
<span>Play Time</span>
<span>{d.user.totalPlayTime}</span>
</div>
<div class="first-play">
<span>Joined</span>
<span>{moment(d.user.joined).format("YYYY-MM-DD HH:mm:ss")}</span>
</div>
<div class="last-play">
<span>Last Seen</span>
<span>{moment(d.user.lastSeen).format("YYYY-MM-DD HH:mm:ss")}</span>
</div>
<div class="last-version">
<span>Last Version</span>
<span>{d.user.lastVersion}</span>
</div>
</div>
</div>
<div id="cal-heatmap" bind:this={calElement} />
{:else}
<p>Loading...</p>
{/if}
</main>
</main>
<style lang="sass">
@import "../vars"
#user-home
display: flex
flex-direction: column
gap: 20px
padding: 0 32px
.pfp
width: 100px
height: 100px
border-radius: 5px
object-fit: cover
.info-bottom, .info-top, .other-info
display: flex
gap: 20px
> div
display: flex
flex-direction: column
> span:first-child
font-weight: bold
font-size: 0.8rem
// character spacing
letter-spacing: 0.1em
color: $c-main
.info-top > div > span:last-child
font-size: 1.5rem
.scoring-info
display: flex
gap: 20px
max-height: 250px
.chart
flex: 1
display: flex
flex-direction: column
.other-info
flex: 0 0 100px
flex-direction: column
gap: 0
justify-content: space-between
.trend
height: 300px
width: 100%
</style>

View File

@ -60,7 +60,7 @@ class Maimai2New(
}
return mapOf(
"name" to user,
"name" to user.userName,
"iconId" to user.iconId,
"serverRank" to userDataRepository.getRanking(user.playerRating),