ProfilePreview.svelte 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. <script lang="ts">
  2. import { DropdownMenu } from 'bits-ui';
  3. import { createEventDispatcher } from 'svelte';
  4. import { flyAndScale } from '$lib/utils/transitions';
  5. import { WEBUI_BASE_URL } from '$lib/constants';
  6. import { activeUserIds } from '$lib/stores';
  7. export let side = 'right';
  8. export let align = 'top';
  9. export let user = null;
  10. let show = false;
  11. const dispatch = createEventDispatcher();
  12. </script>
  13. <DropdownMenu.Root
  14. bind:open={show}
  15. closeFocus={false}
  16. onOpenChange={(state) => {
  17. dispatch('change', state);
  18. }}
  19. typeahead={false}
  20. >
  21. <DropdownMenu.Trigger>
  22. <slot />
  23. </DropdownMenu.Trigger>
  24. <slot name="content">
  25. <DropdownMenu.Content
  26. class="max-w-full w-[240px] rounded-lg z-50 bg-white dark:bg-black dark:text-white shadow-lg"
  27. sideOffset={8}
  28. {side}
  29. {align}
  30. transition={flyAndScale}
  31. >
  32. {#if user}
  33. <div class=" flex flex-col gap-2 w-full rounded-lg">
  34. <div class="py-8 relative bg-gray-900 rounded-t-lg">
  35. <img
  36. crossorigin="anonymous"
  37. src={user?.profile_image_url ?? `${WEBUI_BASE_URL}/static/favicon.png`}
  38. class=" absolute -bottom-5 left-3 size-12 ml-0.5 object-cover rounded-full -translate-y-[1px]"
  39. alt="profile"
  40. />
  41. </div>
  42. <div class=" flex flex-col pt-4 pb-2.5 px-4">
  43. <div class=" -mb-1">
  44. <span class="font-medium text-sm line-clamp-1"> {user.name} </span>
  45. </div>
  46. <div class=" flex items-center gap-2">
  47. {#if $activeUserIds.includes(user.id)}
  48. <div>
  49. <span class="relative flex size-2">
  50. <span
  51. class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"
  52. />
  53. <span class="relative inline-flex rounded-full size-2 bg-green-500" />
  54. </span>
  55. </div>
  56. <div class=" -translate-y-[1px]">
  57. <span class="text-xs"> Active </span>
  58. </div>
  59. {:else}
  60. <div>
  61. <span class="relative flex size-2">
  62. <span class="relative inline-flex rounded-full size-2 bg-gray-500" />
  63. </span>
  64. </div>
  65. <div class=" -translate-y-[1px]">
  66. <span class="text-xs"> Away </span>
  67. </div>
  68. {/if}
  69. </div>
  70. </div>
  71. </div>
  72. {/if}
  73. </DropdownMenu.Content>
  74. </slot>
  75. </DropdownMenu.Root>