feat: 增加带格式的复制 (#182)

* feat: 增加带格式的复制

* feat: 移除前端超时设定

* chore: update deps

* feat: 添加权限页面

* feat: 设定页面优化

* feat: 更新 chatgpt 以支持 `gpt-3.5-turbo-0301`

* chore: version 2.9.0
This commit is contained in:
Redon
2023-03-02 12:59:20 +08:00
committed by GitHub
parent 42e320fe35
commit 32ebbec8ad
28 changed files with 689 additions and 306 deletions

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup>
import { computed } from 'vue'
import { computed, ref } from 'vue'
import { marked } from 'marked'
import hljs from 'highlight.js'
import { useBasicLayout } from '@/hooks/useBasicLayout'
@@ -18,6 +18,8 @@ const { isMobile } = useBasicLayout()
const renderer = new marked.Renderer()
const textRef = ref<HTMLElement>()
renderer.html = (html) => {
return `<p>${encodeHTML(html)}</p>`
}
@@ -54,6 +56,8 @@ const text = computed(() => {
return marked(value)
return value
})
defineExpose({ textRef })
</script>
<template>
@@ -62,7 +66,7 @@ const text = computed(() => {
<span class="dark:text-white w-[4px] h-[20px] block animate-blink" />
</template>
<template v-else>
<div class="leading-relaxed break-all">
<div ref="textRef" class="leading-relaxed break-all">
<div v-if="!inversion" class="markdown-body" v-html="text" />
<div v-else class="whitespace-pre-wrap" v-text="text" />
</div>

View File

@@ -1,4 +1,5 @@
<script setup lang='ts'>
import { ref } from 'vue'
import { NDropdown, useMessage } from 'naive-ui'
import AvatarComponent from './Avatar.vue'
import TextComponent from './Text.vue'
@@ -27,32 +28,41 @@ const ms = useMessage()
const { iconRender } = useIconRender()
const textRef = ref<HTMLElement>()
const options = [
{
label: 'Copy',
key: 'copy',
label: 'Copy Raw',
key: 'copyRaw',
icon: iconRender({ icon: 'ri:file-copy-2-line' }),
}, {
},
{
label: 'Copy Text',
key: 'copyText',
icon: iconRender({ icon: 'ri:file-copy-line' }),
},
{
label: 'Delete',
key: 'delete',
icon: iconRender({ icon: 'ri:delete-bin-line' }),
},
]
function handleSelect(key: 'copy' | 'delete') {
if (key === 'copy')
handleCopy()
else
handleDelete()
}
function handleDelete() {
emit('delete')
}
function handleCopy() {
copyText(props.text ?? '')
ms.success('Copied')
function handleSelect(key: 'copyRaw' | 'copyText' | 'delete') {
switch (key) {
case 'copyRaw':
if (textRef.value && (textRef.value as any).textRef) {
copyText({ text: (textRef.value as any).textRef.innerText })
ms.success('Copied Raw')
}
return
case 'copyText':
copyText({ text: props.text ?? '', origin: false })
ms.success('Copied Text')
return
case 'delete':
emit('delete')
}
}
function handleRegenerate() {
@@ -73,10 +83,11 @@ function handleRegenerate() {
{{ dateTime }}
</p>
<div
class="flex items-end gap-2 mt-2"
class="flex items-end gap-1 mt-2"
:class="[inversion ? 'flex-row-reverse' : 'flex-row']"
>
<TextComponent
ref="textRef"
:inversion="inversion"
:error="error"
:text="text"
@@ -85,14 +96,14 @@ function handleRegenerate() {
<div class="flex flex-col">
<button
v-if="!inversion"
class="mb-2 transition text-neutral-400 hover:text-neutral-800 dark:hover:text-neutral-200"
class="mb-2 transition text-neutral-300 hover:text-neutral-800 dark:hover:text-neutral-300"
@click="handleRegenerate"
>
<SvgIcon icon="ri:restart-line" />
</button>
<NDropdown :options="options" @select="handleSelect">
<NDropdown :placement="!inversion ? 'right' : 'left'" :options="options" @select="handleSelect">
<button class="transition text-neutral-300 hover:text-neutral-800 dark:hover:text-neutral-200">
<SvgIcon icon="ri:function-line" />
<SvgIcon icon="ri:more-2-fill" />
</button>
</NDropdown>
</div>