diff --git a/README.md b/README.md index 630bd3d..71a35e4 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,51 @@ -# nw-splasher +# NW-Splasher + Small library to show a splash screen until main application loads. + +The splash screen will run in a separate process so any animations will play smoothly while the app is loading. + + +* * * + + +## Demo + +Here is a demo projec that uses the `nw-splasher.js` and `nw-splasher.css` files: + +* https://github.com/nwutils/nw-splash-screen-example + + +* * * + + +## Usage + +1. `npm install --save nw-splasher` +1. Create a `splash.html` file and an `index.html` file (for your app) + * Add this line to the `
` of both files. + * `` +1. In `package.json` set `"main": "splash.html"` +1. In the `splash.html` run `nwSplasher.loadAppWindowInBackground()` +1. In the `index.html` run `nwSplasher.closeSplashAndShowApp()` after the app is done loading and ready to be displayed + + +## API + +`nwSplasher.loadAppWindowInBackground(url, newWindowOptions, port)` + +Used by your Splash screen window. This creates a websocket and spawns your main app in a hidden window. Then waits for the app to send a signal to the websocket to close the splash screen. + +Argument | Optional | Type | Description | Defaults +:-- | :-- | :-- | :-- | :-- +`url` | yes | String | URL to load in the App window. | Defaults to `index.html`, `default.html`, `main.html`, or `app.html` if those files exist, or the first html file it finds in the current directory. Console logs if no html file found. +`newWindowOptions` | yes | Object | Object with the [NW.js Window Subfields](http://docs.nwjs.io/en/latest/References/Manifest%20Format/#window-subfields). | `show` is always set to `false`. `new_instance` is always set to `true`. +`port` | yes | Number | If you pass in a number it must match the same port number passed in the app window. | Defaults to 4443. + + +`nwSplasher.closeSplashAndShowApp(port)` + +Call this from your App window when it is ready to be shown. This will also trigger closing the Splash screen window. + +Argument | Optional | Type | Description | Defaults +:-- | :-- | :-- | :-- | :-- +`port` | yes | Number | If you pass in a number it must match the same port number passed in the splash window. | Defaults to 4443. diff --git a/nw-splasher.css b/nw-splasher.css new file mode 100644 index 0000000..9c4a212 --- /dev/null +++ b/nw-splasher.css @@ -0,0 +1,61 @@ +html, +body, +.wrapper { + height: 100%; + box-sizing: border-box; +} + +body { + background: transparent; + border: 4px solid #222; + border-radius: 20px; + margin: 0px; + padding: 00px; + color: #DEDEDE; + font-family: sans-serif; + text-align: center; +} + +.wrapper { + background: linear-gradient(300deg, hsla(0, 0%, 18%, 1), hsla(0, 0%, 22%, 0.3)); + border-radius: 10px; + padding: 20px; +} + +.drag-enable { + -webkit-app-region: drag; +} + +.drag-disable { + -webkit-app-region: no-drag; +} + +.close { + position: absolute; + top: 3px; + right: 12px; + font-size: 30px; + cursor: pointer; +} + +@keyframes spin { + 0% { + transform: rotateZ(0deg); + } + 45% { + background-color: rgba(168, 225, 136, 0.95) + } + 100% { + transform: rotateZ(719deg); + } +} + +.spinner { + display: block; + width: 100px; + height: 100px; + background: rgba(168, 180, 136, 0.95); + border-radius: 10px; + margin: 50px auto; + animation: spin 4s ease 0s infinite normal; +} diff --git a/nw-splasher.js b/nw-splasher.js new file mode 100644 index 0000000..c03fa91 --- /dev/null +++ b/nw-splasher.js @@ -0,0 +1,125 @@ +const nwSplasher = { + º: '%c', + consoleNormal: 'font-family: sans-serif', + consoleBold: '' + + 'font-family: sans-serif' + + 'font-weight: bold', + consoleCode: '' + + 'background: #EEEEF6;' + + 'border: 1px solid #B2B0C1;' + + 'border-radius: 7px;' + + 'padding: 2px 8px 3px;' + + 'color: #5F5F5F;' + + 'line-height: 22px;' + + 'box-shadow: 0px 0px 1px 1px rgba(178,176,193,0.3)', + validateUrl: function (url) { + if (typeof(url) === 'string') { + return url; + } + let fs = require('fs'); + files = fs.readdirSync('.'); + files = files.filter(function (file) { + return file.endsWith('.html') + }); + + if (files.length) { + url = files[0]; + } + + const defaults = [ + 'app.html', + 'main.html', + 'default.html', + 'index.html', + ]; + + defaults.forEach(function (possibleFile) { + if (files.includes(possibleFile)) { + url = possibleFile; + } + }); + if (url) { + return url; + } + return false; + }, + validateNewWindowOptions: function (newWindowOptions) { + if (!newWindowOptions || typeof(newWindowOptions) !== 'object' || Array.isArray(newWindowOptions)) { + newWindowOptions = {}; + } + + // Needs to be a new instance so splash screen animations play smoothly + newWindowOptions.new_instance = true; + // hide the app window until it signals it is done loading + newWindowOptions.show = false; + + return newWindowOptions; + }, + validatePort: function (port) { + if (typeof(port) !== 'number') { + port = 4443; + } + return port; + }, + /** + * Used by your Splash screen window. This creates a websocket and spawns + * your main app in a hidden window. Then waits for the app to send a signal + * to the websocket to close the splash screen. + * + * All params are optional. + * + * @param {string} url URL to load in the App window. Defaults to index.html, default.html, main.html, or app.html if those files exist, or the first html file it finds. + * @param {object} newWindowOptions Object with the NW.js Window fields (height, width, frameless, etc) + * @param {number} port Defaults to 1337, must match the same port number used in the app window + * @return {undefined} Returns nothing, just executes + */ + loadAppWindowInBackground: function (url, newWindowOptions, port) { + url = this.validateUrl(url); + newWindowOptions = this.validateNewWindowOptions(newWindowOptions); + port = this.validatePort(port); + + if (!url) { + console.log(this.º + 'NW-Splasher: Could not find a valid path to load your app window.\n' + + 'Pass in url or filename to load in the app Window.', this.consoleNormal); + console.log(this.º + 'Example:', this.consoleBold); + console.log(this.º + 'nwSplasher.loadAppInBackground(\'index.html\');', this.consoleCode); + return; + } + + const net = require('net'); + const server = net.createServer(function (socket) { + socket.write('Echo server'); + socket.pipe(socket); + + // Handle incoming messages app window + socket.on('data', function (data) { + if (data.toString() === 'loaded') { + server.close(); + nw.Window.get().close(true); + } + }); + }); + + server.listen(port, 'localhost'); + + // Launch hidden app window and wait for it to signal to close the splasher window + nw.Window.open(url, newWindowOptions); + }, + /** + * Call this from your App window when it is ready to be shown. + * This will also trigger closing the Splash screen window. + * + * @param {number} port Optional port number, defaults to 1337. Must match port number used in Splash window + * @return {undefined} Nothing is returned, this just runs a command. + */ + closeSplashAndShowApp: function (port) { + port = this.validatePort(port); + + const net = require('net'); + const client = new net.Socket(); + client.connect(port, 'localhost'); + + client.write('loaded'); + nw.Window.get().show(); + } +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..cdb5a67 --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "nw-splasher", + "version": "1.0.0", + "description": "Small library to show a splash screen until main application loads.", + "main": "nw-splasher.js", + "repository": { + "type": "git", + "url": "git+https://github.com/nwutils/nw-splasher.git" + }, + "keywords": [ + "NW.js", + "Splash screen", + "loading" + ], + "author": "", + "license": "MIT", + "bugs": { + "url": "https://github.com/nwutils/nw-splasher/issues" + }, + "homepage": "https://github.com/nwutils/nw-splasher#readme" +}