Skip to content

Commit 314ca43

Browse files
committed
refactor(profile): Change upload component
1 parent 2d437af commit 314ca43

File tree

4 files changed

+97
-18
lines changed

4 files changed

+97
-18
lines changed

components/Account/Profile.vue

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
<template>
22
<div>
3-
<n-upload
4-
class="overflow-hidden w-min mx-auto my-4"
5-
list-type="image-card"
6-
:max="1"
7-
accept="image/*"
8-
:custom-request="(e) => file = e.file.file"
9-
>
10-
<img v-if="model.picture" :src="model.picture" class="object-cover">
11-
</n-upload>
3+
<ImageUpload
4+
ref="uploadRef"
5+
class="mx-auto shadow hover:shadow-lg border-blue-300 border-2"
6+
:src="model.picture"
7+
:width="180"
8+
@select="(f)=> model.file=f"
9+
/>
1210

1311
<n-form ref="formRef" @submit.prevent="onSubmit(updateAccount)">
1412
<n-form-item label="Name">
1513
<n-input v-model:value="model.name" />
1614
</n-form-item>
1715

18-
<FormButtons :loading="pending" :disabled="pending" @reset="reset" />
16+
<FormButtons :loading="pending" :disabled="pending || !edited" @reset="handleReset" />
1917
</n-form>
2018
</div>
2119
</template>
@@ -25,23 +23,29 @@ const { user } = useAuthSession()
2523
const { upload } = useS3Object()
2624
const { fetchUser } = useAuth()
2725
26+
const uploadRef = ref()
27+
2828
const model = ref({
2929
name: user.value?.name,
30-
picture: user.value?.picture
30+
picture: user.value?.picture,
31+
file: undefined
3132
})
3233
33-
const { formRef, pending, onSubmit, reset } = useNaiveForm(model)
34-
35-
const file = ref<File | null>()
34+
const { edited, formRef, pending, onSubmit, reset } = useNaiveForm(model)
3635
3736
const loading = ref(false)
3837
38+
function handleReset () {
39+
uploadRef.value.reset()
40+
reset()
41+
}
42+
3943
async function updateAccount () {
4044
try {
4145
loading.value = true
4246
43-
if (file.value) {
44-
const url = await upload(file.value, {
47+
if (model.value.file) {
48+
const url = await upload(model.value.file, {
4549
url: model.value.picture,
4650
prefix: `image/${user.value!.id}/`
4751
})
@@ -54,7 +58,7 @@ async function updateAccount () {
5458
body: model.value
5559
})
5660
57-
file.value = null
61+
model.value.file = undefined
5862
5963
await fetchUser()
6064
} finally {

components/Form/Buttons.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<n-button type="primary" attr-type="submit" :loading="loading" :disabled="disabled">
44
Save
55
</n-button>
6-
<n-button secondary attr-type="button" :disabled="disabled" @click="$emit('reset')">
6+
<n-button secondary attr-type="reset" :disabled="disabled" @click="$emit('reset')">
77
Reset
88
</n-button>
99
</div>

components/Image/Upload.vue

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<template>
2+
<div class="relative rounded-full" :style="{width:`${width}px`}">
3+
<div class="absolute right-2 bottom-2 border-4 rounded-full" :style="{borderColor: theme.bodyColor}">
4+
<n-button circle type="primary" @click="()=>input?.click()">
5+
<template #icon>
6+
<naive-icon name="ph:camera" />
7+
</template>
8+
</n-button>
9+
</div>
10+
11+
<div class="overflow-hidden rounded-full" :style="{ height:`${width}px`}">
12+
<n-image
13+
class="h-full"
14+
:width="width"
15+
:src="image"
16+
:fallback-src="placeholder"
17+
object-fit="cover"
18+
/>
19+
</div>
20+
21+
<input
22+
ref="input"
23+
type="file"
24+
hidden
25+
accept="image/*"
26+
@change="onSelect"
27+
>
28+
</div>
29+
</template>
30+
31+
<script setup lang="ts">
32+
33+
const props = withDefaults(defineProps<{ src?: string, width?: number, placeholder?: string }>(), {
34+
src: '/images/placeholder.webp',
35+
placeholder: '/images/placeholder.webp',
36+
width: 150
37+
})
38+
39+
const emit = defineEmits(['select'])
40+
41+
const inputImage = computed(() => props.src)
42+
43+
const image = ref(inputImage.value)
44+
45+
const input = ref<HTMLInputElement>()
46+
47+
watch(inputImage, () => reset())
48+
49+
const theme = useThemeVars()
50+
51+
function reset () {
52+
image.value = inputImage.value
53+
}
54+
55+
function getBase64 (file:File):Promise<string | undefined> {
56+
return new Promise((resolve, reject) => {
57+
const reader = new FileReader()
58+
reader.readAsDataURL(file)
59+
reader.onload = () => resolve(reader.result?.toString())
60+
reader.onerror = error => reject(error)
61+
})
62+
}
63+
64+
async function onSelect (event:any) {
65+
const selectedFile = event.target.files[0]
66+
const selectedFileUrl = await getBase64(selectedFile)
67+
68+
if (selectedFileUrl) {
69+
image.value = selectedFileUrl
70+
emit('select', selectedFile)
71+
}
72+
}
73+
74+
defineExpose({ reset })
75+
</script>

public/images/placeholder.webp

3.44 KB
Loading

0 commit comments

Comments
 (0)