├── .github └── FUNDING.yml ├── .gitignore ├── .prettierrc ├── CNAME ├── LICENSE ├── README.md ├── code.png ├── dist ├── constants.d.ts ├── constants.d.ts.map ├── dom.d.ts ├── dom.d.ts.map ├── index.d.ts ├── index.d.ts.map ├── interfaces.d.ts ├── interfaces.d.ts.map ├── sounds.d.ts ├── sounds.d.ts.map ├── stylesheet.d.ts ├── stylesheet.d.ts.map ├── svgs.d.ts ├── svgs.d.ts.map ├── terminal.d.ts ├── terminal.d.ts.map ├── termo.cjs.js ├── termo.cjs.js.map ├── termo.esm.js ├── termo.esm.js.map ├── termo.min.js ├── termo.min.js.map ├── utils.d.ts └── utils.d.ts.map ├── finaltermo.gif ├── index.html ├── main.js ├── og.png ├── package-lock.json ├── package.json ├── rollup.config.js ├── sounds ├── run_command.mp3 ├── terminal_close.mp3 └── terminal_open.mp3 ├── src ├── constants.ts ├── dom.ts ├── index.ts ├── interfaces.ts ├── sounds.ts ├── stylesheet.ts ├── svgs.ts ├── terminal.ts └── utils.ts ├── styles.css ├── terminal.png └── tsconfig.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: rajnandan1 2 | buy_me_a_coffee: rajnandan1 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | .DS_Store 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | 93 | # Gatsby files 94 | .cache/ 95 | # Comment in the public line in if your project uses Gatsby and not Next.js 96 | # https://nextjs.org/blog/next-9-1#public-directory-support 97 | # public 98 | 99 | # vuepress build output 100 | .vuepress/dist 101 | 102 | # vuepress v2.x temp and cache directory 103 | .temp 104 | .cache 105 | 106 | # Docusaurus cache and generated files 107 | .docusaurus 108 | 109 | # Serverless directories 110 | .serverless/ 111 | 112 | # FuseBox cache 113 | .fusebox/ 114 | 115 | # DynamoDB Local files 116 | .dynamodb/ 117 | 118 | # TernJS port file 119 | .tern-port 120 | 121 | # Stores VSCode versions used for testing VSCode extensions 122 | .vscode-test 123 | 124 | # yarn v2 125 | .yarn/cache 126 | .yarn/unplugged 127 | .yarn/build-state.yml 128 | .yarn/install-state.gz 129 | .pnp.* 130 | 131 | .okgit 132 | svelteapp 133 | react-test 134 | svelte-test -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "singleQuote": true, 4 | "trailingComma": "all", 5 | "tabWidth": 4 6 | } 7 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | termo.rajnandan.com -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Raj Nandan Sharma 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Termo 2 | 3 | Termo is a simple terminal emulator that can be used to create a terminal-like interface on your website. It is inspired by the terminal emulator in [stripe.dev](https://stripe.dev). It is an wrapper on top of xterm.js. 4 | 5 | 6 | 7 | --- 8 | 9 | ### Demo 10 | 11 | Check out the [demo and documentation](https://rajnandan1.github.io/termo/). 12 | 13 | ### Features 14 | 15 | - [x] Customizable terminal title, prompt, font, and theme 16 | - [x] Set a welcome message for the terminal 17 | - [x] Add and execute any javascript as commands 18 | - [x] Control sound effects 19 | - [x] Get full access to the terminal (xterm.js) 20 | - [x] Set terminal to dock/floating mode 21 | 22 | ### Installation 23 | 24 | - [CDN](#cdn) 25 | - [NPM](#npm) 26 | 27 | Include the following script tag in your HTML file. 28 | 29 | ```html 30 | 31 | ``` 32 | 33 | Install the package using npm. 34 | 35 | ```bash 36 | npm install @rajnandan1/termo 37 | ``` 38 | 39 | ### Quick Start 40 | 41 | Create a new instance of Termo by passing an object . 42 | 43 | ```js 44 | const myTermo = new termo({ 45 | title: 'Termo', 46 | welcomeMessage: 'Welcome to Termo', 47 | commands: [ 48 | { 49 | command: 'hello', 50 | description: 'Says hello', 51 | action: async (terminal, args) => terminal.write('\r\nHello! ' + args.join(' ')), 52 | }, 53 | ], 54 | }); 55 | myTermo.create(); 56 | myTermo.show(); 57 | ``` 58 | 59 | ### Complete Example 60 | 61 | Here is a complete example of how to create a terminal with a custom command. 62 | 63 | ```js 64 | import { termo } from 'termo'; 65 | 66 | let commands = [ 67 | { 68 | command: 'hello', 69 | description: 'Says hello', 70 | action: async (terminal, args) => terminal.write('\r\nHello! ' + args.join(' ')), 71 | }, 72 | { 73 | command: 'joke', 74 | description: 'Hear a random joke from a random API', 75 | action: (terminal, args) => { 76 | terminal.write('\r\n' + 'Thinking of a joke...'); 77 | return new Promise(async (resolve, reject) => { 78 | try { 79 | const response = await fetch('https://official-joke-api.appspot.com/random_joke'); 80 | const data = await response.json(); 81 | terminal.write('\r\n' + data.setup); 82 | setTimeout(() => { 83 | resolve(terminal.write('\r\n' + data.punchline)); 84 | }, 2000); 85 | } catch (error) { 86 | terminal.write('\r\nFailed to fetch joke'); 87 | } 88 | }); 89 | }, 90 | }, 91 | { 92 | command: 'theme', 93 | description: 'Change the website theme', 94 | subCommands: [ 95 | { 96 | command: 'set', 97 | description: 'Set the website theme to light or dark', 98 | action: async (terminal, args) => { 99 | let theme = args[0]; 100 | if (theme === 'light') { 101 | document.body.setAttribute('data-bs-theme', 'light'); 102 | } else { 103 | document.body.setAttribute('data-bs-theme', 'dark'); 104 | } 105 | terminal.write('\r\nsetting theme to ' + args[0]); 106 | }, 107 | }, 108 | { 109 | command: 'list', 110 | description: 'List all available themes', 111 | action: async (terminal, args) => { 112 | let list = ['light', 'dark']; 113 | list.forEach((theme) => { 114 | terminal.write('\r\n' + theme); 115 | }); 116 | }, 117 | }, 118 | ], 119 | }, 120 | ]; 121 | 122 | let myDemoTerminal = new termo({ 123 | commands: commands, 124 | title: 'Termo v0.0.2', 125 | theme: 'dark', 126 | prompt: '$', 127 | }); 128 | 129 | myDemoTerminal.create(); 130 | 131 | myDemoTerminal.show(); 132 | ``` 133 | 134 | ### Options 135 | 136 | Termo accepts an object with the following options. 137 | 138 | ```js 139 | /** 140 | * Configuration options for initializing the terminal 141 | * @interface InitOptions 142 | * 143 | * @property {boolean} [playSound=true] - Enable/disable terminal sound effects 144 | * @property {string} [title='termo'] - Terminal window title 145 | * @property {string} [welcomeMessage] - Initial message displayed when terminal opens 146 | * @property {'light' | 'dark'} [theme='light'] - Terminal color theme 147 | * @property {string} [fontFamily='Courier New, monospace'] - Font family for terminal text 148 | * @property {string} [prompt='$'] - Terminal prompt character 149 | * @property {Command[]} [commands=[]] - Array of available terminal commands 150 | * @property {ITerminalOptions} [terminalOptions] - XTerm.js specific terminal options 151 | * 152 | * @example 153 | * const options: InitOptions = { 154 | * playSound: true, 155 | * title: 'My Terminal', 156 | * theme: 'dark', 157 | * commands: [{ 158 | * command: 'hello', 159 | * description: 'Says hello', 160 | * action: async (terminal, args) => terminal.write('\r\nHello! ' + args.join(' ')), 161 | * }] 162 | * }; 163 | */ 164 | export interface InitOptions { 165 | playSound?: boolean; 166 | title?: string; 167 | welcomeMessage?: string; 168 | theme?: 'light' | 'dark'; 169 | fontFamily?: string; 170 | prompt?: string; 171 | commands?: Command[]; 172 | terminalOptions?: ITerminalOptions; 173 | } 174 | ``` 175 | 176 | ### Command 177 | 178 | Command object for defining terminal commands. 179 | 180 | ```js 181 | /** 182 | * Represents a terminal command with its description, action and optional subcommands 183 | * @interface Command 184 | * 185 | * @property {string} command - The command name/identifier 186 | * @property {string} description - Brief description of what the command does 187 | * @property {function} action - Async function to execute when command is invoked 188 | * @property {Command[]} [subCommands] - Optional array of nested subcommands 189 | * 190 | * @example 191 | * const myCommand: Command = { 192 | * command: 'git', 193 | * description: 'Git version control', 194 | * action: async (terminal, args) => { 195 | * terminal.write('Executing git command...\r\n'); 196 | * }, 197 | * subCommands: [{ 198 | * command: 'status', 199 | * description: 'Show working tree status', 200 | * action: async (terminal) => { 201 | * terminal.write('git status output...\r\n'); 202 | * } 203 | * }] 204 | * }; 205 | */ 206 | export interface Command { 207 | command: string; 208 | description: string; 209 | action: (terminal: Terminal, args: string[]) => Promise; 210 | subCommands?: Command[]; 211 | } 212 | ``` 213 | 214 | ### API 215 | 216 | Termo exposes the following methods and variable. 217 | 218 | ```js 219 | const myTermo = new termo({ 220 | title: 'Termo', 221 | }); 222 | ``` 223 | 224 | #### Methods 225 | 226 | Termo has the following methods. 227 | 228 | ```js 229 | /** 230 | * Creates a new terminal instance with the specified options. 231 | * 232 | * This method initializes the terminal container, header, and various control buttons 233 | * (resize, close). It also sets up event listeners for these buttons to handle terminal 234 | * resizing and closing actions. The terminal is appended to the document body and made 235 | * draggable. 236 | * 237 | * @throws {Error} If a terminal with the same title already exists. 238 | */ 239 | myTermo.create(); 240 | 241 | /** 242 | * Displays the terminal by applying a scale transformation to the container element. 243 | * If the container exists, it plays the terminal open sound, sets the state to 'open', 244 | * and focuses the terminal. If the container does not exist, it throws an error. 245 | * 246 | * @throws {Error} If the terminal container is not created. 247 | */ 248 | myTermo.show(); 249 | 250 | /** 251 | * Hides the terminal by scaling down its container element. 252 | * If the container exists, it plays the terminal close sound, 253 | * scales the container to zero, and updates the state to 'minimized'. 254 | * If the container does not exist, it throws an error. 255 | * 256 | * @throws {Error} If the terminal container is not created. 257 | */ 258 | myTermo.hide(); // Hides the terminal 259 | 260 | /** 261 | * Sets the theme of the terminal. 262 | * 263 | * @param theme - The theme to set, either 'dark' or 'light'. 264 | * @throws Will throw an error if the terminal container is not created. 265 | */ 266 | myTermo.setTheme(); 267 | 268 | /** 269 | * Destroys the terminal instance by performing the following actions: 270 | * - If the container exists: 271 | * - Destroys the terminal manager. 272 | * - Removes the container element from the document body. 273 | * - Removes the associated stylesheet from the document head. 274 | * - Sets the container to undefined. 275 | * - Deletes the terminal manager. 276 | * - Updates the state to 'destroyed'. 277 | * - Sets the mode to 'floating'. 278 | * - If the container does not exist, throws an error indicating that the terminal was not created. 279 | * 280 | * @throws {Error} If the terminal was not created. 281 | */ 282 | myTermo.destroy(); 283 | 284 | /** 285 | * Adjusts the dimensions and position of the terminal container to dock it 286 | * at the bottom right corner of the viewport. 287 | * 288 | * @throws {Error} Throws an error if the terminal container is not created. 289 | */ 290 | myTermo.dock(); 291 | 292 | /** 293 | * Adjusts the dimensions and position of the container element to float it 294 | * at a specific size and position on the screen. If the container element 295 | * is not available, an error is thrown. 296 | * 297 | * @throws {Error} If the container element is not created. 298 | */ 299 | myTermo.float(); 300 | ``` 301 | 302 | #### Variables 303 | 304 | Termo has the following variables. 305 | 306 | ```js 307 | /** 308 | * @class Termo 309 | * @property {InitOptions} options - The initialization options for the terminal. 310 | * @property {'floating' | 'docked'} mode - The current mode of the terminal (floating or docked). 311 | * @property {'minimized' | 'open' | 'destroyed' | 'initiated'} state - The current state of the terminal. 312 | * @property {HTMLDivElement | undefined} container - The container element for the terminal. 313 | * @property {TerminalManager | undefined} terminalManager - The terminal manager instance. 314 | */ 315 | ``` 316 | -------------------------------------------------------------------------------- /code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rajnandan1/termo/93d0d757ce55228814941f90897eb81ab3ed9697/code.png -------------------------------------------------------------------------------- /dist/constants.d.ts: -------------------------------------------------------------------------------- 1 | declare const constants: { 2 | SOUND_TERMINAL_OPEN: string; 3 | SOUND_TERMINAL_CLOSE: string; 4 | SOUND_RUN_CMD: string; 5 | }; 6 | export default constants; 7 | //# sourceMappingURL=constants.d.ts.map -------------------------------------------------------------------------------- /dist/constants.d.ts.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,SAAS;;;;CAId,CAAC;AACF,eAAe,SAAS,CAAC"} -------------------------------------------------------------------------------- /dist/dom.d.ts: -------------------------------------------------------------------------------- 1 | declare const DOM: { 2 | createDiv(id: string, cls: string): HTMLDivElement; 3 | addCss(div: HTMLDivElement, css: string): void; 4 | appendChild(parent: HTMLElement, child: HTMLElement): void; 5 | injectStylesheet(id: string, styleSheet: string): void; 6 | }; 7 | export default DOM; 8 | //# sourceMappingURL=dom.d.ts.map -------------------------------------------------------------------------------- /dist/dom.d.ts.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../src/dom.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,GAAG;kBACS,MAAM,OAAO,MAAM,GAAG,cAAc;gBAMtC,cAAc,OAAO,MAAM,GAAG,IAAI;wBAG1B,WAAW,SAAS,WAAW,GAAG,IAAI;yBAGrC,MAAM,cAAc,MAAM,GAAG,IAAI;CAUzD,CAAC;AAEF,eAAe,GAAG,CAAC"} -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | import { InitOptions } from './interfaces'; 2 | import TerminalManager from './terminal'; 3 | /** 4 | * @class Termo 5 | * @property {InitOptions} options - The initialization options for the terminal. 6 | * @property {'floating' | 'docked'} mode - The current mode of the terminal (floating or docked). 7 | * @property {'minimized' | 'open' | 'destroyed' | 'initiated'} state - The current state of the terminal. 8 | * @property {HTMLDivElement | undefined} container - The container element for the terminal. 9 | * @property {TerminalManager | undefined} terminalManager - The terminal manager instance. 10 | */ 11 | declare class Termo { 12 | options: InitOptions; 13 | mode: 'floating' | 'docked'; 14 | state: 'minimized' | 'open' | 'destroyed' | 'initiated'; 15 | container: HTMLDivElement | undefined; 16 | terminalManager: TerminalManager | undefined; 17 | constructor(options: InitOptions); 18 | /** 19 | * Creates a new terminal instance with the specified options. 20 | * 21 | * This method initializes the terminal container, header, and various control buttons 22 | * (resize, close). It also sets up event listeners for these buttons to handle terminal 23 | * resizing and closing actions. The terminal is appended to the document body and made 24 | * draggable. 25 | * 26 | * @throws {Error} If a terminal with the same title already exists. 27 | */ 28 | create(): void; 29 | /** 30 | * Adjusts the dimensions and position of the container element to float it 31 | * at a specific size and position on the screen. If the container element 32 | * is not available, an error is thrown. 33 | * 34 | * @throws {Error} If the container element is not created. 35 | */ 36 | float(): void; 37 | /** 38 | * Adjusts the dimensions and position of the terminal container to dock it 39 | * at the bottom right corner of the viewport. 40 | * 41 | * @throws {Error} Throws an error if the terminal container is not created. 42 | */ 43 | dock(): void; 44 | /** 45 | * Hides the terminal by scaling down its container element. 46 | * If the container exists, it plays the terminal close sound, 47 | * scales the container to zero, and updates the state to 'minimized'. 48 | * If the container does not exist, it throws an error. 49 | * 50 | * @throws {Error} If the terminal container is not created. 51 | */ 52 | hide(): void; 53 | /** 54 | * Displays the terminal by applying a scale transformation to the container element. 55 | * If the container exists, it plays the terminal open sound, sets the state to 'open', 56 | * and focuses the terminal. If the container does not exist, it throws an error. 57 | * 58 | * @throws {Error} If the terminal container is not created. 59 | */ 60 | show(): void; 61 | /** 62 | * Sets the theme of the terminal. 63 | * 64 | * @param theme - The theme to set, either 'dark' or 'light'. 65 | * @throws Will throw an error if the terminal container is not created. 66 | */ 67 | setTheme(theme: 'dark' | 'light'): void; 68 | /** 69 | * Destroys the terminal instance by performing the following actions: 70 | * - If the container exists: 71 | * - Destroys the terminal manager. 72 | * - Removes the container element from the document body. 73 | * - Removes the associated stylesheet from the document head. 74 | * - Sets the container to undefined. 75 | * - Deletes the terminal manager. 76 | * - Updates the state to 'destroyed'. 77 | * - Sets the mode to 'floating'. 78 | * - If the container does not exist, throws an error indicating that the terminal was not created. 79 | * 80 | * @throws {Error} If the terminal was not created. 81 | */ 82 | destroy(): void; 83 | } 84 | export default Termo; 85 | //# sourceMappingURL=index.d.ts.map -------------------------------------------------------------------------------- /dist/index.d.ts.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAM3C,OAAO,eAAe,MAAM,YAAY,CAAC;AAEzC;;;;;;;GAOG;AACH,cAAM,KAAK;IACP,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,EAAE,UAAU,GAAG,QAAQ,CAAC;IAC5B,KAAK,EAAE,WAAW,GAAG,MAAM,GAAG,WAAW,GAAG,WAAW,CAAC;IACxD,SAAS,EAAE,cAAc,GAAG,SAAS,CAAC;IACtC,eAAe,EAAE,eAAe,GAAG,SAAS,CAAC;gBAIjC,OAAO,EAAE,WAAW;IAWhC;;;;;;;;;OASG;IACH,MAAM;IAqEN;;;;;;OAMG;IACH,KAAK;IAaL;;;;;OAKG;IACH,IAAI;IAYJ;;;;;;;OAOG;IACH,IAAI;IASJ;;;;;;OAMG;IACH,IAAI;IAWJ;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAYhC;;;;;;;;;;;;;OAaG;IACH,OAAO;CAcV;AAED,eAAe,KAAK,CAAC"} -------------------------------------------------------------------------------- /dist/interfaces.d.ts: -------------------------------------------------------------------------------- 1 | import { ITerminalOptions, Terminal } from '@xterm/xterm'; 2 | /** 3 | * Options for initializing the terminal. 4 | */ 5 | export interface InitOptions { 6 | /** 7 | * The welcome message displayed when the terminal starts. 8 | */ 9 | welcomeMessage: string; 10 | /** 11 | * The list of commands available in the terminal. 12 | */ 13 | commands: Command[]; 14 | /** 15 | * Configuration options for the terminal. 16 | */ 17 | terminalOptions: ITerminalOptions; 18 | /** 19 | * The theme of the terminal. 20 | */ 21 | theme: string; 22 | /** 23 | * Whether to play a sound on certain actions. 24 | */ 25 | playSound: boolean; 26 | /** 27 | * The title of the terminal window. 28 | */ 29 | title: string; 30 | /** 31 | * The font family used in the terminal. 32 | */ 33 | fontFamily: string; 34 | /** 35 | * The unique identifier for the terminal instance. 36 | */ 37 | id: string; 38 | /** 39 | * The prompt string displayed in the terminal. 40 | */ 41 | prompt: string; 42 | } 43 | export interface Command { 44 | command: string; 45 | description: string; 46 | action: (terminal: Terminal, args: string[]) => Promise; 47 | subCommands?: Command[]; 48 | } 49 | export interface TerminalManagerReturn { 50 | terminal: Terminal; 51 | destroy: () => void; 52 | } 53 | //# sourceMappingURL=interfaces.d.ts.map -------------------------------------------------------------------------------- /dist/interfaces.d.ts.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,WAAW;IACxB;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,QAAQ,EAAE,OAAO,EAAE,CAAC;IAEpB;;OAEG;IACH,eAAe,EAAE,gBAAgB,CAAC;IAElC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,OAAO;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB"} -------------------------------------------------------------------------------- /dist/sounds.d.ts: -------------------------------------------------------------------------------- 1 | import { InitOptions } from './interfaces'; 2 | declare const _default: { 3 | terminalOpen: (opts: InitOptions) => void; 4 | terminalClose: (opts: InitOptions) => void; 5 | runCommand: (opts: InitOptions) => void; 6 | }; 7 | export default _default; 8 | //# sourceMappingURL=sounds.d.ts.map -------------------------------------------------------------------------------- /dist/sounds.d.ts.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"sounds.d.ts","sourceRoot":"","sources":["../src/sounds.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;;yBAUT,WAAW;0BAcV,WAAW;uBAed,WAAW;;AA9B3C,wBA4CE"} -------------------------------------------------------------------------------- /dist/stylesheet.d.ts: -------------------------------------------------------------------------------- 1 | import { InitOptions } from './interfaces'; 2 | export default function (opts: InitOptions): string; 3 | //# sourceMappingURL=stylesheet.d.ts.map -------------------------------------------------------------------------------- /dist/stylesheet.d.ts.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"stylesheet.d.ts","sourceRoot":"","sources":["../src/stylesheet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAqO3C,MAAM,CAAC,OAAO,WAAW,IAAI,EAAE,WAAW,UAMzC"} -------------------------------------------------------------------------------- /dist/svgs.d.ts: -------------------------------------------------------------------------------- 1 | export declare const close = "\n\n"; 2 | export declare const dock = "\nAlign window to bottom\n"; 3 | export declare const pop = "\nFloat window in corner\n"; 4 | //# sourceMappingURL=svgs.d.ts.map -------------------------------------------------------------------------------- /dist/svgs.d.ts.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"svgs.d.ts","sourceRoot":"","sources":["../src/svgs.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,KAAK,+ZAEjB,CAAC;AAEF,eAAO,MAAM,IAAI,oZAEhB,CAAC;AAEF,eAAO,MAAM,GAAG,ocAEf,CAAC"} -------------------------------------------------------------------------------- /dist/terminal.d.ts: -------------------------------------------------------------------------------- 1 | import { ITerminalOptions, Terminal } from '@xterm/xterm'; 2 | import { FitAddon } from '@xterm/addon-fit'; 3 | import { WebLinksAddon } from '@xterm/addon-web-links'; 4 | import { InitOptions, Command } from './interfaces'; 5 | declare class TerminalManager { 6 | terminalOptions: ITerminalOptions; 7 | terminal: Terminal; 8 | fitAddon: FitAddon; 9 | webLinksAddon: WebLinksAddon; 10 | userCommands: Command[]; 11 | commandHistory: any; 12 | historyIndex: number; 13 | inputBuffer: string; 14 | opts: InitOptions; 15 | constructor(div: HTMLElement, optsReceived: InitOptions); 16 | destroy(): void; 17 | focus(): void; 18 | resize(): void; 19 | } 20 | export default TerminalManager; 21 | //# sourceMappingURL=terminal.d.ts.map -------------------------------------------------------------------------------- /dist/terminal.d.ts.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../src/terminal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGpD,cAAM,eAAe;IACjB,eAAe,EAAE,gBAAgB,CAAC;IAClC,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,OAAO,EAAE,CAAC;IACxB,cAAc,EAAE,GAAG,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;gBAEN,GAAG,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW;IA4KvD,OAAO;IAcP,KAAK;IAGL,MAAM;CAKT;AAED,eAAe,eAAe,CAAC"} -------------------------------------------------------------------------------- /dist/utils.d.ts: -------------------------------------------------------------------------------- 1 | import { InitOptions } from './interfaces'; 2 | declare const Utils: { 3 | generateId(prefix: string): string; 4 | containerDraggable(container: HTMLElement, header: HTMLElement): void; 5 | getBottomRightPosition(): { 6 | top: number; 7 | left: number; 8 | }; 9 | playAudio(filePath: string): void; 10 | getInitOptions(opts: InitOptions): InitOptions; 11 | titleID(title: string): string; 12 | }; 13 | export default Utils; 14 | //# sourceMappingURL=utils.d.ts.map -------------------------------------------------------------------------------- /dist/utils.d.ts.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,QAAA,MAAM,KAAK;uBAEY,MAAM,GAAG,MAAM;kCAGJ,WAAW,UAAU,WAAW;8BAoCpC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;wBAMnC,MAAM;yBAIL,WAAW,GAAG,WAAW;mBAgD/B,MAAM,GAAG,MAAM;CAIjC,CAAC;AAEF,eAAe,KAAK,CAAC"} -------------------------------------------------------------------------------- /finaltermo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rajnandan1/termo/93d0d757ce55228814941f90897eb81ab3ed9697/finaltermo.gif -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Termo - An Easy to use terminal for your browser 7 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 41 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | 61 |
62 |

