diff --git a/app/index.pug b/app/index.pug index 7cad0401..9913d713 100644 --- a/app/index.pug +++ b/app/index.pug @@ -10,3 +10,25 @@ html script(src='./bundle.js', defer) body(style='background: ; min-height: 100vh; overflow: hidden') app-root + .preload-logo + div + .terminus-logo.animated + .part(style='transform: rotateZ(0deg)') + div + .part(style='transform: rotateZ(51deg)') + div + .part(style='transform: rotateZ(102deg)') + div + .part(style='transform: rotateZ(154deg)') + div + .part(style='transform: rotateZ(205deg)') + div + .part(style='transform: rotateZ(257deg)') + div + .part(style='transform: rotateZ(308deg)') + div + h1.terminus-title Terminus + .progress + .bar(style='width: 50%') + + diff --git a/app/main.js b/app/main.js index 78de3ddc..88b8ec13 100644 --- a/app/main.js +++ b/app/main.js @@ -23,6 +23,12 @@ require('electron-debug')({enabled: true, showDevTools: process.argv.indexOf('-- let windowConfig = new Config({name: 'window'}) +if (!process.env.TERMINUS_PLUGINS) { + process.env.TERMINUS_PLUGINS = '' +} + +process.env.TERMINUS_PLUGINS += `:${path.resolve(__dirname, '..')}` + setupWindowManagement = () => { let windowCloseable @@ -144,7 +150,7 @@ start = () => { minHeight: 100, 'web-preferences': {'web-security': false}, //- background to avoid the flash of unstyled window - backgroundColor: '#1D272D', + backgroundColor: '#131d27', frame: false, //type: 'toolbar', } @@ -161,7 +167,7 @@ start = () => { app.commandLine.appendSwitch('disable-http-cache') app.window = new electron.BrowserWindow(options) - app.window.loadURL(`file://${app.getAppPath()}/assets/webpack/index.html`, {extraHeaders: "pragma: no-cache\n"}) + app.window.loadURL(`file://${app.getAppPath()}/dist/index.html`, {extraHeaders: "pragma: no-cache\n"}) if (platform != 'darwin') { app.window.setMenu(null) diff --git a/app/src/app.module.ts b/app/src/app.module.ts index 4e93e41a..57bd36d7 100644 --- a/app/src/app.module.ts +++ b/app/src/app.module.ts @@ -1,10 +1,8 @@ import { NgModule } from '@angular/core' import { BrowserModule } from '@angular/platform-browser' import { NgbModule } from '@ng-bootstrap/ng-bootstrap' -import { loadPlugins } from './plugins' -export async function getRootModule(): Promise { - let plugins = await loadPlugins() +export async function getRootModule(plugins: any[]): Promise { let imports = [ BrowserModule, ...(plugins.map(x => x.default.forRoot ? x.default.forRoot() : x.default)), diff --git a/app/src/entry.preload.ts b/app/src/entry.preload.ts index 52f7cb2b..358467d9 100644 --- a/app/src/entry.preload.ts +++ b/app/src/entry.preload.ts @@ -1,2 +1,3 @@ import 'source-sans-pro' import 'font-awesome/css/font-awesome.css' +import './preload.scss' diff --git a/app/src/entry.ts b/app/src/entry.ts index a0936e1b..fe0c9f24 100644 --- a/app/src/entry.ts +++ b/app/src/entry.ts @@ -8,16 +8,21 @@ import 'rxjs' // Always land on the start view location.hash = '' -import { getRootModule } from './app.module' import { enableProdMode } from '@angular/core' import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' +import { getRootModule } from './app.module' +import { loadPlugins } from './plugins' + if ((global).require('electron-is-dev')) { console.warn('Running in debug mode') } else { enableProdMode() } -getRootModule().then(module => { +loadPlugins((current, total) => { + document.querySelector('.progress .bar').style.width = 100 * current / total + '%' +}).then(async plugins => { + let module = await getRootModule(plugins) platformBrowserDynamic().bootstrapModule(module) }) diff --git a/app/src/plugins.ts b/app/src/plugins.ts index b123f84a..3e2721eb 100644 --- a/app/src/plugins.ts +++ b/app/src/plugins.ts @@ -17,26 +17,40 @@ if (process.env.TERMINUS_PLUGINS) { process.env.TERMINUS_PLUGINS.split(':').map(x => nodeModule.globalPaths.unshift(normalizePath(x))) } -export async function loadPlugins (): Promise { +export declare type ProgressCallback = (current, total) => void + +interface IFoundPlugin { + name: string + path: string +} + +export async function loadPlugins (progress: ProgressCallback): Promise { let paths = nodeModule.globalPaths let plugins: any[] = [] + let foundPlugins: IFoundPlugin[] = [] + + progress(0, 1) for (let pluginDir of paths) { pluginDir = normalizePath(pluginDir) if (!await fs.exists(pluginDir)) { continue } - for (let pluginName of await fs.readdir(pluginDir)) { - if (/^terminus-/.exec(pluginName)) { - let pluginPath = path.join(pluginDir, pluginName) - console.info(`Loading ${pluginName}: ${(global).require.resolve(pluginPath)}`) - try { - let pluginModule = (global).require(pluginPath) - plugins.push(pluginModule) - } catch (error) { - console.error(`Could not load ${pluginName}:`, error) - } - } - } + let pluginNames = await fs.readdir(pluginDir) + pluginNames.filter(pluginName => /^terminus-/.exec(pluginName)).forEach(name => { + foundPlugins.push({ name, path: path.join(pluginDir, name) }) + }) } + foundPlugins.forEach((foundPlugin, index) => { + console.info(`Loading ${foundPlugin.name}: ${(global).require.resolve(foundPlugin.path)}`) + progress(index, foundPlugins.length) + try { + let pluginModule = (global).require(foundPlugin.path) + plugins.push(pluginModule) + } catch (error) { + console.error(`Could not load ${foundPlugin.name}:`, error) + } + }) + + progress(1, 1) return plugins } diff --git a/app/src/preload.scss b/app/src/preload.scss new file mode 100644 index 00000000..989d79fa --- /dev/null +++ b/app/src/preload.scss @@ -0,0 +1,102 @@ +$color: rgba(0, 0, 0, 0.5); + + +.preload-logo { + position: fixed; + left: 0; + top: 0; + width: 100vw; + height: 100vh; + display: flex; + animation: 0.5s ease-out fadeIn; + + &>div { + width: 200px; + height: 200px; + margin: auto; + flex: none; + + .progress { + background: rgba(0,0,0,.25); + height: 3px; + margin: 10px 50px; + + .bar { + transition: 1s ease-out width; + background: $color; + height: 3px; + } + } + } +} + + +@keyframes fadeIn { + 0% { opacity: 0; } + 100% { opacity: 1; } +} + + + +.terminus-logo { + width: 160px; + height: 160px; + margin: auto; + position: relative; + + .part { + position: absolute; + width: 160px; + height: 160px; + + div { + position: absolute; + top: 33px; + left: 24px; + width: 44px; + height: 44px; + background: rgba(0,0,0, .75); + transform: rotateX(52deg) rotateY(-42deg); + animation: terminusLogoPartOnce ease-out 1s; + } + } + + &.animated .part div { + animation: terminusLogoPart infinite ease-out 2s; + } +} + + +.terminus-title { + color: $color; + font-family: 'Source Sans Pro'; + text-align: center; + font-weight: normal; + font-size: 42px; + margin: 0; +} + + +@keyframes terminusLogoPart { + 0% { + transform: rotateX(90deg) rotateY(-90deg); + } + 25% { + transform: rotateX(52deg) rotateY(-42deg); + } + 75% { + transform: rotateX(52deg) rotateY(-42deg); + } + 100% { + transform: rotateX(-90deg) rotateY(-90deg); + } +} + +@keyframes terminusLogoPartOnce { + 0% { + transform: rotateX(90deg) rotateY(-90deg); + } + 100% { + transform: rotateX(52deg) rotateY(-42deg); + } +} diff --git a/app/webpack.config.js b/app/webpack.config.js index 1a429cef..ceb6ce1b 100644 --- a/app/webpack.config.js +++ b/app/webpack.config.js @@ -12,9 +12,8 @@ module.exports = { context: __dirname, devtool: 'source-map', output: { - path: path.join(__dirname, 'assets', 'webpack'), + path: path.join(__dirname, 'dist'), pathinfo: true, - //publicPath: 'assets/webpack/', filename: '[name].js' }, resolve: { diff --git a/package.json b/package.json index bd436100..9ae64968 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,14 @@ { "name": "term", "devDependencies": { - "@types/fs-promise": "^1.0.1", "@types/core-js": "^0.9.35", "@types/electron": "1.4.34", + "@types/fs-promise": "^1.0.1", "@types/node": "^7.0.5", "@types/webpack-env": "^1.13.0", "apply-loader": "^0.1.0", "awesome-typescript-loader": "3.1.2", + "cross-env": "^4.0.0", "css-loader": "0.26.1", "electron": "1.6.2", "electron-builder": "10.6.1", @@ -16,7 +17,6 @@ "file-loader": "^0.9.0", "font-awesome": "4.7.0", "html-loader": "^0.4.4", - "source-sans-pro": "^2.0.10", "less": "^2.7.1", "less-loader": "^2.2.3", "node-gyp": "^3.4.0", @@ -26,6 +26,7 @@ "pug-static-loader": "0.0.1", "raw-loader": "^0.5.1", "sass-loader": "^6.0.3", + "source-sans-pro": "^2.0.10", "style-loader": "^0.13.1", "to-string-loader": "^1.1.5", "tslint": "5.0.0", @@ -58,6 +59,7 @@ "scripts": { "build": "webpack --progress --color", "watch": "webpack --progress --color --watch", + "start": "cross-env DEV=1 electron app --debug", "pack": "build --dir", "postinstall": "install-app-deps", "dist": "build" diff --git a/terminus-core/src/components/appRoot.component.scss b/terminus-core/src/components/appRoot.component.scss index ab1cf5a2..01a4b7ba 100644 --- a/terminus-core/src/components/appRoot.component.scss +++ b/terminus-core/src/components/appRoot.component.scss @@ -7,6 +7,7 @@ -webkit-user-select: none; -webkit-font-smoothing: antialiased; cursor: default; + animation: 0.5s ease-out fadeIn; } $tabs-height: 40px; diff --git a/terminus-core/src/components/startPage.component.pug b/terminus-core/src/components/startPage.component.pug index 1529ceb9..bd568fa0 100644 --- a/terminus-core/src/components/startPage.component.pug +++ b/terminus-core/src/components/startPage.component.pug @@ -1,5 +1,22 @@ div - button.btn.btn-outline-info.btn-lg.btn-block( + .terminus-logo + .part(style='transform: rotateZ(0deg)') + div + .part(style='transform: rotateZ(51deg)') + div + .part(style='transform: rotateZ(102deg)') + div + .part(style='transform: rotateZ(154deg)') + div + .part(style='transform: rotateZ(205deg)') + div + .part(style='transform: rotateZ(257deg)') + div + .part(style='transform: rotateZ(308deg)') + div + h1.terminus-title Terminus + + button.btn.btn-outline-primary.btn-lg.btn-block( *ngFor='let button of getButtons()', (click)='button.click()', ) diff --git a/terminus-core/src/components/startPage.component.scss b/terminus-core/src/components/startPage.component.scss index bbecf169..d0a3cd61 100644 --- a/terminus-core/src/components/startPage.component.scss +++ b/terminus-core/src/components/startPage.component.scss @@ -3,11 +3,15 @@ flex: auto; } -:host div { +:host > div { flex: none; margin: auto; - width: 400px; + width: 300px; max-width: 100vw; display: flex; flex-direction: column; } + +.terminus-title { + margin: 0 0 60px; +} diff --git a/terminus-core/src/theme.scss b/terminus-core/src/theme.scss index 82d1fef8..8296910e 100644 --- a/terminus-core/src/theme.scss +++ b/terminus-core/src/theme.scss @@ -145,7 +145,7 @@ app-root { } &.tabs-on-top .tab-bar { - margin-top: 3px; + margin-top: 5px; tab-header { .wrapper { @@ -318,6 +318,10 @@ ngb-tabset .tab-content { i + * { margin-left: 5px; } + + &.btn-lg i + * { + margin-left: 10px; + } } .input-group-addon + .form-control {