[codex] add customizable profile avatars (#870)
* add customizable profile avatars * keep profile avatar visible when sidebar collapses * simplify collapsed profile avatar styling * force managed gateway startup in docker * limit gateway autostart to active profile * restore all profile gateway autostart * fix managed gateway runtime detection
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import multiavatar from '@multiavatar/multiavatar'
|
||||
import type { ProfileAvatar } from '@/api/hermes/profiles'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
name: string
|
||||
avatar?: ProfileAvatar | null
|
||||
size?: number
|
||||
}>(), {
|
||||
size: 24,
|
||||
})
|
||||
|
||||
const fallbackSeed = computed(() => props.name || 'default')
|
||||
const generatedSvg = computed(() => multiavatar(props.avatar?.seed || fallbackSeed.value))
|
||||
const style = computed(() => ({
|
||||
width: `${props.size}px`,
|
||||
height: `${props.size}px`,
|
||||
flexBasis: `${props.size}px`,
|
||||
}))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span class="profile-avatar-view" :style="style">
|
||||
<img
|
||||
v-if="avatar?.type === 'image' && avatar.dataUrl"
|
||||
class="profile-avatar-image"
|
||||
:src="avatar.dataUrl"
|
||||
alt=""
|
||||
draggable="false"
|
||||
>
|
||||
<span v-else class="profile-avatar-svg" v-html="generatedSvg" />
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.profile-avatar-view {
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
.profile-avatar-image,
|
||||
.profile-avatar-svg,
|
||||
.profile-avatar-svg :deep(svg) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.profile-avatar-image {
|
||||
object-fit: cover;
|
||||
}
|
||||
</style>
|
||||
@@ -4,6 +4,7 @@ import { NButton, NTag, NSpin, useMessage, useDialog } from 'naive-ui'
|
||||
import type { HermesProfile, HermesProfileDetail } from '@/api/hermes/profiles'
|
||||
import { useProfilesStore } from '@/stores/hermes/profiles'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import ProfileAvatar from './ProfileAvatar.vue'
|
||||
|
||||
const props = defineProps<{ profile: HermesProfile }>()
|
||||
const emit = defineEmits<{}>()
|
||||
@@ -86,7 +87,10 @@ async function handleExport() {
|
||||
<template>
|
||||
<div class="profile-card" :class="{ active: profile.active }">
|
||||
<div class="card-header">
|
||||
<h3 class="profile-name">{{ profile.name }}</h3>
|
||||
<div class="profile-title">
|
||||
<ProfileAvatar :name="profile.name" :avatar="profile.avatar" :size="28" />
|
||||
<h3 class="profile-name">{{ profile.name }}</h3>
|
||||
</div>
|
||||
<NTag v-if="profile.active" size="tiny" type="success" :bordered="false">
|
||||
{{ t('profiles.active') }}
|
||||
</NTag>
|
||||
@@ -188,9 +192,17 @@ async function handleExport() {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.profile-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.profile-name {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
@@ -198,7 +210,8 @@ async function handleExport() {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 70%;
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
|
||||
Reference in New Issue
Block a user