fix: lint issues
This commit is contained in:
1 parent
b3bc3a8731
commit
187e892c18
12 files changed
+319
-213
No files matched your search
@@ -44,7 +44,13 @@
|
||||
</div>
|
||||
<div v-else class="logged-out account">
|
||||
<h4>Not signed in</h4>
|
||||
<Button v-tooltip="'Log in'" :disabled="loginDisabled" icon-only color="primary" @click="login()">
|
||||
<Button
|
||||
v-tooltip="'Log in'"
|
||||
:disabled="loginDisabled"
|
||||
icon-only
|
||||
color="primary"
|
||||
@click="login()"
|
||||
>
|
||||
<LogInIcon v-if="!loginDisabled" />
|
||||
<SpinnerIcon v-else class="animate-spin" />
|
||||
</Button>
|
||||
@@ -95,7 +101,7 @@ defineProps({
|
||||
const emit = defineEmits(['change'])
|
||||
|
||||
const accounts = ref({})
|
||||
const loginDisabled = ref(false);
|
||||
const loginDisabled = ref(false)
|
||||
const defaultUser = ref()
|
||||
|
||||
async function refreshValues() {
|
||||
@@ -104,13 +110,13 @@ async function refreshValues() {
|
||||
}
|
||||
|
||||
function setLoginDisabled(value) {
|
||||
loginDisabled.value = value;
|
||||
loginDisabled.value = value
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
refreshValues,
|
||||
setLoginDisabled,
|
||||
loginDisabled
|
||||
loginDisabled,
|
||||
})
|
||||
await refreshValues()
|
||||
|
||||
@@ -129,7 +135,7 @@ async function setAccount(account) {
|
||||
}
|
||||
|
||||
async function login() {
|
||||
loginDisabled.value = true;
|
||||
loginDisabled.value = true
|
||||
const loggedIn = await login_flow().catch(handleSevereError)
|
||||
|
||||
if (loggedIn) {
|
||||
@@ -138,7 +144,7 @@ async function login() {
|
||||
}
|
||||
|
||||
trackEvent('AccountLogIn')
|
||||
loginDisabled.value = false;
|
||||
loginDisabled.value = false
|
||||
}
|
||||
|
||||
const logout = async (id) => {
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
:variant="variant"
|
||||
:texture-src="previewSkin"
|
||||
:cape-src="selectedCapeTexture"
|
||||
:scale="1.4" :fov="50"
|
||||
:scale="1.4"
|
||||
:fov="50"
|
||||
:initial-rotation="Math.PI / 8"
|
||||
class="h-full w-full"
|
||||
/>
|
||||
@@ -26,14 +27,12 @@
|
||||
<div class="flex flex-col gap-4 w-full min-h-[20rem]">
|
||||
<section>
|
||||
<h2 class="text-base font-semibold mb-2">Texture</h2>
|
||||
<Button @click="openUploadSkinModal">
|
||||
<UploadIcon /> Replace texture
|
||||
</Button>
|
||||
<Button @click="openUploadSkinModal"> <UploadIcon /> Replace texture </Button>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 class="text-base font-semibold mb-2">Arm style</h2>
|
||||
<RadioButtons v-model="variant" :items="['CLASSIC','SLIM']">
|
||||
<RadioButtons v-model="variant" :items="['CLASSIC', 'SLIM']">
|
||||
<template #default="{ item }">
|
||||
{{ item === 'CLASSIC' ? 'Wide' : 'Slim' }}
|
||||
</template>
|
||||
@@ -69,7 +68,7 @@
|
||||
tooltip="View more capes"
|
||||
@mouseup="openSelectCapeModal"
|
||||
>
|
||||
<template #icon><ChevronRightIcon/></template>
|
||||
<template #icon><ChevronRightIcon /></template>
|
||||
<span>More</span>
|
||||
</CapeLikeTextButton>
|
||||
</div>
|
||||
@@ -84,41 +83,49 @@
|
||||
{{ mode === 'new' ? 'Add skin' : 'Save skin' }}
|
||||
</Button>
|
||||
</ButtonStyled>
|
||||
<Button @click="hide"><XIcon/>Cancel</Button>
|
||||
<Button @click="hide"><XIcon />Cancel</Button>
|
||||
</div>
|
||||
</NewModal>
|
||||
|
||||
<SelectCapeModal ref="selectCapeModal" :capes="capes || []" @select="handleCapeSelected" @cancel="handleCapeCancel" />
|
||||
<SelectCapeModal
|
||||
ref="selectCapeModal"
|
||||
:capes="capes || []"
|
||||
@select="handleCapeSelected"
|
||||
@cancel="handleCapeCancel"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, useTemplateRef } from 'vue'
|
||||
import SelectCapeModal from '@/components/ui/skin/SelectCapeModal.vue'
|
||||
import {
|
||||
Card, FileInput, SkinPreviewRenderer,
|
||||
Button, RadioButtons, CapeButton, CapeLikeTextButton, ButtonStyled,
|
||||
NewModal
|
||||
SkinPreviewRenderer,
|
||||
Button,
|
||||
RadioButtons,
|
||||
CapeButton,
|
||||
CapeLikeTextButton,
|
||||
ButtonStyled,
|
||||
NewModal,
|
||||
} from '@modrinth/ui'
|
||||
import {
|
||||
add_and_equip_custom_skin,
|
||||
remove_custom_skin,
|
||||
unequip_skin,
|
||||
type Skin, type Cape, type SkinModel
|
||||
type Skin,
|
||||
type Cape,
|
||||
type SkinModel,
|
||||
} from '@/helpers/skins.ts'
|
||||
import { handleError } from '@/store/notifications'
|
||||
import {
|
||||
UploadIcon,
|
||||
CheckIcon, SaveIcon, XIcon, TrashIcon, ChevronRightIcon
|
||||
} from '@modrinth/assets'
|
||||
import { UploadIcon, CheckIcon, SaveIcon, XIcon, ChevronRightIcon } from '@modrinth/assets'
|
||||
|
||||
const modal = useTemplateRef('modal')
|
||||
const selectCapeModal = useTemplateRef('selectCapeModal')
|
||||
const mode = ref<'new'|'edit'>('new')
|
||||
const currentSkin = ref<Skin|null>(null)
|
||||
const mode = ref<'new' | 'edit'>('new')
|
||||
const currentSkin = ref<Skin | null>(null)
|
||||
const shouldRestoreModal = ref(false)
|
||||
|
||||
const fileUploadTextureBlob = ref<Uint8Array|null>(null)
|
||||
const fileName = ref<string|null>(null)
|
||||
const fileUploadTextureBlob = ref<Uint8Array | null>(null)
|
||||
const fileName = ref<string | null>(null)
|
||||
watch(fileUploadTextureBlob, () => {
|
||||
if (fileName.value === null && fileUploadTextureBlob.value) {
|
||||
fileName.value = 'New upload'
|
||||
@@ -126,7 +133,7 @@ watch(fileUploadTextureBlob, () => {
|
||||
})
|
||||
|
||||
const variant = ref<SkinModel>('CLASSIC')
|
||||
const selectedCape = ref<Cape|undefined>(undefined)
|
||||
const selectedCape = ref<Cape | undefined>(undefined)
|
||||
const props = defineProps<{ capes?: Cape[] }>()
|
||||
|
||||
const selectedCapeTexture = computed(() => selectedCape.value?.texture)
|
||||
@@ -134,11 +141,11 @@ const visibleCapeList = ref<Cape[]>([])
|
||||
|
||||
const sortedCapes = computed(() => {
|
||||
return [...(props.capes || [])].sort((a, b) => {
|
||||
const nameA = (a.name || '').toLowerCase();
|
||||
const nameB = (b.name || '').toLowerCase();
|
||||
return nameA.localeCompare(nameB);
|
||||
});
|
||||
});
|
||||
const nameA = (a.name || '').toLowerCase()
|
||||
const nameB = (b.name || '').toLowerCase()
|
||||
return nameA.localeCompare(nameB)
|
||||
})
|
||||
})
|
||||
|
||||
function initVisibleCapeList() {
|
||||
if (!props.capes || props.capes.length === 0) {
|
||||
@@ -163,10 +170,10 @@ function getSortedCapes(count: number): Cape[] {
|
||||
|
||||
function getSortedCapeExcluding(excludeId: string): Cape | undefined {
|
||||
if (!sortedCapes.value || sortedCapes.value.length <= 1) return undefined
|
||||
return sortedCapes.value.find(cape => cape.id !== excludeId)
|
||||
return sortedCapes.value.find((cape) => cape.id !== excludeId)
|
||||
}
|
||||
|
||||
const localPreviewUrl = ref<string|null>(null)
|
||||
const localPreviewUrl = ref<string | null>(null)
|
||||
watch(fileUploadTextureBlob, (blob, prev) => {
|
||||
if (prev && localPreviewUrl.value) URL.revokeObjectURL(localPreviewUrl.value)
|
||||
if (blob) localPreviewUrl.value = URL.createObjectURL(new Blob([blob]))
|
||||
@@ -179,24 +186,25 @@ const previewSkin = computed(() => {
|
||||
})
|
||||
|
||||
const hasEdits = computed(() => {
|
||||
if (mode.value !== 'edit') return true;
|
||||
if (fileUploadTextureBlob.value) return true;
|
||||
if (!currentSkin.value) return false;
|
||||
if (variant.value !== currentSkin.value.variant) return true;
|
||||
if ((selectedCape.value?.id || null) !== (currentSkin.value.cape_id || null)) return true;
|
||||
return false;
|
||||
});
|
||||
if (mode.value !== 'edit') return true
|
||||
if (fileUploadTextureBlob.value) return true
|
||||
if (!currentSkin.value) return false
|
||||
if (variant.value !== currentSkin.value.variant) return true
|
||||
if ((selectedCape.value?.id || null) !== (currentSkin.value.cape_id || null)) return true
|
||||
return false
|
||||
})
|
||||
|
||||
const disableSave = computed(() =>
|
||||
(mode.value === 'new' && !fileUploadTextureBlob.value) ||
|
||||
(mode.value === 'edit' && !hasEdits.value)
|
||||
);
|
||||
const disableSave = computed(
|
||||
() =>
|
||||
(mode.value === 'new' && !fileUploadTextureBlob.value) ||
|
||||
(mode.value === 'edit' && !hasEdits.value),
|
||||
)
|
||||
|
||||
const saveTooltip = computed(() => {
|
||||
if (mode.value === 'new' && !fileUploadTextureBlob.value) return 'Upload a skin first!';
|
||||
if (mode.value === 'edit' && !hasEdits.value) return 'Make an edit to the skin first!';
|
||||
return undefined;
|
||||
});
|
||||
if (mode.value === 'new' && !fileUploadTextureBlob.value) return 'Upload a skin first!'
|
||||
if (mode.value === 'edit' && !hasEdits.value) return 'Make an edit to the skin first!'
|
||||
return undefined
|
||||
})
|
||||
|
||||
function resetState() {
|
||||
mode.value = 'new'
|
||||
@@ -218,7 +226,7 @@ function show(e: MouseEvent, skin?: Skin) {
|
||||
currentSkin.value = skin ?? null
|
||||
if (skin) {
|
||||
variant.value = skin.variant
|
||||
selectedCape.value = props.capes?.find(c=>c.id===skin.cape_id)
|
||||
selectedCape.value = props.capes?.find((c) => c.id === skin.cape_id)
|
||||
} else {
|
||||
variant.value = 'CLASSIC'
|
||||
selectedCape.value = undefined
|
||||
@@ -243,7 +251,7 @@ function showNew(e: MouseEvent, skinTexture: Uint8Array, filename: string) {
|
||||
function restoreWithNewTexture(skinTexture: Uint8Array, filename: string) {
|
||||
fileUploadTextureBlob.value = skinTexture
|
||||
fileName.value = filename
|
||||
|
||||
|
||||
if (shouldRestoreModal.value) {
|
||||
setTimeout(() => {
|
||||
modal.value?.show()
|
||||
@@ -257,12 +265,12 @@ function hide() {
|
||||
setTimeout(() => resetState(), 250)
|
||||
}
|
||||
|
||||
function selectCape(cape: Cape|undefined) {
|
||||
function selectCape(cape: Cape | undefined) {
|
||||
if (cape && selectedCape.value?.id !== cape.id) {
|
||||
const isInVisibleList = visibleCapeList.value.some(c => c.id === cape.id)
|
||||
const isInVisibleList = visibleCapeList.value.some((c) => c.id === cape.id)
|
||||
if (!isInVisibleList && visibleCapeList.value.length > 0) {
|
||||
visibleCapeList.value.splice(0, 1, cape)
|
||||
|
||||
|
||||
if (visibleCapeList.value.length > 1 && visibleCapeList.value[1].id === cape.id) {
|
||||
const otherCape = getSortedCapeExcluding(cape.id)
|
||||
if (otherCape) {
|
||||
@@ -306,7 +314,7 @@ function openSelectCapeModal(e: MouseEvent) {
|
||||
currentSkin.value?.texture_key,
|
||||
selectedCape.value,
|
||||
previewSkin.value,
|
||||
variant.value
|
||||
variant.value,
|
||||
)
|
||||
}, 0)
|
||||
}
|
||||
@@ -329,7 +337,7 @@ async function save() {
|
||||
blob = new Uint8Array(buf)
|
||||
}
|
||||
|
||||
await unequip_skin();
|
||||
await unequip_skin()
|
||||
|
||||
if (mode.value === 'new') {
|
||||
await add_and_equip_custom_skin(blob, variant.value, selectedCape.value)
|
||||
@@ -346,9 +354,13 @@ async function save() {
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => props.capes, () => {
|
||||
initVisibleCapeList()
|
||||
}, { immediate: true })
|
||||
watch(
|
||||
() => props.capes,
|
||||
() => {
|
||||
initVisibleCapeList()
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'saved'): void
|
||||
@@ -361,6 +373,6 @@ defineExpose({
|
||||
showNew,
|
||||
restoreWithNewTexture,
|
||||
hide,
|
||||
shouldRestoreModal
|
||||
shouldRestoreModal,
|
||||
})
|
||||
</script>
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
CapeButton,
|
||||
CapeLikeTextButton,
|
||||
SkinPreviewRenderer,
|
||||
NewModal
|
||||
NewModal,
|
||||
} from '@modrinth/ui'
|
||||
import { CheckIcon, XIcon } from '@modrinth/assets'
|
||||
|
||||
@@ -24,11 +24,11 @@ const props = defineProps<{
|
||||
|
||||
const sortedCapes = computed(() => {
|
||||
return [...props.capes].sort((a, b) => {
|
||||
const nameA = (a.name || '').toLowerCase();
|
||||
const nameB = (b.name || '').toLowerCase();
|
||||
return nameA.localeCompare(nameB);
|
||||
});
|
||||
});
|
||||
const nameA = (a.name || '').toLowerCase()
|
||||
const nameB = (b.name || '').toLowerCase()
|
||||
return nameA.localeCompare(nameB)
|
||||
})
|
||||
})
|
||||
|
||||
const currentSkinId = ref<string | undefined>()
|
||||
const currentSkinTexture = ref<string | undefined>()
|
||||
@@ -93,7 +93,7 @@ defineExpose({
|
||||
:variant="currentSkinVariant"
|
||||
:scale="1.4"
|
||||
:fov="50"
|
||||
:initial-rotation="Math.PI + (Math.PI / 8)"
|
||||
:initial-rotation="Math.PI + Math.PI / 8"
|
||||
class="h-full w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<NewModal ref="modal" @on-hide="hide(true)">
|
||||
<template #title>
|
||||
<span class="text-lg font-extrabold text-contrast">
|
||||
Upload skin texture
|
||||
</span>
|
||||
<span class="text-lg font-extrabold text-contrast"> Upload skin texture </span>
|
||||
</template>
|
||||
<div class="relative">
|
||||
<div
|
||||
@@ -12,10 +10,22 @@
|
||||
@drop.prevent="handleFileOperation"
|
||||
@dragover.prevent
|
||||
>
|
||||
<p class="mx-auto mb-0 text-primary text-xl text-center flex items-center gap-2"><UploadIcon /> Select skin texture file</p>
|
||||
<p class="mx-auto mt-0 text-secondary text-sm text-center">Drag and drop or click here to browse</p>
|
||||
<p class="mx-auto mt-0 text-secondary text-xs text-center">Only 64x64 PNG files are accepted</p>
|
||||
<input ref="fileInput" type="file" accept="image/png" class="hidden" @change="handleFileOperation" />
|
||||
<p class="mx-auto mb-0 text-primary text-xl text-center flex items-center gap-2">
|
||||
<UploadIcon /> Select skin texture file
|
||||
</p>
|
||||
<p class="mx-auto mt-0 text-secondary text-sm text-center">
|
||||
Drag and drop or click here to browse
|
||||
</p>
|
||||
<p class="mx-auto mt-0 text-secondary text-xs text-center">
|
||||
Only 64x64 PNG files are accepted
|
||||
</p>
|
||||
<input
|
||||
ref="fileInput"
|
||||
type="file"
|
||||
accept="image/png"
|
||||
class="hidden"
|
||||
@change="handleFileOperation"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</NewModal>
|
||||
@@ -24,7 +34,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { UploadIcon } from '@modrinth/assets'
|
||||
import { useNotifications } from "@/store/state"
|
||||
import { useNotifications } from '@/store/state'
|
||||
import { NewModal } from '@modrinth/ui'
|
||||
|
||||
const notifications = useNotifications()
|
||||
@@ -71,30 +81,30 @@ async function validateImageDimensions(file: File): Promise<boolean> {
|
||||
|
||||
async function handleFileOperation(e: Event | DragEvent) {
|
||||
// Get files from either drag event or file input
|
||||
const files = (e as DragEvent).dataTransfer?.files || (e.target as HTMLInputElement).files;
|
||||
const files = (e as DragEvent).dataTransfer?.files || (e.target as HTMLInputElement).files
|
||||
if (!files || files.length === 0) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
const file = files[0];
|
||||
const file = files[0]
|
||||
if (file.type !== 'image/png') {
|
||||
notifications.addNotification({
|
||||
title: 'Invalid file type.',
|
||||
text: 'Only PNG files are accepted.',
|
||||
type: 'error',
|
||||
});
|
||||
return;
|
||||
})
|
||||
return
|
||||
}
|
||||
const isValidDimensions = await validateImageDimensions(file);
|
||||
const isValidDimensions = await validateImageDimensions(file)
|
||||
if (!isValidDimensions) {
|
||||
notifications.addNotification({
|
||||
title: 'Invalid dimensions.',
|
||||
text: 'Only 64x64 PNG files are accepted.',
|
||||
type: 'error',
|
||||
});
|
||||
return;
|
||||
})
|
||||
return
|
||||
}
|
||||
emit('uploaded', file);
|
||||
hide();
|
||||
emit('uploaded', file)
|
||||
hide()
|
||||
}
|
||||
|
||||
defineExpose({ show, hide })
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import { UpdatedIcon, PlusIcon, ExcitedRinthbot, LogInIcon, SpinnerIcon, EditIcon, TrashIcon } from '@modrinth/assets'
|
||||
import {
|
||||
UpdatedIcon,
|
||||
PlusIcon,
|
||||
ExcitedRinthbot,
|
||||
LogInIcon,
|
||||
SpinnerIcon,
|
||||
EditIcon,
|
||||
TrashIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
SkinPreviewRenderer,
|
||||
SkinButton,
|
||||
SkinLikeTextButton,
|
||||
Button,
|
||||
ConfirmModal
|
||||
ConfirmModal,
|
||||
} from '@modrinth/ui'
|
||||
import type { Ref } from 'vue';
|
||||
import type { Ref } from 'vue'
|
||||
import { ref, computed, useTemplateRef, watch, onMounted, onUnmounted, inject } from 'vue'
|
||||
import EditSkinModal from '@/components/ui/skin/EditSkinModal.vue'
|
||||
import SelectCapeModal from '@/components/ui/skin/SelectCapeModal.vue'
|
||||
@@ -28,9 +36,9 @@ import type { Cape, Skin } from '@/helpers/skins.ts'
|
||||
import { get_default_user, users, login as login_flow } from '@/helpers/auth'
|
||||
import type { RenderResult } from '@/helpers/rendering/batchSkinRenderer.ts'
|
||||
import { generateSkinPreviews, map } from '@/helpers/rendering/batchSkinRenderer.ts'
|
||||
import { handleSevereError } from "@/store/error";
|
||||
import { trackEvent } from "@/helpers/analytics";
|
||||
import type AccountsCard from "@/components/ui/AccountsCard.vue";
|
||||
import { handleSevereError } from '@/store/error'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import type AccountsCard from '@/components/ui/AccountsCard.vue'
|
||||
|
||||
const editSkinModal = useTemplateRef('editSkinModal')
|
||||
const selectCapeModal = useTemplateRef('selectCapeModal')
|
||||
@@ -64,7 +72,9 @@ const currentCape = computed(() => {
|
||||
const skinTexture = computed(() => selectedSkin.value?.texture ?? '')
|
||||
const capeTexture = computed(() => currentCape.value?.texture)
|
||||
const skinVariant = computed(() => selectedSkin.value?.variant)
|
||||
const skinNametag = computed(() => settings.value.hide_nametag_skins_page ? undefined : username.value)
|
||||
const skinNametag = computed(() =>
|
||||
settings.value.hide_nametag_skins_page ? undefined : username.value,
|
||||
)
|
||||
|
||||
let userCheckInterval: number | null = null
|
||||
|
||||
@@ -141,7 +151,7 @@ function getBakedSkinTextures(skin: Skin): RenderResult | undefined {
|
||||
}
|
||||
|
||||
async function login() {
|
||||
accountsCard.value.setLoginDisabled(true);
|
||||
accountsCard.value.setLoginDisabled(true)
|
||||
const loggedIn = await login_flow().catch(handleSevereError)
|
||||
|
||||
if (loggedIn && accountsCard) {
|
||||
@@ -149,7 +159,7 @@ async function login() {
|
||||
}
|
||||
|
||||
trackEvent('AccountLogIn')
|
||||
accountsCard.value.setLoginDisabled(false);
|
||||
accountsCard.value.setLoginDisabled(false)
|
||||
}
|
||||
|
||||
function openUploadSkinModal(e: MouseEvent) {
|
||||
@@ -158,9 +168,9 @@ function openUploadSkinModal(e: MouseEvent) {
|
||||
|
||||
function onSkinFileUploaded(file: File) {
|
||||
const fakeEvent = new MouseEvent('click')
|
||||
file.arrayBuffer().then(buf => {
|
||||
file.arrayBuffer().then((buf) => {
|
||||
const skinTexture = new Uint8Array(buf)
|
||||
|
||||
|
||||
if (editSkinModal.value && editSkinModal.value.shouldRestoreModal) {
|
||||
editSkinModal.value.restoreWithNewTexture(skinTexture, file.name)
|
||||
} else {
|
||||
@@ -181,16 +191,16 @@ function onUploadCanceled() {
|
||||
|
||||
watch(
|
||||
() => selectedSkin.value?.cape_id,
|
||||
() => {}
|
||||
() => {},
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
userCheckInterval = window.setInterval(checkUserChanges, 250);
|
||||
userCheckInterval = window.setInterval(checkUserChanges, 250)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (userCheckInterval !== null) {
|
||||
window.clearInterval(userCheckInterval);
|
||||
window.clearInterval(userCheckInterval)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -198,9 +208,9 @@ async function checkUserChanges() {
|
||||
try {
|
||||
const defaultId = await get_default_user()
|
||||
if (defaultId !== currentUserId.value) {
|
||||
await loadCurrentUser();
|
||||
await loadCapes();
|
||||
await loadSkins();
|
||||
await loadCurrentUser()
|
||||
await loadCapes()
|
||||
await loadSkins()
|
||||
}
|
||||
} catch (error) {
|
||||
if (currentUser.value) {
|
||||
@@ -221,7 +231,11 @@ await Promise.all([loadCapes(), loadSkins(), loadCurrentUser()])
|
||||
@open-upload-modal="openUploadSkinModal"
|
||||
/>
|
||||
<SelectCapeModal ref="selectCapeModal" :capes="capes" @select="handleCapeSelected" />
|
||||
<UploadSkinModal ref="uploadSkinModal" @uploaded="onSkinFileUploaded" @canceled="onUploadCanceled" />
|
||||
<UploadSkinModal
|
||||
ref="uploadSkinModal"
|
||||
@uploaded="onSkinFileUploaded"
|
||||
@canceled="onUploadCanceled"
|
||||
/>
|
||||
<ConfirmModal
|
||||
ref="deleteSkinModal"
|
||||
title="Are you sure you want to delete this skin?"
|
||||
@@ -237,20 +251,21 @@ await Promise.all([loadCapes(), loadSkins(), loadCurrentUser()])
|
||||
<ButtonStyled :disabled="!!selectedSkin?.cape_id">
|
||||
<button
|
||||
v-tooltip="
|
||||
selectedSkin?.cape_id
|
||||
? 'The equipped skin is overriding the default cape.'
|
||||
: undefined
|
||||
"
|
||||
selectedSkin?.cape_id
|
||||
? 'The equipped skin is overriding the default cape.'
|
||||
: undefined
|
||||
"
|
||||
:disabled="!!selectedSkin?.cape_id"
|
||||
@click="
|
||||
(e: MouseEvent) => selectCapeModal?.show(
|
||||
e,
|
||||
selectedSkin?.texture_key,
|
||||
currentCape,
|
||||
skinTexture,
|
||||
skinVariant
|
||||
)
|
||||
"
|
||||
(e: MouseEvent) =>
|
||||
selectCapeModal?.show(
|
||||
e,
|
||||
selectedSkin?.texture_key,
|
||||
currentCape,
|
||||
skinTexture,
|
||||
skinVariant,
|
||||
)
|
||||
"
|
||||
>
|
||||
<UpdatedIcon />
|
||||
Change cape
|
||||
@@ -275,15 +290,11 @@ await Promise.all([loadCapes(), loadSkins(), loadCurrentUser()])
|
||||
<section class="flex flex-col gap-2 mt-1">
|
||||
<h2 class="text-lg font-bold m-0 text-primary">Saved skins</h2>
|
||||
<div class="skin-card-grid">
|
||||
<SkinLikeTextButton
|
||||
class="skin-card"
|
||||
tooltip="Add a skin"
|
||||
@click="openUploadSkinModal"
|
||||
>
|
||||
<template #icon>
|
||||
<PlusIcon class="w-5 h-5 stroke-2" />
|
||||
</template>
|
||||
<span>Add a skin</span>
|
||||
<SkinLikeTextButton class="skin-card" tooltip="Add a skin" @click="openUploadSkinModal">
|
||||
<template #icon>
|
||||
<PlusIcon class="w-5 h-5 stroke-2" />
|
||||
</template>
|
||||
<span>Add a skin</span>
|
||||
</SkinLikeTextButton>
|
||||
|
||||
<SkinButton
|
||||
@@ -296,24 +307,24 @@ await Promise.all([loadCapes(), loadSkins(), loadCurrentUser()])
|
||||
@select="changeSkin(skin)"
|
||||
>
|
||||
<template #overlay-buttons>
|
||||
<Button
|
||||
color="green"
|
||||
aria-label="Edit skin"
|
||||
@click.stop="(e) => editSkinModal?.show(e, skin)"
|
||||
>
|
||||
<EditIcon class="w-5 h-5" /> Edit
|
||||
</Button>
|
||||
<Button
|
||||
v-show="!skin.is_equipped"
|
||||
v-tooltip="'Delete skin'"
|
||||
aria-label="Delete skin"
|
||||
color="red"
|
||||
class="!rounded-[100%]"
|
||||
icon-only
|
||||
@click.stop="() => confirmDeleteSkin(skin)"
|
||||
>
|
||||
<TrashIcon class="w-5 h-5" />
|
||||
</Button>
|
||||
<Button
|
||||
color="green"
|
||||
aria-label="Edit skin"
|
||||
@click.stop="(e) => editSkinModal?.show(e, skin)"
|
||||
>
|
||||
<EditIcon class="w-5 h-5" /> Edit
|
||||
</Button>
|
||||
<Button
|
||||
v-show="!skin.is_equipped"
|
||||
v-tooltip="'Delete skin'"
|
||||
aria-label="Delete skin"
|
||||
color="red"
|
||||
class="!rounded-[100%]"
|
||||
icon-only
|
||||
@click.stop="() => confirmDeleteSkin(skin)"
|
||||
>
|
||||
<TrashIcon class="w-5 h-5" />
|
||||
</Button>
|
||||
</template>
|
||||
</SkinButton>
|
||||
</div>
|
||||
@@ -338,14 +349,32 @@ await Promise.all([loadCapes(), loadSkins(), loadCurrentUser()])
|
||||
</div>
|
||||
|
||||
<div v-else class="flex items-center justify-center min-h-[50vh] pt-[25%]">
|
||||
<div class="bg-bg-raised rounded-lg p-7 flex flex-col gap-5 shadow-md relative max-w-xl w-full mx-auto">
|
||||
<img :src="ExcitedRinthbot" alt="Excited Modrinth Bot" class="absolute -top-28 right-8 md:right-20 h-28 w-auto" />
|
||||
<div class="absolute top-0 left-0 w-full h-[1px] opacity-40 bg-gradient-to-r from-transparent via-green-500 to-transparent" style="background: linear-gradient(to right, transparent 2rem, var(--color-green) calc(100% - 13rem), var(--color-green) calc(100% - 5rem), transparent calc(100% - 2rem))"></div>
|
||||
<div
|
||||
class="bg-bg-raised rounded-lg p-7 flex flex-col gap-5 shadow-md relative max-w-xl w-full mx-auto"
|
||||
>
|
||||
<img
|
||||
:src="ExcitedRinthbot"
|
||||
alt="Excited Modrinth Bot"
|
||||
class="absolute -top-28 right-8 md:right-20 h-28 w-auto"
|
||||
/>
|
||||
<div
|
||||
class="absolute top-0 left-0 w-full h-[1px] opacity-40 bg-gradient-to-r from-transparent via-green-500 to-transparent"
|
||||
style="
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
transparent 2rem,
|
||||
var(--color-green) calc(100% - 13rem),
|
||||
var(--color-green) calc(100% - 5rem),
|
||||
transparent calc(100% - 2rem)
|
||||
);
|
||||
"
|
||||
></div>
|
||||
|
||||
<div class="flex flex-col gap-5">
|
||||
<h1 class="text-3xl font-extrabold m-0">Please sign-in</h1>
|
||||
<p class="text-lg m-0">
|
||||
Please sign into your Minecraft account to use the skin management features of the Modrinth app.
|
||||
Please sign into your Minecraft account to use the skin management features of the
|
||||
Modrinth app.
|
||||
</p>
|
||||
<ButtonStyled v-show="accountsCard" color="brand" :disabled="accountsCard.loginDisabled">
|
||||
<Button :disabled="accountsCard.loginDisabled" @click="login">
|
||||
|
||||
Reference in new issue
Block a user