@@ -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 { batch , createEffect , createResource , createSignal , lazy , Suspense } from 'solid-js' ;
7- import { useParams } from 'solid-app-router' ;
6+ import { batch , createResource , createSignal , lazy , Show , Suspense } from 'solid-js' ;
7+ import { useMatch , useNavigate , useParams } from 'solid-app-router' ;
88import { API , useAppContext } from '../context' ;
99import { debounce } from '@solid-primitives/scheduled' ;
10- import { createTabList , defaultTabs , Tab } from '../../src' ;
10+ import { defaultTabs , Tab } from '../../src' ;
1111import type { APIRepl } from './home' ;
1212import { Header } from '../components/header' ;
1313import { compressToURL } from '@amoutonbrady/lz-string' ;
@@ -28,136 +28,185 @@ const Repl = lazy(() => import('../../src/components/repl'));
2828 } ,
2929} ;
3030
31- export const Edit = ( props : { horizontal : boolean ; scratchpad ?: boolean } ) => {
31+ interface InternalTab extends Tab {
32+ _source : string ;
33+ }
34+ export const Edit = ( props : { horizontal : boolean } ) => {
35+ const scratchpad = useMatch ( ( ) => '/scratchpad' ) ;
3236 const compiler = new CompilerWorker ( ) ;
3337 const formatter = new FormatterWorker ( ) ;
3438
3539 const params = useParams ( ) ;
3640 const context = useAppContext ( ) ! ;
41+ const navigate = useNavigate ( ) ;
3742
38- let loaded = false ;
43+ let disableFetch : true | undefined ;
3944
40- const [ tabs , setTabs ] = createTabList ( [ ] ) ;
45+ let readonly = ( ) => ! scratchpad ( ) && context . user ( ) ?. display != params . user ;
46+
47+ const mapTabs = ( toMap : ( Tab | InternalTab ) [ ] ) : InternalTab [ ] =>
48+ toMap . map ( ( tab ) => {
49+ if ( ( tab as InternalTab ) . _source ) return tab as InternalTab ;
50+ return {
51+ name : tab . name ,
52+ _source : tab . source ,
53+ get source ( ) {
54+ return this . _source ;
55+ } ,
56+ set source ( source : string ) {
57+ this . _source = source ;
58+ if ( readonly ( ) ) {
59+ const myScratchpad = localStorage . getItem ( 'scratchpad' ) ;
60+ let output : APIRepl ;
61+ if ( ! myScratchpad ) {
62+ output = {
63+ id : 'scratchpad' ,
64+ title : resource . latest ?. title + ' - Forked' ,
65+ public : true ,
66+ version : '1.0' ,
67+ labels : [ ] ,
68+ size : 0 ,
69+ created_at : new Date ( ) . toISOString ( ) ,
70+ files : tabs ( ) ! . map ( ( x ) => ( {
71+ name : x . name ,
72+ content : x . source . split ( '\n' ) ,
73+ } ) ) ,
74+ } ;
75+ } else {
76+ output = JSON . parse ( myScratchpad ) ;
77+ output . files = tabs ( ) ! . map ( ( x ) => ( {
78+ name : x . name ,
79+ content : x . source . split ( '\n' ) ,
80+ } ) ) ;
81+ }
82+ localStorage . setItem ( 'scratchpad' , JSON . stringify ( output ) ) ;
83+ disableFetch = true ;
84+ navigate ( '/scratchpad' ) ;
85+ } else {
86+ updateRepl ( ) ;
87+ }
88+ } ,
89+ } ;
90+ } ) ;
91+
92+ const [ tabs , trueSetTabs ] = createSignal < InternalTab [ ] > ( [ ] ) ;
93+ const setTabs = ( tabs : ( Tab | InternalTab ) [ ] ) => trueSetTabs ( mapTabs ( tabs ) ) ;
4194 context . setTabs ( tabs ) ;
42- const [ current , setCurrent ] = createSignal < string > ( ) ;
43- const [ resource , { mutate } ] = createResource < APIRepl , string > ( async ( ) => {
44- const repl = params . repl ;
45-
46- let output : APIRepl ;
47- if ( props . scratchpad ) {
48- const scratchpad = localStorage . getItem ( 'scratchpad' ) ;
49- if ( ! scratchpad ) {
50- output = {
51- id : 'scratchpad' ,
52- title : 'Scratchpad' ,
53- public : true ,
54- version : '1.0' ,
55- labels : [ ] ,
56- size : 0 ,
57- created_at : new Date ( ) . toISOString ( ) ,
58- files : defaultTabs . map ( ( x ) => ( {
59- name : x . name ,
60- content : x . source . split ( '\n' ) ,
61- } ) ) ,
62- } ;
63- localStorage . setItem ( 'scratchpad' , JSON . stringify ( output ) ) ;
95+
96+ const [ current , setCurrent ] = createSignal < string | undefined > ( undefined , { equals : false } ) ;
97+ const [ resource , { mutate } ] = createResource < APIRepl , { repl : string ; scratchpad : boolean } > (
98+ ( ) => ( { repl : params . repl , scratchpad : ! ! scratchpad ( ) } ) ,
99+ async ( { repl, scratchpad } ) => {
100+ if ( disableFetch ) {
101+ disableFetch = undefined ;
102+ return resource . latest ;
103+ }
104+
105+ let output : APIRepl ;
106+ if ( scratchpad ) {
107+ const myScratchpad = localStorage . getItem ( 'scratchpad' ) ;
108+ if ( ! myScratchpad ) {
109+ output = {
110+ id : 'scratchpad' ,
111+ title : 'Scratchpad' ,
112+ public : true ,
113+ version : '1.0' ,
114+ labels : [ ] ,
115+ size : 0 ,
116+ created_at : new Date ( ) . toISOString ( ) ,
117+ files : defaultTabs . map ( ( x ) => ( {
118+ name : x . name ,
119+ content : x . source . split ( '\n' ) ,
120+ } ) ) ,
121+ } ;
122+ localStorage . setItem ( 'scratchpad' , JSON . stringify ( output ) ) ;
123+ } else {
124+ output = JSON . parse ( myScratchpad ) ;
125+ }
64126 } else {
65- output = JSON . parse ( scratchpad ) ;
127+ output = await fetch ( `${ API } /repl/${ repl } ` , {
128+ headers : { authorization : context . token ? `Bearer ${ context . token } ` : '' } ,
129+ } ) . then ( ( r ) => r . json ( ) ) ;
66130 }
67- } else {
68- output = await fetch ( `${ API } /repl/${ repl } ` , {
69- headers : { authorization : context . token ? `Bearer ${ context . token } ` : '' } ,
70- } ) . then ( ( r ) => r . json ( ) ) ;
71- }
72131
73- batch ( ( ) => {
74- setTabs (
75- output . files . map ( ( x ) => {
76- return { name : x . name , source : x . content . join ( '\n' ) } ;
77- } ) ,
78- ) ;
79- setCurrent ( output . files [ 0 ] . name ) ;
80- } ) ;
81- loaded = true ;
132+ console . log ( 'refetched' ) ;
133+
134+ batch ( ( ) => {
135+ setTabs (
136+ output . files . map ( ( x ) => {
137+ return { name : x . name , source : x . content . join ( '\n' ) } ;
138+ } ) ,
139+ ) ;
140+ setCurrent ( output . files [ 0 ] . name ) ;
141+ } ) ;
82142
83- return output ;
84- } ) ;
143+ return output ;
144+ } ,
145+ ) ;
85146
86- const tabMapper = ( tabs : Tab [ ] ) => tabs . map ( ( x ) => ( { name : x . name , content : x . source . split ( '\n' ) } ) ) ;
87147 const updateRepl = debounce (
88148 ( ) => {
89149 const repl = resource . latest ;
90150 if ( ! repl ) return ;
91151
92- const files = tabMapper ( tabs ( ) ) ;
93- if ( props . scratchpad ) {
152+ const files = tabs ( ) . map ( ( x ) => ( { name : x . name , content : x . source . split ( '\n' ) } ) ) ;
153+
154+ if ( scratchpad ( ) ) {
94155 localStorage . setItem ( 'scratchpad' , JSON . stringify ( { ...repl , files } ) ) ;
95- return ;
156+ } else if ( context . token && context . user ( ) ?. display == params . user ) {
157+ fetch ( `${ API } /repl/${ params . repl } ` , {
158+ method : 'PUT' ,
159+ headers : {
160+ 'authorization' : `Bearer ${ context . token } ` ,
161+ 'Content-Type' : 'application/json' ,
162+ } ,
163+ body : JSON . stringify ( {
164+ title : repl . title ,
165+ version : repl . version ,
166+ public : repl . public ,
167+ labels : repl . labels ,
168+ files,
169+ } ) ,
170+ } ) ;
96171 }
97-
98- if ( ! context . token || context . user ( ) ?. display != params . user ) return ;
99- fetch ( `${ API } /repl/${ params . repl } ` , {
100- method : 'PUT' ,
101- headers : {
102- 'authorization' : `Bearer ${ context . token } ` ,
103- 'Content-Type' : 'application/json' ,
104- } ,
105- body : JSON . stringify ( {
106- title : repl . title ,
107- version : repl . version ,
108- public : repl . public ,
109- labels : repl . labels ,
110- files,
111- } ) ,
112- } ) ;
113172 } ,
114- params . user == 'local' ? 10 : 1000 ,
173+ ! ! scratchpad ( ) ? 10 : 1000 ,
115174 ) ;
116175
117- createEffect ( ( ) => {
118- tabMapper ( tabs ( ) ) ; // use the latest value on debounce, and just throw this value away (but use it to track)
119- resource ( ) ;
120- if ( loaded ) updateRepl ( ) ;
121- } ) ;
122-
123176 return (
124177 < >
125178 < Header
126179 fork = { ( ) => { } }
127- share = { ( ) => {
128- if ( props . scratchpad ) {
180+ share = { async ( ) => {
181+ if ( scratchpad ( ) ) {
129182 let url = new URL ( location . origin ) ;
130183 url . hash = compressToURL ( JSON . stringify ( context . tabs ( ) ) ) ;
131184 console . log ( 'Shareable url:' , url . href ) ;
132185
133- return fetch ( '/' , { method : 'PUT' , body : `{"url":"${ url . href } "}` } )
134- . then ( ( response ) => {
135- if ( response . status >= 400 ) {
136- throw new Error ( response . statusText ) ;
137- }
138-
139- return response . text ( ) ;
140- } )
141- . then ( ( hash ) => {
142- const tinyUrl = new URL ( location . origin ) ;
143- tinyUrl . searchParams . set ( 'hash' , hash ) ;
144-
145- return tinyUrl . toString ( ) ;
146- } )
147- . catch ( ( ) => {
148- return url . href ;
149- } ) ;
186+ try {
187+ const response = await fetch ( '/' , { method : 'PUT' , body : `{"url":"${ url . href } "}` } ) ;
188+ if ( response . status >= 400 ) {
189+ throw new Error ( response . statusText ) ;
190+ }
191+ const hash = await response . text ( ) ;
192+ const tinyUrl = new URL ( location . origin ) ;
193+ tinyUrl . searchParams . set ( 'hash' , hash ) ;
194+ return tinyUrl . toString ( ) ;
195+ } catch {
196+ return url . href ;
197+ }
150198 } else {
151- return Promise . resolve ( location . href ) ;
199+ return location . href ;
152200 }
153201 } }
154202 >
155- { resource ( ) ?. title && (
203+ { resource ( ) && (
156204 < input
157205 class = "bg-transparent"
158206 value = { resource ( ) ?. title }
159207 onChange = { ( e ) => {
160208 mutate ( ( x ) => x && { ...x , title : e . currentTarget . value } ) ;
209+ updateRepl ( ) ;
161210 } }
162211 />
163212 ) }
@@ -179,17 +228,19 @@ export const Edit = (props: { horizontal: boolean; scratchpad?: boolean }) => {
179228 </ svg >
180229 }
181230 >
182- < Repl
183- compiler = { compiler }
184- formatter = { formatter }
185- isHorizontal = { props . horizontal }
186- dark = { context . dark ( ) }
187- tabs = { tabs ( ) }
188- setTabs = { setTabs }
189- current = { current ( ) }
190- setCurrent = { setCurrent }
191- id = "repl"
192- />
231+ < Show when = { resource ( ) } >
232+ < Repl
233+ compiler = { compiler }
234+ formatter = { formatter }
235+ isHorizontal = { props . horizontal }
236+ dark = { context . dark ( ) }
237+ tabs = { tabs ( ) }
238+ setTabs = { setTabs }
239+ current = { current ( ) }
240+ setCurrent = { setCurrent }
241+ id = { 'repl' }
242+ />
243+ </ Show >
193244 </ Suspense >
194245 </ >
195246 ) ;
0 commit comments