All checks were successful
CI / container-job (push) Successful in 41s
- adonisrc.ts: Load official drive_provider and unload custom driver_provider. - packages.json: Add @headlessui/vue dependency for tab components. - AvatarController.ts: Rewrite avatar generation logic to always return the same avatar per user. - auth/UserController.ts: Add profile and profileUpdate methods to support user profile editing. - Submitter/datasetController.ts & app/models/file.ts: Adapt code to use the official drive_provider. - app/models/user.ts: Introduce “isAdmin” getter. - config/drive.ts: Create new configuration for the official drive_provider. - providers/vinejs_provider.ts: Adapt allowedExtensions control to use provided options or database enabled extensions. - resource/js/app.ts: Load default Head and Link components. - resources/js/menu.ts: Add settings-profile.edit menu point. - resources/js/Components/action-message.vue: Add new component for improved user feedback after form submissions. - New avatar-input.vue component: Enable profile picture selection. - Components/CardBox.vue: Alter layout to optionally show HeaderIcon in title bar. - FormControl.vue: Define a readonly prop for textareas. - Improve overall UI with updates to NavBar.vue, UserAvatar.vue, UserAvatarCurrentUser.vue, and add v-model support to password-meter.vue. - Remove profile editing logic from AccountInfo.vue and introduce new profile components (show.vue, update-password-form.vue, update-profile-information.vue). - app.edge: Modify page (add @inertiaHead tag) for better meta management. - routes.ts: Add new routes for editing user profiles. - General npm updates.
79 lines
2.5 KiB
Vue
79 lines
2.5 KiB
Vue
<template>
|
|
<div class="relative inline-block overflow-hidden rounded-full">
|
|
<input type="file" ref="avatarInput" @change="onChangeFile" class="hidden" accept="image/*">
|
|
|
|
<img :src="avatarUrl" alt="Avatar" class="h-full w-full object-cover">
|
|
<div class="absolute top-0 h-full w-full bg-black bg-opacity-25 flex items-center justify-center">
|
|
<button @click.prevent="browse"
|
|
class="rounded-full hover:bg-white hover:bg-opacity-25 p-2 focus:outline-none text-white transition-colors duration-300">
|
|
<IconRounded :icon="mdiCameraEnhanceOutline" class="bg-transparent h-6 w-6" />
|
|
</button>
|
|
<button v-if="file" @click.prevent="reset"
|
|
class="rounded-full hover:bg-white hover:bg-opacity-25 p-2 focus:outline-none text-white transition-colors duration-300">
|
|
<IconRounded :icon="mdiAlphaXCircleOutline " class="bg-transparent h-6 w-6" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, defineProps, defineEmits } from 'vue';
|
|
import { mdiCameraEnhanceOutline, mdiAlphaXCircleOutline } from '@mdi/js';
|
|
import IconRounded from './IconRounded.vue';
|
|
|
|
const props = defineProps({
|
|
|
|
modelValue: File,
|
|
defaultSrc: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
});
|
|
|
|
// vue data properties
|
|
const file = ref<File | null>(null);
|
|
const avatarUrl = ref<string>(props.defaultSrc);
|
|
const avatarInput = ref<HTMLInputElement | null>(null);
|
|
|
|
|
|
// const avatarUrl = computed({
|
|
// get: () => props.modelValue ? props.modelValue : props.defaultSrc,
|
|
// set: (value: string) => {
|
|
// emit('update:modelValue', value);
|
|
// },
|
|
// });
|
|
|
|
|
|
const emit = defineEmits<{ (e: 'update:modelValue', file: File | null): void; (e: 'input', file: File | null): void }>();
|
|
|
|
// const avatarInput = ref<HTMLInputElement | null>(null);
|
|
|
|
const browse = () => {
|
|
avatarInput.value?.click();
|
|
};
|
|
|
|
const reset = () => {
|
|
file.value = null;
|
|
avatarUrl.value = props.defaultSrc;
|
|
emit('input', file.value);
|
|
};
|
|
|
|
const onChangeFile = (e: Event) => {
|
|
// const target = (<HTMLInputElement>e.target)
|
|
const target = e.target as HTMLInputElement;
|
|
if (target.files && target.files[0]) {
|
|
file.value = target.files[0];
|
|
}
|
|
if (file.value) {
|
|
emit('input', file.value);
|
|
emit('update:modelValue', file.value);
|
|
let reader = new FileReader();
|
|
reader.readAsDataURL(file.value);
|
|
reader.onload = (e) => {
|
|
avatarUrl.value = e.target?.result as string;
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
</script>
|