Skip to content

Commit

Permalink
feat: sessions support copy, copy markdown, export images, close #18 (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
ayangweb committed Mar 22, 2023
1 parent 3c1ba49 commit 7a4758c
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 75 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"clipboard": "^2.0.11",
"dayjs": "^1.11.7",
"highlight.js": "^11.7.0",
"html-to-image": "^1.11.11",
"html2canvas": "^1.4.1",
"markdown-it": "^13.0.1",
"markdown-it-highlightjs": "^4.0.1",
"pinia": "^2.0.33",
Expand Down
35 changes: 31 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/assets/image/markdown.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
93 changes: 68 additions & 25 deletions src/components/Session/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,48 +6,91 @@
}

::v-deep(.session-item) {
p {
--uno: leading-6;
}
.operation {
.copy {
background-color: var(--color-text-1);

-webkit-mask-image: url('@/assets/image/copy.svg');
mask-image: url('@/assets/image/copy.svg');
-webkit-mask-size: contain;
mask-size: contain;
&.active {
-webkit-mask-image: url('@/assets/image/copied.svg');
mask-image: url('@/assets/image/copied.svg');
}
}

pre {
--uno: m0;
.markdown {
background-color: var(--color-text-1);

code {
--uno: rounded-md leading-6;
-webkit-mask-image: url('@/assets/image/markdown.svg');
mask-image: url('@/assets/image/markdown.svg');
-webkit-mask-size: contain;
mask-size: contain;
}

+ .code-copy {
background-image: url('@/assets/image/copy.svg');
> * {
cursor: pointer;

--uno: transition-300 absolute top-2 right-2 h-6 w-6 cursor-pointer
bg-contain bg-center bg-no-repeat text-white opacity-0;
--uno: transition-300 h-6 w-6 opacity-70;

&:hover {
--uno: opacity-100;
}
}
}

&.copied {
opacity: 1 !important;
background-image: url('@/assets/image/copied.svg');
}
.session-content {
p {
--uno: leading-6;
}

&:hover {
pre {
--uno: m0;

code {
--uno: rounded-md leading-6;
}

+ .code-copy {
--uno: opacity-70;
background-image: url('@/assets/image/copy.svg');

--uno: transition-300 absolute top-2 right-2 h-6 w-6 cursor-pointer bg-contain bg-center bg-no-repeat text-white opacity-0;

&:hover {
--uno: opacity-100;
}

&.copied {
opacity: 1 !important;
background-image: url('@/assets/image/copied.svg');
}
}

&:hover {
+ .code-copy {
--uno: opacity-70;
}
}
}
}

ol,
ul,
li {
--uno: flex flex-col gap-4;
}
ol,
ul {
--uno: flex flex-col gap-4;
li {
> *:not(:last-child) {
--uno: pb-4;
}

a {
--uno: text-[rgb(var(--primary-6))] hover:underline;
> code {
--uno: leading-6;
}
}
}

a {
--uno: text-[rgb(var(--primary-6))] hover:underline;
}
}
}

Expand Down
72 changes: 49 additions & 23 deletions src/components/Session/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import MarkdownIt from 'markdown-it'
import MarkdownItHighlight from 'markdown-it-highlightjs'
import { IconImage } from '@arco-design/web-vue/es/icon'
import { copyCode } from '@/utils'
import { useSettingsStore, useSessionStore, useRoleStore } from '@/stores'
import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc'
import { copyText, copyCode, saveImage } from '@/utils'
import { useSettingsStore, useSessionStore, useRoleStore } from '@/stores'
dayjs.extend(utc)
Expand All @@ -19,23 +19,21 @@ const { uuid } = storeToRefs(useSettingsStore())
const { sessionDataList } = storeToRefs(useSessionStore())
const { currentRole } = storeToRefs(useRoleStore())
const getLocalTime = (time: string) =>
dayjs.utc(time).local().format('YYYY-MM-DD HH:mm:ss')
const sessionElement = ref<HTMLDivElement | null>(null)
const scrollHeight = ref<number | undefined>(0)
/**
* 自动滚动到底部
*/
const autoScrollBottom = () => {
if (scrollHeight.value !== sessionElement.value?.scrollHeight) {
sessionElement.value?.scroll({
top: sessionElement.value.scrollHeight
})
scrollHeight.value = sessionElement.value?.scrollHeight
}
}
if (!sessionElement.value) return
const localTime = (time: string) =>
dayjs.utc(time).local().format('YYYY-MM-DD HH:mm:ss')
sessionElement.value.scroll({
top: sessionElement.value.scrollHeight
})
}
onUpdated(() => {
autoScrollBottom()
Expand Down Expand Up @@ -63,20 +61,48 @@ onUpdated(() => {
:class="item.is_ask && 'items-end'"
>
<span class="text-xs text-[var(--color-text-2)]">
{{ localTime(item.time!) }}
{{ getLocalTime(item.time!) }}
</span>
<div class="blink-block" v-if="!item.message.content"></div>
<div
class="session-item relative flex w-fit flex-col gap-4 rounded-md p-4"
:class="
item.is_ask
? 'bg-[rgb(var(--blue-6))] text-white'
: 'bg-[var(--session-background)]'
"
v-html="marked.render(item.message.content)"
v-else
></div>
<div class="session-item group relative max-w-fit" v-else>
<div
class="operation transition-300 absolute flex flex-col gap-1 opacity-0 group-hover:opacity-100"
:class="
item.is_ask
? 'left-0 -translate-x-full pr-2'
: 'right-0 translate-x-full pl-2'
"
>
<div
class="copy"
:id="`copy-${item.id}`"
@click="
copyText($event, { nodeId: `session-content-${item.id}` })
"
></div>

<div
class="markdown"
:id="`markdown-${item.id}`"
@click="copyText($event, { content: item.message.content })"
></div>

<IconImage @click="saveImage(`session-data-${item.id}`)" />
</div>

<div
:id="`session-content-${item.id}`"
class="session-content flex flex-col gap-4 rounded-md p-4"
v-html="marked.render(item.message.content)"
:class="
item.is_ask
? 'bg-[rgb(var(--blue-6))] text-white'
: 'bg-[var(--session-background)]'
"
></div>
</div>
</div>
</div>
</template>
Expand Down
1 change: 0 additions & 1 deletion src/stores/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { hide, show } from '@tauri-apps/api/app'
import { enable, disable } from 'tauri-plugin-autostart-api'
import { THEME, DEFAULT_SHORTCUT_KEY } from '@/constants'

// @unocss-include
export const useSettingsStore = defineStore(
'settingsStore',
() => {
Expand Down
40 changes: 40 additions & 0 deletions src/utils/copyCode.ts → src/utils/copy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import Clipboard from 'clipboard'
import { writeText } from '@tauri-apps/api/clipboard'
import { Message } from '@arco-design/web-vue'

type RulesArgs = [Array<{ content: string }>, number]

Expand Down Expand Up @@ -51,3 +53,41 @@ export const copyCode = (md: any) => {
md.renderer.rules.code_block = renderCode(md.renderer.rules.code_block)
md.renderer.rules.fence = renderCode(md.renderer.rules.fence)
}

export const copyText = async (
event: MouseEvent,
payload: { nodeId?: string; content?: string }
) => {
try {
const element = event.target as HTMLElement
const id = '_' + element.getAttribute('id')

if (!id || window[id]) {
return
}

element.classList.add('active')

window[id] = setTimeout(() => {
element.classList.remove('active')

clearTimeout(window[id])
window[id] = null
}, 3000)

const { nodeId } = payload
let { content } = payload

if (nodeId) {
content = document.getElementById(nodeId)?.innerText
}

if (!content) return

await writeText(content)

Message.success('复制成功')
} catch (error) {
Message.error('复制失败')
}
}
2 changes: 1 addition & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ export * from './shared'
export * from './tauri'
export * from './keyMap'
export * from './saveImage'
export * from './copyCode'
export * from './copy'

0 comments on commit 7a4758c

Please sign in to comment.