@@ -3,22 +3,14 @@ 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 {
7- batch ,
8- createEffect ,
9- createResource ,
10- createSignal ,
11- lazy ,
12- onCleanup ,
13- onMount ,
14- ParentComponent ,
15- Suspense ,
16- } from 'solid-js' ;
6+ import { batch , createEffect , createResource , createSignal , lazy , Suspense } from 'solid-js' ;
177import { useParams } from 'solid-app-router' ;
188import { API , useAppContext } from '../context' ;
199import { debounce } from '@solid-primitives/scheduled' ;
20- import { createTabList , Tab } from '../../src' ;
10+ import { createTabList , defaultTabs , Tab } from '../../src' ;
2111import type { APIRepl } from './home' ;
12+ import { Header } from '../components/header' ;
13+ import { compressToURL } from '@amoutonbrady/lz-string' ;
2214
2315const Repl = lazy ( ( ) => import ( '../../src/components/repl' ) ) ;
2416
@@ -36,22 +28,7 @@ const Repl = lazy(() => import('../../src/components/repl'));
3628 } ,
3729} ;
3830
39- const RenderHeader : ParentComponent = ( props ) => {
40- onMount ( ( ) => {
41- const projectName = document . getElementById ( 'project-name' ) ! ;
42- const content = projectName . firstChild ! ;
43- content . remove ( ) ;
44- const children = props . children as HTMLElement ;
45- projectName . appendChild ( children ) ;
46- onCleanup ( ( ) => {
47- projectName . appendChild ( content ) ;
48- projectName . removeChild ( children ) ;
49- } ) ;
50- } ) ;
51- return < > </ > ;
52- } ;
53-
54- export const Edit = ( props : { horizontal : boolean } ) => {
31+ export const Edit = ( props : { horizontal : boolean ; scratchpad ?: boolean } ) => {
5532 const compiler = new CompilerWorker ( ) ;
5633 const formatter = new FormatterWorker ( ) ;
5734
@@ -63,10 +40,30 @@ export const Edit = (props: { horizontal: boolean }) => {
6340 const [ tabs , setTabs ] = createTabList ( [ ] ) ;
6441 context . setTabs ( tabs ) ;
6542 const [ current , setCurrent ] = createSignal < string > ( ) ;
66- const [ resource , { mutate } ] = createResource < APIRepl , string > ( params . repl , async ( repl ) => {
43+ const [ resource , { mutate } ] = createResource < APIRepl , string > ( async ( ) => {
44+ const repl = params . repl ;
45+
6746 let output : APIRepl ;
68- if ( params . user == 'local' ) {
69- output = JSON . parse ( localStorage . getItem ( repl ) ! ) ;
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 ) ) ;
64+ } else {
65+ output = JSON . parse ( scratchpad ) ;
66+ }
7067 } else {
7168 output = await fetch ( `${ API } /repl/${ repl } ` , {
7269 headers : { authorization : context . token ? `Bearer ${ context . token } ` : '' } ,
@@ -91,20 +88,13 @@ export const Edit = (props: { horizontal: boolean }) => {
9188 ( ) => {
9289 const repl = resource . latest ;
9390 if ( ! repl ) return ;
91+
9492 const files = tabMapper ( tabs ( ) ) ;
95- if ( params . user == 'local' ) {
96- localStorage . setItem (
97- params . repl ,
98- JSON . stringify ( {
99- title : repl . title ,
100- version : repl . version ,
101- public : repl . public ,
102- labels : repl . labels ,
103- files,
104- } ) ,
105- ) ;
93+ if ( props . scratchpad ) {
94+ localStorage . setItem ( 'scratchpad' , JSON . stringify ( { ...repl , files } ) ) ;
10695 return ;
10796 }
97+
10898 if ( ! context . token || context . user ( ) ?. display != params . user ) return ;
10999 fetch ( `${ API } /repl/${ params . repl } ` , {
110100 method : 'PUT' ,
@@ -131,43 +121,76 @@ export const Edit = (props: { horizontal: boolean }) => {
131121 } ) ;
132122
133123 return (
134- < Suspense
135- fallback = {
136- < svg
137- class = "animate-spin h-12 w-12 text-white m-auto"
138- xmlns = "http://www.w3.org/2000/svg"
139- fill = "none"
140- viewBox = "0 0 24 24"
141- >
142- < circle class = "opacity-25" cx = "12" cy = "12" r = "10" stroke = "currentColor" stroke-width = "4" > </ circle >
143- < path
144- class = "opacity-75"
145- fill = "currentColor"
146- d = "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
147- > </ path >
148- </ svg >
149- }
150- >
151- < Repl
152- compiler = { compiler }
153- formatter = { formatter }
154- isHorizontal = { props . horizontal }
155- dark = { context . dark ( ) }
156- tabs = { tabs ( ) }
157- setTabs = { setTabs }
158- current = { current ( ) }
159- setCurrent = { setCurrent }
160- id = "repl"
161- />
162- < RenderHeader >
163- < input
164- class = "bg-transparent"
165- value = { resource ( ) ?. title || '' }
166- onChange = { ( e ) => {
167- mutate ( ( x ) => x && { ...x , title : e . currentTarget . value } ) ;
168- } }
124+ < >
125+ < Header
126+ fork = { ( ) => { } }
127+ share = { ( ) => {
128+ if ( props . scratchpad ) {
129+ let url = new URL ( location . origin ) ;
130+ url . hash = compressToURL ( JSON . stringify ( context . tabs ( ) ) ) ;
131+ console . log ( 'Shareable url:' , url . href ) ;
132+
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+ } ) ;
150+ } else {
151+ return Promise . resolve ( location . href ) ;
152+ }
153+ } }
154+ >
155+ { resource ( ) ?. title && (
156+ < input
157+ class = "bg-transparent"
158+ value = { resource ( ) ?. title }
159+ onChange = { ( e ) => {
160+ mutate ( ( x ) => x && { ...x , title : e . currentTarget . value } ) ;
161+ } }
162+ />
163+ ) }
164+ </ Header >
165+ < Suspense
166+ fallback = {
167+ < svg
168+ class = "animate-spin h-12 w-12 text-white m-auto"
169+ xmlns = "http://www.w3.org/2000/svg"
170+ fill = "none"
171+ viewBox = "0 0 24 24"
172+ >
173+ < circle class = "opacity-25" cx = "12" cy = "12" r = "10" stroke = "currentColor" stroke-width = "4" > </ circle >
174+ < path
175+ class = "opacity-75"
176+ fill = "currentColor"
177+ d = "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
178+ > </ path >
179+ </ svg >
180+ }
181+ >
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"
169192 />
170- </ RenderHeader >
171- </ Suspense >
193+ </ Suspense >
194+ </ >
172195 ) ;
173196} ;
0 commit comments