11import { useCallback , useEffect , useReducer , useRef , useState } from "react" ;
22import "./App.css" ;
33
4- import Editor , { Monaco } from "@monaco-editor/react" ;
5- import { editor , KeyCode } from "monaco-editor" ;
6- import Gallery , { GalleryItem } from "./Gallery.js" ;
74import { Button , Root } from "@itwin/itwinui-react/bricks" ;
85import { decodeBase64Data , makeCompressedBase64String } from "./Helpers.ts" ;
6+ import Gallery , { GalleryItem } from "./Gallery.js" ;
97import Bucket from "./Bucket.tsx" ;
8+ import SandcastleEditor , { SandcastleEditorRef } from "./SandcastleEditor.tsx" ;
109
1110const defaultJsCode = `import * as Cesium from "cesium";
1211
@@ -25,22 +24,20 @@ function getBaseUrl() {
2524 return `${ location . protocol } //${ location . host } ${ location . pathname } ` ;
2625}
2726
28- const TYPES_URL = `${ __PAGE_BASE_URL__ } Source/Cesium.d.ts` ;
29- const SANDCASTLE_TYPES_URL = `templates/Sandcastle.d.ts` ;
3027const GALLERY_BASE = __GALLERY_BASE_URL__ ;
3128
29+ export type SandcastleAction =
30+ | { type : "reset" }
31+ | { type : "setCode" ; code : string }
32+ | { type : "setHtml" ; html : string }
33+ | { type : "runSandcastle" }
34+ | { type : "setAndRun" ; code ?: string ; html ?: string } ;
35+
3236function App ( ) {
33- const [ activeTab , setActiveTab ] = useState < "js" | "html" > ( "js" ) ;
3437 const [ darkTheme , setDarkTheme ] = useState ( false ) ;
3538
36- const editorRef = useRef < editor . IStandaloneCodeEditor > ( null ) ;
39+ const editorRef = useRef < SandcastleEditorRef > ( null ) ;
3740
38- type SandcastleAction =
39- | { type : "reset" }
40- | { type : "setCode" ; code : string }
41- | { type : "setHtml" ; html : string }
42- | { type : "runSandcastle" }
43- | { type : "setAndRun" ; code ?: string ; html ?: string } ;
4441 type CodeState = {
4542 code : string ;
4643 html : string ;
@@ -105,87 +102,12 @@ function App() {
105102 dispatch ( { type : "runSandcastle" } ) ;
106103 }
107104
108- function handleEditorDidMount (
109- editor : editor . IStandaloneCodeEditor ,
110- monaco : Monaco ,
111- ) {
112- editorRef . current = editor ;
113-
114- monaco . editor . addCommand ( {
115- id : "run-cesium" ,
116- run : ( ) => {
117- dispatch ( { type : "runSandcastle" } ) ;
118- } ,
119- } ) ;
120-
121- monaco . editor . addKeybindingRules ( [
122- // Remove some default keybindings that get in the way
123- // https://github.com/microsoft/monaco-editor/issues/102
124- // disable show command center
125- { keybinding : KeyCode . F1 , command : null } ,
126- // disable show error command
127- { keybinding : KeyCode . F8 , command : null } ,
128- // disable toggle debugger breakpoint
129- { keybinding : KeyCode . F9 , command : null } ,
130- // disable go to definition to allow opening dev console
131- { keybinding : KeyCode . F12 , command : null } ,
132- // Set up our custom run command
133- { keybinding : KeyCode . F8 , command : "run-cesium" } ,
134- ] ) ;
135- }
136-
137- function handleEditorWillMount ( monaco : Monaco ) {
138- // here is the monaco instance
139- // do something before editor is mounted
140-
141- monaco . languages . typescript . javascriptDefaults . setCompilerOptions ( {
142- // TODO: pick what target we want, probably newer than ES2020 but TS was upset with that
143- target : monaco . languages . typescript . ScriptTarget . ES2020 ,
144- allowNonTsExtensions : true ,
145- } ) ;
146-
147- setTypes ( monaco ) ;
148- }
149-
150- function handleChange ( value : string = "" ) {
151- if ( activeTab === "js" ) {
152- dispatch ( { type : "setCode" , code : value } ) ;
153- } else {
154- dispatch ( { type : "setHtml" , html : value } ) ;
155- }
156- }
157-
158- async function setTypes ( monaco : Monaco ) {
159- // https://microsoft.github.io/monaco-editor/playground.html?source=v0.52.2#example-extending-language-services-configure-javascript-defaults
160-
161- const cesiumTypes = await ( await fetch ( TYPES_URL ) ) . text ( ) ;
162- // define a "global" variable so types work even with out the import statement
163- const cesiumTypesWithGlobal = `${ cesiumTypes } \nvar Cesium: typeof import('cesium');` ;
164- monaco . languages . typescript . javascriptDefaults . addExtraLib (
165- cesiumTypesWithGlobal ,
166- "ts:cesium.d.ts" ,
167- ) ;
168-
169- const sandcastleTypes = await ( await fetch ( SANDCASTLE_TYPES_URL ) ) . text ( ) ;
170- // surround in a module so the import statement works nicely
171- // also define a "global" so types show even if you don't have the import
172- const sandcastleModuleTypes = `declare module 'Sandcastle' {
173- ${ sandcastleTypes }
174- }
175- var Sandcastle: typeof import('Sandcastle').default;` ;
176-
177- monaco . languages . typescript . javascriptDefaults . addExtraLib (
178- sandcastleModuleTypes ,
179- "ts:sandcastle.d.ts" ,
180- ) ;
181- }
182-
183105 function highlightLine ( lineNumber : number ) {
184106 console . log ( "would highlight line" , lineNumber , "but not implemented yet" ) ;
185107 }
186108
187109 function formatJs ( ) {
188- editorRef . current ?. getAction ( "editor.action.formatDocument" ) ?. run ( ) ;
110+ editorRef . current ?. formatCode ( ) ;
189111 }
190112
191113 function nextHighestVariableName ( code : string , name : string ) {
@@ -394,32 +316,19 @@ Sandcastle.addToolbarMenu(${variableName});`,
394316 < div className = "spacer" > </ div >
395317 < Button onClick = { ( ) => setDarkTheme ( ! darkTheme ) } > Swap Theme</ Button >
396318 </ div >
397- < div className = "editor-container" >
398- < div className = "tabs" >
399- < Button
400- disabled = { activeTab === "js" }
401- onClick = { ( ) => setActiveTab ( "js" ) }
402- >
403- Javascript
404- </ Button >
405- < Button
406- disabled = { activeTab === "html" }
407- onClick = { ( ) => setActiveTab ( "html" ) }
408- >
409- HTML/CSS
410- </ Button >
411- </ div >
412- < Editor
413- theme = { darkTheme ? "vs-dark" : "light" }
414- path = { activeTab === "js" ? "script.js" : "index.html" }
415- language = { activeTab === "js" ? "javascript" : "html" }
416- value = { activeTab === "js" ? codeState . code : codeState . html }
417- defaultValue = { defaultJsCode }
418- onMount = { handleEditorDidMount }
419- beforeMount = { handleEditorWillMount }
420- onChange = { handleChange }
421- />
422- </ div >
319+ < SandcastleEditor
320+ ref = { editorRef }
321+ darkTheme = { darkTheme }
322+ onJsChange = { ( value : string = "" ) =>
323+ dispatch ( { type : "setCode" , code : value } )
324+ }
325+ onHtmlChange = { ( value : string = "" ) =>
326+ dispatch ( { type : "setHtml" , html : value } )
327+ }
328+ onRun = { ( ) => dispatch ( { type : "runSandcastle" } ) }
329+ js = { codeState . code }
330+ html = { codeState . html }
331+ />
423332 < div className = "viewer-bucket" >
424333 < Bucket
425334 code = { codeState . committedCode }
@@ -436,7 +345,10 @@ Sandcastle.addToolbarMenu(${variableName});`,
436345 loadGalleryItem ( item . id ) ;
437346
438347 const searchParams = new URLSearchParams ( window . location . search ) ;
439- if ( searchParams . has ( "id" ) && searchParams . get ( "id" ) !== item . id ) {
348+ if (
349+ ! searchParams . has ( "id" ) ||
350+ ( searchParams . has ( "id" ) && searchParams . get ( "id" ) !== item . id )
351+ ) {
440352 // only push state if it's not the current url to prevent duplicated in history
441353 window . history . pushState ( { } , "" , `${ getBaseUrl ( ) } ?id=${ item . id } ` ) ;
442354 }
0 commit comments