mirror of https://github.com/hykilpikonna/AquaDX
[+] Add a B50 / rating page to frontend
parent
d3d7b5a5c7
commit
95e78e4f93
|
@ -0,0 +1,146 @@
|
||||||
|
<!-- Svelte 4.2.11 -->
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { slide } from "svelte/transition";
|
||||||
|
import { DATA_HOST } from "../libs/config";
|
||||||
|
import { t } from "../libs/i18n";
|
||||||
|
import { type GameName, getMult } from "../libs/scoring";
|
||||||
|
export let g: string
|
||||||
|
export let meta: MusicMeta
|
||||||
|
export let game: GameName
|
||||||
|
import { coverNotFound } from "../libs/ui";
|
||||||
|
import { DATA } from "../libs/sdk";
|
||||||
|
import type { MusicMeta } from "../libs/generalTypes";
|
||||||
|
import { parse } from "svelte/compiler";
|
||||||
|
|
||||||
|
let mapData = g.split(":").map(Number)
|
||||||
|
let mult = getMult(mapData[3], game)
|
||||||
|
let mapRank = parseFloat(meta.notes?.[mapData[1] === 10 ? 0 : mapData[1]]?.lv?.toFixed(1) ?? mapData[1] ?? '0')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="map-detail-container" transition:slide>
|
||||||
|
<div class="scores">
|
||||||
|
<div>
|
||||||
|
<img src={`${DATA_HOST}/d/mai2/music/00${mapData[0].toString().padStart(6, '0').substring(2)}.png`} alt="" on:error={coverNotFound} />
|
||||||
|
<div class="info">
|
||||||
|
<div class="firstline">
|
||||||
|
<div class="song-title">{meta.name ?? t("UserHome.UnknownSong")}</div>
|
||||||
|
<span class={`lv level-${mapData[1] === 10 ? 3 : mapData[1]}`}>
|
||||||
|
{ mapRank }
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class={`rank-${getMult(mapData[3], game)[2].toString()[0]}`}>
|
||||||
|
|
||||||
|
<span class="rank-text">{("" + getMult(mapData[3], game)[2]).replace("p", "+")}</span>
|
||||||
|
<span class="rank-num">{(mapData[3] / 10000).toFixed(2)}%</span>
|
||||||
|
</span>
|
||||||
|
{#if game === 'mai2'}
|
||||||
|
<span class:increased={true} class="dx-change">
|
||||||
|
{ (mapData[3] / 1000000 * mapRank * Number(mult[1])).toFixed(0) }
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="sass">
|
||||||
|
|
||||||
|
@import "../vars"
|
||||||
|
$gap: 20px
|
||||||
|
|
||||||
|
.map-detail-container
|
||||||
|
background-color: rgb(35,35,35)
|
||||||
|
border-radius: $border-radius
|
||||||
|
max-width: 250px
|
||||||
|
.scores
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
flex-wrap: wrap
|
||||||
|
gap: $gap
|
||||||
|
|
||||||
|
// Image and song info
|
||||||
|
> div
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
gap: 12px
|
||||||
|
max-width: 100%
|
||||||
|
box-sizing: border-box
|
||||||
|
|
||||||
|
img
|
||||||
|
width: 50px
|
||||||
|
height: 50px
|
||||||
|
border-radius: $border-radius
|
||||||
|
object-fit: cover
|
||||||
|
|
||||||
|
// Song info and score
|
||||||
|
> div.info
|
||||||
|
flex: 1
|
||||||
|
display: flex
|
||||||
|
justify-content: space-between
|
||||||
|
overflow: hidden
|
||||||
|
flex-direction: column
|
||||||
|
|
||||||
|
.firstline
|
||||||
|
display: flex
|
||||||
|
flex-direction: row
|
||||||
|
|
||||||
|
// Limit song name to one line
|
||||||
|
.song-title
|
||||||
|
flex: 1
|
||||||
|
min-width: 0
|
||||||
|
overflow: hidden
|
||||||
|
text-overflow: ellipsis
|
||||||
|
white-space: nowrap
|
||||||
|
|
||||||
|
// Make song score and rank not wrap
|
||||||
|
> div:last-child
|
||||||
|
white-space: nowrap
|
||||||
|
|
||||||
|
@media (max-width: $w-mobile)
|
||||||
|
flex-direction: column
|
||||||
|
gap: 0
|
||||||
|
|
||||||
|
.rank-text
|
||||||
|
text-align: left
|
||||||
|
|
||||||
|
.rank-S
|
||||||
|
// Gold green gradient on text
|
||||||
|
background: $grad-special
|
||||||
|
-webkit-background-clip: text
|
||||||
|
color: transparent
|
||||||
|
|
||||||
|
.rank-A
|
||||||
|
color: #ff8a8a
|
||||||
|
|
||||||
|
.rank-B
|
||||||
|
color: #6ba6ff
|
||||||
|
|
||||||
|
.lv
|
||||||
|
width: 30px
|
||||||
|
text-align: center
|
||||||
|
background: rgba(var(--lv-color), 0.6)
|
||||||
|
padding: 0 6px
|
||||||
|
border-radius: $border-radius
|
||||||
|
margin-right: 6px
|
||||||
|
|
||||||
|
span
|
||||||
|
display: inline-block
|
||||||
|
text-align: left
|
||||||
|
|
||||||
|
// Vertical table-like alignment
|
||||||
|
span.rank-text
|
||||||
|
min-width: 40px
|
||||||
|
span.rank-num
|
||||||
|
min-width: 60px
|
||||||
|
span.dx-change
|
||||||
|
min-width: 50px
|
||||||
|
|
||||||
|
span.increased
|
||||||
|
&:before
|
||||||
|
content: "+"
|
||||||
|
color: $c-good
|
||||||
|
</style>
|
||||||
|
|
|
@ -23,6 +23,7 @@ export const EN_REF_USER = {
|
||||||
'UserHome.ShowRanksDetails': "Click to show details",
|
'UserHome.ShowRanksDetails': "Click to show details",
|
||||||
'UserHome.RankDetail.Title': 'Achievement Details',
|
'UserHome.RankDetail.Title': 'Achievement Details',
|
||||||
'UserHome.RankDetail.Level': "Level",
|
'UserHome.RankDetail.Level': "Level",
|
||||||
|
'UserHome.B50': "B50",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EN_REF_Welcome = {
|
export const EN_REF_Welcome = {
|
||||||
|
|
|
@ -25,6 +25,7 @@ const zhUser: typeof EN_REF_USER = {
|
||||||
'UserHome.ShowRanksDetails': "点击显示评分详细",
|
'UserHome.ShowRanksDetails': "点击显示评分详细",
|
||||||
'UserHome.RankDetail.Title': '评分详细',
|
'UserHome.RankDetail.Title': '评分详细',
|
||||||
'UserHome.RankDetail.Level': "等级",
|
'UserHome.RankDetail.Level': "等级",
|
||||||
|
'UserHome.B50': "B50",
|
||||||
}
|
}
|
||||||
|
|
||||||
const zhWelcome: typeof EN_REF_Welcome = {
|
const zhWelcome: typeof EN_REF_Welcome = {
|
||||||
|
|
|
@ -5,7 +5,10 @@
|
||||||
GenericGameSummary,
|
GenericGameSummary,
|
||||||
MusicMeta,
|
MusicMeta,
|
||||||
TrendEntry,
|
TrendEntry,
|
||||||
AquaNetUser
|
AquaNetUser,
|
||||||
|
|
||||||
|
AllMusic
|
||||||
|
|
||||||
} from "../libs/generalTypes";
|
} from "../libs/generalTypes";
|
||||||
import { DATA_HOST } from "../libs/config";
|
import { DATA_HOST } from "../libs/config";
|
||||||
import 'cal-heatmap/cal-heatmap.css';
|
import 'cal-heatmap/cal-heatmap.css';
|
||||||
|
@ -18,6 +21,7 @@
|
||||||
import Icon from "@iconify/svelte";
|
import Icon from "@iconify/svelte";
|
||||||
import { GAME_TITLE, t } from "../libs/i18n";
|
import { GAME_TITLE, t } from "../libs/i18n";
|
||||||
import RankDetails from "../components/RankDetails.svelte";
|
import RankDetails from "../components/RankDetails.svelte";
|
||||||
|
import MapDetails from "../components/MapDetails.svelte";
|
||||||
|
|
||||||
const TREND_DAYS = 60
|
const TREND_DAYS = 60
|
||||||
|
|
||||||
|
@ -38,11 +42,11 @@
|
||||||
user: GenericGameSummary,
|
user: GenericGameSummary,
|
||||||
trend: TrendEntry[]
|
trend: TrendEntry[]
|
||||||
recent: MusicAndPlay[],
|
recent: MusicAndPlay[],
|
||||||
validGames: [ string, string ][]
|
validGames: [ string, string ][],
|
||||||
} | null
|
} | null
|
||||||
|
|
||||||
|
let allMusics: AllMusic
|
||||||
let showDetailRank = false
|
let showDetailRank = false
|
||||||
|
|
||||||
USER.isLoggedIn() && USER.me().then(u => me = u)
|
USER.isLoggedIn() && USER.me().then(u => me = u)
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,6 +73,7 @@
|
||||||
recent: user.recent.map(it => {return {...music[it.musicId], ...it}}),
|
recent: user.recent.map(it => {return {...music[it.musicId], ...it}}),
|
||||||
validGames: Object.entries(GAME_TITLE).filter(g => games[g[0] as GameName])
|
validGames: Object.entries(GAME_TITLE).filter(g => games[g[0] as GameName])
|
||||||
}
|
}
|
||||||
|
allMusics = music
|
||||||
renderCal(calElement, trend.map(it => {return {date: it.date, value: it.plays}})).then(() => {
|
renderCal(calElement, trend.map(it => {return {date: it.date, value: it.plays}})).then(() => {
|
||||||
// Scroll to the rightmost
|
// Scroll to the rightmost
|
||||||
calElement.scrollLeft = calElement.scrollWidth - calElement.clientWidth
|
calElement.scrollLeft = calElement.scrollWidth - calElement.clientWidth
|
||||||
|
@ -216,6 +221,18 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>B35</h2>
|
||||||
|
<div style="display: flex; flex-wrap: wrap; gap: 12px; item-align: center; align-content: flex-start">
|
||||||
|
{#each d.user.ratingComposition.best35.split(",") as map}
|
||||||
|
<!-- TODO: fix flex: 1 0 -->
|
||||||
|
<div style="width:260px;">
|
||||||
|
<MapDetails g={map} meta={allMusics[map.split(":")[0]]} game={game}/>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="recent">
|
<div class="recent">
|
||||||
<h2>{t('UserHome.RecentScores')}</h2>
|
<h2>{t('UserHome.RecentScores')}</h2>
|
||||||
<div class="scores">
|
<div class="scores">
|
||||||
|
|
Loading…
Reference in New Issue