mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-10-31 18:48:11 +08:00 
			
		
		
		
	Improve the example page. (#780)
This commit is contained in:
		| @@ -21,6 +21,8 @@ if (EMSCRIPTEN) | ||||
|   get_property(EXAMPLES GLOBAL PROPERTY FTXUI::EXAMPLES) | ||||
|   foreach(file | ||||
|       "index.html" | ||||
|       "index.mjs" | ||||
|       "index.css" | ||||
|       "sw.js" | ||||
|       "run_webassembly.py") | ||||
|     configure_file(${file} ${file}) | ||||
|   | ||||
							
								
								
									
										107
									
								
								examples/index.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								examples/index.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | ||||
| @import url(https://fonts.googleapis.com/css?family=Khula:700); | ||||
|  | ||||
| body { | ||||
|   background-color:#EEE; | ||||
|   padding:0px; | ||||
|   margin:0px; | ||||
|   font-family: Khula, Helvetica, sans-serif; | ||||
|   font-size: 130%; | ||||
| } | ||||
|  | ||||
| .page { | ||||
|   max-width:1300px; | ||||
|   margin: auto; | ||||
|   padding: 10px; | ||||
| } | ||||
|  | ||||
| a { | ||||
|   box-shadow: inset 0 0 0 0 #54b3d6; | ||||
|   color: #0087b9; | ||||
|   margin: 0 -.25rem; | ||||
|   padding: 0 .25rem; | ||||
|   transition: color .3s ease-in-out, | ||||
|               box-shadow .3s ease-in-out; | ||||
| } | ||||
|  | ||||
| a:hover { | ||||
|   box-shadow: inset 120px 0 0 0 #54b3d6; | ||||
|   color: white; | ||||
| } | ||||
|  | ||||
| h1 { | ||||
|   text-decoration: underline; | ||||
|   width:100%; | ||||
|   background-color: rgba(100,100,255,0.5); | ||||
|   padding: 10px; | ||||
|   margin: 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| #selectExample { | ||||
|   flex:1; | ||||
| } | ||||
|  | ||||
| #selectExample, #selectExample option { | ||||
|   font-size: 16px; | ||||
|   font-family: sans-serif; | ||||
|   font-weight: 700; | ||||
|   line-height: 1.3; | ||||
|   border:0px; | ||||
|   background-color: #bbb; | ||||
|   color:black; | ||||
| } | ||||
|  | ||||
| #selectExample:focus { | ||||
|   outline:none; | ||||
| } | ||||
|  | ||||
| #terminal { | ||||
|   width:100%; | ||||
|   height 500px; | ||||
|   height: calc(clamp(200px, 100vh - 300px, 900px)); | ||||
|   overflow: hidden; | ||||
|   border:none; | ||||
|   background-color:black; | ||||
| } | ||||
|  | ||||
| #terminalContainer { | ||||
|   overflow: hidden; | ||||
|   border-radius: 10px; | ||||
|   box-shadow: 0px 2px 10px 0px rgba(0,0,0,0.75), | ||||
|   0px 2px 80px 0px rgba(0,0,0,0.50); | ||||
| } | ||||
|  | ||||
| .fakeButtons { | ||||
|   height: 10px; | ||||
|   width: 10px; | ||||
|   border-radius: 50%; | ||||
|   border: 1px solid #000; | ||||
|   margin:6px; | ||||
|   background-color: #ff3b47; | ||||
|   border-color: #9d252b; | ||||
|   display: inline-block; | ||||
| } | ||||
|  | ||||
| .fakeMinimize { | ||||
|   left: 11px; | ||||
|   background-color: #ffc100; | ||||
|   border-color: #9d802c; | ||||
| } | ||||
|  | ||||
| .fakeZoom { | ||||
|   left: 16px; | ||||
|   background-color: #00d742; | ||||
|   border-color: #049931; | ||||
| } | ||||
|  | ||||
| .fakeMenu { | ||||
|   display:flex; | ||||
|   flex-direction: row; | ||||
|   width:100%; | ||||
|   box-sizing: border-box; | ||||
|   height: 25px; | ||||
|   background-color: #bbb; | ||||
|   color:black; | ||||
|   margin: 0 auto; | ||||
|   overflow: hidden; | ||||
| } | ||||
| @@ -1,173 +1,32 @@ | ||||
| <!DOCTYPE html> <html lang="en"> | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
|   <head> | ||||
|     <meta charset="utf-8"> | ||||
|     <title>FTXUI examples WebAssembly</title> | ||||
|     <script src="https://cdn.jsdelivr.net/npm/xterm@4.18.0/lib/xterm.min.js"></script> | ||||
|     <script src="https://cdn.jsdelivr.net/npm/xterm-addon-webgl@0.11.4/lib/xterm-addon-webgl.min.js"></script> | ||||
|     <script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.5.0/lib/xterm-addon-fit.min.js"></script> | ||||
|     <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>➡️</text></svg>"> | ||||
|     <link rel="stylesheet" href="index.css"> | ||||
|     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@4.11.0/css/xterm.css"></link> | ||||
|     <!--Add COOP/COEP via a ServiceWorker to use SharedArrayBuffer--> | ||||
|     <script> | ||||
|       if ("serviceWorker" in navigator && !window.crossOriginIsolated) { | ||||
|         navigator.serviceWorker.register(new URL("./sw.js", location.href)).then( | ||||
|           registration => { | ||||
|             if (registration.active && !navigator.serviceWorker.controller) { | ||||
|               window.location.reload(); | ||||
|             } | ||||
|           }, | ||||
|         ); | ||||
|       }  | ||||
|     </script> | ||||
|     <script type="module" src="index.mjs"></script> | ||||
|   </head> | ||||
|   <body> | ||||
|     <script id="example_script"></script> | ||||
|  | ||||
|     <div class="page"> | ||||
|       <h1>FTXUI WebAssembly Example </h1> | ||||
|       <p> | ||||
|         <a href="https://github.com/ArthurSonzogni/FTXUI">FTXUI</a> is a single | ||||
|         C++ library for terminal user interface. | ||||
|         <a href="https://github.com/ArthurSonzogni/FTXUI">FTXUI</a> is a simple | ||||
|         functional C++ library for terminal user interface. <br/> | ||||
|         This showcase the: <a href="https://github.com/ArthurSonzogni/FTXUI/tree/master/examples">./example/</a> folder. <br/> | ||||
|       </p> | ||||
|       <p> | ||||
|         On this page, you can try all the examples contained in: <a | ||||
|         href="https://github.com/ArthurSonzogni/FTXUI/tree/master/examples">./example/</a> | ||||
|         Those are compiled using WebAssembly. | ||||
|       </p> | ||||
|       <select id="selectExample"></select> | ||||
|       <div id="terminal"></div> | ||||
|  | ||||
|       <div id="terminalContainer"> | ||||
|         <div class="fakeMenu"> | ||||
|           <div class="fakeButtons fakeClose"></div> | ||||
|           <div class="fakeButtons fakeMinimize"></div> | ||||
|           <div class="fakeButtons fakeZoom"></div> | ||||
|           <select id="selectExample"></select> | ||||
|         </div> | ||||
|         <div id="terminal"></div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </body> | ||||
|   <script> | ||||
|     const example_list = "@EXAMPLES@".split(";"); | ||||
|  | ||||
|     const url_search_params = new URLSearchParams(window.location.search); | ||||
|     const example = url_search_params.get("file") || "dom/color_gallery"; | ||||
|     const select = document.getElementById("selectExample");  | ||||
|  | ||||
|     for(var i = 0; i < example_list.length; i++) { | ||||
|         var opt = example_list[i]; | ||||
|         var el = document.createElement("option"); | ||||
|         el.textContent = opt; | ||||
|         el.value = opt; | ||||
|         select.appendChild(el); | ||||
|     } | ||||
|     select.selectedIndex = example_list.findIndex(path => path == example) || 0; | ||||
|     select.addEventListener("change", () => { | ||||
|       location.href = (location.href).split('?')[0] + "?file=" + | ||||
|             example_list[select.selectedIndex]; | ||||
|     }); | ||||
|  | ||||
|     let stdin_buffer = []; | ||||
|     const stdin = () => { | ||||
|       return stdin_buffer.shift() || 0; | ||||
|     } | ||||
|  | ||||
|     let stdout_buffer = []; | ||||
|     const stdout = code => { | ||||
|       if (code == 0) { | ||||
|         term.write(new Uint8Array(stdout_buffer)); | ||||
|         stdout_buffer = []; | ||||
|       } else { | ||||
|         stdout_buffer.push(code) | ||||
|       } | ||||
|     } | ||||
|     let stderrbuffer = []; | ||||
|     const stderr = code => { | ||||
|       if (code == 0 || code == 10) { | ||||
|         console.error(String.fromCodePoint(...stderrbuffer)); | ||||
|         stderrbuffer = []; | ||||
|       } else { | ||||
|         stderrbuffer.push(code) | ||||
|       } | ||||
|     } | ||||
|     const term = new Terminal(); | ||||
|     const term_element = document.querySelector('#terminal'); | ||||
|     term.open(term_element); | ||||
|  | ||||
|     const webgl_addon = new (WebglAddon.WebglAddon)(); | ||||
|     term.loadAddon(webgl_addon); | ||||
|  | ||||
|     const onBinary = e => { | ||||
|       for(c of e) | ||||
|         stdin_buffer.push(c.charCodeAt(0)); | ||||
|     } | ||||
|     term.onBinary(onBinary); | ||||
|     term.onData(onBinary) | ||||
|     term.resize(140,43); | ||||
|     window.Module = { | ||||
|       preRun: () => { | ||||
|         FS.init(stdin, stdout, stderr); | ||||
|       }, | ||||
|       postRun: [], | ||||
|       onRuntimeInitialized: () => { | ||||
|         if (window.Module._ftxui_on_resize == undefined) | ||||
|           return; | ||||
|  | ||||
|         const fit_addon = new (FitAddon.FitAddon)(); | ||||
|         term.loadAddon(fit_addon); | ||||
|         fit_addon.fit(); | ||||
|         const resize_handler = () => { | ||||
|           const {cols, rows} = fit_addon.proposeDimensions(); | ||||
|           term.resize(cols, rows); | ||||
|           window.Module._ftxui_on_resize(cols, rows); | ||||
|         }; | ||||
|         const resize_observer = new ResizeObserver(resize_handler); | ||||
|         resize_observer.observe(term_element); | ||||
|         resize_handler(); | ||||
|  | ||||
|         // Disable scrollbar | ||||
|         term.write('\x1b[?47h') | ||||
|       }, | ||||
|     }; | ||||
|  | ||||
|     const words = example.split('/') | ||||
|     words[1] = "ftxui_example_" + words[1] + ".js" | ||||
|     document.querySelector("#example_script").src = words.join('/'); | ||||
|   </script> | ||||
|  | ||||
|   <style> | ||||
|  | ||||
|     body { | ||||
|       background-color:#EEE; | ||||
|       padding:20px; | ||||
|       font-family: Helvetica, sans-serif; | ||||
|       font-size: 130%; | ||||
|     } | ||||
|  | ||||
|     .page { | ||||
|       max-width:1300px; | ||||
|       margin: auto; | ||||
|     } | ||||
|  | ||||
|     h1 { | ||||
|       text-decoration: underline; | ||||
|     } | ||||
|  | ||||
|     select { | ||||
|       display:block; | ||||
|       padding: .6em 1.4em .5em .8em; | ||||
|       border-radius: 20px 20px 0px 0px; | ||||
|       font-size: 16px; | ||||
|       font-family: sans-serif; | ||||
|       font-weight: 700; | ||||
|  | ||||
|       color: #444; | ||||
|       line-height: 1.3; | ||||
|       background-color:black; | ||||
|       border:0px; | ||||
|       color:white; | ||||
|       transition: color 0.2s linear; | ||||
|       transition: background-color 0.2s linear; | ||||
|     } | ||||
|  | ||||
|     #terminal { | ||||
|       width:100%; | ||||
|       height: 500px; | ||||
|       height: calc(clamp(200px, 100vh - 300px, 900px)); | ||||
|       overflow: hidden; | ||||
|       border:none; | ||||
|       padding:auto; | ||||
|     } | ||||
|  | ||||
|   </style> | ||||
|  | ||||
| </html> | ||||
|   | ||||
							
								
								
									
										102
									
								
								examples/index.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								examples/index.mjs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | ||||
