diff --git a/web-app/public/images/emoji/akarshan.png b/web-app/public/images/emoji/akarshan.png new file mode 100644 index 000000000..b0b573d3e Binary files /dev/null and b/web-app/public/images/emoji/akarshan.png differ diff --git a/web-app/public/images/emoji/alan.png b/web-app/public/images/emoji/alan.png new file mode 100644 index 000000000..8302524f4 Binary files /dev/null and b/web-app/public/images/emoji/alan.png differ diff --git a/web-app/public/images/emoji/alex.png b/web-app/public/images/emoji/alex.png new file mode 100644 index 000000000..1ee7d122e Binary files /dev/null and b/web-app/public/images/emoji/alex.png differ diff --git a/web-app/public/images/emoji/bach.png b/web-app/public/images/emoji/bach.png new file mode 100644 index 000000000..92003adc5 Binary files /dev/null and b/web-app/public/images/emoji/bach.png differ diff --git a/web-app/public/images/emoji/daniel.png b/web-app/public/images/emoji/daniel.png new file mode 100644 index 000000000..5b18f0be6 Binary files /dev/null and b/web-app/public/images/emoji/daniel.png differ diff --git a/web-app/public/images/emoji/doug.png b/web-app/public/images/emoji/doug.png new file mode 100644 index 000000000..da69f312f Binary files /dev/null and b/web-app/public/images/emoji/doug.png differ diff --git a/web-app/public/images/emoji/emre.png b/web-app/public/images/emoji/emre.png new file mode 100644 index 000000000..e55632f64 Binary files /dev/null and b/web-app/public/images/emoji/emre.png differ diff --git a/web-app/public/images/emoji/faisal.png b/web-app/public/images/emoji/faisal.png new file mode 100644 index 000000000..e832438a6 Binary files /dev/null and b/web-app/public/images/emoji/faisal.png differ diff --git a/web-app/public/images/emoji/gaunerst.png b/web-app/public/images/emoji/gaunerst.png new file mode 100644 index 000000000..e4cf14f3c Binary files /dev/null and b/web-app/public/images/emoji/gaunerst.png differ diff --git a/web-app/public/images/emoji/hien.png b/web-app/public/images/emoji/hien.png new file mode 100644 index 000000000..2ae61ea90 Binary files /dev/null and b/web-app/public/images/emoji/hien.png differ diff --git a/web-app/public/images/emoji/louis.png b/web-app/public/images/emoji/louis.png new file mode 100644 index 000000000..54a0f7ca7 Binary files /dev/null and b/web-app/public/images/emoji/louis.png differ diff --git a/web-app/public/images/emoji/nicole.png b/web-app/public/images/emoji/nicole.png new file mode 100644 index 000000000..556f52bb5 Binary files /dev/null and b/web-app/public/images/emoji/nicole.png differ diff --git a/web-app/public/images/emoji/rach.png b/web-app/public/images/emoji/rach.png new file mode 100644 index 000000000..392e6a4ec Binary files /dev/null and b/web-app/public/images/emoji/rach.png differ diff --git a/web-app/public/images/emoji/rex.png b/web-app/public/images/emoji/rex.png new file mode 100644 index 000000000..e4d746471 Binary files /dev/null and b/web-app/public/images/emoji/rex.png differ diff --git a/web-app/public/images/emoji/sang.png b/web-app/public/images/emoji/sang.png new file mode 100644 index 000000000..d206f01c0 Binary files /dev/null and b/web-app/public/images/emoji/sang.png differ diff --git a/web-app/public/images/emoji/yuuki.png b/web-app/public/images/emoji/yuuki.png new file mode 100644 index 000000000..31e950f0a Binary files /dev/null and b/web-app/public/images/emoji/yuuki.png differ diff --git a/web-app/src/containers/AvatarEmoji.tsx b/web-app/src/containers/AvatarEmoji.tsx new file mode 100644 index 000000000..d18bc3a0b --- /dev/null +++ b/web-app/src/containers/AvatarEmoji.tsx @@ -0,0 +1,31 @@ +import React from 'react' + +/** + * Checks if an avatar is a custom image (starts with '/images/') + */ +const isCustomImageAvatar = (avatar: React.ReactNode): avatar is string => { + return typeof avatar === 'string' && avatar.startsWith('/images/') +} + +/** + * Component for rendering assistant avatars with consistent styling + */ +interface AvatarEmojiProps { + avatar?: React.ReactNode + fallback?: React.ReactNode + imageClassName?: string + textClassName?: string +} + +export const AvatarEmoji: React.FC = ({ + avatar, + fallback = '👋', + imageClassName = 'w-5 h-5 object-contain', + textClassName = 'text-base', +}) => { + if (isCustomImageAvatar(avatar)) { + return Custom avatar + } + + return {avatar || fallback} +} diff --git a/web-app/src/containers/DropdownAssistant.tsx b/web-app/src/containers/DropdownAssistant.tsx index d8702de92..eb3b17565 100644 --- a/web-app/src/containers/DropdownAssistant.tsx +++ b/web-app/src/containers/DropdownAssistant.tsx @@ -10,6 +10,7 @@ import { useAssistant } from '@/hooks/useAssistant' import AddEditAssistant from './dialogs/AddEditAssistant' import { IconCirclePlus, IconSettings } from '@tabler/icons-react' import { useThreads } from '@/hooks/useThreads' +import { AvatarEmoji } from '@/containers/AvatarEmoji' const DropdownAssistant = () => { const { @@ -34,13 +35,21 @@ const DropdownAssistant = () => {
-
{ > {assistants.map((assistant) => (
- - +
{ setCurrentAssistant(assistant) updateCurrentThreadAssistant(assistant) }} > - {assistant?.avatar} - {assistant.name} - +
+ +
+
+ {assistant.name} +
+
diff --git a/web-app/src/containers/ThreadContent.tsx b/web-app/src/containers/ThreadContent.tsx index 5c89f20a6..07e3593f9 100644 --- a/web-app/src/containers/ThreadContent.tsx +++ b/web-app/src/containers/ThreadContent.tsx @@ -7,6 +7,7 @@ import { IconRefresh, IconTrash, IconPencil, + IconInfoCircle, } from '@tabler/icons-react' import { useAppState } from '@/hooks/useAppState' import { cn } from '@/lib/utils' @@ -32,6 +33,9 @@ import { TooltipTrigger, } from '@/components/ui/tooltip' import { formatDate } from '@/utils/formatDate' +import { AvatarEmoji } from '@/containers/AvatarEmoji' +import CodeEditor from '@uiw/react-textarea-code-editor' +import '@uiw/react-textarea-code-editor/dist.css' const CopyButton = ({ text }: { text: string }) => { const [copied, setCopied] = useState(false) @@ -154,7 +158,7 @@ export const ThreadContent = memo( {item.content?.[0]?.text && item.role === 'user' && (
-
+

{item.content?.[0].text.value}

@@ -237,8 +241,13 @@ export const ThreadContent = memo( <> {item.showAssistant && (
-
- {assistant?.avatar || '👋'} +
+
@@ -303,6 +312,55 @@ export const ThreadContent = memo(

Delete

+ + + + + + + +

Metadata

+
+
+
+ + + Message Metadata +
+
+ +
+
+ + + + + +
+
+
{item.isLastMessage && ( diff --git a/web-app/src/containers/dialogs/AddEditAssistant.tsx b/web-app/src/containers/dialogs/AddEditAssistant.tsx index 6a06d9502..dd7bd40ef 100644 --- a/web-app/src/containers/dialogs/AddEditAssistant.tsx +++ b/web-app/src/containers/dialogs/AddEditAssistant.tsx @@ -20,6 +20,8 @@ import { DropdownMenuTrigger, } from '@/components/ui/dropdown-menu' import { useTheme } from '@/hooks/useTheme' +import { teamEmoji } from '@/utils/teamEmoji' +import { AvatarEmoji } from '@/containers/AvatarEmoji' interface AddEditAssistantProps { open: boolean @@ -218,10 +220,15 @@ export default function AddEditAssistant({
setShowEmojiPicker(!showEmojiPicker)} > - {avatar || '😊'} +
{ - setAvatar(emojiData.emoji) + // For custom emojis, use the imageUrl instead of the emoji name + if (emojiData.isCustom && emojiData.imageUrl) { + setAvatar(emojiData.imageUrl) + } else { + setAvatar(emojiData.emoji) + } setShowEmojiPicker(false) }} /> diff --git a/web-app/src/hooks/useAssistant.ts b/web-app/src/hooks/useAssistant.ts index f24c7f3e1..559f5530a 100644 --- a/web-app/src/hooks/useAssistant.ts +++ b/web-app/src/hooks/useAssistant.ts @@ -28,12 +28,19 @@ export const useAssistant = create()( currentAssistant: defaultAssistant, addAssistant: (assistant) => set({ assistants: [...get().assistants, assistant] }), - updateAssistant: (assistant) => + updateAssistant: (assistant) => { + const state = get() set({ - assistants: get().assistants.map((a) => + assistants: state.assistants.map((a) => a.id === assistant.id ? assistant : a ), - }), + // Update currentAssistant if it's the same assistant being updated + currentAssistant: + state.currentAssistant.id === assistant.id + ? assistant + : state.currentAssistant, + }) + }, deleteAssistant: (id) => set({ assistants: get().assistants.filter((a) => a.id !== id) }), setCurrentAssistant: (assistant) => { diff --git a/web-app/src/routes/assistant.tsx b/web-app/src/routes/assistant.tsx index 4592d86d9..b725e5928 100644 --- a/web-app/src/routes/assistant.tsx +++ b/web-app/src/routes/assistant.tsx @@ -16,6 +16,7 @@ import { DialogTitle, } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' +import { AvatarEmoji } from '@/containers/AvatarEmoji' // eslint-disable-next-line @typescript-eslint/no-explicit-any export const Route = createFileRoute(route.assistant as any)({ @@ -67,10 +68,16 @@ function Assistant() { >

- {assistant.avatar && ( - {assistant.avatar} - )} - {assistant.name} +
+ + + + {assistant.name} +

{/*