Termo

63 |
64 |

65 | Termo is a simple terminal emulator that can be used to create a terminal-like interface on your 66 | website. It is inspired by the terminal emulator in stripe.dev. It 67 | is an wrapper on top of xterm.js. 68 |

69 |
70 | 71 | 72 | 73 | 74 | 75 | Clone from Github 76 | 77 |
78 |
79 |
80 |
81 |

Installation

82 | 120 | 121 |
122 |
123 |

Include the following script tag in your HTML file.

124 |
<script src="https://cdn.jsdelivr.net/gh/rajnandan1/termo/dist/termo.min.js"></script>
125 |
126 |
127 |

Install the package using npm.

128 |
npm install @rajnandan1/termo
129 |

Include / Import.

130 |
import Termo from '@rajnandan1/termo';
131 | 132 |

Please note that termo is a client side library and it will not work in server side code.

133 |
134 |
135 |

Sample React Code

136 |
import React, { useEffect, useRef } from 'react';
137 | import logo from './logo.svg';
138 | import './App.css';
139 | import Termo from '@rajnandan1/termo';
140 | 
141 | function App() {
142 |     const myDemoTerminalRef = useRef(null);
143 | 
144 |     useEffect(() => {
145 |         myDemoTerminalRef.current = new Termo({
146 |             title: 'bterm v1.0.022',
147 |             fontFamily: 'Sono',
148 |             theme: 'dark',
149 |             prompt: 'bterm@localhost:$',
150 |         });
151 |         myDemoTerminalRef.current.create();
152 | 
153 |         return () => {
154 |             myDemoTerminalRef.current.destroy();
155 |         };
156 |     }, []);
157 | 
158 |     const handleClick = () => {
159 |         myDemoTerminalRef.current.show();
160 |     };
161 | 
162 |     return (
163 |         <div className="App">
164 |             <header className="App-header">
165 |                 
166 |                 <button onClick={handleClick}>Show Terminal</button>
167 |             </header>
168 |         </div>
169 |     );
170 | }
171 | 
172 | export default App;
173 | 
174 | 175 |
176 |
177 |
178 | 179 |
180 |

Quick Start

181 |

Create a new instance of Termo by passing an object .

182 |
const myTermo = new termo({
183 |   title: "Termo",
184 |   welcomeMessage: "Welcome to Termo",
185 |   commands: [{
186 |     command: "hello",
187 |     description: "Says hello",
188 |     action: async (terminal, args) => terminal.write('\r\nHello! ' + args.join(' ')),
189 |   }],
190 | });
191 | myTermo.create();
192 | myTermo.show();
193 | 						
194 |
195 |
196 |

Complete Example

197 |

Here is a complete example of how to create a terminal with a custom command.

198 |
import { termo } from 'termo';
199 | 
200 | let commands = [{
201 |   command: 'hello',
202 |   description: 'Says hello',
203 |   action: async (terminal, args) => terminal.write('\r\nHello! ' + args.join(' ')),
204 | }, {
205 |   command: 'joke',
206 |   description: 'Hear a random joke from a random API',
207 |   action: (terminal, args) => {
208 |     terminal.write('\r\n' + 'Thinking of a joke...');
209 |     return new Promise(async (resolve, reject) => {
210 |       try {
211 |         const response = await fetch('https://official-joke-api.appspot.com/random_joke');
212 |         const data = await response.json();
213 |         terminal.write('\r\n' + data.setup);
214 |         setTimeout(() => {
215 |           resolve(terminal.write('\r\n' + data.punchline));
216 |         }, 2000);
217 |       } catch (error) {
218 |         terminal.write('\r\nFailed to fetch joke');
219 |       }
220 |     });
221 |   },
222 | }, {
223 |   command: 'theme',
224 |   description: 'Change the website theme',
225 |   subCommands: [{
226 |       command: 'set',
227 |       description: 'Set the website theme to light or dark',
228 |       action: async (terminal, args) => {
229 |         let theme = args[0];
230 |         if (theme === 'light') {
231 |           document.body.setAttribute('data-bs-theme', 'light');
232 |         } else {
233 |           document.body.setAttribute('data-bs-theme', 'dark');
234 |         }
235 |         terminal.write('\r\nsetting theme to ' + args[0]);
236 |       },
237 |     },
238 |     {
239 |       command: 'list',
240 |       description: 'List all available themes',
241 |       action: async (terminal, args) => {
242 |         let list = ['light', 'dark'];
243 |         list.forEach((theme) => {
244 |           terminal.write('\r\n' + theme);
245 |         });
246 |       },
247 |     },
248 |   ],
249 | }];
250 | 
251 | let myDemoTerminal = new termo({
252 |   commands: commands,
253 |   title: 'Termo v0.0.2',
254 |   theme: 'dark',
255 |   prompt: '$',
256 | });
257 | 
258 | myDemoTerminal.create();
259 | 
260 | myDemoTerminal.show();
261 | 				
262 |
263 |
264 |

Options

265 |

Termo accepts an object with the following options.

266 |

267 | /**
268 |  * Configuration options for initializing the terminal
269 |  * @interface InitOptions
270 |  * 
271 |  * @property {boolean} [playSound=true] - Enable/disable terminal sound effects
272 |  * @property {string} [title='termo'] - Terminal window title
273 |  * @property {string} [welcomeMessage] - Initial message displayed when terminal opens
274 |  * @property {'light' | 'dark'} [theme='light'] - Terminal color theme
275 |  * @property {string} [fontFamily='Courier New, monospace'] - Font family for terminal text
276 |  * @property {string} [prompt='$'] - Terminal prompt character
277 |  * @property {Command[]} [commands=[]] - Array of available terminal commands
278 |  * @property {ITerminalOptions} [terminalOptions] - XTerm.js specific terminal options
279 |  * 
280 |  * @example
281 |  * const options: InitOptions = {
282 |  *   playSound: true,
283 |  *   title: 'My Terminal',
284 |  *   theme: 'dark',
285 |  *   commands: [{
286 |  *     command: 'hello',
287 |  *     description: 'Says hello',
288 |  *     action: async (terminal, args) => terminal.write('\r\nHello! ' + args.join(' ')),
289 |  *   }]
290 |  * };
291 |  */
292 | export interface InitOptions {
293 |     playSound?: boolean;
294 |     title?: string;
295 |     welcomeMessage?: string;
296 |     theme?: 'light' | 'dark';
297 |     fontFamily?: string;
298 |     prompt?: string;
299 |     commands?: Command[];
300 |     terminalOptions?: ITerminalOptions;
301 | }
302 | 				
303 |

Command

304 |

Command object for defining terminal commands.

305 |

306 | /**
307 |  * Represents a terminal command with its description, action and optional subcommands
308 |  * @interface Command
309 |  * 
310 |  * @property {string} command - The command name/identifier
311 |  * @property {string} description - Brief description of what the command does
312 |  * @property {function} action - Async function to execute when command is invoked
313 |  * @property {Command[]} [subCommands] - Optional array of nested subcommands
314 |  * 
315 |  * @example
316 |  * const myCommand: Command = {
317 |  *   command: 'git',
318 |  *   description: 'Git version control',
319 |  *   action: async (terminal, args) => {
320 |  *     terminal.write('Executing git command...\r\n');
321 |  *   },
322 |  *   subCommands: [{
323 |  *     command: 'status',
324 |  *     description: 'Show working tree status',
325 |  *     action: async (terminal) => {
326 |  *       terminal.write('git status output...\r\n');
327 |  *     }
328 |  *   }]
329 |  * };
330 |  */
331 | export interface Command {
332 |     command: string;
333 |     description: string;
334 |     action: (terminal: Terminal, args: string[]) => Promise;
335 |     subCommands?: Command[];
336 | }
337 | 				
338 |
339 |
340 |

API

341 |

Termo exposes the following methods and variable.

342 |
const myTermo = new termo({
343 | 	"title": "Termo",
344 | });
345 |

Methods

346 |

Termo has the following methods.

347 |
/**
348 | * Creates a new terminal instance with the specified options.
349 | * 
350 | * This method initializes the terminal container, header, and various control buttons
351 | * (resize, close). It also sets up event listeners for these buttons to handle terminal
352 | * resizing and closing actions. The terminal is appended to the document body and made
353 | * draggable.
354 | * 
355 | * @throws {Error} If a terminal with the same title already exists.
356 | */
357 | myTermo.create();
358 |
/**
359 | * Displays the terminal by applying a scale transformation to the container element.
360 | * If the container exists, it plays the terminal open sound, sets the state to 'open',
361 | * and focuses the terminal. If the container does not exist, it throws an error.
362 | *
363 | * @throws {Error} If the terminal container is not created.
364 | */
365 | myTermo.show();  
366 |
/**
367 | * Hides the terminal by scaling down its container element.
368 | * If the container exists, it plays the terminal close sound,
369 | * scales the container to zero, and updates the state to 'minimized'.
370 | * If the container does not exist, it throws an error.
371 | *
372 | * @throws {Error} If the terminal container is not created.
373 | */
374 | myTermo.hide(); // Hides the terminal 
375 |
/**
376 | * Sets the theme of the terminal.
377 | * 
378 | * @param theme - The theme to set, either 'dark' or 'light'.
379 | * @throws Will throw an error if the terminal container is not created.
380 | */					
381 | myTermo.setTheme();  
382 |
/**
383 | * Destroys the terminal instance by performing the following actions:
384 | * - If the container exists:
385 | *   - Destroys the terminal manager.
386 | *   - Removes the container element from the document body.
387 | *   - Removes the associated stylesheet from the document head.
388 | *   - Sets the container to undefined.
389 | *   - Deletes the terminal manager.
390 | *   - Updates the state to 'destroyed'.
391 | *   - Sets the mode to 'floating'.
392 | * - If the container does not exist, throws an error indicating that the terminal was not created.
393 | *
394 | * @throws {Error} If the terminal was not created.
395 | */
396 | myTermo.destroy();  
397 |
/**
398 | * Adjusts the dimensions and position of the terminal container to dock it
399 | * at the bottom right corner of the viewport.
400 | * 
401 | * @throws {Error} Throws an error if the terminal container is not created.
402 | */
403 | myTermo.dock();
404 |
/**
405 | * Adjusts the dimensions and position of the container element to float it
406 | * at a specific size and position on the screen. If the container element
407 | * is not available, an error is thrown.
408 | *
409 | * @throws {Error} If the container element is not created.
410 | */
411 | myTermo.float(); 
412 |
413 |
414 |

Variables

415 |

Termo has the following variables.

