@@ -3,11 +3,11 @@ import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
3
3
import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker' ;
4
4
import CompilerWorker from '../../src/workers/compiler?worker' ;
5
5
import FormatterWorker from '../../src/workers/formatter?worker' ;
6
- import { createTabList } from '../../src' ;
7
6
import { createEffect , createResource , createSignal , lazy , Suspense } from 'solid-js' ;
8
7
import { useParams } from 'solid-app-router' ;
9
8
import { API , useAppContext } from '../context' ;
10
9
import createDebounce from '@solid-primitives/debounce' ;
10
+ import type { Tab } from '../../src' ;
11
11
import type { APIRepl } from './home' ;
12
12
13
13
const Repl = lazy ( ( ) => import ( '../../src/components/repl' ) ) ;
@@ -26,53 +26,97 @@ const Repl = lazy(() => import('../../src/components/repl'));
26
26
} ,
27
27
} ;
28
28
29
+ // Custom version of createTabList that allows us to use a resource as the backing signal
30
+ const createTabList = ( ) => {
31
+ let sourceSignals : Record < string , [ get : ( ) => string , set : ( value : string ) => string ] > = { } ;
32
+
33
+ const mapTabs = ( tabs : Tab [ ] ) : Tab [ ] => {
34
+ const oldSignals = sourceSignals ;
35
+ sourceSignals = { } ;
36
+
37
+ return tabs . map ( ( tab ) => {
38
+ const id = `${ tab . name } .${ tab . type } ` ;
39
+ sourceSignals [ id ] = oldSignals [ id ] || createSignal ( tab . source ) ;
40
+ if ( oldSignals [ id ] ) oldSignals [ id ] [ 1 ] ( tab . source ) ;
41
+
42
+ return {
43
+ name : tab . name ,
44
+ type : tab . type ,
45
+ get source ( ) {
46
+ return sourceSignals [ id ] [ 0 ] ( ) ;
47
+ } ,
48
+ set source ( source : string ) {
49
+ sourceSignals [ id ] [ 1 ] ( source ) ;
50
+ } ,
51
+ } ;
52
+ } ) ;
53
+ } ;
54
+
55
+ return mapTabs ;
56
+ } ;
57
+
29
58
export const Edit = ( props : { dark : boolean ; horizontal : boolean } ) => {
30
59
const compiler = new CompilerWorker ( ) ;
31
60
const formatter = new FormatterWorker ( ) ;
32
61
33
62
const params = useParams ( ) ;
34
63
const context = useAppContext ( ) ! ;
35
- const [ fetchedTabs ] = createResource < APIRepl , string > ( params . repl , ( repl ) =>
36
- fetch ( `${ API } /repl/${ repl } ` ) . then ( ( r ) => r . json ( ) ) ,
37
- ) ;
38
64
39
- const [ tabs , setTabs ] = createTabList ( [ ] ) ;
65
+ const tabMapper = ( tabs : Tab [ ] ) => tabs . map ( ( x ) => ( { name : `${ x . name } .${ x . type } ` , content : x . source . split ( '\n' ) } ) ) ;
66
+ const mapTabs = createTabList ( ) ;
67
+ const [ resource , { mutate } ] = createResource < { tabs : Tab [ ] ; repl : APIRepl } , string > ( params . repl , async ( repl ) => {
68
+ let x : APIRepl = await fetch ( `${ API } /repl/${ repl } ` , {
69
+ headers : { authorization : `Bearer ${ context . token } ` } ,
70
+ } ) . then ( ( r ) => r . json ( ) ) ;
71
+
72
+ return {
73
+ repl : x ,
74
+ tabs : mapTabs (
75
+ x . files . map ( ( x ) => {
76
+ let dot = x . name . lastIndexOf ( '.' ) ;
77
+ return { name : x . name . slice ( 0 , dot ) , type : x . name . slice ( dot + 1 ) , source : x . content . join ( '\n' ) } ;
78
+ } ) ,
79
+ ) ,
80
+ } ;
81
+ } ) ;
82
+
40
83
const [ current , setCurrent ] = createSignal < string > ( ) ;
41
84
createEffect ( ( ) => {
42
- const myRepl = fetchedTabs ( ) ;
85
+ const myRepl = resource ( ) ;
43
86
if ( ! myRepl ) return ;
44
- setTabs (
45
- myRepl . files . map ( ( x ) => {
46
- let dot = x . name . lastIndexOf ( '.' ) ;
47
- return { name : x . name . slice ( 0 , dot ) , type : x . name . slice ( dot + 1 ) , source : x . content . join ( '\n' ) } ;
48
- } ) ,
49
- ) ;
50
- setCurrent ( myRepl . files [ 0 ] . name ) ;
87
+ setCurrent ( `${ myRepl . tabs [ 0 ] . name } .${ myRepl . tabs [ 0 ] . type } ` ) ;
51
88
} ) ;
52
89
53
- const tabMapper = ( ) => tabs ( ) . map ( ( x ) => ( { name : `${ x . name } .${ x . type } ` , content : x . source . split ( '\n' ) } ) ) ;
90
+ const tabs = ( ) => resource ( ) ?. tabs || [ ] ;
91
+ const setTabs = ( tabs : Tab [ ] ) => {
92
+ if ( resource . latest ) mutate ( { repl : resource . latest . repl , tabs : mapTabs ( tabs ) } ) ;
93
+ } ;
94
+
54
95
const updateRepl = createDebounce ( ( ) => {
55
- const repl = fetchedTabs ( ) ;
56
- const tabs = tabMapper ( ) ;
57
- if ( ! repl || ! tabs . length ) return ;
58
- fetch ( `${ API } /repl/${ repl . id } ` , {
96
+ const repl = resource ( ) ;
97
+ if ( ! repl ) return ;
98
+ const tabs = tabMapper ( repl . tabs ) ;
99
+ fetch ( `${ API } /repl/${ params . repl } ` , {
59
100
method : 'PUT' ,
60
101
headers : {
61
102
authorization : `Bearer ${ context . token } ` ,
62
103
'Content-Type' : 'application/json' ,
63
104
} ,
64
105
body : JSON . stringify ( {
65
- title : repl . title ,
66
- version : repl . version ,
67
- public : repl . public ,
68
- labels : repl . labels ,
106
+ title : repl . repl . title ,
107
+ version : repl . repl . version ,
108
+ public : repl . repl . public ,
109
+ labels : repl . repl . labels ,
69
110
files : tabs ,
70
111
} ) ,
71
112
} ) ;
72
113
} , 1000 ) ;
114
+
115
+ let firstRun = true ;
73
116
createEffect ( ( ) => {
74
- tabMapper ( ) ;
75
- updateRepl ( ) ;
117
+ tabMapper ( tabs ( ) ) ; // use the latest value on debounce, and just throw this value away (but use it to track)
118
+ if ( firstRun ) firstRun = false ;
119
+ else updateRepl ( ) ;
76
120
} ) ;
77
121
78
122
return (
0 commit comments