feat: Integrate official drive_provider, update user profile features & UI improvements
All checks were successful
CI / container-job (push) Successful in 41s
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.
This commit is contained in:
parent
a41b091214
commit
36cd7a757b
34 changed files with 1396 additions and 407 deletions
|
@ -6,9 +6,9 @@ const props = defineProps({
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
avatar: {
|
||||
defaultUrl: {
|
||||
type: String,
|
||||
default: null,
|
||||
required: false
|
||||
},
|
||||
api: {
|
||||
type: String,
|
||||
|
@ -16,58 +16,37 @@ const props = defineProps({
|
|||
},
|
||||
});
|
||||
|
||||
const avatar = computed(
|
||||
// () => props.avatar ?? `https://avatars.dicebear.com/api/${props.api}/${props.username?.replace(/[^a-z0-9]+/i, '-')}.svg`
|
||||
|
||||
// () => props.avatar ?? `https://avatars.dicebear.com/api/initials/${props.username}.svg`,
|
||||
|
||||
() => {
|
||||
const initials = props.username
|
||||
.split(' ')
|
||||
.map((part) => part.charAt(0).toUpperCase())
|
||||
.join('');
|
||||
|
||||
return props.avatar ?? generateAvatarUrl(props.username);
|
||||
},
|
||||
);
|
||||
const avatar = computed(() => {
|
||||
return props.defaultUrl ?? generateAvatarUrl(props.username);
|
||||
});
|
||||
|
||||
const username = computed(() => props.username);
|
||||
|
||||
const darkenColor = (color) => {
|
||||
// Convert hex to RGB
|
||||
const r = parseInt(color.slice(0, 2), 16);
|
||||
const g = parseInt(color.slice(2, 4), 16);
|
||||
const b = parseInt(color.slice(4, 6), 16);
|
||||
|
||||
// Calculate darker color by reducing 20% of each RGB component
|
||||
const darkerR = Math.round(r * 0.6);
|
||||
const darkerG = Math.round(g * 0.6);
|
||||
const darkerB = Math.round(b * 0.6);
|
||||
|
||||
// Convert back to hex
|
||||
const darkerColor = ((darkerR << 16) + (darkerG << 8) + darkerB).toString(16);
|
||||
|
||||
return darkerColor.padStart(6, '0'); // Ensure it's 6 digits
|
||||
return darkerColor.padStart(6, '0');
|
||||
};
|
||||
|
||||
const getRandomColor = () => {
|
||||
return Math.floor(Math.random() * 16777215).toString(16);
|
||||
};
|
||||
|
||||
const adjustOpacity = (hexColor, opacity) => {
|
||||
// Remove # if present
|
||||
hexColor = hexColor.replace('#', '');
|
||||
// Convert hex to RGB
|
||||
// const r = parseInt(hexColor.slice(0, 2), 16);
|
||||
// const g = parseInt(hexColor.slice(2, 4), 16);
|
||||
// const b = parseInt(hexColor.slice(4, 6), 16);
|
||||
|
||||
// const r = parseInt(hexColor.slice(1, 3), 16);
|
||||
// const g = parseInt(hexColor.slice(3, 5), 16);
|
||||
// const b = parseInt(hexColor.slice(5, 7), 16);
|
||||
const [r, g, b] = hexColor.match(/\w\w/g).map(x => parseInt(x, 16));
|
||||
|
||||
return `rgba(${r},${g},${b},${opacity})`;
|
||||
const getColorFromName = (name) => {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < name.length; i++) {
|
||||
hash = name.charCodeAt(i) + ((hash << 5) - hash);
|
||||
}
|
||||
let color = '#';
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const value = (hash >> (i * 8)) & 0xff;
|
||||
color += ('00' + value.toString(16)).substr(-2);
|
||||
}
|
||||
return color.replace('#', '');
|
||||
};
|
||||
|
||||
const lightenColor = (hexColor, percent) => {
|
||||
|
@ -88,21 +67,12 @@ const lightenColor = (hexColor, percent) => {
|
|||
return lighterHex.padStart(6, '0');
|
||||
};
|
||||
|
||||
// backgroundColor = '7F9CF5',
|
||||
const generateAvatarUrl = (name) => {
|
||||
const initials = name
|
||||
.split(' ')
|
||||
.map((part) => part.charAt(0).toUpperCase())
|
||||
.join('');
|
||||
|
||||
const originalColor = getRandomColor();
|
||||
|
||||
const backgroundColor = lightenColor(originalColor, 60); // Lighten by 20%
|
||||
|
||||
const originalColor = getColorFromName(name);
|
||||
const backgroundColor = lightenColor(originalColor, 60);
|
||||
const textColor = darkenColor(originalColor);
|
||||
|
||||
// const avatarUrl = `https://ui-avatars.com/api/?name=${initials}&size=50&background=${backgroundColor}&color=${textColor}`;
|
||||
const avatarUrl = `/api/avatar?name=${name}&size=50&background=${backgroundColor}&textColor=${textColor}`;
|
||||
const avatarUrl = `/api/avatar?name=${name}&size=50`;
|
||||
return avatarUrl;
|
||||
};
|
||||
</script>
|
||||
|
|
Loading…
Add table
editor.link_modal.header
Reference in a new issue