mirror of
https://github.com/MewoLab/AquaDX.git
synced 2026-02-09 06:07:27 +08:00
[F] Fix build warnings
This commit is contained in:
@@ -1,76 +1,76 @@
|
|||||||
<!-- Svelte 4.2.11 -->
|
<!-- Svelte 4.2.11 -->
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Icon from "@iconify/svelte";
|
import Icon from "@iconify/svelte";
|
||||||
|
|
||||||
export let color: string = '179, 198, 255'
|
export let color: string = '179, 198, 255'
|
||||||
export let icon: string
|
export let icon: string
|
||||||
|
|
||||||
// Manually positioned icons
|
// Manually positioned icons
|
||||||
const iconPos = [
|
const iconPos = [
|
||||||
[1, 0.5, 2],
|
[1, 0.5, 2],
|
||||||
[6, 2, 1.5],
|
[6, 2, 1.5],
|
||||||
[-0.5, 4.5, 1.3],
|
[-0.5, 4.5, 1.3],
|
||||||
[5, -0.5],
|
[5, -0.5],
|
||||||
[3.5, 4.5],
|
[3.5, 4.5],
|
||||||
[9.5, 0.3, 1.2],
|
[9.5, 0.3, 1.2],
|
||||||
[12.5, 2.5, 0.8],
|
[12.5, 2.5, 0.8],
|
||||||
[10, 4.4, 0.8],
|
[10, 4.4, 0.8],
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="action-card" style="--card-color: {color}" on:click role="button" tabindex="0" on:keydown>
|
<div class="action-card" style="--card-color: {color}" on:click role="button" tabindex="0" on:keydown>
|
||||||
<slot/>
|
<slot/>
|
||||||
|
|
||||||
<div class="icons">
|
<div class="icons">
|
||||||
{#each iconPos as [x, y, size], i}
|
{#each iconPos as [x, y, size], i}
|
||||||
<Icon icon={icon} style={`top: ${y}rem; right: ${x}rem; font-size: ${size || 1}em`} />
|
<Icon icon={icon} style={`top: ${y}rem; right: ${x}rem; font-size: ${size || 1}em`} />
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
@use '../vars'
|
@use '../vars'
|
||||||
|
|
||||||
.action-card
|
.action-card
|
||||||
overflow: hidden
|
overflow: hidden
|
||||||
padding: 1rem
|
padding: 1rem
|
||||||
border-radius: vars.$border-radius
|
border-radius: vars.$border-radius
|
||||||
box-shadow: 0 5px 5px 1px vars.$c-shadow
|
box-shadow: 0 5px 5px 1px vars.$c-shadow
|
||||||
transition: all 0.2s ease
|
transition: all 0.2s ease
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
position: relative
|
position: relative
|
||||||
background: linear-gradient(45deg, transparent 20%, rgba(var(--card-color), 0.5) 100%)
|
background: linear-gradient(45deg, transparent 20%, rgba(var(--card-color), 0.5) 100%)
|
||||||
outline: 1px solid transparent
|
outline: 1px solid transparent
|
||||||
filter: drop-shadow(0 0 12px rgba(var(--card-color), 0))
|
filter: drop-shadow(0 0 12px rgba(var(--card-color), 0))
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
box-shadow: 0 0 0.5rem 0.2rem vars.$c-shadow
|
box-shadow: 0 0 0.5rem 0.2rem vars.$c-shadow
|
||||||
transform: translateY(-3px)
|
transform: translateY(-3px)
|
||||||
|
|
||||||
// Drop shadow glow
|
// Drop shadow glow
|
||||||
filter: drop-shadow(0 0 12px rgba(var(--card-color), 0.5))
|
filter: drop-shadow(0 0 12px rgba(var(--card-color), 0.5))
|
||||||
outline-color: rgba(var(--card-color), 0.5)
|
outline-color: rgba(var(--card-color), 0.5)
|
||||||
|
|
||||||
span
|
:global(span)
|
||||||
font-size: 1.2rem
|
font-size: 1.2rem
|
||||||
display: block
|
display: block
|
||||||
margin-bottom: 0.5rem
|
margin-bottom: 0.5rem
|
||||||
|
|
||||||
.icons
|
.icons
|
||||||
position: absolute
|
position: absolute
|
||||||
inset: 0
|
inset: 0
|
||||||
color: rgba(var(--card-color), 0.5)
|
color: rgba(var(--card-color), 0.5)
|
||||||
font-size: 2rem
|
font-size: 2rem
|
||||||
transition: all 0.2s ease
|
transition: all 0.2s ease
|
||||||
z-index: -1
|
z-index: -1
|
||||||
mask-image: linear-gradient(45deg, transparent 30%, rgba(255,255,255,0.5) 70%, white 100%)
|
mask-image: linear-gradient(45deg, transparent 30%, rgba(255,255,255,0.5) 70%, white 100%)
|
||||||
opacity: 0.8
|
opacity: 0.8
|
||||||
|
|
||||||
@media (max-width: vars.$w-mobile)
|
@media (max-width: vars.$w-mobile)
|
||||||
opacity: 0.6
|
opacity: 0.6
|
||||||
|
|
||||||
:global(> svg)
|
:global(> svg)
|
||||||
position: absolute
|
position: absolute
|
||||||
rotate: 20deg
|
rotate: 20deg
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
filter: drop-shadow(0 0 12px rgba(var(--card-color), 0.5))
|
filter: drop-shadow(0 0 12px rgba(var(--card-color), 0.5))
|
||||||
outline-color: rgba(var(--card-color), 0.5)
|
outline-color: rgba(var(--card-color), 0.5)
|
||||||
|
|
||||||
span
|
:global(span)
|
||||||
font-size: 1.2rem
|
font-size: 1.2rem
|
||||||
display: block
|
display: block
|
||||||
margin-bottom: 0.5rem
|
margin-bottom: 0.5rem
|
||||||
|
|||||||
@@ -26,16 +26,10 @@
|
|||||||
|
|
||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
@use "../vars"
|
@use "../vars"
|
||||||
|
|
||||||
.rating-composition
|
.rating-composition
|
||||||
display: grid
|
display: grid
|
||||||
// 3 columns
|
// 3 columns
|
||||||
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr))
|
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr))
|
||||||
gap: vars.$gap
|
gap: vars.$gap
|
||||||
|
|
||||||
.rating-composition-2
|
|
||||||
display: grid
|
|
||||||
// 2 columns
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(290px, 1fr))
|
|
||||||
gap: vars.$gap
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -434,37 +434,10 @@
|
|||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
@use "../vars"
|
@use "../vars"
|
||||||
|
|
||||||
.outer-container
|
|
||||||
display: flex
|
|
||||||
flex-direction: column
|
|
||||||
gap: 1rem
|
|
||||||
|
|
||||||
nav
|
|
||||||
display: flex
|
|
||||||
gap: 1rem
|
|
||||||
|
|
||||||
div
|
|
||||||
padding: 0.5rem 1rem
|
|
||||||
border-radius: 0.4rem
|
|
||||||
cursor: pointer
|
|
||||||
transition: background-color 0.2s
|
|
||||||
font-weight: 500
|
|
||||||
|
|
||||||
&.active
|
|
||||||
color: vars.$c-main
|
|
||||||
|
|
||||||
img
|
img
|
||||||
width: 100%
|
width: 100%
|
||||||
height: auto
|
height: auto
|
||||||
|
|
||||||
.container
|
|
||||||
display: flex
|
|
||||||
flex-direction: row
|
|
||||||
gap: 3rem
|
|
||||||
|
|
||||||
@media (max-width: vars.$w-max)
|
|
||||||
flex-direction: column
|
|
||||||
|
|
||||||
.preview
|
.preview
|
||||||
display: flex
|
display: flex
|
||||||
flex-direction: column
|
flex-direction: column
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<div>Error: {error}</div>
|
<div>Error: {error}</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="user-card">
|
<div class="user-card">
|
||||||
<img use:pfp={data.aquaUser} alt="Profile Picture" />
|
<img use:pfp={data.aquaUser} alt="Profile" />
|
||||||
<div class="details">
|
<div class="details">
|
||||||
<span class="in-game-name">{data.name}</span>
|
<span class="in-game-name">{data.name}</span>
|
||||||
<span class="username">@{username}</span>
|
<span class="username">@{username}</span>
|
||||||
|
|||||||
@@ -1,98 +1,98 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fade } from "svelte/transition";
|
import { fade } from "svelte/transition";
|
||||||
import LinkCard from "./Home/LinkCard.svelte";
|
import LinkCard from "./Home/LinkCard.svelte";
|
||||||
import SetupInstructions from "./Home/SetupInstructions.svelte";
|
import SetupInstructions from "./Home/SetupInstructions.svelte";
|
||||||
import { DISCORD_INVITE, FADE_IN, FADE_OUT } from "../libs/config";
|
import { DISCORD_INVITE, FADE_IN, FADE_OUT } from "../libs/config";
|
||||||
import { USER } from "../libs/sdk.js";
|
import { USER } from "../libs/sdk.js";
|
||||||
import type { AquaNetUser } from "../libs/generalTypes";
|
import type { AquaNetUser } from "../libs/generalTypes";
|
||||||
import StatusOverlays from "../components/StatusOverlays.svelte";
|
import StatusOverlays from "../components/StatusOverlays.svelte";
|
||||||
import ActionCard from "../components/ActionCard.svelte";
|
import ActionCard from "../components/ActionCard.svelte";
|
||||||
import { t } from "../libs/i18n";
|
import { t } from "../libs/i18n";
|
||||||
import ImportDataAction from "./Home/ImportDataAction.svelte";
|
import ImportDataAction from "./Home/ImportDataAction.svelte";
|
||||||
import Communities from "./Home/Communities.svelte";
|
import Communities from "./Home/Communities.svelte";
|
||||||
|
|
||||||
USER.ensureLoggedIn();
|
USER.ensureLoggedIn();
|
||||||
|
|
||||||
let me: AquaNetUser
|
let me: AquaNetUser
|
||||||
let error = ""
|
let error = ""
|
||||||
|
|
||||||
let tab = 0;
|
let tab = 0;
|
||||||
let tabs = [t('home.nav.portal'), t('home.nav.link-card'), t('home.nav.game-setup')]
|
let tabs = [t('home.nav.portal'), t('home.nav.link-card'), t('home.nav.game-setup')]
|
||||||
|
|
||||||
USER.me().then((m) => me = m).catch(e => error = e.message)
|
USER.me().then((m) => me = m).catch(e => error = e.message)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main class="content">
|
<main class="content">
|
||||||
<!-- <h2 class="outer-title"> </h2>-->
|
<!-- <h2 class="outer-title"> </h2>-->
|
||||||
<nav class="tabs">
|
<nav class="tabs">
|
||||||
{#each tabs as t, i}
|
{#each tabs as t, i}
|
||||||
<div class="clickable"
|
<div class="clickable"
|
||||||
class:active={tab === i}
|
class:active={tab === i}
|
||||||
on:click={() => tab = i}
|
on:click={() => tab = i}
|
||||||
on:keydown={(e) => e.key === "Enter" && (tab = i)}
|
on:keydown={(e) => e.key === "Enter" && (tab = i)}
|
||||||
role="button" tabindex={i}>{t}
|
role="button" tabindex={i}>{t}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{#if tab === 0}
|
{#if tab === 0}
|
||||||
<div out:fade={FADE_OUT} in:fade={FADE_IN} class="action-cards">
|
<div out:fade={FADE_OUT} in:fade={FADE_IN} class="action-cards">
|
||||||
<ActionCard color="255, 192, 203" icon="solar:card-bold-duotone" on:click={() => tab = 1}>
|
<ActionCard color="255, 192, 203" icon="solar:card-bold-duotone" on:click={() => tab = 1}>
|
||||||
{#if me && me.cards.length > 1}
|
{#if me && me.cards.length > 1}
|
||||||
<h3>{t('home.manage-cards')}</h3>
|
<h3>{t('home.manage-cards')}</h3>
|
||||||
<span>{t('home.manage-cards-description')}</span>
|
<span>{t('home.manage-cards-description')}</span>
|
||||||
{:else if me}
|
{:else if me}
|
||||||
<h3>{t('home.link-card')}</h3>
|
<h3>{t('home.link-card')}</h3>
|
||||||
<span>{t('home.link-cards-description')}</span>
|
<span>{t('home.link-cards-description')}</span>
|
||||||
{/if}
|
{/if}
|
||||||
</ActionCard>
|
</ActionCard>
|
||||||
|
|
||||||
<ActionCard color="82, 93, 233" icon="fluent:chat-12-filled" on:click={() => tab = 3}>
|
<ActionCard color="82, 93, 233" icon="fluent:chat-12-filled" on:click={() => tab = 3}>
|
||||||
<h3>{t('home.join-community')}</h3>
|
<h3>{t('home.join-community')}</h3>
|
||||||
<span>{t('home.join-community-description')}</span>
|
<span>{t('home.join-community-description')}</span>
|
||||||
</ActionCard>
|
</ActionCard>
|
||||||
|
|
||||||
<ActionCard on:click={() => tab = 2} icon="uil:link-alt">
|
<ActionCard on:click={() => tab = 2} icon="uil:link-alt">
|
||||||
<h3>{t('home.setup')}</h3>
|
<h3>{t('home.setup')}</h3>
|
||||||
<span>{t('home.setup-description')}</span>
|
<span>{t('home.setup-description')}</span>
|
||||||
</ActionCard>
|
</ActionCard>
|
||||||
|
|
||||||
<ImportDataAction/>
|
<ImportDataAction/>
|
||||||
</div>
|
</div>
|
||||||
{:else if tab === 1}
|
{:else if tab === 1}
|
||||||
<div out:fade={FADE_OUT} in:fade={FADE_IN}>
|
<div out:fade={FADE_OUT} in:fade={FADE_IN}>
|
||||||
<LinkCard/>
|
<LinkCard/>
|
||||||
</div>
|
</div>
|
||||||
{:else if tab === 2}
|
{:else if tab === 2}
|
||||||
<div out:fade={FADE_OUT} in:fade={FADE_IN}>
|
<div out:fade={FADE_OUT} in:fade={FADE_IN}>
|
||||||
<SetupInstructions/>
|
<SetupInstructions/>
|
||||||
</div>
|
</div>
|
||||||
{:else if tab === 3}
|
{:else if tab === 3}
|
||||||
<div out:fade={FADE_OUT} in:fade={FADE_IN}>
|
<div out:fade={FADE_OUT} in:fade={FADE_IN}>
|
||||||
<Communities/>
|
<Communities/>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<StatusOverlays {error} loading={!me}/>
|
<StatusOverlays {error} loading={!me}/>
|
||||||
|
|
||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
@use "../vars"
|
@use "../vars"
|
||||||
|
|
||||||
.tabs
|
.tabs
|
||||||
display: flex
|
display: flex
|
||||||
gap: 1rem
|
gap: 1rem
|
||||||
|
|
||||||
div
|
div
|
||||||
&.active
|
&.active
|
||||||
color: vars.$c-main
|
color: vars.$c-main
|
||||||
|
|
||||||
h3
|
h3
|
||||||
font-size: 1.3rem
|
font-size: 1.3rem
|
||||||
margin: 0
|
margin: 0
|
||||||
|
|
||||||
.action-cards
|
.action-cards
|
||||||
display: flex
|
display: flex
|
||||||
flex-direction: column
|
flex-direction: column
|
||||||
gap: 1rem
|
gap: 1rem
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,375 +1,375 @@
|
|||||||
<!-- Svelte 4.2.11 -->
|
<!-- Svelte 4.2.11 -->
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fade, slide } from "svelte/transition"
|
import { fade, slide } from "svelte/transition"
|
||||||
import type { Card, CardSummary, CardSummaryGame, ConfirmProps, AquaNetUser } from "../../libs/generalTypes";
|
import type { Card, CardSummary, CardSummaryGame, ConfirmProps, AquaNetUser } from "../../libs/generalTypes";
|
||||||
import { CARD, USER } from "../../libs/sdk";
|
import { CARD, USER } from "../../libs/sdk";
|
||||||
import moment from "moment"
|
import moment from "moment"
|
||||||
import Icon from "@iconify/svelte";
|
import Icon from "@iconify/svelte";
|
||||||
import StatusOverlays from "../../components/StatusOverlays.svelte";
|
import StatusOverlays from "../../components/StatusOverlays.svelte";
|
||||||
import { t } from "../../libs/i18n";
|
import { t } from "../../libs/i18n";
|
||||||
|
|
||||||
// State
|
// State
|
||||||
let state: 'ready' | 'linking-AC' | 'linking-SN' | 'loading' = "loading"
|
let state: 'ready' | 'linking-AC' | 'linking-SN' | 'loading' = "loading"
|
||||||
let showConfirm: ConfirmProps | null = null
|
let showConfirm: ConfirmProps | null = null
|
||||||
|
|
||||||
let error: string = ""
|
let error: string = ""
|
||||||
let me: AquaNetUser | null = null
|
let me: AquaNetUser | null = null
|
||||||
let accountCardSummary: CardSummary | null = null
|
let accountCardSummary: CardSummary | null = null
|
||||||
|
|
||||||
// Fetch data for current user
|
// Fetch data for current user
|
||||||
const updateMe = () => USER.me().then(m => {
|
const updateMe = () => USER.me().then(m => {
|
||||||
me = m
|
me = m
|
||||||
m.cards.sort((a, b) => a.registerTime < b.registerTime ? 1 : -1)
|
m.cards.sort((a, b) => a.registerTime < b.registerTime ? 1 : -1)
|
||||||
CARD.summary(m.ghostCard.luid).then(s => accountCardSummary = s.summary)
|
CARD.summary(m.ghostCard.luid).then(s => accountCardSummary = s.summary)
|
||||||
|
|
||||||
// Always put the ghost card at the top
|
// Always put the ghost card at the top
|
||||||
m.cards.sort((a, b) => a.isGhost ? -1 : 1)
|
m.cards.sort((a, b) => a.isGhost ? -1 : 1)
|
||||||
state = "ready"
|
state = "ready"
|
||||||
}).catch(e => error = e.message)
|
}).catch(e => error = e.message)
|
||||||
updateMe()
|
updateMe()
|
||||||
|
|
||||||
// Data conflict overlay
|
// Data conflict overlay
|
||||||
let conflictCardID: string = ""
|
let conflictCardID: string = ""
|
||||||
let conflictSummary: CardSummary | null = null
|
let conflictSummary: CardSummary | null = null
|
||||||
let conflictGame: string = ""
|
let conflictGame: string = ""
|
||||||
let conflictNew: CardSummaryGame | null = null
|
let conflictNew: CardSummaryGame | null = null
|
||||||
let conflictOld: CardSummaryGame | null = null
|
let conflictOld: CardSummaryGame | null = null
|
||||||
let conflictToMigrate: string[] = []
|
let conflictToMigrate: string[] = []
|
||||||
|
|
||||||
function setError(msg: string, type: 'AC' | 'SN') {
|
function setError(msg: string, type: 'AC' | 'SN') {
|
||||||
type === 'AC' ? errorAC = msg : errorSN = msg
|
type === 'AC' ? errorAC = msg : errorSN = msg
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doLink(id: string, migrate: string) {
|
async function doLink(id: string, migrate: string) {
|
||||||
await CARD.link({cardId: id, migrate})
|
await CARD.link({cardId: id, migrate})
|
||||||
await updateMe()
|
await updateMe()
|
||||||
state = "ready"
|
state = "ready"
|
||||||
}
|
}
|
||||||
|
|
||||||
async function link(type: 'AC' | 'SN') {
|
async function link(type: 'AC' | 'SN') {
|
||||||
if (state !== 'ready' || accountCardSummary === null) return
|
if (state !== 'ready' || accountCardSummary === null) return
|
||||||
state = "linking-" + type
|
state = "linking-" + type
|
||||||
const id = type === 'AC' ? inputAC : inputSN
|
const id = type === 'AC' ? inputAC : inputSN
|
||||||
|
|
||||||
console.log("linking card", id)
|
console.log("linking card", id)
|
||||||
|
|
||||||
// Check if this card is already linked in the account
|
// Check if this card is already linked in the account
|
||||||
if (me?.cards?.some(c => formatLUID(c.luid, c.isGhost).toLowerCase() === id.toLowerCase())) {
|
if (me?.cards?.some(c => formatLUID(c.luid, c.isGhost).toLowerCase() === id.toLowerCase())) {
|
||||||
setError(t('home.linkcard.linked-own'), type)
|
setError(t('home.linkcard.linked-own'), type)
|
||||||
state = "ready"
|
state = "ready"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// First, lookup the card summary
|
// First, lookup the card summary
|
||||||
const card = (await CARD.summary(id).catch(e => {
|
const card = (await CARD.summary(id).catch(e => {
|
||||||
// If card is not found, create a card and link it
|
// If card is not found, create a card and link it
|
||||||
if (e.message === t('home.linkcard.notfound')) {
|
if (e.message === t('home.linkcard.notfound')) {
|
||||||
doLink(id, "")
|
doLink(id, "")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setError(e.message, type)
|
setError(e.message, type)
|
||||||
state = "ready"
|
state = "ready"
|
||||||
return
|
return
|
||||||
}))!
|
}))!
|
||||||
const summary = card.summary
|
const summary = card.summary
|
||||||
|
|
||||||
// Check if it's already linked
|
// Check if it's already linked
|
||||||
if (card.card.linked) {
|
if (card.card.linked) {
|
||||||
setError(t('home.linkcard.linked-another'), type)
|
setError(t('home.linkcard.linked-another'), type)
|
||||||
state = "ready"
|
state = "ready"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If all games in summary are null or doesn't conflict with the ghost card,
|
// If all games in summary are null or doesn't conflict with the ghost card,
|
||||||
// we can link the card directly
|
// we can link the card directly
|
||||||
if (Object.keys(summary).every(k => summary[k as keyof CardSummary] === null
|
if (Object.keys(summary).every(k => summary[k as keyof CardSummary] === null
|
||||||
|| accountCardSummary!![k as keyof CardSummary] === null)) {
|
|| accountCardSummary!![k as keyof CardSummary] === null)) {
|
||||||
console.log("linking card directly")
|
console.log("linking card directly")
|
||||||
await doLink(id, Object.keys(summary).filter(k => summary[k as keyof CardSummary] !== null).join(","))
|
await doLink(id, Object.keys(summary).filter(k => summary[k as keyof CardSummary] !== null).join(","))
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each conflicting game, ask the user if they want to migrate the data
|
// For each conflicting game, ask the user if they want to migrate the data
|
||||||
else {
|
else {
|
||||||
conflictSummary = summary
|
conflictSummary = summary
|
||||||
conflictCardID = id
|
conflictCardID = id
|
||||||
await linkConflictContinue(null)
|
await linkConflictContinue(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function linkConflictContinue(choose: "old" | "new" | null) {
|
async function linkConflictContinue(choose: "old" | "new" | null) {
|
||||||
if (accountCardSummary === null || conflictSummary === null) return
|
if (accountCardSummary === null || conflictSummary === null) return
|
||||||
console.log("linking card with migration")
|
console.log("linking card with migration")
|
||||||
|
|
||||||
if (choose) {
|
if (choose) {
|
||||||
// If old is chosen, nothing needs to be migrated
|
// If old is chosen, nothing needs to be migrated
|
||||||
// If new is chosen, we need to migrate the data
|
// If new is chosen, we need to migrate the data
|
||||||
if (choose === "new") {
|
if (choose === "new") {
|
||||||
conflictToMigrate.push(conflictGame)
|
conflictToMigrate.push(conflictGame)
|
||||||
}
|
}
|
||||||
// Continue to the next card
|
// Continue to the next card
|
||||||
conflictSummary[conflictGame as keyof CardSummary] = null
|
conflictSummary[conflictGame as keyof CardSummary] = null
|
||||||
}
|
}
|
||||||
|
|
||||||
let isConflict = false
|
let isConflict = false
|
||||||
for (const k in conflictSummary) {
|
for (const k in conflictSummary) {
|
||||||
conflictNew = conflictSummary[k as keyof CardSummary]
|
conflictNew = conflictSummary[k as keyof CardSummary]
|
||||||
conflictOld = accountCardSummary[k as keyof CardSummary]
|
conflictOld = accountCardSummary[k as keyof CardSummary]
|
||||||
conflictGame = k
|
conflictGame = k
|
||||||
if (!conflictNew || !conflictOld) continue
|
if (!conflictNew || !conflictOld) continue
|
||||||
|
|
||||||
isConflict = true
|
isConflict = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are no longer conflicts, we can link the card
|
// If there are no longer conflicts, we can link the card
|
||||||
if (!isConflict) {
|
if (!isConflict) {
|
||||||
await doLink(conflictCardID, conflictToMigrate.join(","))
|
await doLink(conflictCardID, conflictToMigrate.join(","))
|
||||||
|
|
||||||
// Reset the conflict state
|
// Reset the conflict state
|
||||||
linkConflictCancel()
|
linkConflictCancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function linkConflictCancel() {
|
function linkConflictCancel() {
|
||||||
state = "ready"
|
state = "ready"
|
||||||
conflictSummary = null
|
conflictSummary = null
|
||||||
conflictCardID = ""
|
conflictCardID = ""
|
||||||
conflictGame = ""
|
conflictGame = ""
|
||||||
conflictNew = null
|
conflictNew = null
|
||||||
conflictOld = null
|
conflictOld = null
|
||||||
conflictToMigrate = []
|
conflictToMigrate = []
|
||||||
}
|
}
|
||||||
|
|
||||||
async function unlink(card: Card) {
|
async function unlink(card: Card) {
|
||||||
showConfirm = {
|
showConfirm = {
|
||||||
title: t('home.linkcard.unlink'),
|
title: t('home.linkcard.unlink'),
|
||||||
message: t('home.linkcard.unlink-notice'),
|
message: t('home.linkcard.unlink-notice'),
|
||||||
confirm: async () => {
|
confirm: async () => {
|
||||||
await CARD.unlink(card.luid)
|
await CARD.unlink(card.luid)
|
||||||
await updateMe()
|
await updateMe()
|
||||||
showConfirm = null
|
showConfirm = null
|
||||||
},
|
},
|
||||||
cancel: () => showConfirm = null,
|
cancel: () => showConfirm = null,
|
||||||
dangerous: true
|
dangerous: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access code input
|
// Access code input
|
||||||
const inputACRegex = /^(\d{4} ){0,4}\d{0,4}$/
|
const inputACRegex = /^(\d{4} ){0,4}\d{0,4}$/
|
||||||
let inputAC = ""
|
let inputAC = ""
|
||||||
let errorAC = ""
|
let errorAC = ""
|
||||||
|
|
||||||
function inputACChange(e: any) {
|
function inputACChange(e: any) {
|
||||||
e = e as InputEvent
|
e = e as InputEvent
|
||||||
// Add spaces to the input
|
// Add spaces to the input
|
||||||
const old = inputAC
|
const old = inputAC
|
||||||
if (e.inputType === "insertText" && inputAC.length % 5 === 4 && inputAC.length < 24)
|
if (e.inputType === "insertText" && inputAC.length % 5 === 4 && inputAC.length < 24)
|
||||||
inputAC += " "
|
inputAC += " "
|
||||||
inputAC = inputAC.slice(0, 24)
|
inputAC = inputAC.slice(0, 24)
|
||||||
if (inputAC !== old) errorAC = ""
|
if (inputAC !== old) errorAC = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serial number input
|
// Serial number input
|
||||||
const inputSNRegex = /^([0-9A-Fa-f]{0,2}:){0,7}[0-9A-Fa-f]{0,2}$/
|
const inputSNRegex = /^([0-9A-Fa-f]{0,2}:){0,7}[0-9A-Fa-f]{0,2}$/
|
||||||
let inputSN = ""
|
let inputSN = ""
|
||||||
let errorSN = ""
|
let errorSN = ""
|
||||||
|
|
||||||
function inputSNChange(e: any) {
|
function inputSNChange(e: any) {
|
||||||
e = e as InputEvent
|
e = e as InputEvent
|
||||||
// Add colons to the input
|
// Add colons to the input
|
||||||
const old = inputSN
|
const old = inputSN
|
||||||
if (e.inputType === "insertText" && inputSN.length % 3 === 2 && inputSN.length < 23)
|
if (e.inputType === "insertText" && inputSN.length % 3 === 2 && inputSN.length < 23)
|
||||||
inputSN += ":"
|
inputSN += ":"
|
||||||
inputSN = inputSN.toUpperCase().slice(0, 23)
|
inputSN = inputSN.toUpperCase().slice(0, 23)
|
||||||
if (inputSN !== old) errorSN = ""
|
if (inputSN !== old) errorSN = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatLUID(luid: string, ghost: boolean = false) {
|
function formatLUID(luid: string, ghost: boolean = false) {
|
||||||
if (ghost) return luid.slice(0, 6) + " " + (luid.slice(6).match(/.{4}/g)?.join(" ") ?? "")
|
if (ghost) return luid.slice(0, 6) + " " + (luid.slice(6).match(/.{4}/g)?.join(" ") ?? "")
|
||||||
switch (cardType(luid)) {
|
switch (cardType(luid)) {
|
||||||
case "Felica SN":
|
case "Felica SN":
|
||||||
return BigInt(luid).toString(16).toUpperCase().padStart(16, "0").match(/.{1,2}/g)!.join(":")
|
return BigInt(luid).toString(16).toUpperCase().padStart(16, "0").match(/.{1,2}/g)!.join(":")
|
||||||
case "Access Code":
|
case "Access Code":
|
||||||
return luid.match(/.{4}/g)!.join(" ")
|
return luid.match(/.{4}/g)!.join(" ")
|
||||||
default:
|
default:
|
||||||
return luid
|
return luid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function cardType(luid: string) {
|
function cardType(luid: string) {
|
||||||
if (luid.startsWith("00")) return "Felica SN"
|
if (luid.startsWith("00")) return "Felica SN"
|
||||||
if (luid.length === 20) return "Access Code"
|
if (luid.length === 20) return "Access Code"
|
||||||
if (luid.includes(":")) return "Felica SN"
|
if (luid.includes(":")) return "Felica SN"
|
||||||
if (luid.includes(" ")) return "Access Code"
|
if (luid.includes(" ")) return "Access Code"
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
function isInput(e: KeyboardEvent) {
|
function isInput(e: KeyboardEvent) {
|
||||||
return e.key.length === 1 && !e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey
|
return e.key.length === 1 && !e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="link-card">
|
<div class="link-card">
|
||||||
<h2>{t('home.linkcard.cards')}</h2>
|
<h2>{t('home.linkcard.cards')}</h2>
|
||||||
<p>{t('home.linkcard.description')}:</p>
|
<p>{t('home.linkcard.description')}:</p>
|
||||||
|
|
||||||
{#if me}
|
{#if me}
|
||||||
<div class="existing-cards" transition:slide>
|
<div class="existing-cards" transition:slide>
|
||||||
{#each me.cards as card (card.luid)}
|
{#each me.cards as card (card.luid)}
|
||||||
<div class:ghost={card.isGhost} class='existing card' transition:fade|global>
|
<div class:ghost={card.isGhost} class='existing card' transition:fade|global>
|
||||||
<span class="type">{card.isGhost ? t('home.linkcard.account-card') : cardType(card.luid)}</span>
|
<span class="type">{card.isGhost ? t('home.linkcard.account-card') : cardType(card.luid)}</span>
|
||||||
<span class="register">{t('home.linkcard.registered')}: {moment(card.registerTime).format("YYYY MMM DD")}</span>
|
<span class="register">{t('home.linkcard.registered')}: {moment(card.registerTime).format("YYYY MMM DD")}</span>
|
||||||
<span class="last">{t('home.linkcard.lastused')}: {moment(card.accessTime).format("YYYY MMM DD")}</span>
|
<span class="last">{t('home.linkcard.lastused')}: {moment(card.accessTime).format("YYYY MMM DD")}</span>
|
||||||
<div/>
|
<div></div>
|
||||||
<span class="id">{formatLUID(card.luid, card.isGhost)}</span>
|
<span class="id">{formatLUID(card.luid, card.isGhost)}</span>
|
||||||
{#if !card.isGhost}
|
{#if !card.isGhost}
|
||||||
<button class="icon error" on:click={() => unlink(card)}><Icon icon="tabler:trash-x-filled"/></button>
|
<button class="icon error" on:click={() => unlink(card)}><Icon icon="tabler:trash-x-filled"/></button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<h2>{t('home.link-card')}</h2>
|
<h2>{t('home.link-card')}</h2>
|
||||||
<p>{t('home.linkcard.enter-info')}:</p>
|
<p>{t('home.linkcard.enter-info')}:</p>
|
||||||
{#if !inputSN}
|
{#if !inputSN}
|
||||||
<div out:slide={{ duration: 250 }}>
|
<div out:slide={{ duration: 250 }}>
|
||||||
<p>{t('home.linkcard.access-code')}</p>
|
<p>{t('home.linkcard.access-code')}</p>
|
||||||
<label>
|
<label>
|
||||||
<!-- DO NOT change the order of bind:value and on:input. Their order determines the order of reactivity -->
|
<!-- DO NOT change the order of bind:value and on:input. Their order determines the order of reactivity -->
|
||||||
<input placeholder="e.g. 5200 1234 5678 9012 3456"
|
<input placeholder="e.g. 5200 1234 5678 9012 3456"
|
||||||
on:keydown={(e) => {
|
on:keydown={(e) => {
|
||||||
e.key === "Enter" && link('AC')
|
e.key === "Enter" && link('AC')
|
||||||
// Ensure key is numeric
|
// Ensure key is numeric
|
||||||
if (isInput(e) && !/[\d ]/.test(e.key)) e.preventDefault()
|
if (isInput(e) && !/[\d ]/.test(e.key)) e.preventDefault()
|
||||||
}}
|
}}
|
||||||
bind:value={inputAC}
|
bind:value={inputAC}
|
||||||
on:input={inputACChange}
|
on:input={inputACChange}
|
||||||
class:error={inputAC && (!inputACRegex.test(inputAC) || errorAC)}>
|
class:error={inputAC && (!inputACRegex.test(inputAC) || errorAC)}>
|
||||||
{#if inputAC.length > 0}
|
{#if inputAC.length > 0}
|
||||||
<button transition:slide={{axis: 'x'}} on:click={() => {link('AC');inputAC=''}}>{t('home.linkcard.link')}</button>
|
<button transition:slide={{axis: 'x'}} on:click={() => {link('AC');inputAC=''}}>{t('home.linkcard.link')}</button>
|
||||||
{/if}
|
{/if}
|
||||||
</label>
|
</label>
|
||||||
{#if errorAC}
|
{#if errorAC}
|
||||||
<p class="error" transition:slide>{errorAC}</p>
|
<p class="error" transition:slide>{errorAC}</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if !inputAC}
|
{#if !inputAC}
|
||||||
<div out:slide={{ duration: 250 }}>
|
<div out:slide={{ duration: 250 }}>
|
||||||
<p>{t('home.linkcard.enter-sn1')}
|
<p>{t('home.linkcard.enter-sn1')}
|
||||||
(<a href="https://play.google.com/store/apps/details?id=com.wakdev.wdnfc">Android</a> /
|
(<a href="https://play.google.com/store/apps/details?id=com.wakdev.wdnfc">Android</a> /
|
||||||
<a href="https://apps.apple.com/us/app/nfc-tools/id1252962749">Apple</a>)
|
<a href="https://apps.apple.com/us/app/nfc-tools/id1252962749">Apple</a>)
|
||||||
{t('home.linkcard.enter-sn2')}
|
{t('home.linkcard.enter-sn2')}
|
||||||
</p>
|
</p>
|
||||||
<label>
|
<label>
|
||||||
<input placeholder="e.g. 01:2E:1A:2B:3C:4D:5E:6F"
|
<input placeholder="e.g. 01:2E:1A:2B:3C:4D:5E:6F"
|
||||||
on:keydown={(e) => {
|
on:keydown={(e) => {
|
||||||
e.key === "Enter" && link('SN')
|
e.key === "Enter" && link('SN')
|
||||||
// Ensure key is hex or colon
|
// Ensure key is hex or colon
|
||||||
if (isInput(e) && !/[0-9A-Fa-f:]/.test(e.key)) e.preventDefault()
|
if (isInput(e) && !/[0-9A-Fa-f:]/.test(e.key)) e.preventDefault()
|
||||||
}}
|
}}
|
||||||
bind:value={inputSN}
|
bind:value={inputSN}
|
||||||
on:input={inputSNChange}
|
on:input={inputSNChange}
|
||||||
class:error={inputSN && (!inputSNRegex.test(inputSN) || errorSN)}>
|
class:error={inputSN && (!inputSNRegex.test(inputSN) || errorSN)}>
|
||||||
{#if inputSN.length > 0}
|
{#if inputSN.length > 0}
|
||||||
<button transition:slide={{axis: 'x'}} on:click={() => {link('SN'); inputSN = ''}}>{t('home.linkcard.link')}</button>
|
<button transition:slide={{axis: 'x'}} on:click={() => {link('SN'); inputSN = ''}}>{t('home.linkcard.link')}</button>
|
||||||
{/if}
|
{/if}
|
||||||
</label>
|
</label>
|
||||||
{#if errorSN}
|
{#if errorSN}
|
||||||
<p class="error" transition:slide>{errorSN}</p>
|
<p class="error" transition:slide>{errorSN}</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if conflictOld && conflictNew && me}
|
{#if conflictOld && conflictNew && me}
|
||||||
<div class="overlay" transition:fade>
|
<div class="overlay" transition:fade>
|
||||||
<div>
|
<div>
|
||||||
<h2>{t('home.linkcard.data-conflict')}</h2>
|
<h2>{t('home.linkcard.data-conflict')}</h2>
|
||||||
<p></p>
|
<p></p>
|
||||||
<div class="conflict-cards">
|
<div class="conflict-cards">
|
||||||
<div class="old card clickable" on:click={() => linkConflictContinue('old')}
|
<div class="old card clickable" on:click={() => linkConflictContinue('old')}
|
||||||
role="button" tabindex="0" on:keydown={e => e.key === "Enter" && linkConflictContinue('old')}>
|
role="button" tabindex="0" on:keydown={e => e.key === "Enter" && linkConflictContinue('old')}>
|
||||||
<span class="type">{t('home.linkcard.account-card')}</span>
|
<span class="type">{t('home.linkcard.account-card')}</span>
|
||||||
<span>{t('home.linkcard.name')}: {conflictOld.name}</span>
|
<span>{t('home.linkcard.name')}: {conflictOld.name}</span>
|
||||||
<span>{t('home.linkcard.rating')}: {conflictOld.rating}</span>
|
<span>{t('home.linkcard.rating')}: {conflictOld.rating}</span>
|
||||||
<span>{t('home.linkcard.last-login')}: {moment(conflictOld.lastLogin).format("YYYY MMM DD")}</span>
|
<span>{t('home.linkcard.last-login')}: {moment(conflictOld.lastLogin).format("YYYY MMM DD")}</span>
|
||||||
<span class="id">{formatLUID(me.ghostCard.luid, true)}</span>
|
<span class="id">{formatLUID(me.ghostCard.luid, true)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="new card clickable" on:click={() => linkConflictContinue('new')}
|
<div class="new card clickable" on:click={() => linkConflictContinue('new')}
|
||||||
role="button" tabindex="0" on:keydown={e => e.key === "Enter" && linkConflictContinue('new')}>
|
role="button" tabindex="0" on:keydown={e => e.key === "Enter" && linkConflictContinue('new')}>
|
||||||
<span class="type">{cardType(conflictCardID)}</span>
|
<span class="type">{cardType(conflictCardID)}</span>
|
||||||
<span>{t('home.linkcard.name')}: {conflictNew.name}</span>
|
<span>{t('home.linkcard.name')}: {conflictNew.name}</span>
|
||||||
<span>{t('home.linkcard.rating')}: {conflictNew.rating}</span>
|
<span>{t('home.linkcard.rating')}: {conflictNew.rating}</span>
|
||||||
<span>{t('home.linkcard.last-login')}: {moment(conflictNew.lastLogin).format("YYYY MMM DD")}</span>
|
<span>{t('home.linkcard.last-login')}: {moment(conflictNew.lastLogin).format("YYYY MMM DD")}</span>
|
||||||
<span class="id">{conflictCardID}</span>
|
<span class="id">{conflictCardID}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="error" on:click={linkConflictCancel}>{t('action.cancel')}</button>
|
<button class="error" on:click={linkConflictCancel}>{t('action.cancel')}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<StatusOverlays bind:confirm={showConfirm} bind:error={error} loading={!me} />
|
<StatusOverlays bind:confirm={showConfirm} bind:error={error} loading={!me} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
@use "../../vars"
|
@use "../../vars"
|
||||||
|
|
||||||
.link-card
|
.link-card
|
||||||
input
|
input
|
||||||
width: 100%
|
width: 100%
|
||||||
|
|
||||||
label
|
label
|
||||||
display: flex
|
display: flex
|
||||||
|
|
||||||
button
|
button
|
||||||
margin-left: 1rem
|
margin-left: 1rem
|
||||||
|
|
||||||
.existing-cards, .conflict-cards
|
.existing-cards, .conflict-cards
|
||||||
display: grid
|
display: grid
|
||||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr))
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr))
|
||||||
gap: 1rem
|
gap: 1rem
|
||||||
|
|
||||||
.existing.card
|
.existing-cards .existing.card
|
||||||
min-height: 90px
|
min-height: 90px
|
||||||
position: relative
|
position: relative
|
||||||
overflow: hidden
|
overflow: hidden
|
||||||
|
|
||||||
*
|
*
|
||||||
white-space: nowrap
|
white-space: nowrap
|
||||||
|
|
||||||
&.ghost
|
&.ghost
|
||||||
background: rgba(vars.$c-darker, 0.8)
|
background: rgba(vars.$c-darker, 0.8)
|
||||||
|
|
||||||
.register, .last
|
.register, .last
|
||||||
opacity: 0.7
|
opacity: 0.7
|
||||||
|
|
||||||
span:not(.type)
|
span:not(.type)
|
||||||
font-size: 0.8rem
|
font-size: 0.8rem
|
||||||
|
|
||||||
> div
|
> div
|
||||||
flex: 1
|
flex: 1
|
||||||
|
|
||||||
button
|
button
|
||||||
position: absolute
|
position: absolute
|
||||||
right: 10px
|
right: 10px
|
||||||
bottom: 10px
|
bottom: 10px
|
||||||
|
|
||||||
.conflict-cards
|
.conflict-cards
|
||||||
.card
|
.card
|
||||||
transition: vars.$transition
|
transition: vars.$transition
|
||||||
|
|
||||||
.card:hover
|
.card:hover
|
||||||
background: vars.$c-darker
|
background: vars.$c-darker
|
||||||
|
|
||||||
span:not(.type)
|
span:not(.type)
|
||||||
font-size: 0.8rem
|
font-size: 0.8rem
|
||||||
|
|
||||||
.id
|
.id
|
||||||
opacity: 0.7
|
opacity: 0.7
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
{#if d}
|
{#if d}
|
||||||
<div class="leaderboard-container">
|
<div class="leaderboard-container">
|
||||||
<div class="lb-user" on:mouseenter={() => hoveringUser = d.users[0].username}>
|
<div class="lb-user" on:mouseenter={() => hoveringUser = d.users[0].username} role="heading" aria-level="2">
|
||||||
<span class="rank">{t("Leaderboard.Rank")}</span>
|
<span class="rank">{t("Leaderboard.Rank")}</span>
|
||||||
<span class="name"></span>
|
<span class="name"></span>
|
||||||
<span class="rating">{t("Leaderboard.Rating")}</span>
|
<span class="rating">{t("Leaderboard.Rating")}</span>
|
||||||
@@ -47,7 +47,9 @@
|
|||||||
<span class="ap">{t("Leaderboard.AP")}</span>
|
<span class="ap">{t("Leaderboard.AP")}</span>
|
||||||
</div>
|
</div>
|
||||||
{#each d.users as user, i (user.rank)}
|
{#each d.users as user, i (user.rank)}
|
||||||
<div class="lb-user" class:alternate={i % 2 === 1} on:mouseover={() => hoveringUser = user.username}>
|
<div class="lb-user" class:alternate={i % 2 === 1} role="listitem"
|
||||||
|
on:mouseover={() => hoveringUser = user.username} on:focus={() => {}}>
|
||||||
|
|
||||||
<span class="rank">#{user.rank}</span>
|
<span class="rank">#{user.rank}</span>
|
||||||
<span class="name">
|
<span class="name">
|
||||||
{#if user.username !== ""}
|
{#if user.username !== ""}
|
||||||
|
|||||||
@@ -109,9 +109,10 @@
|
|||||||
<div class="name-box">
|
<div class="name-box">
|
||||||
<h2>{d.user.name}</h2>
|
<h2>{d.user.name}</h2>
|
||||||
{#if typeof d.user.rival === 'boolean' && game === 'mai2'}
|
{#if typeof d.user.rival === 'boolean' && game === 'mai2'}
|
||||||
<a class="clickable" on:click={()=>setRival(!d.user.rival)}>
|
<span class="clickable" on:click={() => setRival(!d?.user.rival)} role="button" tabindex="0"
|
||||||
|
on:keydown={e => e.key === "Enter" && setRival(!d?.user.rival)}>
|
||||||
{d.user.rival ? t("UserHome.RemoveRival") : t("UserHome.AddRival")}
|
{d.user.rival ? t("UserHome.RemoveRival") : t("UserHome.AddRival")}
|
||||||
</a>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
{#if me && me.username === username}
|
{#if me && me.username === username}
|
||||||
<a class="setting-icon clickable" use:tooltip={t("UserHome.Settings")} href="/settings">
|
<a class="setting-icon clickable" use:tooltip={t("UserHome.Settings")} href="/settings">
|
||||||
@@ -219,7 +220,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<h2>{t('UserHome.PlayActivity')}</h2>
|
<h2>{t('UserHome.PlayActivity')}</h2>
|
||||||
<div class="activity-info">
|
<div class="activity-info">
|
||||||
<div class="hide-scrollbar" id="cal-heatmap" bind:this={calElement} />
|
<div class="hide-scrollbar" id="cal-heatmap" bind:this={calElement}></div>
|
||||||
|
|
||||||
<div class="info-bottom">
|
<div class="info-bottom">
|
||||||
<div class="plays">
|
<div class="plays">
|
||||||
|
|||||||
Reference in New Issue
Block a user