@@ -3,11 +3,11 @@ import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
33import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker' ;
44import CompilerWorker from '../../src/workers/compiler?worker' ;
55import FormatterWorker from '../../src/workers/formatter?worker' ;
6- import { createTabList } from '../../src' ;
76import { createEffect , createResource , createSignal , lazy , Suspense } from 'solid-js' ;
87import { useParams } from 'solid-app-router' ;
98import { API , useAppContext } from '../context' ;
109import createDebounce from '@solid-primitives/debounce' ;
10+ import type { Tab } from '../../src' ;
1111import type { APIRepl } from './home' ;
1212
1313const Repl = lazy ( ( ) => import ( '../../src/components/repl' ) ) ;
@@ -26,53 +26,97 @@ const Repl = lazy(() => import('../../src/components/repl'));
2626 } ,
2727} ;
2828
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+
2958export const Edit = ( props : { dark : boolean ; horizontal : boolean } ) => {
3059 const compiler = new CompilerWorker ( ) ;
3160 const formatter = new FormatterWorker ( ) ;
3261
3362 const params = useParams ( ) ;
3463 const context = useAppContext ( ) ! ;
35- const [ fetchedTabs ] = createResource < APIRepl , string > ( params . repl , ( repl ) =>
36- fetch ( `${ API } /repl/${ repl } ` ) . then ( ( r ) => r . json ( ) ) ,
37- ) ;
3864
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+
4083 const [ current , setCurrent ] = createSignal < string > ( ) ;
4184 createEffect ( ( ) => {
42- const myRepl = fetchedTabs ( ) ;
85+ const myRepl = resource ( ) ;
4386 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 } ` ) ;
5188 } ) ;
5289
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+
5495 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 } ` , {
59100 method : 'PUT' ,
60101 headers : {
61102 authorization : `Bearer ${ context . token } ` ,
62103 'Content-Type' : 'application/json' ,
63104 } ,
64105 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 ,
69110 files : tabs ,
70111 } ) ,
71112 } ) ;
72113 } , 1000 ) ;
114+
115+ let firstRun = true ;
73116 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 ( ) ;
76120 } ) ;
77121
78122 return (
0 commit comments