1
1
import { useStore } from '@nanostores/solid'
2
- import { For } from 'solid-js'
2
+ import { For , Show , createSignal } from 'solid-js'
3
+ import satori from 'satori'
4
+ import * as resvg from '@resvg/resvg-wasm'
3
5
import { useClipboardCopy , useI18n } from '@/hooks'
4
6
import { currentConversationId } from '@/stores/conversation'
5
7
import { getMessagesByConversationId } from '@/stores/messages'
@@ -11,11 +13,62 @@ export default () => {
11
13
const { t } = useI18n ( )
12
14
const $currentConversationId = useStore ( currentConversationId )
13
15
const messages = getMessagesByConversationId ( $currentConversationId ( ) ) . filter ( item => item . isSelected )
16
+ const [ imageUrl , setImageUrl ] = createSignal ( '' )
17
+ const [ loading , setLoading ] = createSignal ( false )
14
18
15
19
console . log ( $currentConversationId ( ) , messages )
16
20
17
21
const [ copied , copy ] = useClipboardCopy ( messages . map ( item => `${ item . role } : ${ item . content } ` ) . join ( '\n' ) )
18
22
23
+ const handleLoadImage = async ( ) => {
24
+ let _result = ''
25
+ setLoading ( true )
26
+ try {
27
+ const fontData = await fetch ( 'https://cdn.jsdelivr.net/gh/yzh990918/static@master/20230609/Inter-Medium.388xm374fse8.ttf' ) . then ( res => res . arrayBuffer ( ) )
28
+ _result = await satori (
29
+ // TODO: context image dom
30
+ {
31
+ type : 'div' ,
32
+ props : {
33
+ children : 'hello, world' ,
34
+ style : { color : 'black' } ,
35
+ } ,
36
+ } ,
37
+ {
38
+ width : 600 ,
39
+ height : 400 ,
40
+ fonts : [
41
+ {
42
+ name : 'Inter-Medium' ,
43
+ data : fontData ,
44
+ style : 'normal' ,
45
+ } ,
46
+ ] ,
47
+ } ,
48
+ )
49
+ await resvg . initWasm ( fetch ( 'https://unpkg.com/@resvg/resvg-wasm/index_bg.wasm' ) )
50
+ const res = new resvg . Resvg ( _result , {
51
+ fitTo : {
52
+ mode : 'width' ,
53
+ value : 600 ,
54
+ } ,
55
+ } )
56
+
57
+ const png = res . render ( )
58
+ const pngBuffer = png . asPng ( )
59
+ const url = URL . createObjectURL ( new Blob ( [ pngBuffer ] , { type : 'image/png' } ) )
60
+ if ( url ) {
61
+ setLoading ( false )
62
+ setImageUrl ( url )
63
+ console . log ( url )
64
+ }
65
+ } catch ( error ) {
66
+ console . log ( error )
67
+ } finally {
68
+ setLoading ( false )
69
+ }
70
+ }
71
+
19
72
const tabs : TabItem [ ] = [
20
73
{
21
74
value : 'context' ,
@@ -41,7 +94,28 @@ export default () => {
41
94
{
42
95
value : 'image' ,
43
96
label : t ( 'conversations.share.tabs.image' ) ,
44
- content : < div class = "flex" > image</ div > ,
97
+ content : < div class = "flex flex-col gap-2" >
98
+ { messages . length
99
+ ? (
100
+ < div class = "flex flex-col gap-2" >
101
+ < div class = "inline-block text-left" >
102
+ < 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 >
104
+ </ Show >
105
+ < Show when = { ! imageUrl ( ) . length } >
106
+ < 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 >
107
+ </ Show >
108
+ </ div >
109
+ < Show when = { loading ( ) } >
110
+ < div class = "i-carbon:circle-solid text-slate-400 animate-ping mx-auto" />
111
+ </ Show >
112
+ < Show when = { imageUrl ( ) . length } >
113
+ < img src = { imageUrl ( ) } alt = "" />
114
+ </ Show >
115
+ </ div >
116
+ )
117
+ : < div class = "text-center text-sm" > { t ( 'empty' ) } </ div > }
118
+ </ div > ,
45
119
} ,
46
120
]
47
121
0 commit comments