list.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. <script setup lang="tsx">
  2. import { UserOutlined } from '@ant-design/icons-vue';
  3. import { BubbleList } from 'ant-design-x-vue';
  4. import { Button, Flex, Switch } from 'ant-design-vue';
  5. import type { BubbleListProps, BubbleProps } from 'ant-design-x-vue';
  6. import { ref } from 'vue';
  7. defineOptions({ name: 'BubbleList' });
  8. const rolesAsObject: BubbleListProps['roles'] = {
  9. ai: {
  10. placement: 'start',
  11. avatar: { icon: <UserOutlined />, style: { background: '#fde3cf' } },
  12. typing: { step: 5, interval: 20 },
  13. style: {
  14. maxWidth: '600px',
  15. },
  16. },
  17. user: {
  18. placement: 'end',
  19. avatar: { icon: <UserOutlined />, style: { background: '#87d068' } },
  20. },
  21. };
  22. const rolesAsFunction = (bubbleData: BubbleProps, index: number) => {
  23. const RenderIndex: BubbleProps['messageRender'] = (content) => (
  24. <Flex>
  25. #{index}: {content}
  26. </Flex>
  27. );
  28. switch (bubbleData.role) {
  29. case 'ai':
  30. return {
  31. placement: 'start' as const,
  32. avatar: { icon: <UserOutlined />, style: { background: '#fde3cf' } },
  33. typing: { step: 5, interval: 20 },
  34. style: {
  35. maxWidth: 600,
  36. },
  37. messageRender: RenderIndex,
  38. };
  39. case 'user':
  40. return {
  41. placement: 'end' as const,
  42. avatar: { icon: <UserOutlined />, style: { background: '#87d068' } },
  43. messageRender: RenderIndex,
  44. };
  45. default:
  46. return { messageRender: RenderIndex };
  47. }
  48. };
  49. const count = ref<number>(3);
  50. const useRolesAsFunction = ref(false);
  51. // const listRef = useTemplateRef<InstanceType<typeof BubbleList>>(null);
  52. const listRef = ref<InstanceType<typeof BubbleList>>(null);
  53. defineRender(() => {
  54. return (
  55. <Flex vertical gap="small">
  56. <Flex gap="large" align="center">
  57. Use roles as:
  58. <Switch
  59. checked={useRolesAsFunction.value}
  60. onChange={(checked) => useRolesAsFunction.value = checked as boolean}
  61. checkedChildren="Function"
  62. unCheckedChildren="Object"
  63. />
  64. </Flex>
  65. <Flex gap="small" style={{ alignSelf: 'flex-end' }}>
  66. <Button
  67. onClick={() => {
  68. count.value = count.value + 1;
  69. }}
  70. >
  71. Add Bubble
  72. </Button>
  73. <Button
  74. onClick={() => {
  75. listRef.value?.scrollTo({ key: 0, block: 'nearest' });
  76. }}
  77. >
  78. Scroll To First
  79. </Button>
  80. </Flex>
  81. <BubbleList
  82. ref={listRef}
  83. style={{ maxHeight: '300px' }}
  84. roles={useRolesAsFunction.value ? rolesAsFunction : rolesAsObject}
  85. items={Array.from({ length: count.value }).map((_, i) => {
  86. const isAI = !!(i % 2);
  87. const content = isAI ? 'Mock AI content. '.repeat(20) : 'Mock user content.';
  88. return {
  89. key: i,
  90. role: isAI ? 'ai' : 'user',
  91. content,
  92. };
  93. })}
  94. />
  95. </Flex>
  96. )
  97. });
  98. </script>