mirror of https://github.com/hykilpikonna/AquaDX
[+] Display more info on user page
parent
85301c92ec
commit
7e198bd7a1
|
@ -6,13 +6,14 @@ import {
|
||||||
LineElement,
|
LineElement,
|
||||||
LinearScale,
|
LinearScale,
|
||||||
PointElement,
|
PointElement,
|
||||||
CategoryScale, TimeScale,
|
CategoryScale, TimeScale, type ChartOptions, type LineOptions,
|
||||||
} from 'chart.js';
|
} from 'chart.js';
|
||||||
import moment from "moment/moment";
|
import moment from "moment/moment";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import CalHeatmap from "cal-heatmap";
|
import CalHeatmap from "cal-heatmap";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import CalTooltip from 'cal-heatmap/plugins/Tooltip';
|
import CalTooltip from 'cal-heatmap/plugins/Tooltip';
|
||||||
|
import type {Line} from "svelte-chartjs";
|
||||||
|
|
||||||
export function title(t: string) {
|
export function title(t: string) {
|
||||||
document.title = `AquaNet - ${t}`
|
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
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {registerChart, renderCal, title} from "../libs/ui";
|
import {CHARTJS_OPT, registerChart, renderCal, title} from "../libs/ui";
|
||||||
import {getMaimai, getMaimaiTrend} from "../libs/maimai";
|
import {getMaimaiTrend, getMaimaiUser} from "../libs/maimai";
|
||||||
import type {MaiUserPreviewData} from "../libs/maimaiTypes";
|
import type {MaimaiUserSummaryEntry} from "../libs/maimaiTypes";
|
||||||
import type {TrendEntry} from "../libs/generalTypes";
|
import type {TrendEntry} from "../libs/generalTypes";
|
||||||
import {data_host} from "../libs/config";
|
import {data_host} from "../libs/config";
|
||||||
// @ts-ignore
|
|
||||||
import CalHeatmap from 'cal-heatmap';
|
|
||||||
import 'cal-heatmap/cal-heatmap.css';
|
import 'cal-heatmap/cal-heatmap.css';
|
||||||
import { Line } from 'svelte-chartjs';
|
import { Line } from 'svelte-chartjs';
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
@ -20,12 +18,12 @@
|
||||||
title(`User ${userId}`)
|
title(`User ${userId}`)
|
||||||
|
|
||||||
let d: {
|
let d: {
|
||||||
user: MaiUserPreviewData,
|
user: MaimaiUserSummaryEntry,
|
||||||
trend: TrendEntry[]
|
trend: TrendEntry[]
|
||||||
} | null = null
|
} | null = null
|
||||||
|
|
||||||
Promise.all([
|
Promise.all([
|
||||||
getMaimai('GetUserPreviewApi', {userId}),
|
getMaimaiUser(userId),
|
||||||
getMaimaiTrend(userId)
|
getMaimaiTrend(userId)
|
||||||
]).then(([user, trend]) => {
|
]).then(([user, trend]) => {
|
||||||
console.log(user)
|
console.log(user)
|
||||||
|
@ -37,10 +35,26 @@
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main>
|
<main id="user-home">
|
||||||
{#if d !== null}
|
{#if d !== null}
|
||||||
|
<div class="user-pfp">
|
||||||
<img src={`${data_host}/maimai/assetbundle/icon/${d.user.iconId.toString().padStart(6, "0")}.png`} alt="" class="pfp">
|
<img src={`${data_host}/maimai/assetbundle/icon/${d.user.iconId.toString().padStart(6, "0")}.png`} alt="" class="pfp">
|
||||||
<h1>{d.user.userName}</h1>
|
<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">
|
<div class="trend">
|
||||||
<Line data={{
|
<Line data={{
|
||||||
|
@ -48,41 +62,144 @@
|
||||||
{
|
{
|
||||||
label: 'Rating',
|
label: 'Rating',
|
||||||
data: d.trend.map(it => {return {x: Date.parse(it.date), y: it.rating}}),
|
data: d.trend.map(it => {return {x: Date.parse(it.date), y: it.rating}}),
|
||||||
fill: false,
|
borderColor: '#646cff',
|
||||||
borderColor: 'rgb(75, 192, 192)',
|
tension: 0.1,
|
||||||
tension: 0.1
|
|
||||||
|
// TODO: Set X axis span to 3 months
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}} options={{
|
}} options={CHARTJS_OPT} />
|
||||||
// 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>
|
</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 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>
|
||||||
|
|
||||||
{:else}
|
{:else}
|
||||||
<p>Loading...</p>
|
<p>Loading...</p>
|
||||||
{/if}
|
{/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>
|
|
@ -60,7 +60,7 @@ class Maimai2New(
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapOf(
|
return mapOf(
|
||||||
"name" to user,
|
"name" to user.userName,
|
||||||
"iconId" to user.iconId,
|
"iconId" to user.iconId,
|
||||||
|
|
||||||
"serverRank" to userDataRepository.getRanking(user.playerRating),
|
"serverRank" to userDataRepository.getRanking(user.playerRating),
|
||||||
|
|
Loading…
Reference in New Issue