From 100b6bd9d41a014af6e422b706bf53ba0235299b Mon Sep 17 00:00:00 2001
From: yzh990918 <251205668@qq.com>
Date: Mon, 22 May 2023 15:49:01 +0800
Subject: [PATCH 01/18] feat: add export icon
---
.../header/ConversationMessageShareButton.tsx | 22 +++++++++++++++++++
src/components/header/Header.tsx | 2 ++
src/components/main/MessageItem.tsx | 3 +--
3 files changed, 25 insertions(+), 2 deletions(-)
create mode 100644 src/components/header/ConversationMessageShareButton.tsx
diff --git a/src/components/header/ConversationMessageShareButton.tsx b/src/components/header/ConversationMessageShareButton.tsx
new file mode 100644
index 00000000..f7b678df
--- /dev/null
+++ b/src/components/header/ConversationMessageShareButton.tsx
@@ -0,0 +1,22 @@
+import { useStore } from '@nanostores/solid'
+import { currentConversationId } from '@/stores/conversation'
+
+export default () => {
+ const $currentConversationId = useStore(currentConversationId)
+
+ const handleClearMessage = () => {
+ }
+
+ return (
+ <>
+ {$currentConversationId() && (
+
+
showSettingsSidebar.set(true)}
diff --git a/src/components/main/MessageItem.tsx b/src/components/main/MessageItem.tsx
index 1315e3b6..16597541 100644
--- a/src/components/main/MessageItem.tsx
+++ b/src/components/main/MessageItem.tsx
@@ -77,11 +77,10 @@ export default (props: Props) => {
const [menuList, setMenuList] = createSignal
+
+
+
+
+
>
)
}
diff --git a/src/components/header/ConversationMessageShareButton.tsx b/src/components/header/ConversationMessageShareButton.tsx
index f7b678df..9601b027 100644
--- a/src/components/header/ConversationMessageShareButton.tsx
+++ b/src/components/header/ConversationMessageShareButton.tsx
@@ -1,18 +1,16 @@
import { useStore } from '@nanostores/solid'
import { currentConversationId } from '@/stores/conversation'
+import { showShareModal } from '@/stores/ui'
export default () => {
const $currentConversationId = useStore(currentConversationId)
- const handleClearMessage = () => {
- }
-
return (
<>
{$currentConversationId() && (
{ showShareModal.set(true) }}
>
diff --git a/src/components/ui/ShareModal.tsx b/src/components/ui/ShareModal.tsx
new file mode 100644
index 00000000..2bcbb730
--- /dev/null
+++ b/src/components/ui/ShareModal.tsx
@@ -0,0 +1,36 @@
+import { useI18n } from '@/hooks'
+import { Tabs } from '../ui/base'
+import type { TabItem } from './base/Tabs'
+
+export default () => {
+ const { t } = useI18n()
+
+ const tabs: TabItem[] = [
+ {
+ value: 'context',
+ label: t('conversations.share.tabs.context'),
+ content:
context
,
+ },
+ {
+ value: 'image',
+ label: t('conversations.share.tabs.image'),
+ content:
image
,
+ },
+ ]
+
+ return (
+
+
+
{t('conversations.share.link.title')}
+
+
+
+
+ {t('conversations.share.messages.selected')}
+ 2 Messages
+
+
+
+
+ )
+}
diff --git a/src/components/ui/base/Checkbox.tsx b/src/components/ui/base/Checkbox.tsx
new file mode 100644
index 00000000..bcd4a749
--- /dev/null
+++ b/src/components/ui/base/Checkbox.tsx
@@ -0,0 +1,24 @@
+import * as checkbox from '@zag-js/checkbox'
+import { normalizeProps, useMachine } from '@zag-js/solid'
+import { createMemo, createUniqueId } from 'solid-js'
+
+interface Props {
+ initValue?: boolean
+ label: string
+}
+
+export const Checkbox = (props: Props) => {
+ const [state, send] = useMachine(checkbox.machine({ id: createUniqueId(), checked: props.initValue ?? false }))
+
+ const api = createMemo(() => checkbox.connect(state, send, normalizeProps))
+
+ return (
+
+ )
+}
diff --git a/src/components/ui/base/Tabs.tsx b/src/components/ui/base/Tabs.tsx
new file mode 100644
index 00000000..9a8a07ee
--- /dev/null
+++ b/src/components/ui/base/Tabs.tsx
@@ -0,0 +1,42 @@
+import * as tabs from '@zag-js/tabs'
+import { normalizeProps, useMachine } from '@zag-js/solid'
+import { For, createMemo, createUniqueId } from 'solid-js'
+import type { JSX } from 'solid-js'
+
+export interface TabItem {
+ value: string
+ label: string
+ content: JSX.Element
+}
+
+interface Props {
+ tabs: TabItem[]
+ initValue?: string
+}
+
+export const Tabs = (props: Props) => {
+ const [state, send] = useMachine(tabs.machine({ id: createUniqueId(), value: props.initValue ?? props.tabs[0].value }))
+
+ const api = createMemo(() => tabs.connect(state, send, normalizeProps))
+
+ return (
+
+
+
+ {item => (
+
+ )}
+
+
+
+ {item => (
+
+ {item.content}
+
+ )}
+
+
+ )
+}
diff --git a/src/components/ui/base/index.ts b/src/components/ui/base/index.ts
index bbec0356..6256a643 100644
--- a/src/components/ui/base/index.ts
+++ b/src/components/ui/base/index.ts
@@ -5,3 +5,5 @@ export * from './Select'
export * from './Slider'
export * from './Tooltip'
export * from './Toggle'
+export * from './Checkbox'
+export * from './Tabs'
diff --git a/src/stores/ui.ts b/src/stores/ui.ts
index 7990c17d..8f615168 100644
--- a/src/stores/ui.ts
+++ b/src/stores/ui.ts
@@ -6,6 +6,7 @@ export const showSettingsSidebar = atom(false)
export const showConversationEditModal = atom(false)
export const showEmojiPickerModal = atom(false)
export const showConfirmModal = atom(false)
+export const showShareModal = atom(false)
export const isSendBoxFocus = atom(false)
export const currentErrorMessage = atom
(null)
diff --git a/unocss.config.ts b/unocss.config.ts
index 83741e01..7189d9a0 100644
--- a/unocss.config.ts
+++ b/unocss.config.ts
@@ -59,6 +59,7 @@ export default defineConfig({
'input-base': 'bg-transparent placeholder:op-50 dark:placeholder:op-20 focus:(ring-0 outline-none) resize-none',
'button': 'mt-4 px-3 py-2 text-xs border border-base rounded-lg hv-base hover:border-base-100',
'emerald-button': 'mt-4 px-3 py-2 text-xs border rounded-lg text-light-400 border-emerald-600 bg-emerald-600 hover-bg-emerald-700 hover-border-emerald-700',
+ 'emerald-light-button': 'mt-4 px-3 py-2 text-xs border rounded-lg text-emerald-400 bg-emerald/12 border-emerald-400 hover-bg-emerald-600 hover-border-emerald-600 hover-text-light-700',
'max-w-base': 'max-w-3xl mx-auto',
'text-error': 'text-red-700 dark:text-red-400/80',
'border-error': 'border border-red-700 dark:border-red-400/80',
From e32b56b459c024b993202f78a980f13a42c0ddb3 Mon Sep 17 00:00:00 2001
From: yzh990918 <251205668@qq.com>
Date: Thu, 25 May 2023 11:49:20 +0800
Subject: [PATCH 04/18] feat: add context copy
---
.eslintrc.js | 1 +
src/components/ui/ShareModal.tsx | 28 ++++++++++++++++++++++++----
src/components/ui/base/Tabs.tsx | 8 +++++---
src/locale/lang/en.ts | 2 ++
src/locale/lang/zh-cn.ts | 2 ++
5 files changed, 34 insertions(+), 7 deletions(-)
diff --git a/.eslintrc.js b/.eslintrc.js
index cb63f0b4..ffe5d560 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -8,6 +8,7 @@ module.exports = {
'@typescript-eslint/no-unused-vars': 'warn',
'react/jsx-key': 'off',
'import/namespace': 'off',
+ 'react/jsx-closing-tag-location': 'off',
},
overrides: [
{
diff --git a/src/components/ui/ShareModal.tsx b/src/components/ui/ShareModal.tsx
index 2bcbb730..8749ec3f 100644
--- a/src/components/ui/ShareModal.tsx
+++ b/src/components/ui/ShareModal.tsx
@@ -1,15 +1,35 @@
-import { useI18n } from '@/hooks'
+import { useStore } from '@nanostores/solid'
+import { For } from 'solid-js'
+import { useClipboardCopy, useI18n } from '@/hooks'
+import { currentConversationId } from '@/stores/conversation'
+import { getMessagesByConversationId } from '@/stores/messages'
import { Tabs } from '../ui/base'
import type { TabItem } from './base/Tabs'
export default () => {
const { t } = useI18n()
+ const $currentConversationId = useStore(currentConversationId)
+ const messages = getMessagesByConversationId($currentConversationId())
+
+ console.log($currentConversationId(), messages)
+
+ const [copied, copy] = useClipboardCopy(messages.map(item => `${item.role}: ${item.content}`).join('\n'))
const tabs: TabItem[] = [
{
value: 'context',
label: t('conversations.share.tabs.context'),
- content: context
,
+ content:
+
copy()}>{copied() ? t('copyed') : t('conversations.share.copy')}
+
+ {item => (
+
+
{item.role}:
+
{item.content}
+
+ )}
+
+
,
},
{
value: 'image',
@@ -22,14 +42,14 @@ export default () => {
{t('conversations.share.link.title')}
-
+
{t('conversations.share.messages.selected')}
2 Messages
-
+
)
diff --git a/src/components/ui/base/Tabs.tsx b/src/components/ui/base/Tabs.tsx
index 9a8a07ee..b3988414 100644
--- a/src/components/ui/base/Tabs.tsx
+++ b/src/components/ui/base/Tabs.tsx
@@ -12,6 +12,8 @@ export interface TabItem {
interface Props {
tabs: TabItem[]
initValue?: string
+ sticky?: boolean
+ tabClass?: string
}
export const Tabs = (props: Props) => {
@@ -21,10 +23,10 @@ export const Tabs = (props: Props) => {
return (
-
+
{item => (
-
{item => (
-
+
{item.content}
)}
diff --git a/src/locale/lang/en.ts b/src/locale/lang/en.ts
index e2dadd81..dee18cdd 100644
--- a/src/locale/lang/en.ts
+++ b/src/locale/lang/en.ts
@@ -38,6 +38,7 @@ export const en = {
create: 'Create Link',
},
save: 'Save',
+ copy: 'Copy Context',
messages: {
title: 'Select Message',
selected: 'Selected Messages',
@@ -51,5 +52,6 @@ export const en = {
send: {
placeholder: 'Enter Something...',
},
+ copyed: 'Copyed!',
},
} as language
diff --git a/src/locale/lang/zh-cn.ts b/src/locale/lang/zh-cn.ts
index 136f1146..8a8aabb2 100644
--- a/src/locale/lang/zh-cn.ts
+++ b/src/locale/lang/zh-cn.ts
@@ -38,6 +38,7 @@ export const zhCN = {
create: '创建链接',
},
save: '保存',
+ copy: '复制上下文',
messages: {
title: '选择消息',
selected: '已选择的消息',
@@ -51,5 +52,6 @@ export const zhCN = {
send: {
placeholder: '输入内容...',
},
+ copyed: '已拷贝!',
},
} as language
From f3f3a0477ad061fe189c16e2b728a4563682b9cd Mon Sep 17 00:00:00 2001
From: yzh990918 <251205668@qq.com>
Date: Mon, 29 May 2023 10:11:57 +0800
Subject: [PATCH 05/18] style: update content overflow style
---
src/components/ui/ShareModal.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/ui/ShareModal.tsx b/src/components/ui/ShareModal.tsx
index 8749ec3f..0e54847d 100644
--- a/src/components/ui/ShareModal.tsx
+++ b/src/components/ui/ShareModal.tsx
@@ -25,7 +25,7 @@ export default () => {
{item => (
{item.role}:
-
{item.content}
+
{item.content}
)}
From 85bb70f816f2abf41c711faa45a49040320baaa4 Mon Sep 17 00:00:00 2001
From: yzh990918 <251205668@qq.com>
Date: Fri, 2 Jun 2023 17:06:08 +0800
Subject: [PATCH 06/18] feat: add selectMessageModal
---
src/components/ModalsLayer.tsx | 7 ++++++
src/components/ui/SelectMessageModal.tsx | 31 ++++++++++++++++++++++++
src/components/ui/ShareModal.tsx | 11 +++++++--
src/components/ui/base/Checkbox.tsx | 21 +++++++++++-----
src/components/ui/base/Tabs.tsx | 2 +-
src/stores/ui.ts | 1 +
6 files changed, 64 insertions(+), 9 deletions(-)
create mode 100644 src/components/ui/SelectMessageModal.tsx
diff --git a/src/components/ModalsLayer.tsx b/src/components/ModalsLayer.tsx
index 143afab8..8ce03259 100644
--- a/src/components/ModalsLayer.tsx
+++ b/src/components/ModalsLayer.tsx
@@ -2,6 +2,7 @@ import {
showConversationEditModal,
showConversationSidebar,
showEmojiPickerModal,
+ showSelectMessageModal,
showSettingsSidebar,
showShareModal,
} from '@/stores/ui'
@@ -10,6 +11,7 @@ import SettingsSidebar from './settings/SettingsSidebar'
import ConversationEditModal from './conversations/ConversationEditModal'
import EmojiPickerModal from './ui/EmojiPickerModal'
import ShareModal from './ui/ShareModal'
+import SelectMessageModal from './ui/SelectMessageModal'
import Modal from './ui/Modal'
export default () => {
@@ -40,6 +42,11 @@ export default () => {
+
+
+
+
+
>
)
}
diff --git a/src/components/ui/SelectMessageModal.tsx b/src/components/ui/SelectMessageModal.tsx
new file mode 100644
index 00000000..31f99573
--- /dev/null
+++ b/src/components/ui/SelectMessageModal.tsx
@@ -0,0 +1,31 @@
+import { useStore } from '@nanostores/solid'
+import { For } from 'solid-js'
+import { useI18n } from '@/hooks'
+import { currentConversationId } from '@/stores/conversation'
+import { getMessagesByConversationId } from '@/stores/messages'
+import { Checkbox } from '../ui/base'
+
+export default () => {
+ const { t } = useI18n()
+ const $currentConversationId = useStore(currentConversationId)
+ const messages = getMessagesByConversationId($currentConversationId())
+
+ console.log($currentConversationId(), messages)
+ return (
+
+
+
{t('conversations.share.messages.title')}
+
+
+
+ {item => (
+
+
+
+ )}
+
+
+
{t('settings.save')}
+
+ )
+}
diff --git a/src/components/ui/ShareModal.tsx b/src/components/ui/ShareModal.tsx
index 0e54847d..0748e0a8 100644
--- a/src/components/ui/ShareModal.tsx
+++ b/src/components/ui/ShareModal.tsx
@@ -3,6 +3,7 @@ import { For } from 'solid-js'
import { useClipboardCopy, useI18n } from '@/hooks'
import { currentConversationId } from '@/stores/conversation'
import { getMessagesByConversationId } from '@/stores/messages'
+import { showSelectMessageModal, showShareModal } from '@/stores/ui'
import { Tabs } from '../ui/base'
import type { TabItem } from './base/Tabs'
@@ -20,7 +21,7 @@ export default () => {
value: 'context',
label: t('conversations.share.tabs.context'),
content:
-
copy()}>{copied() ? t('copyed') : t('conversations.share.copy')}
+
copy()}>{copied() ? t('copyed') : t('conversations.share.copy')}
{item => (
@@ -45,7 +46,13 @@ export default () => {
{t('conversations.share.link.create')}
-
+
{
+ showShareModal.set(false)
+ showSelectMessageModal.set(true)
+ }}
+ >
{t('conversations.share.messages.selected')}
2 Messages
diff --git a/src/components/ui/base/Checkbox.tsx b/src/components/ui/base/Checkbox.tsx
index bcd4a749..aca15ce6 100644
--- a/src/components/ui/base/Checkbox.tsx
+++ b/src/components/ui/base/Checkbox.tsx
@@ -8,17 +8,26 @@ interface Props {
}
export const Checkbox = (props: Props) => {
- const [state, send] = useMachine(checkbox.machine({ id: createUniqueId(), checked: props.initValue ?? false }))
+ const [state, send] = useMachine(checkbox.machine({
+ id: createUniqueId(),
+ checked: props.initValue ?? false,
+ onChange(detail) {
+ console.log('onChange', detail)
+ },
+ }))
const api = createMemo(() => checkbox.connect(state, send, normalizeProps))
return (
)
}
diff --git a/src/components/ui/base/Tabs.tsx b/src/components/ui/base/Tabs.tsx
index b3988414..b8c31492 100644
--- a/src/components/ui/base/Tabs.tsx
+++ b/src/components/ui/base/Tabs.tsx
@@ -23,7 +23,7 @@ export const Tabs = (props: Props) => {
return (
-
+
{item => (
diff --git a/src/stores/ui.ts b/src/stores/ui.ts
index 8f615168..6f1db443 100644
--- a/src/stores/ui.ts
+++ b/src/stores/ui.ts
@@ -7,6 +7,7 @@ export const showConversationEditModal = atom(false)
export const showEmojiPickerModal = atom(false)
export const showConfirmModal = atom(false)
export const showShareModal = atom(false)
+export const showSelectMessageModal = atom(false)
export const isSendBoxFocus = atom(false)
export const currentErrorMessage = atom(null)
From 017055db01da80b5f1888f0337fbedc40c9ef26f Mon Sep 17 00:00:00 2001
From: yzh990918 <251205668@qq.com>
Date: Fri, 9 Jun 2023 13:58:51 +0800
Subject: [PATCH 07/18] feat: add select message logic
---
src/components/ModalsLayer.tsx | 2 +-
src/components/ui/Modal.tsx | 4 ++
src/components/ui/SelectMessageModal.tsx | 54 +++++++++++++++++++-----
src/components/ui/ShareModal.tsx | 28 +++++++-----
src/components/ui/base/Checkbox.tsx | 9 +++-
src/locale/lang/en.ts | 2 +
src/locale/lang/zh-cn.ts | 2 +
src/logics/conversation.ts | 2 +
src/types/message.ts | 1 +
9 files changed, 80 insertions(+), 24 deletions(-)
diff --git a/src/components/ModalsLayer.tsx b/src/components/ModalsLayer.tsx
index 8ce03259..44cbe936 100644
--- a/src/components/ModalsLayer.tsx
+++ b/src/components/ModalsLayer.tsx
@@ -42,7 +42,7 @@ export default () => {
-
+ { showShareModal.set(true) }}>
diff --git a/src/components/ui/Modal.tsx b/src/components/ui/Modal.tsx
index 4c201ef6..4cb8e48c 100644
--- a/src/components/ui/Modal.tsx
+++ b/src/components/ui/Modal.tsx
@@ -11,6 +11,7 @@ interface Props {
direction: 'top' | 'bottom' | 'left' | 'right'
children: JSXElement
closeBtnClass?: string
+ closeCallback?: () => void
}
export default (props: Props) => {
@@ -19,6 +20,9 @@ export default (props: Props) => {
// TODO: set it to true will cause the modal closes exceptionally
// https://github.com/chakra-ui/zag/issues/596
closeOnOutsideClick: false,
+ onClose: () => {
+ props.closeCallback && props.closeCallback()
+ },
}))
const api = createMemo(() => dialog.connect(state, send, normalizeProps))
diff --git a/src/components/ui/SelectMessageModal.tsx b/src/components/ui/SelectMessageModal.tsx
index 31f99573..b4076cd4 100644
--- a/src/components/ui/SelectMessageModal.tsx
+++ b/src/components/ui/SelectMessageModal.tsx
@@ -1,31 +1,65 @@
import { useStore } from '@nanostores/solid'
-import { For } from 'solid-js'
+import { For, createSignal } from 'solid-js'
import { useI18n } from '@/hooks'
import { currentConversationId } from '@/stores/conversation'
-import { getMessagesByConversationId } from '@/stores/messages'
+import { getMessagesByConversationId, updateMessage } from '@/stores/messages'
+import { showSelectMessageModal, showShareModal } from '@/stores/ui'
import { Checkbox } from '../ui/base'
export default () => {
const { t } = useI18n()
const $currentConversationId = useStore(currentConversationId)
const messages = getMessagesByConversationId($currentConversationId())
+ const [checkAll, setCheckAll] = createSignal(messages.every(item => item.isSelected))
+ const [selectedMessages, setSelectedMessages] = createSignal(messages)
+
+ console.log(messages, selectedMessages())
+
+ const handleToggleMessages = (id: string) => {
+ messages.forEach((item) => {
+ if (item.id === id)
+ item.isSelected = !item.isSelected
+ })
+ setSelectedMessages(messages)
+ }
+
+ const handleSelectAll = () => {
+ messages.forEach((item) => {
+ item.isSelected = !checkAll()
+ })
+ setSelectedMessages(messages)
+ setCheckAll(!checkAll())
+ console.log(selectedMessages(), checkAll())
+ }
+
+ const handleSaveContext = () => {
+ messages.forEach((item) => {
+ updateMessage($currentConversationId(), item.id, { isSelected: item.isSelected })
+ })
+ showSelectMessageModal.set(false)
+ showShareModal.set(true)
+ }
- console.log($currentConversationId(), messages)
return (
{t('conversations.share.messages.title')}
-
- {item => (
-
-
-
- )}
+
+ handleSelectAll()} initValue={checkAll()} label={`${t('conversations.share.messages.selectAll')}`} />
+
+
+ {(item) => {
+ return (
+
+ handleToggleMessages(item.id)} initValue={item.isSelected} label={`${item.role}: ${item.content}`} />
+
+ )
+ }}
-
{t('settings.save')}
+
handleSaveContext()}>{t('settings.save')}
)
}
diff --git a/src/components/ui/ShareModal.tsx b/src/components/ui/ShareModal.tsx
index 0748e0a8..f7dbf7c5 100644
--- a/src/components/ui/ShareModal.tsx
+++ b/src/components/ui/ShareModal.tsx
@@ -10,7 +10,7 @@ import type { TabItem } from './base/Tabs'
export default () => {
const { t } = useI18n()
const $currentConversationId = useStore(currentConversationId)
- const messages = getMessagesByConversationId($currentConversationId())
+ const messages = getMessagesByConversationId($currentConversationId()).filter(item => item.isSelected)
console.log($currentConversationId(), messages)
@@ -21,15 +21,21 @@ export default () => {
value: 'context',
label: t('conversations.share.tabs.context'),
content:
-
copy()}>{copied() ? t('copyed') : t('conversations.share.copy')}
-
- {item => (
-
-
{item.role}:
-
{item.content}
+ {messages.length
+ ? (
+
+
copy()}>{copied() ? t('copyed') : t('conversations.share.copy')}
+
+ {item => (
+
+
{item.role}:
+
{item.content}
+
+ )}
+
- )}
-
+ )
+ :
{t('empty')}
}
,
},
{
@@ -49,12 +55,12 @@ export default () => {
{
- showShareModal.set(false)
showSelectMessageModal.set(true)
+ showShareModal.set(false)
}}
>
{t('conversations.share.messages.selected')}
- 2 Messages
+ {messages.length ? `${messages.length} Messages` : t('conversations.share.messages.title')}
diff --git a/src/components/ui/base/Checkbox.tsx b/src/components/ui/base/Checkbox.tsx
index aca15ce6..c6365920 100644
--- a/src/components/ui/base/Checkbox.tsx
+++ b/src/components/ui/base/Checkbox.tsx
@@ -1,10 +1,11 @@
import * as checkbox from '@zag-js/checkbox'
import { normalizeProps, useMachine } from '@zag-js/solid'
-import { createMemo, createUniqueId } from 'solid-js'
+import { createEffect, createMemo, createUniqueId } from 'solid-js'
interface Props {
initValue?: boolean
label: string
+ setValue: (v?: boolean) => void
}
export const Checkbox = (props: Props) => {
@@ -12,10 +13,14 @@ export const Checkbox = (props: Props) => {
id: createUniqueId(),
checked: props.initValue ?? false,
onChange(detail) {
- console.log('onChange', detail)
+ props.setValue(detail.checked as boolean)
},
}))
+ createEffect(() => {
+ console.log('props', props.initValue)
+ })
+
const api = createMemo(() => checkbox.connect(state, send, normalizeProps))
return (
diff --git a/src/locale/lang/en.ts b/src/locale/lang/en.ts
index dee18cdd..632c1ea9 100644
--- a/src/locale/lang/en.ts
+++ b/src/locale/lang/en.ts
@@ -42,6 +42,7 @@ export const en = {
messages: {
title: 'Select Message',
selected: 'Selected Messages',
+ selectAll: 'Select All',
},
tabs: {
context: 'Share Context',
@@ -49,6 +50,7 @@ export const en = {
},
},
},
+ empty: 'No data',
send: {
placeholder: 'Enter Something...',
},
diff --git a/src/locale/lang/zh-cn.ts b/src/locale/lang/zh-cn.ts
index 8a8aabb2..d0befa67 100644
--- a/src/locale/lang/zh-cn.ts
+++ b/src/locale/lang/zh-cn.ts
@@ -42,6 +42,7 @@ export const zhCN = {
messages: {
title: '选择消息',
selected: '已选择的消息',
+ selectAll: '全选',
},
tabs: {
context: '分享上下文',
@@ -49,6 +50,7 @@ export const zhCN = {
},
},
},
+ empty: '暂无数据',
send: {
placeholder: '输入内容...',
},
diff --git a/src/logics/conversation.ts b/src/logics/conversation.ts
index 0217ff73..3bf67e50 100644
--- a/src/logics/conversation.ts
+++ b/src/logics/conversation.ts
@@ -28,6 +28,7 @@ export const handlePrompt = async(conversation: Conversation, prompt?: string, s
role: 'user',
content: prompt,
dateTime: new Date().getTime(),
+ isSelected: false,
})
}
@@ -80,6 +81,7 @@ export const handlePrompt = async(conversation: Conversation, prompt?: string, s
content: typeof providerResponse === 'string' ? providerResponse : '',
stream: providerResponse instanceof ReadableStream,
dateTime: new Date().getTime(),
+ isSelected: false,
})
}
setLoadingStateByConversationId(conversation.id, false)
diff --git a/src/types/message.ts b/src/types/message.ts
index b91a5796..5c6f119c 100644
--- a/src/types/message.ts
+++ b/src/types/message.ts
@@ -8,6 +8,7 @@ export interface MessageInstance extends Message {
id: string
stream?: boolean
dateTime?: number
+ isSelected?: boolean
}
export interface ErrorMessage {
From 4de8a40679edaa4aac93dc1d6d61254b261677cb Mon Sep 17 00:00:00 2001
From: yzh990918 <251205668@qq.com>
Date: Fri, 9 Jun 2023 14:20:19 +0800
Subject: [PATCH 08/18] feat: add single message share logic
---
.../header/ConversationMessageShareButton.tsx | 11 ++++++++++-
src/components/main/MessageItem.tsx | 18 ++++++++++++++----
src/stores/messages.ts | 3 ++-
3 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/src/components/header/ConversationMessageShareButton.tsx b/src/components/header/ConversationMessageShareButton.tsx
index 9601b027..cb412c42 100644
--- a/src/components/header/ConversationMessageShareButton.tsx
+++ b/src/components/header/ConversationMessageShareButton.tsx
@@ -1,16 +1,25 @@
import { useStore } from '@nanostores/solid'
import { currentConversationId } from '@/stores/conversation'
import { showShareModal } from '@/stores/ui'
+import { getMessagesByConversationId, updateMessage } from '@/stores/messages'
export default () => {
const $currentConversationId = useStore(currentConversationId)
+ const handleShareContext = () => {
+ const messages = getMessagesByConversationId($currentConversationId())
+ messages.forEach((message) => {
+ updateMessage($currentConversationId(), message.id, { isSelected: true },
+ )
+ })
+ showShareModal.set(true)
+ }
return (
<>
{$currentConversationId() && (
{ showShareModal.set(true) }}
+ onClick={() => { handleShareContext() }}
>
diff --git a/src/components/main/MessageItem.tsx b/src/components/main/MessageItem.tsx
index 16597541..f59ee070 100644
--- a/src/components/main/MessageItem.tsx
+++ b/src/components/main/MessageItem.tsx
@@ -2,10 +2,10 @@ import { For, Show } from 'solid-js/web'
import { createSignal } from 'solid-js'
import { useStore } from '@nanostores/solid'
import { useClipboardCopy } from '@/hooks'
-import { deleteMessageByConversationId, spliceMessageByConversationId, spliceUpdateMessageByConversationId } from '@/stores/messages'
-import { conversationMap } from '@/stores/conversation'
+import { deleteMessageByConversationId, getMessagesByConversationId, spliceMessageByConversationId, spliceUpdateMessageByConversationId, updateMessage } from '@/stores/messages'
+import { conversationMap, currentConversationId } from '@/stores/conversation'
import { handlePrompt } from '@/logics/conversation'
-import { scrollController } from '@/stores/ui'
+import { scrollController, showShareModal } from '@/stores/ui'
import { globalAbortController } from '@/stores/settings'
import StreamableText from '../StreamableText'
import { DropDownMenu, Tooltip } from '../ui/base'
@@ -23,6 +23,7 @@ interface Props {
export default (props: Props) => {
let inputRef: HTMLTextAreaElement
const $conversationMap = useStore(conversationMap)
+ const $currentConversationId = useStore(currentConversationId)
const [showRawCode, setShowRawCode] = createSignal(false)
const [copied, setCopied] = createSignal(false)
@@ -58,6 +59,15 @@ export default (props: Props) => {
inputRef.focus()
}
+ const handleShareMessageItem = () => {
+ const messages = getMessagesByConversationId($currentConversationId())
+ messages.forEach((message) => {
+ updateMessage($currentConversationId(), message.id, { isSelected: props.message.id === message.id },
+ )
+ })
+ showShareModal.set(true)
+ }
+
const handleSend = () => {
if (!inputRef.value)
return
@@ -80,7 +90,7 @@ export default (props: Props) => {
{ id: 'edit', label: 'Edit message', icon: 'i-carbon:edit', role: 'user', action: handleEditMessageItem },
{ id: 'copy', label: 'Copy message', icon: 'i-carbon-copy', role: 'all', action: handleCopyMessageItem },
{ id: 'delete', label: 'Delete message', icon: 'i-carbon-trash-can', role: 'all', action: handleDeleteMessageItem },
- { id: 'share', label: 'Share message', icon: 'i-carbon:export', role: 'all' },
+ { id: 'share', label: 'Share message', icon: 'i-carbon:export', role: 'all', action: handleShareMessageItem },
])
if (props.message.role === 'user')
diff --git a/src/stores/messages.ts b/src/stores/messages.ts
index 418b5cf6..db16c21a 100644
--- a/src/stores/messages.ts
+++ b/src/stores/messages.ts
@@ -1,10 +1,11 @@
-import { action, map } from 'nanostores'
+import { action, atom, map } from 'nanostores'
import { conversationMessagesMapData } from './tests/message.mock'
import { db } from './storage/message'
import { updateConversationById } from './conversation'
import type { MessageInstance } from '@/types/message'
export const conversationMessagesMap = map>({})
+export const shareMessageIds = atom([])
export const rebuildMessagesStore = async() => {
const data = await db.exportData() || {}
From a130017942dd35c21b787d1d01fabaf47a21c2e9 Mon Sep 17 00:00:00 2001
From: yzh990918 <251205668@qq.com>
Date: Fri, 9 Jun 2023 17:19:10 +0800
Subject: [PATCH 09/18] feat: add generate image logic
---
package.json | 2 +
pnpm-lock.yaml | 120 +++++++++++++++++++++++++++++++
src/components/ui/ShareModal.tsx | 78 +++++++++++++++++++-
src/locale/lang/en.ts | 5 ++
src/locale/lang/zh-cn.ts | 5 ++
5 files changed, 208 insertions(+), 2 deletions(-)
diff --git a/package.json b/package.json
index 29a6be37..0bc92147 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
"@astrojs/vercel": "^3.2.2",
"@mapbox/rehype-prism": "^0.8.0",
"@nanostores/solid": "^0.3.2",
+ "@resvg/resvg-wasm": "^2.3.1",
"@solid-primitives/clipboard": "^1.5.4",
"@solid-primitives/keyboard": "^1.1.0",
"@solid-primitives/scheduled": "^1.3.2",
@@ -54,6 +55,7 @@
"remark-math": "^5.1.1",
"remark-parse": "^10.0.1",
"remark-rehype": "^10.1.0",
+ "satori": "^0.10.1",
"solid-emoji-picker": "^0.2.0",
"solid-js": "1.6.12",
"solid-transition-group": "^0.2.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c005f318..ac5aa366 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -19,6 +19,9 @@ dependencies:
'@nanostores/solid':
specifier: ^0.3.2
version: 0.3.2(nanostores@0.7.4)(solid-js@1.6.12)
+ '@resvg/resvg-wasm':
+ specifier: ^2.3.1
+ version: 2.4.1
'@solid-primitives/clipboard':
specifier: ^1.5.4
version: 1.5.4(solid-js@1.6.12)
@@ -115,6 +118,9 @@ dependencies:
remark-rehype:
specifier: ^10.1.0
version: 10.1.0
+ satori:
+ specifier: ^0.10.1
+ version: 0.10.1
solid-emoji-picker:
specifier: ^0.2.0
version: 0.2.0(solid-js@1.6.12)
@@ -1968,6 +1974,11 @@ packages:
resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==}
dev: true
+ /@resvg/resvg-wasm@2.4.1:
+ resolution: {integrity: sha512-yi6R0HyHtsoWTRA06Col4WoDs7SvlXU3DLMNP2bdAgs7HK18dTEVl1weXgxRzi8gwLteGUbIg29zulxIB3GSdg==}
+ engines: {node: '>= 10'}
+ dev: false
+
/@rollup/plugin-babel@5.3.1(@babel/core@7.21.4)(rollup@2.79.1):
resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==}
engines: {node: '>= 10.0.0'}
@@ -2074,6 +2085,15 @@ packages:
rollup: 3.20.2
dev: true
+ /@shuding/opentype.js@1.4.0-beta.0:
+ resolution: {integrity: sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==}
+ engines: {node: '>= 8.0.0'}
+ hasBin: true
+ dependencies:
+ fflate: 0.7.4
+ string.prototype.codepointat: 0.2.1
+ dev: false
+
/@sindresorhus/is@0.14.0:
resolution: {integrity: sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==}
engines: {node: '>=6'}
@@ -3343,6 +3363,11 @@ packages:
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ /base64-js@0.0.8:
+ resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==}
+ engines: {node: '>= 0.4'}
+ dev: false
+
/base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
dev: false
@@ -3551,6 +3576,10 @@ packages:
engines: {node: '>=10'}
dev: false
+ /camelize@1.0.1:
+ resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==}
+ dev: false
+
/caniuse-lite@1.0.30001474:
resolution: {integrity: sha512-iaIZ8gVrWfemh5DG3T9/YqarVZoYf0r188IjaGwx68j4Pf0SGY6CQkmJUIE+NZHkkecQGohzXmBGEwWDr9aM3Q==}
@@ -3892,6 +3921,27 @@ packages:
resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
engines: {node: '>=8'}
+ /css-background-parser@0.1.0:
+ resolution: {integrity: sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==}
+ dev: false
+
+ /css-box-shadow@1.0.0-3:
+ resolution: {integrity: sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==}
+ dev: false
+
+ /css-color-keywords@1.0.0:
+ resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==}
+ engines: {node: '>=4'}
+ dev: false
+
+ /css-to-react-native@3.2.0:
+ resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==}
+ dependencies:
+ camelize: 1.0.1
+ css-color-keywords: 1.0.0
+ postcss-value-parser: 4.2.0
+ dev: false
+
/css-tree@2.3.1:
resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
@@ -4194,6 +4244,10 @@ packages:
'@emmetio/css-abbreviation': 2.1.6
dev: false
+ /emoji-regex@10.2.1:
+ resolution: {integrity: sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA==}
+ dev: false
+
/emoji-regex@7.0.3:
resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==}
dev: false
@@ -5151,6 +5205,10 @@ packages:
dependencies:
reusify: 1.0.4
+ /fflate@0.7.4:
+ resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==}
+ dev: false
+
/figures@3.2.0:
resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
engines: {node: '>=8'}
@@ -5731,6 +5789,11 @@ packages:
space-separated-tokens: 2.0.2
dev: false
+ /hex-rgb@4.3.0:
+ resolution: {integrity: sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==}
+ engines: {node: '>=6'}
+ dev: false
+
/homedir-polyfill@1.0.3:
resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==}
engines: {node: '>=0.10.0'}
@@ -6477,6 +6540,13 @@ packages:
engines: {node: '>=10'}
dev: true
+ /linebreak@1.1.0:
+ resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==}
+ dependencies:
+ base64-js: 0.0.8
+ unicode-trie: 2.0.0
+ dev: false
+
/lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
dev: true
@@ -7618,12 +7688,23 @@ packages:
semver: 6.3.0
dev: false
+ /pako@0.2.9:
+ resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
+ dev: false
+
/parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
dependencies:
callsites: 3.1.0
+ /parse-css-color@0.2.1:
+ resolution: {integrity: sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==}
+ dependencies:
+ color-name: 1.1.4
+ hex-rgb: 4.3.0
+ dev: false
+
/parse-entities@2.0.0:
resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==}
dependencies:
@@ -7776,6 +7857,10 @@ packages:
util-deprecate: 1.0.2
dev: true
+ /postcss-value-parser@4.2.0:
+ resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
+ dev: false
+
/postcss@8.4.21:
resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==}
engines: {node: ^10 || ^12 || >=14}
@@ -8401,6 +8486,22 @@ packages:
suf-log: 2.5.3
dev: false
+ /satori@0.10.1:
+ resolution: {integrity: sha512-F4bTCkDp931tLb7+UCNPBuSQwXhikrUkI4fBQo6fA8lF0Evqqgg3nDyUpRktQpR5Ry1DIiIVqLyEwkAms87ykg==}
+ engines: {node: '>=16'}
+ dependencies:
+ '@shuding/opentype.js': 1.4.0-beta.0
+ css-background-parser: 0.1.0
+ css-box-shadow: 1.0.0-3
+ css-to-react-native: 3.2.0
+ emoji-regex: 10.2.1
+ escape-html: 1.0.3
+ linebreak: 1.1.0
+ parse-css-color: 0.2.1
+ postcss-value-parser: 4.2.0
+ yoga-wasm-web: 0.3.3
+ dev: false
+
/section-matter@1.0.0:
resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
engines: {node: '>=4'}
@@ -8750,6 +8851,10 @@ packages:
emoji-regex: 9.2.2
strip-ansi: 7.0.1
+ /string.prototype.codepointat@0.2.1:
+ resolution: {integrity: sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==}
+ dev: false
+
/string.prototype.matchall@4.0.8:
resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==}
dependencies:
@@ -9003,6 +9108,10 @@ packages:
globalyzer: 0.1.0
globrex: 0.1.2
+ /tiny-inflate@1.0.3:
+ resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==}
+ dev: false
+
/tmp@0.0.33:
resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
engines: {node: '>=0.6.0'}
@@ -9211,6 +9320,13 @@ packages:
engines: {node: '>=4'}
dev: true
+ /unicode-trie@2.0.0:
+ resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==}
+ dependencies:
+ pako: 0.2.9
+ tiny-inflate: 1.0.3
+ dev: false
+
/unified@10.1.2:
resolution: {integrity: sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==}
dependencies:
@@ -10083,6 +10199,10 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
+ /yoga-wasm-web@0.3.3:
+ resolution: {integrity: sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==}
+ dev: false
+
/zod@3.21.4:
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
dev: false
diff --git a/src/components/ui/ShareModal.tsx b/src/components/ui/ShareModal.tsx
index f7dbf7c5..b6c8d2df 100644
--- a/src/components/ui/ShareModal.tsx
+++ b/src/components/ui/ShareModal.tsx
@@ -1,5 +1,7 @@
import { useStore } from '@nanostores/solid'
-import { For } from 'solid-js'
+import { For, Show, createSignal } from 'solid-js'
+import satori from 'satori'
+import * as resvg from '@resvg/resvg-wasm'
import { useClipboardCopy, useI18n } from '@/hooks'
import { currentConversationId } from '@/stores/conversation'
import { getMessagesByConversationId } from '@/stores/messages'
@@ -11,11 +13,62 @@ export default () => {
const { t } = useI18n()
const $currentConversationId = useStore(currentConversationId)
const messages = getMessagesByConversationId($currentConversationId()).filter(item => item.isSelected)
+ const [imageUrl, setImageUrl] = createSignal('')
+ const [loading, setLoading] = createSignal(false)
console.log($currentConversationId(), messages)
const [copied, copy] = useClipboardCopy(messages.map(item => `${item.role}: ${item.content}`).join('\n'))
+ const handleLoadImage = async() => {
+ let _result = ''
+ setLoading(true)
+ try {
+ const fontData = await fetch('https://cdn.jsdelivr.net/gh/yzh990918/static@master/20230609/Inter-Medium.388xm374fse8.ttf').then(res => res.arrayBuffer())
+ _result = await satori(
+ // TODO: context image dom
+ {
+ type: 'div',
+ props: {
+ children: 'hello, world',
+ style: { color: 'black' },
+ },
+ },
+ {
+ width: 600,
+ height: 400,
+ fonts: [
+ {
+ name: 'Inter-Medium',
+ data: fontData,
+ style: 'normal',
+ },
+ ],
+ },
+ )
+ await resvg.initWasm(fetch('https://unpkg.com/@resvg/resvg-wasm/index_bg.wasm'))
+ const res = new resvg.Resvg(_result, {
+ fitTo: {
+ mode: 'width',
+ value: 600,
+ },
+ })
+
+ const png = res.render()
+ const pngBuffer = png.asPng()
+ const url = URL.createObjectURL(new Blob([pngBuffer], { type: 'image/png' }))
+ if (url) {
+ setLoading(false)
+ setImageUrl(url)
+ console.log(url)
+ }
+ } catch (error) {
+ console.log(error)
+ } finally {
+ setLoading(false)
+ }
+ }
+
const tabs: TabItem[] = [
{
value: 'context',
@@ -41,7 +94,28 @@ export default () => {
{
value: 'image',
label: t('conversations.share.tabs.image'),
- content: image
,
+ content:
+ {messages.length
+ ? (
+
+
+
+ { window.open(imageUrl()) }}>{t('conversations.share.image.open')}
+
+
+ handleLoadImage()}>{loading() ? t('conversations.share.image.loading') : t('conversations.share.image.btn')}
+
+
+
+
+
+
+
+
+
+ )
+ :
{t('empty')}
}
+
,
},
]
diff --git a/src/locale/lang/en.ts b/src/locale/lang/en.ts
index 632c1ea9..2cec69eb 100644
--- a/src/locale/lang/en.ts
+++ b/src/locale/lang/en.ts
@@ -48,6 +48,11 @@ export const en = {
context: 'Share Context',
image: 'Share Image',
},
+ image: {
+ btn: 'Generate Image',
+ open: 'Open in Tab',
+ loading: 'Generating...',
+ },
},
},
empty: 'No data',
diff --git a/src/locale/lang/zh-cn.ts b/src/locale/lang/zh-cn.ts
index d0befa67..15f6b7ae 100644
--- a/src/locale/lang/zh-cn.ts
+++ b/src/locale/lang/zh-cn.ts
@@ -48,6 +48,11 @@ export const zhCN = {
context: '分享上下文',
image: '分享图片',
},
+ image: {
+ btn: '生成图片',
+ open: '新窗口打开',
+ loading: '生成中...',
+ },
},
},
empty: '暂无数据',
From 75b67e2f729f3be869afc909dbad363441bae04d Mon Sep 17 00:00:00 2001
From: yzh990918 <251205668@qq.com>
Date: Mon, 12 Jun 2023 15:32:41 +0800
Subject: [PATCH 10/18] feat: add tailwindcss support, add copy image btn
---
src/components/ui/ShareModal.tsx | 34 +++++++++++++++++++++++++-------
src/hooks/useCopy.ts | 4 ++--
src/locale/lang/en.ts | 1 +
src/locale/lang/zh-cn.ts | 1 +
4 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/src/components/ui/ShareModal.tsx b/src/components/ui/ShareModal.tsx
index b6c8d2df..b15fe5e2 100644
--- a/src/components/ui/ShareModal.tsx
+++ b/src/components/ui/ShareModal.tsx
@@ -1,8 +1,8 @@
import { useStore } from '@nanostores/solid'
-import { For, Show, createSignal } from 'solid-js'
+import { For, Show, createEffect, createSignal } from 'solid-js'
import satori from 'satori'
import * as resvg from '@resvg/resvg-wasm'
-import { useClipboardCopy, useI18n } from '@/hooks'
+import { useClipboardCopy, useDark, useI18n } from '@/hooks'
import { currentConversationId } from '@/stores/conversation'
import { getMessagesByConversationId } from '@/stores/messages'
import { showSelectMessageModal, showShareModal } from '@/stores/ui'
@@ -14,24 +14,43 @@ export default () => {
const $currentConversationId = useStore(currentConversationId)
const messages = getMessagesByConversationId($currentConversationId()).filter(item => item.isSelected)
const [imageUrl, setImageUrl] = createSignal('')
+ const [imageBuffer, setImageBuffer] = createSignal()
const [loading, setLoading] = createSignal(false)
+ const [isDark] = useDark()
console.log($currentConversationId(), messages)
const [copied, copy] = useClipboardCopy(messages.map(item => `${item.role}: ${item.content}`).join('\n'))
+ const copyImage = () => {
+ const [,copy] = useClipboardCopy(imageBuffer()!)
+ copy()
+ }
+
+ createEffect(async() => {
+ try {
+ await resvg.initWasm(fetch('https://unpkg.com/@resvg/resvg-wasm/index_bg.wasm'))
+ } catch (error) {
+ }
+ }, [])
+
const handleLoadImage = async() => {
let _result = ''
setLoading(true)
try {
const fontData = await fetch('https://cdn.jsdelivr.net/gh/yzh990918/static@master/20230609/Inter-Medium.388xm374fse8.ttf').then(res => res.arrayBuffer())
_result = await satori(
- // TODO: context image dom
{
type: 'div',
props: {
- children: 'hello, world',
- style: { color: 'black' },
+ tw: isDark() ? 'flex flex-col items-stretch w-full h-full text-white bg-[#3333333] p-0' : 'flex flex-col items-stretch w-full h-full text-black bg-white/90 p-0',
+ children: messages.map(item => ({
+ type: 'div',
+ props: {
+ tw: 'flex items-center w-full h-12 px-4',
+ children: item.content as string,
+ },
+ })),
},
},
{
@@ -46,7 +65,6 @@ export default () => {
],
},
)
- await resvg.initWasm(fetch('https://unpkg.com/@resvg/resvg-wasm/index_bg.wasm'))
const res = new resvg.Resvg(_result, {
fitTo: {
mode: 'width',
@@ -56,6 +74,7 @@ export default () => {
const png = res.render()
const pngBuffer = png.asPng()
+ setImageBuffer(new Blob([pngBuffer], { type: 'image/png' }))
const url = URL.createObjectURL(new Blob([pngBuffer], { type: 'image/png' }))
if (url) {
setLoading(false)
@@ -100,7 +119,8 @@ export default () => {
- { window.open(imageUrl()) }}>{t('conversations.share.image.open')}
+ { copyImage() }}>{t('conversations.share.image.copy')}
+ { window.open(imageUrl()) }}>{t('conversations.share.image.open')}
handleLoadImage()}>{loading() ? t('conversations.share.image.loading') : t('conversations.share.image.btn')}
diff --git a/src/hooks/useCopy.ts b/src/hooks/useCopy.ts
index 873c9ada..b9dc4e57 100644
--- a/src/hooks/useCopy.ts
+++ b/src/hooks/useCopy.ts
@@ -1,11 +1,11 @@
import { createEffect, createSignal } from 'solid-js'
import { writeClipboard } from '@solid-primitives/clipboard'
-export const useClipboardCopy = (source: string, delay = 1000) => {
+export const useClipboardCopy = (source: string | Blob, delay = 1000) => {
const [copied, setCopied] = createSignal(false)
const copy = async() => {
- writeClipboard(source)
+ writeClipboard(typeof source === 'string' ? source : [new ClipboardItem({ [source.type]: source })])
setCopied(true)
}
diff --git a/src/locale/lang/en.ts b/src/locale/lang/en.ts
index 2cec69eb..698fc723 100644
--- a/src/locale/lang/en.ts
+++ b/src/locale/lang/en.ts
@@ -52,6 +52,7 @@ export const en = {
btn: 'Generate Image',
open: 'Open in Tab',
loading: 'Generating...',
+ copy: 'Copy Image',
},
},
},
diff --git a/src/locale/lang/zh-cn.ts b/src/locale/lang/zh-cn.ts
index 15f6b7ae..adbb721c 100644
--- a/src/locale/lang/zh-cn.ts
+++ b/src/locale/lang/zh-cn.ts
@@ -52,6 +52,7 @@ export const zhCN = {
btn: '生成图片',
open: '新窗口打开',
loading: '生成中...',
+ copy: '复制图片',
},
},
},
From efbad862388e1fa178c27eea4577a47dfc0456c8 Mon Sep 17 00:00:00 2001
From: Diu
Date: Wed, 14 Jun 2023 13:20:36 +0800
Subject: [PATCH 11/18] feat(openai): add model `gpt-4-0613` and
`gpt-3.5-turbo-0613`
---
src/providers/openai/index.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/providers/openai/index.ts b/src/providers/openai/index.ts
index 8464e50f..a2fbefb6 100644
--- a/src/providers/openai/index.ts
+++ b/src/providers/openai/index.ts
@@ -31,9 +31,11 @@ const providerOpenAI = () => {
{ value: 'gpt-3.5-turbo', label: 'gpt-3.5-turbo' },
{ value: 'gpt-4', label: 'gpt-4' },
{ value: 'gpt-4-0314', label: 'gpt-4-0314' },
+ { value: 'gpt-4-0613', label: 'gpt-4-0613' },
{ value: 'gpt-4-32k', label: 'gpt-4-32k' },
{ value: 'gpt-4-32k-0314', label: 'gpt-4-32k-0314' },
{ value: 'gpt-3.5-turbo-0301', label: 'gpt-3.5-turbo-0301' },
+ { value: 'gpt-3.5-turbo-0613', label: 'gpt-3.5-turbo-0613' },
],
default: 'gpt-3.5-turbo',
},
From ca74062f63a55abb0393f4271e1891f1124d3412 Mon Sep 17 00:00:00 2001
From: Diu
Date: Wed, 14 Jun 2023 13:25:06 +0800
Subject: [PATCH 12/18] feat(openai): add model `gpt-4-32k-0613` and
`gpt-3.5-turbo-16k`
---
src/providers/openai/index.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/providers/openai/index.ts b/src/providers/openai/index.ts
index a2fbefb6..348609c4 100644
--- a/src/providers/openai/index.ts
+++ b/src/providers/openai/index.ts
@@ -34,8 +34,10 @@ const providerOpenAI = () => {
{ value: 'gpt-4-0613', label: 'gpt-4-0613' },
{ value: 'gpt-4-32k', label: 'gpt-4-32k' },
{ value: 'gpt-4-32k-0314', label: 'gpt-4-32k-0314' },
+ { value: 'gpt-4-32k-0613', label: 'gpt-4-32k-0613' },
{ value: 'gpt-3.5-turbo-0301', label: 'gpt-3.5-turbo-0301' },
{ value: 'gpt-3.5-turbo-0613', label: 'gpt-3.5-turbo-0613' },
+ { value: 'gpt-3.5-turbo-16k', label: 'gpt-3.5-turbo-16k' },
],
default: 'gpt-3.5-turbo',
},
From 18c9cd60ba6fa5c8dfc331f6ea210541d3ba49cd Mon Sep 17 00:00:00 2001
From: Nova Tsui
Date: Thu, 15 Jun 2023 11:30:38 +0800
Subject: [PATCH 13/18] refactor: Refactor conversation logic and logging
statements. (#64)
---
src/logics/conversation.ts | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/logics/conversation.ts b/src/logics/conversation.ts
index c187db47..6529edd9 100644
--- a/src/logics/conversation.ts
+++ b/src/logics/conversation.ts
@@ -122,7 +122,20 @@ const getProviderResponse = async(providerId: string, payload: HandlerPayload, o
// Called by both client and server
export const callProviderHandler = async(providerId: string, payload: HandlerPayload, signal?: AbortSignal) => {
- console.log('callProviderHandler', payload)
+ // To filter out sensitive fields, such as `apiKey` and `prompt`
+ console.log('callProviderHandler', {
+ conversationId: payload.conversationId,
+ conversationType: payload.conversationType,
+ botId: payload.botId,
+ globalSettings: {
+ baseUrl: payload.globalSettings?.baseUrl,
+ model: payload.globalSettings?.model,
+ maxTokens: payload.globalSettings?.maxTokens,
+ temperature: payload.globalSettings?.temperature,
+ top_p: payload.globalSettings?.top_p,
+ },
+ botSettings: payload.botSettings,
+ })
const provider = getProviderById(providerId)
if (!provider) return
From e78291514122b661c8165488354cc7943b97d111 Mon Sep 17 00:00:00 2001
From: yzh990918 <251205668@qq.com>
Date: Thu, 15 Jun 2023 18:15:01 +0800
Subject: [PATCH 14/18] feat: use html2Canvas to save image
---
package.json | 3 +-
pnpm-lock.yaml | 148 +++++------------------
src/components/main/Continuous.tsx | 41 +++++--
src/components/main/MessageItem.tsx | 2 +-
src/components/ui/SelectMessageModal.tsx | 6 +-
src/components/ui/ShareModal.tsx | 71 +++--------
src/components/ui/base/Checkbox.tsx | 6 +-
unocss.config.ts | 4 +
8 files changed, 85 insertions(+), 196 deletions(-)
diff --git a/package.json b/package.json
index 0bc92147..a0faf0cd 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,6 @@
"@astrojs/vercel": "^3.2.2",
"@mapbox/rehype-prism": "^0.8.0",
"@nanostores/solid": "^0.3.2",
- "@resvg/resvg-wasm": "^2.3.1",
"@solid-primitives/clipboard": "^1.5.4",
"@solid-primitives/keyboard": "^1.1.0",
"@solid-primitives/scheduled": "^1.3.2",
@@ -55,7 +54,6 @@
"remark-math": "^5.1.1",
"remark-parse": "^10.0.1",
"remark-rehype": "^10.1.0",
- "satori": "^0.10.1",
"solid-emoji-picker": "^0.2.0",
"solid-js": "1.6.12",
"solid-transition-group": "^0.2.2",
@@ -71,6 +69,7 @@
"@unocss/preset-icons": "^0.50.6",
"@unocss/preset-typography": "^0.50.6",
"eslint-plugin-astro": "^0.24.0",
+ "html2canvas": "^1.4.1",
"lint-staged": "^13.2.2",
"punycode": "^2.3.0",
"simple-git-hooks": "^2.8.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ac5aa366..5f93bd76 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -19,9 +19,6 @@ dependencies:
'@nanostores/solid':
specifier: ^0.3.2
version: 0.3.2(nanostores@0.7.4)(solid-js@1.6.12)
- '@resvg/resvg-wasm':
- specifier: ^2.3.1
- version: 2.4.1
'@solid-primitives/clipboard':
specifier: ^1.5.4
version: 1.5.4(solid-js@1.6.12)
@@ -118,9 +115,6 @@ dependencies:
remark-rehype:
specifier: ^10.1.0
version: 10.1.0
- satori:
- specifier: ^0.10.1
- version: 0.10.1
solid-emoji-picker:
specifier: ^0.2.0
version: 0.2.0(solid-js@1.6.12)
@@ -162,6 +156,9 @@ devDependencies:
eslint-plugin-astro:
specifier: ^0.24.0
version: 0.24.0(eslint@8.37.0)
+ html2canvas:
+ specifier: ^1.4.1
+ version: 1.4.1
lint-staged:
specifier: ^13.2.2
version: 13.2.2
@@ -1974,11 +1971,6 @@ packages:
resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==}
dev: true
- /@resvg/resvg-wasm@2.4.1:
- resolution: {integrity: sha512-yi6R0HyHtsoWTRA06Col4WoDs7SvlXU3DLMNP2bdAgs7HK18dTEVl1weXgxRzi8gwLteGUbIg29zulxIB3GSdg==}
- engines: {node: '>= 10'}
- dev: false
-
/@rollup/plugin-babel@5.3.1(@babel/core@7.21.4)(rollup@2.79.1):
resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==}
engines: {node: '>= 10.0.0'}
@@ -2085,15 +2077,6 @@ packages:
rollup: 3.20.2
dev: true
- /@shuding/opentype.js@1.4.0-beta.0:
- resolution: {integrity: sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==}
- engines: {node: '>= 8.0.0'}
- hasBin: true
- dependencies:
- fflate: 0.7.4
- string.prototype.codepointat: 0.2.1
- dev: false
-
/@sindresorhus/is@0.14.0:
resolution: {integrity: sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==}
engines: {node: '>=6'}
@@ -3363,10 +3346,10 @@ packages:
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
- /base64-js@0.0.8:
- resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==}
- engines: {node: '>= 0.4'}
- dev: false
+ /base64-arraybuffer@1.0.2:
+ resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
+ engines: {node: '>= 0.6.0'}
+ dev: true
/base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@@ -3576,10 +3559,6 @@ packages:
engines: {node: '>=10'}
dev: false
- /camelize@1.0.1:
- resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==}
- dev: false
-
/caniuse-lite@1.0.30001474:
resolution: {integrity: sha512-iaIZ8gVrWfemh5DG3T9/YqarVZoYf0r188IjaGwx68j4Pf0SGY6CQkmJUIE+NZHkkecQGohzXmBGEwWDr9aM3Q==}
@@ -3921,26 +3900,11 @@ packages:
resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
engines: {node: '>=8'}
- /css-background-parser@0.1.0:
- resolution: {integrity: sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==}
- dev: false
-
- /css-box-shadow@1.0.0-3:
- resolution: {integrity: sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==}
- dev: false
-
- /css-color-keywords@1.0.0:
- resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==}
- engines: {node: '>=4'}
- dev: false
-
- /css-to-react-native@3.2.0:
- resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==}
+ /css-line-break@2.1.0:
+ resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==}
dependencies:
- camelize: 1.0.1
- css-color-keywords: 1.0.0
- postcss-value-parser: 4.2.0
- dev: false
+ utrie: 1.0.2
+ dev: true
/css-tree@2.3.1:
resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
@@ -4244,10 +4208,6 @@ packages:
'@emmetio/css-abbreviation': 2.1.6
dev: false
- /emoji-regex@10.2.1:
- resolution: {integrity: sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA==}
- dev: false
-
/emoji-regex@7.0.3:
resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==}
dev: false
@@ -5205,10 +5165,6 @@ packages:
dependencies:
reusify: 1.0.4
- /fflate@0.7.4:
- resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==}
- dev: false
-
/figures@3.2.0:
resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
engines: {node: '>=8'}
@@ -5789,11 +5745,6 @@ packages:
space-separated-tokens: 2.0.2
dev: false
- /hex-rgb@4.3.0:
- resolution: {integrity: sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==}
- engines: {node: '>=6'}
- dev: false
-
/homedir-polyfill@1.0.3:
resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==}
engines: {node: '>=0.10.0'}
@@ -5816,6 +5767,14 @@ packages:
resolution: {integrity: sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==}
dev: false
+ /html2canvas@1.4.1:
+ resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
+ engines: {node: '>=8.0.0'}
+ dependencies:
+ css-line-break: 2.1.0
+ text-segmentation: 1.0.3
+ dev: true
+
/htmlparser2@7.2.0:
resolution: {integrity: sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==}
dependencies:
@@ -6540,13 +6499,6 @@ packages:
engines: {node: '>=10'}
dev: true
- /linebreak@1.1.0:
- resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==}
- dependencies:
- base64-js: 0.0.8
- unicode-trie: 2.0.0
- dev: false
-
/lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
dev: true
@@ -7688,23 +7640,12 @@ packages:
semver: 6.3.0
dev: false
- /pako@0.2.9:
- resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
- dev: false
-
/parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
dependencies:
callsites: 3.1.0
- /parse-css-color@0.2.1:
- resolution: {integrity: sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==}
- dependencies:
- color-name: 1.1.4
- hex-rgb: 4.3.0
- dev: false
-
/parse-entities@2.0.0:
resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==}
dependencies:
@@ -7857,10 +7798,6 @@ packages:
util-deprecate: 1.0.2
dev: true
- /postcss-value-parser@4.2.0:
- resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
- dev: false
-
/postcss@8.4.21:
resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==}
engines: {node: ^10 || ^12 || >=14}
@@ -8486,22 +8423,6 @@ packages:
suf-log: 2.5.3
dev: false
- /satori@0.10.1:
- resolution: {integrity: sha512-F4bTCkDp931tLb7+UCNPBuSQwXhikrUkI4fBQo6fA8lF0Evqqgg3nDyUpRktQpR5Ry1DIiIVqLyEwkAms87ykg==}
- engines: {node: '>=16'}
- dependencies:
- '@shuding/opentype.js': 1.4.0-beta.0
- css-background-parser: 0.1.0
- css-box-shadow: 1.0.0-3
- css-to-react-native: 3.2.0
- emoji-regex: 10.2.1
- escape-html: 1.0.3
- linebreak: 1.1.0
- parse-css-color: 0.2.1
- postcss-value-parser: 4.2.0
- yoga-wasm-web: 0.3.3
- dev: false
-
/section-matter@1.0.0:
resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
engines: {node: '>=4'}
@@ -8851,10 +8772,6 @@ packages:
emoji-regex: 9.2.2
strip-ansi: 7.0.1
- /string.prototype.codepointat@0.2.1:
- resolution: {integrity: sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==}
- dev: false
-
/string.prototype.matchall@4.0.8:
resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==}
dependencies:
@@ -9091,6 +9008,12 @@ packages:
source-map-support: 0.5.21
dev: true
+ /text-segmentation@1.0.3:
+ resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==}
+ dependencies:
+ utrie: 1.0.2
+ dev: true
+
/text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
@@ -9108,10 +9031,6 @@ packages:
globalyzer: 0.1.0
globrex: 0.1.2
- /tiny-inflate@1.0.3:
- resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==}
- dev: false
-
/tmp@0.0.33:
resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
engines: {node: '>=0.6.0'}
@@ -9320,13 +9239,6 @@ packages:
engines: {node: '>=4'}
dev: true
- /unicode-trie@2.0.0:
- resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==}
- dependencies:
- pako: 0.2.9
- tiny-inflate: 1.0.3
- dev: false
-
/unified@10.1.2:
resolution: {integrity: sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==}
dependencies:
@@ -9586,6 +9498,12 @@ packages:
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+ /utrie@1.0.2:
+ resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==}
+ dependencies:
+ base64-arraybuffer: 1.0.2
+ dev: true
+
/uvu@0.5.6:
resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==}
engines: {node: '>=8'}
@@ -10199,10 +10117,6 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
- /yoga-wasm-web@0.3.3:
- resolution: {integrity: sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==}
- dev: false
-
/zod@3.21.4:
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
dev: false
diff --git a/src/components/main/Continuous.tsx b/src/components/main/Continuous.tsx
index 864328d3..ef090714 100644
--- a/src/components/main/Continuous.tsx
+++ b/src/components/main/Continuous.tsx
@@ -38,18 +38,35 @@ export default (props: Props) => {
return (
<>
{
return (
{
const [checkAll, setCheckAll] = createSignal(messages.every(item => item.isSelected))
const [selectedMessages, setSelectedMessages] = createSignal(messages)
- console.log(messages, selectedMessages())
-
const handleToggleMessages = (id: string) => {
messages.forEach((item) => {
if (item.id === id)
@@ -46,9 +44,9 @@ export default () => {
{t('conversations.share.messages.title')}
-
+ {/*
handleSelectAll()} initValue={checkAll()} label={`${t('conversations.share.messages.selectAll')}`} />
-
+
*/}
{(item) => {
return (
diff --git a/src/components/ui/ShareModal.tsx b/src/components/ui/ShareModal.tsx
index b15fe5e2..582217ec 100644
--- a/src/components/ui/ShareModal.tsx
+++ b/src/components/ui/ShareModal.tsx
@@ -1,8 +1,7 @@
import { useStore } from '@nanostores/solid'
-import { For, Show, createEffect, createSignal } from 'solid-js'
-import satori from 'satori'
-import * as resvg from '@resvg/resvg-wasm'
-import { useClipboardCopy, useDark, useI18n } from '@/hooks'
+import { For, Show, createSignal } from 'solid-js'
+import html2canvas from 'html2canvas'
+import { useClipboardCopy, useI18n } from '@/hooks'
import { currentConversationId } from '@/stores/conversation'
import { getMessagesByConversationId } from '@/stores/messages'
import { showSelectMessageModal, showShareModal } from '@/stores/ui'
@@ -16,7 +15,6 @@ export default () => {
const [imageUrl, setImageUrl] = createSignal('')
const [imageBuffer, setImageBuffer] = createSignal()
const [loading, setLoading] = createSignal(false)
- const [isDark] = useDark()
console.log($currentConversationId(), messages)
@@ -27,60 +25,23 @@ export default () => {
copy()
}
- createEffect(async() => {
- try {
- await resvg.initWasm(fetch('https://unpkg.com/@resvg/resvg-wasm/index_bg.wasm'))
- } catch (error) {
- }
- }, [])
-
const handleLoadImage = async() => {
- let _result = ''
setLoading(true)
try {
- const fontData = await fetch('https://cdn.jsdelivr.net/gh/yzh990918/static@master/20230609/Inter-Medium.388xm374fse8.ttf').then(res => res.arrayBuffer())
- _result = await satori(
- {
- type: 'div',
- props: {
- tw: isDark() ? 'flex flex-col items-stretch w-full h-full text-white bg-[#3333333] p-0' : 'flex flex-col items-stretch w-full h-full text-black bg-white/90 p-0',
- children: messages.map(item => ({
- type: 'div',
- props: {
- tw: 'flex items-center w-full h-12 px-4',
- children: item.content as string,
- },
- })),
- },
- },
- {
- width: 600,
- height: 400,
- fonts: [
- {
- name: 'Inter-Medium',
- data: fontData,
- style: 'normal',
- },
- ],
- },
- )
- const res = new resvg.Resvg(_result, {
- fitTo: {
- mode: 'width',
- value: 600,
- },
+ const messageWrapper = document.getElementById('message_list_wrapper') as HTMLDivElement
+ messageWrapper.style.display = 'block'
+ const canvas = await html2canvas(messageWrapper, {
+ useCORS: true,
+ })
+ messageWrapper.style.display = 'none'
+ canvas.toBlob((res) => {
+ if (res) {
+ setImageBuffer(res)
+ const url = URL.createObjectURL(res)
+ setLoading(false)
+ setImageUrl(url)
+ }
})
-
- const png = res.render()
- const pngBuffer = png.asPng()
- setImageBuffer(new Blob([pngBuffer], { type: 'image/png' }))
- const url = URL.createObjectURL(new Blob([pngBuffer], { type: 'image/png' }))
- if (url) {
- setLoading(false)
- setImageUrl(url)
- console.log(url)
- }
} catch (error) {
console.log(error)
} finally {
diff --git a/src/components/ui/base/Checkbox.tsx b/src/components/ui/base/Checkbox.tsx
index c6365920..7a904b94 100644
--- a/src/components/ui/base/Checkbox.tsx
+++ b/src/components/ui/base/Checkbox.tsx
@@ -1,6 +1,6 @@
import * as checkbox from '@zag-js/checkbox'
import { normalizeProps, useMachine } from '@zag-js/solid'
-import { createEffect, createMemo, createUniqueId } from 'solid-js'
+import { createMemo, createUniqueId } from 'solid-js'
interface Props {
initValue?: boolean
@@ -17,10 +17,6 @@ export const Checkbox = (props: Props) => {
},
}))
- createEffect(() => {
- console.log('props', props.initValue)
- })
-
const api = createMemo(() => checkbox.connect(state, send, normalizeProps))
return (
diff --git a/unocss.config.ts b/unocss.config.ts
index 7189d9a0..876507df 100644
--- a/unocss.config.ts
+++ b/unocss.config.ts
@@ -110,6 +110,10 @@ export default defineConfig({
outline: none;
-webkit-appearance: none
}
+ img { display: initial; }
+ .clipped {
+ clip-path: inset(0 100% 0 0);
+ }
`,
}],
})
From c7bea531961cff5f991f40a638ad0dc36abe07ba Mon Sep 17 00:00:00 2001
From: yzh990918 <251205668@qq.com>
Date: Thu, 15 Jun 2023 18:36:42 +0800
Subject: [PATCH 15/18] style: use group-hover to show DropDownMenu
---
src/components/main/MessageItem.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/main/MessageItem.tsx b/src/components/main/MessageItem.tsx
index d9397b94..e3e4f8b1 100644
--- a/src/components/main/MessageItem.tsx
+++ b/src/components/main/MessageItem.tsx
@@ -113,7 +113,7 @@ export default (props: Props) => {
>