| import xterm             from 'https://cdn.jsdelivr.net/npm/xterm@4.18.0/+esm' | ||||
| import xterm_addon_webgl from 'https://cdn.jsdelivr.net/npm/xterm-addon-webgl@0.11.4/+esm' | ||||
| import xterm_addon_fit   from 'https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.5.0/+esm' | ||||
|  | ||||
| // Add COOP/COEP via a ServiceWorker to use SharedArrayBuffer | ||||
| if ("serviceWorker" in navigator && !window.crossOriginIsolated) { | ||||
|   const url_sw = new URL("./sw.js", location.href); | ||||
|   const registration = await navigator.serviceWorker.register(url_sw); | ||||
|   if (registration.active && !navigator.serviceWorker.controller) { | ||||
|     window.location.reload(); // Reload to ensure the COOP/COEP headers are set. | ||||
|   } | ||||
| }  | ||||
|  | ||||
| const example_list = "@EXAMPLES@".split(";"); | ||||
| const url_search_params = new URLSearchParams(window.location.search); | ||||
|  | ||||
| const select = document.getElementById("selectExample");  | ||||
| for(const example of example_list) { | ||||
|   const option = document.createElement("option"); | ||||
|   option.textContent = example; | ||||
|   option.value = example; | ||||
|   select.appendChild(option); | ||||
| } | ||||
| const example = url_search_params.get("file") || "dom/color_gallery"; | ||||
| select.selectedIndex = example_list.findIndex(path => path == example) || 0; | ||||
| select.addEventListener("change", () => { | ||||
|   history.pushState({}, "", "?file=" + example_list[select.selectedIndex]); | ||||
|   location.reload(); | ||||
| }); | ||||
|  | ||||
| const term_element = document.querySelector('#terminal'); | ||||
| const term = new xterm.Terminal(); | ||||
| term.options.scrollback = 0; | ||||
| term.open(term_element); | ||||
| const fit_addon = new xterm_addon_fit.FitAddon(); | ||||
| const webgl_addon = new xterm_addon_webgl.WebglAddon(); | ||||
| term.loadAddon(webgl_addon); | ||||
| term.loadAddon(fit_addon); | ||||
|  | ||||
| const stdin_buffer = []; | ||||
| const stdout_buffer = []; | ||||
| const stderr_buffer = []; | ||||
|  | ||||
| const stdin = () => { | ||||
|   return stdin_buffer.shift() || 0; | ||||
| } | ||||
|  | ||||
| const stdout = code => { | ||||
|   if (code == 0) { | ||||
|     term.write(new Uint8Array(stdout_buffer)); | ||||
|     stdout_buffer.length = 0; | ||||
|   } else { | ||||
|     stdout_buffer.push(code) | ||||
|   } | ||||
| } | ||||
|  | ||||
| const stderr = code => { | ||||
|   if (code == 0 || code == 10) { | ||||
|     console.error(String.fromCodePoint(...stderr_buffer)); | ||||
|     stderr_buffer = []; | ||||
|   } else { | ||||
|     stderr_buffer.push(code) | ||||
|   } | ||||
| } | ||||
|  | ||||
| const onBinary = e => { | ||||
|   for(const c of e) | ||||
|     stdin_buffer.push(c.charCodeAt(0)); | ||||
| } | ||||
|  | ||||
| term.onBinary(onBinary); | ||||
| term.onData(onBinary) | ||||
| term.resize(140,43); | ||||
|  | ||||
| window.Module = { | ||||
|   preRun: () => { | ||||
|     FS.init(stdin, stdout, stderr); | ||||
|   }, | ||||
|   postRun: [], | ||||
|   onRuntimeInitialized: () => { | ||||
|     if (window.Module._ftxui_on_resize == undefined) | ||||
|       return; | ||||
|     fit_addon.fit(); | ||||
|  | ||||
|     const resize_handler = () => { | ||||
|       const {cols, rows} = fit_addon.proposeDimensions(); | ||||
|       term.resize(cols, rows); | ||||
|       window.Module._ftxui_on_resize(cols, rows); | ||||
|       fit_addon.fit(); | ||||
|     }; | ||||
|     const resize_observer = new ResizeObserver(resize_handler); | ||||
|     resize_observer.observe(term_element); | ||||
|     resize_handler(); | ||||
|  | ||||
|     // Disable scrollbar | ||||
|     //term.write('\x1b[?47h') | ||||
|   }, | ||||
| }; | ||||
|  | ||||
| const words = example.split('/') | ||||
| words[1] = "ftxui_example_" + words[1] + ".js" | ||||
| document.querySelector("#example_script").src = words.join('/'); | ||||
		Reference in New Issue
	
	Block a user
	 Arthur Sonzogni
					Arthur Sonzogni