mirror of https://github.com/hykilpikonna/AquaDX
[+] Implement user settings
parent
49da7aafd0
commit
fa4ccf07b8
|
@ -9,6 +9,7 @@
|
||||||
import { USER } from "./libs/sdk";
|
import { USER } from "./libs/sdk";
|
||||||
import type { UserMe } from "./libs/generalTypes";
|
import type { UserMe } from "./libs/generalTypes";
|
||||||
import { DEFAULT_PFP, IMG_HOST } from "./libs/config";
|
import { DEFAULT_PFP, IMG_HOST } from "./libs/config";
|
||||||
|
import Settings from "./pages/User/Settings.svelte";
|
||||||
|
|
||||||
console.log(`%c
|
console.log(`%c
|
||||||
┏━┓ ┳━┓━┓┏━
|
┏━┓ ┳━┓━┓┏━
|
||||||
|
@ -53,6 +54,7 @@
|
||||||
<Route path="/u/:username" component={UserHome} />
|
<Route path="/u/:username" component={UserHome} />
|
||||||
<Route path="/u/:username/:game" component={UserHome} />
|
<Route path="/u/:username/:game" component={UserHome} />
|
||||||
<Route path="/u/:username/:game/rating" component={MaimaiRating} />
|
<Route path="/u/:username/:game/rating" component={MaimaiRating} />
|
||||||
|
<Route path="/settings" component={Settings} />
|
||||||
</Router>
|
</Router>
|
||||||
|
|
||||||
<style lang="sass">
|
<style lang="sass">
|
||||||
|
|
|
@ -158,7 +158,8 @@ input.error
|
||||||
user-select: none
|
user-select: none
|
||||||
|
|
||||||
|
|
||||||
main.content
|
// Content containers
|
||||||
|
.content-main
|
||||||
display: flex
|
display: flex
|
||||||
flex-direction: column
|
flex-direction: column
|
||||||
gap: 20px
|
gap: 20px
|
||||||
|
@ -167,7 +168,7 @@ main.content
|
||||||
min-height: 100%
|
min-height: 100%
|
||||||
max-width: $w-max
|
max-width: $w-max
|
||||||
|
|
||||||
background-color: rgba(black, 0.2)
|
background-color: darken($c-bg, 3%)
|
||||||
border-radius: 16px 16px 0 0
|
border-radius: 16px 16px 0 0
|
||||||
|
|
||||||
@media (max-width: #{$w-max + (64px) * 2})
|
@media (max-width: #{$w-max + (64px) * 2})
|
||||||
|
@ -178,15 +179,36 @@ main.content
|
||||||
|
|
||||||
> h2.outer-title
|
> h2.outer-title
|
||||||
margin-top: -3.5rem
|
margin-top: -3.5rem
|
||||||
//color: transparent
|
|
||||||
//background-color: rgba($c-main, 70%)
|
|
||||||
//-webkit-background-clip: text
|
|
||||||
//background-clip: text
|
|
||||||
//text-shadow: rgb(0 0 0 / 50%) 0 5px 6px
|
|
||||||
|
|
||||||
@media (max-width: $w-mobile)
|
@media (max-width: $w-mobile)
|
||||||
text-align: center
|
text-align: center
|
||||||
|
|
||||||
|
main.content
|
||||||
|
@extend .content-main
|
||||||
|
|
||||||
|
// Not used. still need a lot of work
|
||||||
|
.content-popup
|
||||||
|
position: absolute
|
||||||
|
inset: 0
|
||||||
|
|
||||||
|
> div
|
||||||
|
@extend .content-main
|
||||||
|
position: absolute
|
||||||
|
inset: 0
|
||||||
|
top: 100px
|
||||||
|
background: rgba(darken($c-bg, 3%), 0.9)
|
||||||
|
backdrop-filter: blur(5px)
|
||||||
|
box-shadow: 0 0 10px 6px rgba(black, 0.4)
|
||||||
|
max-width: calc($w-max + 20px)
|
||||||
|
|
||||||
|
@media (max-width: #{$w-max + (64px) * 2})
|
||||||
|
margin: 100px 22px 0
|
||||||
|
|
||||||
|
@media (max-width: $w-mobile)
|
||||||
|
margin: 100px 0 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Overlay
|
// Overlay
|
||||||
.overlay
|
.overlay
|
||||||
position: fixed
|
position: fixed
|
||||||
|
|
|
@ -121,6 +121,8 @@ export const USER = {
|
||||||
},
|
},
|
||||||
keychip: (): Promise<string> =>
|
keychip: (): Promise<string> =>
|
||||||
post('/api/v2/user/keychip', {}).then(it => it.keychip),
|
post('/api/v2/user/keychip', {}).then(it => it.keychip),
|
||||||
|
setting: (key: string, value: string) =>
|
||||||
|
post('/api/v2/user/setting', { key: key === 'password' ? 'pwHash' : key, value }),
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
ensureLoggedIn,
|
ensureLoggedIn,
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
<!-- Svelte 4.2.11 -->
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { slide } from "svelte/transition";
|
||||||
|
import type { UserMe } from "../../libs/generalTypes";
|
||||||
|
import { USER } from "../../libs/sdk";
|
||||||
|
import StatusOverlays from "../../components/StatusOverlays.svelte";
|
||||||
|
import Icon from "@iconify/svelte";
|
||||||
|
|
||||||
|
USER.ensureLoggedIn()
|
||||||
|
|
||||||
|
let me: UserMe;
|
||||||
|
let error: string;
|
||||||
|
let submitting = ""
|
||||||
|
|
||||||
|
const fields = [
|
||||||
|
[ 'displayName', "Display Name" ],
|
||||||
|
[ 'username', "Username" ],
|
||||||
|
[ 'password', "Password" ],
|
||||||
|
[ 'profileLocation', "Location" ],
|
||||||
|
[ 'profileBio', "Bio" ],
|
||||||
|
]
|
||||||
|
|
||||||
|
// Fetch user data
|
||||||
|
USER.me().then(m => {
|
||||||
|
me = m
|
||||||
|
values = fields.map(([field]) => me[field as keyof UserMe])
|
||||||
|
}).catch(e => error = e.message)
|
||||||
|
|
||||||
|
let values = Array(fields.length).fill('')
|
||||||
|
let changed: string[] = []
|
||||||
|
|
||||||
|
function submit(field: string, value: string) {
|
||||||
|
if (submitting) return
|
||||||
|
submitting = field
|
||||||
|
|
||||||
|
USER.setting(field, value).then(() => {
|
||||||
|
changed = changed.filter(c => c !== field)
|
||||||
|
}).catch(e => error = e.message).finally(() => submitting = "")
|
||||||
|
}
|
||||||
|
|
||||||
|
const passwordAction = (node: HTMLInputElement, whether: boolean) => {
|
||||||
|
if (whether) node.type = 'password'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<main class="content">
|
||||||
|
<h2>Profile Settings</h2>
|
||||||
|
|
||||||
|
{#each fields as [field, name], i (field)}
|
||||||
|
<div class="field">
|
||||||
|
<label for={field}>{name}</label>
|
||||||
|
<div>
|
||||||
|
<input id={field} type="text" use:passwordAction={field === 'password'}
|
||||||
|
bind:value={values[i]} on:input={() => changed = [...changed, field]}
|
||||||
|
placeholder={field === 'password' ? 'Unchanged' : 'Unset'}/>
|
||||||
|
{#if changed.includes(field) && values[i]}
|
||||||
|
<button transition:slide={{axis: 'x'}} on:click={() => submit(field, values[i])}>
|
||||||
|
{#if submitting === field}
|
||||||
|
<Icon icon="line-md:loading-twotone-loop" />
|
||||||
|
{:else}
|
||||||
|
Save
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
<StatusOverlays {error} loading={!me} />
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<style lang="sass">
|
||||||
|
|
||||||
|
.field
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
|
||||||
|
> div
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
gap: 1rem
|
||||||
|
margin-top: 0.5rem
|
||||||
|
|
||||||
|
> input
|
||||||
|
flex: 1
|
||||||
|
|
||||||
|
</style>
|
|
@ -10,7 +10,6 @@
|
||||||
import { type GameName, getMult } from "../libs/scoring";
|
import { type GameName, getMult } from "../libs/scoring";
|
||||||
import StatusOverlays from "../components/StatusOverlays.svelte";
|
import StatusOverlays from "../components/StatusOverlays.svelte";
|
||||||
import Icon from "@iconify/svelte";
|
import Icon from "@iconify/svelte";
|
||||||
import EditProfile from "./User/EditProfile.svelte";
|
|
||||||
|
|
||||||
registerChart()
|
registerChart()
|
||||||
|
|
||||||
|
@ -18,7 +17,6 @@
|
||||||
export let game: GameName = "mai2"
|
export let game: GameName = "mai2"
|
||||||
let calElement: HTMLElement
|
let calElement: HTMLElement
|
||||||
let error: string;
|
let error: string;
|
||||||
let editingProfile = false
|
|
||||||
let me: UserMe
|
let me: UserMe
|
||||||
title(`User ${username}`)
|
title(`User ${username}`)
|
||||||
|
|
||||||
|
@ -62,11 +60,9 @@
|
||||||
<div class="name-box">
|
<div class="name-box">
|
||||||
<h2>{d.user.name}</h2>
|
<h2>{d.user.name}</h2>
|
||||||
{#if me && me.username === username}
|
{#if me && me.username === username}
|
||||||
<span class="setting-icon clickable" on:click={() => editingProfile = true}
|
<a class="setting-icon clickable" use:tooltip={"Settings"} href="/settings">
|
||||||
on:keydown={e => e.key === "Enter" && (editingProfile = true)} tabindex="0" role="button"
|
<Icon icon="eos-icons:rotating-gear"/>
|
||||||
use:tooltip={"Settings"}>
|
</a>
|
||||||
<Icon icon="eos-icons:rotating-gear"/>
|
|
||||||
</span>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<nav>
|
<nav>
|
||||||
|
|
Loading…
Reference in New Issue