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.
85 lines
2.4 KiB
Vue
85 lines
2.4 KiB
Vue
<script setup>
|
|
import { mdiCog } from '@mdi/js';
|
|
import { computed, useSlots } from 'vue';
|
|
import BaseIcon from '@/Components/BaseIcon.vue';
|
|
|
|
const props = defineProps({
|
|
title: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
icon: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
showHeaderIcon: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
headerIcon: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
rounded: {
|
|
type: String,
|
|
default: 'rounded-xl',
|
|
},
|
|
hasFormData: Boolean,
|
|
empty: Boolean,
|
|
form: Boolean,
|
|
hoverable: Boolean,
|
|
modal: Boolean,
|
|
});
|
|
|
|
const emit = defineEmits(['header-icon-click', 'submit']);
|
|
|
|
const is = computed(() => (props.form ? 'form' : 'div'));
|
|
|
|
const slots = useSlots();
|
|
|
|
const footer = computed(() => slots.footer && !!slots.footer());
|
|
|
|
const componentClass = computed(() => {
|
|
const base = [props.rounded, props.modal ? 'dark:bg-slate-900' : 'dark:bg-slate-900/70'];
|
|
|
|
if (props.hoverable) {
|
|
base.push('hover:shadow-lg transition-shadow duration-500');
|
|
}
|
|
|
|
return base;
|
|
});
|
|
|
|
const computedHeaderIcon = computed(() => props.headerIcon ?? mdiCog);
|
|
|
|
const headerIconClick = () => {
|
|
emit('header-icon-click');
|
|
};
|
|
|
|
const submit = (e) => {
|
|
emit('submit', e);
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<component :is="is" :class="componentClass" class="bg-white flex flex-col" @submit="submit">
|
|
<header v-if="title" class="flex items-stretch border-b border-gray-100 dark:border-slate-800">
|
|
<div class="flex items-center py-3 grow font-bold" :class="[icon ? 'px-4' : 'px-6']">
|
|
<BaseIcon v-if="icon" :path="icon" class="mr-3" />
|
|
{{ title }}
|
|
</div>
|
|
<button v-if="showHeaderIcon" class="flex items-center py-3 px-4 justify-center ring-blue-700 focus:ring" @click="headerIconClick">
|
|
<BaseIcon :path="computedHeaderIcon" />
|
|
</button>
|
|
</header>
|
|
<div v-if="empty" class="text-center py-24 text-gray-500 dark:text-slate-400">
|
|
<p>Nothing's here…</p>
|
|
</div>
|
|
<!-- <div v-else class="flex-1" :class="{'p-6':!hasTable}"> -->
|
|
<div v-else class="flex-1" :class="[!hasFormData && 'p-6']">
|
|
<slot />
|
|
</div>
|
|
<div v-if="footer" class="p-6 border-t border-gray-100 dark:border-slate-800">
|
|
<slot name="footer" />
|
|
</div>
|
|
</component>
|
|
</template>
|