Chat.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. <script setup lang="ts">
  2. import AppLayout from "@/Layouts/AppLayout.vue"
  3. import {ArrowUpIcon} from "lucide-vue-next"
  4. import {
  5. DropdownMenu,
  6. DropdownMenuContent,
  7. DropdownMenuItem,
  8. DropdownMenuTrigger
  9. } from "@/Packages/Shadcn/Components/ui/dropdown-menu"
  10. import {
  11. InputGroup,
  12. InputGroupAddon,
  13. InputGroupButton,
  14. InputGroupText,
  15. InputGroupTextarea
  16. } from "@/Packages/Shadcn/Components/ui/input-group"
  17. import {Separator} from "@/Packages/Shadcn/Components/ui/separator"
  18. import {nextTick, reactive, ref} from "vue";
  19. import {useForm} from "@inertiajs/vue3";
  20. const messages = reactive<Array<string>>([])
  21. const form = useForm({
  22. message: null
  23. })
  24. const submit = function () {
  25. messages.push({from: 'user', text: form.message})
  26. messages.push({from: 'ai', text: form.message})
  27. form.reset()
  28. }
  29. const handleEnter = function (e) {
  30. if (e.metaKey || e.ctrlKey) {
  31. const {selectionStart, selectionEnd, value} = e.target
  32. form.message = value.slice(0, selectionStart) + '\n' + value.slice(selectionEnd)
  33. nextTick(() => {
  34. const pos = selectionStart + 1
  35. e.target.setSelectionRange(pos, pos)
  36. })
  37. } else submit()
  38. }
  39. </script>
  40. <template>
  41. <AppLayout page-class="!py-0">
  42. <div class="max-w-4xl mx-auto flex flex-col h-full">
  43. <div class="overflow-y-auto duration-500" :class="{'grow mt-2': messages.length !== 0}">
  44. <div v-for="message in messages">
  45. <div class="flex" v-if="message.from === 'user'">
  46. <div class="ml-auto border bg-card text-card-foreground p-2 rounded-lg max-w-[75%]">
  47. {{ message.text }}
  48. </div>
  49. </div>
  50. <div v-else>{{ message.text }}</div>
  51. </div>
  52. <!-- <div class=""></div>-->
  53. </div>
  54. <div class="my-auto pb-2" :class="{'sticky bottom-0': messages.length !== 0}">
  55. <InputGroup class="!bg-card">
  56. <InputGroupTextarea placeholder="Ask, Search or Chat..." v-model="form.message"
  57. @keydown.enter.prevent="handleEnter"/>
  58. <InputGroupAddon align="block-end">
  59. <!-- <InputGroupButton-->
  60. <!-- variant="outline"-->
  61. <!-- class="rounded-full"-->
  62. <!-- size="icon-xs"-->
  63. <!-- >-->
  64. <!-- <PlusIcon class="size-4"/>-->
  65. <!-- </InputGroupButton>-->
  66. <DropdownMenu>
  67. <DropdownMenuTrigger as-child>
  68. <InputGroupButton variant="ghost">
  69. Модель 1
  70. </InputGroupButton>
  71. </DropdownMenuTrigger>
  72. <DropdownMenuContent side="top" align="start">
  73. <DropdownMenuItem>Модель 1</DropdownMenuItem>
  74. <DropdownMenuItem>Модель 2</DropdownMenuItem>
  75. <DropdownMenuItem>Модель 3</DropdownMenuItem>
  76. </DropdownMenuContent>
  77. </DropdownMenu>
  78. <InputGroupText class="ml-auto">
  79. 123 токенов
  80. </InputGroupText>
  81. <Separator orientation="vertical" class="!h-4"/>
  82. <InputGroupButton class="cursor-pointer" variant="default" size="icon-xs"
  83. @click="() => submit()">
  84. <ArrowUpIcon class="size-4"/>
  85. <span class="sr-only">Отправить</span>
  86. </InputGroupButton>
  87. </InputGroupAddon>
  88. </InputGroup>
  89. </div>
  90. </div>
  91. </AppLayout>
  92. </template>
  93. <style scoped>
  94. </style>