416 |
/**
417 | * @class Termo
418 | * @property {InitOptions} options - The initialization options for the terminal.
419 | * @property {'floating' | 'docked'} mode - The current mode of the terminal (floating or docked).
420 | * @property {'minimized' | 'open' | 'destroyed' | 'initiated'} state - The current state of the terminal.
421 | * @property {HTMLDivElement | undefined} container - The container element for the terminal.
422 | * @property {TerminalManager | undefined} terminalManager - The terminal manager instance.
423 | */
424 | 				
425 |
426 |
427 | 428 | 429 | 430 | 431 | 432 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | let myDemoTerminal; 2 | 3 | function schoolPride() { 4 | var end = Date.now() + 2 * 1000; 5 | 6 | // go Buckeyes! 7 | var colors = ['#bb0000', '#ffffff']; 8 | 9 | (function frame() { 10 | confetti({ 11 | particleCount: 2, 12 | angle: 60, 13 | spread: 55, 14 | origin: { x: 0 }, 15 | colors: colors, 16 | }); 17 | confetti({ 18 | particleCount: 2, 19 | angle: 120, 20 | spread: 55, 21 | origin: { x: 1 }, 22 | colors: colors, 23 | }); 24 | 25 | if (Date.now() < end) { 26 | requestAnimationFrame(frame); 27 | } 28 | })(); 29 | } 30 | 31 | function fireWorks() { 32 | var duration = 2 * 1000; 33 | var animationEnd = Date.now() + duration; 34 | var defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 }; 35 | 36 | function randomInRange(min, max) { 37 | return Math.random() * (max - min) + min; 38 | } 39 | 40 | var interval = setInterval(function () { 41 | var timeLeft = animationEnd - Date.now(); 42 | 43 | if (timeLeft <= 0) { 44 | return clearInterval(interval); 45 | } 46 | 47 | var particleCount = 50 * (timeLeft / duration); 48 | // since particles fall down, start a bit higher than random 49 | confetti({ ...defaults, particleCount, origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 } }); 50 | confetti({ ...defaults, particleCount, origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 } }); 51 | }, 250); 52 | } 53 | 54 | $(document).ready(function () { 55 | // let myDemoTerminal2; 56 | let commands = [ 57 | { 58 | command: 'hello', 59 | description: 'Says hello', 60 | action: async (terminal, args) => terminal.write('\r\nHello! ' + args.join(' ')), 61 | }, 62 | { 63 | command: 'theme', 64 | description: 'Change the website theme', 65 | subCommands: [ 66 | { 67 | command: 'set', 68 | description: 'Set the website theme to light or dark', 69 | action: async (terminal, args) => { 70 | let theme = args[0]; 71 | if (theme === 'light') { 72 | document.body.setAttribute('data-bs-theme', 'light'); 73 | myDemoTerminal.setTheme('light'); 74 | } else { 75 | document.body.setAttribute('data-bs-theme', 'dark'); 76 | myDemoTerminal.setTheme('dark'); 77 | } 78 | terminal.write('\r\nsetting theme to ' + args[0]); 79 | }, 80 | }, 81 | { 82 | command: 'list', 83 | description: 'List all available themes', 84 | action: async (terminal, args) => { 85 | let list = ['light', 'dark']; 86 | list.forEach((theme) => { 87 | terminal.write('\r\n' + theme); 88 | }); 89 | }, 90 | }, 91 | ], 92 | }, 93 | { 94 | command: 'poppers', 95 | description: 'Poppers/School Pride animation', 96 | action: async (terminal, args) => { 97 | schoolPride(); 98 | terminal.write('\r\nGo Buckeyes!'); 99 | }, 100 | }, 101 | { 102 | command: 'fireworks', 103 | description: 'Fireworks animation', 104 | action: async (terminal, args) => { 105 | fireWorks(); 106 | terminal.write('\r\nFireworks!'); 107 | }, 108 | }, 109 | ]; 110 | myDemoTerminal = new termo({ 111 | commands: commands, 112 | title: 'bterm v1.0.02', 113 | fontFamily: 'Sono', 114 | theme: 'dark', 115 | prompt: 'bterm@localhost:$', 116 | }); 117 | myDemoTerminal.create(); 118 | 119 | $('#fireup').click(function (e) { 120 | myDemoTerminal.show(); 121 | }); 122 | 123 | // if c is pressed, hide the terminal 124 | $(document).keypress(function (e) { 125 | if (e.which === 99) { 126 | e.preventDefault(); 127 | myDemoTerminal.show(); 128 | } 129 | }); 130 | 131 | hljs.highlightAll(); 132 | }); 133 | -------------------------------------------------------------------------------- /og.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rajnandan1/termo/93d0d757ce55228814941f90897eb81ab3ed9697/og.png -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rajnandan1/termo", 3 | "version": "0.0.1", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@rajnandan1/termo", 9 | "version": "0.0.1", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "@rollup/plugin-commonjs": "^28.0.1", 13 | "@rollup/plugin-json": "^6.1.0", 14 | "@rollup/plugin-node-resolve": "^15.3.0", 15 | "@rollup/plugin-terser": "^0.4.4", 16 | "@types/xterm": "^2.0.3", 17 | "@xterm/addon-fit": "^0.10.0", 18 | "@xterm/addon-web-links": "^0.11.0", 19 | "@xterm/xterm": "^5.5.0", 20 | "prettier": "^3.2.5", 21 | "rollup": "^4.18.0", 22 | "rollup-plugin-postcss": "^4.0.2", 23 | "rollup-plugin-typescript2": "^0.36.0", 24 | "tslib": "^2.6.2", 25 | "typescript": "^5.4.5" 26 | } 27 | }, 28 | "node_modules/@jridgewell/gen-mapping": { 29 | "version": "0.3.5", 30 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", 31 | "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", 32 | "dev": true, 33 | "license": "MIT", 34 | "dependencies": { 35 | "@jridgewell/set-array": "^1.2.1", 36 | "@jridgewell/sourcemap-codec": "^1.4.10", 37 | "@jridgewell/trace-mapping": "^0.3.24" 38 | }, 39 | "engines": { 40 | "node": ">=6.0.0" 41 | } 42 | }, 43 | "node_modules/@jridgewell/resolve-uri": { 44 | "version": "3.1.2", 45 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 46 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 47 | "dev": true, 48 | "license": "MIT", 49 | "engines": { 50 | "node": ">=6.0.0" 51 | } 52 | }, 53 | "node_modules/@jridgewell/set-array": { 54 | "version": "1.2.1", 55 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", 56 | "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", 57 | "dev": true, 58 | "license": "MIT", 59 | "engines": { 60 | "node": ">=6.0.0" 61 | } 62 | }, 63 | "node_modules/@jridgewell/source-map": { 64 | "version": "0.3.6", 65 | "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", 66 | "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", 67 | "dev": true, 68 | "license": "MIT", 69 | "dependencies": { 70 | "@jridgewell/gen-mapping": "^0.3.5", 71 | "@jridgewell/trace-mapping": "^0.3.25" 72 | } 73 | }, 74 | "node_modules/@jridgewell/sourcemap-codec": { 75 | "version": "1.5.0", 76 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", 77 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", 78 | "dev": true, 79 | "license": "MIT" 80 | }, 81 | "node_modules/@jridgewell/trace-mapping": { 82 | "version": "0.3.25", 83 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", 84 | "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", 85 | "dev": true, 86 | "license": "MIT", 87 | "dependencies": { 88 | "@jridgewell/resolve-uri": "^3.1.0", 89 | "@jridgewell/sourcemap-codec": "^1.4.14" 90 | } 91 | }, 92 | "node_modules/@rollup/plugin-commonjs": { 93 | "version": "28.0.1", 94 | "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.1.tgz", 95 | "integrity": "sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==", 96 | "dev": true, 97 | "license": "MIT", 98 | "dependencies": { 99 | "@rollup/pluginutils": "^5.0.1", 100 | "commondir": "^1.0.1", 101 | "estree-walker": "^2.0.2", 102 | "fdir": "^6.2.0", 103 | "is-reference": "1.2.1", 104 | "magic-string": "^0.30.3", 105 | "picomatch": "^4.0.2" 106 | }, 107 | "engines": { 108 | "node": ">=16.0.0 || 14 >= 14.17" 109 | }, 110 | "peerDependencies": { 111 | "rollup": "^2.68.0||^3.0.0||^4.0.0" 112 | }, 113 | "peerDependenciesMeta": { 114 | "rollup": { 115 | "optional": true 116 | } 117 | } 118 | }, 119 | "node_modules/@rollup/plugin-commonjs/node_modules/@rollup/pluginutils": { 120 | "version": "5.1.3", 121 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", 122 | "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", 123 | "dev": true, 124 | "license": "MIT", 125 | "dependencies": { 126 | "@types/estree": "^1.0.0", 127 | "estree-walker": "^2.0.2", 128 | "picomatch": "^4.0.2" 129 | }, 130 | "engines": { 131 | "node": ">=14.0.0" 132 | }, 133 | "peerDependencies": { 134 | "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" 135 | }, 136 | "peerDependenciesMeta": { 137 | "rollup": { 138 | "optional": true 139 | } 140 | } 141 | }, 142 | "node_modules/@rollup/plugin-commonjs/node_modules/fdir": { 143 | "version": "6.4.2", 144 | "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.2.tgz", 145 | "integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==", 146 | "dev": true, 147 | "license": "MIT", 148 | "peerDependencies": { 149 | "picomatch": "^3 || ^4" 150 | }, 151 | "peerDependenciesMeta": { 152 | "picomatch": { 153 | "optional": true 154 | } 155 | } 156 | }, 157 | "node_modules/@rollup/plugin-commonjs/node_modules/picomatch": { 158 | "version": "4.0.2", 159 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", 160 | "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", 161 | "dev": true, 162 | "license": "MIT", 163 | "engines": { 164 | "node": ">=12" 165 | }, 166 | "funding": { 167 | "url": "https://github.com/sponsors/jonschlinkert" 168 | } 169 | }, 170 | "node_modules/@rollup/plugin-json": { 171 | "version": "6.1.0", 172 | "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", 173 | "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", 174 | "dev": true, 175 | "license": "MIT", 176 | "dependencies": { 177 | "@rollup/pluginutils": "^5.1.0" 178 | }, 179 | "engines": { 180 | "node": ">=14.0.0" 181 | }, 182 | "peerDependencies": { 183 | "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" 184 | }, 185 | "peerDependenciesMeta": { 186 | "rollup": { 187 | "optional": true 188 | } 189 | } 190 | }, 191 | "node_modules/@rollup/plugin-json/node_modules/@rollup/pluginutils": { 192 | "version": "5.1.3", 193 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", 194 | "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", 195 | "dev": true, 196 | "license": "MIT", 197 | "dependencies": { 198 | "@types/estree": "^1.0.0", 199 | "estree-walker": "^2.0.2", 200 | "picomatch": "^4.0.2" 201 | }, 202 | "engines": { 203 | "node": ">=14.0.0" 204 | }, 205 | "peerDependencies": { 206 | "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" 207 | }, 208 | "peerDependenciesMeta": { 209 | "rollup": { 210 | "optional": true 211 | } 212 | } 213 | }, 214 | "node_modules/@rollup/plugin-json/node_modules/picomatch": { 215 | "version": "4.0.2", 216 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", 217 | "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", 218 | "dev": true, 219 | "license": "MIT", 220 | "engines": { 221 | "node": ">=12" 222 | }, 223 | "funding": { 224 | "url": "https://github.com/sponsors/jonschlinkert" 225 | } 226 | }, 227 | "node_modules/@rollup/plugin-node-resolve": { 228 | "version": "15.3.0", 229 | "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.0.tgz", 230 | "integrity": "sha512-9eO5McEICxMzJpDW9OnMYSv4Sta3hmt7VtBFz5zR9273suNOydOyq/FrGeGy+KsTRFm8w0SLVhzig2ILFT63Ag==", 231 | "dev": true, 232 | "license": "MIT", 233 | "dependencies": { 234 | "@rollup/pluginutils": "^5.0.1", 235 | "@types/resolve": "1.20.2", 236 | "deepmerge": "^4.2.2", 237 | "is-module": "^1.0.0", 238 | "resolve": "^1.22.1" 239 | }, 240 | "engines": { 241 | "node": ">=14.0.0" 242 | }, 243 | "peerDependencies": { 244 | "rollup": "^2.78.0||^3.0.0||^4.0.0" 245 | }, 246 | "peerDependenciesMeta": { 247 | "rollup": { 248 | "optional": true 249 | } 250 | } 251 | }, 252 | "node_modules/@rollup/plugin-node-resolve/node_modules/@rollup/pluginutils": { 253 | "version": "5.1.3", 254 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", 255 | "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", 256 | "dev": true, 257 | "license": "MIT", 258 | "dependencies": { 259 | "@types/estree": "^1.0.0", 260 | "estree-walker": "^2.0.2", 261 | "picomatch": "^4.0.2" 262 | }, 263 | "engines": { 264 | "node": ">=14.0.0" 265 | }, 266 | "peerDependencies": { 267 | "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" 268 | }, 269 | "peerDependenciesMeta": { 270 | "rollup": { 271 | "optional": true 272 | } 273 | } 274 | }, 275 | "node_modules/@rollup/plugin-node-resolve/node_modules/picomatch": { 276 | "version": "4.0.2", 277 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", 278 | "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", 279 | "dev": true, 280 | "license": "MIT", 281 | "engines": { 282 | "node": ">=12" 283 | }, 284 | "funding": { 285 | "url": "https://github.com/sponsors/jonschlinkert" 286 | } 287 | }, 288 | "node_modules/@rollup/plugin-terser": { 289 | "version": "0.4.4", 290 | "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", 291 | "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", 292 | "dev": true, 293 | "license": "MIT", 294 | "dependencies": { 295 | "serialize-javascript": "^6.0.1", 296 | "smob": "^1.0.0", 297 | "terser": "^5.17.4" 298 | }, 299 | "engines": { 300 | "node": ">=14.0.0" 301 | }, 302 | "peerDependencies": { 303 | "rollup": "^2.0.0||^3.0.0||^4.0.0" 304 | }, 305 | "peerDependenciesMeta": { 306 | "rollup": { 307 | "optional": true 308 | } 309 | } 310 | }, 311 | "node_modules/@rollup/pluginutils": { 312 | "version": "4.2.1", 313 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", 314 | "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", 315 | "dev": true, 316 | "license": "MIT", 317 | "dependencies": { 318 | "estree-walker": "^2.0.1", 319 | "picomatch": "^2.2.2" 320 | }, 321 | "engines": { 322 | "node": ">= 8.0.0" 323 | } 324 | }, 325 | "node_modules/@rollup/rollup-android-arm-eabi": { 326 | "version": "4.28.1", 327 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.28.1.tgz", 328 | "integrity": "sha512-2aZp8AES04KI2dy3Ss6/MDjXbwBzj+i0GqKtWXgw2/Ma6E4jJvujryO6gJAghIRVz7Vwr9Gtl/8na3nDUKpraQ==", 329 | "cpu": [ 330 | "arm" 331 | ], 332 | "dev": true, 333 | "license": "MIT", 334 | "optional": true, 335 | "os": [ 336 | "android" 337 | ] 338 | }, 339 | "node_modules/@rollup/rollup-android-arm64": { 340 | "version": "4.28.1", 341 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.28.1.tgz", 342 | "integrity": "sha512-EbkK285O+1YMrg57xVA+Dp0tDBRB93/BZKph9XhMjezf6F4TpYjaUSuPt5J0fZXlSag0LmZAsTmdGGqPp4pQFA==", 343 | "cpu": [ 344 | "arm64" 345 | ], 346 | "dev": true, 347 | "license": "MIT", 348 | "optional": true, 349 | "os": [ 350 | "android" 351 | ] 352 | }, 353 | "node_modules/@rollup/rollup-darwin-arm64": { 354 | "version": "4.28.1", 355 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.28.1.tgz", 356 | "integrity": "sha512-prduvrMKU6NzMq6nxzQw445zXgaDBbMQvmKSJaxpaZ5R1QDM8w+eGxo6Y/jhT/cLoCvnZI42oEqf9KQNYz1fqQ==", 357 | "cpu": [ 358 | "arm64" 359 | ], 360 | "dev": true, 361 | "license": "MIT", 362 | "optional": true, 363 | "os": [ 364 | "darwin" 365 | ] 366 | }, 367 | "node_modules/@rollup/rollup-darwin-x64": { 368 | "version": "4.28.1", 369 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.28.1.tgz", 370 | "integrity": "sha512-WsvbOunsUk0wccO/TV4o7IKgloJ942hVFK1CLatwv6TJspcCZb9umQkPdvB7FihmdxgaKR5JyxDjWpCOp4uZlQ==", 371 | "cpu": [ 372 | "x64" 373 | ], 374 | "dev": true, 375 | "license": "MIT", 376 | "optional": true, 377 | "os": [ 378 | "darwin" 379 | ] 380 | }, 381 | "node_modules/@rollup/rollup-freebsd-arm64": { 382 | "version": "4.28.1", 383 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.28.1.tgz", 384 | "integrity": "sha512-HTDPdY1caUcU4qK23FeeGxCdJF64cKkqajU0iBnTVxS8F7H/7BewvYoG+va1KPSL63kQ1PGNyiwKOfReavzvNA==", 385 | "cpu": [ 386 | "arm64" 387 | ], 388 | "dev": true, 389 | "license": "MIT", 390 | "optional": true, 391 | "os": [ 392 | "freebsd" 393 | ] 394 | }, 395 | "node_modules/@rollup/rollup-freebsd-x64": { 396 | "version": "4.28.1", 397 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.28.1.tgz", 398 | "integrity": "sha512-m/uYasxkUevcFTeRSM9TeLyPe2QDuqtjkeoTpP9SW0XxUWfcYrGDMkO/m2tTw+4NMAF9P2fU3Mw4ahNvo7QmsQ==", 399 | "cpu": [ 400 | "x64" 401 | ], 402 | "dev": true, 403 | "license": "MIT", 404 | "optional": true, 405 | "os": [ 406 | "freebsd" 407 | ] 408 | }, 409 | "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 410 | "version": "4.28.1", 411 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.28.1.tgz", 412 | "integrity": "sha512-QAg11ZIt6mcmzpNE6JZBpKfJaKkqTm1A9+y9O+frdZJEuhQxiugM05gnCWiANHj4RmbgeVJpTdmKRmH/a+0QbA==", 413 | "cpu": [ 414 | "arm" 415 | ], 416 | "dev": true, 417 | "license": "MIT", 418 | "optional": true, 419 | "os": [ 420 | "linux" 421 | ] 422 | }, 423 | "node_modules/@rollup/rollup-linux-arm-musleabihf": { 424 | "version": "4.28.1", 425 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.28.1.tgz", 426 | "integrity": "sha512-dRP9PEBfolq1dmMcFqbEPSd9VlRuVWEGSmbxVEfiq2cs2jlZAl0YNxFzAQS2OrQmsLBLAATDMb3Z6MFv5vOcXg==", 427 | "cpu": [ 428 | "arm" 429 | ], 430 | "dev": true, 431 | "license": "MIT", 432 | "optional": true, 433 | "os": [ 434 | "linux" 435 | ] 436 | }, 437 | "node_modules/@rollup/rollup-linux-arm64-gnu": { 438 | "version": "4.28.1", 439 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.28.1.tgz", 440 | "integrity": "sha512-uGr8khxO+CKT4XU8ZUH1TTEUtlktK6Kgtv0+6bIFSeiSlnGJHG1tSFSjm41uQ9sAO/5ULx9mWOz70jYLyv1QkA==", 441 | "cpu": [ 442 | "arm64" 443 | ], 444 | "dev": true, 445 | "license": "MIT", 446 | "optional": true, 447 | "os": [ 448 | "linux" 449 | ] 450 | }, 451 | "node_modules/@rollup/rollup-linux-arm64-musl": { 452 | "version": "4.28.1", 453 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.28.1.tgz", 454 | "integrity": "sha512-QF54q8MYGAqMLrX2t7tNpi01nvq5RI59UBNx+3+37zoKX5KViPo/gk2QLhsuqok05sSCRluj0D00LzCwBikb0A==", 455 | "cpu": [ 456 | "arm64" 457 | ], 458 | "dev": true, 459 | "license": "MIT", 460 | "optional": true, 461 | "os": [ 462 | "linux" 463 | ] 464 | }, 465 | "node_modules/@rollup/rollup-linux-loongarch64-gnu": { 466 | "version": "4.28.1", 467 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.28.1.tgz", 468 | "integrity": "sha512-vPul4uodvWvLhRco2w0GcyZcdyBfpfDRgNKU+p35AWEbJ/HPs1tOUrkSueVbBS0RQHAf/A+nNtDpvw95PeVKOA==", 469 | "cpu": [ 470 | "loong64" 471 | ], 472 | "dev": true, 473 | "license": "MIT", 474 | "optional": true, 475 | "os": [ 476 | "linux" 477 | ] 478 | }, 479 | "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { 480 | "version": "4.28.1", 481 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.28.1.tgz", 482 | "integrity": "sha512-pTnTdBuC2+pt1Rmm2SV7JWRqzhYpEILML4PKODqLz+C7Ou2apEV52h19CR7es+u04KlqplggmN9sqZlekg3R1A==", 483 | "cpu": [ 484 | "ppc64" 485 | ], 486 | "dev": true, 487 | "license": "MIT", 488 | "optional": true, 489 | "os": [ 490 | "linux" 491 | ] 492 | }, 493 | "node_modules/@rollup/rollup-linux-riscv64-gnu": { 494 | "version": "4.28.1", 495 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.28.1.tgz", 496 | "integrity": "sha512-vWXy1Nfg7TPBSuAncfInmAI/WZDd5vOklyLJDdIRKABcZWojNDY0NJwruY2AcnCLnRJKSaBgf/GiJfauu8cQZA==", 497 | "cpu": [ 498 | "riscv64" 499 | ], 500 | "dev": true, 501 | "license": "MIT", 502 | "optional": true, 503 | "os": [ 504 | "linux" 505 | ] 506 | }, 507 | "node_modules/@rollup/rollup-linux-s390x-gnu": { 508 | "version": "4.28.1", 509 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.28.1.tgz", 510 | "integrity": "sha512-/yqC2Y53oZjb0yz8PVuGOQQNOTwxcizudunl/tFs1aLvObTclTwZ0JhXF2XcPT/zuaymemCDSuuUPXJJyqeDOg==", 511 | "cpu": [ 512 | "s390x" 513 | ], 514 | "dev": true, 515 | "license": "MIT", 516 | "optional": true, 517 | "os": [ 518 | "linux" 519 | ] 520 | }, 521 | "node_modules/@rollup/rollup-linux-x64-gnu": { 522 | "version": "4.28.1", 523 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.28.1.tgz", 524 | "integrity": "sha512-fzgeABz7rrAlKYB0y2kSEiURrI0691CSL0+KXwKwhxvj92VULEDQLpBYLHpF49MSiPG4sq5CK3qHMnb9tlCjBw==", 525 | "cpu": [ 526 | "x64" 527 | ], 528 | "dev": true, 529 | "license": "MIT", 530 | "optional": true, 531 | "os": [ 532 | "linux" 533 | ] 534 | }, 535 | "node_modules/@rollup/rollup-linux-x64-musl": { 536 | "version": "4.28.1", 537 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.28.1.tgz", 538 | "integrity": "sha512-xQTDVzSGiMlSshpJCtudbWyRfLaNiVPXt1WgdWTwWz9n0U12cI2ZVtWe/Jgwyv/6wjL7b66uu61Vg0POWVfz4g==", 539 | "cpu": [ 540 | "x64" 541 | ], 542 | "dev": true, 543 | "license": "MIT", 544 | "optional": true, 545 | "os": [ 546 | "linux" 547 | ] 548 | }, 549 | "node_modules/@rollup/rollup-win32-arm64-msvc": { 550 | "version": "4.28.1", 551 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.28.1.tgz", 552 | "integrity": "sha512-wSXmDRVupJstFP7elGMgv+2HqXelQhuNf+IS4V+nUpNVi/GUiBgDmfwD0UGN3pcAnWsgKG3I52wMOBnk1VHr/A==", 553 | "cpu": [ 554 | "arm64" 555 | ], 556 | "dev": true, 557 | "license": "MIT", 558 | "optional": true, 559 | "os": [ 560 | "win32" 561 | ] 562 | }, 563 | "node_modules/@rollup/rollup-win32-ia32-msvc": { 564 | "version": "4.28.1", 565 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.28.1.tgz", 566 | "integrity": "sha512-ZkyTJ/9vkgrE/Rk9vhMXhf8l9D+eAhbAVbsGsXKy2ohmJaWg0LPQLnIxRdRp/bKyr8tXuPlXhIoGlEB5XpJnGA==", 567 | "cpu": [ 568 | "ia32" 569 | ], 570 | "dev": true, 571 | "license": "MIT", 572 | "optional": true, 573 | "os": [ 574 | "win32" 575 | ] 576 | }, 577 | "node_modules/@rollup/rollup-win32-x64-msvc": { 578 | "version": "4.28.1", 579 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.28.1.tgz", 580 | "integrity": "sha512-ZvK2jBafvttJjoIdKm/Q/Bh7IJ1Ose9IBOwpOXcOvW3ikGTQGmKDgxTC6oCAzW6PynbkKP8+um1du81XJHZ0JA==", 581 | "cpu": [ 582 | "x64" 583 | ], 584 | "dev": true, 585 | "license": "MIT", 586 | "optional": true, 587 | "os": [ 588 | "win32" 589 | ] 590 | }, 591 | "node_modules/@trysound/sax": { 592 | "version": "0.2.0", 593 | "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", 594 | "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", 595 | "dev": true, 596 | "license": "ISC", 597 | "engines": { 598 | "node": ">=10.13.0" 599 | } 600 | }, 601 | "node_modules/@types/estree": { 602 | "version": "1.0.6", 603 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", 604 | "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", 605 | "dev": true, 606 | "license": "MIT" 607 | }, 608 | "node_modules/@types/resolve": { 609 | "version": "1.20.2", 610 | "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", 611 | "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", 612 | "dev": true, 613 | "license": "MIT" 614 | }, 615 | "node_modules/@types/xterm": { 616 | "version": "2.0.3", 617 | "resolved": "https://registry.npmjs.org/@types/xterm/-/xterm-2.0.3.tgz", 618 | "integrity": "sha512-Owlz29ThHtn2RQry87juaNYeIc4Dr8ykLLX0JKKt4SdO6ujwJnsXCpBAr6bwo/f4L3xSfM9KA7OnPPf9Xit6tA==", 619 | "dev": true, 620 | "license": "MIT" 621 | }, 622 | "node_modules/@xterm/addon-fit": { 623 | "version": "0.10.0", 624 | "resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.10.0.tgz", 625 | "integrity": "sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ==", 626 | "dev": true, 627 | "license": "MIT", 628 | "peerDependencies": { 629 | "@xterm/xterm": "^5.0.0" 630 | } 631 | }, 632 | "node_modules/@xterm/addon-web-links": { 633 | "version": "0.11.0", 634 | "resolved": "https://registry.npmjs.org/@xterm/addon-web-links/-/addon-web-links-0.11.0.tgz", 635 | "integrity": "sha512-nIHQ38pQI+a5kXnRaTgwqSHnX7KE6+4SVoceompgHL26unAxdfP6IPqUTSYPQgSwM56hsElfoNrrW5V7BUED/Q==", 636 | "dev": true, 637 | "license": "MIT", 638 | "peerDependencies": { 639 | "@xterm/xterm": "^5.0.0" 640 | } 641 | }, 642 | "node_modules/@xterm/xterm": { 643 | "version": "5.5.0", 644 | "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", 645 | "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==", 646 | "dev": true, 647 | "license": "MIT" 648 | }, 649 | "node_modules/acorn": { 650 | "version": "8.14.0", 651 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", 652 | "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", 653 | "dev": true, 654 | "license": "MIT", 655 | "bin": { 656 | "acorn": "bin/acorn" 657 | }, 658 | "engines": { 659 | "node": ">=0.4.0" 660 | } 661 | }, 662 | "node_modules/ansi-styles": { 663 | "version": "4.3.0", 664 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 665 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 666 | "dev": true, 667 | "license": "MIT", 668 | "dependencies": { 669 | "color-convert": "^2.0.1" 670 | }, 671 | "engines": { 672 | "node": ">=8" 673 | }, 674 | "funding": { 675 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 676 | } 677 | }, 678 | "node_modules/boolbase": { 679 | "version": "1.0.0", 680 | "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", 681 | "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", 682 | "dev": true, 683 | "license": "ISC" 684 | }, 685 | "node_modules/browserslist": { 686 | "version": "4.24.2", 687 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", 688 | "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", 689 | "dev": true, 690 | "funding": [ 691 | { 692 | "type": "opencollective", 693 | "url": "https://opencollective.com/browserslist" 694 | }, 695 | { 696 | "type": "tidelift", 697 | "url": "https://tidelift.com/funding/github/npm/browserslist" 698 | }, 699 | { 700 | "type": "github", 701 | "url": "https://github.com/sponsors/ai" 702 | } 703 | ], 704 | "license": "MIT", 705 | "dependencies": { 706 | "caniuse-lite": "^1.0.30001669", 707 | "electron-to-chromium": "^1.5.41", 708 | "node-releases": "^2.0.18", 709 | "update-browserslist-db": "^1.1.1" 710 | }, 711 | "bin": { 712 | "browserslist": "cli.js" 713 | }, 714 | "engines": { 715 | "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 716 | } 717 | }, 718 | "node_modules/buffer-from": { 719 | "version": "1.1.2", 720 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 721 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 722 | "dev": true, 723 | "license": "MIT" 724 | }, 725 | "node_modules/caniuse-api": { 726 | "version": "3.0.0", 727 | "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", 728 | "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", 729 | "dev": true, 730 | "license": "MIT", 731 | "dependencies": { 732 | "browserslist": "^4.0.0", 733 | "caniuse-lite": "^1.0.0", 734 | "lodash.memoize": "^4.1.2", 735 | "lodash.uniq": "^4.5.0" 736 | } 737 | }, 738 | "node_modules/caniuse-lite": { 739 | "version": "1.0.30001687", 740 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001687.tgz", 741 | "integrity": "sha512-0S/FDhf4ZiqrTUiQ39dKeUjYRjkv7lOZU1Dgif2rIqrTzX/1wV2hfKu9TOm1IHkdSijfLswxTFzl/cvir+SLSQ==", 742 | "dev": true, 743 | "funding": [ 744 | { 745 | "type": "opencollective", 746 | "url": "https://opencollective.com/browserslist" 747 | }, 748 | { 749 | "type": "tidelift", 750 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 751 | }, 752 | { 753 | "type": "github", 754 | "url": "https://github.com/sponsors/ai" 755 | } 756 | ], 757 | "license": "CC-BY-4.0" 758 | }, 759 | "node_modules/chalk": { 760 | "version": "4.1.2", 761 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 762 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 763 | "dev": true, 764 | "license": "MIT", 765 | "dependencies": { 766 | "ansi-styles": "^4.1.0", 767 | "supports-color": "^7.1.0" 768 | }, 769 | "engines": { 770 | "node": ">=10" 771 | }, 772 | "funding": { 773 | "url": "https://github.com/chalk/chalk?sponsor=1" 774 | } 775 | }, 776 | "node_modules/color-convert": { 777 | "version": "2.0.1", 778 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 779 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 780 | "dev": true, 781 | "license": "MIT", 782 | "dependencies": { 783 | "color-name": "~1.1.4" 784 | }, 785 | "engines": { 786 | "node": ">=7.0.0" 787 | } 788 | }, 789 | "node_modules/color-name": { 790 | "version": "1.1.4", 791 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 792 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 793 | "dev": true, 794 | "license": "MIT" 795 | }, 796 | "node_modules/colord": { 797 | "version": "2.9.3", 798 | "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", 799 | "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", 800 | "dev": true, 801 | "license": "MIT" 802 | }, 803 | "node_modules/commander": { 804 | "version": "2.20.3", 805 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 806 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 807 | "dev": true, 808 | "license": "MIT" 809 | }, 810 | "node_modules/commondir": { 811 | "version": "1.0.1", 812 | "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", 813 | "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", 814 | "dev": true, 815 | "license": "MIT" 816 | }, 817 | "node_modules/concat-with-sourcemaps": { 818 | "version": "1.1.0", 819 | "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", 820 | "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", 821 | "dev": true, 822 | "license": "ISC", 823 | "dependencies": { 824 | "source-map": "^0.6.1" 825 | } 826 | }, 827 | "node_modules/css-declaration-sorter": { 828 | "version": "6.4.1", 829 | "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", 830 | "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", 831 | "dev": true, 832 | "license": "ISC", 833 | "engines": { 834 | "node": "^10 || ^12 || >=14" 835 | }, 836 | "peerDependencies": { 837 | "postcss": "^8.0.9" 838 | } 839 | }, 840 | "node_modules/css-select": { 841 | "version": "4.3.0", 842 | "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", 843 | "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", 844 | "dev": true, 845 | "license": "BSD-2-Clause", 846 | "dependencies": { 847 | "boolbase": "^1.0.0", 848 | "css-what": "^6.0.1", 849 | "domhandler": "^4.3.1", 850 | "domutils": "^2.8.0", 851 | "nth-check": "^2.0.1" 852 | }, 853 | "funding": { 854 | "url": "https://github.com/sponsors/fb55" 855 | } 856 | }, 857 | "node_modules/css-tree": { 858 | "version": "1.1.3", 859 | "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", 860 | "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", 861 | "dev": true, 862 | "license": "MIT", 863 | "dependencies": { 864 | "mdn-data": "2.0.14", 865 | "source-map": "^0.6.1" 866 | }, 867 | "engines": { 868 | "node": ">=8.0.0" 869 | } 870 | }, 871 | "node_modules/css-what": { 872 | "version": "6.1.0", 873 | "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", 874 | "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", 875 | "dev": true, 876 | "license": "BSD-2-Clause", 877 | "engines": { 878 | "node": ">= 6" 879 | }, 880 | "funding": { 881 | "url": "https://github.com/sponsors/fb55" 882 | } 883 | }, 884 | "node_modules/cssesc": { 885 | "version": "3.0.0", 886 | "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", 887 | "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", 888 | "dev": true, 889 | "license": "MIT", 890 | "bin": { 891 | "cssesc": "bin/cssesc" 892 | }, 893 | "engines": { 894 | "node": ">=4" 895 | } 896 | }, 897 | "node_modules/cssnano": { 898 | "version": "5.1.15", 899 | "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", 900 | "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", 901 | "dev": true, 902 | "license": "MIT", 903 | "dependencies": { 904 | "cssnano-preset-default": "^5.2.14", 905 | "lilconfig": "^2.0.3", 906 | "yaml": "^1.10.2" 907 | }, 908 | "engines": { 909 | "node": "^10 || ^12 || >=14.0" 910 | }, 911 | "funding": { 912 | "type": "opencollective", 913 | "url": "https://opencollective.com/cssnano" 914 | }, 915 | "peerDependencies": { 916 | "postcss": "^8.2.15" 917 | } 918 | }, 919 | "node_modules/cssnano-preset-default": { 920 | "version": "5.2.14", 921 | "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", 922 | "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", 923 | "dev": true, 924 | "license": "MIT", 925 | "dependencies": { 926 | "css-declaration-sorter": "^6.3.1", 927 | "cssnano-utils": "^3.1.0", 928 | "postcss-calc": "^8.2.3", 929 | "postcss-colormin": "^5.3.1", 930 | "postcss-convert-values": "^5.1.3", 931 | "postcss-discard-comments": "^5.1.2", 932 | "postcss-discard-duplicates": "^5.1.0", 933 | "postcss-discard-empty": "^5.1.1", 934 | "postcss-discard-overridden": "^5.1.0", 935 | "postcss-merge-longhand": "^5.1.7", 936 | "postcss-merge-rules": "^5.1.4", 937 | "postcss-minify-font-values": "^5.1.0", 938 | "postcss-minify-gradients": "^5.1.1", 939 | "postcss-minify-params": "^5.1.4", 940 | "postcss-minify-selectors": "^5.2.1", 941 | "postcss-normalize-charset": "^5.1.0", 942 | "postcss-normalize-display-values": "^5.1.0", 943 | "postcss-normalize-positions": "^5.1.1", 944 | "postcss-normalize-repeat-style": "^5.1.1", 945 | "postcss-normalize-string": "^5.1.0", 946 | "postcss-normalize-timing-functions": "^5.1.0", 947 | "postcss-normalize-unicode": "^5.1.1", 948 | "postcss-normalize-url": "^5.1.0", 949 | "postcss-normalize-whitespace": "^5.1.1", 950 | "postcss-ordered-values": "^5.1.3", 951 | "postcss-reduce-initial": "^5.1.2", 952 | "postcss-reduce-transforms": "^5.1.0", 953 | "postcss-svgo": "^5.1.0", 954 | "postcss-unique-selectors": "^5.1.1" 955 | }, 956 | "engines": { 957 | "node": "^10 || ^12 || >=14.0" 958 | }, 959 | "peerDependencies": { 960 | "postcss": "^8.2.15" 961 | } 962 | }, 963 | "node_modules/cssnano-utils": { 964 | "version": "3.1.0", 965 | "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", 966 | "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", 967 | "dev": true, 968 | "license": "MIT", 969 | "engines": { 970 | "node": "^10 || ^12 || >=14.0" 971 | }, 972 | "peerDependencies": { 973 | "postcss": "^8.2.15" 974 | } 975 | }, 976 | "node_modules/csso": { 977 | "version": "4.2.0", 978 | "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", 979 | "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", 980 | "dev": true, 981 | "license": "MIT", 982 | "dependencies": { 983 | "css-tree": "^1.1.2" 984 | }, 985 | "engines": { 986 | "node": ">=8.0.0" 987 | } 988 | }, 989 | "node_modules/deepmerge": { 990 | "version": "4.3.1", 991 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", 992 | "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", 993 | "dev": true, 994 | "license": "MIT", 995 | "engines": { 996 | "node": ">=0.10.0" 997 | } 998 | }, 999 | "node_modules/dom-serializer": { 1000 | "version": "1.4.1", 1001 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", 1002 | "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", 1003 | "dev": true, 1004 | "license": "MIT", 1005 | "dependencies": { 1006 | "domelementtype": "^2.0.1", 1007 | "domhandler": "^4.2.0", 1008 | "entities": "^2.0.0" 1009 | }, 1010 | "funding": { 1011 | "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" 1012 | } 1013 | }, 1014 | "node_modules/domelementtype": { 1015 | "version": "2.3.0", 1016 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", 1017 | "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", 1018 | "dev": true, 1019 | "funding": [ 1020 | { 1021 | "type": "github", 1022 | "url": "https://github.com/sponsors/fb55" 1023 | } 1024 | ], 1025 | "license": "BSD-2-Clause" 1026 | }, 1027 | "node_modules/domhandler": { 1028 | "version": "4.3.1", 1029 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", 1030 | "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", 1031 | "dev": true, 1032 | "license": "BSD-2-Clause", 1033 | "dependencies": { 1034 | "domelementtype": "^2.2.0" 1035 | }, 1036 | "engines": { 1037 | "node": ">= 4" 1038 | }, 1039 | "funding": { 1040 | "url": "https://github.com/fb55/domhandler?sponsor=1" 1041 | } 1042 | }, 1043 | "node_modules/domutils": { 1044 | "version": "2.8.0", 1045 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", 1046 | "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", 1047 | "dev": true, 1048 | "license": "BSD-2-Clause", 1049 | "dependencies": { 1050 | "dom-serializer": "^1.0.1", 1051 | "domelementtype": "^2.2.0", 1052 | "domhandler": "^4.2.0" 1053 | }, 1054 | "funding": { 1055 | "url": "https://github.com/fb55/domutils?sponsor=1" 1056 | } 1057 | }, 1058 | "node_modules/electron-to-chromium": { 1059 | "version": "1.5.71", 1060 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.71.tgz", 1061 | "integrity": "sha512-dB68l59BI75W1BUGVTAEJy45CEVuEGy9qPVVQ8pnHyHMn36PLPPoE1mjLH+lo9rKulO3HC2OhbACI/8tCqJBcA==", 1062 | "dev": true, 1063 | "license": "ISC" 1064 | }, 1065 | "node_modules/entities": { 1066 | "version": "2.2.0", 1067 | "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", 1068 | "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", 1069 | "dev": true, 1070 | "license": "BSD-2-Clause", 1071 | "funding": { 1072 | "url": "https://github.com/fb55/entities?sponsor=1" 1073 | } 1074 | }, 1075 | "node_modules/escalade": { 1076 | "version": "3.2.0", 1077 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", 1078 | "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", 1079 | "dev": true, 1080 | "license": "MIT", 1081 | "engines": { 1082 | "node": ">=6" 1083 | } 1084 | }, 1085 | "node_modules/estree-walker": { 1086 | "version": "2.0.2", 1087 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 1088 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 1089 | "dev": true, 1090 | "license": "MIT" 1091 | }, 1092 | "node_modules/eventemitter3": { 1093 | "version": "4.0.7", 1094 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", 1095 | "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", 1096 | "dev": true, 1097 | "license": "MIT" 1098 | }, 1099 | "node_modules/find-cache-dir": { 1100 | "version": "3.3.2", 1101 | "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", 1102 | "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", 1103 | "dev": true, 1104 | "license": "MIT", 1105 | "dependencies": { 1106 | "commondir": "^1.0.1", 1107 | "make-dir": "^3.0.2", 1108 | "pkg-dir": "^4.1.0" 1109 | }, 1110 | "engines": { 1111 | "node": ">=8" 1112 | }, 1113 | "funding": { 1114 | "url": "https://github.com/avajs/find-cache-dir?sponsor=1" 1115 | } 1116 | }, 1117 | "node_modules/find-up": { 1118 | "version": "4.1.0", 1119 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", 1120 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", 1121 | "dev": true, 1122 | "license": "MIT", 1123 | "dependencies": { 1124 | "locate-path": "^5.0.0", 1125 | "path-exists": "^4.0.0" 1126 | }, 1127 | "engines": { 1128 | "node": ">=8" 1129 | } 1130 | }, 1131 | "node_modules/fs-extra": { 1132 | "version": "10.1.0", 1133 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", 1134 | "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", 1135 | "dev": true, 1136 | "license": "MIT", 1137 | "dependencies": { 1138 | "graceful-fs": "^4.2.0", 1139 | "jsonfile": "^6.0.1", 1140 | "universalify": "^2.0.0" 1141 | }, 1142 | "engines": { 1143 | "node": ">=12" 1144 | } 1145 | }, 1146 | "node_modules/fsevents": { 1147 | "version": "2.3.3", 1148 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1149 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1150 | "dev": true, 1151 | "hasInstallScript": true, 1152 | "license": "MIT", 1153 | "optional": true, 1154 | "os": [ 1155 | "darwin" 1156 | ], 1157 | "engines": { 1158 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1159 | } 1160 | }, 1161 | "node_modules/function-bind": { 1162 | "version": "1.1.2", 1163 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 1164 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 1165 | "dev": true, 1166 | "license": "MIT", 1167 | "funding": { 1168 | "url": "https://github.com/sponsors/ljharb" 1169 | } 1170 | }, 1171 | "node_modules/generic-names": { 1172 | "version": "4.0.0", 1173 | "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-4.0.0.tgz", 1174 | "integrity": "sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==", 1175 | "dev": true, 1176 | "license": "MIT", 1177 | "dependencies": { 1178 | "loader-utils": "^3.2.0" 1179 | } 1180 | }, 1181 | "node_modules/graceful-fs": { 1182 | "version": "4.2.11", 1183 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 1184 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 1185 | "dev": true, 1186 | "license": "ISC" 1187 | }, 1188 | "node_modules/has-flag": { 1189 | "version": "4.0.0", 1190 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1191 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1192 | "dev": true, 1193 | "license": "MIT", 1194 | "engines": { 1195 | "node": ">=8" 1196 | } 1197 | }, 1198 | "node_modules/hasown": { 1199 | "version": "2.0.2", 1200 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 1201 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 1202 | "dev": true, 1203 | "license": "MIT", 1204 | "dependencies": { 1205 | "function-bind": "^1.1.2" 1206 | }, 1207 | "engines": { 1208 | "node": ">= 0.4" 1209 | } 1210 | }, 1211 | "node_modules/icss-replace-symbols": { 1212 | "version": "1.1.0", 1213 | "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", 1214 | "integrity": "sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==", 1215 | "dev": true, 1216 | "license": "ISC" 1217 | }, 1218 | "node_modules/icss-utils": { 1219 | "version": "5.1.0", 1220 | "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", 1221 | "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", 1222 | "dev": true, 1223 | "license": "ISC", 1224 | "engines": { 1225 | "node": "^10 || ^12 || >= 14" 1226 | }, 1227 | "peerDependencies": { 1228 | "postcss": "^8.1.0" 1229 | } 1230 | }, 1231 | "node_modules/import-cwd": { 1232 | "version": "3.0.0", 1233 | "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", 1234 | "integrity": "sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==", 1235 | "dev": true, 1236 | "license": "MIT", 1237 | "dependencies": { 1238 | "import-from": "^3.0.0" 1239 | }, 1240 | "engines": { 1241 | "node": ">=8" 1242 | } 1243 | }, 1244 | "node_modules/import-from": { 1245 | "version": "3.0.0", 1246 | "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", 1247 | "integrity": "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==", 1248 | "dev": true, 1249 | "license": "MIT", 1250 | "dependencies": { 1251 | "resolve-from": "^5.0.0" 1252 | }, 1253 | "engines": { 1254 | "node": ">=8" 1255 | } 1256 | }, 1257 | "node_modules/is-core-module": { 1258 | "version": "2.15.1", 1259 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", 1260 | "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", 1261 | "dev": true, 1262 | "license": "MIT", 1263 | "dependencies": { 1264 | "hasown": "^2.0.2" 1265 | }, 1266 | "engines": { 1267 | "node": ">= 0.4" 1268 | }, 1269 | "funding": { 1270 | "url": "https://github.com/sponsors/ljharb" 1271 | } 1272 | }, 1273 | "node_modules/is-module": { 1274 | "version": "1.0.0", 1275 | "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", 1276 | "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", 1277 | "dev": true, 1278 | "license": "MIT" 1279 | }, 1280 | "node_modules/is-reference": { 1281 | "version": "1.2.1", 1282 | "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", 1283 | "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", 1284 | "dev": true, 1285 | "license": "MIT", 1286 | "dependencies": { 1287 | "@types/estree": "*" 1288 | } 1289 | }, 1290 | "node_modules/jsonfile": { 1291 | "version": "6.1.0", 1292 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", 1293 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", 1294 | "dev": true, 1295 | "license": "MIT", 1296 | "dependencies": { 1297 | "universalify": "^2.0.0" 1298 | }, 1299 | "optionalDependencies": { 1300 | "graceful-fs": "^4.1.6" 1301 | } 1302 | }, 1303 | "node_modules/lilconfig": { 1304 | "version": "2.1.0", 1305 | "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", 1306 | "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", 1307 | "dev": true, 1308 | "license": "MIT", 1309 | "engines": { 1310 | "node": ">=10" 1311 | } 1312 | }, 1313 | "node_modules/loader-utils": { 1314 | "version": "3.3.1", 1315 | "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", 1316 | "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", 1317 | "dev": true, 1318 | "license": "MIT", 1319 | "engines": { 1320 | "node": ">= 12.13.0" 1321 | } 1322 | }, 1323 | "node_modules/locate-path": { 1324 | "version": "5.0.0", 1325 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", 1326 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", 1327 | "dev": true, 1328 | "license": "MIT", 1329 | "dependencies": { 1330 | "p-locate": "^4.1.0" 1331 | }, 1332 | "engines": { 1333 | "node": ">=8" 1334 | } 1335 | }, 1336 | "node_modules/lodash.camelcase": { 1337 | "version": "4.3.0", 1338 | "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", 1339 | "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", 1340 | "dev": true, 1341 | "license": "MIT" 1342 | }, 1343 | "node_modules/lodash.memoize": { 1344 | "version": "4.1.2", 1345 | "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", 1346 | "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", 1347 | "dev": true, 1348 | "license": "MIT" 1349 | }, 1350 | "node_modules/lodash.uniq": { 1351 | "version": "4.5.0", 1352 | "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", 1353 | "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", 1354 | "dev": true, 1355 | "license": "MIT" 1356 | }, 1357 | "node_modules/magic-string": { 1358 | "version": "0.30.14", 1359 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz", 1360 | "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==", 1361 | "dev": true, 1362 | "license": "MIT", 1363 | "dependencies": { 1364 | "@jridgewell/sourcemap-codec": "^1.5.0" 1365 | } 1366 | }, 1367 | "node_modules/make-dir": { 1368 | "version": "3.1.0", 1369 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", 1370 | "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", 1371 | "dev": true, 1372 | "license": "MIT", 1373 | "dependencies": { 1374 | "semver": "^6.0.0" 1375 | }, 1376 | "engines": { 1377 | "node": ">=8" 1378 | }, 1379 | "funding": { 1380 | "url": "https://github.com/sponsors/sindresorhus" 1381 | } 1382 | }, 1383 | "node_modules/make-dir/node_modules/semver": { 1384 | "version": "6.3.1", 1385 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", 1386 | "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", 1387 | "dev": true, 1388 | "license": "ISC", 1389 | "bin": { 1390 | "semver": "bin/semver.js" 1391 | } 1392 | }, 1393 | "node_modules/mdn-data": { 1394 | "version": "2.0.14", 1395 | "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", 1396 | "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", 1397 | "dev": true, 1398 | "license": "CC0-1.0" 1399 | }, 1400 | "node_modules/nanoid": { 1401 | "version": "3.3.8", 1402 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", 1403 | "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", 1404 | "dev": true, 1405 | "funding": [ 1406 | { 1407 | "type": "github", 1408 | "url": "https://github.com/sponsors/ai" 1409 | } 1410 | ], 1411 | "license": "MIT", 1412 | "peer": true, 1413 | "bin": { 1414 | "nanoid": "bin/nanoid.cjs" 1415 | }, 1416 | "engines": { 1417 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 1418 | } 1419 | }, 1420 | "node_modules/node-releases": { 1421 | "version": "2.0.18", 1422 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", 1423 | "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", 1424 | "dev": true, 1425 | "license": "MIT" 1426 | }, 1427 | "node_modules/normalize-url": { 1428 | "version": "6.1.0", 1429 | "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", 1430 | "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", 1431 | "dev": true, 1432 | "license": "MIT", 1433 | "engines": { 1434 | "node": ">=10" 1435 | }, 1436 | "funding": { 1437 | "url": "https://github.com/sponsors/sindresorhus" 1438 | } 1439 | }, 1440 | "node_modules/nth-check": { 1441 | "version": "2.1.1", 1442 | "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", 1443 | "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", 1444 | "dev": true, 1445 | "license": "BSD-2-Clause", 1446 | "dependencies": { 1447 | "boolbase": "^1.0.0" 1448 | }, 1449 | "funding": { 1450 | "url": "https://github.com/fb55/nth-check?sponsor=1" 1451 | } 1452 | }, 1453 | "node_modules/p-finally": { 1454 | "version": "1.0.0", 1455 | "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", 1456 | "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", 1457 | "dev": true, 1458 | "license": "MIT", 1459 | "engines": { 1460 | "node": ">=4" 1461 | } 1462 | }, 1463 | "node_modules/p-limit": { 1464 | "version": "2.3.0", 1465 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 1466 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 1467 | "dev": true, 1468 | "license": "MIT", 1469 | "dependencies": { 1470 | "p-try": "^2.0.0" 1471 | }, 1472 | "engines": { 1473 | "node": ">=6" 1474 | }, 1475 | "funding": { 1476 | "url": "https://github.com/sponsors/sindresorhus" 1477 | } 1478 | }, 1479 | "node_modules/p-locate": { 1480 | "version": "4.1.0", 1481 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", 1482 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", 1483 | "dev": true, 1484 | "license": "MIT", 1485 | "dependencies": { 1486 | "p-limit": "^2.2.0" 1487 | }, 1488 | "engines": { 1489 | "node": ">=8" 1490 | } 1491 | }, 1492 | "node_modules/p-queue": { 1493 | "version": "6.6.2", 1494 | "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", 1495 | "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", 1496 | "dev": true, 1497 | "license": "MIT", 1498 | "dependencies": { 1499 | "eventemitter3": "^4.0.4", 1500 | "p-timeout": "^3.2.0" 1501 | }, 1502 | "engines": { 1503 | "node": ">=8" 1504 | }, 1505 | "funding": { 1506 | "url": "https://github.com/sponsors/sindresorhus" 1507 | } 1508 | }, 1509 | "node_modules/p-timeout": { 1510 | "version": "3.2.0", 1511 | "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", 1512 | "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", 1513 | "dev": true, 1514 | "license": "MIT", 1515 | "dependencies": { 1516 | "p-finally": "^1.0.0" 1517 | }, 1518 | "engines": { 1519 | "node": ">=8" 1520 | } 1521 | }, 1522 | "node_modules/p-try": { 1523 | "version": "2.2.0", 1524 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 1525 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", 1526 | "dev": true, 1527 | "license": "MIT", 1528 | "engines": { 1529 | "node": ">=6" 1530 | } 1531 | }, 1532 | "node_modules/path-exists": { 1533 | "version": "4.0.0", 1534 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 1535 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 1536 | "dev": true, 1537 | "license": "MIT", 1538 | "engines": { 1539 | "node": ">=8" 1540 | } 1541 | }, 1542 | "node_modules/path-parse": { 1543 | "version": "1.0.7", 1544 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 1545 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 1546 | "dev": true, 1547 | "license": "MIT" 1548 | }, 1549 | "node_modules/picocolors": { 1550 | "version": "1.1.1", 1551 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 1552 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 1553 | "dev": true, 1554 | "license": "ISC" 1555 | }, 1556 | "node_modules/picomatch": { 1557 | "version": "2.3.1", 1558 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1559 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1560 | "dev": true, 1561 | "license": "MIT", 1562 | "engines": { 1563 | "node": ">=8.6" 1564 | }, 1565 | "funding": { 1566 | "url": "https://github.com/sponsors/jonschlinkert" 1567 | } 1568 | }, 1569 | "node_modules/pify": { 1570 | "version": "5.0.0", 1571 | "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", 1572 | "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", 1573 | "dev": true, 1574 | "license": "MIT", 1575 | "engines": { 1576 | "node": ">=10" 1577 | }, 1578 | "funding": { 1579 | "url": "https://github.com/sponsors/sindresorhus" 1580 | } 1581 | }, 1582 | "node_modules/pkg-dir": { 1583 | "version": "4.2.0", 1584 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", 1585 | "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", 1586 | "dev": true, 1587 | "license": "MIT", 1588 | "dependencies": { 1589 | "find-up": "^4.0.0" 1590 | }, 1591 | "engines": { 1592 | "node": ">=8" 1593 | } 1594 | }, 1595 | "node_modules/postcss": { 1596 | "version": "8.4.49", 1597 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", 1598 | "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", 1599 | "dev": true, 1600 | "funding": [ 1601 | { 1602 | "type": "opencollective", 1603 | "url": "https://opencollective.com/postcss/" 1604 | }, 1605 | { 1606 | "type": "tidelift", 1607 | "url": "https://tidelift.com/funding/github/npm/postcss" 1608 | }, 1609 | { 1610 | "type": "github", 1611 | "url": "https://github.com/sponsors/ai" 1612 | } 1613 | ], 1614 | "license": "MIT", 1615 | "peer": true, 1616 | "dependencies": { 1617 | "nanoid": "^3.3.7", 1618 | "picocolors": "^1.1.1", 1619 | "source-map-js": "^1.2.1" 1620 | }, 1621 | "engines": { 1622 | "node": "^10 || ^12 || >=14" 1623 | } 1624 | }, 1625 | "node_modules/postcss-calc": { 1626 | "version": "8.2.4", 1627 | "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", 1628 | "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", 1629 | "dev": true, 1630 | "license": "MIT", 1631 | "dependencies": { 1632 | "postcss-selector-parser": "^6.0.9", 1633 | "postcss-value-parser": "^4.2.0" 1634 | }, 1635 | "peerDependencies": { 1636 | "postcss": "^8.2.2" 1637 | } 1638 | }, 1639 | "node_modules/postcss-colormin": { 1640 | "version": "5.3.1", 1641 | "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", 1642 | "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", 1643 | "dev": true, 1644 | "license": "MIT", 1645 | "dependencies": { 1646 | "browserslist": "^4.21.4", 1647 | "caniuse-api": "^3.0.0", 1648 | "colord": "^2.9.1", 1649 | "postcss-value-parser": "^4.2.0" 1650 | }, 1651 | "engines": { 1652 | "node": "^10 || ^12 || >=14.0" 1653 | }, 1654 | "peerDependencies": { 1655 | "postcss": "^8.2.15" 1656 | } 1657 | }, 1658 | "node_modules/postcss-convert-values": { 1659 | "version": "5.1.3", 1660 | "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", 1661 | "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", 1662 | "dev": true, 1663 | "license": "MIT", 1664 | "dependencies": { 1665 | "browserslist": "^4.21.4", 1666 | "postcss-value-parser": "^4.2.0" 1667 | }, 1668 | "engines": { 1669 | "node": "^10 || ^12 || >=14.0" 1670 | }, 1671 | "peerDependencies": { 1672 | "postcss": "^8.2.15" 1673 | } 1674 | }, 1675 | "node_modules/postcss-discard-comments": { 1676 | "version": "5.1.2", 1677 | "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", 1678 | "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", 1679 | "dev": true, 1680 | "license": "MIT", 1681 | "engines": { 1682 | "node": "^10 || ^12 || >=14.0" 1683 | }, 1684 | "peerDependencies": { 1685 | "postcss": "^8.2.15" 1686 | } 1687 | }, 1688 | "node_modules/postcss-discard-duplicates": { 1689 | "version": "5.1.0", 1690 | "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", 1691 | "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", 1692 | "dev": true, 1693 | "license": "MIT", 1694 | "engines": { 1695 | "node": "^10 || ^12 || >=14.0" 1696 | }, 1697 | "peerDependencies": { 1698 | "postcss": "^8.2.15" 1699 | } 1700 | }, 1701 | "node_modules/postcss-discard-empty": { 1702 | "version": "5.1.1", 1703 | "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", 1704 | "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", 1705 | "dev": true, 1706 | "license": "MIT", 1707 | "engines": { 1708 | "node": "^10 || ^12 || >=14.0" 1709 | }, 1710 | "peerDependencies": { 1711 | "postcss": "^8.2.15" 1712 | } 1713 | }, 1714 | "node_modules/postcss-discard-overridden": { 1715 | "version": "5.1.0", 1716 | "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", 1717 | "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", 1718 | "dev": true, 1719 | "license": "MIT", 1720 | "engines": { 1721 | "node": "^10 || ^12 || >=14.0" 1722 | }, 1723 | "peerDependencies": { 1724 | "postcss": "^8.2.15" 1725 | } 1726 | }, 1727 | "node_modules/postcss-load-config": { 1728 | "version": "3.1.4", 1729 | "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", 1730 | "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", 1731 | "dev": true, 1732 | "license": "MIT", 1733 | "dependencies": { 1734 | "lilconfig": "^2.0.5", 1735 | "yaml": "^1.10.2" 1736 | }, 1737 | "engines": { 1738 | "node": ">= 10" 1739 | }, 1740 | "funding": { 1741 | "type": "opencollective", 1742 | "url": "https://opencollective.com/postcss/" 1743 | }, 1744 | "peerDependencies": { 1745 | "postcss": ">=8.0.9", 1746 | "ts-node": ">=9.0.0" 1747 | }, 1748 | "peerDependenciesMeta": { 1749 | "postcss": { 1750 | "optional": true 1751 | }, 1752 | "ts-node": { 1753 | "optional": true 1754 | } 1755 | } 1756 | }, 1757 | "node_modules/postcss-merge-longhand": { 1758 | "version": "5.1.7", 1759 | "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", 1760 | "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", 1761 | "dev": true, 1762 | "license": "MIT", 1763 | "dependencies": { 1764 | "postcss-value-parser": "^4.2.0", 1765 | "stylehacks": "^5.1.1" 1766 | }, 1767 | "engines": { 1768 | "node": "^10 || ^12 || >=14.0" 1769 | }, 1770 | "peerDependencies": { 1771 | "postcss": "^8.2.15" 1772 | } 1773 | }, 1774 | "node_modules/postcss-merge-rules": { 1775 | "version": "5.1.4", 1776 | "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", 1777 | "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", 1778 | "dev": true, 1779 | "license": "MIT", 1780 | "dependencies": { 1781 | "browserslist": "^4.21.4", 1782 | "caniuse-api": "^3.0.0", 1783 | "cssnano-utils": "^3.1.0", 1784 | "postcss-selector-parser": "^6.0.5" 1785 | }, 1786 | "engines": { 1787 | "node": "^10 || ^12 || >=14.0" 1788 | }, 1789 | "peerDependencies": { 1790 | "postcss": "^8.2.15" 1791 | } 1792 | }, 1793 | "node_modules/postcss-minify-font-values": { 1794 | "version": "5.1.0", 1795 | "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", 1796 | "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", 1797 | "dev": true, 1798 | "license": "MIT", 1799 | "dependencies": { 1800 | "postcss-value-parser": "^4.2.0" 1801 | }, 1802 | "engines": { 1803 | "node": "^10 || ^12 || >=14.0" 1804 | }, 1805 | "peerDependencies": { 1806 | "postcss": "^8.2.15" 1807 | } 1808 | }, 1809 | "node_modules/postcss-minify-gradients": { 1810 | "version": "5.1.1", 1811 | "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", 1812 | "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", 1813 | "dev": true, 1814 | "license": "MIT", 1815 | "dependencies": { 1816 | "colord": "^2.9.1", 1817 | "cssnano-utils": "^3.1.0", 1818 | "postcss-value-parser": "^4.2.0" 1819 | }, 1820 | "engines": { 1821 | "node": "^10 || ^12 || >=14.0" 1822 | }, 1823 | "peerDependencies": { 1824 | "postcss": "^8.2.15" 1825 | } 1826 | }, 1827 | "node_modules/postcss-minify-params": { 1828 | "version": "5.1.4", 1829 | "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", 1830 | "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", 1831 | "dev": true, 1832 | "license": "MIT", 1833 | "dependencies": { 1834 | "browserslist": "^4.21.4", 1835 | "cssnano-utils": "^3.1.0", 1836 | "postcss-value-parser": "^4.2.0" 1837 | }, 1838 | "engines": { 1839 | "node": "^10 || ^12 || >=14.0" 1840 | }, 1841 | "peerDependencies": { 1842 | "postcss": "^8.2.15" 1843 | } 1844 | }, 1845 | "node_modules/postcss-minify-selectors": { 1846 | "version": "5.2.1", 1847 | "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", 1848 | "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", 1849 | "dev": true, 1850 | "license": "MIT", 1851 | "dependencies": { 1852 | "postcss-selector-parser": "^6.0.5" 1853 | }, 1854 | "engines": { 1855 | "node": "^10 || ^12 || >=14.0" 1856 | }, 1857 | "peerDependencies": { 1858 | "postcss": "^8.2.15" 1859 | } 1860 | }, 1861 | "node_modules/postcss-modules": { 1862 | "version": "4.3.1", 1863 | "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.3.1.tgz", 1864 | "integrity": "sha512-ItUhSUxBBdNamkT3KzIZwYNNRFKmkJrofvC2nWab3CPKhYBQ1f27XXh1PAPE27Psx58jeelPsxWB/+og+KEH0Q==", 1865 | "dev": true, 1866 | "license": "MIT", 1867 | "dependencies": { 1868 | "generic-names": "^4.0.0", 1869 | "icss-replace-symbols": "^1.1.0", 1870 | "lodash.camelcase": "^4.3.0", 1871 | "postcss-modules-extract-imports": "^3.0.0", 1872 | "postcss-modules-local-by-default": "^4.0.0", 1873 | "postcss-modules-scope": "^3.0.0", 1874 | "postcss-modules-values": "^4.0.0", 1875 | "string-hash": "^1.1.1" 1876 | }, 1877 | "peerDependencies": { 1878 | "postcss": "^8.0.0" 1879 | } 1880 | }, 1881 | "node_modules/postcss-modules-extract-imports": { 1882 | "version": "3.1.0", 1883 | "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", 1884 | "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", 1885 | "dev": true, 1886 | "license": "ISC", 1887 | "engines": { 1888 | "node": "^10 || ^12 || >= 14" 1889 | }, 1890 | "peerDependencies": { 1891 | "postcss": "^8.1.0" 1892 | } 1893 | }, 1894 | "node_modules/postcss-modules-local-by-default": { 1895 | "version": "4.1.0", 1896 | "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.1.0.tgz", 1897 | "integrity": "sha512-rm0bdSv4jC3BDma3s9H19ZddW0aHX6EoqwDYU2IfZhRN+53QrufTRo2IdkAbRqLx4R2IYbZnbjKKxg4VN5oU9Q==", 1898 | "dev": true, 1899 | "license": "MIT", 1900 | "dependencies": { 1901 | "icss-utils": "^5.0.0", 1902 | "postcss-selector-parser": "^7.0.0", 1903 | "postcss-value-parser": "^4.1.0" 1904 | }, 1905 | "engines": { 1906 | "node": "^10 || ^12 || >= 14" 1907 | }, 1908 | "peerDependencies": { 1909 | "postcss": "^8.1.0" 1910 | } 1911 | }, 1912 | "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { 1913 | "version": "7.0.0", 1914 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", 1915 | "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", 1916 | "dev": true, 1917 | "license": "MIT", 1918 | "dependencies": { 1919 | "cssesc": "^3.0.0", 1920 | "util-deprecate": "^1.0.2" 1921 | }, 1922 | "engines": { 1923 | "node": ">=4" 1924 | } 1925 | }, 1926 | "node_modules/postcss-modules-scope": { 1927 | "version": "3.2.1", 1928 | "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", 1929 | "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", 1930 | "dev": true, 1931 | "license": "ISC", 1932 | "dependencies": { 1933 | "postcss-selector-parser": "^7.0.0" 1934 | }, 1935 | "engines": { 1936 | "node": "^10 || ^12 || >= 14" 1937 | }, 1938 | "peerDependencies": { 1939 | "postcss": "^8.1.0" 1940 | } 1941 | }, 1942 | "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { 1943 | "version": "7.0.0", 1944 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", 1945 | "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", 1946 | "dev": true, 1947 | "license": "MIT", 1948 | "dependencies": { 1949 | "cssesc": "^3.0.0", 1950 | "util-deprecate": "^1.0.2" 1951 | }, 1952 | "engines": { 1953 | "node": ">=4" 1954 | } 1955 | }, 1956 | "node_modules/postcss-modules-values": { 1957 | "version": "4.0.0", 1958 | "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", 1959 | "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", 1960 | "dev": true, 1961 | "license": "ISC", 1962 | "dependencies": { 1963 | "icss-utils": "^5.0.0" 1964 | }, 1965 | "engines": { 1966 | "node": "^10 || ^12 || >= 14" 1967 | }, 1968 | "peerDependencies": { 1969 | "postcss": "^8.1.0" 1970 | } 1971 | }, 1972 | "node_modules/postcss-normalize-charset": { 1973 | "version": "5.1.0", 1974 | "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", 1975 | "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", 1976 | "dev": true, 1977 | "license": "MIT", 1978 | "engines": { 1979 | "node": "^10 || ^12 || >=14.0" 1980 | }, 1981 | "peerDependencies": { 1982 | "postcss": "^8.2.15" 1983 | } 1984 | }, 1985 | "node_modules/postcss-normalize-display-values": { 1986 | "version": "5.1.0", 1987 | "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", 1988 | "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", 1989 | "dev": true, 1990 | "license": "MIT", 1991 | "dependencies": { 1992 | "postcss-value-parser": "^4.2.0" 1993 | }, 1994 | "engines": { 1995 | "node": "^10 || ^12 || >=14.0" 1996 | }, 1997 | "peerDependencies": { 1998 | "postcss": "^8.2.15" 1999 | } 2000 | }, 2001 | "node_modules/postcss-normalize-positions": { 2002 | "version": "5.1.1", 2003 | "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", 2004 | "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", 2005 | "dev": true, 2006 | "license": "MIT", 2007 | "dependencies": { 2008 | "postcss-value-parser": "^4.2.0" 2009 | }, 2010 | "engines": { 2011 | "node": "^10 || ^12 || >=14.0" 2012 | }, 2013 | "peerDependencies": { 2014 | "postcss": "^8.2.15" 2015 | } 2016 | }, 2017 | "node_modules/postcss-normalize-repeat-style": { 2018 | "version": "5.1.1", 2019 | "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", 2020 | "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", 2021 | "dev": true, 2022 | "license": "MIT", 2023 | "dependencies": { 2024 | "postcss-value-parser": "^4.2.0" 2025 | }, 2026 | "engines": { 2027 | "node": "^10 || ^12 || >=14.0" 2028 | }, 2029 | "peerDependencies": { 2030 | "postcss": "^8.2.15" 2031 | } 2032 | }, 2033 | "node_modules/postcss-normalize-string": { 2034 | "version": "5.1.0", 2035 | "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", 2036 | "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", 2037 | "dev": true, 2038 | "license": "MIT", 2039 | "dependencies": { 2040 | "postcss-value-parser": "^4.2.0" 2041 | }, 2042 | "engines": { 2043 | "node": "^10 || ^12 || >=14.0" 2044 | }, 2045 | "peerDependencies": { 2046 | "postcss": "^8.2.15" 2047 | } 2048 | }, 2049 | "node_modules/postcss-normalize-timing-functions": { 2050 | "version": "5.1.0", 2051 | "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", 2052 | "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", 2053 | "dev": true, 2054 | "license": "MIT", 2055 | "dependencies": { 2056 | "postcss-value-parser": "^4.2.0" 2057 | }, 2058 | "engines": { 2059 | "node": "^10 || ^12 || >=14.0" 2060 | }, 2061 | "peerDependencies": { 2062 | "postcss": "^8.2.15" 2063 | } 2064 | }, 2065 | "node_modules/postcss-normalize-unicode": { 2066 | "version": "5.1.1", 2067 | "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", 2068 | "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", 2069 | "dev": true, 2070 | "license": "MIT", 2071 | "dependencies": { 2072 | "browserslist": "^4.21.4", 2073 | "postcss-value-parser": "^4.2.0" 2074 | }, 2075 | "engines": { 2076 | "node": "^10 || ^12 || >=14.0" 2077 | }, 2078 | "peerDependencies": { 2079 | "postcss": "^8.2.15" 2080 | } 2081 | }, 2082 | "node_modules/postcss-normalize-url": { 2083 | "version": "5.1.0", 2084 | "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", 2085 | "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", 2086 | "dev": true, 2087 | "license": "MIT", 2088 | "dependencies": { 2089 | "normalize-url": "^6.0.1", 2090 | "postcss-value-parser": "^4.2.0" 2091 | }, 2092 | "engines": { 2093 | "node": "^10 || ^12 || >=14.0" 2094 | }, 2095 | "peerDependencies": { 2096 | "postcss": "^8.2.15" 2097 | } 2098 | }, 2099 | "node_modules/postcss-normalize-whitespace": { 2100 | "version": "5.1.1", 2101 | "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", 2102 | "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", 2103 | "dev": true, 2104 | "license": "MIT", 2105 | "dependencies": { 2106 | "postcss-value-parser": "^4.2.0" 2107 | }, 2108 | "engines": { 2109 | "node": "^10 || ^12 || >=14.0" 2110 | }, 2111 | "peerDependencies": { 2112 | "postcss": "^8.2.15" 2113 | } 2114 | }, 2115 | "node_modules/postcss-ordered-values": { 2116 | "version": "5.1.3", 2117 | "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", 2118 | "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", 2119 | "dev": true, 2120 | "license": "MIT", 2121 | "dependencies": { 2122 | "cssnano-utils": "^3.1.0", 2123 | "postcss-value-parser": "^4.2.0" 2124 | }, 2125 | "engines": { 2126 | "node": "^10 || ^12 || >=14.0" 2127 | }, 2128 | "peerDependencies": { 2129 | "postcss": "^8.2.15" 2130 | } 2131 | }, 2132 | "node_modules/postcss-reduce-initial": { 2133 | "version": "5.1.2", 2134 | "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", 2135 | "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", 2136 | "dev": true, 2137 | "license": "MIT", 2138 | "dependencies": { 2139 | "browserslist": "^4.21.4", 2140 | "caniuse-api": "^3.0.0" 2141 | }, 2142 | "engines": { 2143 | "node": "^10 || ^12 || >=14.0" 2144 | }, 2145 | "peerDependencies": { 2146 | "postcss": "^8.2.15" 2147 | } 2148 | }, 2149 | "node_modules/postcss-reduce-transforms": { 2150 | "version": "5.1.0", 2151 | "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", 2152 | "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", 2153 | "dev": true, 2154 | "license": "MIT", 2155 | "dependencies": { 2156 | "postcss-value-parser": "^4.2.0" 2157 | }, 2158 | "engines": { 2159 | "node": "^10 || ^12 || >=14.0" 2160 | }, 2161 | "peerDependencies": { 2162 | "postcss": "^8.2.15" 2163 | } 2164 | }, 2165 | "node_modules/postcss-selector-parser": { 2166 | "version": "6.1.2", 2167 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", 2168 | "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", 2169 | "dev": true, 2170 | "license": "MIT", 2171 | "dependencies": { 2172 | "cssesc": "^3.0.0", 2173 | "util-deprecate": "^1.0.2" 2174 | }, 2175 | "engines": { 2176 | "node": ">=4" 2177 | } 2178 | }, 2179 | "node_modules/postcss-svgo": { 2180 | "version": "5.1.0", 2181 | "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", 2182 | "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", 2183 | "dev": true, 2184 | "license": "MIT", 2185 | "dependencies": { 2186 | "postcss-value-parser": "^4.2.0", 2187 | "svgo": "^2.7.0" 2188 | }, 2189 | "engines": { 2190 | "node": "^10 || ^12 || >=14.0" 2191 | }, 2192 | "peerDependencies": { 2193 | "postcss": "^8.2.15" 2194 | } 2195 | }, 2196 | "node_modules/postcss-unique-selectors": { 2197 | "version": "5.1.1", 2198 | "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", 2199 | "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", 2200 | "dev": true, 2201 | "license": "MIT", 2202 | "dependencies": { 2203 | "postcss-selector-parser": "^6.0.5" 2204 | }, 2205 | "engines": { 2206 | "node": "^10 || ^12 || >=14.0" 2207 | }, 2208 | "peerDependencies": { 2209 | "postcss": "^8.2.15" 2210 | } 2211 | }, 2212 | "node_modules/postcss-value-parser": { 2213 | "version": "4.2.0", 2214 | "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", 2215 | "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", 2216 | "dev": true, 2217 | "license": "MIT" 2218 | }, 2219 | "node_modules/prettier": { 2220 | "version": "3.4.2", 2221 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", 2222 | "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", 2223 | "dev": true, 2224 | "license": "MIT", 2225 | "bin": { 2226 | "prettier": "bin/prettier.cjs" 2227 | }, 2228 | "engines": { 2229 | "node": ">=14" 2230 | }, 2231 | "funding": { 2232 | "url": "https://github.com/prettier/prettier?sponsor=1" 2233 | } 2234 | }, 2235 | "node_modules/promise.series": { 2236 | "version": "0.2.0", 2237 | "resolved": "https://registry.npmjs.org/promise.series/-/promise.series-0.2.0.tgz", 2238 | "integrity": "sha512-VWQJyU2bcDTgZw8kpfBpB/ejZASlCrzwz5f2hjb/zlujOEB4oeiAhHygAWq8ubsX2GVkD4kCU5V2dwOTaCY5EQ==", 2239 | "dev": true, 2240 | "license": "MIT", 2241 | "engines": { 2242 | "node": ">=0.12" 2243 | } 2244 | }, 2245 | "node_modules/randombytes": { 2246 | "version": "2.1.0", 2247 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 2248 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 2249 | "dev": true, 2250 | "license": "MIT", 2251 | "dependencies": { 2252 | "safe-buffer": "^5.1.0" 2253 | } 2254 | }, 2255 | "node_modules/resolve": { 2256 | "version": "1.22.8", 2257 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", 2258 | "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", 2259 | "dev": true, 2260 | "license": "MIT", 2261 | "dependencies": { 2262 | "is-core-module": "^2.13.0", 2263 | "path-parse": "^1.0.7", 2264 | "supports-preserve-symlinks-flag": "^1.0.0" 2265 | }, 2266 | "bin": { 2267 | "resolve": "bin/resolve" 2268 | }, 2269 | "funding": { 2270 | "url": "https://github.com/sponsors/ljharb" 2271 | } 2272 | }, 2273 | "node_modules/resolve-from": { 2274 | "version": "5.0.0", 2275 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", 2276 | "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", 2277 | "dev": true, 2278 | "license": "MIT", 2279 | "engines": { 2280 | "node": ">=8" 2281 | } 2282 | }, 2283 | "node_modules/rollup": { 2284 | "version": "4.28.1", 2285 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.28.1.tgz", 2286 | "integrity": "sha512-61fXYl/qNVinKmGSTHAZ6Yy8I3YIJC/r2m9feHo6SwVAVcLT5MPwOUFe7EuURA/4m0NR8lXG4BBXuo/IZEsjMg==", 2287 | "dev": true, 2288 | "license": "MIT", 2289 | "dependencies": { 2290 | "@types/estree": "1.0.6" 2291 | }, 2292 | "bin": { 2293 | "rollup": "dist/bin/rollup" 2294 | }, 2295 | "engines": { 2296 | "node": ">=18.0.0", 2297 | "npm": ">=8.0.0" 2298 | }, 2299 | "optionalDependencies": { 2300 | "@rollup/rollup-android-arm-eabi": "4.28.1", 2301 | "@rollup/rollup-android-arm64": "4.28.1", 2302 | "@rollup/rollup-darwin-arm64": "4.28.1", 2303 | "@rollup/rollup-darwin-x64": "4.28.1", 2304 | "@rollup/rollup-freebsd-arm64": "4.28.1", 2305 | "@rollup/rollup-freebsd-x64": "4.28.1", 2306 | "@rollup/rollup-linux-arm-gnueabihf": "4.28.1", 2307 | "@rollup/rollup-linux-arm-musleabihf": "4.28.1", 2308 | "@rollup/rollup-linux-arm64-gnu": "4.28.1", 2309 | "@rollup/rollup-linux-arm64-musl": "4.28.1", 2310 | "@rollup/rollup-linux-loongarch64-gnu": "4.28.1", 2311 | "@rollup/rollup-linux-powerpc64le-gnu": "4.28.1", 2312 | "@rollup/rollup-linux-riscv64-gnu": "4.28.1", 2313 | "@rollup/rollup-linux-s390x-gnu": "4.28.1", 2314 | "@rollup/rollup-linux-x64-gnu": "4.28.1", 2315 | "@rollup/rollup-linux-x64-musl": "4.28.1", 2316 | "@rollup/rollup-win32-arm64-msvc": "4.28.1", 2317 | "@rollup/rollup-win32-ia32-msvc": "4.28.1", 2318 | "@rollup/rollup-win32-x64-msvc": "4.28.1", 2319 | "fsevents": "~2.3.2" 2320 | } 2321 | }, 2322 | "node_modules/rollup-plugin-postcss": { 2323 | "version": "4.0.2", 2324 | "resolved": "https://registry.npmjs.org/rollup-plugin-postcss/-/rollup-plugin-postcss-4.0.2.tgz", 2325 | "integrity": "sha512-05EaY6zvZdmvPUDi3uCcAQoESDcYnv8ogJJQRp6V5kZ6J6P7uAVJlrTZcaaA20wTH527YTnKfkAoPxWI/jPp4w==", 2326 | "dev": true, 2327 | "license": "MIT", 2328 | "dependencies": { 2329 | "chalk": "^4.1.0", 2330 | "concat-with-sourcemaps": "^1.1.0", 2331 | "cssnano": "^5.0.1", 2332 | "import-cwd": "^3.0.0", 2333 | "p-queue": "^6.6.2", 2334 | "pify": "^5.0.0", 2335 | "postcss-load-config": "^3.0.0", 2336 | "postcss-modules": "^4.0.0", 2337 | "promise.series": "^0.2.0", 2338 | "resolve": "^1.19.0", 2339 | "rollup-pluginutils": "^2.8.2", 2340 | "safe-identifier": "^0.4.2", 2341 | "style-inject": "^0.3.0" 2342 | }, 2343 | "engines": { 2344 | "node": ">=10" 2345 | }, 2346 | "peerDependencies": { 2347 | "postcss": "8.x" 2348 | } 2349 | }, 2350 | "node_modules/rollup-plugin-typescript2": { 2351 | "version": "0.36.0", 2352 | "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.36.0.tgz", 2353 | "integrity": "sha512-NB2CSQDxSe9+Oe2ahZbf+B4bh7pHwjV5L+RSYpCu7Q5ROuN94F9b6ioWwKfz3ueL3KTtmX4o2MUH2cgHDIEUsw==", 2354 | "dev": true, 2355 | "license": "MIT", 2356 | "dependencies": { 2357 | "@rollup/pluginutils": "^4.1.2", 2358 | "find-cache-dir": "^3.3.2", 2359 | "fs-extra": "^10.0.0", 2360 | "semver": "^7.5.4", 2361 | "tslib": "^2.6.2" 2362 | }, 2363 | "peerDependencies": { 2364 | "rollup": ">=1.26.3", 2365 | "typescript": ">=2.4.0" 2366 | } 2367 | }, 2368 | "node_modules/rollup-pluginutils": { 2369 | "version": "2.8.2", 2370 | "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", 2371 | "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", 2372 | "dev": true, 2373 | "license": "MIT", 2374 | "dependencies": { 2375 | "estree-walker": "^0.6.1" 2376 | } 2377 | }, 2378 | "node_modules/rollup-pluginutils/node_modules/estree-walker": { 2379 | "version": "0.6.1", 2380 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", 2381 | "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", 2382 | "dev": true, 2383 | "license": "MIT" 2384 | }, 2385 | "node_modules/safe-buffer": { 2386 | "version": "5.2.1", 2387 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 2388 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 2389 | "dev": true, 2390 | "funding": [ 2391 | { 2392 | "type": "github", 2393 | "url": "https://github.com/sponsors/feross" 2394 | }, 2395 | { 2396 | "type": "patreon", 2397 | "url": "https://www.patreon.com/feross" 2398 | }, 2399 | { 2400 | "type": "consulting", 2401 | "url": "https://feross.org/support" 2402 | } 2403 | ], 2404 | "license": "MIT" 2405 | }, 2406 | "node_modules/safe-identifier": { 2407 | "version": "0.4.2", 2408 | "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz", 2409 | "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==", 2410 | "dev": true, 2411 | "license": "ISC" 2412 | }, 2413 | "node_modules/semver": { 2414 | "version": "7.6.3", 2415 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", 2416 | "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", 2417 | "dev": true, 2418 | "license": "ISC", 2419 | "bin": { 2420 | "semver": "bin/semver.js" 2421 | }, 2422 | "engines": { 2423 | "node": ">=10" 2424 | } 2425 | }, 2426 | "node_modules/serialize-javascript": { 2427 | "version": "6.0.2", 2428 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", 2429 | "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", 2430 | "dev": true, 2431 | "license": "BSD-3-Clause", 2432 | "dependencies": { 2433 | "randombytes": "^2.1.0" 2434 | } 2435 | }, 2436 | "node_modules/smob": { 2437 | "version": "1.5.0", 2438 | "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", 2439 | "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", 2440 | "dev": true, 2441 | "license": "MIT" 2442 | }, 2443 | "node_modules/source-map": { 2444 | "version": "0.6.1", 2445 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 2446 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 2447 | "dev": true, 2448 | "license": "BSD-3-Clause", 2449 | "engines": { 2450 | "node": ">=0.10.0" 2451 | } 2452 | }, 2453 | "node_modules/source-map-js": { 2454 | "version": "1.2.1", 2455 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 2456 | "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 2457 | "dev": true, 2458 | "license": "BSD-3-Clause", 2459 | "peer": true, 2460 | "engines": { 2461 | "node": ">=0.10.0" 2462 | } 2463 | }, 2464 | "node_modules/source-map-support": { 2465 | "version": "0.5.21", 2466 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 2467 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 2468 | "dev": true, 2469 | "license": "MIT", 2470 | "dependencies": { 2471 | "buffer-from": "^1.0.0", 2472 | "source-map": "^0.6.0" 2473 | } 2474 | }, 2475 | "node_modules/stable": { 2476 | "version": "0.1.8", 2477 | "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", 2478 | "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", 2479 | "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", 2480 | "dev": true, 2481 | "license": "MIT" 2482 | }, 2483 | "node_modules/string-hash": { 2484 | "version": "1.1.3", 2485 | "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", 2486 | "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==", 2487 | "dev": true, 2488 | "license": "CC0-1.0" 2489 | }, 2490 | "node_modules/style-inject": { 2491 | "version": "0.3.0", 2492 | "resolved": "https://registry.npmjs.org/style-inject/-/style-inject-0.3.0.tgz", 2493 | "integrity": "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==", 2494 | "dev": true, 2495 | "license": "MIT" 2496 | }, 2497 | "node_modules/stylehacks": { 2498 | "version": "5.1.1", 2499 | "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", 2500 | "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", 2501 | "dev": true, 2502 | "license": "MIT", 2503 | "dependencies": { 2504 | "browserslist": "^4.21.4", 2505 | "postcss-selector-parser": "^6.0.4" 2506 | }, 2507 | "engines": { 2508 | "node": "^10 || ^12 || >=14.0" 2509 | }, 2510 | "peerDependencies": { 2511 | "postcss": "^8.2.15" 2512 | } 2513 | }, 2514 | "node_modules/supports-color": { 2515 | "version": "7.2.0", 2516 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 2517 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 2518 | "dev": true, 2519 | "license": "MIT", 2520 | "dependencies": { 2521 | "has-flag": "^4.0.0" 2522 | }, 2523 | "engines": { 2524 | "node": ">=8" 2525 | } 2526 | }, 2527 | "node_modules/supports-preserve-symlinks-flag": { 2528 | "version": "1.0.0", 2529 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 2530 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 2531 | "dev": true, 2532 | "license": "MIT", 2533 | "engines": { 2534 | "node": ">= 0.4" 2535 | }, 2536 | "funding": { 2537 | "url": "https://github.com/sponsors/ljharb" 2538 | } 2539 | }, 2540 | "node_modules/svgo": { 2541 | "version": "2.8.0", 2542 | "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", 2543 | "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", 2544 | "dev": true, 2545 | "license": "MIT", 2546 | "dependencies": { 2547 | "@trysound/sax": "0.2.0", 2548 | "commander": "^7.2.0", 2549 | "css-select": "^4.1.3", 2550 | "css-tree": "^1.1.3", 2551 | "csso": "^4.2.0", 2552 | "picocolors": "^1.0.0", 2553 | "stable": "^0.1.8" 2554 | }, 2555 | "bin": { 2556 | "svgo": "bin/svgo" 2557 | }, 2558 | "engines": { 2559 | "node": ">=10.13.0" 2560 | } 2561 | }, 2562 | "node_modules/svgo/node_modules/commander": { 2563 | "version": "7.2.0", 2564 | "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", 2565 | "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", 2566 | "dev": true, 2567 | "license": "MIT", 2568 | "engines": { 2569 | "node": ">= 10" 2570 | } 2571 | }, 2572 | "node_modules/terser": { 2573 | "version": "5.37.0", 2574 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", 2575 | "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", 2576 | "dev": true, 2577 | "license": "BSD-2-Clause", 2578 | "dependencies": { 2579 | "@jridgewell/source-map": "^0.3.3", 2580 | "acorn": "^8.8.2", 2581 | "commander": "^2.20.0", 2582 | "source-map-support": "~0.5.20" 2583 | }, 2584 | "bin": { 2585 | "terser": "bin/terser" 2586 | }, 2587 | "engines": { 2588 | "node": ">=10" 2589 | } 2590 | }, 2591 | "node_modules/tslib": { 2592 | "version": "2.8.1", 2593 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", 2594 | "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", 2595 | "dev": true, 2596 | "license": "0BSD" 2597 | }, 2598 | "node_modules/typescript": { 2599 | "version": "5.7.2", 2600 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", 2601 | "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", 2602 | "dev": true, 2603 | "license": "Apache-2.0", 2604 | "bin": { 2605 | "tsc": "bin/tsc", 2606 | "tsserver": "bin/tsserver" 2607 | }, 2608 | "engines": { 2609 | "node": ">=14.17" 2610 | } 2611 | }, 2612 | "node_modules/universalify": { 2613 | "version": "2.0.1", 2614 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", 2615 | "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", 2616 | "dev": true, 2617 | "license": "MIT", 2618 | "engines": { 2619 | "node": ">= 10.0.0" 2620 | } 2621 | }, 2622 | "node_modules/update-browserslist-db": { 2623 | "version": "1.1.1", 2624 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", 2625 | "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", 2626 | "dev": true, 2627 | "funding": [ 2628 | { 2629 | "type": "opencollective", 2630 | "url": "https://opencollective.com/browserslist" 2631 | }, 2632 | { 2633 | "type": "tidelift", 2634 | "url": "https://tidelift.com/funding/github/npm/browserslist" 2635 | }, 2636 | { 2637 | "type": "github", 2638 | "url": "https://github.com/sponsors/ai" 2639 | } 2640 | ], 2641 | "license": "MIT", 2642 | "dependencies": { 2643 | "escalade": "^3.2.0", 2644 | "picocolors": "^1.1.0" 2645 | }, 2646 | "bin": { 2647 | "update-browserslist-db": "cli.js" 2648 | }, 2649 | "peerDependencies": { 2650 | "browserslist": ">= 4.21.0" 2651 | } 2652 | }, 2653 | "node_modules/util-deprecate": { 2654 | "version": "1.0.2", 2655 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 2656 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 2657 | "dev": true, 2658 | "license": "MIT" 2659 | }, 2660 | "node_modules/yaml": { 2661 | "version": "1.10.2", 2662 | "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", 2663 | "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", 2664 | "dev": true, 2665 | "license": "ISC", 2666 | "engines": { 2667 | "node": ">= 6" 2668 | } 2669 | } 2670 | } 2671 | } 2672 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rajnandan1/termo", 3 | "version": "0.0.1", 4 | "description": "A terminal emulator for the web", 5 | "type": "module", 6 | "main": "dist/termo.min.js", 7 | "module": "dist/termo.esm.js", 8 | "types": "dist/index.d.ts", 9 | "files": [ 10 | "dist" 11 | ], 12 | "exports": { 13 | ".": { 14 | "types": "./dist/index.d.ts", 15 | "import": "./dist/termo.esm.js", 16 | "require": "./dist/termo.min.js" 17 | } 18 | }, 19 | "scripts": { 20 | "clean": "rm -rf dist", 21 | "build:types": "tsc --emitDeclarationOnly", 22 | "build": "npm run clean && npm run build:types && rollup --bundleConfigAsCjs -c rollup.config.js", 23 | "watch": "rollup --bundleConfigAsCjs -c rollup.config.js --watch", 24 | "prettify": "prettier --write ." 25 | }, 26 | "keywords": [ 27 | "termo" 28 | ], 29 | "author": "Raj Nandan Sharma (https://www.rajnandan.com)", 30 | "license": "MIT", 31 | "devDependencies": { 32 | "@rollup/plugin-commonjs": "^28.0.1", 33 | "@rollup/plugin-json": "^6.1.0", 34 | "@rollup/plugin-node-resolve": "^15.3.0", 35 | "@rollup/plugin-terser": "^0.4.4", 36 | "@types/xterm": "^2.0.3", 37 | "@xterm/addon-fit": "^0.10.0", 38 | "@xterm/addon-web-links": "^0.11.0", 39 | "@xterm/xterm": "^5.5.0", 40 | "prettier": "^3.2.5", 41 | "rollup": "^4.18.0", 42 | "rollup-plugin-postcss": "^4.0.2", 43 | "rollup-plugin-typescript2": "^0.36.0", 44 | "tslib": "^2.6.2", 45 | "typescript": "^5.4.5" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from 'rollup-plugin-typescript2'; 2 | import terser from '@rollup/plugin-terser'; 3 | import resolve from '@rollup/plugin-node-resolve'; 4 | import commonjs from '@rollup/plugin-commonjs'; 5 | import json from '@rollup/plugin-json'; 6 | 7 | export default { 8 | input: 'src/index.ts', 9 | output: [ 10 | { 11 | file: 'dist/termo.min.js', 12 | name: 'termo', 13 | format: 'umd', 14 | sourcemap: true, 15 | plugins: [terser()], 16 | }, 17 | { 18 | file: 'dist/termo.cjs.js', 19 | format: 'cjs', 20 | sourcemap: true, 21 | }, 22 | { 23 | file: 'dist/termo.esm.js', 24 | format: 'es', 25 | sourcemap: true, 26 | }, 27 | ], 28 | external: [], 29 | plugins: [ 30 | resolve({ 31 | browser: true, 32 | preferBuiltins: false, 33 | }), 34 | commonjs(), 35 | 36 | typescript({ 37 | tsconfig: './tsconfig.json', 38 | clean: true, 39 | }), 40 | json(), 41 | ], 42 | }; 43 | -------------------------------------------------------------------------------- /sounds/run_command.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rajnandan1/termo/93d0d757ce55228814941f90897eb81ab3ed9697/sounds/run_command.mp3 -------------------------------------------------------------------------------- /sounds/terminal_close.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rajnandan1/termo/93d0d757ce55228814941f90897eb81ab3ed9697/sounds/terminal_close.mp3 -------------------------------------------------------------------------------- /sounds/terminal_open.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rajnandan1/termo/93d0d757ce55228814941f90897eb81ab3ed9697/sounds/terminal_open.mp3 -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | const constants = { 2 | SOUND_TERMINAL_OPEN: 'https://stripe.dev/audio/terminal_open.mp3', 3 | SOUND_TERMINAL_CLOSE: 'https://stripe.dev/audio/terminal_close.mp3', 4 | SOUND_RUN_CMD: 'https://stripe.dev/audio/run_command.mp3', 5 | }; 6 | export default constants; 7 | -------------------------------------------------------------------------------- /src/dom.ts: -------------------------------------------------------------------------------- 1 | const DOM = { 2 | createDiv(id: string, cls: string): HTMLDivElement { 3 | const div = document.createElement('div'); 4 | div.id = id; 5 | div.className = cls; 6 | return div; 7 | }, 8 | addCss(div: HTMLDivElement, css: string): void { 9 | div.style.cssText = css; 10 | }, 11 | appendChild(parent: HTMLElement, child: HTMLElement): void { 12 | parent.appendChild(child); 13 | }, 14 | injectStylesheet(id: string, styleSheet: string): void { 15 | //check if stylesheet is already injected 16 | if (document.querySelector('#' + id)) { 17 | return; 18 | } 19 | const style = document.createElement('style'); 20 | style.id = id; 21 | style.innerHTML = styleSheet; 22 | document.head.appendChild(style); 23 | }, 24 | }; 25 | 26 | export default DOM; 27 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { InitOptions } from './interfaces'; 2 | import { close, dock, pop } from './svgs'; 3 | import DOM from './dom'; 4 | import Utils from './utils'; 5 | import Sounds from './sounds'; 6 | import Stylesheet from './stylesheet'; 7 | import TerminalManager from './terminal'; 8 | 9 | /** 10 | * @class Termo 11 | * @property {InitOptions} options - The initialization options for the terminal. 12 | * @property {'floating' | 'docked'} mode - The current mode of the terminal (floating or docked). 13 | * @property {'minimized' | 'open' | 'destroyed' | 'initiated'} state - The current state of the terminal. 14 | * @property {HTMLDivElement | undefined} container - The container element for the terminal. 15 | * @property {TerminalManager | undefined} terminalManager - The terminal manager instance. 16 | */ 17 | class Termo { 18 | options: InitOptions; 19 | mode: 'floating' | 'docked'; 20 | state: 'minimized' | 'open' | 'destroyed' | 'initiated'; 21 | container: HTMLDivElement | undefined; 22 | terminalManager: TerminalManager | undefined; 23 | 24 | //define constructor arguments 25 | 26 | constructor(options: InitOptions) { 27 | if (!!!options.title) { 28 | throw new Error('title is required'); 29 | } 30 | options.id = Utils.titleID(options.title); 31 | this.options = Utils.getInitOptions(options); 32 | this.mode = 'floating'; 33 | this.state = 'initiated'; 34 | this.container = undefined; 35 | } 36 | 37 | /** 38 | * Creates a new terminal instance with the specified options. 39 | * 40 | * This method initializes the terminal container, header, and various control buttons 41 | * (resize, close). It also sets up event listeners for these buttons to handle terminal 42 | * resizing and closing actions. The terminal is appended to the document body and made 43 | * draggable. 44 | * 45 | * @throws {Error} If a terminal with the same title already exists. 46 | */ 47 | create() { 48 | //define show method 49 | let containerID = `termo-${this.options.id}-container`; 50 | 51 | let existingContainer = document.querySelector(`#${containerID}`); 52 | if (existingContainer) { 53 | throw new Error('Terminal with the same title already exists'); 54 | } 55 | const styleSheet = Stylesheet(this.options); 56 | DOM.injectStylesheet(this.options.id, styleSheet); 57 | 58 | this.container = DOM.createDiv(containerID, 'termo-container'); 59 | this.container.setAttribute('mode', this.mode); 60 | 61 | let headerID = Utils.generateId('termo-header'); 62 | let header = DOM.createDiv(headerID, 'termo-header'); 63 | if (this.options.theme === 'dark') { 64 | this.container.classList.add('darker'); 65 | } 66 | 67 | let resizeButton = DOM.createDiv(Utils.generateId('termo-resize-button'), 'termo-resize-button'); 68 | resizeButton.innerHTML = dock; 69 | DOM.appendChild(header, resizeButton); 70 | resizeButton.addEventListener('click', () => { 71 | if (this.container) { 72 | this.container.style.removeProperty('left'); 73 | this.container.style.removeProperty('top'); 74 | 75 | if (this.mode == 'floating') { 76 | this.dock(); 77 | this.mode = 'docked'; 78 | resizeButton.innerHTML = pop; 79 | } else { 80 | this.float(); 81 | this.mode = 'floating'; 82 | resizeButton.innerHTML = dock; 83 | } 84 | //terminalManager.terminal.focus(); 85 | } 86 | }); 87 | 88 | let titleDiv = DOM.createDiv(Utils.generateId('termo-title'), 'termo-title'); 89 | titleDiv.innerHTML = this.options.title; 90 | DOM.appendChild(header, titleDiv); 91 | 92 | let closeButton = DOM.createDiv(Utils.generateId('termo-close-button'), 'termo-close-button'); 93 | closeButton.innerHTML = close; 94 | DOM.appendChild(header, closeButton); 95 | //add a click event to close the terminal 96 | closeButton.addEventListener('click', () => { 97 | this.hide(); 98 | }); 99 | 100 | // Append the header to the container 101 | DOM.appendChild(this.container, header); 102 | 103 | let terminalID = Utils.generateId('termo-terminal'); 104 | let terminal = DOM.createDiv(terminalID, 'termo-terminal'); 105 | DOM.appendChild(this.container, terminal); 106 | this.container.style.transform = 'scale(0)'; 107 | DOM.appendChild(document.body, this.container); 108 | Utils.containerDraggable(this.container, header); 109 | this.container.style.bottom = '12px'; 110 | this.container.style.right = '12px'; 111 | 112 | this.terminalManager = new TerminalManager(terminal, this.options); 113 | this.state = 'minimized'; 114 | } 115 | 116 | /** 117 | * Adjusts the dimensions and position of the container element to float it 118 | * at a specific size and position on the screen. If the container element 119 | * is not available, an error is thrown. 120 | * 121 | * @throws {Error} If the container element is not created. 122 | */ 123 | float() { 124 | if (this.container) { 125 | this.container.style.width = '705px'; 126 | this.container.style.height = '482px'; 127 | this.container.style.right = '12px'; 128 | this.container.style.bottom = '12px'; 129 | this.container.setAttribute('mode', 'floating'); 130 | this.terminalManager?.resize(); 131 | } else { 132 | throw new Error('Terminal not created'); 133 | } 134 | } 135 | 136 | /** 137 | * Adjusts the dimensions and position of the terminal container to dock it 138 | * at the bottom right corner of the viewport. 139 | * 140 | * @throws {Error} Throws an error if the terminal container is not created. 141 | */ 142 | dock() { 143 | if (this.container) { 144 | this.container.style.height = '300px'; 145 | this.container.style.width = '100vw'; 146 | this.container.style.right = '0px'; 147 | this.container.style.bottom = '0px'; 148 | this.container.setAttribute('mode', 'docked'); 149 | this.terminalManager?.resize(); 150 | } else { 151 | throw new Error('Terminal not created'); 152 | } 153 | } 154 | /** 155 | * Hides the terminal by scaling down its container element. 156 | * If the container exists, it plays the terminal close sound, 157 | * scales the container to zero, and updates the state to 'minimized'. 158 | * If the container does not exist, it throws an error. 159 | * 160 | * @throws {Error} If the terminal container is not created. 161 | */ 162 | hide() { 163 | if (this.container) { 164 | Sounds.terminalClose(this.options); 165 | this.container.style.transform = 'scale(0)'; 166 | this.state = 'minimized'; 167 | } else { 168 | throw new Error('Terminal not created'); 169 | } 170 | } 171 | /** 172 | * Displays the terminal by applying a scale transformation to the container element. 173 | * If the container exists, it plays the terminal open sound, sets the state to 'open', 174 | * and focuses the terminal. If the container does not exist, it throws an error. 175 | * 176 | * @throws {Error} If the terminal container is not created. 177 | */ 178 | show() { 179 | if (this.container) { 180 | Sounds.terminalOpen(this.options); 181 | this.container.style.transform = 'scale(1)'; 182 | this.state = 'open'; 183 | this.terminalManager?.terminal.focus(); 184 | } else { 185 | throw new Error('Terminal not created'); 186 | } 187 | } 188 | 189 | /** 190 | * Sets the theme of the terminal. 191 | * 192 | * @param theme - The theme to set, either 'dark' or 'light'. 193 | * @throws Will throw an error if the terminal container is not created. 194 | */ 195 | setTheme(theme: 'dark' | 'light') { 196 | if (this.container) { 197 | if (theme === 'dark') { 198 | this.container.classList.add('darker'); 199 | } else { 200 | this.container.classList.remove('darker'); 201 | } 202 | } else { 203 | throw new Error('Terminal not created'); 204 | } 205 | } 206 | 207 | /** 208 | * Destroys the terminal instance by performing the following actions: 209 | * - If the container exists: 210 | * - Destroys the terminal manager. 211 | * - Removes the container element from the document body. 212 | * - Removes the associated stylesheet from the document head. 213 | * - Sets the container to undefined. 214 | * - Deletes the terminal manager. 215 | * - Updates the state to 'destroyed'. 216 | * - Sets the mode to 'floating'. 217 | * - If the container does not exist, throws an error indicating that the terminal was not created. 218 | * 219 | * @throws {Error} If the terminal was not created. 220 | */ 221 | destroy() { 222 | if (this.container) { 223 | this.terminalManager?.destroy(); 224 | document.body.removeChild(this.container); 225 | //remove the stylesheet also 226 | document.head.removeChild(document.getElementById(this.options.id) as HTMLStyleElement); 227 | this.container = undefined; 228 | delete this.terminalManager; 229 | this.state = 'destroyed'; 230 | this.mode = 'floating'; 231 | } else { 232 | throw new Error('Terminal not created'); 233 | } 234 | } 235 | } 236 | 237 | export default Termo; 238 | -------------------------------------------------------------------------------- /src/interfaces.ts: -------------------------------------------------------------------------------- 1 | import { ITerminalOptions, Terminal } from '@xterm/xterm'; 2 | 3 | /** 4 | * Options for initializing the terminal. 5 | */ 6 | export interface InitOptions { 7 | /** 8 | * The welcome message displayed when the terminal starts. 9 | */ 10 | welcomeMessage: string; 11 | 12 | /** 13 | * The list of commands available in the terminal. 14 | */ 15 | commands: Command[]; 16 | 17 | /** 18 | * Configuration options for the terminal. 19 | */ 20 | terminalOptions: ITerminalOptions; 21 | 22 | /** 23 | * The theme of the terminal. 24 | */ 25 | theme: string; 26 | 27 | /** 28 | * Whether to play a sound on certain actions. 29 | */ 30 | playSound: boolean; 31 | 32 | /** 33 | * The title of the terminal window. 34 | */ 35 | title: string; 36 | 37 | /** 38 | * The font family used in the terminal. 39 | */ 40 | fontFamily: string; 41 | 42 | /** 43 | * The unique identifier for the terminal instance. 44 | */ 45 | id: string; 46 | 47 | /** 48 | * The prompt string displayed in the terminal. 49 | */ 50 | prompt: string; 51 | } 52 | 53 | export interface Command { 54 | command: string; 55 | description: string; 56 | action: (terminal: Terminal, args: string[]) => Promise; 57 | subCommands?: Command[]; 58 | } 59 | 60 | export interface TerminalManagerReturn { 61 | terminal: Terminal; 62 | destroy: () => void; 63 | } 64 | -------------------------------------------------------------------------------- /src/sounds.ts: -------------------------------------------------------------------------------- 1 | import { InitOptions } from './interfaces'; 2 | let soundTerminalOpen: HTMLAudioElement | undefined, 3 | soundTerminalClose: HTMLAudioElement | undefined, 4 | soundRunCommand: HTMLAudioElement | undefined; 5 | 6 | soundTerminalOpen = undefined; 7 | soundTerminalClose = undefined; 8 | soundRunCommand = undefined; 9 | 10 | export default { 11 | terminalOpen: function (opts: InitOptions) { 12 | let { playSound } = opts; 13 | if (!playSound) { 14 | return; 15 | } 16 | 17 | if (soundTerminalOpen === undefined) { 18 | soundTerminalOpen = new Audio( 19 | 'https://raw.githubusercontent.com/rajnandan1/termo/main/sounds/terminal_open.mp3', 20 | ); 21 | soundTerminalOpen.preload = 'auto'; 22 | } 23 | soundTerminalOpen.play().catch((error) => console.error('Error playing audio:', error)); 24 | }, 25 | terminalClose: function (opts: InitOptions) { 26 | let { playSound } = opts; 27 | if (!playSound) { 28 | return; 29 | } 30 | 31 | if (soundTerminalClose === undefined) { 32 | soundTerminalClose = new Audio( 33 | 'https://raw.githubusercontent.com/rajnandan1/termo/main/sounds/terminal_close.mp3', 34 | ); 35 | soundTerminalClose.preload = 'auto'; 36 | } 37 | 38 | soundTerminalClose.play().catch((error) => console.error('Error playing audio:', error)); 39 | }, 40 | runCommand: function (opts: InitOptions) { 41 | let { playSound } = opts; 42 | if (!playSound) { 43 | return; 44 | } 45 | if (soundRunCommand === undefined) { 46 | soundRunCommand = new Audio( 47 | 'https://raw.githubusercontent.com/rajnandan1/termo/main/sounds/run_command.mp3', 48 | ); 49 | soundRunCommand.preload = 'auto'; 50 | } 51 | 52 | soundRunCommand.play().catch((error) => console.error('Error playing audio:', error)); 53 | }, 54 | }; 55 | -------------------------------------------------------------------------------- /src/stylesheet.ts: -------------------------------------------------------------------------------- 1 | import { InitOptions } from './interfaces'; 2 | const xtermCSS = ` 3 | .xterm { 4 | cursor: text; 5 | padding: 10px; 6 | position: relative; 7 | user-select: none; 8 | -ms-user-select: none; 9 | -webkit-user-select: none; 10 | } 11 | 12 | .xterm.focus, 13 | .xterm:focus { 14 | outline: none; 15 | } 16 | 17 | .xterm .xterm-helpers { 18 | position: absolute; 19 | top: 0; 20 | /** 21 | * The z-index of the helpers must be higher than the canvases in order for 22 | * IMEs to appear on top. 23 | */ 24 | z-index: 5; 25 | } 26 | 27 | .xterm .xterm-helper-textarea { 28 | padding: 0; 29 | border: 0; 30 | margin: 0; 31 | /* Move textarea out of the screen to the far left, so that the cursor is not visible */ 32 | position: absolute; 33 | opacity: 0; 34 | left: -9999em; 35 | top: 0; 36 | width: 0; 37 | height: 0; 38 | z-index: -5; 39 | /** Prevent wrapping so the IME appears against the textarea at the correct position */ 40 | white-space: nowrap; 41 | overflow: hidden; 42 | resize: none; 43 | } 44 | 45 | .xterm .composition-view { 46 | /* TODO: Composition position got messed up somewhere */ 47 | background: transparent; 48 | color: #FFF; 49 | display: none; 50 | position: absolute; 51 | white-space: nowrap; 52 | z-index: 1; 53 | } 54 | 55 | .xterm .composition-view.active { 56 | display: block; 57 | } 58 | 59 | .xterm .xterm-viewport { 60 | /* On OS X this is required in order for the scroll bar to appear fully opaque */ 61 | background-color: transparent; 62 | overflow-y: scroll; 63 | cursor: default; 64 | position: absolute; 65 | right: 0; 66 | left: 0; 67 | top: 0; 68 | bottom: 0; 69 | } 70 | 71 | .xterm .xterm-screen { 72 | position: relative; 73 | } 74 | 75 | .xterm .xterm-screen canvas { 76 | position: absolute; 77 | left: 0; 78 | top: 0; 79 | } 80 | 81 | .xterm .xterm-scroll-area { 82 | visibility: hidden; 83 | } 84 | 85 | .xterm-char-measure-element { 86 | display: inline-block; 87 | visibility: hidden; 88 | position: absolute; 89 | top: 0; 90 | left: -9999em; 91 | line-height: normal; 92 | } 93 | 94 | .xterm.enable-mouse-events { 95 | /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ 96 | cursor: default; 97 | } 98 | 99 | .xterm.xterm-cursor-pointer, 100 | .xterm .xterm-cursor-pointer { 101 | cursor: pointer; 102 | } 103 | 104 | .xterm.column-select.focus { 105 | /* Column selection mode */ 106 | cursor: crosshair; 107 | } 108 | 109 | .xterm .xterm-accessibility, 110 | .xterm .xterm-message { 111 | position: absolute; 112 | left: 0; 113 | top: 0; 114 | bottom: 0; 115 | right: 0; 116 | z-index: 10; 117 | color: transparent; 118 | } 119 | 120 | .xterm .live-region { 121 | position: absolute; 122 | left: -9999px; 123 | width: 1px; 124 | height: 1px; 125 | overflow: hidden; 126 | } 127 | 128 | .xterm-dim { 129 | opacity: 0.5; 130 | } 131 | 132 | .xterm-underline { 133 | text-decoration: underline; 134 | } 135 | 136 | .xterm-strikethrough { 137 | text-decoration: line-through; 138 | } 139 | 140 | .xterm-screen .xterm-decoration-container .xterm-decoration { 141 | z-index: 6; 142 | position: absolute; 143 | } 144 | 145 | .xterm-decoration-overview-ruler { 146 | z-index: 7; 147 | position: absolute; 148 | top: 0; 149 | right: 0; 150 | pointer-events: none; 151 | } 152 | 153 | .xterm-decoration-top { 154 | z-index: 2; 155 | position: relative; 156 | } 157 | `; 158 | 159 | const Stylesheet = ` 160 | 161 | 162 | #termo-{{titleID}}-container{ 163 | box-sizing: border-box; 164 | font-family: {{fontFamily}}; 165 | position: fixed; 166 | bottom: 12px; 167 | right: 12px; 168 | border: 1px solid #011627; 169 | width: 705px; 170 | max-width: 100vw; 171 | height: 482px; 172 | padding: 8px 4px 4px; 173 | gap: 8px; 174 | display: flex; 175 | flex-direction: column; 176 | z-index: 2147483647; 177 | transition: transform 0.3s ease, width 0.3s ease, height 0.3s ease; 178 | background: rgba(255, 255, 255, 0.2); 179 | box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1); 180 | backdrop-filter: blur(5px); 181 | -webkit-backdrop-filter: blur(5px); 182 | 183 | } 184 | .termo-container *{ 185 | font-family: {{fontFamily}}; 186 | box-sizing: border-box; 187 | } 188 | 189 | .termo-header{ 190 | display: flex; 191 | justify-content: space-between; 192 | line-height: 1; 193 | cursor: grab; 194 | padding: 1px 4px; 195 | font-size: 14px; 196 | font-weight: 500; 197 | font-family: monospace; 198 | text-transform: uppercase; 199 | user-select: none; 200 | color: #011627; 201 | 202 | .termo-close-button{ 203 | cursor: pointer; 204 | } 205 | .termo-resize-button{ 206 | cursor: pointer; 207 | } 208 | } 209 | [mode="docked"] .termo-header{ 210 | cursor: pointer; 211 | } 212 | .darker .termo-header{ 213 | color: #fefefe; 214 | } 215 | .termo-container .termo-terminal{ 216 | background-color: transparent; 217 | border: 1px solid transparent; 218 | border-radius: 4px; 219 | padding: 0px; 220 | flex-grow: 1; 221 | overflow: auto; 222 | background: #1e1e1e; 223 | } 224 | 225 | ${xtermCSS} 226 | 227 | 228 | `; 229 | 230 | export default function (opts: InitOptions) { 231 | let fontFamily = opts.fontFamily; 232 | let titleID = opts.id; 233 | let newStyle = Stylesheet.replace(/{{fontFamily}}/g, fontFamily); 234 | newStyle = newStyle.replace(/{{titleID}}/g, titleID); 235 | return newStyle; 236 | } 237 | -------------------------------------------------------------------------------- /src/svgs.ts: -------------------------------------------------------------------------------- 1 | export const close = ` 2 | 3 | `; 4 | 5 | export const dock = ` 6 | Align window to bottom 7 | `; 8 | 9 | export const pop = ` 10 | Float window in corner 11 | `; 12 | -------------------------------------------------------------------------------- /src/terminal.ts: -------------------------------------------------------------------------------- 1 | import { ITerminalOptions, Terminal } from '@xterm/xterm'; 2 | import { FitAddon } from '@xterm/addon-fit'; 3 | import { WebLinksAddon } from '@xterm/addon-web-links'; 4 | import { InitOptions, Command } from './interfaces'; 5 | import Sounds from './sounds'; 6 | 7 | class TerminalManager { 8 | terminalOptions: ITerminalOptions; 9 | terminal: Terminal; 10 | fitAddon: FitAddon; 11 | webLinksAddon: WebLinksAddon; 12 | userCommands: Command[]; 13 | commandHistory: any; 14 | historyIndex: number; 15 | inputBuffer: string; 16 | opts: InitOptions; 17 | 18 | constructor(div: HTMLElement, optsReceived: InitOptions) { 19 | this.opts = { ...optsReceived }; 20 | 21 | this.terminalOptions = this.opts.terminalOptions; 22 | this.terminal = new Terminal(this.terminalOptions); 23 | this.fitAddon = new FitAddon(); 24 | this.webLinksAddon = new WebLinksAddon(); 25 | this.terminal.open(div); 26 | this.terminal.loadAddon(this.fitAddon); 27 | this.terminal.loadAddon(this.webLinksAddon); 28 | this.fitAddon.fit(); 29 | 30 | this.userCommands = this.opts.commands; 31 | 32 | //create help command 33 | this.userCommands.push({ 34 | command: 'help', 35 | description: 'List all commands', 36 | action: async (terminal) => { 37 | terminal.write(`\r\nCommands:\r\n`); 38 | this.userCommands.forEach((cmd) => { 39 | terminal.write(` ${cmd.command} - ${cmd.description}\r\n`); 40 | }); 41 | }, 42 | }); 43 | // Create clear command 44 | this.userCommands.push({ 45 | command: 'clear', 46 | description: 'Clear the terminal screen', 47 | action: async (terminal) => { 48 | terminal.write('\x1b[2J'); // Clear screen 49 | terminal.write('\x1b[H'); // Move cursor to home position 50 | }, 51 | }); 52 | 53 | this.commandHistory = []; 54 | this.historyIndex = -1; 55 | this.inputBuffer = ''; 56 | 57 | // Add color codes 58 | const GREEN = '\x1b[32m'; 59 | const RESET = '\x1b[0m'; 60 | const prompt = `${GREEN}${this.opts.prompt}${RESET} `; 61 | 62 | if (!!this.opts.welcomeMessage) { 63 | this.terminal.write('\x1b[3m'); 64 | this.terminal.write(this.opts.welcomeMessage); 65 | this.terminal.write('\x1b[0m'); 66 | this.terminal.write('\r\n'); 67 | } 68 | 69 | this.terminal.write('-'.repeat(this.terminal.cols)); 70 | this.terminal.write('\r\n'); 71 | this.terminal.write("Type 'help' to list all available commands"); 72 | this.terminal.write('\r\n'); 73 | this.terminal.write('-'.repeat(this.terminal.cols)); 74 | 75 | this.terminal.write(`\r\n${prompt}`); 76 | 77 | this.terminal.onData(async (data) => { 78 | const key = data.charCodeAt(0); 79 | 80 | // Handle Ctrl+C 81 | if (key === 3) { 82 | this.inputBuffer = ''; 83 | this.historyIndex = -1; 84 | this.terminal.write('^C'); 85 | this.terminal.write(`\r\n${prompt}`); 86 | return; 87 | } 88 | 89 | // Handle up arrow (27 91 65) 90 | if (data === '\x1b[A') { 91 | if (this.historyIndex < this.commandHistory.length - 1) { 92 | this.historyIndex++; 93 | // Clear current line 94 | this.terminal.write('\x1b[2K\r'); 95 | this.terminal.write(`${prompt}`); 96 | // Show command from history 97 | this.inputBuffer = this.commandHistory[this.commandHistory.length - 1 - this.historyIndex]; 98 | this.terminal.write(this.inputBuffer); 99 | } 100 | return; 101 | } 102 | 103 | // Handle down arrow (27 91 66) 104 | if (data === '\x1b[B') { 105 | if (this.historyIndex > 0) { 106 | this.historyIndex--; 107 | this.terminal.write('\x1b[2K\r'); 108 | this.terminal.write(`${prompt}`); 109 | this.inputBuffer = this.commandHistory[this.commandHistory.length - 1 - this.historyIndex]; 110 | this.terminal.write(this.inputBuffer); 111 | } else if (this.historyIndex === 0) { 112 | this.historyIndex = -1; 113 | this.terminal.write('\x1b[2K\r'); 114 | this.terminal.write(`${prompt}`); 115 | this.inputBuffer = ''; 116 | } 117 | return; 118 | } 119 | 120 | // Handle Enter 121 | if (data === '\r') { 122 | if (this.inputBuffer.length > 0) { 123 | this.commandHistory.push(this.inputBuffer); 124 | this.historyIndex = -1; 125 | } else { 126 | this.terminal.write(`\r\n${prompt}`); 127 | return; 128 | } 129 | Sounds.runCommand(this.opts); 130 | if (this.inputBuffer.trim() === 'clear') { 131 | // Clear screen and scroll buffer 132 | this.terminal.write('\x1b[2J'); // Clear screen 133 | this.terminal.write('\x1b[H'); // Move cursor to home position 134 | this.terminal.write(`${prompt}`); // New prompt 135 | this.inputBuffer = ''; 136 | return; 137 | } 138 | 139 | //find command 140 | let cmd = this.userCommands.find((c) => c.command === this.inputBuffer.split(' ')[0]); 141 | if (cmd) { 142 | //has subcommands, then show the usage of the commands if no subcommand is provided 143 | if (cmd.subCommands) { 144 | if (this.inputBuffer.split(' ').length === 1) { 145 | this.terminal.write(`\r\nUsage: ${cmd.command} `); 146 | this.terminal.write(`\r\nSubcommands:\r\n`); 147 | cmd.subCommands.forEach((subCmd: Command) => { 148 | this.terminal.write(` ${subCmd.command} - ${subCmd.description}\r\n`); 149 | }); 150 | } else { 151 | let subCmd = cmd.subCommands.find((c) => c.command === this.inputBuffer.split(' ')[1]); 152 | if (subCmd) { 153 | subCmd.action(this.terminal, this.inputBuffer.split(' ').slice(2)); 154 | } else { 155 | this.terminal.write( 156 | `\r\nSubcommand not found: ${this.inputBuffer.split(' ')[1]}. Type 'help' to list all available commands. And this is some text`, 157 | ); 158 | } 159 | } 160 | } else { 161 | await cmd.action(this.terminal, this.inputBuffer.split(' ').slice(1)); 162 | } 163 | } else { 164 | this.terminal.write( 165 | `\r\nCommand not found: ${this.inputBuffer}. Type 'help' to list all available commands`, 166 | ); 167 | } 168 | 169 | this.inputBuffer = ''; 170 | this.terminal.write(`\r\n${prompt}`); 171 | 172 | return; 173 | } 174 | 175 | // Handle backspace 176 | if (data === '\x7f') { 177 | if (this.inputBuffer.length > 0) { 178 | this.inputBuffer = this.inputBuffer.slice(0, -1); 179 | this.terminal.write('\b \b'); 180 | } 181 | return; 182 | } 183 | 184 | // Add character to buffer and echo 185 | this.inputBuffer += data; 186 | this.terminal.write(data); 187 | }); 188 | } 189 | 190 | destroy() { 191 | // Dispose addons 192 | this.fitAddon.dispose(); 193 | this.webLinksAddon.dispose(); 194 | 195 | // Dispose terminal 196 | this.terminal.dispose(); 197 | 198 | // // Clear any references 199 | this.userCommands = []; 200 | this.inputBuffer = ''; 201 | this.commandHistory = []; 202 | } 203 | 204 | focus() { 205 | this.terminal.focus(); 206 | } 207 | resize() { 208 | setTimeout(() => { 209 | this.fitAddon.fit(); 210 | }, 310); 211 | } 212 | } 213 | 214 | export default TerminalManager; 215 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { InitOptions } from './interfaces'; 2 | import * as packageInfo from '../package.json'; 3 | const Utils = { 4 | // Function to generate random string for id 5 | generateId(prefix: string): string { 6 | return prefix + '-' + Math.random().toString(36).substring(2); 7 | }, 8 | containerDraggable(container: HTMLElement, header: HTMLElement) { 9 | let isDown = false; 10 | let startX: number; 11 | let startY: number; 12 | let offsetX: number; 13 | let offsetY: number; 14 | 15 | header.addEventListener('mousedown', (e) => { 16 | isDown = true; 17 | startX = e.clientX; 18 | startY = e.clientY; 19 | offsetX = container.offsetLeft; 20 | offsetY = container.offsetTop; 21 | document.addEventListener('mousemove', onMouseMove); 22 | document.addEventListener('mouseup', onMouseUp); 23 | }); 24 | 25 | const onMouseMove = (e: MouseEvent) => { 26 | if (!isDown || container.getAttribute('mode') == 'docked') return; 27 | e.preventDefault(); 28 | const x = e.clientX - startX; 29 | const y = e.clientY - startY; 30 | container.style.left = offsetX + x + 'px'; 31 | container.style.top = offsetY + y + 'px'; 32 | // Calculate position from right and bottom edges 33 | container.style.right = `${window.innerWidth - (offsetX + x)}px`; 34 | container.style.bottom = `${window.innerHeight - (offsetY + y)}px`; 35 | }; 36 | 37 | const onMouseUp = () => { 38 | isDown = false; 39 | document.removeEventListener('mousemove', onMouseMove); 40 | document.removeEventListener('mouseup', onMouseUp); 41 | }; 42 | }, 43 | //given an element, return top,left given it should be at bottom:12, right:12 44 | getBottomRightPosition(): { top: number; left: number } { 45 | return { 46 | top: window.innerHeight - 490 - 12, 47 | left: window.innerWidth - 705 - 12, 48 | }; 49 | }, 50 | playAudio(filePath: string) { 51 | const audio = new Audio(filePath); 52 | audio.play(); 53 | }, 54 | getInitOptions(opts: InitOptions): InitOptions { 55 | const defaultOptions: InitOptions = { 56 | playSound: true, 57 | title: 'termo', 58 | welcomeMessage: `Welcome to termo v${packageInfo.version}!`, 59 | theme: 'light', 60 | id: 'termo', 61 | fontFamily: 'Courier New, monospace', 62 | prompt: '$', 63 | commands: [ 64 | { 65 | command: 'joke', 66 | description: 'Hear a random joke from a random API', 67 | action: (terminal) => { 68 | terminal.write('\r\n' + 'Thinking of a joke...'); 69 | return new Promise(async (resolve) => { 70 | try { 71 | const response = await fetch('https://official-joke-api.appspot.com/random_joke'); 72 | const data = await response.json(); 73 | terminal.write('\r\n' + data.setup); 74 | setTimeout(() => { 75 | resolve(terminal.write('\r\n' + data.punchline)); 76 | }, 2000); 77 | } catch (error) { 78 | terminal.write('\r\nFailed to fetch joke'); 79 | } 80 | }); 81 | }, 82 | }, 83 | ], 84 | terminalOptions: { 85 | cursorBlink: true, 86 | fontSize: 14, 87 | theme: { 88 | background: '#1e1e1e', 89 | foreground: '#fefefe', 90 | cursor: '#ffffff', 91 | }, 92 | fontFamily: 'Courier New, monospace', 93 | fontWeight: 'normal', 94 | lineHeight: 1.2, 95 | allowTransparency: true, 96 | }, 97 | }; 98 | const mergedOptions = { ...defaultOptions, ...opts }; 99 | return mergedOptions; 100 | }, 101 | 102 | titleID(title: string): string { 103 | //md5 hash the title 104 | return btoa(title).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); 105 | }, 106 | }; 107 | 108 | export default Utils; 109 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: 'Sono', monospace; 3 | } 4 | 5 | .squares-pattern { 6 | position: absolute; 7 | top: 0; 8 | left: 0; 9 | width: 100%; 10 | z-index: 0; 11 | background-repeat: no-repeat; 12 | background-size: 100%; 13 | height: 100svh; 14 | clip-path: polygon(0 0, 100% 0, 100% 54%, 0% 100%); 15 | transform: blur(3px); 16 | } 17 | 18 | .squares-pattern::after { 19 | content: ''; 20 | position: absolute; 21 | background-image: linear-gradient(#444cf7 1px, transparent 1px), linear-gradient(to right, #444cf7 1px, #fbfbfb 1px); 22 | 23 | mask-image: linear-gradient( 24 | 180deg, 25 | rgba(0, 0, 0, 0.2) 0%, 26 | rgba(0, 0, 0, 0.1) 20%, 27 | rgba(0, 0, 0, 0.05) 40%, 28 | rgba(0, 0, 0, 0.025) 60%, 29 | rgba(0, 0, 0, 0.0125) 80%, 30 | rgba(0, 0, 0, 0) 100% 31 | ); 32 | background-size: 32px 32px; 33 | width: 100%; 34 | height: 100vh; 35 | top: 0; 36 | left: 0; 37 | } 38 | [data-bs-theme='dark'] .squares-pattern::after { 39 | background-image: linear-gradient(#47e76c 1px, transparent 1px), linear-gradient(to right, #47e76c 1px, #000000 1px); 40 | } 41 | .blur-card { 42 | border-radius: 100%/85%; 43 | background-color: rgba(255, 255, 255, 0.75); 44 | box-shadow: 0 0 64px 64px rgba(255, 255, 255, 0.75); 45 | } 46 | [data-bs-theme='dark'] .blur-card { 47 | background-color: rgba(34, 37, 41, 0.75); 48 | box-shadow: 0 0 64px 64px rgba(34, 37, 41, 0.75); 49 | } 50 | 51 | /* CSS */ 52 | .button-68 { 53 | appearance: none; 54 | backface-visibility: hidden; 55 | background-color: #27ae60; 56 | border-radius: 8px; 57 | border-style: none; 58 | box-shadow: rgba(39, 174, 96, 0.15) 0 4px 9px; 59 | box-sizing: border-box; 60 | color: #fff; 61 | cursor: pointer; 62 | display: inline-block; 63 | 64 | font-size: 16px; 65 | font-weight: 600; 66 | letter-spacing: normal; 67 | line-height: 1.5; 68 | outline: none; 69 | overflow: hidden; 70 | padding: 13px 20px; 71 | position: relative; 72 | text-align: center; 73 | text-decoration: none; 74 | transform: translate3d(0, 0, 0); 75 | transition: all 0.3s; 76 | user-select: none; 77 | -webkit-user-select: none; 78 | touch-action: manipulation; 79 | vertical-align: top; 80 | white-space: nowrap; 81 | } 82 | 83 | .button-68:hover { 84 | background-color: #1e8449; 85 | opacity: 1; 86 | transform: translateY(0); 87 | transition-duration: 0.35s; 88 | } 89 | 90 | .button-68:active { 91 | transform: translateY(2px); 92 | transition-duration: 0.35s; 93 | } 94 | 95 | .button-68:hover { 96 | box-shadow: rgba(39, 174, 96, 0.2) 0 6px 12px; 97 | } 98 | .button-68.gh { 99 | background-color: #292c33; 100 | box-shadow: none; 101 | } 102 | -------------------------------------------------------------------------------- /terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rajnandan1/termo/93d0d757ce55228814941f90897eb81ab3ed9697/terminal.png -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "ES2018" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 15 | "lib": [ 16 | "DOM", 17 | "DOM.Iterable", 18 | "ESNext" 19 | ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, 20 | "jsx": "react" /* Specify what JSX code is generated. */, 21 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 22 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 23 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 24 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 25 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 26 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 27 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 28 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 29 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 30 | 31 | /* Modules */ 32 | "module": "ESNext" /* Specify what module code is generated. */, 33 | "rootDir": "./src" /* Specify source root */, 34 | "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, 35 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 36 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 37 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 38 | "typeRoots": ["./node_modules/@types"] /* Specify multiple folders that act like './node_modules/@types'. */, 39 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 40 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 41 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 42 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 43 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 44 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 45 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 46 | "resolveJsonModule": true /* Enable importing .json files. */, 47 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 48 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 49 | 50 | /* JavaScript Support */ 51 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 52 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 53 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 54 | 55 | /* Emit */ 56 | "declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */, 57 | "declarationDir": "./dist/types" /* Specify the output directory for generated declaration files. */, 58 | "declarationMap": true /* Create sourcemaps for d.ts files. */, 59 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 60 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 61 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 62 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 63 | "outDir": "./dist" /* Specify an output folder for all emitted files. */, 64 | // "removeComments": true, /* Disable emitting comments. */ 65 | // "noEmit": true, /* Disable emitting files from a compilation. */ 66 | // "importHelpers": true /* Allow importing helper functions from tslib once per project, instead of including them per-file. */, 67 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 68 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 69 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 70 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 71 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 72 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 73 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 74 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 75 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 76 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 77 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 78 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 79 | 80 | /* Interop Constraints */ 81 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 82 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 83 | "allowSyntheticDefaultImports": true /* Allow 'import x from y' when a module doesn't have a default export. */, 84 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, 85 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 86 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 87 | 88 | /* Type Checking */ 89 | "strict": true /* Enable all strict type-checking options. */, 90 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 91 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 92 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 93 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 94 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 95 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 96 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 97 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 98 | "noUnusedLocals": true /* Enable error reporting when local variables aren't read. */, 99 | "noUnusedParameters": true /* Raise an error when a function parameter isn't read. */, 100 | "noImplicitReturns": true /* Enable error reporting for codepaths that do not explicitly return in a function. */, 101 | "noFallthroughCasesInSwitch": true /* Enable error reporting for fallthrough cases in switch statements. */, 102 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 103 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 104 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 105 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 106 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 107 | 108 | /* Completeness */ 109 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 110 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 111 | }, 112 | "include": ["src/**/*"], 113 | "exclude": ["node_modules", "dist", "**/*.test.ts"] 114 | } 115 | --------------------------------------------------------------------------------