1
1
import { useStore } from '@nanostores/solid'
2
- import { For , Show , createSignal } from 'solid-js'
2
+ import { For , Show , createEffect , createSignal } from 'solid-js'
3
3
import satori from 'satori'
4
4
import * as resvg from '@resvg/resvg-wasm'
5
- import { useClipboardCopy , useI18n } from '@/hooks'
5
+ import { useClipboardCopy , useDark , useI18n } from '@/hooks'
6
6
import { currentConversationId } from '@/stores/conversation'
7
7
import { getMessagesByConversationId } from '@/stores/messages'
8
8
import { showSelectMessageModal , showShareModal } from '@/stores/ui'
@@ -14,24 +14,43 @@ export default () => {
14
14
const $currentConversationId = useStore ( currentConversationId )
15
15
const messages = getMessagesByConversationId ( $currentConversationId ( ) ) . filter ( item => item . isSelected )
16
16
const [ imageUrl , setImageUrl ] = createSignal ( '' )
17
+ const [ imageBuffer , setImageBuffer ] = createSignal < Blob > ( )
17
18
const [ loading , setLoading ] = createSignal ( false )
19
+ const [ isDark ] = useDark ( )
18
20
19
21
console . log ( $currentConversationId ( ) , messages )
20
22
21
23
const [ copied , copy ] = useClipboardCopy ( messages . map ( item => `${ item . role } : ${ item . content } ` ) . join ( '\n' ) )
22
24
25
+ const copyImage = ( ) => {
26
+ const [ , copy ] = useClipboardCopy ( imageBuffer ( ) ! )
27
+ copy ( )
28
+ }
29
+
30
+ createEffect ( async ( ) => {
31
+ try {
32
+ await resvg . initWasm ( fetch ( 'https://unpkg.com/@resvg/resvg-wasm/index_bg.wasm' ) )
33
+ } catch ( error ) {
34
+ }
35
+ } , [ ] )
36
+
23
37
const handleLoadImage = async ( ) => {
24
38
let _result = ''
25
39
setLoading ( true )
26
40
try {
27
41
const fontData = await fetch ( 'https://cdn.jsdelivr.net/gh/yzh990918/static@master/20230609/Inter-Medium.388xm374fse8.ttf' ) . then ( res => res . arrayBuffer ( ) )
28
42
_result = await satori (
29
- // TODO: context image dom
30
43
{
31
44
type : 'div' ,
32
45
props : {
33
- children : 'hello, world' ,
34
- style : { color : 'black' } ,
46
+ 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' ,
47
+ children : messages . map ( item => ( {
48
+ type : 'div' ,
49
+ props : {
50
+ tw : 'flex items-center w-full h-12 px-4' ,
51
+ children : item . content as string ,
52
+ } ,
53
+ } ) ) ,
35
54
} ,
36
55
} ,
37
56
{
@@ -46,7 +65,6 @@ export default () => {
46
65
] ,
47
66
} ,
48
67
)
49
- await resvg . initWasm ( fetch ( 'https://unpkg.com/@resvg/resvg-wasm/index_bg.wasm' ) )
50
68
const res = new resvg . Resvg ( _result , {
51
69
fitTo : {
52
70
mode : 'width' ,
@@ -56,6 +74,7 @@ export default () => {
56
74
57
75
const png = res . render ( )
58
76
const pngBuffer = png . asPng ( )
77
+ setImageBuffer ( new Blob ( [ pngBuffer ] , { type : 'image/png' } ) )
59
78
const url = URL . createObjectURL ( new Blob ( [ pngBuffer ] , { type : 'image/png' } ) )
60
79
if ( url ) {
61
80
setLoading ( false )
@@ -100,7 +119,8 @@ export default () => {
100
119
< div class = "flex flex-col gap-2" >
101
120
< div class = "inline-block text-left" >
102
121
< Show when = { imageUrl ( ) . length } >
103
- < div class = "button inline-block mt-0 cursor-pointer mb-2" onClick = { ( ) => { window . open ( imageUrl ( ) ) } } > { t ( 'conversations.share.image.open' ) } </ div >
122
+ < div class = "button inline-block mt-0 cursor-pointer mb-2" onClick = { ( ) => { copyImage ( ) } } > { t ( 'conversations.share.image.copy' ) } </ div >
123
+ < div class = "button inline-block mt-0 cursor-pointer mb-2 ml-2" onClick = { ( ) => { window . open ( imageUrl ( ) ) } } > { t ( 'conversations.share.image.open' ) } </ div >
104
124
</ Show >
105
125
< Show when = { ! imageUrl ( ) . length } >
106
126
< div class = "emerald-light-button inline-block mt-0 cursor-pointer mb-2" onClick = { ( ) => handleLoadImage ( ) } > { loading ( ) ? t ( 'conversations.share.image.loading' ) : t ( 'conversations.share.image.btn' ) } </ div >
0 commit comments