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>

View File

@@ -1,61 +1,22 @@
<script setup lang='ts'>
import { computed, ref } from 'vue'
import { NDropdown } from 'naive-ui'
import { HoverButton, Setting, SvgIcon, UserAvatar } from '@/components/common'
import { useAppStore } from '@/store'
import { useIconRender } from '@/hooks/useIconRender'
import { defineAsyncComponent, ref } from 'vue'
import { HoverButton, SvgIcon, UserAvatar } from '@/components/common'
const appStore = useAppStore()
const { iconRender } = useIconRender()
const Setting = defineAsyncComponent(() => import('@/components/common/Setting/index.vue'))
const show = ref(false)
const theme = computed(() => appStore.theme)
const options = [
{
label: 'Dark',
key: 'dark',
icon: iconRender({ icon: 'ri:moon-foggy-line' }),
},
{
label: 'Light',
key: 'light',
icon: iconRender({ icon: 'ri:sun-foggy-line' }),
},
{
label: 'Auto',
key: 'auto',
icon: iconRender({ icon: 'ri:contrast-line' }),
},
]
function handleThemeChange(key: 'light' | 'dark' | 'auto') {
appStore.setTheme(key)
}
</script>
<template>
<footer class="flex items-center justify-between min-w-0 p-4 overflow-hidden border-t dark:border-neutral-800">
<UserAvatar />
<NDropdown :options="options" placement="top" trigger="click" @select="handleThemeChange">
<HoverButton>
<span class="text-xl text-[#4f555e] dark:text-white">
<SvgIcon v-if="theme === 'dark'" icon="ri:moon-foggy-line" />
<SvgIcon v-if="theme === 'light'" icon="ri:sun-foggy-line" />
<SvgIcon v-if="theme === 'auto'" icon="ri:contrast-line" />
</span>
</HoverButton>
</NDropdown>
<HoverButton tooltip="Setting" @click="show = true">
<span class="text-xl text-[#4f555e] dark:text-white">
<SvgIcon icon="ri:settings-4-line" />
</span>
</HoverButton>
<Setting v-model:visible="show" />
<Setting v-if="show" v-model:visible="show" />
</footer>
</template>

View File

@@ -0,0 +1,34 @@
<script lang="ts" setup>
import { NButton } from 'naive-ui'
import { useRouter } from 'vue-router'
const router = useRouter()
function goHome() {
router.push('/')
}
</script>
<template>
<div class="flex h-full">
<div class="px-4 m-auto space-y-4 text-center max-[400px]">
<h1 class="text-4xl text-slate-800 dark:text-neutral-200">
No permission
</h1>
<p class="text-base text-slate-500 dark:text-neutral-400">
The page you're trying access has restricted access.
Please refer to your system administrator
</p>
<div class="flex items-center justify-center text-center">
<div class="w-[300px]">
<div class="w-[300px]">
<img src="../../../icons/403.svg" alt="404">
</div>
</div>
</div>
<NButton type="primary" @click="goHome">
Go to Home
</NButton>
</div>
</div>
</template>

View File

@@ -0,0 +1,31 @@
<script lang="ts" setup>
import { NButton } from 'naive-ui'
import { useRouter } from 'vue-router'
const router = useRouter()
function goHome() {
router.push('/')
}
</script>
<template>
<div class="flex h-full">
<div class="px-4 m-auto space-y-4 text-center max-[400px]">
<h1 class="text-4xl text-slate-800 dark:text-neutral-200">
Sorry, page not found!
</h1>
<p class="text-base text-slate-500 dark:text-neutral-400">
Sorry, we couldnt find the page youre looking for. Perhaps youve mistyped the URL? Be sure to check your spelling.
</p>
<div class="flex items-center justify-center text-center">
<div class="w-[300px]">
<img src="../../../icons/404.svg" alt="404">
</div>
</div>
<NButton type="primary" @click="goHome">
Go to Home
</NButton>
</div>
</div>
</template>