Skip to content

feat(app): skins frontend #3657

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 83 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
f210de5
chore: typo fix and formatting tidyups
AlexTMjugador Apr 11, 2025
ed8ff79
refactor(theseus): extend auth subsystem to fetch complete user profiles
AlexTMjugador Apr 12, 2025
8abbc02
chore: fix new `prettier` lints
AlexTMjugador Apr 12, 2025
23f0c1d
chore: document differences between similar `Credentials` methods
AlexTMjugador Apr 14, 2025
f07bc86
chore: remove dead `profile_run_credentials` plugin command
AlexTMjugador Apr 26, 2025
e189219
feat(app): skin selector backend
AlexTMjugador Apr 17, 2025
a822613
enh(app/skin-selector): better DB intension through deferred FKs, fur…
AlexTMjugador Apr 17, 2025
8ecc7c5
chore: fix comment typo spotted by Copilot
AlexTMjugador Apr 17, 2025
65d15fe
fix: less racy auth token refresh logic
AlexTMjugador Apr 26, 2025
9dda6e0
tweak(app-lib): improve consistency of skin field serialization case
AlexTMjugador May 12, 2025
3587b0a
fix(app-lib/minecraft_skins): fix custom skin removal from DB not wor…
AlexTMjugador May 15, 2025
161dc73
Begin skins frontend
Prospector Apr 26, 2025
5a8bbae
Cape preview
Prospector May 13, 2025
79c18d3
feat: start on SkinPreviewRenderer
IMB11 May 14, 2025
1aa9610
feat: setting for nametag
IMB11 May 14, 2025
6294fce
feat: hide nametag setting (sql)
IMB11 May 14, 2025
7032a1e
fix: positioning of meshes
IMB11 May 14, 2025
7e0dfc1
fix: lighting
IMB11 May 14, 2025
dc6ce0d
fix: allow dragging off-bounds
IMB11 May 14, 2025
7838fb0
fix: better color mapping
IMB11 May 14, 2025
79f0dfd
feat: hide nametag setting (impl)
IMB11 May 14, 2025
fd6e263
feat: Start on edit modal + cape button cleanup + renderer fixes
IMB11 May 15, 2025
d8cb19b
feat: Finish new skin modal
IMB11 May 15, 2025
46261d1
feat: finish cape modal
IMB11 May 15, 2025
6dfeb05
feat: skin rendering on load
IMB11 May 15, 2025
c8492f1
fix: logic for Skins.vue
IMB11 May 15, 2025
cf29286
fix: types
IMB11 May 15, 2025
cd4b2eb
fix: types (for modal + renderer)
IMB11 May 15, 2025
87c0706
feat: Editing?
IMB11 May 15, 2025
1a45575
fix: renderer not updating variant
IMB11 May 15, 2025
d7cf1d2
fix: mojang username not modrinth username
IMB11 May 15, 2025
c5813a9
feat: batched skin rendering - remove vzge references (apart from cap…
IMB11 May 15, 2025
4000777
feat: fix sizing on SkinButton and SkinLikeButton, also implement bus…
IMB11 May 16, 2025
b558a0f
feat: capes in preview renderer & baked renders
IMB11 May 16, 2025
77796e8
fix: lint fixes
IMB11 May 16, 2025
075a9d5
refactor: Start on cleanup and polish
IMB11 May 17, 2025
aa77870
fix: hide error notification when logged out
IMB11 May 18, 2025
8ac1112
revert: .gltf formatting
IMB11 May 18, 2025
949078e
chore(app-frontend): fix typos
AlexTMjugador May 18, 2025
a6627ff
fix(app-lib): delay account skin data deletion to next reboot
AlexTMjugador May 18, 2025
6a18f7c
fix: login button & provide/inject AccountsCard
IMB11 May 21, 2025
560b674
polish: skin buttons
IMB11 May 21, 2025
721577c
fix: imports
IMB11 May 22, 2025
cf354d2
polish: use figma values
IMB11 May 22, 2025
11926ef
polish: tweak underneath shadow
IMB11 May 22, 2025
6bfa833
polish: cursor grab
IMB11 May 22, 2025
ecbb5e3
polish: remove green bg from CapeLikeTextButton when selected.
IMB11 May 22, 2025
5d7df18
polish: modal tweaks
IMB11 May 22, 2025
673b973
polish: grid tweaks + start on upload skin modal
IMB11 May 22, 2025
beb2079
polish: drag and drop file flow
IMB11 May 22, 2025
b3bc3a8
polish: button positioning in SkinButton
IMB11 May 22, 2025
187e892
fix: lint issues
IMB11 May 22, 2025
fc929bf
polish: deduplicate model+cape stuff and fix layout
IMB11 May 24, 2025
b83eb10
fix: lint issues
IMB11 May 24, 2025
0dd033d
fix: camel case requirement for make-default
IMB11 May 24, 2025
dd4f227
polish: use indexed db to persist skin previews
IMB11 May 24, 2025
0a19663
fix: lint issues
IMB11 May 24, 2025
a4e8b05
polish: add skin icon sizing
IMB11 May 24, 2025
cbfb48f
polish: theme fixes
IMB11 May 24, 2025
f503752
feat: animation system for skin preview renderer
IMB11 May 25, 2025
0155262
feat(app/minecraft_skins): save current custom external skin when equ…
AlexTMjugador May 25, 2025
3b9cbc6
fix: cape button & dynamic nametag sizing
IMB11 May 25, 2025
33269d3
feat(theseus): add `normalize_skin_texture` Tauri command
AlexTMjugador May 28, 2025
5fa9a0e
chore: Rust build fixes
AlexTMjugador May 28, 2025
774950d
feat: start impl of skin normalization on frontend
IMB11 May 29, 2025
92f281a
feat(theseus): change parameter type of `normalize_skin_texture` Taur…
AlexTMjugador May 29, 2025
6c5480e
fix: normalization
IMB11 May 29, 2025
4f70e79
fix(theseus): make new `normalize_skin_texture` command usable
AlexTMjugador May 29, 2025
a22d90a
feat: finish normalization impl
IMB11 May 29, 2025
34e49d4
fix: vueuse issue
IMB11 Jun 2, 2025
006611b
fix: use optimistic approach when changing skins/capes.
IMB11 Jun 3, 2025
d37e8fd
fix: nametag cleanup + scroll fix
IMB11 Jun 3, 2025
97042fb
fix: edit modal computedAsync not fast enough for skin preview renderer
IMB11 Jun 4, 2025
3133cec
feat: classic player model animations
IMB11 Jun 12, 2025
4ba5498
chore: fix new Clippy lint
AlexTMjugador Jun 14, 2025
864c20c
fix(app-lib): actually delete custom skins with no cape overrides
AlexTMjugador Jun 14, 2025
d622833
fix(app-lib): handle repeated addition of the same skin properly
AlexTMjugador Jun 14, 2025
1b4b2a9
refactor(app-lib): simplify DB connection logic a little
AlexTMjugador Jun 14, 2025
cb39fe6
fix: various improvements
IMB11 Jun 15, 2025
40bc811
feat: slim animations
IMB11 Jun 15, 2025
5e69cbc
fix: z-fighting on models
IMB11 Jun 16, 2025
b851cd8
fix: shading + lighting improvements
IMB11 Jun 16, 2025
cbb7c80
fix: shadows
IMB11 Jun 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ async-tungstenite = { version = "0.29.1", default-features = false, features = [
async-walkdir = "2.1.0"
base64 = "0.22.1"
bitflags = "2.9.1"
bytemuck = "1.23.0"
bytes = "1.10.1"
censor = "0.3.0"
chardetng = "0.1.17"
Expand All @@ -47,6 +48,7 @@ color-thief = "0.2.2"
console-subscriber = "0.4.1"
daedalus = { path = "packages/daedalus" }
dashmap = "6.1.0"
data-url = "0.3.1"
deadpool-redis = "0.21.1"
dirs = "6.0.0"
discord-rich-presence = "0.2.5"
Expand All @@ -60,6 +62,7 @@ flate2 = "1.1.2"
fs4 = { version = "0.13.1", default-features = false }
futures = { version = "0.3.31", default-features = false }
futures-util = "0.3.31"
heck = "0.5.0"
hex = "0.4.3"
hickory-resolver = "0.25.2"
hmac = "0.12.1"
Expand Down Expand Up @@ -89,6 +92,7 @@ notify = { version = "8.0.0", default-features = false }
notify-debouncer-mini = { version = "0.6.0", default-features = false }
p256 = "0.13.2"
paste = "1.0.15"
png = "0.17.16"
prometheus = "0.14.0"
quartz_nbt = "0.2.9"
quick-xml = "0.37.5"
Expand All @@ -97,6 +101,7 @@ rand_chacha = "=0.3.1" # Locked on 0.3 until we can update rand to 0.9
redis = "=0.31.0" # Locked on 0.31 until deadpool-redis updates to 0.32
regex = "1.11.1"
reqwest = { version = "0.12.19", default-features = false }
rgb = "0.8.50"
rust_decimal = { version = "1.37.1", features = [
"serde-with-float",
"serde-with-str",
Expand Down
1 change: 1 addition & 0 deletions apps/app-frontend/.prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
**/dist
*.gltf
3 changes: 3 additions & 0 deletions apps/app-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@
"@tauri-apps/plugin-os": "^2.2.1",
"@tauri-apps/plugin-updater": "^2.7.1",
"@tauri-apps/plugin-window-state": "^2.2.2",
"@types/three": "^0.172.0",
"@vintl/vintl": "^4.4.1",
"@vueuse/core": "^11.1.0",
"dayjs": "^1.11.10",
"floating-vue": "^5.2.2",
"ofetch": "^1.3.4",
"pinia": "^2.1.7",
"posthog-js": "^1.158.2",
"three": "^0.172.0",
"vite-svg-loader": "^5.1.0",
"vue": "^3.5.13",
"vue-multiselect": "3.0.0",
Expand Down
17 changes: 16 additions & 1 deletion apps/app-frontend/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<script setup>
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { computed, onMounted, onUnmounted, ref, watch, provide } from 'vue'
import { RouterView, useRoute, useRouter } from 'vue-router'
import {
ArrowBigUpDashIcon,
ChangeSkinIcon,
CompassIcon,
DownloadIcon,
HomeIcon,
Expand Down Expand Up @@ -68,6 +69,8 @@ import { hide_ads_window, init_ads_window } from '@/helpers/ads.js'
import FriendsList from '@/components/ui/friends/FriendsList.vue'
import { openUrl } from '@tauri-apps/plugin-opener'
import QuickInstanceSwitcher from '@/components/ui/QuickInstanceSwitcher.vue'
import { get_available_capes, get_available_skins } from './helpers/skins'
import { generateSkinPreviews } from './helpers/rendering/batch-skin-renderer'

const formatRelativeTime = useRelativeTime()

Expand Down Expand Up @@ -197,6 +200,14 @@ async function setupApp() {
get_opening_command().then(handleCommand)
checkUpdates()
fetchCredentials()

try {
const skins = (await get_available_skins()) ?? []
const capes = (await get_available_capes()) ?? []
generateSkinPreviews(skins, capes)
} catch (error) {
console.warn('Failed to generate skin previews in app setup.', error)
}
}

const stateFailed = ref(false)
Expand Down Expand Up @@ -304,6 +315,7 @@ onMounted(() => {
})

const accounts = ref(null)
provide('accountsCard', accounts)

command_listener(handleCommand)
async function handleCommand(e) {
Expand Down Expand Up @@ -399,6 +411,9 @@ function handleAuxClick(e) {
>
<CompassIcon />
</NavButton>
<NavButton v-tooltip.right="'Skins'" to="/skins">
<ChangeSkinIcon />
</NavButton>
<NavButton
v-tooltip.right="'Library'"
to="/library"
Expand Down
1 change: 1 addition & 0 deletions apps/app-frontend/src/assets/models/cape.gltf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"asset":{"version":"2.0","generator":"Blockbench 4.12.4 glTF exporter"},"scenes":[{"nodes":[1],"name":"blockbench_export"}],"scene":0,"nodes":[{"rotation":[0,0,0.19509032201612825,0.9807852804032304],"translation":[0.15625,1,0],"name":"Cape","mesh":0},{"children":[0]}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":288,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":576,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":768,"byteLength":72,"target":34963}],"buffers":[{"byteLength":840,"uri":"data:application/octet-stream;base64,AAAAPQAAAAAAAKA+AAAAPQAAAAAAAKC+AAAAPQAAgL8AAKA+AAAAPQAAgL8AAKC+AAAAvQAAAAAAAKC+AAAAvQAAAAAAAKA+AAAAvQAAgL8AAKC+AAAAvQAAgL8AAKA+AAAAvQAAAAAAAKC+AAAAPQAAAAAAAKC+AAAAvQAAAAAAAKA+AAAAPQAAAAAAAKA+AAAAvQAAgL8AAKA+AAAAPQAAgL8AAKA+AAAAvQAAgL8AAKC+AAAAPQAAgL8AAKC+AAAAvQAAAAAAAKA+AAAAPQAAAAAAAKA+AAAAvQAAgL8AAKA+AAAAPQAAgL8AAKA+AAAAPQAAAAAAAKC+AAAAvQAAAAAAAKC+AAAAPQAAgL8AAKC+AAAAvQAAgL8AAKC+AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAPAAAgD0AADA+AACAPQAAgDwAAAg/AAAwPgAACD8AAEA+AACAPQAAsD4AAIA9AABAPgAACD8AALA+AAAIPwAAgDwAAAA9AACAPAAAgD0AADA+AAAAPQAAMD4AAIA9AAAwPgAAAD0AAKg+AAAAPQAAMD4AAAAAAACoPgAAAAAAAEA+AACAPQAAMD4AAIA9AABAPgAACD8AADA+AAAIPwAAAAAAAIA9AACAPAAAgD0AAAAAAAAIPwAAgDwAAAg/AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUA"}],"accessors":[{"bufferView":0,"componentType":5126,"count":24,"max":[0.03125,0,0.3125],"min":[-0.03125,-1,-0.3125],"type":"VEC3"},{"bufferView":1,"componentType":5126,"count":24,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":2,"componentType":5126,"count":24,"max":[0.34375,0.53125],"min":[0,0],"type":"VEC2"},{"bufferView":3,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"}],"materials":[{"pbrMetallicRoughness":{"metallicFactor":0,"roughnessFactor":1,"baseColorTexture":{"index":0}},"alphaMode":"MASK","alphaCutoff":0.05,"doubleSided":true}],"textures":[{"sampler":0,"source":0,"name":"cape.png"}],"samplers":[{"magFilter":9728,"minFilter":9728,"wrapS":33071,"wrapT":33071}],"images":[{"mimeType":"image/png","uri":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAAgCAYAAACinX6EAAAAAXNSR0IArs4c6QAABCRJREFUaEPtlktoE1EUhm/sIzFpYsBgHyn2oRZt0C5ESxWFYutKNyKIWBBR6kpBd3Ur2J0FRdCiuKmIIG4qLnzgQqTUXSlVqdoXTU0lljRpYtOHI/8dznBnOm1mphMwJWeTzJ0795zznf/cex2MMXam2S/ht38siJ8V1lgd5mOBARerc3rZnmK37rwvCyk2nE6wezMRh+4EncH9B1ql+fkU64rPsaBz5bqh4T7Daxn1Kc5zVNeEePJIci0Aq71bzenY6JChwAnA0OBHQ/OtJLnWNwqAy61R1tO3k891ueRKoDKwtqbv7MGbgCnfRgHQoqG9hyX4hc/yiho+/HNqVPFtdj2jwTpQgd/RKT7/0ZUku/o4qAJw50KYXbzr4e+3BioYzc3kwGzAUCLWFw2+UBiCb3bNTDHiPQeAP3CGNmg/6VcSBpDu3hhvDQpOCwABwrQKsRIsqYAChy/EQAXwlPiZ3a3igNPkXIyTjr8o5L7PPdzGf59c+sV/faeWeIIIAHPJ8M3kc7l1K09LKghWAIgqoPZ7djPFTlxb4D6yAgBOQfntrUVWVeRk44tplXJorOVGkVIJTBCTpw9ECFYBIEkyMfmsAXh3u1qi5MlxbbGX/x1ZSCjBAAwgfPr6h49R5UVavk0FXC2wju5p07s6iqEF0PtqSlEf+bKzDRwdgaDU7AkoySJ5Oo/D6ZRq/H0yyuJ/lxkSheG/FgCNm7kL0BoEAG32sqtY1YIHd2/mGzTMVgD3y2slqjgW9xY6ma9AThAARIMiBtOpjADwTWc0bEkB+FZsSTxTW0KBsGPXx0yvrUpEeHAAQIM7wBJLcu8DwHaP/H8i6VSND6SiSjBlRW4WWUypVIBbIgzjVgB0tpdKqLReS0KVPTMTfH0ra2cEgAmAAEd+l1z52LybqwBQYAQAyZPh6gtDW4jjuC4fHx8wXSm0JDbeI95SRYHiFZlUaWVtPQiKAugl5E8ASAUYiy8vc0C474uGasPE5PHc4g0wK/f4obom6UNimol7kTZwQLANwOuqBokqDEeQf4lfvvnNxZJcBTBAGZplWQcQ3tcgwY9oWlXinRW4ugoAgNAWWe6ocn1QvgyRTUb4RZFVljlY/3hSBYCqb6cCZo8ekuATVRZPI/gQW8FWAI1VHganVgDQUajdA6y2gAgAcZFBjTBSpG0AcAqc3VVmCMDTbxGWZvIRCaMNkJ7pFMCzVQD4liCQ8kRFUlvaBkCvL+wYw2ZmNUgCgLajFhRPJlv3ADuS1VtjPQCk823S574ffN/x1dQqy8dHR5SN2Spcbaymz2mjwNYDAD4IQn3TDpVLQIAqNjwAANRrAdoI/3sAOF7Xe1khCNQGVH1bL0JGJb1R52VtD8gVYHkAuVKpbMWZV0C2yObKunkF5EqlshVnXgHZIpsr6/4DlbxcPydnT74AAAAASUVORK5CYII="}],"meshes":[{"primitives":[{"mode":4,"attributes":{"POSITION":0,"NORMAL":1,"TEXCOORD_0":2},"indices":3,"material":0}]}]}
1 change: 1 addition & 0 deletions apps/app-frontend/src/assets/models/classic_player.gltf

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions apps/app-frontend/src/assets/models/slim_player.gltf

Large diffs are not rendered by default.

Binary file added apps/app-frontend/src/assets/skins/herobrine.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/app-frontend/src/assets/skins/steve.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
79 changes: 61 additions & 18 deletions apps/app-frontend/src/components/ui/AccountsCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@
<Avatar
size="36px"
:src="
selectedAccount
? `https://mc-heads.net/avatar/${selectedAccount.id}/128`
: 'https://launcher-files.modrinth.com/assets/steve_head.png'
selectedAccount ? avatarUrl : 'https://launcher-files.modrinth.com/assets/steve_head.png'
"
/>
<div class="flex flex-col w-full">
<span>{{ selectedAccount ? selectedAccount.username : 'Select account' }}</span>
<span>{{ selectedAccount ? selectedAccount.profile.name : 'Select account' }}</span>
<span class="text-secondary text-xs">Minecraft account</span>
</div>
<DropdownIcon class="w-5 h-5 shrink-0" />
Expand All @@ -28,28 +26,47 @@
:class="{ expanded: mode === 'expanded', isolated: mode === 'isolated' }"
>
<div v-if="selectedAccount" class="selected account">
<Avatar size="xs" :src="`https://mc-heads.net/avatar/${selectedAccount.id}/128`" />
<Avatar size="xs" :src="`https://mc-heads.net/avatar/${selectedAccount.profile.id}/128`" />
<div>
<h4>{{ selectedAccount.username }}</h4>
<h4>{{ selectedAccount.profile.name }}</h4>
<p>Selected</p>
</div>
<Button v-tooltip="'Log out'" icon-only color="raised" @click="logout(selectedAccount.id)">
<Button
v-tooltip="'Log out'"
icon-only
color="raised"
@click="logout(selectedAccount.profile.id)"
>
<TrashIcon />
</Button>
</div>
<div v-else class="logged-out account">
<h4>Not signed in</h4>
<Button v-tooltip="'Log in'" icon-only color="primary" @click="login()">
<LogInIcon />
<Button
v-tooltip="'Log in'"
:disabled="loginDisabled"
icon-only
color="primary"
@click="login()"
>
<LogInIcon v-if="!loginDisabled" />
<SpinnerIcon v-else class="animate-spin" />
</Button>
</div>
<div v-if="displayAccounts.length > 0" class="account-group">
<div v-for="account in displayAccounts" :key="account.id" class="account-row">
<div v-for="account in displayAccounts" :key="account.profile.id" class="account-row">
<Button class="option account" @click="setAccount(account)">
<Avatar :src="`https://mc-heads.net/avatar/${account.id}/128`" class="icon" />
<p>{{ account.username }}</p>
<Avatar
:src="
account.profile.id == selectedAccount.profile.id
? avatarUrl
: `https://mc-heads.net/avatar/${account.profile.id}/128`
"
class="icon"
/>
<p>{{ account.profile.name }}</p>
</Button>
<Button v-tooltip="'Log out'" icon-only @click="logout(account.id)">
<Button v-tooltip="'Log out'" icon-only @click="logout(account.profile.id)">
<TrashIcon />
</Button>
</div>
Expand All @@ -63,7 +80,7 @@
</template>

<script setup>
import { DropdownIcon, PlusIcon, TrashIcon, LogInIcon } from '@modrinth/assets'
import { DropdownIcon, PlusIcon, TrashIcon, LogInIcon, SpinnerIcon } from '@modrinth/assets'
import { Avatar, Button, Card } from '@modrinth/ui'
import { ref, computed, onMounted, onBeforeUnmount, onUnmounted } from 'vue'
import {
Expand All @@ -77,6 +94,7 @@ import { handleError } from '@/store/state.js'
import { trackEvent } from '@/helpers/analytics'
import { process_listener } from '@/helpers/events'
import { handleSevereError } from '@/store/error.js'
import { get_available_skins } from '@/helpers/skins'

defineProps({
mode: {
Expand All @@ -89,32 +107,56 @@ defineProps({
const emit = defineEmits(['change'])

const accounts = ref({})
const loginDisabled = ref(false)
const defaultUser = ref()
const equippedSkin = ref(null)

async function refreshValues() {
defaultUser.value = await get_default_user().catch(handleError)
accounts.value = await users().catch(handleError)

try {
const skins = await get_available_skins()
equippedSkin.value = skins.find((skin) => skin.is_equipped)
} catch {
equippedSkin.value = null
}
}

function setLoginDisabled(value) {
loginDisabled.value = value
}

defineExpose({
refreshValues,
setLoginDisabled,
loginDisabled,
})
await refreshValues()

const displayAccounts = computed(() =>
accounts.value.filter((account) => defaultUser.value !== account.id),
accounts.value.filter((account) => defaultUser.value !== account.profile.id),
)

const avatarUrl = computed(() => {
if (equippedSkin.value?.texture_key) {
return `https://mc-heads.net/avatar/${equippedSkin.value.texture_key}/128`
}
return `https://mc-heads.net/avatar/${selectedAccount.value.profile.id}/128`
})

const selectedAccount = computed(() =>
accounts.value.find((account) => account.id === defaultUser.value),
accounts.value.find((account) => account.profile.id === defaultUser.value),
)

async function setAccount(account) {
defaultUser.value = account.id
await set_default_user(account.id).catch(handleError)
defaultUser.value = account.profile.id
await set_default_user(account.profile.id).catch(handleError)
emit('change')
}

async function login() {
loginDisabled.value = true
const loggedIn = await login_flow().catch(handleSevereError)

if (loggedIn) {
Expand All @@ -123,6 +165,7 @@ async function login() {
}

trackEvent('AccountLogIn')
loginDisabled.value = false
}

const logout = async (id) => {
Expand Down
6 changes: 3 additions & 3 deletions apps/app-frontend/src/components/ui/ErrorModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ async function loginMinecraft() {
const loggedIn = await login_flow()

if (loggedIn) {
await set_default_user(loggedIn.id).catch(handleError)
await set_default_user(loggedIn.profile.id).catch(handleError)
}

await trackEvent('AccountLogIn', { source: 'ErrorModal' })
Expand Down Expand Up @@ -219,8 +219,8 @@ async function copyToClipboard(text) {
<template v-else-if="metadata.notEnoughSpace">
<h3>Not enough space</h3>
<p>
It looks like there is not enough space on the disk containing the dirctory you
selected Please free up some space and try again or cancel the directory change.
It looks like there is not enough space on the disk containing the directory you
selected. Please free up some space and try again or cancel the directory change.
</p>
</template>
<template v-else>
Expand Down
Loading
Loading