diff --git a/.bithoundrc b/.bithoundrc deleted file mode 100644 index 33264d52..00000000 --- a/.bithoundrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ignore": [ - "**/tmp/**" - ] -} \ No newline at end of file diff --git a/.desktop/assets/Cinematic_full.png b/.desktop/assets/Cinematic_full.png deleted file mode 100644 index a11067e3..00000000 Binary files a/.desktop/assets/Cinematic_full.png and /dev/null differ diff --git a/.desktop/assets/dmgBackground.png b/.desktop/assets/dmgBackground.png deleted file mode 100644 index c85101cf..00000000 Binary files a/.desktop/assets/dmgBackground.png and /dev/null differ diff --git a/.desktop/assets/icon.icns b/.desktop/assets/icon.icns deleted file mode 100644 index d3fdb866..00000000 Binary files a/.desktop/assets/icon.icns and /dev/null differ diff --git a/.desktop/assets/icon.ico b/.desktop/assets/icon.ico deleted file mode 100644 index 2f05aa93..00000000 Binary files a/.desktop/assets/icon.ico and /dev/null differ diff --git a/.desktop/assets/icon.png b/.desktop/assets/icon.png deleted file mode 100644 index 6c222e35..00000000 Binary files a/.desktop/assets/icon.png and /dev/null differ diff --git a/.desktop/assets/loading.gif b/.desktop/assets/loading.gif deleted file mode 100644 index 51edb9ea..00000000 Binary files a/.desktop/assets/loading.gif and /dev/null differ diff --git a/.desktop/assets/splashScreen.png b/.desktop/assets/splashScreen.png deleted file mode 100644 index 7b02f332..00000000 Binary files a/.desktop/assets/splashScreen.png and /dev/null differ diff --git a/.desktop/assets/splashScreen.xcf b/.desktop/assets/splashScreen.xcf deleted file mode 100644 index e3362388..00000000 Binary files a/.desktop/assets/splashScreen.xcf and /dev/null differ diff --git a/.desktop/assets/updating.gif b/.desktop/assets/updating.gif deleted file mode 100644 index 51edb9ea..00000000 Binary files a/.desktop/assets/updating.gif and /dev/null differ diff --git a/.desktop/desktop.js b/.desktop/desktop.js deleted file mode 100644 index 8f04a933..00000000 --- a/.desktop/desktop.js +++ /dev/null @@ -1,180 +0,0 @@ -'use strict' -import process from 'process'; -import { app, dialog, ipcMain, globalShortcut, BrowserWindow, Menu } from 'electron'; -import {autoUpdater} from 'electron-updater' -import {is} from 'electron-util' -import unhandled from 'electron-unhandled' -import debug from 'electron-debug' -import contextMenu from 'electron-context-menu' -import menu from './menu' - -unhandled() -debug() -contextMenu(); - -// Note: Must match `build.appId` in package.json -app.setAppUserModelId('com.lacymorrow.Cinematic') - -// Uncomment this before publishing your first version. -// It's commented out as it throws an error if there are no published versions. -// if (!is.development) { -// const FOUR_HOURS = 1000 * 60 * 60 * 4 -// setInterval(() => { -// autoUpdater.checkForUpdates() -// }, FOUR_HOURS) - -// autoUpdater.checkForUpdates() -// } -/** - * Entry point to your native desktop code. - * - * @class - */ -export default class Desktop { - /** - * @param {Object} log - Winston logger instance - * @param {Object} skeletonApp - reference to the skeleton app instance - * @param {Object} appSettings - settings.json contents - * @param {Object} eventsBus - event emitter for listening or emitting events - * shared across skeleton app and every module/plugin - * @param {Object} modules - references to all loaded modules - * @param {Object} Module - reference to the Module class - * @constructor - */ - constructor({ - log, skeletonApp, appSettings, eventsBus, modules, Module - }) { - /** - * You can delete unused var from the param destructuring. - * Left them here just to emphasize what is passed. Delete the eslint rule at the top - * when done. - * You can also just have a one `config` param and do `Object.assign(this, config);` - */ - const desktop = new Module('desktop'); - // Get the automatically predefined logger instance. - this.log = log; - - // From Meteor use this by invoking Desktop.send('desktop', 'closeApp'); - desktop.on('closeApp', () => app.quit()); - - // We need to handle gracefully potential problems. - // Lets remove the default handler and replace it with ours. - skeletonApp.removeUncaughtExceptionListener(); - - process.on('uncaughtException', Desktop.uncaughtExceptionHandler); - - // Chrome problems should also be handled. The `windowCreated` event has a `window` - // reference. This is the reference to the current Electron renderer process (Chrome) - // displaying your Meteor app. - eventsBus.on('windowCreated', (window) => { - window.webContents.on('dom-ready', () => { - // set perfect size - // window.setSize(1300,768); - // window.setFullScreen(true); - // window.minimize(); - window.maximize(); - window.show() - }); - - window.webContents.on('crashed', Desktop.windowCrashedHandler); - window.on('unresponsive', Desktop.windowUnresponsiveHandler); - - Menu.setApplicationMenu(menu); - - /* IPC */ - - // https://stackoverflow.com/questions/44773029/how-to-select-file-or-folder-in-file-dialog - // listen to an open-file-dialog command and sending back selected information - desktop.on('open-file-dialog', () => { - movieSelectDialog(); - }); - - const movieSelectDialog = () => { - dialog.showOpenDialog({ - filters: [ - { name: 'Movies', extensions: ['.avi', '.flv', '.mp4', '.m4v', '.mov', '.ogg', '.ogv', '.vob', '.wmv', '.mkv'] }, - { name: 'All Files', extensions: ['*'] } - ], - title: 'Scan Movies', - message: 'Choose movie folder to scan:', - properties: ['openDirectory', 'openFile', 'multiSelections'] - }, function(files) { - if (files) { - desktop.send('selected-file', files) - } else { - desktop.send('selected-file', false) - } - }); - - } - - }); // /eventsBus.on('windowCreated' - - // Consider setting a crash reporter -> - // https://github.com/electron/electron/blob/master/docs/api/crash-reporter.md - } - - /** - * File browser handler. - */ - static dialogLaunch() { - Desktop.displayRestartDialog( - 'Cinematic has crashed unexpectedly', - 'Do you want to restart it?' - ); - } - - /** - * Window crash handler. - */ - static windowCrashedHandler() { - Desktop.displayRestartDialog( - 'Cinematic has crashed', - 'Do you want to restart it?' - ); - } - - /** - * Window's unresponsiveness handler. - */ - static windowUnresponsiveHandler() { - Desktop.displayRestartDialog( - 'Cinematic is not responding', - 'Do you want to restart it?' - ); - } - - /** - * JS's uncaught exception handler. - * @param {string} error - error message - */ - static uncaughtExceptionHandler(error) { - // Consider sending a log somewhere, it is good be aware your users are having problems, - // right? - Desktop.displayRestartDialog( - 'Cinematic encountered an error', - 'Do you want to restart it?', - error.message - ); - } - - /** - * Displays an error dialog with simple 'restart' or 'shutdown' choice. - * @param {string} title - title of the dialog - * @param {string} message - message shown in the dialog - * @param {string} details - additional details to be displayed - */ - static displayRestartDialog(title, message, details = '') { - dialog.showMessageBox( - { - type: 'error', buttons: ['Restart', 'Shutdown'], title, message, detail: details - }, - (response) => { - if (response === 0) { - app.relaunch(); - } - app.exit(0); - } - ); - } -} diff --git a/.desktop/desktop.test.js b/.desktop/desktop.test.js deleted file mode 100644 index 9221249a..00000000 --- a/.desktop/desktop.test.js +++ /dev/null @@ -1,125 +0,0 @@ -/* eslint-disable no-param-reassign */ -import test from 'ava'; -import electron from 'electron'; -import path from 'path'; -import { Application } from 'spectron'; - -/** - * For this to work, init testing with `npm run desktop -- init-tests-support`. - * This will add necessary packages to your `devDependencies` and add `desktop-test` to scripts. - * - * This is an example of functional test for your desktop app. - * Remember that you need to rebuild your desktop app if you made changes in .desktop. You can - * do that with `npm run desktop -- build`. - * There is a plan for using desktop.asar built from omega:meteor-desktop-bundler so that you could - * avoid manual rebuild. - */ - -test.beforeEach(async (t) => { - // Before each test we will spawn a new desktop app instance. - t.context.app = new Application({ - path: electron, - requireName: 'electronRequire', - args: [path.join(__dirname, '..', '.meteor', 'desktop-build')], - env: { NODE_ENV: 'test', ELECTRON_ENV: 'test', METEOR_DESKTOP_NO_SPLASH_SCREEN: 1 } - }); - await t.context.app.start(); -}); - -test.afterEach.always(async (t) => { - // Kill the app after the test. - if (t.context.app && t.context.app.isRunning()) { - await t.context.app.stop(); - } -}); - -/** - * Sends an IPC event to your module. - * - * @param {Object} app - app ref from Spectron - * @param {string} module - module name - * @param {string} event - event from your module - * @param {...*} args - arguments to pass to ipc.send - */ -function sendModuleEvent(app, module, event, ...args) { - args.unshift(`${module}__${event}`); - return app.electron.ipcRenderer.send(...args); -} - -/** - * Waits until a promise from a function finally returns true. - * @param {Function} functionReturningPromise - function to test - * @param {number} ms - expiration timeout in milliseconds - * @returns {Promise} - */ -function waitFor(functionReturningPromise, ms = 10000) { - return new Promise((resolve, reject) => { - let invokerTimeout; - let timeout; - const invokeFunction = () => - functionReturningPromise() - .then((result) => { - if (result) { - clearTimeout(invokerTimeout); - clearTimeout(timeout); - resolve(); - } else { - invokerTimeout = setTimeout(invokeFunction, 500); - } - }) - .catch(() => { - invokerTimeout = setTimeout(invokeFunction, 500); - }); - invokeFunction(); - timeout = setTimeout(() => { - clearTimeout(invokerTimeout); - reject('timeout expired on waitFor'); - }, ms); - }); -} - -/** - * Waits for the app to load and appear. - * @param {Object} t - test context - * @returns {{app: (Application|*), window: *}} - */ -async function waitForApp(t) { - const { app } = t.context; - await app.client.waitUntilWindowLoaded(); - const window = app.browserWindow; - // Wait for the main window for max 30seconds. Adjust to your app. - await waitFor(window.isVisible, 30000); - t.is(await app.client.getWindowCount(), 1); - await app.client.waitUntil( - () => app.client.execute( - () => document.readyState === 'complete' - ) - ); - return { app, window }; -} - -test.serial('if app can be closed', async (t) => { - const { app, window } = await waitForApp(t); // eslint-disable-line no-unused-vars - await sendModuleEvent(app, 'desktop', 'closeApp'); - t.true(await app.client.getWindowCount() === 0); - - // Spectron does not seem to notice app has quit so we need to do it manually. - t.context.app.running = false; -}); - -// Empty test. -test.serial('if window title is set properly', async (t) => { - const { app, window } = await waitForApp(t); // eslint-disable-line no-unused-vars - - // Your assertions... - - /* - const title = await window.getTitle(); - t.is(title, 'my app '); - - // NOTE: - // avoid using await in assertions like - // t.is(await window.getTitle(), 'my app <title>'); - // it makes Power Assert not producing it's useful graphs - */ -}); diff --git a/.desktop/menu.js b/.desktop/menu.js deleted file mode 100644 index ff568979..00000000 --- a/.desktop/menu.js +++ /dev/null @@ -1,182 +0,0 @@ -'use strict' -const path = require('path') -const {app, Menu, shell, BrowserWindow} = require('electron') -const { - is, - appMenu, - aboutMenuItem, - openUrlMenuItem, - openNewGitHubIssue, - debugInfo -} = require('electron-util') - -const showPreferences = () => { - console.log('Show Preferences…') -} - -const helpSubmenu = [ - openUrlMenuItem({ - label: 'Website', - url: 'https://github.com/lacymorrow/cinematic' - }), - openUrlMenuItem({ - label: 'Source Code', - url: 'https://github.com/lacymorrow/cinematic' - }), - { - label: 'Report an Issue…', - click() { - const body = ` -<!-- Please succinctly describe your issue and steps to reproduce it. --> - - ---- - -${debugInfo()}` - - openNewGitHubIssue({ - user: 'lacymorrow', - repo: 'cinematic', - body - }) - } - } -] - -if (!is.macos) { - helpSubmenu.push( - { - type: 'separator' - }, - aboutMenuItem({ - icon: path.join(__dirname, 'static', 'icon.png'), - text: 'Created by Lacy Morrow' - }) - ) -} - -const debugSubmenu = [ - { - label: 'Show Settings', - click() { - shell.openItem(this.path); - } - }, - { - label: 'Show App Data', - click() { - shell.openItem(app.getPath('userData')) - } - }, - { - type: 'separator' - }, - { - label: 'Delete Settings', - click() { - app.relaunch() - app.quit() - } - }, - { - label: 'Delete App Data', - click() { - shell.moveItemToTrash(app.getPath('userData')) - app.relaunch() - app.quit() - } - } -] - -const macosTemplate = [ - appMenu([ - { - label: 'Open at startup', - type: 'checkbox', - checked: false, - click() { - showBootLaunch() - } - }, - { - label: 'Preferences…', - accelerator: 'Command+,', - click() { - showPreferences() - } - } - ]), - { - role: 'fileMenu', - submenu: [ - { - type: 'separator' - }, - { - role: 'close' - } - ] - }, - { - role: 'editMenu' - }, - { - role: 'viewMenu' - }, - { - role: 'windowMenu' - }, - { - role: 'help', - submenu: helpSubmenu - } -] - -// Linux and Windows -const otherTemplate = [ - { - role: 'fileMenu', - submenu: [ - { - label: 'Custom' - }, - { - type: 'separator' - }, - { - label: 'Settings', - accelerator: 'Control+,', - click() { - showPreferences() - } - }, - { - type: 'separator' - }, - { - role: 'quit' - } - ] - }, - { - role: 'editMenu' - }, - { - role: 'viewMenu' - }, - { - role: 'help', - submenu: helpSubmenu - } -] - -const template = process.platform === 'darwin' ? macosTemplate : otherTemplate - -if (is.development) { - template.push({ - label: 'Debug', - submenu: debugSubmenu - }) -} - -module.exports = Menu.buildFromTemplate(template) diff --git a/.desktop/settings.json b/.desktop/settings.json deleted file mode 100644 index cb936ed4..00000000 --- a/.desktop/settings.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "name": "Cinematic", - "version": "2.0.0", - "projectName": "cinematic", - "devTools": true, - "devtron": true, - "desktopHCP": false, - "desktopHCPIgnoreCompatibilityVersion": false, - "squirrel": { - "autoUpdateFeedUrl": "http://127.0.0.1/update/:platform/:version", - "autoUpdateFeedHeaders": {}, - "autoUpdateCheckOnStart": false - }, - "webAppStartupTimeout": 15000, - "exposeLocalFilesystem": false, - "window": { - "icon": "@assets/icon.png", - "_windows": { - "icon": "@assets/icon.ico" - } - }, - "windowDev": { - }, - "uglify": true, - "plugins": {}, - "dependencies": {}, - "packageJsonFields": { - "description": "Cinematic takes the effort out of organizing your movies and finds information, photos, and trailers for you to make choosing what to watch a breeze.", - "author": { - "name": "Lacy Morrow", - "email": "me@lacymorrow.com", - "url": "http://lacymorrow.com" - }, - "repository": { - "type": "git", - "url": "https://github.com/lacymorrow/cinematic" - }, - "license": "GPL-3.0", - "private": false - }, - "builderOptions": { - "icon": ".desktop/assets/icon.ico", - "appId": "com.lacymorrow.Cinematic", - "productName": "Cinematic", - "compression": "maximum", - "win": { - "target": [ - "nsis" - ] - }, - "linux": { - "target": [ - "deb", - "rpm", - "apk", - "pacman", - "freebsd", - "AppImage" - ], - "category": "Development" - }, - "squirrelWindows": { - "iconUrl": "https://raw.githubusercontent.com/lacymorrow/cinematic/master/.desktop/assets/icon.ico", - "loadingGif": ".desktop/assets/loading.gif" - }, - "publish": [ - { - "provider": "generic", - "url": "http://127.0.0.1:8080/" - } - ], - "mac": { - "icon": ".desktop/assets/icon.icns", - "appId": null, - "target": [ - "dmg" - ] - }, - "dmg": { - "icon": ".desktop/assets/icon.icns", - "background": ".desktop/assets/dmgBackground.png", - "iconSize": 54, - "contents": [ - { "x": 377, "y": 190, "type": "link", "path": "/Applications" }, - { "x": 63, "y": 190, "type": "file" } - ], - "window": { - "width": 480, - "height": 300 - } - } - }, - "packagerOptions": { - "icon": ".desktop/assets/icon.ico", - "_osx": { - "icon": ".desktop/assets/icon.icns" - }, - "appVersion": "@version", - "buildVersion": "@version", - "appCopyright": "Copyright 2018 Lacy Morrow - All rights reserved.", - "win32metadata": { - "CompanyName": "lacymorrow", - "FileDescription": "Cinematic", - "OriginalFilename": "Cinematic.exe", - "ProductName": "Cinematic", - "InternalName": "Cinematic.exe" - } - } -} diff --git a/.editorconfig b/.editorconfig index 1c6314a3..4a7ea303 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,12 +1,12 @@ root = true [*] -indent_style = tab +indent_style = space +indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -[*.yml] -indent_style = space -indent_size = 2 +[*.md] +trim_trailing_whitespace = false diff --git a/.erb/configs/.eslintrc b/.erb/configs/.eslintrc new file mode 100644 index 00000000..89d242ba --- /dev/null +++ b/.erb/configs/.eslintrc @@ -0,0 +1,7 @@ +{ + "rules": { + "no-console": "off", + "global-require": "off", + "import/no-dynamic-require": "off" + } +} diff --git a/.erb/configs/webpack.config.base.ts b/.erb/configs/webpack.config.base.ts new file mode 100644 index 00000000..0ef00445 --- /dev/null +++ b/.erb/configs/webpack.config.base.ts @@ -0,0 +1,59 @@ +/** + * Base webpack config used across other specific configs + */ + +import webpack from 'webpack'; +import TsconfigPathsPlugins from 'tsconfig-paths-webpack-plugin'; +import webpackPaths from './webpack.paths'; +import { dependencies as externals } from '../../release/app/package.json'; + +const configuration: webpack.Configuration = { + externals: [...Object.keys(externals || {})], + + stats: 'errors-only', + + module: { + rules: [ + { + test: /\.[jt]sx?$/, + exclude: /node_modules/, + use: { + loader: 'ts-loader', + options: { + // Remove this line to enable type checking in webpack builds + transpileOnly: true, + compilerOptions: { + module: 'esnext', + }, + }, + }, + }, + ], + }, + + output: { + path: webpackPaths.srcPath, + // https://github.com/webpack/webpack/issues/1114 + library: { + type: 'commonjs2', + }, + }, + + /** + * Determine the array of extensions that should be used to resolve modules. + */ + resolve: { + extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'], + modules: [webpackPaths.srcPath, 'node_modules'], + // There is no need to add aliases here, the paths in tsconfig get mirrored + plugins: [new TsconfigPathsPlugins()], + }, + + plugins: [ + new webpack.EnvironmentPlugin({ + NODE_ENV: 'production', + }), + ], +}; + +export default configuration; diff --git a/.erb/configs/webpack.config.eslint.ts b/.erb/configs/webpack.config.eslint.ts new file mode 100644 index 00000000..35a631b7 --- /dev/null +++ b/.erb/configs/webpack.config.eslint.ts @@ -0,0 +1,3 @@ +/* eslint import/no-unresolved: off, import/no-self-import: off */ + +module.exports = require('./webpack.config.renderer.dev').default; diff --git a/.erb/configs/webpack.config.main.prod.ts b/.erb/configs/webpack.config.main.prod.ts new file mode 100644 index 00000000..47274821 --- /dev/null +++ b/.erb/configs/webpack.config.main.prod.ts @@ -0,0 +1,83 @@ +/** + * Webpack config for production electron main process + */ + +import path from 'path'; +import webpack from 'webpack'; +import { merge } from 'webpack-merge'; +import TerserPlugin from 'terser-webpack-plugin'; +import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; +import baseConfig from './webpack.config.base'; +import webpackPaths from './webpack.paths'; +import checkNodeEnv from '../scripts/check-node-env'; +import deleteSourceMaps from '../scripts/delete-source-maps'; + +checkNodeEnv('production'); +deleteSourceMaps(); + +const configuration: webpack.Configuration = { + devtool: 'source-map', + + mode: 'production', + + target: 'electron-main', + + entry: { + main: path.join(webpackPaths.srcMainPath, 'main.ts'), + preload: path.join(webpackPaths.srcMainPath, 'preload.ts'), + }, + + output: { + path: webpackPaths.distMainPath, + filename: '[name].js', + library: { + type: 'umd', + }, + }, + + optimization: { + minimizer: [ + new TerserPlugin({ + parallel: true, + }), + ], + }, + + plugins: [ + new BundleAnalyzerPlugin({ + analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled', + analyzerPort: 8888, + }), + + /** + * Create global constants which can be configured at compile time. + * + * Useful for allowing different behaviour between development builds and + * release builds + * + * NODE_ENV should be production so that modules do not perform certain + * development checks + */ + new webpack.EnvironmentPlugin({ + NODE_ENV: 'production', + DEBUG_PROD: false, + START_MINIMIZED: false, + }), + + new webpack.DefinePlugin({ + 'process.type': '"browser"', + }), + ], + + /** + * Disables webpack processing of __dirname and __filename. + * If you run the bundle in node.js it falls back to these values of node.js. + * https://github.com/webpack/webpack/issues/2010 + */ + node: { + __dirname: false, + __filename: false, + }, +}; + +export default merge(baseConfig, configuration); diff --git a/.erb/configs/webpack.config.preload.dev.ts b/.erb/configs/webpack.config.preload.dev.ts new file mode 100644 index 00000000..d6679e63 --- /dev/null +++ b/.erb/configs/webpack.config.preload.dev.ts @@ -0,0 +1,71 @@ +import path from 'path'; +import webpack from 'webpack'; +import { merge } from 'webpack-merge'; +import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; +import baseConfig from './webpack.config.base'; +import webpackPaths from './webpack.paths'; +import checkNodeEnv from '../scripts/check-node-env'; + +// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's +// at the dev webpack config is not accidentally run in a production environment +if (process.env.NODE_ENV === 'production') { + checkNodeEnv('development'); +} + +const configuration: webpack.Configuration = { + devtool: 'inline-source-map', + + mode: 'development', + + target: 'electron-preload', + + entry: path.join(webpackPaths.srcMainPath, 'preload.ts'), + + output: { + path: webpackPaths.dllPath, + filename: 'preload.js', + library: { + type: 'umd', + }, + }, + + plugins: [ + new BundleAnalyzerPlugin({ + analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled', + }), + + /** + * Create global constants which can be configured at compile time. + * + * Useful for allowing different behaviour between development builds and + * release builds + * + * NODE_ENV should be production so that modules do not perform certain + * development checks + * + * By default, use 'development' as NODE_ENV. This can be overriden with + * 'staging', for example, by changing the ENV variables in the npm scripts + */ + new webpack.EnvironmentPlugin({ + NODE_ENV: 'development', + }), + + new webpack.LoaderOptionsPlugin({ + debug: true, + }), + ], + + /** + * Disables webpack processing of __dirname and __filename. + * If you run the bundle in node.js it falls back to these values of node.js. + * https://github.com/webpack/webpack/issues/2010 + */ + node: { + __dirname: false, + __filename: false, + }, + + watch: true, +}; + +export default merge(baseConfig, configuration); diff --git a/.erb/configs/webpack.config.renderer.dev.dll.ts b/.erb/configs/webpack.config.renderer.dev.dll.ts new file mode 100644 index 00000000..614b90f0 --- /dev/null +++ b/.erb/configs/webpack.config.renderer.dev.dll.ts @@ -0,0 +1,77 @@ +/** + * Builds the DLL for development electron renderer process + */ + +import webpack from 'webpack'; +import path from 'path'; +import { merge } from 'webpack-merge'; +import baseConfig from './webpack.config.base'; +import webpackPaths from './webpack.paths'; +import { dependencies } from '../../package.json'; +import checkNodeEnv from '../scripts/check-node-env'; + +checkNodeEnv('development'); + +const dist = webpackPaths.dllPath; + +const configuration: webpack.Configuration = { + context: webpackPaths.rootPath, + + devtool: 'eval', + + mode: 'development', + + target: 'electron-renderer', + + externals: ['fsevents', 'crypto-browserify'], + + /** + * Use `module` from `webpack.config.renderer.dev.js` + */ + module: require('./webpack.config.renderer.dev').default.module, + + entry: { + renderer: Object.keys(dependencies || {}), + }, + + output: { + path: dist, + filename: '[name].dev.dll.js', + library: { + name: 'renderer', + type: 'var', + }, + }, + + plugins: [ + new webpack.DllPlugin({ + path: path.join(dist, '[name].json'), + name: '[name]', + }), + + /** + * Create global constants which can be configured at compile time. + * + * Useful for allowing different behaviour between development builds and + * release builds + * + * NODE_ENV should be production so that modules do not perform certain + * development checks + */ + new webpack.EnvironmentPlugin({ + NODE_ENV: 'development', + }), + + new webpack.LoaderOptionsPlugin({ + debug: true, + options: { + context: webpackPaths.srcPath, + output: { + path: webpackPaths.dllPath, + }, + }, + }), + ], +}; + +export default merge(baseConfig, configuration); diff --git a/.erb/configs/webpack.config.renderer.dev.ts b/.erb/configs/webpack.config.renderer.dev.ts new file mode 100644 index 00000000..5d6fb125 --- /dev/null +++ b/.erb/configs/webpack.config.renderer.dev.ts @@ -0,0 +1,213 @@ +import 'webpack-dev-server'; +import path from 'path'; +import fs from 'fs'; +import webpack from 'webpack'; +import HtmlWebpackPlugin from 'html-webpack-plugin'; +import chalk from 'chalk'; +import { merge } from 'webpack-merge'; +import { execSync, spawn } from 'child_process'; +import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin'; +import baseConfig from './webpack.config.base'; +import webpackPaths from './webpack.paths'; +import checkNodeEnv from '../scripts/check-node-env'; + +// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's +// at the dev webpack config is not accidentally run in a production environment +if (process.env.NODE_ENV === 'production') { + checkNodeEnv('development'); +} + +const port = process.env.PORT || 1212; +const manifest = path.resolve(webpackPaths.dllPath, 'renderer.json'); +const skipDLLs = + module.parent?.filename.includes('webpack.config.renderer.dev.dll') || + module.parent?.filename.includes('webpack.config.eslint'); + +/** + * Warn if the DLL is not built + */ +if ( + !skipDLLs && + !(fs.existsSync(webpackPaths.dllPath) && fs.existsSync(manifest)) +) { + console.log( + chalk.black.bgYellow.bold( + 'The DLL files are missing. Sit back while we build them for you with "npm run build-dll"', + ), + ); + execSync('npm run postinstall'); +} + +const configuration: webpack.Configuration = { + devtool: 'inline-source-map', + + mode: 'development', + + target: ['web', 'electron-renderer'], + + entry: [ + `webpack-dev-server/client?http://localhost:${port}/dist`, + 'webpack/hot/only-dev-server', + path.join(webpackPaths.srcRendererPath, 'index.tsx'), + ], + + output: { + path: webpackPaths.distRendererPath, + publicPath: '/', + filename: 'renderer.dev.js', + library: { + type: 'umd', + }, + }, + + module: { + rules: [ + { + test: /\.s?(c|a)ss$/, + use: [ + 'style-loader', + { + loader: 'css-loader', + options: { + modules: true, + sourceMap: true, + importLoaders: 1, + }, + }, + 'sass-loader', + ], + include: /\.module\.s?(c|a)ss$/, + }, + { + test: /\.s?css$/, + use: ['style-loader', 'css-loader', 'sass-loader', 'postcss-loader'], + exclude: /\.module\.s?(c|a)ss$/, + }, + // Fonts + { + test: /\.(woff|woff2|eot|ttf|otf)$/i, + type: 'asset/resource', + }, + // Images + { + test: /\.(png|jpg|jpeg|gif)$/i, + type: 'asset/resource', + }, + // SVG + { + test: /\.svg$/, + use: [ + { + loader: '@svgr/webpack', + options: { + prettier: false, + svgo: false, + svgoConfig: { + plugins: [{ removeViewBox: false }], + }, + titleProp: true, + ref: true, + }, + }, + 'file-loader', + ], + }, + ], + }, + plugins: [ + ...(skipDLLs + ? [] + : [ + new webpack.DllReferencePlugin({ + context: webpackPaths.dllPath, + manifest: require(manifest), + sourceType: 'var', + }), + ]), + + new webpack.NoEmitOnErrorsPlugin(), + + /** + * Create global constants which can be configured at compile time. + * + * Useful for allowing different behaviour between development builds and + * release builds + * + * NODE_ENV should be production so that modules do not perform certain + * development checks + * + * By default, use 'development' as NODE_ENV. This can be overriden with + * 'staging', for example, by changing the ENV variables in the npm scripts + */ + new webpack.EnvironmentPlugin({ + NODE_ENV: 'development', + }), + + new webpack.LoaderOptionsPlugin({ + debug: true, + }), + + new ReactRefreshWebpackPlugin(), + + new HtmlWebpackPlugin({ + filename: path.join('index.html'), + template: path.join(webpackPaths.srcRendererPath, 'index.ejs'), + minify: { + collapseWhitespace: true, + removeAttributeQuotes: true, + removeComments: true, + }, + isBrowser: false, + env: process.env.NODE_ENV, + isDevelopment: process.env.NODE_ENV !== 'production', + nodeModules: webpackPaths.appNodeModulesPath, + }), + ], + + node: { + __dirname: false, + __filename: false, + }, + + devServer: { + port, + compress: true, + hot: true, + headers: { 'Access-Control-Allow-Origin': '*' }, + static: { + publicPath: '/', + }, + historyApiFallback: { + verbose: true, + }, + setupMiddlewares(middlewares) { + console.log('Starting preload.js builder...'); + const preloadProcess = spawn('npm', ['run', 'start:preload'], { + shell: true, + stdio: 'inherit', + }) + .on('close', (code: number) => process.exit(code!)) + .on('error', (spawnError) => console.error(spawnError)); + + console.log('Starting Main Process...'); + let args = ['run', 'start:main']; + if (process.env.MAIN_ARGS) { + args = args.concat( + ['--', ...process.env.MAIN_ARGS.matchAll(/"[^"]+"|[^\s"]+/g)].flat(), + ); + } + spawn('npm', args, { + shell: true, + stdio: 'inherit', + }) + .on('close', (code: number) => { + preloadProcess.kill(); + process.exit(code!); + }) + .on('error', (spawnError) => console.error(spawnError)); + return middlewares; + }, + }, +}; + +export default merge(baseConfig, configuration); diff --git a/.erb/configs/webpack.config.renderer.prod.ts b/.erb/configs/webpack.config.renderer.prod.ts new file mode 100644 index 00000000..b4134479 --- /dev/null +++ b/.erb/configs/webpack.config.renderer.prod.ts @@ -0,0 +1,146 @@ +/** + * Build config for electron renderer process + */ + +import path from 'path'; +import webpack from 'webpack'; +import HtmlWebpackPlugin from 'html-webpack-plugin'; +import MiniCssExtractPlugin from 'mini-css-extract-plugin'; +import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; +import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'; +import { merge } from 'webpack-merge'; +import TerserPlugin from 'terser-webpack-plugin'; +import baseConfig from './webpack.config.base'; +import webpackPaths from './webpack.paths'; +import checkNodeEnv from '../scripts/check-node-env'; +import deleteSourceMaps from '../scripts/delete-source-maps'; + +checkNodeEnv('production'); +deleteSourceMaps(); + +const configuration: webpack.Configuration = { + devtool: 'source-map', + + mode: 'production', + + target: ['web', 'electron-renderer'], + + entry: [path.join(webpackPaths.srcRendererPath, 'index.tsx')], + + output: { + path: webpackPaths.distRendererPath, + publicPath: './', + filename: 'renderer.js', + library: { + type: 'umd', + }, + }, + + module: { + rules: [ + { + test: /\.s?(a|c)ss$/, + use: [ + MiniCssExtractPlugin.loader, + { + loader: 'css-loader', + options: { + modules: true, + sourceMap: true, + importLoaders: 1, + }, + }, + 'sass-loader', + ], + include: /\.module\.s?(c|a)ss$/, + }, + { + test: /\.s?(a|c)ss$/, + use: [ + MiniCssExtractPlugin.loader, + 'css-loader', + 'sass-loader', + 'postcss-loader', + ], + exclude: /\.module\.s?(c|a)ss$/, + }, + // Fonts + { + test: /\.(woff|woff2|eot|ttf|otf)$/i, + type: 'asset/resource', + }, + // Images + { + test: /\.(png|jpg|jpeg|gif)$/i, + type: 'asset/resource', + }, + // SVG + { + test: /\.svg$/, + use: [ + { + loader: '@svgr/webpack', + options: { + prettier: false, + svgo: false, + svgoConfig: { + plugins: [{ removeViewBox: false }], + }, + titleProp: true, + ref: true, + }, + }, + 'file-loader', + ], + }, + ], + }, + + optimization: { + minimize: true, + minimizer: [new TerserPlugin(), new CssMinimizerPlugin()], + }, + + plugins: [ + /** + * Create global constants which can be configured at compile time. + * + * Useful for allowing different behaviour between development builds and + * release builds + * + * NODE_ENV should be production so that modules do not perform certain + * development checks + */ + new webpack.EnvironmentPlugin({ + NODE_ENV: 'production', + DEBUG_PROD: false, + }), + + new MiniCssExtractPlugin({ + filename: 'style.css', + }), + + new BundleAnalyzerPlugin({ + analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled', + analyzerPort: 8889, + }), + + new HtmlWebpackPlugin({ + filename: 'index.html', + template: path.join(webpackPaths.srcRendererPath, 'index.ejs'), + minify: { + collapseWhitespace: true, + removeAttributeQuotes: true, + removeComments: true, + }, + isBrowser: false, + isDevelopment: false, + }), + + new webpack.DefinePlugin({ + 'process.type': '"renderer"', + }), + ], +}; + +export default merge(baseConfig, configuration); diff --git a/.erb/configs/webpack.paths.ts b/.erb/configs/webpack.paths.ts new file mode 100644 index 00000000..e5ba5734 --- /dev/null +++ b/.erb/configs/webpack.paths.ts @@ -0,0 +1,38 @@ +const path = require('path'); + +const rootPath = path.join(__dirname, '../..'); + +const dllPath = path.join(__dirname, '../dll'); + +const srcPath = path.join(rootPath, 'src'); +const srcMainPath = path.join(srcPath, 'main'); +const srcRendererPath = path.join(srcPath, 'renderer'); + +const releasePath = path.join(rootPath, 'release'); +const appPath = path.join(releasePath, 'app'); +const appPackagePath = path.join(appPath, 'package.json'); +const appNodeModulesPath = path.join(appPath, 'node_modules'); +const srcNodeModulesPath = path.join(srcPath, 'node_modules'); + +const distPath = path.join(appPath, 'dist'); +const distMainPath = path.join(distPath, 'main'); +const distRendererPath = path.join(distPath, 'renderer'); + +const buildPath = path.join(releasePath, 'build'); + +export default { + rootPath, + dllPath, + srcPath, + srcMainPath, + srcRendererPath, + releasePath, + appPath, + appPackagePath, + appNodeModulesPath, + srcNodeModulesPath, + distPath, + distMainPath, + distRendererPath, + buildPath, +}; diff --git a/.erb/img/erb-banner.svg b/.erb/img/erb-banner.svg new file mode 100644 index 00000000..f7ce6707 --- /dev/null +++ b/.erb/img/erb-banner.svg @@ -0,0 +1,32 @@ +<svg width="2312" height="412" viewBox="0 0 2312 412" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M0 0H2312V412H0V0Z" fill="#7140FF"/> +<rect width="2312" height="412" fill="url(#paint0_linear_23_17)"/> +<g> +<path d="M597.5 91V90.5H597H367H366.5V91V321V321.5H367H597H597.5V321V91ZM406.5 115C406.5 123.008 400.008 129.5 392 129.5C383.992 129.5 377.5 123.008 377.5 115C377.5 106.992 383.992 100.5 392 100.5C400.008 100.5 406.5 106.992 406.5 115ZM586.5 115C586.5 123.008 580.008 129.5 572 129.5C563.992 129.5 557.5 123.008 557.5 115C557.5 106.992 563.992 100.5 572 100.5C580.008 100.5 586.5 106.992 586.5 115ZM406.5 295C406.5 303.008 400.008 309.5 392 309.5C383.992 309.5 377.5 303.008 377.5 295C377.5 286.992 383.992 280.5 392 280.5C400.008 280.5 406.5 286.992 406.5 295ZM586.5 295C586.5 303.008 580.008 309.5 572 309.5C563.992 309.5 557.5 303.008 557.5 295C557.5 286.992 563.992 280.5 572 280.5C580.008 280.5 586.5 286.992 586.5 295ZM575.5 201C575.5 252.639 533.639 294.5 482 294.5C430.361 294.5 388.5 252.639 388.5 201C388.5 149.361 430.361 107.5 482 107.5C533.639 107.5 575.5 149.361 575.5 201Z" fill="white" stroke="white"/> +<path d="M429.5 236.5C429.5 239.959 426.897 242.5 424 242.5C421.103 242.5 418.5 239.959 418.5 236.5C418.5 233.041 421.103 230.5 424 230.5C426.897 230.5 429.5 233.041 429.5 236.5Z" stroke="white" stroke-width="5"/> +<path d="M420.986 229.466C420.986 229.466 417.197 206.315 449.187 183.165C481.178 160.014 499.698 159.593 499.698 159.593" stroke="white" stroke-width="5" stroke-linecap="round"/> +<path d="M544.902 232.686C543.27 229.853 539.652 228.88 536.819 230.512C533.987 232.144 533.014 235.762 534.646 238.595C536.277 241.427 539.896 242.4 542.728 240.768C545.561 239.137 546.534 235.518 544.902 232.686Z" stroke="white" stroke-width="5"/> +<path d="M535.409 241.555C535.409 241.555 517.24 256.394 481.211 240.232C445.182 224.07 435.572 208.232 435.572 208.232" stroke="white" stroke-width="5" stroke-linecap="round"/> +<path d="M475.577 131.971C473.966 134.814 474.964 138.426 477.808 140.038C480.651 141.65 484.263 140.651 485.875 137.808C487.487 134.964 486.488 131.352 483.645 129.74C480.801 128.128 477.189 129.127 475.577 131.971Z" stroke="white" stroke-width="5"/> +<path d="M488.038 135.647C488.038 135.647 510.047 143.767 514.412 183.013C518.778 222.259 510.012 238.579 510.012 238.579" stroke="white" stroke-width="5" stroke-linecap="round"/> +<path d="M425.633 195C425.633 195 416.437 172.104 427.305 163.362C438.174 154.619 462 159.199 462 159.199" stroke="white" stroke-width="5" stroke-linecap="round"/> +<path d="M515.532 156.978C515.532 156.978 540.391 158.913 543.477 172.638C546.564 186.363 531.799 205.833 531.799 205.833" stroke="white" stroke-width="5" stroke-linecap="round"/> +<path d="M504.248 253.363C504.248 253.363 490.023 273.841 476.618 269.573C463.213 265.305 453.866 242.728 453.866 242.728" stroke="white" stroke-width="5" stroke-linecap="round"/> +<path d="M482 209C486.418 209 490 205.642 490 201.5C490 197.358 486.418 194 482 194C477.582 194 474 197.358 474 201.5C474 205.642 477.582 209 482 209Z" fill="white"/> +</g> +<path d="M767.932 159.626H802.918V153.2H767.932V128.312H805.366V121.784H760.588V194H806.59V187.472H767.932V159.626ZM827.683 116.888H820.747V194H827.683V116.888ZM850.119 166.46C850.731 158.3 857.565 150.854 866.847 150.854C876.741 150.854 882.249 157.484 882.657 166.46H850.119ZM889.695 168.704C889.695 155.648 881.841 145.04 866.847 145.04C853.281 145.04 842.775 155.75 842.775 170.132C842.775 184.514 853.281 195.224 867.459 195.224C875.313 195.224 882.351 192.266 887.961 185.126L882.759 181.046C880.107 185.33 874.599 189.308 867.459 189.308C857.667 189.308 850.221 181.556 850.017 171.968H889.593C889.695 170.744 889.695 169.622 889.695 168.704ZM944.394 153.302C940.314 147.794 933.072 145.04 926.646 145.04C911.244 145.04 901.146 155.75 901.146 170.132C901.146 184.514 911.244 195.224 926.646 195.224C934.908 195.224 940.722 191.96 944.802 186.962L939.6 183.086C936.846 186.758 932.664 189.308 926.646 189.308C915.528 189.308 908.49 180.944 908.49 170.132C908.49 159.218 915.63 150.854 926.748 150.854C931.95 150.854 936.744 153.506 938.988 157.178L944.394 153.302ZM977.136 146.264H963.672V132.8H956.736V146.264H946.842V152.078H956.736V181.862C956.736 192.368 963.876 194.612 968.976 194.612C972.138 194.612 974.688 194.102 977.136 193.184L976.83 187.166C974.994 188.084 972.75 188.696 970.812 188.696C966.63 188.696 963.672 187.064 963.672 179.924V152.078H977.136V146.264ZM987.987 156.77V194H994.923V169.52C994.923 156.77 1001.55 151.466 1008.9 151.466C1010.73 151.466 1012.98 151.772 1013.79 152.078L1014.71 145.55C1013.28 145.142 1011.85 145.04 1010.12 145.04C1003.39 145.04 997.473 148.916 994.821 154.424H994.617C994.617 152.384 994.413 148.814 994.209 146.264H987.579C987.885 149.528 987.987 154.22 987.987 156.77ZM1070.38 170.132C1070.38 155.75 1059.77 145.04 1044.88 145.04C1030.09 145.04 1019.48 155.75 1019.48 170.132C1019.48 184.514 1030.09 195.224 1044.88 195.224C1059.77 195.224 1070.38 184.514 1070.38 170.132ZM1063.04 170.132C1063.04 180.842 1056 189.308 1044.88 189.308C1033.86 189.308 1026.83 180.842 1026.83 170.132C1026.83 159.422 1033.86 150.854 1044.88 150.854C1056 150.854 1063.04 159.422 1063.04 170.132ZM1084.9 146.264C1085.2 149.528 1085.31 154.22 1085.31 156.77V194H1092.24V169.52C1092.24 156.77 1099.38 150.854 1106.73 150.854C1116.72 150.854 1119.68 157.586 1119.68 167.582V194H1126.62V164.726C1126.62 152.894 1120.6 145.04 1108.46 145.04C1101.73 145.04 1094.79 148.916 1092.14 154.424H1091.94C1091.94 152.384 1091.73 148.814 1091.53 146.264H1084.9ZM1177.82 160.238H1190.06L1210.06 194H1219.03L1197.92 159.626C1208.42 158.504 1216.38 151.772 1216.38 141.062C1216.38 126.986 1205.98 121.784 1191.7 121.784H1170.48V194H1177.82V160.238ZM1177.82 128.108H1190.88C1201.79 128.108 1209.04 131.576 1209.04 141.062C1209.04 149.63 1202.3 153.914 1190.57 153.914H1177.82V128.108ZM1233.81 166.46C1234.43 158.3 1241.26 150.854 1250.54 150.854C1260.44 150.854 1265.94 157.484 1266.35 166.46H1233.81ZM1273.39 168.704C1273.39 155.648 1265.54 145.04 1250.54 145.04C1236.98 145.04 1226.47 155.75 1226.47 170.132C1226.47 184.514 1236.98 195.224 1251.15 195.224C1259.01 195.224 1266.05 192.266 1271.66 185.126L1266.45 181.046C1263.8 185.33 1258.29 189.308 1251.15 189.308C1241.36 189.308 1233.92 181.556 1233.71 171.968H1273.29C1273.39 170.744 1273.39 169.622 1273.39 168.704ZM1317.8 164.726C1300.36 164.726 1284.14 166.052 1284.14 180.74C1284.14 191.348 1293.42 195.224 1300.67 195.224C1308.32 195.224 1313.62 192.572 1318.01 186.248H1318.21C1318.21 188.798 1318.52 191.654 1318.92 194H1325.15C1324.64 191.348 1324.33 186.962 1324.33 183.29V162.38C1324.33 150.752 1316.07 145.04 1305.77 145.04C1297.61 145.04 1290.87 147.998 1287 151.874L1290.87 156.464C1294.24 153.098 1299.44 150.854 1305.05 150.854C1313.31 150.854 1317.8 154.934 1317.8 163.196V164.726ZM1317.8 170.132V173.702C1317.8 182.168 1312.29 189.512 1302.5 189.512C1297.1 189.512 1291.28 187.268 1291.28 180.434C1291.28 171.356 1304.44 170.132 1315.76 170.132H1317.8ZM1381.98 153.302C1377.9 147.794 1370.66 145.04 1364.23 145.04C1348.83 145.04 1338.73 155.75 1338.73 170.132C1338.73 184.514 1348.83 195.224 1364.23 195.224C1372.49 195.224 1378.31 191.96 1382.39 186.962L1377.18 183.086C1374.43 186.758 1370.25 189.308 1364.23 189.308C1353.11 189.308 1346.07 180.944 1346.07 170.132C1346.07 159.218 1353.21 150.854 1364.33 150.854C1369.53 150.854 1374.33 153.506 1376.57 157.178L1381.98 153.302ZM1414.72 146.264H1401.26V132.8H1394.32V146.264H1384.43V152.078H1394.32V181.862C1394.32 192.368 1401.46 194.612 1406.56 194.612C1409.72 194.612 1412.27 194.102 1414.72 193.184L1414.41 187.166C1412.58 188.084 1410.33 188.696 1408.4 188.696C1404.21 188.696 1401.26 187.064 1401.26 179.924V152.078H1414.72V146.264ZM1451.48 194H1472.9C1489.52 194 1499.83 186.044 1499.83 174.008C1499.83 163.502 1492.89 156.974 1483.51 155.954V155.75C1491.16 154.016 1496.26 147.794 1496.26 140.246C1496.26 125.762 1484.02 121.784 1473 121.784H1451.48V194ZM1458.82 128.108H1471.57C1481.06 128.108 1488.91 131.576 1488.91 140.756C1488.91 150.344 1480.65 153.404 1473.61 153.404H1458.82V128.108ZM1458.82 159.422H1473.82C1485.55 159.422 1492.38 164.114 1492.38 173.6C1492.38 183.698 1483.1 187.676 1472.49 187.676H1458.82V159.422ZM1563.35 170.132C1563.35 155.75 1552.74 145.04 1537.85 145.04C1523.06 145.04 1512.45 155.75 1512.45 170.132C1512.45 184.514 1523.06 195.224 1537.85 195.224C1552.74 195.224 1563.35 184.514 1563.35 170.132ZM1556 170.132C1556 180.842 1548.96 189.308 1537.85 189.308C1526.83 189.308 1519.79 180.842 1519.79 170.132C1519.79 159.422 1526.83 150.854 1537.85 150.854C1548.96 150.854 1556 159.422 1556 170.132ZM1585.31 146.264H1578.37V194H1585.31V146.264ZM1586.74 127.904C1586.74 125.048 1584.29 123.008 1581.84 123.008C1579.39 123.008 1576.95 125.048 1576.95 127.904C1576.95 130.76 1579.39 132.8 1581.84 132.8C1584.29 132.8 1586.74 130.76 1586.74 127.904ZM1610.91 116.888H1603.98V194H1610.91V116.888ZM1633.35 166.46C1633.96 158.3 1640.79 150.854 1650.08 150.854C1659.97 150.854 1665.48 157.484 1665.89 166.46H1633.35ZM1672.92 168.704C1672.92 155.648 1665.07 145.04 1650.08 145.04C1636.51 145.04 1626 155.75 1626 170.132C1626 184.514 1636.51 195.224 1650.69 195.224C1658.54 195.224 1665.58 192.266 1671.19 185.126L1665.99 181.046C1663.34 185.33 1657.83 189.308 1650.69 189.308C1640.9 189.308 1633.45 181.556 1633.25 171.968H1672.82C1672.92 170.744 1672.92 169.622 1672.92 168.704ZM1687.84 156.77V194H1694.78V169.52C1694.78 156.77 1701.41 151.466 1708.75 151.466C1710.59 151.466 1712.83 151.772 1713.65 152.078L1714.57 145.55C1713.14 145.142 1711.71 145.04 1709.98 145.04C1703.24 145.04 1697.33 148.916 1694.68 154.424H1694.47C1694.47 152.384 1694.27 148.814 1694.06 146.264H1687.43C1687.74 149.528 1687.84 154.22 1687.84 156.77ZM1731.53 185.942H1731.84C1735.82 191.858 1742.96 195.224 1749.79 195.224C1764.68 195.224 1774.48 184.208 1774.48 170.132C1774.48 156.056 1764.68 145.04 1749.79 145.04C1742.96 145.04 1735.82 148.304 1731.84 154.526H1731.53V146.264H1724.6V218.48H1731.53V185.942ZM1767.13 170.132C1767.13 180.74 1760.6 189.308 1749.08 189.308C1738.37 189.308 1730.72 181.046 1730.72 170.132C1730.72 159.218 1738.37 150.854 1749.08 150.854C1760.6 150.854 1767.13 159.524 1767.13 170.132ZM1796.48 116.888H1789.55V194H1796.48V116.888ZM1845.13 164.726C1827.69 164.726 1811.47 166.052 1811.47 180.74C1811.47 191.348 1820.76 195.224 1828 195.224C1835.65 195.224 1840.95 192.572 1845.34 186.248H1845.54C1845.54 188.798 1845.85 191.654 1846.26 194H1852.48C1851.97 191.348 1851.66 186.962 1851.66 183.29V162.38C1851.66 150.752 1843.4 145.04 1833.1 145.04C1824.94 145.04 1818.21 147.998 1814.33 151.874L1818.21 156.464C1821.57 153.098 1826.77 150.854 1832.38 150.854C1840.65 150.854 1845.13 154.934 1845.13 163.196V164.726ZM1845.13 170.132V173.702C1845.13 182.168 1839.63 189.512 1829.83 189.512C1824.43 189.512 1818.61 187.268 1818.61 180.434C1818.61 171.356 1831.77 170.132 1843.09 170.132H1845.13ZM1890.06 146.264H1876.59V132.8H1869.66V146.264H1859.76V152.078H1869.66V181.862C1869.66 192.368 1876.8 194.612 1881.9 194.612C1885.06 194.612 1887.61 194.102 1890.06 193.184L1889.75 187.166C1887.91 188.084 1885.67 188.696 1883.73 188.696C1879.55 188.696 1876.59 187.064 1876.59 179.924V152.078H1890.06V146.264ZM1904.78 166.46C1905.39 158.3 1912.23 150.854 1921.51 150.854C1931.4 150.854 1936.91 157.484 1937.32 166.46H1904.78ZM1944.36 168.704C1944.36 155.648 1936.5 145.04 1921.51 145.04C1907.94 145.04 1897.44 155.75 1897.44 170.132C1897.44 184.514 1907.94 195.224 1922.12 195.224C1929.98 195.224 1937.01 192.266 1942.62 185.126L1937.42 181.046C1934.77 185.33 1929.26 189.308 1922.12 189.308C1912.33 189.308 1904.88 181.556 1904.68 171.968H1944.26C1944.36 170.744 1944.36 169.622 1944.36 168.704Z" fill="#F2F2F2"/> +<path d="M788.893 282L773.899 245.892H765.433L750.286 282H759.772L762.424 274.911H776.398L779.203 282H788.893ZM774.001 267.924H764.923L769.513 255.531L774.001 267.924ZM835.657 253.338V245.892H811.891V282H820.51V267.975H834.484V260.784H820.51V253.338H835.657ZM869.384 269.199C869.384 260.886 862.958 255.786 855.257 255.786C847.607 255.786 841.181 260.886 841.181 269.199C841.181 277.512 847.607 282.816 855.257 282.816C862.958 282.816 869.384 277.512 869.384 269.199ZM861.326 269.199C861.326 272.463 859.235 275.778 855.308 275.778C851.381 275.778 849.29 272.463 849.29 269.199C849.29 265.935 851.33 262.722 855.257 262.722C859.184 262.722 861.326 265.935 861.326 269.199ZM903.546 282V256.602H895.182V270.321C895.182 273.228 893.601 275.778 890.694 275.778C887.634 275.778 886.92 273.228 886.92 270.372V256.602H878.505V272.31C878.505 277.41 880.902 282.714 887.736 282.714C891.306 282.714 894.213 280.725 895.386 278.481H895.488V282H903.546ZM939.259 282V266.292C939.259 261.192 936.811 255.888 929.977 255.888C926.458 255.888 923.551 257.877 922.378 260.121H922.276V256.602H914.167V282H922.582V268.23C922.582 265.323 924.112 262.773 927.07 262.773C930.079 262.773 930.844 265.323 930.844 268.128V282H939.259ZM976.602 282V243.444H968.238V259.305H968.136C966.708 257.622 964.107 255.888 960.384 255.888C952.989 255.888 948.399 262.11 948.399 269.199C948.399 276.288 952.836 282.714 960.486 282.714C963.852 282.714 967.167 281.235 968.799 278.685H968.901V282H976.602ZM968.595 269.25C968.595 272.565 966.249 275.778 962.475 275.778C958.497 275.778 956.457 272.514 956.457 269.199C956.457 265.935 958.497 262.722 962.475 262.722C966.249 262.722 968.595 266.037 968.595 269.25ZM1002.32 271.8C1002.32 274.962 1000.43 277.002 997.063 277.002C995.38 277.002 993.442 276.339 993.442 274.401C993.442 271.392 997.573 270.933 1001.25 270.933H1002.32V271.8ZM991.198 264.609C992.728 263.181 995.074 262.008 997.471 262.008C1000.07 262.008 1002.06 263.181 1002.06 265.68V266.088C994.666 266.088 985.741 267.312 985.741 274.656C985.741 280.623 990.943 282.612 994.972 282.612C997.981 282.612 1000.89 281.388 1002.16 279.297H1002.32V282H1009.97V269.199C1009.97 259.968 1006.8 255.786 998.287 255.786C994.156 255.786 989.923 257.265 986.965 260.07L991.198 264.609ZM1034.84 262.875V256.602H1028.87V249.921H1020.66V256.602H1016.63V262.875H1020.71V273.585C1020.71 278.991 1022.95 282.612 1029.74 282.612C1031.52 282.612 1033.46 282.255 1034.58 281.847L1034.48 275.727C1033.87 275.982 1032.85 276.135 1032.03 276.135C1029.63 276.135 1028.87 274.911 1028.87 272.565V262.875H1034.84ZM1051.92 248.493C1051.92 245.943 1049.78 243.903 1047.13 243.903C1044.43 243.903 1042.34 246.045 1042.34 248.493C1042.34 250.992 1044.43 253.083 1047.13 253.083C1049.78 253.083 1051.92 251.094 1051.92 248.493ZM1051.31 282V256.602H1042.95V282H1051.31ZM1088.95 269.199C1088.95 260.886 1082.52 255.786 1074.82 255.786C1067.17 255.786 1060.74 260.886 1060.74 269.199C1060.74 277.512 1067.17 282.816 1074.82 282.816C1082.52 282.816 1088.95 277.512 1088.95 269.199ZM1080.89 269.199C1080.89 272.463 1078.8 275.778 1074.87 275.778C1070.94 275.778 1068.85 272.463 1068.85 269.199C1068.85 265.935 1070.89 262.722 1074.82 262.722C1078.75 262.722 1080.89 265.935 1080.89 269.199ZM1123.41 282V266.292C1123.41 261.192 1120.96 255.888 1114.13 255.888C1110.61 255.888 1107.7 257.877 1106.53 260.121H1106.43V256.602H1098.32V282H1106.74V268.23C1106.74 265.323 1108.27 262.773 1111.22 262.773C1114.23 262.773 1115 265.323 1115 268.128V282H1123.41ZM1166.98 242.985C1165.86 242.628 1164.38 242.475 1162.95 242.475C1154.48 242.475 1152.03 247.932 1152.03 254.154V256.602H1147.39V262.875H1152.03V282H1160.4V262.875H1166.06V256.602H1160.4V254.052C1160.4 251.706 1161.06 249.258 1164.12 249.258C1164.94 249.258 1165.8 249.411 1166.42 249.615L1166.98 242.985ZM1200.24 269.199C1200.24 260.886 1193.82 255.786 1186.12 255.786C1178.47 255.786 1172.04 260.886 1172.04 269.199C1172.04 277.512 1178.47 282.816 1186.12 282.816C1193.82 282.816 1200.24 277.512 1200.24 269.199ZM1192.18 269.199C1192.18 272.463 1190.09 275.778 1186.17 275.778C1182.24 275.778 1180.15 272.463 1180.15 269.199C1180.15 265.935 1182.19 262.722 1186.12 262.722C1190.04 262.722 1192.18 265.935 1192.18 269.199ZM1226.45 256.092C1226.04 255.939 1225.33 255.888 1224.66 255.888C1221.55 255.888 1219.05 257.724 1217.78 260.274H1217.68V256.602H1209.62V282H1217.98V268.944C1217.98 266.853 1219.46 263.181 1223.95 263.181C1224.61 263.181 1225.33 263.232 1226.09 263.436L1226.45 256.092ZM1275.84 249.411C1272.68 246.504 1268.09 244.974 1264.01 244.974C1257.28 244.974 1250.04 248.289 1250.04 256.296C1250.04 262.824 1254.68 265.17 1259.27 266.649C1264.01 268.179 1266.76 269.046 1266.76 271.8C1266.76 274.707 1264.42 275.727 1261.77 275.727C1258.91 275.727 1255.7 274.095 1253.96 271.902L1248.25 277.716C1251.41 281.031 1256.61 282.918 1261.77 282.918C1268.91 282.918 1275.59 279.195 1275.59 270.882C1275.59 263.691 1269.26 261.6 1264.37 260.019C1260.95 258.948 1258.81 258.183 1258.81 255.786C1258.81 252.93 1261.61 252.165 1263.86 252.165C1266.1 252.165 1268.8 253.389 1270.28 255.276L1275.84 249.411ZM1307.3 259.203C1305.31 257.163 1301.48 255.786 1297.86 255.786C1289.96 255.786 1283.69 261.039 1283.69 269.301C1283.69 277.716 1289.91 282.816 1297.91 282.816C1301.64 282.816 1305.21 281.592 1307.3 279.552L1302.66 273.891C1301.64 275.115 1299.8 275.778 1298.12 275.778C1294.45 275.778 1292.15 272.82 1292.15 269.301C1292.15 265.782 1294.5 262.773 1298.02 262.773C1299.7 262.773 1301.54 263.589 1302.45 264.813L1307.3 259.203ZM1329.68 271.8C1329.68 274.962 1327.8 277.002 1324.43 277.002C1322.75 277.002 1320.81 276.339 1320.81 274.401C1320.81 271.392 1324.94 270.933 1328.61 270.933H1329.68V271.8ZM1318.57 264.609C1320.1 263.181 1322.44 262.008 1324.84 262.008C1327.44 262.008 1329.43 263.181 1329.43 265.68V266.088C1322.03 266.088 1313.11 267.312 1313.11 274.656C1313.11 280.623 1318.31 282.612 1322.34 282.612C1325.35 282.612 1328.26 281.388 1329.53 279.297H1329.68V282H1337.33V269.199C1337.33 259.968 1334.17 255.786 1325.66 255.786C1321.52 255.786 1317.29 257.265 1314.33 260.07L1318.57 264.609ZM1356.23 282V243.444H1347.76V282H1356.23ZM1381.92 271.8C1381.92 274.962 1380.03 277.002 1376.67 277.002C1374.99 277.002 1373.05 276.339 1373.05 274.401C1373.05 271.392 1377.18 270.933 1380.85 270.933H1381.92V271.8ZM1370.8 264.609C1372.33 263.181 1374.68 262.008 1377.08 262.008C1379.68 262.008 1381.67 263.181 1381.67 265.68V266.088C1374.27 266.088 1365.35 267.312 1365.35 274.656C1365.35 280.623 1370.55 282.612 1374.58 282.612C1377.59 282.612 1380.49 281.388 1381.77 279.297H1381.92V282H1389.57V269.199C1389.57 259.968 1386.41 255.786 1377.89 255.786C1373.76 255.786 1369.53 257.265 1366.57 260.07L1370.8 264.609ZM1428.2 269.199C1428.2 262.11 1423.61 255.888 1416.21 255.888C1412.49 255.888 1409.89 257.622 1408.46 259.305H1408.36V243.444H1400V282H1407.7V278.685H1407.8C1409.43 281.235 1412.75 282.714 1416.11 282.714C1423.76 282.714 1428.2 276.288 1428.2 269.199ZM1420.14 269.199C1420.14 272.514 1418.1 275.778 1414.12 275.778C1410.35 275.778 1408 272.565 1408 269.25C1408 266.037 1410.35 262.722 1414.12 262.722C1418.1 262.722 1420.14 265.935 1420.14 269.199ZM1446.16 282V243.444H1437.69V282H1446.16ZM1463.59 266.394C1463.8 263.793 1466.14 261.549 1469.36 261.549C1472.67 261.549 1474.36 263.742 1474.36 266.394H1463.59ZM1482.06 269.607C1482.06 260.937 1476.8 255.786 1469.31 255.786C1461.61 255.786 1455.59 261.09 1455.59 269.403C1455.59 277.971 1461.91 282.816 1469.56 282.816C1474.71 282.816 1478.69 280.878 1481.09 277.41L1475.27 273.738C1474.15 275.268 1472.32 276.39 1469.66 276.39C1466.65 276.39 1463.85 274.401 1463.59 271.596H1482.01C1482.06 270.984 1482.06 270.27 1482.06 269.607ZM1542.32 263.844C1542.32 250.176 1531.92 245.892 1521.67 245.892H1508.61V282H1522.08C1532.02 282 1542.32 276.543 1542.32 263.844ZM1533.25 263.844C1533.25 271.902 1527.48 274.452 1521.26 274.452H1517.13V253.338H1521.46C1527.48 253.338 1533.25 255.735 1533.25 263.844ZM1558.46 266.394C1558.66 263.793 1561.01 261.549 1564.22 261.549C1567.54 261.549 1569.22 263.742 1569.22 266.394H1558.46ZM1576.92 269.607C1576.92 260.937 1571.67 255.786 1564.17 255.786C1556.47 255.786 1550.45 261.09 1550.45 269.403C1550.45 277.971 1556.78 282.816 1564.43 282.816C1569.58 282.816 1573.56 280.878 1575.95 277.41L1570.14 273.738C1569.02 275.268 1567.18 276.39 1564.53 276.39C1561.52 276.39 1558.72 274.401 1558.46 271.596H1576.87C1576.92 270.984 1576.92 270.27 1576.92 269.607ZM1605.72 259.356C1603.22 257.01 1599.3 255.786 1595.52 255.786C1590.68 255.786 1584.97 258.234 1584.97 264.303C1584.97 269.097 1588.84 270.882 1592.36 271.698C1595.83 272.514 1597.41 273.024 1597.41 274.605C1597.41 276.237 1595.78 276.798 1594.4 276.798C1591.95 276.798 1589.66 275.574 1588.18 273.942L1583.49 278.889C1586.14 281.439 1590.42 282.816 1594.55 282.816C1599.76 282.816 1605.42 280.572 1605.42 274.146C1605.42 269.199 1601.18 267.261 1597.31 266.394C1594.04 265.68 1592.67 265.272 1592.67 263.844C1592.67 262.365 1594.25 261.804 1595.83 261.804C1597.87 261.804 1599.81 262.824 1601.13 264.099L1605.72 259.356ZM1631.41 268.077L1641.2 256.602H1631.05L1622.94 266.904H1622.79V243.444H1614.38V282H1622.79V269.811H1622.94L1631.26 282H1641.61L1631.41 268.077ZM1663.78 262.875V256.602H1657.81V249.921H1649.6V256.602H1645.57V262.875H1649.65V273.585C1649.65 278.991 1651.9 282.612 1658.68 282.612C1660.47 282.612 1662.4 282.255 1663.53 281.847L1663.42 275.727C1662.81 275.982 1661.79 276.135 1660.98 276.135C1658.58 276.135 1657.81 274.911 1657.81 272.565V262.875H1663.78ZM1698.72 269.199C1698.72 260.886 1692.29 255.786 1684.59 255.786C1676.94 255.786 1670.52 260.886 1670.52 269.199C1670.52 277.512 1676.94 282.816 1684.59 282.816C1692.29 282.816 1698.72 277.512 1698.72 269.199ZM1690.66 269.199C1690.66 272.463 1688.57 275.778 1684.64 275.778C1680.72 275.778 1678.63 272.463 1678.63 269.199C1678.63 265.935 1680.67 262.722 1684.59 262.722C1688.52 262.722 1690.66 265.935 1690.66 269.199ZM1736.35 269.199C1736.35 262.11 1731.71 255.888 1724.31 255.888C1720.59 255.888 1717.73 257.673 1716.2 259.713H1716.05V256.602H1708.1V294.24H1716.46V279.195H1716.56C1718.14 281.388 1721.15 282.714 1724.26 282.714C1731.91 282.714 1736.35 276.288 1736.35 269.199ZM1728.24 269.199C1728.24 272.514 1726.25 275.778 1722.27 275.778C1718.5 275.778 1716.15 272.565 1716.15 269.25C1716.15 266.037 1718.5 262.722 1722.27 262.722C1726.25 262.722 1728.24 265.935 1728.24 269.199ZM1796.26 282L1781.26 245.892H1772.8L1757.65 282H1767.14L1769.79 274.911H1783.76L1786.57 282H1796.26ZM1781.36 267.924H1772.29L1776.88 255.531L1781.36 267.924ZM1831.12 269.199C1831.12 262.11 1826.47 255.888 1819.08 255.888C1815.36 255.888 1812.5 257.673 1810.97 259.713H1810.82V256.602H1802.86V294.24H1811.23V279.195H1811.33C1812.91 281.388 1815.92 282.714 1819.03 282.714C1826.68 282.714 1831.12 276.288 1831.12 269.199ZM1823.01 269.199C1823.01 272.514 1821.02 275.778 1817.04 275.778C1813.27 275.778 1810.92 272.565 1810.92 269.25C1810.92 266.037 1813.27 262.722 1817.04 262.722C1821.02 262.722 1823.01 265.935 1823.01 269.199ZM1868.71 269.199C1868.71 262.11 1864.07 255.888 1856.68 255.888C1852.96 255.888 1850.1 257.673 1848.57 259.713H1848.42V256.602H1840.46V294.24H1848.82V279.195H1848.93C1850.51 281.388 1853.52 282.714 1856.63 282.714C1864.28 282.714 1868.71 276.288 1868.71 269.199ZM1860.61 269.199C1860.61 272.514 1858.62 275.778 1854.64 275.778C1850.86 275.778 1848.52 272.565 1848.52 269.25C1848.52 266.037 1850.86 262.722 1854.64 262.722C1858.62 262.722 1860.61 265.935 1860.61 269.199ZM1897.59 259.356C1895.09 257.01 1891.17 255.786 1887.39 255.786C1882.55 255.786 1876.84 258.234 1876.84 264.303C1876.84 269.097 1880.71 270.882 1884.23 271.698C1887.7 272.514 1889.28 273.024 1889.28 274.605C1889.28 276.237 1887.65 276.798 1886.27 276.798C1883.82 276.798 1881.53 275.574 1880.05 273.942L1875.36 278.889C1878.01 281.439 1882.29 282.816 1886.42 282.816C1891.63 282.816 1897.29 280.572 1897.29 274.146C1897.29 269.199 1893.05 267.261 1889.18 266.394C1885.91 265.68 1884.54 265.272 1884.54 263.844C1884.54 262.365 1886.12 261.804 1887.7 261.804C1889.74 261.804 1891.68 262.824 1893 264.099L1897.59 259.356Z" fill="#F2F2F2" fill-opacity="0.5"/> +<defs> +<filter id="filter0_b_23_17" x="362" y="86" width="240" height="240" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> +<feFlood flood-opacity="0" result="BackgroundImageFix"/> +<feGaussianBlur in="BackgroundImage" stdDeviation="2"/> +<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_23_17"/> +<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_23_17" result="shape"/> +</filter> +<linearGradient id="paint0_linear_23_17" x1="2396.5" y1="-160" x2="2335.15" y2="738.65" gradientUnits="userSpaceOnUse"> +<stop stop-color="#FEDC2A"/> +<stop offset="0.51037" stop-color="#DD5789"/> +<stop offset="1" stop-color="#7A2C9E"/> +</linearGradient> +</defs> +</svg> diff --git a/.erb/img/erb-logo.png b/.erb/img/erb-logo.png new file mode 100644 index 00000000..97a5661a Binary files /dev/null and b/.erb/img/erb-logo.png differ diff --git a/.erb/img/palette-sponsor-banner.svg b/.erb/img/palette-sponsor-banner.svg new file mode 100644 index 00000000..c1abcfd2 --- /dev/null +++ b/.erb/img/palette-sponsor-banner.svg @@ -0,0 +1,6 @@ +<svg width="2269" height="437" viewBox="0 0 2269 437" fill="none" xmlns="http://www.w3.org/2000/svg"> +<rect width="2269" height="437" rx="37" fill="black"/> +<path d="M708.83 324V285.513H733.862V291.357H715.802V301.806H732.565V307.65H715.802V318.155H734.012V324H708.83ZM747.477 285.513V324H740.674V285.513H747.477ZM767.252 324.564C764.358 324.564 761.858 323.962 759.753 322.76C757.661 321.544 756.051 319.828 754.924 317.611C753.796 315.38 753.232 312.756 753.232 309.736C753.232 306.767 753.796 304.161 754.924 301.919C756.064 299.664 757.655 297.91 759.697 296.657C761.739 295.391 764.138 294.759 766.895 294.759C768.674 294.759 770.352 295.047 771.931 295.623C773.522 296.187 774.925 297.064 776.141 298.254C777.368 299.444 778.333 300.96 779.035 302.802C779.736 304.631 780.087 306.811 780.087 309.342V311.428H756.427V306.842H773.566C773.553 305.539 773.272 304.381 772.72 303.366C772.169 302.338 771.399 301.53 770.409 300.941C769.432 300.353 768.292 300.058 766.989 300.058C765.598 300.058 764.376 300.396 763.324 301.073C762.272 301.737 761.451 302.614 760.862 303.704C760.286 304.781 759.991 305.965 759.979 307.256V311.259C759.979 312.937 760.286 314.378 760.9 315.581C761.514 316.771 762.372 317.686 763.474 318.325C764.577 318.951 765.867 319.264 767.346 319.264C768.335 319.264 769.231 319.126 770.033 318.851C770.835 318.563 771.53 318.143 772.119 317.592C772.708 317.04 773.153 316.358 773.453 315.543L779.805 316.257C779.404 317.936 778.64 319.402 777.512 320.655C776.397 321.895 774.969 322.86 773.228 323.549C771.486 324.226 769.494 324.564 767.252 324.564ZM798.433 324.564C795.552 324.564 793.077 323.931 791.01 322.666C788.956 321.4 787.371 319.653 786.256 317.423C785.153 315.18 784.602 312.599 784.602 309.68C784.602 306.748 785.166 304.161 786.293 301.919C787.421 299.664 789.012 297.91 791.067 296.657C793.134 295.391 795.577 294.759 798.396 294.759C800.739 294.759 802.812 295.191 804.616 296.055C806.433 296.907 807.88 298.116 808.957 299.682C810.035 301.236 810.649 303.053 810.799 305.132H804.297C804.034 303.742 803.407 302.583 802.417 301.656C801.44 300.716 800.131 300.246 798.49 300.246C797.099 300.246 795.878 300.622 794.825 301.374C793.773 302.113 792.952 303.178 792.363 304.568C791.787 305.959 791.499 307.625 791.499 309.567C791.499 311.534 791.787 313.226 792.363 314.641C792.94 316.044 793.748 317.128 794.788 317.892C795.84 318.644 797.074 319.02 798.49 319.02C799.492 319.02 800.388 318.832 801.177 318.456C801.979 318.068 802.649 317.51 803.188 316.784C803.727 316.057 804.096 315.174 804.297 314.134H810.799C810.636 316.176 810.035 317.986 808.995 319.565C807.955 321.131 806.539 322.359 804.748 323.248C802.956 324.125 800.851 324.564 798.433 324.564ZM830.799 295.135V300.396H814.205V295.135H830.799ZM818.302 288.219H825.105V315.318C825.105 316.232 825.243 316.934 825.518 317.423C825.806 317.899 826.182 318.224 826.646 318.4C827.109 318.575 827.623 318.663 828.187 318.663C828.613 318.663 829.001 318.632 829.352 318.569C829.715 318.506 829.991 318.45 830.179 318.4L831.325 323.718C830.962 323.843 830.442 323.981 829.765 324.132C829.101 324.282 828.287 324.37 827.322 324.395C825.618 324.445 824.084 324.188 822.718 323.624C821.353 323.048 820.269 322.158 819.467 320.956C818.678 319.753 818.289 318.249 818.302 316.445V288.219ZM836.488 324V295.135H843.085V299.945H843.385C843.911 298.279 844.814 296.995 846.091 296.093C847.382 295.178 848.854 294.721 850.508 294.721C850.884 294.721 851.303 294.74 851.767 294.777C852.243 294.803 852.638 294.846 852.951 294.909V301.167C852.663 301.067 852.205 300.979 851.579 300.904C850.965 300.816 850.37 300.772 849.794 300.772C848.553 300.772 847.438 301.042 846.448 301.58C845.471 302.107 844.701 302.84 844.137 303.779C843.573 304.719 843.291 305.802 843.291 307.03V324H836.488ZM868.873 324.564C866.054 324.564 863.611 323.944 861.544 322.703C859.476 321.463 857.873 319.728 856.733 317.498C855.605 315.268 855.041 312.662 855.041 309.68C855.041 306.698 855.605 304.086 856.733 301.844C857.873 299.601 859.476 297.859 861.544 296.619C863.611 295.379 866.054 294.759 868.873 294.759C871.692 294.759 874.135 295.379 876.202 296.619C878.269 297.859 879.866 299.601 880.994 301.844C882.134 304.086 882.704 306.698 882.704 309.68C882.704 312.662 882.134 315.268 880.994 317.498C879.866 319.728 878.269 321.463 876.202 322.703C874.135 323.944 871.692 324.564 868.873 324.564ZM868.91 319.114C870.439 319.114 871.717 318.694 872.744 317.855C873.771 317.003 874.536 315.863 875.037 314.435C875.55 313.006 875.807 311.415 875.807 309.661C875.807 307.895 875.55 306.297 875.037 304.869C874.536 303.428 873.771 302.282 872.744 301.43C871.717 300.578 870.439 300.152 868.91 300.152C867.344 300.152 866.041 300.578 865.001 301.43C863.974 302.282 863.204 303.428 862.69 304.869C862.189 306.297 861.938 307.895 861.938 309.661C861.938 311.415 862.189 313.006 862.69 314.435C863.204 315.863 863.974 317.003 865.001 317.855C866.041 318.694 867.344 319.114 868.91 319.114ZM895.281 307.087V324H888.478V295.135H894.98V300.039H895.319C895.983 298.423 897.041 297.139 898.495 296.187C899.96 295.235 901.771 294.759 903.926 294.759C905.918 294.759 907.653 295.185 909.131 296.037C910.622 296.889 911.775 298.123 912.589 299.739C913.416 301.355 913.823 303.316 913.811 305.621V324H907.008V306.673C907.008 304.744 906.507 303.234 905.504 302.144C904.515 301.054 903.143 300.509 901.389 300.509C900.198 300.509 899.14 300.772 898.213 301.299C897.298 301.812 896.578 302.558 896.052 303.535C895.538 304.512 895.281 305.696 895.281 307.087ZM933.853 334.825V295.135H940.543V299.908H940.938C941.289 299.206 941.783 298.461 942.422 297.672C943.061 296.87 943.926 296.187 945.016 295.623C946.106 295.047 947.496 294.759 949.188 294.759C951.418 294.759 953.429 295.329 955.22 296.469C957.024 297.596 958.452 299.269 959.505 301.486C960.57 303.691 961.102 306.398 961.102 309.605C961.102 312.775 960.582 315.468 959.542 317.686C958.503 319.903 957.087 321.595 955.295 322.76C953.504 323.925 951.474 324.507 949.206 324.507C947.553 324.507 946.181 324.232 945.091 323.681C944.001 323.129 943.124 322.465 942.46 321.689C941.808 320.899 941.301 320.154 940.938 319.452H940.656V334.825H933.853ZM940.524 309.567C940.524 311.434 940.787 313.069 941.314 314.472C941.852 315.875 942.623 316.972 943.625 317.761C944.64 318.538 945.868 318.926 947.308 318.926C948.812 318.926 950.071 318.525 951.086 317.723C952.101 316.909 952.865 315.8 953.378 314.397C953.905 312.981 954.168 311.371 954.168 309.567C954.168 307.776 953.911 306.185 953.397 304.794C952.884 303.403 952.119 302.313 951.105 301.524C950.09 300.735 948.824 300.34 947.308 300.34C945.855 300.34 944.621 300.722 943.606 301.486C942.591 302.251 941.821 303.322 941.295 304.7C940.781 306.078 940.524 307.701 940.524 309.567ZM979.707 324.564C976.813 324.564 974.313 323.962 972.209 322.76C970.116 321.544 968.507 319.828 967.379 317.611C966.251 315.38 965.688 312.756 965.688 309.736C965.688 306.767 966.251 304.161 967.379 301.919C968.519 299.664 970.11 297.91 972.152 296.657C974.194 295.391 976.594 294.759 979.35 294.759C981.129 294.759 982.808 295.047 984.386 295.623C985.977 296.187 987.381 297.064 988.596 298.254C989.824 299.444 990.788 300.96 991.49 302.802C992.191 304.631 992.542 306.811 992.542 309.342V311.428H968.882V306.842H986.021C986.009 305.539 985.727 304.381 985.176 303.366C984.624 302.338 983.854 301.53 982.864 300.941C981.887 300.353 980.747 300.058 979.444 300.058C978.053 300.058 976.832 300.396 975.779 301.073C974.727 301.737 973.906 302.614 973.317 303.704C972.741 304.781 972.447 305.965 972.434 307.256V311.259C972.434 312.937 972.741 314.378 973.355 315.581C973.969 316.771 974.827 317.686 975.93 318.325C977.032 318.951 978.323 319.264 979.801 319.264C980.791 319.264 981.686 319.126 982.488 318.851C983.29 318.563 983.985 318.143 984.574 317.592C985.163 317.04 985.608 316.358 985.908 315.543L992.26 316.257C991.859 317.936 991.095 319.402 989.968 320.655C988.853 321.895 987.424 322.86 985.683 323.549C983.942 324.226 981.949 324.564 979.707 324.564ZM998.297 324V295.135H1004.89V299.945H1005.19C1005.72 298.279 1006.62 296.995 1007.9 296.093C1009.19 295.178 1010.66 294.721 1012.32 294.721C1012.69 294.721 1013.11 294.74 1013.58 294.777C1014.05 294.803 1014.45 294.846 1014.76 294.909V301.167C1014.47 301.067 1014.01 300.979 1013.39 300.904C1012.77 300.816 1012.18 300.772 1011.6 300.772C1010.36 300.772 1009.25 301.042 1008.26 301.58C1007.28 302.107 1006.51 302.84 1005.95 303.779C1005.38 304.719 1005.1 305.802 1005.1 307.03V324H998.297ZM1035.45 295.135V300.396H1018.39V295.135H1035.45ZM1022.65 324V292.41C1022.65 290.468 1023.05 288.852 1023.86 287.561C1024.67 286.271 1025.76 285.306 1027.13 284.667C1028.49 284.028 1030.01 283.709 1031.67 283.709C1032.85 283.709 1033.9 283.803 1034.81 283.991C1035.73 284.178 1036.4 284.348 1036.84 284.498L1035.49 289.76C1035.2 289.672 1034.84 289.584 1034.4 289.497C1033.96 289.397 1033.47 289.346 1032.93 289.346C1031.67 289.346 1030.77 289.653 1030.24 290.267C1029.73 290.869 1029.47 291.733 1029.47 292.861V324H1022.65ZM1052.28 324.564C1049.47 324.564 1047.02 323.944 1044.95 322.703C1042.89 321.463 1041.28 319.728 1040.14 317.498C1039.02 315.268 1038.45 312.662 1038.45 309.68C1038.45 306.698 1039.02 304.086 1040.14 301.844C1041.28 299.601 1042.89 297.859 1044.95 296.619C1047.02 295.379 1049.47 294.759 1052.28 294.759C1055.1 294.759 1057.55 295.379 1059.61 296.619C1061.68 297.859 1063.28 299.601 1064.41 301.844C1065.55 304.086 1066.12 306.698 1066.12 309.68C1066.12 312.662 1065.55 315.268 1064.41 317.498C1063.28 319.728 1061.68 321.463 1059.61 322.703C1057.55 323.944 1055.1 324.564 1052.28 324.564ZM1052.32 319.114C1053.85 319.114 1055.13 318.694 1056.16 317.855C1057.18 317.003 1057.95 315.863 1058.45 314.435C1058.96 313.006 1059.22 311.415 1059.22 309.661C1059.22 307.895 1058.96 306.297 1058.45 304.869C1057.95 303.428 1057.18 302.282 1056.16 301.43C1055.13 300.578 1053.85 300.152 1052.32 300.152C1050.76 300.152 1049.45 300.578 1048.41 301.43C1047.39 302.282 1046.61 303.428 1046.1 304.869C1045.6 306.297 1045.35 307.895 1045.35 309.661C1045.35 311.415 1045.6 313.006 1046.1 314.435C1046.61 315.863 1047.39 317.003 1048.41 317.855C1049.45 318.694 1050.76 319.114 1052.32 319.114ZM1071.89 324V295.135H1078.49V299.945H1078.79C1079.31 298.279 1080.21 296.995 1081.49 296.093C1082.78 295.178 1084.25 294.721 1085.91 294.721C1086.28 294.721 1086.7 294.74 1087.17 294.777C1087.64 294.803 1088.04 294.846 1088.35 294.909V301.167C1088.06 301.067 1087.61 300.979 1086.98 300.904C1086.37 300.816 1085.77 300.772 1085.19 300.772C1083.95 300.772 1082.84 301.042 1081.85 301.58C1080.87 302.107 1080.1 302.84 1079.54 303.779C1078.97 304.719 1078.69 305.802 1078.69 307.03V324H1071.89ZM1092.87 324V295.135H1099.37V300.039H1099.71C1100.31 298.386 1101.31 297.095 1102.7 296.168C1104.09 295.229 1105.75 294.759 1107.68 294.759C1109.63 294.759 1111.28 295.235 1112.62 296.187C1113.98 297.127 1114.93 298.411 1115.48 300.039H1115.78C1116.42 298.436 1117.5 297.158 1119.01 296.206C1120.54 295.241 1122.35 294.759 1124.44 294.759C1127.1 294.759 1129.27 295.598 1130.95 297.277C1132.62 298.956 1133.46 301.405 1133.46 304.625V324H1126.64V305.677C1126.64 303.886 1126.17 302.576 1125.21 301.75C1124.26 300.91 1123.1 300.49 1121.72 300.49C1120.08 300.49 1118.79 301.004 1117.87 302.031C1116.95 303.046 1116.49 304.368 1116.49 305.997V324H1109.82V305.395C1109.82 303.904 1109.37 302.714 1108.47 301.825C1107.58 300.935 1106.41 300.49 1104.97 300.49C1104 300.49 1103.11 300.741 1102.31 301.242C1101.5 301.731 1100.86 302.426 1100.39 303.328C1099.91 304.218 1099.67 305.258 1099.67 306.448V324H1092.87ZM1148.67 324.583C1146.84 324.583 1145.19 324.257 1143.73 323.605C1142.28 322.941 1141.12 321.964 1140.27 320.674C1139.43 319.383 1139.01 317.792 1139.01 315.9C1139.01 314.272 1139.31 312.925 1139.91 311.86C1140.52 310.795 1141.34 309.943 1142.38 309.304C1143.42 308.665 1144.59 308.183 1145.89 307.857C1147.21 307.519 1148.56 307.275 1149.97 307.124C1151.66 306.949 1153.03 306.792 1154.08 306.654C1155.14 306.504 1155.9 306.279 1156.38 305.978C1156.86 305.665 1157.11 305.182 1157.11 304.531V304.418C1157.11 303.002 1156.69 301.906 1155.85 301.129C1155.01 300.353 1153.8 299.964 1152.22 299.964C1150.56 299.964 1149.24 300.328 1148.26 301.054C1147.29 301.781 1146.64 302.639 1146.3 303.629L1139.95 302.727C1140.45 300.973 1141.28 299.507 1142.43 298.329C1143.58 297.139 1144.99 296.25 1146.66 295.661C1148.33 295.059 1150.17 294.759 1152.19 294.759C1153.58 294.759 1154.96 294.922 1156.34 295.247C1157.72 295.573 1158.98 296.112 1160.12 296.863C1161.26 297.603 1162.17 298.611 1162.86 299.889C1163.56 301.167 1163.91 302.764 1163.91 304.681V324H1157.37V320.035H1157.15C1156.73 320.837 1156.15 321.588 1155.4 322.29C1154.66 322.979 1153.73 323.536 1152.6 323.962C1151.48 324.376 1150.17 324.583 1148.67 324.583ZM1150.44 319.584C1151.8 319.584 1152.99 319.314 1153.99 318.776C1154.99 318.224 1155.76 317.498 1156.3 316.596C1156.85 315.694 1157.13 314.71 1157.13 313.645V310.244C1156.91 310.419 1156.55 310.582 1156.04 310.732C1155.54 310.883 1154.97 311.014 1154.35 311.127C1153.72 311.24 1153.1 311.34 1152.49 311.428C1151.87 311.515 1151.34 311.591 1150.89 311.653C1149.87 311.791 1148.97 312.017 1148.16 312.33C1147.36 312.643 1146.73 313.081 1146.27 313.645C1145.8 314.197 1145.57 314.911 1145.57 315.788C1145.57 317.04 1146.03 317.986 1146.94 318.625C1147.86 319.264 1149.02 319.584 1150.44 319.584ZM1177.56 307.087V324H1170.75V295.135H1177.25V300.039H1177.59C1178.26 298.423 1179.32 297.139 1180.77 296.187C1182.23 295.235 1184.05 294.759 1186.2 294.759C1188.19 294.759 1189.93 295.185 1191.41 296.037C1192.9 296.889 1194.05 298.123 1194.86 299.739C1195.69 301.355 1196.1 303.316 1196.09 305.621V324H1189.28V306.673C1189.28 304.744 1188.78 303.234 1187.78 302.144C1186.79 301.054 1185.42 300.509 1183.66 300.509C1182.47 300.509 1181.41 300.772 1180.49 301.299C1179.57 301.812 1178.85 302.558 1178.33 303.535C1177.81 304.512 1177.56 305.696 1177.56 307.087ZM1215.59 324.564C1212.71 324.564 1210.24 323.931 1208.17 322.666C1206.11 321.4 1204.53 319.653 1203.41 317.423C1202.31 315.18 1201.76 312.599 1201.76 309.68C1201.76 306.748 1202.32 304.161 1203.45 301.919C1204.58 299.664 1206.17 297.91 1208.23 296.657C1210.29 295.391 1212.74 294.759 1215.55 294.759C1217.9 294.759 1219.97 295.191 1221.77 296.055C1223.59 296.907 1225.04 298.116 1226.12 299.682C1227.19 301.236 1227.81 303.053 1227.96 305.132H1221.46C1221.19 303.742 1220.57 302.583 1219.58 301.656C1218.6 300.716 1217.29 300.246 1215.65 300.246C1214.26 300.246 1213.04 300.622 1211.98 301.374C1210.93 302.113 1210.11 303.178 1209.52 304.568C1208.95 305.959 1208.66 307.625 1208.66 309.567C1208.66 311.534 1208.95 313.226 1209.52 314.641C1210.1 316.044 1210.91 317.128 1211.95 317.892C1213 318.644 1214.23 319.02 1215.65 319.02C1216.65 319.02 1217.55 318.832 1218.34 318.456C1219.14 318.068 1219.81 317.51 1220.35 316.784C1220.89 316.057 1221.25 315.174 1221.46 314.134H1227.96C1227.79 316.176 1227.19 317.986 1226.15 319.565C1225.11 321.131 1223.7 322.359 1221.91 323.248C1220.11 324.125 1218.01 324.564 1215.59 324.564ZM1246.32 324.564C1243.43 324.564 1240.93 323.962 1238.82 322.76C1236.73 321.544 1235.12 319.828 1233.99 317.611C1232.87 315.38 1232.3 312.756 1232.3 309.736C1232.3 306.767 1232.87 304.161 1233.99 301.919C1235.13 299.664 1236.73 297.91 1238.77 296.657C1240.81 295.391 1243.21 294.759 1245.97 294.759C1247.74 294.759 1249.42 295.047 1251 295.623C1252.59 296.187 1254 297.064 1255.21 298.254C1256.44 299.444 1257.4 300.96 1258.11 302.802C1258.81 304.631 1259.16 306.811 1259.16 309.342V311.428H1235.5V306.842H1252.64C1252.62 305.539 1252.34 304.381 1251.79 303.366C1251.24 302.338 1250.47 301.53 1249.48 300.941C1248.5 300.353 1247.36 300.058 1246.06 300.058C1244.67 300.058 1243.45 300.396 1242.39 301.073C1241.34 301.737 1240.52 302.614 1239.93 303.704C1239.36 304.781 1239.06 305.965 1239.05 307.256V311.259C1239.05 312.937 1239.36 314.378 1239.97 315.581C1240.58 316.771 1241.44 317.686 1242.55 318.325C1243.65 318.951 1244.94 319.264 1246.42 319.264C1247.41 319.264 1248.3 319.126 1249.1 318.851C1249.91 318.563 1250.6 318.143 1251.19 317.592C1251.78 317.04 1252.22 316.358 1252.52 315.543L1258.88 316.257C1258.47 317.936 1257.71 319.402 1256.58 320.655C1255.47 321.895 1254.04 322.86 1252.3 323.549C1250.56 324.226 1248.56 324.564 1246.32 324.564ZM1272.9 318.738L1272.66 320.805C1272.48 322.384 1272.17 323.987 1271.72 325.616C1271.28 327.257 1270.81 328.767 1270.33 330.145C1269.84 331.523 1269.44 332.607 1269.14 333.396H1264.56C1264.73 332.632 1264.97 331.592 1265.27 330.277C1265.58 328.961 1265.88 327.483 1266.17 325.842C1266.46 324.2 1266.65 322.534 1266.75 320.843L1266.89 318.738H1272.9ZM1292.46 324V295.135H1298.96V300.039H1299.3C1299.9 298.386 1300.9 297.095 1302.29 296.168C1303.68 295.229 1305.34 294.759 1307.27 294.759C1309.22 294.759 1310.87 295.235 1312.21 296.187C1313.56 297.127 1314.51 298.411 1315.07 300.039H1315.37C1316.01 298.436 1317.08 297.158 1318.6 296.206C1320.13 295.241 1321.94 294.759 1324.03 294.759C1326.69 294.759 1328.85 295.598 1330.53 297.277C1332.21 298.956 1333.05 301.405 1333.05 304.625V324H1326.23V305.677C1326.23 303.886 1325.75 302.576 1324.8 301.75C1323.85 300.91 1322.68 300.49 1321.3 300.49C1319.66 300.49 1318.38 301.004 1317.45 302.031C1316.54 303.046 1316.08 304.368 1316.08 305.997V324H1309.41V305.395C1309.41 303.904 1308.96 302.714 1308.06 301.825C1307.17 300.935 1306 300.49 1304.56 300.49C1303.58 300.49 1302.69 300.741 1301.89 301.242C1301.09 301.731 1300.45 302.426 1299.98 303.328C1299.5 304.218 1299.26 305.258 1299.26 306.448V324H1292.46ZM1348.26 324.583C1346.43 324.583 1344.78 324.257 1343.32 323.605C1341.86 322.941 1340.71 321.964 1339.86 320.674C1339.02 319.383 1338.6 317.792 1338.6 315.9C1338.6 314.272 1338.9 312.925 1339.5 311.86C1340.1 310.795 1340.92 309.943 1341.96 309.304C1343 308.665 1344.17 308.183 1345.48 307.857C1346.79 307.519 1348.15 307.275 1349.55 307.124C1351.25 306.949 1352.62 306.792 1353.67 306.654C1354.72 306.504 1355.49 306.279 1355.96 305.978C1356.45 305.665 1356.7 305.182 1356.7 304.531V304.418C1356.7 303.002 1356.28 301.906 1355.44 301.129C1354.6 300.353 1353.39 299.964 1351.81 299.964C1350.14 299.964 1348.82 300.328 1347.84 301.054C1346.88 301.781 1346.23 302.639 1345.89 303.629L1339.54 302.727C1340.04 300.973 1340.87 299.507 1342.02 298.329C1343.17 297.139 1344.58 296.25 1346.25 295.661C1347.91 295.059 1349.76 294.759 1351.77 294.759C1353.16 294.759 1354.55 294.922 1355.93 295.247C1357.3 295.573 1358.56 296.112 1359.7 296.863C1360.84 297.603 1361.76 298.611 1362.45 299.889C1363.15 301.167 1363.5 302.764 1363.5 304.681V324H1356.96V320.035H1356.73C1356.32 320.837 1355.74 321.588 1354.99 322.29C1354.25 322.979 1353.31 323.536 1352.19 323.962C1351.07 324.376 1349.76 324.583 1348.26 324.583ZM1350.02 319.584C1351.39 319.584 1352.57 319.314 1353.58 318.776C1354.58 318.224 1355.35 317.498 1355.89 316.596C1356.44 315.694 1356.71 314.71 1356.71 313.645V310.244C1356.5 310.419 1356.14 310.582 1355.62 310.732C1355.12 310.883 1354.56 311.014 1353.93 311.127C1353.31 311.24 1352.69 311.34 1352.07 311.428C1351.46 311.515 1350.93 311.591 1350.48 311.653C1349.46 311.791 1348.55 312.017 1347.75 312.33C1346.95 312.643 1346.32 313.081 1345.85 313.645C1345.39 314.197 1345.16 314.911 1345.16 315.788C1345.16 317.04 1345.61 317.986 1346.53 318.625C1347.44 319.264 1348.61 319.584 1350.02 319.584ZM1381.05 324.507C1378.78 324.507 1376.75 323.925 1374.96 322.76C1373.17 321.595 1371.76 319.903 1370.72 317.686C1369.68 315.468 1369.16 312.775 1369.16 309.605C1369.16 306.398 1369.68 303.691 1370.73 301.486C1371.8 299.269 1373.23 297.596 1375.04 296.469C1376.84 295.329 1378.85 294.759 1381.07 294.759C1382.76 294.759 1384.15 295.047 1385.24 295.623C1386.33 296.187 1387.2 296.87 1387.84 297.672C1388.47 298.461 1388.97 299.206 1389.32 299.908H1389.6V285.513H1396.42V324H1389.73V319.452H1389.32C1388.97 320.154 1388.46 320.899 1387.8 321.689C1387.13 322.465 1386.26 323.129 1385.17 323.681C1384.08 324.232 1382.71 324.507 1381.05 324.507ZM1382.95 318.926C1384.39 318.926 1385.62 318.538 1386.63 317.761C1387.65 316.972 1388.42 315.875 1388.94 314.472C1389.47 313.069 1389.73 311.434 1389.73 309.567C1389.73 307.701 1389.47 306.078 1388.94 304.7C1388.43 303.322 1387.67 302.251 1386.65 301.486C1385.65 300.722 1384.42 300.34 1382.95 300.34C1381.43 300.34 1380.17 300.735 1379.15 301.524C1378.14 302.313 1377.37 303.403 1376.86 304.794C1376.35 306.185 1376.09 307.776 1376.09 309.567C1376.09 311.371 1376.35 312.981 1376.86 314.397C1377.39 315.8 1378.16 316.909 1379.17 317.723C1380.2 318.525 1381.46 318.926 1382.95 318.926ZM1416.45 324.564C1413.56 324.564 1411.06 323.962 1408.95 322.76C1406.86 321.544 1405.25 319.828 1404.12 317.611C1403 315.38 1402.43 312.756 1402.43 309.736C1402.43 306.767 1403 304.161 1404.12 301.919C1405.26 299.664 1406.86 297.91 1408.9 296.657C1410.94 295.391 1413.34 294.759 1416.09 294.759C1417.87 294.759 1419.55 295.047 1421.13 295.623C1422.72 296.187 1424.13 297.064 1425.34 298.254C1426.57 299.444 1427.53 300.96 1428.23 302.802C1428.94 304.631 1429.29 306.811 1429.29 309.342V311.428H1405.63V306.842H1422.77C1422.75 305.539 1422.47 304.381 1421.92 303.366C1421.37 302.338 1420.6 301.53 1419.61 300.941C1418.63 300.353 1417.49 300.058 1416.19 300.058C1414.8 300.058 1413.58 300.396 1412.52 301.073C1411.47 301.737 1410.65 302.614 1410.06 303.704C1409.49 304.781 1409.19 305.965 1409.18 307.256V311.259C1409.18 312.937 1409.49 314.378 1410.1 315.581C1410.71 316.771 1411.57 317.686 1412.67 318.325C1413.78 318.951 1415.07 319.264 1416.55 319.264C1417.54 319.264 1418.43 319.126 1419.23 318.851C1420.04 318.563 1420.73 318.143 1421.32 317.592C1421.91 317.04 1422.35 316.358 1422.65 315.543L1429.01 316.257C1428.6 317.936 1427.84 319.402 1426.71 320.655C1425.6 321.895 1424.17 322.86 1422.43 323.549C1420.69 324.226 1418.69 324.564 1416.45 324.564ZM1460.95 324.564C1458.05 324.564 1455.55 323.962 1453.45 322.76C1451.36 321.544 1449.75 319.828 1448.62 317.611C1447.49 315.38 1446.93 312.756 1446.93 309.736C1446.93 306.767 1447.49 304.161 1448.62 301.919C1449.76 299.664 1451.35 297.91 1453.39 296.657C1455.44 295.391 1457.83 294.759 1460.59 294.759C1462.37 294.759 1464.05 295.047 1465.63 295.623C1467.22 296.187 1468.62 297.064 1469.84 298.254C1471.06 299.444 1472.03 300.96 1472.73 302.802C1473.43 304.631 1473.78 306.811 1473.78 309.342V311.428H1450.12V306.842H1467.26C1467.25 305.539 1466.97 304.381 1466.42 303.366C1465.87 302.338 1465.1 301.53 1464.11 300.941C1463.13 300.353 1461.99 300.058 1460.69 300.058C1459.29 300.058 1458.07 300.396 1457.02 301.073C1455.97 301.737 1455.15 302.614 1454.56 303.704C1453.98 304.781 1453.69 305.965 1453.68 307.256V311.259C1453.68 312.937 1453.98 314.378 1454.6 315.581C1455.21 316.771 1456.07 317.686 1457.17 318.325C1458.27 318.951 1459.56 319.264 1461.04 319.264C1462.03 319.264 1462.93 319.126 1463.73 318.851C1464.53 318.563 1465.23 318.143 1465.82 317.592C1466.4 317.04 1466.85 316.358 1467.15 315.543L1473.5 316.257C1473.1 317.936 1472.34 319.402 1471.21 320.655C1470.09 321.895 1468.67 322.86 1466.92 323.549C1465.18 324.226 1463.19 324.564 1460.95 324.564ZM1487.85 324.583C1486.02 324.583 1484.37 324.257 1482.9 323.605C1481.45 322.941 1480.3 321.964 1479.44 320.674C1478.61 319.383 1478.19 317.792 1478.19 315.9C1478.19 314.272 1478.49 312.925 1479.09 311.86C1479.69 310.795 1480.51 309.943 1481.55 309.304C1482.59 308.665 1483.76 308.183 1485.06 307.857C1486.38 307.519 1487.74 307.275 1489.14 307.124C1490.83 306.949 1492.2 306.792 1493.26 306.654C1494.31 306.504 1495.07 306.279 1495.55 305.978C1496.04 305.665 1496.28 305.182 1496.28 304.531V304.418C1496.28 303.002 1495.86 301.906 1495.02 301.129C1494.18 300.353 1492.98 299.964 1491.4 299.964C1489.73 299.964 1488.41 300.328 1487.43 301.054C1486.47 301.781 1485.82 302.639 1485.48 303.629L1479.13 302.727C1479.63 300.973 1480.45 299.507 1481.61 298.329C1482.76 297.139 1484.17 296.25 1485.83 295.661C1487.5 295.059 1489.34 294.759 1491.36 294.759C1492.75 294.759 1494.13 294.922 1495.51 295.247C1496.89 295.573 1498.15 296.112 1499.29 296.863C1500.43 297.603 1501.34 298.611 1502.03 299.889C1502.74 301.167 1503.09 302.764 1503.09 304.681V324H1496.55V320.035H1496.32C1495.91 320.837 1495.32 321.588 1494.57 322.29C1493.83 322.979 1492.9 323.536 1491.77 323.962C1490.66 324.376 1489.35 324.583 1487.85 324.583ZM1489.61 319.584C1490.98 319.584 1492.16 319.314 1493.16 318.776C1494.17 318.224 1494.94 317.498 1495.47 316.596C1496.03 315.694 1496.3 314.71 1496.3 313.645V310.244C1496.09 310.419 1495.73 310.582 1495.21 310.732C1494.71 310.883 1494.15 311.014 1493.52 311.127C1492.89 311.24 1492.27 311.34 1491.66 311.428C1491.05 311.515 1490.51 311.591 1490.06 311.653C1489.05 311.791 1488.14 312.017 1487.34 312.33C1486.54 312.643 1485.9 313.081 1485.44 313.645C1484.98 314.197 1484.74 314.911 1484.74 315.788C1484.74 317.04 1485.2 317.986 1486.12 318.625C1487.03 319.264 1488.2 319.584 1489.61 319.584ZM1532.74 302.764L1526.54 303.441C1526.36 302.814 1526.06 302.226 1525.62 301.674C1525.19 301.123 1524.62 300.678 1523.89 300.34C1523.16 300.002 1522.27 299.833 1521.22 299.833C1519.81 299.833 1518.61 300.14 1517.65 300.754C1516.7 301.367 1516.23 302.163 1516.24 303.14C1516.23 303.98 1516.54 304.662 1517.16 305.189C1517.8 305.715 1518.85 306.147 1520.32 306.485L1525.24 307.538C1527.97 308.127 1530 309.06 1531.33 310.338C1532.67 311.616 1533.35 313.288 1533.36 315.355C1533.35 317.172 1532.82 318.776 1531.76 320.166C1530.72 321.544 1529.28 322.622 1527.42 323.399C1525.57 324.175 1523.44 324.564 1521.03 324.564C1517.5 324.564 1514.66 323.825 1512.5 322.346C1510.35 320.855 1509.06 318.782 1508.65 316.126L1515.28 315.487C1515.58 316.79 1516.22 317.773 1517.2 318.437C1518.18 319.101 1519.45 319.433 1521.01 319.433C1522.63 319.433 1523.93 319.101 1524.9 318.437C1525.89 317.773 1526.39 316.953 1526.39 315.976C1526.39 315.149 1526.07 314.466 1525.43 313.927C1524.8 313.388 1523.83 312.975 1522.5 312.687L1517.57 311.653C1514.81 311.077 1512.76 310.106 1511.43 308.74C1510.1 307.362 1509.44 305.621 1509.46 303.516C1509.44 301.737 1509.93 300.196 1510.9 298.893C1511.89 297.578 1513.27 296.563 1515.02 295.849C1516.79 295.122 1518.82 294.759 1521.13 294.759C1524.51 294.759 1527.17 295.479 1529.11 296.92C1531.07 298.361 1532.28 300.309 1532.74 302.764ZM1543.2 334.825C1542.27 334.825 1541.41 334.749 1540.62 334.599C1539.85 334.461 1539.23 334.298 1538.76 334.11L1540.34 328.811C1541.33 329.099 1542.22 329.237 1542.99 329.224C1543.77 329.212 1544.45 328.968 1545.04 328.491C1545.64 328.028 1546.15 327.251 1546.56 326.161L1547.15 324.601L1536.68 295.135H1543.89L1550.55 316.934H1550.85L1557.52 295.135H1564.75L1553.2 327.495C1552.66 329.024 1551.94 330.333 1551.05 331.423C1550.16 332.526 1549.07 333.365 1547.78 333.941C1546.51 334.53 1544.98 334.825 1543.2 334.825Z" fill="white" fill-opacity="0.8"/> +<path d="M1023.19 179V107.785H1051.29C1056.69 107.785 1061.29 108.817 1065.09 110.88C1068.89 112.92 1071.79 115.76 1073.78 119.4C1075.8 123.016 1076.81 127.189 1076.81 131.918C1076.81 136.647 1075.79 140.82 1073.75 144.436C1071.71 148.052 1068.75 150.869 1064.88 152.886C1061.03 154.902 1056.37 155.911 1050.9 155.911H1033V143.845H1048.47C1051.37 143.845 1053.75 143.346 1055.63 142.35C1057.53 141.33 1058.95 139.927 1059.87 138.142C1060.83 136.334 1061.3 134.259 1061.3 131.918C1061.3 129.553 1060.83 127.49 1059.87 125.728C1058.95 123.943 1057.53 122.564 1055.63 121.59C1053.73 120.593 1051.32 120.095 1048.4 120.095H1038.25V179H1023.19ZM1100.11 180.008C1096.7 180.008 1093.66 179.417 1091 178.235C1088.33 177.03 1086.22 175.256 1084.67 172.915C1083.14 170.55 1082.37 167.606 1082.37 164.083C1082.37 161.115 1082.92 158.623 1084.01 156.606C1085.1 154.59 1086.58 152.967 1088.46 151.738C1090.34 150.51 1092.47 149.582 1094.86 148.956C1097.27 148.33 1099.79 147.89 1102.44 147.635C1105.54 147.31 1108.05 147.009 1109.95 146.731C1111.85 146.43 1113.23 145.989 1114.09 145.41C1114.94 144.83 1115.37 143.972 1115.37 142.836V142.628C1115.37 140.425 1114.68 138.722 1113.29 137.516C1111.92 136.311 1109.97 135.708 1107.44 135.708C1104.78 135.708 1102.66 136.299 1101.08 137.481C1099.5 138.64 1098.46 140.101 1097.95 141.863L1084.25 140.75C1084.95 137.505 1086.31 134.7 1088.35 132.335C1090.39 129.947 1093.02 128.116 1096.25 126.841C1099.49 125.543 1103.25 124.894 1107.51 124.894C1110.48 124.894 1113.32 125.241 1116.03 125.937C1118.77 126.632 1121.19 127.71 1123.3 129.171C1125.43 130.631 1127.11 132.509 1128.34 134.804C1129.57 137.076 1130.19 139.8 1130.19 142.975V179H1116.14V171.593H1115.72C1114.86 173.263 1113.71 174.735 1112.28 176.01C1110.84 177.261 1109.11 178.247 1107.1 178.965C1105.08 179.661 1102.75 180.008 1100.11 180.008ZM1104.35 169.785C1106.53 169.785 1108.45 169.356 1110.12 168.499C1111.79 167.618 1113.1 166.435 1114.05 164.952C1115 163.468 1115.48 161.787 1115.48 159.91V154.242C1115.01 154.543 1114.38 154.821 1113.56 155.076C1112.78 155.308 1111.88 155.528 1110.89 155.737C1109.89 155.922 1108.89 156.096 1107.9 156.259C1106.9 156.398 1105.99 156.525 1105.18 156.641C1103.45 156.896 1101.93 157.302 1100.63 157.858C1099.33 158.415 1098.32 159.168 1097.6 160.118C1096.88 161.046 1096.53 162.205 1096.53 163.596C1096.53 165.613 1097.26 167.154 1098.72 168.22C1100.2 169.264 1102.08 169.785 1104.35 169.785ZM1156.49 107.785V179H1141.68V107.785H1156.49ZM1192.7 180.043C1187.2 180.043 1182.47 178.93 1178.51 176.705C1174.57 174.456 1171.53 171.28 1169.4 167.177C1167.27 163.051 1166.2 158.171 1166.2 152.538C1166.2 147.044 1167.27 142.222 1169.4 138.073C1171.53 133.923 1174.53 130.689 1178.41 128.371C1182.3 126.053 1186.87 124.894 1192.11 124.894C1195.63 124.894 1198.91 125.462 1201.95 126.598C1205.01 127.71 1207.67 129.391 1209.95 131.64C1212.24 133.888 1214.03 136.716 1215.3 140.124C1216.58 143.509 1217.21 147.473 1217.21 152.016V156.085H1172.11V146.905H1203.27C1203.27 144.772 1202.81 142.883 1201.88 141.237C1200.95 139.591 1199.66 138.304 1198.02 137.377C1196.4 136.427 1194.51 135.951 1192.35 135.951C1190.1 135.951 1188.11 136.473 1186.37 137.516C1184.65 138.536 1183.31 139.915 1182.34 141.654C1181.36 143.37 1180.86 145.282 1180.84 147.392V156.12C1180.84 158.762 1181.33 161.046 1182.3 162.97C1183.3 164.894 1184.7 166.378 1186.51 167.421C1188.32 168.464 1190.46 168.985 1192.94 168.985C1194.59 168.985 1196.09 168.754 1197.46 168.29C1198.83 167.826 1200 167.131 1200.97 166.204C1201.95 165.276 1202.69 164.14 1203.2 162.796L1216.9 163.7C1216.2 166.992 1214.78 169.866 1212.62 172.324C1210.49 174.758 1207.73 176.659 1204.35 178.026C1200.99 179.371 1197.1 180.043 1192.7 180.043ZM1255.29 125.589V136.716H1223.12V125.589H1255.29ZM1230.43 112.793H1245.24V162.587C1245.24 163.955 1245.45 165.021 1245.87 165.786C1246.28 166.528 1246.86 167.05 1247.6 167.351C1248.37 167.652 1249.25 167.803 1250.25 167.803C1250.94 167.803 1251.64 167.745 1252.33 167.629C1253.03 167.49 1253.56 167.386 1253.93 167.316L1256.26 178.339C1255.52 178.571 1254.48 178.838 1253.13 179.139C1251.79 179.464 1250.15 179.661 1248.23 179.73C1244.66 179.869 1241.53 179.394 1238.84 178.305C1236.18 177.215 1234.1 175.523 1232.62 173.228C1231.13 170.933 1230.4 168.035 1230.43 164.535V112.793ZM1293.35 125.589V136.716H1261.18V125.589H1293.35ZM1268.49 112.793H1283.3V162.587C1283.3 163.955 1283.51 165.021 1283.92 165.786C1284.34 166.528 1284.92 167.05 1285.66 167.351C1286.43 167.652 1287.31 167.803 1288.31 167.803C1289 167.803 1289.7 167.745 1290.39 167.629C1291.09 167.49 1291.62 167.386 1291.99 167.316L1294.32 178.339C1293.58 178.571 1292.54 178.838 1291.19 179.139C1289.85 179.464 1288.21 179.661 1286.29 179.73C1282.72 179.869 1279.59 179.394 1276.9 178.305C1274.23 177.215 1272.16 175.523 1270.68 173.228C1269.19 170.933 1268.46 168.035 1268.49 164.535V112.793ZM1326.76 180.043C1321.27 180.043 1316.54 178.93 1312.58 176.705C1308.64 174.456 1305.6 171.28 1303.47 167.177C1301.33 163.051 1300.27 158.171 1300.27 152.538C1300.27 147.044 1301.33 142.222 1303.47 138.073C1305.6 133.923 1308.6 130.689 1312.47 128.371C1316.37 126.053 1320.93 124.894 1326.17 124.894C1329.7 124.894 1332.98 125.462 1336.01 126.598C1339.07 127.71 1341.74 129.391 1344.01 131.64C1346.31 133.888 1348.09 136.716 1349.37 140.124C1350.64 143.509 1351.28 147.473 1351.28 152.016V156.085H1306.18V146.905H1337.34C1337.34 144.772 1336.87 142.883 1335.94 141.237C1335.02 139.591 1333.73 138.304 1332.08 137.377C1330.46 136.427 1328.57 135.951 1326.42 135.951C1324.17 135.951 1322.17 136.473 1320.44 137.516C1318.72 138.536 1317.38 139.915 1316.4 141.654C1315.43 143.37 1314.93 145.282 1314.91 147.392V156.12C1314.91 158.762 1315.39 161.046 1316.37 162.97C1317.36 164.894 1318.77 166.378 1320.57 167.421C1322.38 168.464 1324.53 168.985 1327.01 168.985C1328.65 168.985 1330.16 168.754 1331.53 168.29C1332.9 167.826 1334.07 167.131 1335.04 166.204C1336.01 165.276 1336.76 164.14 1337.27 162.796L1350.97 163.7C1350.27 166.992 1348.84 169.866 1346.69 172.324C1344.56 174.758 1341.8 176.659 1338.41 178.026C1335.05 179.371 1331.17 180.043 1326.76 180.043Z" fill="white"/> +<path d="M964.767 117.077C966.204 115.769 966.257 113.525 964.883 112.151L953.026 100.294C951.587 98.8549 949.216 98.9908 947.951 100.585L917.168 139.368C916.123 140.684 916.194 142.566 917.336 143.799L923.305 150.245C924.575 151.617 926.713 151.708 928.096 150.45L964.767 117.077ZM904.952 146.703C895.341 146.703 893.006 154.651 892.943 164.581C892.941 164.861 892.907 165.148 892.833 165.419C890.907 172.498 886.313 175.326 882.208 176.456C879.525 177.194 878.009 180.287 880.118 182.101C885.429 186.67 892.356 189.407 899.08 189.407C912.057 189.407 922.568 178.488 922.568 165.004C922.568 154.878 914.699 146.703 904.952 146.703Z" fill="white"/> +</svg> diff --git a/.erb/mocks/fileMock.js b/.erb/mocks/fileMock.js new file mode 100644 index 00000000..602eb23e --- /dev/null +++ b/.erb/mocks/fileMock.js @@ -0,0 +1 @@ +export default 'test-file-stub'; diff --git a/.erb/scripts/.eslintrc b/.erb/scripts/.eslintrc new file mode 100644 index 00000000..35dc618d --- /dev/null +++ b/.erb/scripts/.eslintrc @@ -0,0 +1,8 @@ +{ + "rules": { + "no-console": "off", + "global-require": "off", + "import/no-dynamic-require": "off", + "import/no-extraneous-dependencies": "off" + } +} diff --git a/.erb/scripts/check-build-exists.ts b/.erb/scripts/check-build-exists.ts new file mode 100644 index 00000000..64992957 --- /dev/null +++ b/.erb/scripts/check-build-exists.ts @@ -0,0 +1,24 @@ +// Check if the renderer and main bundles are built +import path from 'path'; +import chalk from 'chalk'; +import fs from 'fs'; +import webpackPaths from '../configs/webpack.paths'; + +const mainPath = path.join(webpackPaths.distMainPath, 'main.js'); +const rendererPath = path.join(webpackPaths.distRendererPath, 'renderer.js'); + +if (!fs.existsSync(mainPath)) { + throw new Error( + chalk.whiteBright.bgRed.bold( + 'The main process is not built yet. Build it by running "npm run build:main"', + ), + ); +} + +if (!fs.existsSync(rendererPath)) { + throw new Error( + chalk.whiteBright.bgRed.bold( + 'The renderer process is not built yet. Build it by running "npm run build:renderer"', + ), + ); +} diff --git a/.erb/scripts/check-native-dep.js b/.erb/scripts/check-native-dep.js new file mode 100644 index 00000000..62869816 --- /dev/null +++ b/.erb/scripts/check-native-dep.js @@ -0,0 +1,54 @@ +import fs from 'fs'; +import chalk from 'chalk'; +import { execSync } from 'child_process'; +import { dependencies } from '../../package.json'; + +if (dependencies) { + const dependenciesKeys = Object.keys(dependencies); + const nativeDeps = fs + .readdirSync('node_modules') + .filter((folder) => fs.existsSync(`node_modules/${folder}/binding.gyp`)); + if (nativeDeps.length === 0) { + process.exit(0); + } + try { + // Find the reason for why the dependency is installed. If it is installed + // because of a devDependency then that is okay. Warn when it is installed + // because of a dependency + const { dependencies: dependenciesObject } = JSON.parse( + execSync(`npm ls ${nativeDeps.join(' ')} --json`).toString(), + ); + const rootDependencies = Object.keys(dependenciesObject); + const filteredRootDependencies = rootDependencies.filter((rootDependency) => + dependenciesKeys.includes(rootDependency), + ); + if (filteredRootDependencies.length > 0) { + const plural = filteredRootDependencies.length > 1; + console.log(` + ${chalk.whiteBright.bgYellow.bold( + 'Webpack does not work with native dependencies.', + )} +${chalk.bold(filteredRootDependencies.join(', '))} ${ + plural ? 'are native dependencies' : 'is a native dependency' + } and should be installed inside of the "./release/app" folder. + First, uninstall the packages from "./package.json": +${chalk.whiteBright.bgGreen.bold('npm uninstall your-package')} + ${chalk.bold( + 'Then, instead of installing the package to the root "./package.json":', + )} +${chalk.whiteBright.bgRed.bold('npm install your-package')} + ${chalk.bold('Install the package to "./release/app/package.json"')} +${chalk.whiteBright.bgGreen.bold( + 'cd ./release/app && npm install your-package', +)} + Read more about native dependencies at: +${chalk.bold( + 'https://electron-react-boilerplate.js.org/docs/adding-dependencies/#module-structure', +)} + `); + process.exit(1); + } + } catch (e) { + console.log('Native dependencies could not be checked'); + } +} diff --git a/.erb/scripts/check-node-env.js b/.erb/scripts/check-node-env.js new file mode 100644 index 00000000..6bf674ba --- /dev/null +++ b/.erb/scripts/check-node-env.js @@ -0,0 +1,16 @@ +import chalk from 'chalk'; + +export default function checkNodeEnv(expectedEnv) { + if (!expectedEnv) { + throw new Error('"expectedEnv" not set'); + } + + if (process.env.NODE_ENV !== expectedEnv) { + console.log( + chalk.whiteBright.bgRed.bold( + `"process.env.NODE_ENV" must be "${expectedEnv}" to use this webpack config`, + ), + ); + process.exit(2); + } +} diff --git a/.erb/scripts/check-port-in-use.js b/.erb/scripts/check-port-in-use.js new file mode 100644 index 00000000..398cbc17 --- /dev/null +++ b/.erb/scripts/check-port-in-use.js @@ -0,0 +1,16 @@ +import chalk from 'chalk'; +import detectPort from 'detect-port'; + +const port = process.env.PORT || '1212'; + +detectPort(port, (_err, availablePort) => { + if (port !== String(availablePort)) { + throw new Error( + chalk.whiteBright.bgRed.bold( + `Port "${port}" on "localhost" is already in use. Please use another port. ex: PORT=4343 npm start`, + ), + ); + } else { + process.exit(0); + } +}); diff --git a/.erb/scripts/clean.js b/.erb/scripts/clean.js new file mode 100644 index 00000000..2c7b3aea --- /dev/null +++ b/.erb/scripts/clean.js @@ -0,0 +1,13 @@ +import { rimrafSync } from 'rimraf'; +import fs from 'fs'; +import webpackPaths from '../configs/webpack.paths'; + +const foldersToRemove = [ + webpackPaths.distPath, + webpackPaths.buildPath, + webpackPaths.dllPath, +]; + +foldersToRemove.forEach((folder) => { + if (fs.existsSync(folder)) rimrafSync(folder); +}); diff --git a/.erb/scripts/delete-source-maps.js b/.erb/scripts/delete-source-maps.js new file mode 100644 index 00000000..d14519cd --- /dev/null +++ b/.erb/scripts/delete-source-maps.js @@ -0,0 +1,15 @@ +import fs from 'fs'; +import path from 'path'; +import { rimrafSync } from 'rimraf'; +import webpackPaths from '../configs/webpack.paths'; + +export default function deleteSourceMaps() { + if (fs.existsSync(webpackPaths.distMainPath)) + rimrafSync(path.join(webpackPaths.distMainPath, '*.js.map'), { + glob: true, + }); + if (fs.existsSync(webpackPaths.distRendererPath)) + rimrafSync(path.join(webpackPaths.distRendererPath, '*.js.map'), { + glob: true, + }); +} diff --git a/.erb/scripts/electron-rebuild.js b/.erb/scripts/electron-rebuild.js new file mode 100644 index 00000000..0bea3279 --- /dev/null +++ b/.erb/scripts/electron-rebuild.js @@ -0,0 +1,20 @@ +import { execSync } from 'child_process'; +import fs from 'fs'; +import { dependencies } from '../../release/app/package.json'; +import webpackPaths from '../configs/webpack.paths'; + +if ( + Object.keys(dependencies || {}).length > 0 && + fs.existsSync(webpackPaths.appNodeModulesPath) +) { + const electronRebuildCmd = + '../../node_modules/.bin/electron-rebuild --force --types prod,dev,optional --module-dir .'; + const cmd = + process.platform === 'win32' + ? electronRebuildCmd.replace(/\//g, '\\') + : electronRebuildCmd; + execSync(cmd, { + cwd: webpackPaths.appPath, + stdio: 'inherit', + }); +} diff --git a/.erb/scripts/link-modules.ts b/.erb/scripts/link-modules.ts new file mode 100644 index 00000000..6cc31e66 --- /dev/null +++ b/.erb/scripts/link-modules.ts @@ -0,0 +1,9 @@ +import fs from 'fs'; +import webpackPaths from '../configs/webpack.paths'; + +const { srcNodeModulesPath } = webpackPaths; +const { appNodeModulesPath } = webpackPaths; + +if (!fs.existsSync(srcNodeModulesPath) && fs.existsSync(appNodeModulesPath)) { + fs.symlinkSync(appNodeModulesPath, srcNodeModulesPath, 'junction'); +} diff --git a/.erb/scripts/notarize.js b/.erb/scripts/notarize.js new file mode 100644 index 00000000..097ff35b --- /dev/null +++ b/.erb/scripts/notarize.js @@ -0,0 +1,32 @@ +const { notarize } = require('@electron/notarize'); +const { build } = require('../../package.json'); + +exports.default = async function notarizeMacos(context) { + const { electronPlatformName, appOutDir } = context; + if (electronPlatformName !== 'darwin') { + return; + } + + if (process.env.CI !== 'true') { + console.warn('Skipping notarizing step. Packaging is not running in CI'); + return; + } + + if ( + !('APPLE_ID' in process.env && 'APPLE_APP_SPECIFIC_PASSWORD' in process.env) + ) { + console.warn( + 'Skipping notarizing step. APPLE_ID and APPLE_APP_SPECIFIC_PASSWORD env variables must be set', + ); + return; + } + + const appName = context.packager.appInfo.productFilename; + + await notarize({ + appBundleId: build.appId, + appPath: `${appOutDir}/${appName}.app`, + appleId: process.env.APPLE_ID, + appleIdPassword: process.env.APPLE_APP_SPECIFIC_PASSWORD, + }); +}; diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..84cf3b6b --- /dev/null +++ b/.eslintignore @@ -0,0 +1,35 @@ +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Coverage directory used by tools like istanbul +coverage +.eslintcache + +# Dependency directory +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git +node_modules + +# OSX +.DS_Store + +release/app/dist +release/build +.erb/dll + +.idea +npm-debug.log.* +*.css.d.ts +*.sass.d.ts +*.scss.d.ts + +# eslint ignores hidden directories by default: +# https://github.com/eslint/eslint/issues/8429 +*.ejs +!.erb + diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..37a4a067 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,49 @@ +module.exports = { + extends: 'erb', + plugins: ['@typescript-eslint'], + rules: { + 'consistent-return': 'off', + 'no-useless-return': 'warn', + 'react/react-in-jsx-scope': 'off', + 'react/jsx-filename-extension': 'off', + 'react/require-default-props': 'off', + 'react/jsx-props-no-spreading': 'off', + 'react/jsx-no-useless-fragment': 'off', + // A temporary hack related to IDE not resolving correct package.json + 'import/no-extraneous-dependencies': 'off', + 'import/prefer-default-export': 'off', + 'import/extensions': 'off', + 'import/no-unresolved': 'off', + 'import/no-import-module-exports': 'off', + 'no-shadow': 'off', + '@typescript-eslint/no-shadow': 'error', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': [ + 'error', + { + // Ignore unused variables that start with an underscore + vars: 'all', + varsIgnorePattern: '^_', + args: 'after-used', + argsIgnorePattern: '^_', + }, + ], + }, + parserOptions: { + ecmaVersion: 2022, + sourceType: 'module', + }, + settings: { + 'import/resolver': { + // See https://github.com/benmosher/eslint-plugin-import/issues/1396#issuecomment-575727774 for line below + node: {}, + webpack: { + config: require.resolve('./.erb/configs/webpack.config.eslint.ts'), + }, + typescript: {}, + }, + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + }, +}; diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..20570f2f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,12 @@ +* text eol=lf +*.exe binary +*.png binary +*.jpg binary +*.jpeg binary +*.ico binary +*.icns binary +*.eot binary +*.otf binary +*.ttf binary +*.woff binary +*.woff2 binary diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..1981d881 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: lacymorrow +patreon: lacymorrow +open_collective: crossover +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: https://www.buymeacoffee.com/lm diff --git a/.github/ISSUE_TEMPLATE/1-Bug_report.md b/.github/ISSUE_TEMPLATE/1-Bug_report.md new file mode 100644 index 00000000..b4fda541 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1-Bug_report.md @@ -0,0 +1,23 @@ +--- +name: Bug report +about: You're having technical issues. 🐞 +labels: 'bug' +--- + +## Expected Behavior + +<!--- What should have happened? --> + +## Current Behavior + +<!--- What went wrong? --> + +<!--- +❗️❗️ Also, please consider donating (https://www.patreon.com/lacymorrow) ❗️❗️ + +Donations will ensure the following: + +🔨 Long term maintenance of the project +🛣 Progress on the roadmap +🐛 Quick responses to bug reports and help requests + --> diff --git a/.github/ISSUE_TEMPLATE/2-Question.md b/.github/ISSUE_TEMPLATE/2-Question.md new file mode 100644 index 00000000..08795cf7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2-Question.md @@ -0,0 +1,19 @@ +--- +name: Question +about: Ask a question.❓ +labels: 'question' +--- + +## Summary + +<!-- What do you need help with? --> + +<!--- +❗️❗️ Also, please consider donating (https://www.patreon.com/lacymorrow) ❗️❗️ + +Donations will ensure the following: + +🔨 Long term maintenance of the project +🛣 Progress on the roadmap +🐛 Quick responses to bug reports and help requests + --> diff --git a/.github/ISSUE_TEMPLATE/3-Feature_request.md b/.github/ISSUE_TEMPLATE/3-Feature_request.md new file mode 100644 index 00000000..23e6eea6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3-Feature_request.md @@ -0,0 +1,15 @@ +--- +name: Feature request +about: You want something added. 🎉 +labels: 'enhancement' +--- + +<!--- +❗️❗️ Also, please consider donating (https://www.patreon.com/lacymorrow) ❗️❗️ + +Donations will ensure the following: + +🔨 Long term maintenance of the project +🛣 Progress on the roadmap +🐛 Quick responses to bug reports and help requests + --> diff --git a/.github/config.yml b/.github/config.yml new file mode 100644 index 00000000..3708b464 --- /dev/null +++ b/.github/config.yml @@ -0,0 +1,6 @@ +requiredHeaders: + - Prerequisites + - Expected Behavior + - Current Behavior + - Possible Solution + - Your Environment diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 00000000..81990a89 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,17 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 90 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 30 +# Issues with these labels will never be considered stale +exemptLabels: + - discussion + - security +# Label to use when marking an issue as stale +staleLabel: wontfix +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml new file mode 100644 index 00000000..ab4a3473 --- /dev/null +++ b/.github/workflows/build-linux.yml @@ -0,0 +1,45 @@ +name: Build Linux + +on: + push: + branches: + - main + +jobs: + build-linux: + # To enable auto publishing to github, update your electron publisher + # config in package.json > "build" and remove the conditional below + if: ${{ github.repository_owner == 'lacymorrow' }} + + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ubuntu-latest] + + steps: + - name: Checkout git repo + uses: actions/checkout@v3 + + - name: Install Node and NPM + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: npm + + - name: Install and build + run: | + npm install + npm run postinstall + npm run package:linux + + - name: Archive build artifacts + uses: actions/upload-artifact@v3 + with: + name: release-linux + path: | + release/build + !release/**/builder* + !release/**/linux* + !release/**/mac* + !release/**/win* diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..5359b9df --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,45 @@ +name: Build + +on: + push: + branches: + - main + +jobs: + build-mac-windows: + # To enable auto publishing to github, update your electron publisher + # config in package.json > "build" and remove the conditional below + if: ${{ github.repository_owner == 'lacymorrow' }} + + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [macos-latest] + + steps: + - name: Checkout git repo + uses: actions/checkout@v3 + + - name: Install Node and NPM + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: npm + + - name: Install and build + run: | + npm install + npm run postinstall + npm run package:mw + + - name: Archive build artifacts + uses: actions/upload-artifact@v3 + with: + name: release + path: | + release/build + !release/**/builder* + !release/**/linux* + !release/**/mac* + !release/**/win* diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..0d8b5cfe --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,72 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ "main" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "main" ] + schedule: + - cron: '44 16 * * 4' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'javascript' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..d3fe0e2f --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,46 @@ +name: Publish + +on: + push: + branches: + - main + +jobs: + publish: + # To enable auto publishing to github, update your electron publisher + # config in package.json > "build" and remove the conditional below + if: ${{ github.repository_owner == 'lacymorrow' }} + + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [macos-latest] + + steps: + - name: Checkout git repo + uses: actions/checkout@v3 + + - name: Install Node and NPM + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: npm + + - name: Install and build + run: | + npm install + npm run postinstall + npm run build + + - name: Publish releases + env: + # These values are used for auto updates signing + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_ID_PASS }} + CSC_LINK: ${{ secrets.CSC_LINK }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + # This is used for uploading release assets to github + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + npm exec electron-builder -- --publish always --win --mac --linux diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..c8ea922c --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,34 @@ +name: Test + +on: [push, pull_request] + +jobs: + test: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [macos-latest, windows-latest, ubuntu-latest] + + steps: + - name: Check out Git repository + uses: actions/checkout@v3 + + - name: Install Node.js and NPM + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: npm + + - name: npm install + run: | + npm install + + - name: npm test + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + npm run package + npm run lint + npm exec tsc + npm test diff --git a/.gitignore b/.gitignore index 1e97a119..da134307 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,3 @@ -# Confidential -env.json -secrets -.secrets -secrets.* - # Logs logs *.log @@ -13,27 +7,23 @@ pids *.pid *.seed -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - # Coverage directory used by tools like istanbul coverage - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release +.eslintcache # Dependency directory -# Deployed apps should consider commenting this line out: -# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git node_modules + +# OSX .DS_Store -# meteor-desktop -version.desktop -.desktop-installer -.desktop_node_modules -package-lock.json -yarn.lock +release/app/dist +release/build +.erb/dll + +.idea +npm-debug.log.* +*.css.d.ts +*.sass.d.ts +*.scss.d.ts diff --git a/.meteor/.finished-upgraders b/.meteor/.finished-upgraders deleted file mode 100644 index 4538749a..00000000 --- a/.meteor/.finished-upgraders +++ /dev/null @@ -1,18 +0,0 @@ -# This file contains information which helps Meteor properly upgrade your -# app when you run 'meteor update'. You should check it into version control -# with your project. - -notices-for-0.9.0 -notices-for-0.9.1 -0.9.4-platform-file -notices-for-facebook-graph-api-2 -1.2.0-standard-minifiers-package -1.2.0-meteor-platform-split -1.2.0-cordova-changes -1.2.0-breaking-changes -1.3.0-split-minifiers-package -1.4.0-remove-old-dev-bundle-link -1.4.1-add-shell-server-package -1.4.3-split-account-service-packages -1.5-add-dynamic-import-package -1.7-split-underscore-from-meteor-base diff --git a/.meteor/.gitignore b/.meteor/.gitignore deleted file mode 100644 index 5f1ac4cf..00000000 --- a/.meteor/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -local -desktop-build \ No newline at end of file diff --git a/.meteor/.id b/.meteor/.id deleted file mode 100644 index 9a140d75..00000000 --- a/.meteor/.id +++ /dev/null @@ -1,7 +0,0 @@ -# This file contains a token that is unique to your project. -# Check it into your repository along with the rest of this directory. -# It can be used for purposes such as: -# - ensuring you don't accidentally deploy one app on top of another -# - providing package authors with aggregated statistics - -frxxsxxq809drueom9 diff --git a/.meteor/packages b/.meteor/packages deleted file mode 100644 index 49512e04..00000000 --- a/.meteor/packages +++ /dev/null @@ -1,25 +0,0 @@ -# Meteor packages used by this project, one per line. -# Check this file (and the other files in this directory) into your repository. -# -# 'meteor add' and 'meteor remove' will edit this file for you, -# but you can also edit it by hand. - -less -nemo64:bootstrap -meteor-base -mobile-experience -mongo -blaze-html-templates -session -tracker -logging -reload -ejson -spacebars -check -standard-minifier-css -standard-minifier-js -shell-server -dynamic-import -underscore -ecmascript diff --git a/.meteor/platforms b/.meteor/platforms deleted file mode 100644 index 81ae7012..00000000 --- a/.meteor/platforms +++ /dev/null @@ -1,3 +0,0 @@ -browser -ios -server diff --git a/.meteor/release b/.meteor/release deleted file mode 100644 index 97064e19..00000000 --- a/.meteor/release +++ /dev/null @@ -1 +0,0 @@ -METEOR@1.8.1 diff --git a/.meteor/versions b/.meteor/versions deleted file mode 100644 index 25e90604..00000000 --- a/.meteor/versions +++ /dev/null @@ -1,81 +0,0 @@ -allow-deny@1.1.0 -autoupdate@1.6.0 -babel-compiler@7.3.4 -babel-runtime@1.3.0 -base64@1.0.12 -binary-heap@1.0.11 -blaze@2.3.3 -blaze-html-templates@1.1.2 -blaze-tools@1.0.10 -boilerplate-generator@1.6.0 -caching-compiler@1.2.1 -caching-html-compiler@1.1.3 -callback-hook@1.1.0 -check@1.3.1 -ddp@1.4.0 -ddp-client@2.3.3 -ddp-common@1.4.0 -ddp-server@2.3.0 -deps@1.0.12 -diff-sequence@1.1.1 -dynamic-import@0.5.1 -ecmascript@0.12.7 -ecmascript-runtime@0.7.0 -ecmascript-runtime-client@0.8.0 -ecmascript-runtime-server@0.7.1 -ejson@1.1.0 -es5-shim@4.8.0 -fetch@0.1.1 -geojson-utils@1.0.10 -hot-code-push@1.0.4 -html-tools@1.0.11 -htmljs@1.0.11 -id-map@1.1.0 -inter-process-messaging@0.1.0 -jquery@1.11.11 -launch-screen@1.1.1 -less@2.8.0 -livedata@1.0.18 -logging@1.1.20 -meteor@1.9.3 -meteor-base@1.4.0 -minifier-css@1.4.2 -minifier-js@2.4.1 -minimongo@1.4.5 -mobile-experience@1.0.5 -mobile-status-bar@1.0.14 -modern-browsers@0.1.4 -modules@0.13.0 -modules-runtime@0.10.3 -mongo@1.6.3 -mongo-decimal@0.1.1 -mongo-dev-server@1.1.0 -mongo-id@1.0.7 -nemo64:bootstrap@3.3.5_3 -nemo64:bootstrap-data@3.3.5 -npm-mongo@3.1.2 -observe-sequence@1.0.16 -ordered-dict@1.1.0 -promise@0.11.2 -random@1.1.0 -reactive-dict@1.3.0 -reactive-var@1.0.11 -reload@1.3.0 -retry@1.1.0 -routepolicy@1.1.0 -session@1.2.0 -shell-server@0.4.0 -socket-stream-client@0.2.2 -spacebars@1.0.15 -spacebars-compiler@1.1.3 -standard-minifier-css@1.5.3 -standard-minifier-js@2.4.1 -templating@1.3.2 -templating-compiler@1.3.3 -templating-runtime@1.3.2 -templating-tools@1.1.2 -tracker@1.2.0 -ui@1.0.13 -underscore@1.0.10 -webapp@1.7.4 -webapp-hashing@1.0.9 diff --git a/.secrets b/.secrets deleted file mode 100644 index 2f0ebef7..00000000 --- a/.secrets +++ /dev/null @@ -1,4 +0,0 @@ -{ - tmdb_key: '9d2bff12ed955c7f1f74b83187f188ae', - omdb_key: 'e0341ca3' -} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 92e547c3..00000000 --- a/.travis.yml +++ /dev/null @@ -1,60 +0,0 @@ -matrix: - include: - - os: osx - osx_image: xcode10.2 - language: node_js - node_js: '12' - env: - - ELECTRON_CACHE=$HOME/.cache/electron - - ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder - - - os: linux - services: xvfb - language: generic - - cache: - directories: - - node_modules - - $HOME/.cache/electron - - $HOME/.cache/electron-builder - - script: - - | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start - sleep 3 - fi - - node --version - npm --version - npm install - npm test - - before_cache: - - rm -rf $HOME/.cache/electron-builder/wine - - notifications: - email: - on_success: never - on_failure: change - - deploy: - provider: releases - api_key: - secure: QAy6AN+BIMV7yntJz9azJLpN11yC4fDHtsjg1Mgaa2oJ3oCake3fB9dvd9akEXaXEmwFbAmlV+E549Tv7/ECKgjY9un+54ySSKFUwtuyGHk3ZKoYh8+XW1O7aNBoNmnd1ci8soXyu5GlkrWD6U36Heth2J7W0YxR/qmFDYZSD3s= - file_glob: true - file: - - .desktop-installer/*.AppImage - - .desktop-installer/mac/*.dmg - - .desktop-installer/mac/*.zip - - .desktop-installer/win/*.exe - - .desktop-installer/win/*.nupkg - - .desktop-installer/win-ia32/*.exe - - .desktop-installer/win-ia32/*.nupkg - skip_cleanup: true - on: - repo: lacymorrow/cinematic - branch: release - tags: true - diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..d9165248 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["dbaeumer.vscode-eslint", "EditorConfig.EditorConfig"] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..7494aabb --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,30 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Electron: Main", + "type": "node", + "request": "launch", + "protocol": "inspector", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "start"], + "env": { + "MAIN_ARGS": "--inspect=5858 --remote-debugging-port=9223" + } + }, + { + "name": "Electron: Renderer", + "type": "chrome", + "request": "attach", + "port": 9223, + "webRoot": "${workspaceFolder}", + "timeout": 15000 + } + ], + "compounds": [ + { + "name": "Electron: All", + "configurations": ["Electron: Main", "Electron: Renderer"] + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..98925c1b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,31 @@ +{ + "files.associations": { + ".eslintrc": "jsonc", + ".prettierrc": "jsonc", + ".eslintignore": "ignore" + }, + + "eslint.validate": [ + "javascript", + "javascriptreact", + "html", + "typescriptreact" + ], + + "javascript.validate.enable": false, + "javascript.format.enable": false, + "typescript.format.enable": false, + + "search.exclude": { + ".git": true, + ".eslintcache": true, + ".erb/dll": true, + "release/{build,app/dist}": true, + "node_modules": true, + "npm-debug.log.*": true, + "test/**/__snapshots__": true, + "package-lock.json": true, + "*.{css,sass,scss}.d.ts": true + }, + "compile-hero.disable-compile-files-on-did-save-code": true +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..19f80fb5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +# 3.0.0 + +Rebuild from scratch using Electron and React. This is a complete rewrite of the original app. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..2562267e --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at electronreactboilerplate@gmail.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/LICENSE b/LICENSE index 23cb7903..c2885de6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,339 +1,21 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/> - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {description} - Copyright (C) {year} {fullname} - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - {signature of Ty Coon}, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. +The MIT License (MIT) + +Copyright (c) 2015-present Electron React Boilerplate + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 515af7ce..b822d9ed 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ Cinematic =========== -> 🎥 A gorgeous Desktop UI for your digital movie collection. +> 🎥 A gorgeous Desktop UI for your digital movie collection, works on Mac, Windows, and Linux! **Have a digital movie collection?** -Cinematic is a desktop app to beautifully organize and automatically retrieve information about your digital movie collection, so you can spend less time searching and more time watching +Cinematic is a desktop app to beautifully organize and automatically retrieve information about your digital movie collection, so you can spend less time searching and more time watching. <p align="center"> - <img width="720" height="450" src="https://raw.githubusercontent.com/lacymorrow/cinematic/master/public/demo.gif"> + <img width="720" height="450" src="https://raw.githubusercontent.com/lacymorrow/cinematic/main/public/demo.gif"> </p> ### [Download for Windows, OSX, and Linux](https://github.com/lacymorrow/cinematic/releases) @@ -47,23 +47,15 @@ Cinematic prefers filenames like `Independence Day [1996].mp4` but will happily # Installation -_Recently packaged for Windows!_ - ### [Visit the Releases page to download Cinematic for Windows, OSX, and Linux](https://github.com/lacymorrow/cinematic/releases) -### Or build and [run from source](https://github.com/lacymorrow/cinematic/blob/master/docs/build.md) - - # Design -User interface design by [Steve Hernandez](http://slhernandez.com/2013/09/10/Movie-App/). -Thanks to: +UI design by [ShadCN](https://ui.shadcn.com) -* [jzjzjzj/parse-torrent-name](https://github.com/jzjzjzj/parse-torrent-name) -* [bbraithwaite/omdb-client](https://github.com/bbraithwaite/omdb-client) -* [pwnall/node-open](https://github.com/pwnall/node-open) -* Built with [Meteor](http://meteor.com) -* Running on [Electron](https://electronjs.org/) +Original interface design by [Steve Hernandez](http://slhernandez.com/2013/09/10/Movie-App/). + +* Built with [Electron](https://electronjs.org/) * APIs provided by TMDB and OMDB @@ -71,30 +63,53 @@ Thanks to: **Update Oct. 27, 2019:** Currently refactoring the codebase to make a clear upgrade path to faster, leaner product. - - A11y - tab index, keyboard controls - - remove magic words for currpage, nav; ('Recent', etc.) - - move reset button - - cache images - - Remove Jquery + jquery tooltip - - remove map foreach - - Ignore pattern uses regex - - Don't remove movies db on startup (maybe load from cache?) - - Save current dirpath and retrieve on startup - - better getosmediapath - - - [ ] Batch request data to save http connections - - [ ] Extend the cache to hold images + - [ ] Save images to cache + - [X] A11y - tab index, keyboard controls - [X] Speed boost - [X] File open dialog - - [X] Release on Windows + - [X] Windows Release ### Need help? Please post any questions or issues you come across to our [issues page](https://github.com/lacymorrow/cinematic/issues). -### Want to help? +## Development + +```bash +# Run dev app +yarn start + +# Build app for production +yarn package +``` + +### Main Process + +Imports must be relative (the alias `@` is only available in the renderer process). + +#### Order of operations + +1. `main/main` is run. + +If there is a previous session it will be restored. The directory is scanned again, and new files are added, missing files are marked deleted, and existing files are loaded from cache, checked for: + +- Cache expiration; +- Missing tmdb/omdb/trailers metadata +- basic equality checks (file size, last modified date) + +If any of the above are true, the file is sent to the queue to fetch updated metadata. + +### Renderer Process + +You may use the alias `@` to import from the `src` directory. + +Entry is `src/renderer/App`, which contains the router. Routing is handled by [react-router](https://reacttraining.com/react-router/web/guides/quick-start). Instead of `<a>` elements, use `<Link to={"/my/path"}>` elements from `react-router-dom`. + +To open links in the user's default browser, use the `<ExternalLink>` component from `src/renderer/components/ExternalLink`. + +❤️ **Based on [electron-react-boilerplate](https://github.com/electron-react-boilerplate/electron-react-boilerplate/).** ❤️ -Pull requests welcome! +#### Debugging -[![dependencies Status](https://david-dm.org/lacymorrow/cinematic/status.svg)](https://david-dm.org/lacymorrow/cinematic) [![devDependencies Status](https://david-dm.org/lacymorrow/cinematic/dev-status.svg)](https://david-dm.org/lacymorrow/cinematic?type=dev) +https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/400 diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 73a443a6..00000000 --- a/appveyor.yml +++ /dev/null @@ -1,28 +0,0 @@ -build: off - -os: unstable - -platform: - - x86 - - x64 - -branches: - only: - - master - -skip_tags: true - -environment: - nodejs_version: "12" - -cache: - - node_modules -> package.json - -install: - - ps: Install-Product node $env:nodejs_version - - npm install - -test_script: - - node --version - - npm --version - - npm test diff --git a/assets/assets.d.ts b/assets/assets.d.ts new file mode 100644 index 00000000..251085e9 --- /dev/null +++ b/assets/assets.d.ts @@ -0,0 +1,35 @@ +type Styles = Record<string, string>; + +declare module '*.svg' { + import React = require('react'); + + export const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>; + + const content: string; + export default content; +} + +declare module '*.png' { + const content: string; + export default content; +} + +declare module '*.jpg' { + const content: string; + export default content; +} + +declare module '*.scss' { + const content: Styles; + export default content; +} + +declare module '*.sass' { + const content: Styles; + export default content; +} + +declare module '*.css' { + const content: Styles; + export default content; +} diff --git a/assets/entitlements.mac.plist b/assets/entitlements.mac.plist new file mode 100644 index 00000000..dad3e20e --- /dev/null +++ b/assets/entitlements.mac.plist @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> + <dict> + <key>com.apple.security.cs.allow-unsigned-executable-memory</key> + <true/> + <key>com.apple.security.cs.allow-jit</key> + <true/> + </dict> +</plist> diff --git a/assets/icon.icns b/assets/icon.icns new file mode 100644 index 00000000..c2213ce8 Binary files /dev/null and b/assets/icon.icns differ diff --git a/assets/icon.ico b/assets/icon.ico new file mode 100644 index 00000000..98948ea6 Binary files /dev/null and b/assets/icon.ico differ diff --git a/assets/icon.png b/assets/icon.png new file mode 100755 index 00000000..755a6e51 Binary files /dev/null and b/assets/icon.png differ diff --git a/assets/icon.svg b/assets/icon.svg new file mode 100644 index 00000000..b064abf9 --- /dev/null +++ b/assets/icon.svg @@ -0,0 +1,23 @@ +<svg width="232" height="232" viewBox="0 0 232 232" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g filter="url(#filter0_b)"> +<path d="M231.5 1V0.5H231H1H0.5V1V231V231.5H1H231H231.5V231V1ZM40.5 25C40.5 33.0082 34.0082 39.5 26 39.5C17.9918 39.5 11.5 33.0082 11.5 25C11.5 16.9918 17.9918 10.5 26 10.5C34.0082 10.5 40.5 16.9918 40.5 25ZM220.5 25C220.5 33.0082 214.008 39.5 206 39.5C197.992 39.5 191.5 33.0082 191.5 25C191.5 16.9918 197.992 10.5 206 10.5C214.008 10.5 220.5 16.9918 220.5 25ZM40.5 205C40.5 213.008 34.0082 219.5 26 219.5C17.9918 219.5 11.5 213.008 11.5 205C11.5 196.992 17.9918 190.5 26 190.5C34.0082 190.5 40.5 196.992 40.5 205ZM220.5 205C220.5 213.008 214.008 219.5 206 219.5C197.992 219.5 191.5 213.008 191.5 205C191.5 196.992 197.992 190.5 206 190.5C214.008 190.5 220.5 196.992 220.5 205ZM209.5 111C209.5 162.639 167.639 204.5 116 204.5C64.3613 204.5 22.5 162.639 22.5 111C22.5 59.3613 64.3613 17.5 116 17.5C167.639 17.5 209.5 59.3613 209.5 111Z" fill="white" stroke="white"/> +<path d="M63.5 146.5C63.5 149.959 60.8969 152.5 58 152.5C55.1031 152.5 52.5 149.959 52.5 146.5C52.5 143.041 55.1031 140.5 58 140.5C60.8969 140.5 63.5 143.041 63.5 146.5Z" stroke="white" stroke-width="5"/> +<path d="M54.9856 139.466C54.9856 139.466 51.1973 116.315 83.1874 93.1647C115.178 70.014 133.698 69.5931 133.698 69.5931" stroke="white" stroke-width="5" stroke-linecap="round"/> +<path d="M178.902 142.686C177.27 139.853 173.652 138.88 170.819 140.512C167.987 142.144 167.014 145.762 168.646 148.595C170.277 151.427 173.896 152.4 176.728 150.768C179.561 149.137 180.534 145.518 178.902 142.686Z" stroke="white" stroke-width="5"/> +<path d="M169.409 151.555C169.409 151.555 151.24 166.394 115.211 150.232C79.182 134.07 69.5718 118.232 69.5718 118.232" stroke="white" stroke-width="5" stroke-linecap="round"/> +<path d="M109.577 41.9707C107.966 44.8143 108.964 48.4262 111.808 50.038C114.651 51.6498 118.263 50.6512 119.875 47.8075C121.487 44.9639 120.488 41.3521 117.645 39.7403C114.801 38.1285 111.189 39.1271 109.577 41.9707Z" stroke="white" stroke-width="5"/> +<path d="M122.038 45.6467C122.038 45.6467 144.047 53.7668 148.412 93.0129C152.778 132.259 144.012 148.579 144.012 148.579" stroke="white" stroke-width="5" stroke-linecap="round"/> +<path d="M59.6334 105C59.6334 105 50.4373 82.1038 61.3054 73.3616C72.1736 64.6194 96 69.1987 96 69.1987" stroke="white" stroke-width="5" stroke-linecap="round"/> +<path d="M149.532 66.9784C149.532 66.9784 174.391 68.9134 177.477 82.6384C180.564 96.3634 165.799 115.833 165.799 115.833" stroke="white" stroke-width="5" stroke-linecap="round"/> +<path d="M138.248 163.363C138.248 163.363 124.023 183.841 110.618 179.573C97.2129 175.305 87.8662 152.728 87.8662 152.728" stroke="white" stroke-width="5" stroke-linecap="round"/> +<path d="M116 119C120.418 119 124 115.642 124 111.5C124 107.358 120.418 104 116 104C111.582 104 108 107.358 108 111.5C108 115.642 111.582 119 116 119Z" fill="white"/> +</g> +<defs> +<filter id="filter0_b" x="-4" y="-4" width="240" height="240" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> +<feFlood flood-opacity="0" result="BackgroundImageFix"/> +<feGaussianBlur in="BackgroundImage" stdDeviation="2"/> +<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur"/> +<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur" result="shape"/> +</filter> +</defs> +</svg> diff --git a/assets/icons/1024x1024.png b/assets/icons/1024x1024.png new file mode 100644 index 00000000..5940b65a Binary files /dev/null and b/assets/icons/1024x1024.png differ diff --git a/assets/icons/128x128.png b/assets/icons/128x128.png new file mode 100644 index 00000000..14e578d2 Binary files /dev/null and b/assets/icons/128x128.png differ diff --git a/assets/icons/16x16.png b/assets/icons/16x16.png new file mode 100644 index 00000000..260a46cb Binary files /dev/null and b/assets/icons/16x16.png differ diff --git a/assets/icons/24x24.png b/assets/icons/24x24.png new file mode 100644 index 00000000..56172416 Binary files /dev/null and b/assets/icons/24x24.png differ diff --git a/assets/icons/256x256.png b/assets/icons/256x256.png new file mode 100644 index 00000000..755a6e51 Binary files /dev/null and b/assets/icons/256x256.png differ diff --git a/assets/icons/32x32.png b/assets/icons/32x32.png new file mode 100644 index 00000000..63423dfe Binary files /dev/null and b/assets/icons/32x32.png differ diff --git a/assets/icons/48x48.png b/assets/icons/48x48.png new file mode 100644 index 00000000..74d87a0c Binary files /dev/null and b/assets/icons/48x48.png differ diff --git a/assets/icons/512x512.png b/assets/icons/512x512.png new file mode 100644 index 00000000..313cd499 Binary files /dev/null and b/assets/icons/512x512.png differ diff --git a/assets/icons/64x64.png b/assets/icons/64x64.png new file mode 100644 index 00000000..6de0ec0e Binary files /dev/null and b/assets/icons/64x64.png differ diff --git a/assets/icons/96x96.png b/assets/icons/96x96.png new file mode 100644 index 00000000..8255ab58 Binary files /dev/null and b/assets/icons/96x96.png differ diff --git a/client/main.html b/client/main.html deleted file mode 100644 index f2f7a003..00000000 --- a/client/main.html +++ /dev/null @@ -1,38 +0,0 @@ -<head> - <meta charset="utf-8"> - <title>Cinematic - - - - - - - - - - - - - - - - - - - - - - - - - - -
- {{> details }} - {{> header }} - {{> navigation }} - {{> display }} - -
- diff --git a/client/main.js b/client/main.js deleted file mode 100644 index bdc1e58c..00000000 --- a/client/main.js +++ /dev/null @@ -1,425 +0,0 @@ -/* global Desktop */ - -'use strict' -import {Meteor} from 'meteor/meteor' -import {Session} from 'meteor/session' -import {Template} from 'meteor/templating' - -import $ from 'jquery' -import NProgress from 'nprogress' -import {config} from '../imports/config' -import {broadcast} from '../imports/startup/both/util' - -import { - getState, - getGenres, - getGenreById, - - getMovie, - getMovieQuery, - getMovieCount, - getRecent, - getRecentCount, - getWatched, - getWatchedCount - -} from '../imports/startup/client/database' - -import { - bullets, - details, - directory, - display, - header, - movies, - navigation, - sort -} from '../imports/ui' - -import Main from './main.html' - -const SORT_TYPES = [ - 'Alphabetical', - 'Popularity', - 'Ratings', - 'Release Date', - 'Runtime', - 'Random' -] - -// Client-side methods - -const setLoaded = function (loaded) { - // Convert to percentage - NProgress.set(loaded / 100) -} - -const setPath = function () { - const directory = document.querySelector('#directory').value - if (directory !== '') { - resetClient() - Meteor.call('handleConfirmPath', directory) - } -} - -const rotateRating = function () { - // Increment activeRating - const x = Session.get('activeRating') + 1 - Session.set('activeRating', x % Session.get('totalRatings')) -} - -let ratingTimer -const resetRatingInterval = function () { - if (ratingTimer) { - Meteor.clearInterval(ratingTimer) - } - - ratingTimer = Meteor.setInterval(rotateRating, config.RATING_DELAY) -} - -const resetSort = function () { - // Default sort values - Session.set('currentSort', SORT_TYPES[0]) - Session.set('movieSort', {sort: {name: 1}}) -} - -// Defaults -const resetClient = function () { - resetSort() - Session.set('activeRating', 0) - Session.set('currentMovie', 0) - Session.set('currentPage', 'Movies') - Session.set('movieQuery', {}) -} - -/* - * TEMPLATE FUNCTIONS AND PROPERTIES - */ - -// Template tags -Template.registerHelper('equals', (v1, v2) => { - return v1 === v2 -}) - -Template.registerHelper('gt', (v1, v2) => { - return v1 > v2 -}) - -// Database getters -Template.body.helpers({ - isDesktop() { - return Meteor.isDesktop - } -}) - -Template.display.helpers({ - page() { - // Current page display title - const currentPage = Session.get('currentPage') - const genre = getGenreById(currentPage) - return (genre && genre.name) || currentPage - } -}) - -// Loading indicatior -Template.header.helpers({ - loading() { - // Invert percentage (0 is done, 100% complete, false, off; 100 is 0% complete) - const state = getState() - const loaded = (state && 100 - state.loading) || 100 - setLoaded(loaded) - return loaded - } -}) - -// Define path helpers -Template.directory.helpers({ - directory() { - const state = getState() - return (state && state.dir) || '---' - } -}) - -// Sidebar navigation -Template.navigation.helpers({ - page() { - return Session.get('currentPage') - }, - genres() { - return getGenres() - }, - movieCount() { - return getMovieCount() - }, - recentCount() { - return getRecentCount() - }, - watchedCount() { - return getWatchedCount() - } -}) - -// Sort helpers -Template.sort.helpers({ - currentSort() { - return Session.get('currentSort') - }, - sortTypes() { - return SORT_TYPES - } -}) - -// Define movies helpers -Template.movies.helpers({ - currentMovie() { - return Session.get('currentMovie') - }, - movies() { - return getMovieQuery(Session.get('movieQuery'), Session.get('movieSort')) - } -}) - -// Define details helpers -Template.details.helpers({ - rating() { - return Session.get('activeRating') - }, - config() { - return config - }, - movie() { - return getMovie(Session.get('currentMovie')) - }, - currentTrailer() { - return Session.get('currentTrailer') - } -}) - -/* - * TEMPLATE EVENTS - */ - -Template.body.events({ - 'click #refresh'() { - broadcast('Cinematic: Resetting client...') - Meteor.call('handleRefresh') - resetClient() - } -}) - -// Define header events -Template.directory.events({ - 'change #browse-input-web'(event) { - event.preventDefault() - Meteor.call('handleBrowseDialog', event.target.files) - }, - 'click #browse-web'() { - // Desktop - $('#browse-input-web').click() - }, - 'keyup #directory'(event) { - // On set path - if (event.which === 13) { - setPath() - } - }, - 'click #browse-desktop'() { - if (Meteor.isDesktop) { - // Desktop - Desktop.send('desktop', 'open-file-dialog') - } else { - // Web browser - } - } -}) - -// Handle filters navigation -Template.navigation.events({ - // Sidebar nav link - click - 'click #navigation-panel li.link'(event) { - if (Session.get('currentSort') === 'Recent') { - resetSort() - } - - // Set page and title - const currentPage = event.currentTarget.dataset.id - Session.set('currentPage', currentPage) - - // Hide right panel - Session.set('currentMovie', 0) - - // Set current page - switch (currentPage.toLowerCase()) { - case 'new': - // Browse Recently Released - Session.set('movieQuery', {}) - break - - case 'recent': - // Browse recently viewed: alphabetical **** TODO: HAVENT FIGURED OUT SORTING - Session.set('currentSort', 'Recent') - Session.set('movieSort', {sort: {recentTime: -1}}) - Session.set('movieQuery', { - _id: { - $in: getRecent().map(e => { - return e._id - }) - } - }) - break - - case 'watched': - // Browse watched: order of watched - Session.set('currentSort', 'Recent') - Session.set('movieSort', {sort: {watchedTime: -1}}) - Session.set('movieQuery', { - _id: { - $in: getWatched().map(e => { - return e._id - }) - } - }) - break - - default: { - const genre = getGenreById(currentPage) - - if (genre) { - // Genre page - All: alphabetical - Session.set('movieQuery', { - _id: {$in: genre.items} - }) - } else { - // Main page - All: alphabetical - Session.set('movieQuery', {}) - } - - break - } - } - } -}) - -// Sort event -Template.sort.events({ - 'change #sort'(event) { - const sort_value = $(event.currentTarget).val() - Session.set('currentSort', sort_value) - - switch (sort_value) { - case SORT_TYPES[1]: - // Popularity - Session.set('movieSort', {sort: {popularity: -1}}) - break - - case SORT_TYPES[2]: - // Rating - Session.set('movieSort', {sort: {imdbRating: -1}}) - break - - case SORT_TYPES[3]: - // Release Date - Session.set('movieSort', {sort: {releaseDate: -1}}) - break - - case SORT_TYPES[4]: - // Runtime - Session.set('movieSort', {sort: {runtime: 1}}) - break - - case SORT_TYPES[5]: - // Random - Session.set('movieSort', {sort: {seed: 1}}) - break - - // Alphabetical - case SORT_TYPES[0]: - default: - Session.set('movieSort', {sort: {name: 1}}) - break - } - }, - 'click #random'() { - Meteor.call('handleRandomSort') - } -}) - -// Define movie display events (click, keystroke) -Template.movies.events({ - // Show right panel - 'click .movie-image'(event) { - // Handle changing details when user switches movie - const {id} = event.currentTarget.dataset - const {ratings, trailer} = getMovie(id) - - Session.set('totalRatings', ratings.length) - - // Set initial trailer - Session.set('currentTrailer', trailer[0]) - // Set current movie and add to recent - Session.set('currentMovie', id) - // Set timer to rotate ratings - Meteor.call('handleViewMovie', id) - - resetRatingInterval() - } - // 'keyup .movie-image'(event) { - // event.preventDefault() - // if (event.which === 37) { // 38 39 40 - // // Left - // } -}) - -Template.details.events({ - 'click #rating'() { - // Switch ratings - resetRatingInterval() - rotateRating() - }, - 'click #open-link'(event) { - const filepath = event.currentTarget.dataset.src - const mid = event.currentTarget.dataset.id - Meteor.call('handleOpenFile', {mid, filepath}) - }, - 'click #trailer .trailer'(event) { - // Switch trailers - Session.set('currentTrailer', event.currentTarget.dataset.id) - } -}) - -/* OnReady */ -Template.body.rendered = function () { - /* Third-Party Progress bar: NProgress */ - NProgress.configure({trickleRate: 0.01, trickleSpeed: 1400}) - NProgress.start() - - // Jquery tooltip for reset button - $('[data-toggle="tooltip"]').tooltip() - - // Receive files from Electron - // Desktop.on('desktop', 'selected-file', (event, data) => { - // console.log('Selected File Dialog Data:', event, data) - // if (data.length === 1) { - // // Single folder to open - // $('#directory').val(data[0]) - // setPath() - // } - // }) -} - -// Init -resetClient() - -// Prevent eslint no-unused -// I know, terrible coding practice. I'll refund you at the door. -export { - Main, - bullets, - details, - directory, - display, - header, - movies, - navigation, - sort -} diff --git a/client/stylesheets/main/details.import.less b/client/stylesheets/main/details.import.less deleted file mode 100644 index 45649bf4..00000000 --- a/client/stylesheets/main/details.import.less +++ /dev/null @@ -1,259 +0,0 @@ -#details-panel { - height: 100%; - width: @side-panel-width; - right: 0; - background: @color-background; - position: fixed; - z-index: 2; - transform: translate(@side-panel-width, 0); - transition: transform .2s ease-in; - border-left: 2px solid #DFDFDF; - - &.active { - transform: translate(0, 0); - } - - #backdrop { - margin: 0 -15px 0 -15px; - position: absolute; - z-index: -1; - } - - // Mirrored backdrop - #mirror { - -moz-transform: scaleY(-1); - -o-transform: scaleY(-1); - -webkit-transform: scaleY(-1); - transform: scaleY(-1); - filter: FlipV; - -ms-filter: "FlipV"; - -moz-transform: scaleY(-1); - -o-transform: scaleY(-1); - -webkit-transform: scaleY(-1); - transform: scaleY(-1); - filter: FlipV; - -ms-filter: "FlipV"; - @media ( max-height: 600px ){ - display: none; - } - } - - #details-wrapper { - overflow-y: auto; - margin: 0 -15px; - padding-top: 280px; - padding-bottom: 280px; - height: 100%; - .no-trailer {} //dunno - } - - #backdrop-space { - position: relative; - background: - linear-gradient( - to bottom, - rgba(0, 0, 0, 0), - rgba(0, 0, 0, 0), - rgba(0, 0, 0, 0.2) - ); - width: 500px; - height: 280px; - display: block; - @media ( max-height: 800px ){ - display: none; - } - } - - #rated { - color: #fff; - text-shadow: 1px 1px 1px #000; - border: 2px solid #fff; - display: inline-block; - border-radius: 2px; - padding: 5px 10px; - opacity: .85; - margin: 1em; - position: absolute; - bottom: 0; - right: 0; - } - - #release-date { - color: #fff; - text-shadow: 1px 1px 1px #000; - font-family: @font-family-light; - display: inline-block; - opacity: .85; - margin: 1em; - position: absolute; - bottom: 0; - left: 0; - } - - #rating { - position: relative; - z-index: 0; - margin: 20px 0 25px 0; - display: block; - height: 50px; - } - - .rating { - width: 500px; - position: absolute; - top: 0; - left: 0; - opacity: 0; - transform: translate3d(0, 50%, 0); - transition: transform .4s ease-in, - opacity .4s ease-in; - #rating-title { - float: left; - cursor: default; - } - - &.active { - display: block; - opacity: 1; - transform: none; - transition-delay: .3s; - } - - &.old { - transform: translate3d(0, -35%, 0); - } - } - - .rating-text { - margin-left: 250px; - margin-top: 35px; - cursor: default; - } - - .bullet-wrap { - position: absolute; - z-index: 1; - top: 35px; - left: 0; - } - - .bullet-empty-wrap { - position: absolute; - z-index: 0; - top: 35px; - left: 0; - } - - .bullet { - display: inline-block; - float: left; - margin: 4px 8px 4px 0; - border-radius: 50%; - width: 14px; - height: 14px; - background: @color-blue; - background-position: center center; - box-shadow: 1px 1px 5px #BBB; - - &.empty { - background-color: #FFF; - } - } - - #details { - padding: 10px 15px 15px 15px; - background: linear-gradient(to bottom, rgba(252, 252, 252, .8), rgba(252, 252, 252, .99), rgba(252, 252, 252, .99)); - min-height: 300px; - overflow-x: hidden; - - #movie-title { - margin-top: 0; - } - - #open-link { - cursor: pointer; - z-index: 1; - position: relative; - float: right; - margin-right: 25px; - font-family: @font-family-light; - } - - #imdb-link { - z-index: 1; - position: relative; - cursor: pointer; - color: @color-dark; - &:hover { - color: @color-blue; - } - } - - p { - font-family: @font-family-light; - font-size: 16px; - position: relative; - z-index: 1; - span { - font-family: @font-family-regular; - } - } - } - - #trailer { - position: fixed; - z-index: 2; - bottom: 0; - width: 500px; - height:280px; - margin: 0 -15px; - } - - #trailer-bullets { - position: absolute; - cursor: pointer; - z-index: 3; - top: 0; - left: 0; - padding: 1em; - opacity: 0.4; - transition: opacity .2s ease-in; - - &:hover { - opacity: 0.9; - } - } - - #trailer-text { - text-transform: uppercase; - line-height: 0.5; - text-align: center; - margin-top: 2em; - - span { - display: inline-block; - position: relative; - - &:before { - right: 100%; - margin-right: 15px; - } - - &:after { - left: 100%; - margin-left: 15px; - } - - &:before, - &:after { - content: ""; - position: absolute; - height: 5px; - border-bottom: 1px solid @color-h5; - border-top: 1px solid @color-h5; - top: 0; - width: 150px; - } - } - } -} diff --git a/client/stylesheets/main/display.import.less b/client/stylesheets/main/display.import.less deleted file mode 100644 index 7a41ebf2..00000000 --- a/client/stylesheets/main/display.import.less +++ /dev/null @@ -1,69 +0,0 @@ -// Sub-header -.display-header { - margin-left: 58px; - - h3 { - cursor: default; - } - - #sort { - width: auto; - border:0px; - outline:0px; - box-shadow: none; - background-color: @color-background; - font-size: 18px; - display: inline-block; - margin-left: -7px; - margin-right: 1em; - cursor: pointer; - } - - #random { - cursor: pointer; - } -} - -// Movie items -#movies-wrapper { - user-select: none; - height: 100%; - padding: 70px 0 25px 0; - margin-left: -50px; - overflow-x: hidden; - - #movie-items { - padding-bottom: 50px; - } -} - -.movie { - height: 400px; - margin-bottom: 2em; -} - -.movie-image { - display: flex; - flex-direction: column; - height: 100%; - justify-content: space-between; - width: 210px; - border-radius: 6px; - padding: 1em 0 .5em 0; - font-family: @font-family-light; - outline: none; - - img { - max-width: 185px; - } - - &.active { - background-color: @color-blue; - h5 { - color: #FFF; - } - } - .caption { - width: 185px; - } -} diff --git a/client/stylesheets/main/header.import.less b/client/stylesheets/main/header.import.less deleted file mode 100644 index 8d957876..00000000 --- a/client/stylesheets/main/header.import.less +++ /dev/null @@ -1,117 +0,0 @@ -// header -header { - display: flex; - align-items: center; - width: 100%; - height: 70px; - padding-left: 15px; - top: 0; - left: 0; - z-index: 1; - position: fixed; - background-color: @color-background-dark; - border-bottom: 2px solid #DFDFDF; - height: 70px; - - #app-title { - margin: 0; - float: left; - color: @color-blue; - cursor: default; - width: 20rem; - user-select: none; - } - - #directory-wrapper { - margin-right: 2rem; - font-family: @font-family-light; - font-size: 14px; - color: @gray-light; - - #search { - position: relative; - display: inline-block; - } - - #search-icon { - position: absolute; - left: 10px; - top: 7px; - } - - input { - padding: 3px 0 3px 30px; - width: 400px; - border: 1px solid #e1e1e1; - border-radius: 25px; - outline: none; - &:active, &:focus { - box-shadow: 0px 0px 3px 1px @color-blue; - } - } - - &:focus { - outline: 0; - border-color: #66b1ee; - box-shadow: 0 0 2px rgba(85, 168, 236, 0.9); - } - } - - .browse-link { - display: inline-block; - margin-right: 2rem; - position: relative; - padding: .8em 1.4em; - padding-right: 4.7em; - border: none; - border-radius: 0; - color: black; - background: @gray-button-light; - -webkit-font-smoothing: antialiased; - - .icon { - border: none; - background: @gray-button-dark; - position: absolute; - top: 0; - bottom: 0; - right: 0; - padding-top: inherit; - padding-bottom: inherit; - width: 2.8em; - text-align: center; - } - - &:hover { - background: darken(@gray-button-light, 10%); - - .icon { - background: darken(@gray-button-dark, 10%); - } - } - } - - // Desktop - #browse-desktop { - display: none; - } - - // Web - #browse-input-web { - position: absolute; - top: 0; - right: 0; - width: 1px; - height: 1px; - opacity: .1; - } - - .desktop { - #browse-desktop { - display: inline-block; - } - #browse-web-wrapper { - display: none; - } - } -} diff --git a/client/stylesheets/main/main.import.less b/client/stylesheets/main/main.import.less deleted file mode 100644 index d9f9a524..00000000 --- a/client/stylesheets/main/main.import.less +++ /dev/null @@ -1,32 +0,0 @@ -// normalize -body { - font-family: @font-family-regular; - margin: 0; - padding: 0; - background-color: @color-background; -} - -ul, li { - list-style: none; -} - -.height-100 { - height: 100%; -} - -#wrapper{ - height: 100%; - width: 100%; - position: relative; -} - -#refresh { - position: fixed; - bottom: 0; - z-index: 0; - right: 0; - top: auto; - padding: 5rem; - cursor: pointer; - color: @color-dark; -} diff --git a/client/stylesheets/main/navigation.import.less b/client/stylesheets/main/navigation.import.less deleted file mode 100644 index fc9242b5..00000000 --- a/client/stylesheets/main/navigation.import.less +++ /dev/null @@ -1,69 +0,0 @@ -#navigation-wrapper { - user-select: none; - position: fixed; - height: 100%; - width: 20rem; - padding: 70px 0 0 0; -} - -#navigation-panel { - height: 100%; - overflow-y: scroll; - padding: 0 0 90px 0; - font-family: @font-family-light; - border-right: 2px solid #DFDFDF; - - li { - h5 { - width: 100%; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - cursor: pointer; - font-size: 16px; - padding: 6px 6px 6px 35px; - - .badge { - margin: -3px 0 0 5px; - background: @color-blue; - } - } - - &:active { - background-color: @gray-button-dark; - } - - &:hover { - background-color: @gray-button-light; - } - - &.active { - background-color: @color-blue; - - h5 { - color: #FFF; - - .badge { - color: @color-blue; - background-color: #ffffff; - } - } - - &:active { - background-color: @color-blue; - } - - &:hover { - background-color: @color-blue-dark; - } - } - - h5.label { - cursor: default; - margin-top: 2em; - padding-left: 25px; - font-family: @font-family-regular; - background-color: white; - } - } -} diff --git a/client/stylesheets/main/util.import.less b/client/stylesheets/main/util.import.less deleted file mode 100644 index 6d3ec11d..00000000 --- a/client/stylesheets/main/util.import.less +++ /dev/null @@ -1,3 +0,0 @@ -.height-100 { - height: 100%; -} diff --git a/client/stylesheets/style.less b/client/stylesheets/style.less deleted file mode 100644 index f2d45d16..00000000 --- a/client/stylesheets/style.less +++ /dev/null @@ -1,14 +0,0 @@ -// Import Vendors -@import "vendor/custom.bootstrap.mixins.import.less"; -@import "vendor/custom.bootstrap.import.less"; - -// Globals -@import "typo.import.less"; - -// Sites -@import "main/main.import.less"; -@import "main/util.import.less"; -@import "main/header.import.less"; -@import "main/navigation.import.less"; -@import "main/display.import.less"; -@import "main/details.import.less"; diff --git a/client/stylesheets/typo.import.less b/client/stylesheets/typo.import.less deleted file mode 100644 index ace1d5cc..00000000 --- a/client/stylesheets/typo.import.less +++ /dev/null @@ -1,40 +0,0 @@ -@font-face { - font-family: 'oswaldbold'; - src: url('oswald/oswald-bold-webfont.eot'); - src: url('oswald/oswald-bold-webfont.eot?#iefix') format('embedded-opentype'), - url('oswald/oswald-bold-webfont.woff2') format('woff2'), - url('oswald/oswald-bold-webfont.woff') format('woff'), - url('oswald/oswald-bold-webfont.ttf') format('truetype'), - url('oswald/oswald-bold-webfont.svg#oswaldbold') format('svg'); - font-weight: normal; - font-style: normal; - -} -@font-face { - font-family: 'oswaldlight'; - src: url('oswald/oswald-light-webfont.eot'); - src: url('oswald/oswald-light-webfont.eot?#iefix') format('embedded-opentype'), - url('oswald/oswald-light-webfont.woff2') format('woff2'), - url('oswald/oswald-light-webfont.woff') format('woff'), - url('oswald/oswald-light-webfont.ttf') format('truetype'), - url('oswald/oswald-light-webfont.svg#oswaldlight') format('svg'); - font-weight: normal; - font-style: normal; - -} -@font-face { - font-family: 'oswaldregular'; - src: url('oswald/oswald-regular-webfont.eot'); - src: url('oswald/oswald-regular-webfont.eot?#iefix') format('embedded-opentype'), - url('oswald/oswald-regular-webfont.woff2') format('woff2'), - url('oswald/oswald-regular-webfont.woff') format('woff'), - url('oswald/oswald-regular-webfont.ttf') format('truetype'), - url('oswald/oswald-regular-webfont.svg#oswaldregular') format('svg'); - font-weight: normal; - font-style: normal; - -} - -@font-family-light: 'oswaldlight', 'Helvetica Neue', 'Helvetica', sans-serif; -@font-family-regular: 'oswaldregular', 'Helvetica Neue', 'Helvetica', sans-serif; -@font-family-bold: 'oswaldbold', 'Helvetica Neue', 'Helvetica', sans-serif; diff --git a/client/stylesheets/vendor/custom.bootstrap.import.less b/client/stylesheets/vendor/custom.bootstrap.import.less deleted file mode 100644 index bee2f616..00000000 --- a/client/stylesheets/vendor/custom.bootstrap.import.less +++ /dev/null @@ -1,969 +0,0 @@ -// This File is for you to modify! -// It won't be overwritten as long as it exists. -// You may include this file into your less files to benefit from -// mixins and variables that bootstrap provides. - -@import "custom.bootstrap.mixins.import.less"; - - -// @import "bootstrap/less/variables.less" -// -// Variables -// -------------------------------------------------- - - - -@side-panel-width: 502px; - -//== Colors -// -//## Gray and brand colors for use across Bootstrap. -@color-dark: #3D3B39; -@color-h1: @color-dark; -@color-h2: @color-dark; -@color-h3: #120E09; -@color-h4: #1E1C1C; -@color-h5: #555555; -@color-blue: #01A6F6; -@color-blue-dark: darken(@color-blue, 13.5%); -@color-blue-light: lighten(@color-blue, 13.5%); -@color-background: #FCFCFC; -@color-background-dark: #F3F3F3; - -@gray-base: #000; -@gray-darker: lighten(@gray-base, 13.5%); // #222 -@gray-dark: lighten(@gray-base, 20%); // #333 -@gray: lighten(@gray-base, 33.5%); // #555 -@gray-light: lighten(@gray-base, 46.7%); // #777 -@gray-lighter: lighten(@gray-base, 93.5%); // #eee - -@gray-button-light: lighten(@gray-base, 85%); -@gray-button-dark: lighten(@gray-base, 75%); - - -@brand-primary: @color-blue; // #337ab7 -@brand-success: #5cb85c; -@brand-info: #5bc0de; -@brand-warning: #f0ad4e; -@brand-danger: #d9534f; - - -//== Scaffolding -// -//## Settings for some of the most global styles. - -//** Background color for ``. -@body-bg: #fff; -//** Global text color on ``. -@text-color: @gray-dark; - -//** Global textual link color. -@link-color: @brand-primary; -//** Link hover color set via `darken()` function. -@link-hover-color: darken(@link-color, 15%); -//** Link hover decoration. -@link-hover-decoration: underline; - - -//== Typography -// -//## Font, line-height, and color for body text, headings, and more. - -@font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif; -@font-family-serif: Georgia, "Times New Roman", Times, serif; -//** Default monospace fonts for ``, ``, and `
`.
-@font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace;
-@font-family-base:        @font-family-sans-serif;
-
-@font-size-base:          14px;
-@font-size-large:         ceil((@font-size-base * 1.25)); // ~18px
-@font-size-small:         ceil((@font-size-base * 0.85)); // ~12px
-
-@font-size-h1:            floor((@font-size-base * 2.6)); // ~36px
-@font-size-h2:            floor((@font-size-base * 2.15)); // ~30px
-@font-size-h3:            ceil((@font-size-base * 1.7)); // ~24px
-@font-size-h4:            ceil((@font-size-base * 1.25)); // ~18px
-@font-size-h5:            @font-size-base;
-@font-size-h6:            ceil((@font-size-base * 0.85)); // ~12px
-
-//** Unit-less `line-height` for use in components like buttons.
-@line-height-base:        1.428571429; // 20/14
-//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
-@line-height-computed:    floor((@font-size-base * @line-height-base)); // ~20px
-
-//** By default, this inherits from the ``.
-@headings-font-family:    inherit;
-@headings-font-weight:    500;
-@headings-line-height:    1.1;
-@headings-color:          inherit;
-
-
-//== Iconography
-//
-//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
-
-//** Load fonts from this directory.
-@icon-font-path:          "../fonts/";
-//** File name for all font files.
-@icon-font-name:          "glyphicons-halflings-regular";
-//** Element ID within SVG icon file.
-@icon-font-svg-id:        "glyphicons_halflingsregular";
-
-
-//== Components
-//
-//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
-
-@padding-base-vertical:     6px;
-@padding-base-horizontal:   12px;
-
-@padding-large-vertical:    10px;
-@padding-large-horizontal:  16px;
-
-@padding-small-vertical:    5px;
-@padding-small-horizontal:  10px;
-
-@padding-xs-vertical:       1px;
-@padding-xs-horizontal:     5px;
-
-@line-height-large:         1.3333333; // extra decimals for Win 8.1 Chrome
-@line-height-small:         1.5;
-
-@border-radius-base:        4px;
-@border-radius-large:       6px;
-@border-radius-small:       3px;
-
-//** Global color for active items (e.g., navs or dropdowns).
-@component-active-color:    #fff;
-//** Global background color for active items (e.g., navs or dropdowns).
-@component-active-bg:       @brand-primary;
-
-//** Width of the `border` for generating carets that indicator dropdowns.
-@caret-width-base:          4px;
-//** Carets increase slightly in size for larger components.
-@caret-width-large:         5px;
-
-
-//== Tables
-//
-//## Customizes the `.table` component with basic values, each used across all table variations.
-
-//** Padding for ``s and ``s.
-@table-cell-padding:            8px;
-//** Padding for cells in `.table-condensed`.
-@table-condensed-cell-padding:  5px;
-
-//** Default background color used for all tables.
-@table-bg:                      transparent;
-//** Background color used for `.table-striped`.
-@table-bg-accent:               #f9f9f9;
-//** Background color used for `.table-hover`.
-@table-bg-hover:                #f5f5f5;
-@table-bg-active:               @table-bg-hover;
-
-//** Border color for table and cell borders.
-@table-border-color:            #ddd;
-
-
-//== Buttons
-//
-//## For each of Bootstrap's buttons, define text, background and border color.
-
-@btn-font-weight:                normal;
-
-@btn-default-color:              #333;
-@btn-default-bg:                 #fff;
-@btn-default-border:             #ccc;
-
-@btn-primary-color:              #fff;
-@btn-primary-bg:                 @brand-primary;
-@btn-primary-border:             darken(@btn-primary-bg, 5%);
-
-@btn-success-color:              #fff;
-@btn-success-bg:                 @brand-success;
-@btn-success-border:             darken(@btn-success-bg, 5%);
-
-@btn-info-color:                 #fff;
-@btn-info-bg:                    @brand-info;
-@btn-info-border:                darken(@btn-info-bg, 5%);
-
-@btn-warning-color:              #fff;
-@btn-warning-bg:                 @brand-warning;
-@btn-warning-border:             darken(@btn-warning-bg, 5%);
-
-@btn-danger-color:               #fff;
-@btn-danger-bg:                  @brand-danger;
-@btn-danger-border:              darken(@btn-danger-bg, 5%);
-
-@btn-link-disabled-color:        @gray-light;
-
-// Allows for customizing button radius independently from global border radius
-@btn-border-radius-base:         @border-radius-base;
-@btn-border-radius-large:        @border-radius-large;
-@btn-border-radius-small:        @border-radius-small;
-
-
-//== Forms
-//
-//##
-
-//** `` background color
-@input-bg:                       #fff;
-//** `` background color
-@input-bg-disabled:              @gray-lighter;
-
-//** Text color for ``s
-@input-color:                    @gray;
-//** `` border color
-@input-border:                   #ccc;
-
-// TODO: Rename `@input-border-radius` to `@input-border-radius-base` in v4
-//** Default `.form-control` border radius
-// This has no effect on ``s in CSS.
-@input-border-radius:            @border-radius-base;
-//** Large `.form-control` border radius
-@input-border-radius-large:      @border-radius-large;
-//** Small `.form-control` border radius
-@input-border-radius-small:      @border-radius-small;
-
-//** Border color for inputs on focus
-@input-border-focus:             #66afe9;
-
-//** Placeholder text color
-@input-color-placeholder:        #999;
-
-//** Default `.form-control` height
-@input-height-base:              (@line-height-computed + (@padding-base-vertical * 2) + 2);
-//** Large `.form-control` height
-@input-height-large:             (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
-//** Small `.form-control` height
-@input-height-small:             (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
-
-//** `.form-group` margin
-@form-group-margin-bottom:       15px;
-
-@legend-color:                   @gray-dark;
-@legend-border-color:            #e5e5e5;
-
-//** Background color for textual input addons
-@input-group-addon-bg:           @gray-lighter;
-//** Border color for textual input addons
-@input-group-addon-border-color: @input-border;
-
-//** Disabled cursor for form controls and buttons.
-@cursor-disabled:                not-allowed;
-
-
-//== Dropdowns
-//
-//## Dropdown menu container and contents.
-
-//** Background for the dropdown menu.
-@dropdown-bg:                    #fff;
-//** Dropdown menu `border-color`.
-@dropdown-border:                rgba(0,0,0,.15);
-//** Dropdown menu `border-color` **for IE8**.
-@dropdown-fallback-border:       #ccc;
-//** Divider color for between dropdown items.
-@dropdown-divider-bg:            #e5e5e5;
-
-//** Dropdown link text color.
-@dropdown-link-color:            @gray-dark;
-//** Hover color for dropdown links.
-@dropdown-link-hover-color:      darken(@gray-dark, 5%);
-//** Hover background for dropdown links.
-@dropdown-link-hover-bg:         #f5f5f5;
-
-//** Active dropdown menu item text color.
-@dropdown-link-active-color:     @component-active-color;
-//** Active dropdown menu item background color.
-@dropdown-link-active-bg:        @component-active-bg;
-
-//** Disabled dropdown menu item background color.
-@dropdown-link-disabled-color:   @gray-light;
-
-//** Text color for headers within dropdown menus.
-@dropdown-header-color:          @gray-light;
-
-//** Deprecated `@dropdown-caret-color` as of v3.1.0
-@dropdown-caret-color:           #000;
-
-
-//-- Z-index master list
-//
-// Warning: Avoid customizing these values. They're used for a bird's eye view
-// of components dependent on the z-axis and are designed to all work together.
-//
-// Note: These variables are not generated into the Customizer.
-
-@zindex-navbar:            1000;
-@zindex-dropdown:          1000;
-@zindex-popover:           1060;
-@zindex-tooltip:           1070;
-@zindex-navbar-fixed:      1030;
-@zindex-modal-background:  1040;
-@zindex-modal:             1050;
-
-
-//== Media queries breakpoints
-//
-//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
-
-// Extra small screen / phone
-//** Deprecated `@screen-xs` as of v3.0.1
-@screen-xs:                  480px;
-//** Deprecated `@screen-xs-min` as of v3.2.0
-@screen-xs-min:              @screen-xs;
-//** Deprecated `@screen-phone` as of v3.0.1
-@screen-phone:               @screen-xs-min;
-
-// Small screen / tablet
-//** Deprecated `@screen-sm` as of v3.0.1
-@screen-sm:                  768px;
-@screen-sm-min:              @screen-sm;
-//** Deprecated `@screen-tablet` as of v3.0.1
-@screen-tablet:              @screen-sm-min;
-
-// Medium screen / desktop
-//** Deprecated `@screen-md` as of v3.0.1
-@screen-md:                  992px;
-@screen-md-min:              @screen-md;
-//** Deprecated `@screen-desktop` as of v3.0.1
-@screen-desktop:             @screen-md-min;
-
-// Large screen / wide desktop
-//** Deprecated `@screen-lg` as of v3.0.1
-@screen-lg:                  1300px;
-@screen-lg-min:              @screen-lg;
-//** Deprecated `@screen-lg-desktop` as of v3.0.1
-@screen-lg-desktop:          @screen-lg-min;
-
-// XLarge screen / Xwide desktop
-//** Deprecated `@screen-xl` as of v3.0.1
-@screen-xl:                  1500px;
-@screen-xl-min:              @screen-xl;
-//** Deprecated `@screen-xl-desktop` as of v3.0.1
-@screen-xl-desktop:          @screen-xl-min;
-
-// So media queries don't overlap when required, provide a maximum
-@screen-xs-max:              (@screen-sm-min - 1);
-@screen-sm-max:              (@screen-md-min - 1);
-@screen-md-max:              (@screen-lg-min - 1);
-@screen-lg-max:              (@screen-xl-min - 1);
-
-
-//== Grid system
-//
-//## Define your custom responsive grid.
-
-//** Number of columns in the grid.
-@grid-columns:              12;
-//** Padding between columns. Gets divided in half for the left and right.
-@grid-gutter-width:         30px;
-// Navbar collapse
-//** Point at which the navbar becomes uncollapsed.
-@grid-float-breakpoint:     @screen-sm-min;
-//** Point at which the navbar begins collapsing.
-@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
-
-
-//== Container sizes
-//
-//## Define the maximum width of `.container` for different screen sizes.
-
-// Small screen / tablet
-@container-tablet:             (720px + @grid-gutter-width);
-//** For `@screen-sm-min` and up.
-@container-sm:                 @container-tablet;
-
-// Medium screen / desktop
-@container-desktop:            (940px + @grid-gutter-width);
-//** For `@screen-md-min` and up.
-@container-md:                 @container-desktop;
-
-// Large screen / wide desktop
-@container-large-desktop:      (1140px + @grid-gutter-width);
-//** For `@screen-lg-min` and up.
-@container-lg:                 @container-large-desktop;
-
-// XLarge screen / Xwide desktop
-@container-xlarge-desktop:      (1440px + @grid-gutter-width);
-//** For `@screen-lg-min` and up.
-@container-xl:                 @container-xlarge-desktop;
-
-
-//== Navbar
-//
-//##
-
-// Basics of a navbar
-@navbar-height:                    50px;
-@navbar-margin-bottom:             @line-height-computed;
-@navbar-border-radius:             @border-radius-base;
-@navbar-padding-horizontal:        floor((@grid-gutter-width / 2));
-@navbar-padding-vertical:          ((@navbar-height - @line-height-computed) / 2);
-@navbar-collapse-max-height:       340px;
-
-@navbar-default-color:             #777;
-@navbar-default-bg:                #f8f8f8;
-@navbar-default-border:            darken(@navbar-default-bg, 6.5%);
-
-// Navbar links
-@navbar-default-link-color:                #777;
-@navbar-default-link-hover-color:          #333;
-@navbar-default-link-hover-bg:             transparent;
-@navbar-default-link-active-color:         #555;
-@navbar-default-link-active-bg:            darken(@navbar-default-bg, 6.5%);
-@navbar-default-link-disabled-color:       #ccc;
-@navbar-default-link-disabled-bg:          transparent;
-
-// Navbar brand label
-@navbar-default-brand-color:               @navbar-default-link-color;
-@navbar-default-brand-hover-color:         darken(@navbar-default-brand-color, 10%);
-@navbar-default-brand-hover-bg:            transparent;
-
-// Navbar toggle
-@navbar-default-toggle-hover-bg:           #ddd;
-@navbar-default-toggle-icon-bar-bg:        #888;
-@navbar-default-toggle-border-color:       #ddd;
-
-
-//=== Inverted navbar
-// Reset inverted navbar basics
-@navbar-inverse-color:                      lighten(@gray-light, 15%);
-@navbar-inverse-bg:                         #222;
-@navbar-inverse-border:                     darken(@navbar-inverse-bg, 10%);
-
-// Inverted navbar links
-@navbar-inverse-link-color:                 lighten(@gray-light, 15%);
-@navbar-inverse-link-hover-color:           #fff;
-@navbar-inverse-link-hover-bg:              transparent;
-@navbar-inverse-link-active-color:          @navbar-inverse-link-hover-color;
-@navbar-inverse-link-active-bg:             darken(@navbar-inverse-bg, 10%);
-@navbar-inverse-link-disabled-color:        #444;
-@navbar-inverse-link-disabled-bg:           transparent;
-
-// Inverted navbar brand label
-@navbar-inverse-brand-color:                @navbar-inverse-link-color;
-@navbar-inverse-brand-hover-color:          #fff;
-@navbar-inverse-brand-hover-bg:             transparent;
-
-// Inverted navbar toggle
-@navbar-inverse-toggle-hover-bg:            #333;
-@navbar-inverse-toggle-icon-bar-bg:         #fff;
-@navbar-inverse-toggle-border-color:        #333;
-
-
-//== Navs
-//
-//##
-
-//=== Shared nav styles
-@nav-link-padding:                          10px 15px;
-@nav-link-hover-bg:                         @gray-lighter;
-
-@nav-disabled-link-color:                   @gray-light;
-@nav-disabled-link-hover-color:             @gray-light;
-
-//== Tabs
-@nav-tabs-border-color:                     #ddd;
-
-@nav-tabs-link-hover-border-color:          @gray-lighter;
-
-@nav-tabs-active-link-hover-bg:             @body-bg;
-@nav-tabs-active-link-hover-color:          @gray;
-@nav-tabs-active-link-hover-border-color:   #ddd;
-
-@nav-tabs-justified-link-border-color:            #ddd;
-@nav-tabs-justified-active-link-border-color:     @body-bg;
-
-//== Pills
-@nav-pills-border-radius:                   @border-radius-base;
-@nav-pills-active-link-hover-bg:            @component-active-bg;
-@nav-pills-active-link-hover-color:         @component-active-color;
-
-
-//== Pagination
-//
-//##
-
-@pagination-color:                     @link-color;
-@pagination-bg:                        #fff;
-@pagination-border:                    #ddd;
-
-@pagination-hover-color:               @link-hover-color;
-@pagination-hover-bg:                  @gray-lighter;
-@pagination-hover-border:              #ddd;
-
-@pagination-active-color:              #fff;
-@pagination-active-bg:                 @brand-primary;
-@pagination-active-border:             @brand-primary;
-
-@pagination-disabled-color:            @gray-light;
-@pagination-disabled-bg:               #fff;
-@pagination-disabled-border:           #ddd;
-
-
-//== Pager
-//
-//##
-
-@pager-bg:                             @pagination-bg;
-@pager-border:                         @pagination-border;
-@pager-border-radius:                  15px;
-
-@pager-hover-bg:                       @pagination-hover-bg;
-
-@pager-active-bg:                      @pagination-active-bg;
-@pager-active-color:                   @pagination-active-color;
-
-@pager-disabled-color:                 @pagination-disabled-color;
-
-
-//== Jumbotron
-//
-//##
-
-@jumbotron-padding:              30px;
-@jumbotron-color:                inherit;
-@jumbotron-bg:                   @gray-lighter;
-@jumbotron-heading-color:        inherit;
-@jumbotron-font-size:            ceil((@font-size-base * 1.5));
-@jumbotron-heading-font-size:    ceil((@font-size-base * 4.5));
-
-
-//== Form states and alerts
-//
-//## Define colors for form feedback states and, by default, alerts.
-
-@state-success-text:             #3c763d;
-@state-success-bg:               #dff0d8;
-@state-success-border:           darken(spin(@state-success-bg, -10), 5%);
-
-@state-info-text:                #31708f;
-@state-info-bg:                  #d9edf7;
-@state-info-border:              darken(spin(@state-info-bg, -10), 7%);
-
-@state-warning-text:             #8a6d3b;
-@state-warning-bg:               #fcf8e3;
-@state-warning-border:           darken(spin(@state-warning-bg, -10), 5%);
-
-@state-danger-text:              #a94442;
-@state-danger-bg:                #f2dede;
-@state-danger-border:            darken(spin(@state-danger-bg, -10), 5%);
-
-
-//== Tooltips
-//
-//##
-
-//** Tooltip max width
-@tooltip-max-width:           200px;
-//** Tooltip text color
-@tooltip-color:               #fff;
-//** Tooltip background color
-@tooltip-bg:                  #000;
-@tooltip-opacity:             .9;
-
-//** Tooltip arrow width
-@tooltip-arrow-width:         5px;
-//** Tooltip arrow color
-@tooltip-arrow-color:         @tooltip-bg;
-
-
-//== Popovers
-//
-//##
-
-//** Popover body background color
-@popover-bg:                          #fff;
-//** Popover maximum width
-@popover-max-width:                   276px;
-//** Popover border color
-@popover-border-color:                rgba(0,0,0,.2);
-//** Popover fallback border color
-@popover-fallback-border-color:       #ccc;
-
-//** Popover title background color
-@popover-title-bg:                    darken(@popover-bg, 3%);
-
-//** Popover arrow width
-@popover-arrow-width:                 10px;
-//** Popover arrow color
-@popover-arrow-color:                 @popover-bg;
-
-//** Popover outer arrow width
-@popover-arrow-outer-width:           (@popover-arrow-width + 1);
-//** Popover outer arrow color
-@popover-arrow-outer-color:           fadein(@popover-border-color, 5%);
-//** Popover outer arrow fallback color
-@popover-arrow-outer-fallback-color:  darken(@popover-fallback-border-color, 20%);
-
-
-//== Labels
-//
-//##
-
-//** Default label background color
-@label-default-bg:            @gray-light;
-//** Primary label background color
-@label-primary-bg:            @brand-primary;
-//** Success label background color
-@label-success-bg:            @brand-success;
-//** Info label background color
-@label-info-bg:               @brand-info;
-//** Warning label background color
-@label-warning-bg:            @brand-warning;
-//** Danger label background color
-@label-danger-bg:             @brand-danger;
-
-//** Default label text color
-@label-color:                 #fff;
-//** Default text color of a linked label
-@label-link-hover-color:      #fff;
-
-
-//== Modals
-//
-//##
-
-//** Padding applied to the modal body
-@modal-inner-padding:         15px;
-
-//** Padding applied to the modal title
-@modal-title-padding:         15px;
-//** Modal title line-height
-@modal-title-line-height:     @line-height-base;
-
-//** Background color of modal content area
-@modal-content-bg:                             #fff;
-//** Modal content border color
-@modal-content-border-color:                   rgba(0,0,0,.2);
-//** Modal content border color **for IE8**
-@modal-content-fallback-border-color:          #999;
-
-//** Modal backdrop background color
-@modal-backdrop-bg:           #000;
-//** Modal backdrop opacity
-@modal-backdrop-opacity:      .5;
-//** Modal header border color
-@modal-header-border-color:   #e5e5e5;
-//** Modal footer border color
-@modal-footer-border-color:   @modal-header-border-color;
-
-@modal-xl:                    1000px;
-@modal-lg:                    900px;
-@modal-md:                    600px;
-@modal-sm:                    300px;
-
-
-//== Alerts
-//
-//## Define alert colors, border radius, and padding.
-
-@alert-padding:               15px;
-@alert-border-radius:         @border-radius-base;
-@alert-link-font-weight:      bold;
-
-@alert-success-bg:            @state-success-bg;
-@alert-success-text:          @state-success-text;
-@alert-success-border:        @state-success-border;
-
-@alert-info-bg:               @state-info-bg;
-@alert-info-text:             @state-info-text;
-@alert-info-border:           @state-info-border;
-
-@alert-warning-bg:            @state-warning-bg;
-@alert-warning-text:          @state-warning-text;
-@alert-warning-border:        @state-warning-border;
-
-@alert-danger-bg:             @state-danger-bg;
-@alert-danger-text:           @state-danger-text;
-@alert-danger-border:         @state-danger-border;
-
-
-//== Progress bars
-//
-//##
-
-//** Background color of the whole progress component
-@progress-bg:                 #f5f5f5;
-//** Progress bar text color
-@progress-bar-color:          #fff;
-//** Variable for setting rounded corners on progress bar.
-@progress-border-radius:      @border-radius-base;
-
-//** Default progress bar color
-@progress-bar-bg:             @brand-primary;
-//** Success progress bar color
-@progress-bar-success-bg:     @brand-success;
-//** Warning progress bar color
-@progress-bar-warning-bg:     @brand-warning;
-//** Danger progress bar color
-@progress-bar-danger-bg:      @brand-danger;
-//** Info progress bar color
-@progress-bar-info-bg:        @brand-info;
-
-
-//== List group
-//
-//##
-
-//** Background color on `.list-group-item`
-@list-group-bg:                 #fff;
-//** `.list-group-item` border color
-@list-group-border:             #ddd;
-//** List group border radius
-@list-group-border-radius:      @border-radius-base;
-
-//** Background color of single list items on hover
-@list-group-hover-bg:           #f5f5f5;
-//** Text color of active list items
-@list-group-active-color:       @component-active-color;
-//** Background color of active list items
-@list-group-active-bg:          @component-active-bg;
-//** Border color of active list elements
-@list-group-active-border:      @list-group-active-bg;
-//** Text color for content within active list items
-@list-group-active-text-color:  lighten(@list-group-active-bg, 40%);
-
-//** Text color of disabled list items
-@list-group-disabled-color:      @gray-light;
-//** Background color of disabled list items
-@list-group-disabled-bg:         @gray-lighter;
-//** Text color for content within disabled list items
-@list-group-disabled-text-color: @list-group-disabled-color;
-
-@list-group-link-color:         #555;
-@list-group-link-hover-color:   @list-group-link-color;
-@list-group-link-heading-color: #333;
-
-
-//== Panels
-//
-//##
-
-@panel-bg:                    #fff;
-@panel-body-padding:          15px;
-@panel-heading-padding:       10px 15px;
-@panel-footer-padding:        @panel-heading-padding;
-@panel-border-radius:         @border-radius-base;
-
-//** Border color for elements within panels
-@panel-inner-border:          #ddd;
-@panel-footer-bg:             #f5f5f5;
-
-@panel-default-text:          @gray-dark;
-@panel-default-border:        #ddd;
-@panel-default-heading-bg:    #f5f5f5;
-
-@panel-primary-text:          #fff;
-@panel-primary-border:        @brand-primary;
-@panel-primary-heading-bg:    @brand-primary;
-
-@panel-success-text:          @state-success-text;
-@panel-success-border:        @state-success-border;
-@panel-success-heading-bg:    @state-success-bg;
-
-@panel-info-text:             @state-info-text;
-@panel-info-border:           @state-info-border;
-@panel-info-heading-bg:       @state-info-bg;
-
-@panel-warning-text:          @state-warning-text;
-@panel-warning-border:        @state-warning-border;
-@panel-warning-heading-bg:    @state-warning-bg;
-
-@panel-danger-text:           @state-danger-text;
-@panel-danger-border:         @state-danger-border;
-@panel-danger-heading-bg:     @state-danger-bg;
-
-
-//== Thumbnails
-//
-//##
-
-//** Padding around the thumbnail image
-@thumbnail-padding:           4px;
-//** Thumbnail background color
-@thumbnail-bg:                @body-bg;
-//** Thumbnail border color
-@thumbnail-border:            #ddd;
-//** Thumbnail border radius
-@thumbnail-border-radius:     @border-radius-base;
-
-//** Custom text color for thumbnail captions
-@thumbnail-caption-color:     @text-color;
-//** Padding around the thumbnail caption
-@thumbnail-caption-padding:   9px;
-
-
-//== Wells
-//
-//##
-
-@well-bg:                     #f5f5f5;
-@well-border:                 darken(@well-bg, 7%);
-
-
-//== Badges
-//
-//##
-
-@badge-color:                 #fff;
-//** Linked badge text color on hover
-@badge-link-hover-color:      #fff;
-@badge-bg:                    @gray-light;
-
-//** Badge text color in active nav link
-@badge-active-color:          @link-color;
-//** Badge background color in active nav link
-@badge-active-bg:             #fff;
-
-@badge-font-weight:           bold;
-@badge-line-height:           1;
-@badge-border-radius:         10px;
-
-
-//== Breadcrumbs
-//
-//##
-
-@breadcrumb-padding-vertical:   8px;
-@breadcrumb-padding-horizontal: 15px;
-//** Breadcrumb background color
-@breadcrumb-bg:                 #f5f5f5;
-//** Breadcrumb text color
-@breadcrumb-color:              #ccc;
-//** Text color of current page in the breadcrumb
-@breadcrumb-active-color:       @gray-light;
-//** Textual separator for between breadcrumb elements
-@breadcrumb-separator:          "/";
-
-
-//== Carousel
-//
-//##
-
-@carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6);
-
-@carousel-control-color:                      #fff;
-@carousel-control-width:                      15%;
-@carousel-control-opacity:                    .5;
-@carousel-control-font-size:                  20px;
-
-@carousel-indicator-active-bg:                #fff;
-@carousel-indicator-border-color:             #fff;
-
-@carousel-caption-color:                      #fff;
-
-
-//== Close
-//
-//##
-
-@close-font-weight:           bold;
-@close-color:                 #000;
-@close-text-shadow:           0 1px 0 #fff;
-
-
-//== Code
-//
-//##
-
-@code-color:                  #c7254e;
-@code-bg:                     #f9f2f4;
-
-@kbd-color:                   #fff;
-@kbd-bg:                      #333;
-
-@pre-bg:                      #f5f5f5;
-@pre-color:                   @gray-dark;
-@pre-border-color:            #ccc;
-@pre-scrollable-max-height:   340px;
-
-
-//== Type
-//
-//##
-
-//** Horizontal offset for forms and lists.
-@component-offset-horizontal: 180px;
-//** Text muted color
-@text-muted:                  @gray-light;
-//** Abbreviations and acronyms border color
-@abbr-border-color:           @gray-light;
-//** Headings small color
-@headings-small-color:        @gray-light;
-//** Blockquote small color
-@blockquote-small-color:      @gray-light;
-//** Blockquote font size
-@blockquote-font-size:        (@font-size-base * 1.25);
-//** Blockquote border color
-@blockquote-border-color:     @gray-lighter;
-//** Page header border color
-@page-header-border-color:    @gray-lighter;
-//** Width of horizontal description list titles
-@dl-horizontal-offset:        @component-offset-horizontal;
-//** Horizontal line color.
-@hr-border:                   @gray-lighter;
-
-.make-grid-columns() {
-  // Common styles for all sizes of grid columns, widths 1-12
-  .col(@index) { // initial
-    @item: ~".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}, .col-xl-@{index}";
-    .col((@index + 1), @item);
-  }
-  .col(@index, @list) when (@index =< @grid-columns) { // general; "=<" isn't a typo
-    @item: ~".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}, .col-xl-@{index}";
-    .col((@index + 1), ~"@{list}, @{item}");
-  }
-  .col(@index, @list) when (@index > @grid-columns) { // terminal
-    @{list} {
-      position: relative;
-      // Prevent columns from collapsing when empty
-      min-height: 1px;
-      // Inner gutter via padding
-      padding-left:  ceil((@grid-gutter-width / 2));
-      padding-right: floor((@grid-gutter-width / 2));
-    }
-  }
-  .col(1); // kickstart it
-}
-
-// Generate the large columns
-.make-xl-column(@columns; @gutter: @grid-gutter-width) {
-  position: relative;
-  min-height: 1px;
-  padding-left:  (@gutter / 2);
-  padding-right: (@gutter / 2);
-
-  @media (min-width: @screen-xl-min) {
-    float: left;
-    width: percentage((@columns / @grid-columns));
-  }
-}
-.make-xl-column-offset(@columns) {
-  @media (min-width: @screen-xl-min) {
-    margin-left: percentage((@columns / @grid-columns));
-  }
-}
-.make-xl-column-push(@columns) {
-  @media (min-width: @screen-xl-min) {
-    left: percentage((@columns / @grid-columns));
-  }
-}
-.make-xl-column-pull(@columns) {
-  @media (min-width: @screen-xl-min) {
-    right: percentage((@columns / @grid-columns));
-  }
-}
-
-.container {
-  @media (min-width: @screen-xl-min) {
-    width: @container-xl;
-  }
-}
-
-@media (min-width: @screen-xl-min) {
-  .make-grid(xl);
-}
diff --git a/client/stylesheets/vendor/custom.bootstrap.json b/client/stylesheets/vendor/custom.bootstrap.json
deleted file mode 100644
index 6e7510f4..00000000
--- a/client/stylesheets/vendor/custom.bootstrap.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
-  "modules" : {
-    "normalize"            : true,
-    "print"                : false,
-    "glyphicons"           : true,
-
-    "scaffolding"          : true,
-    "type"                 : true,
-    "code"                 : true,
-    "grid"                 : true,
-    "tables"               : true,
-    "forms"                : true,
-    "buttons"              : true,
-
-    "component-animations" : true,
-    "dropdowns"            : true,
-    "button-groups"        : false,
-    "input-groups"         : false,
-    "navs"                 : false,
-    "navbar"               : false,
-    "breadcrumbs"          : false,
-    "pagination"           : false,
-    "pager"                : false,
-    "labels"               : false,
-
-    "badges"               : true,
-    "jumbotron"            : false,
-    "thumbnails"           : true,
-    "alerts"               : false,
-    "progress-bars"        : false,
-    "media"                : false,
-    "list-group"           : false,
-    "panels"               : false,
-    "responsive-embed"     : false,
-    "wells"                : false,
-    "close"                : false,
-
-    "tooltip"              : true,
-    "modals"               : false,
-    "popovers"             : false,
-    "carousel"             : false,
-
-    "affix"                : false,
-    "alert"                : false,
-    "button"               : false,
-    "collapse"             : false,
-    "scrollspy"            : false,
-    "tab"                  : false,
-    "transition"           : true,
-
-    "utilities"            : true,
-    "responsive-utilities" : true
-  }
-}
\ No newline at end of file
diff --git a/client/stylesheets/vendor/custom.bootstrap.less b/client/stylesheets/vendor/custom.bootstrap.less
deleted file mode 100644
index 6367a0ea..00000000
--- a/client/stylesheets/vendor/custom.bootstrap.less
+++ /dev/null
@@ -1,3125 +0,0 @@
-// THIS FILE IS GENERATED, DO NOT MODIFY IT!
-// It includes the bootstrap modules configured in client/stylesheets/vendor/custom.bootstrap.json.
-// You may need to use 'meteor add less' if the styles are not loaded.
-
-// If it throws errors your bootstrap.import.less is probably invalid.
-// To fix that remove that file and then recover your changes.
-
-@import "custom.bootstrap.import.less";
-@icon-font-path: "/packages/nemo64_bootstrap-data/bootstrap/fonts/";
-
-
-// @import "bootstrap/less/normalize.less"
-/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
-
-//
-// 1. Set default font family to sans-serif.
-// 2. Prevent iOS and IE text size adjust after device orientation change,
-//    without disabling user zoom.
-//
-
-html {
-  font-family: sans-serif; // 1
-  -ms-text-size-adjust: 100%; // 2
-  -webkit-text-size-adjust: 100%; // 2
-}
-
-//
-// Remove default margin.
-//
-
-body {
-  margin: 0;
-}
-
-// HTML5 display definitions
-// ==========================================================================
-
-//
-// Correct `block` display not defined for any HTML5 element in IE 8/9.
-// Correct `block` display not defined for `details` or `summary` in IE 10/11
-// and Firefox.
-// Correct `block` display not defined for `main` in IE 11.
-//
-
-article,
-aside,
-details,
-figcaption,
-figure,
-footer,
-header,
-hgroup,
-main,
-menu,
-nav,
-section,
-summary {
-  display: block;
-}
-
-//
-// 1. Correct `inline-block` display not defined in IE 8/9.
-// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
-//
-
-audio,
-canvas,
-progress,
-video {
-  display: inline-block; // 1
-  vertical-align: baseline; // 2
-}
-
-//
-// Prevent modern browsers from displaying `audio` without controls.
-// Remove excess height in iOS 5 devices.
-//
-
-audio:not([controls]) {
-  display: none;
-  height: 0;
-}
-
-//
-// Address `[hidden]` styling not present in IE 8/9/10.
-// Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
-//
-
-[hidden],
-template {
-  display: none;
-}
-
-// Links
-// ==========================================================================
-
-//
-// Remove the gray background color from active links in IE 10.
-//
-
-a {
-  background-color: transparent;
-}
-
-//
-// Improve readability of focused elements when they are also in an
-// active/hover state.
-//
-
-a:active,
-a:hover {
-  outline: 0;
-}
-
-// Text-level semantics
-// ==========================================================================
-
-//
-// Address styling not present in IE 8/9/10/11, Safari, and Chrome.
-//
-
-abbr[title] {
-  border-bottom: 1px dotted;
-}
-
-//
-// Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
-//
-
-b,
-strong {
-  font-weight: bold;
-}
-
-//
-// Address styling not present in Safari and Chrome.
-//
-
-dfn {
-  font-style: italic;
-}
-
-//
-// Address variable `h1` font-size and margin within `section` and `article`
-// contexts in Firefox 4+, Safari, and Chrome.
-//
-
-h1 {
-  font-size: 2em;
-  margin: 0.67em 0;
-}
-
-//
-// Address styling not present in IE 8/9.
-//
-
-mark {
-  background: #ff0;
-  color: #000;
-}
-
-//
-// Address inconsistent and variable font size in all browsers.
-//
-
-small {
-  font-size: 80%;
-}
-
-//
-// Prevent `sub` and `sup` affecting `line-height` in all browsers.
-//
-
-sub,
-sup {
-  font-size: 75%;
-  line-height: 0;
-  position: relative;
-  vertical-align: baseline;
-}
-
-sup {
-  top: -0.5em;
-}
-
-sub {
-  bottom: -0.25em;
-}
-
-// Embedded content
-// ==========================================================================
-
-//
-// Remove border when inside `a` element in IE 8/9/10.
-//
-
-img {
-  border: 0;
-}
-
-//
-// Correct overflow not hidden in IE 9/10/11.
-//
-
-svg:not(:root) {
-  overflow: hidden;
-}
-
-// Grouping content
-// ==========================================================================
-
-//
-// Address margin not present in IE 8/9 and Safari.
-//
-
-figure {
-  margin: 1em 40px;
-}
-
-//
-// Address differences between Firefox and other browsers.
-//
-
-hr {
-  box-sizing: content-box;
-  height: 0;
-}
-
-//
-// Contain overflow in all browsers.
-//
-
-pre {
-  overflow: auto;
-}
-
-//
-// Address odd `em`-unit font size rendering in all browsers.
-//
-
-code,
-kbd,
-pre,
-samp {
-  font-family: monospace, monospace;
-  font-size: 1em;
-}
-
-// Forms
-// ==========================================================================
-
-//
-// Known limitation: by default, Chrome and Safari on OS X allow very limited
-// styling of `select`, unless a `border` property is set.
-//
-
-//
-// 1. Correct color not being inherited.
-//    Known issue: affects color of disabled elements.
-// 2. Correct font properties not being inherited.
-// 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
-//
-
-button,
-input,
-optgroup,
-select,
-textarea {
-  color: inherit; // 1
-  font: inherit; // 2
-  margin: 0; // 3
-}
-
-//
-// Address `overflow` set to `hidden` in IE 8/9/10/11.
-//
-
-button {
-  overflow: visible;
-}
-
-//
-// Address inconsistent `text-transform` inheritance for `button` and `select`.
-// All other form control elements do not inherit `text-transform` values.
-// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
-// Correct `select` style inheritance in Firefox.
-//
-
-button,
-select {
-  text-transform: none;
-}
-
-//
-// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
-//    and `video` controls.
-// 2. Correct inability to style clickable `input` types in iOS.
-// 3. Improve usability and consistency of cursor style between image-type
-//    `input` and others.
-//
-
-button,
-html input[type="button"], // 1
-input[type="reset"],
-input[type="submit"] {
-  -webkit-appearance: button; // 2
-  cursor: pointer; // 3
-}
-
-//
-// Re-set default cursor for disabled elements.
-//
-
-button[disabled],
-html input[disabled] {
-  cursor: default;
-}
-
-//
-// Remove inner padding and border in Firefox 4+.
-//
-
-button::-moz-focus-inner,
-input::-moz-focus-inner {
-  border: 0;
-  padding: 0;
-}
-
-//
-// Address Firefox 4+ setting `line-height` on `input` using `!important` in
-// the UA stylesheet.
-//
-
-input {
-  line-height: normal;
-}
-
-//
-// It's recommended that you don't attempt to style these elements.
-// Firefox's implementation doesn't respect box-sizing, padding, or width.
-//
-// 1. Address box sizing set to `content-box` in IE 8/9/10.
-// 2. Remove excess padding in IE 8/9/10.
-//
-
-input[type="checkbox"],
-input[type="radio"] {
-  box-sizing: border-box; // 1
-  padding: 0; // 2
-}
-
-//
-// Fix the cursor style for Chrome's increment/decrement buttons. For certain
-// `font-size` values of the `input`, it causes the cursor style of the
-// decrement button to change from `default` to `text`.
-//
-
-input[type="number"]::-webkit-inner-spin-button,
-input[type="number"]::-webkit-outer-spin-button {
-  height: auto;
-}
-
-//
-// 1. Address `appearance` set to `searchfield` in Safari and Chrome.
-// 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
-//
-
-input[type="search"] {
-  -webkit-appearance: textfield; // 1
-  box-sizing: content-box; //2
-}
-
-//
-// Remove inner padding and search cancel button in Safari and Chrome on OS X.
-// Safari (but not Chrome) clips the cancel button when the search input has
-// padding (and `textfield` appearance).
-//
-
-input[type="search"]::-webkit-search-cancel-button,
-input[type="search"]::-webkit-search-decoration {
-  -webkit-appearance: none;
-}
-
-//
-// Define consistent border, margin, and padding.
-//
-
-fieldset {
-  border: 1px solid #c0c0c0;
-  margin: 0 2px;
-  padding: 0.35em 0.625em 0.75em;
-}
-
-//
-// 1. Correct `color` not being inherited in IE 8/9/10/11.
-// 2. Remove padding so people aren't caught out if they zero out fieldsets.
-//
-
-legend {
-  border: 0; // 1
-  padding: 0; // 2
-}
-
-//
-// Remove default vertical scrollbar in IE 8/9/10/11.
-//
-
-textarea {
-  overflow: auto;
-}
-
-//
-// Don't inherit the `font-weight` (applied by a rule above).
-// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
-//
-
-optgroup {
-  font-weight: bold;
-}
-
-// Tables
-// ==========================================================================
-
-//
-// Remove most spacing between table cells.
-//
-
-table {
-  border-collapse: collapse;
-  border-spacing: 0;
-}
-
-td,
-th {
-  padding: 0;
-}
-
-
-
-// @import "bootstrap/less/glyphicons.less"
-//
-// Glyphicons for Bootstrap
-//
-// Since icons are fonts, they can be placed anywhere text is placed and are
-// thus automatically sized to match the surrounding child. To use, create an
-// inline element with the appropriate classes, like so:
-//
-//  Star
-
-// Import the fonts
-@font-face {
-  font-family: 'Glyphicons Halflings';
-  src: url('@{icon-font-path}@{icon-font-name}.eot');
-  src: url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype'),
-       url('@{icon-font-path}@{icon-font-name}.woff2') format('woff2'),
-       url('@{icon-font-path}@{icon-font-name}.woff') format('woff'),
-       url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype'),
-       url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg');
-}
-
-// Catchall baseclass
-.glyphicon {
-  position: relative;
-  top: 1px;
-  display: inline-block;
-  font-family: 'Glyphicons Halflings';
-  font-style: normal;
-  font-weight: normal;
-  line-height: 1;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-}
-
-// Individual icons
-.glyphicon-asterisk               { &:before { content: "\2a"; } }
-.glyphicon-plus                   { &:before { content: "\2b"; } }
-.glyphicon-euro,
-.glyphicon-eur                    { &:before { content: "\20ac"; } }
-.glyphicon-minus                  { &:before { content: "\2212"; } }
-.glyphicon-cloud                  { &:before { content: "\2601"; } }
-.glyphicon-envelope               { &:before { content: "\2709"; } }
-.glyphicon-pencil                 { &:before { content: "\270f"; } }
-.glyphicon-glass                  { &:before { content: "\e001"; } }
-.glyphicon-music                  { &:before { content: "\e002"; } }
-.glyphicon-search                 { &:before { content: "\e003"; } }
-.glyphicon-heart                  { &:before { content: "\e005"; } }
-.glyphicon-star                   { &:before { content: "\e006"; } }
-.glyphicon-star-empty             { &:before { content: "\e007"; } }
-.glyphicon-user                   { &:before { content: "\e008"; } }
-.glyphicon-film                   { &:before { content: "\e009"; } }
-.glyphicon-th-large               { &:before { content: "\e010"; } }
-.glyphicon-th                     { &:before { content: "\e011"; } }
-.glyphicon-th-list                { &:before { content: "\e012"; } }
-.glyphicon-ok                     { &:before { content: "\e013"; } }
-.glyphicon-remove                 { &:before { content: "\e014"; } }
-.glyphicon-zoom-in                { &:before { content: "\e015"; } }
-.glyphicon-zoom-out               { &:before { content: "\e016"; } }
-.glyphicon-off                    { &:before { content: "\e017"; } }
-.glyphicon-signal                 { &:before { content: "\e018"; } }
-.glyphicon-cog                    { &:before { content: "\e019"; } }
-.glyphicon-trash                  { &:before { content: "\e020"; } }
-.glyphicon-home                   { &:before { content: "\e021"; } }
-.glyphicon-file                   { &:before { content: "\e022"; } }
-.glyphicon-time                   { &:before { content: "\e023"; } }
-.glyphicon-road                   { &:before { content: "\e024"; } }
-.glyphicon-download-alt           { &:before { content: "\e025"; } }
-.glyphicon-download               { &:before { content: "\e026"; } }
-.glyphicon-upload                 { &:before { content: "\e027"; } }
-.glyphicon-inbox                  { &:before { content: "\e028"; } }
-.glyphicon-play-circle            { &:before { content: "\e029"; } }
-.glyphicon-repeat                 { &:before { content: "\e030"; } }
-.glyphicon-refresh                { &:before { content: "\e031"; } }
-.glyphicon-list-alt               { &:before { content: "\e032"; } }
-.glyphicon-lock                   { &:before { content: "\e033"; } }
-.glyphicon-flag                   { &:before { content: "\e034"; } }
-.glyphicon-headphones             { &:before { content: "\e035"; } }
-.glyphicon-volume-off             { &:before { content: "\e036"; } }
-.glyphicon-volume-down            { &:before { content: "\e037"; } }
-.glyphicon-volume-up              { &:before { content: "\e038"; } }
-.glyphicon-qrcode                 { &:before { content: "\e039"; } }
-.glyphicon-barcode                { &:before { content: "\e040"; } }
-.glyphicon-tag                    { &:before { content: "\e041"; } }
-.glyphicon-tags                   { &:before { content: "\e042"; } }
-.glyphicon-book                   { &:before { content: "\e043"; } }
-.glyphicon-bookmark               { &:before { content: "\e044"; } }
-.glyphicon-print                  { &:before { content: "\e045"; } }
-.glyphicon-camera                 { &:before { content: "\e046"; } }
-.glyphicon-font                   { &:before { content: "\e047"; } }
-.glyphicon-bold                   { &:before { content: "\e048"; } }
-.glyphicon-italic                 { &:before { content: "\e049"; } }
-.glyphicon-text-height            { &:before { content: "\e050"; } }
-.glyphicon-text-width             { &:before { content: "\e051"; } }
-.glyphicon-align-left             { &:before { content: "\e052"; } }
-.glyphicon-align-center           { &:before { content: "\e053"; } }
-.glyphicon-align-right            { &:before { content: "\e054"; } }
-.glyphicon-align-justify          { &:before { content: "\e055"; } }
-.glyphicon-list                   { &:before { content: "\e056"; } }
-.glyphicon-indent-left            { &:before { content: "\e057"; } }
-.glyphicon-indent-right           { &:before { content: "\e058"; } }
-.glyphicon-facetime-video         { &:before { content: "\e059"; } }
-.glyphicon-picture                { &:before { content: "\e060"; } }
-.glyphicon-map-marker             { &:before { content: "\e062"; } }
-.glyphicon-adjust                 { &:before { content: "\e063"; } }
-.glyphicon-tint                   { &:before { content: "\e064"; } }
-.glyphicon-edit                   { &:before { content: "\e065"; } }
-.glyphicon-share                  { &:before { content: "\e066"; } }
-.glyphicon-check                  { &:before { content: "\e067"; } }
-.glyphicon-move                   { &:before { content: "\e068"; } }
-.glyphicon-step-backward          { &:before { content: "\e069"; } }
-.glyphicon-fast-backward          { &:before { content: "\e070"; } }
-.glyphicon-backward               { &:before { content: "\e071"; } }
-.glyphicon-play                   { &:before { content: "\e072"; } }
-.glyphicon-pause                  { &:before { content: "\e073"; } }
-.glyphicon-stop                   { &:before { content: "\e074"; } }
-.glyphicon-forward                { &:before { content: "\e075"; } }
-.glyphicon-fast-forward           { &:before { content: "\e076"; } }
-.glyphicon-step-forward           { &:before { content: "\e077"; } }
-.glyphicon-eject                  { &:before { content: "\e078"; } }
-.glyphicon-chevron-left           { &:before { content: "\e079"; } }
-.glyphicon-chevron-right          { &:before { content: "\e080"; } }
-.glyphicon-plus-sign              { &:before { content: "\e081"; } }
-.glyphicon-minus-sign             { &:before { content: "\e082"; } }
-.glyphicon-remove-sign            { &:before { content: "\e083"; } }
-.glyphicon-ok-sign                { &:before { content: "\e084"; } }
-.glyphicon-question-sign          { &:before { content: "\e085"; } }
-.glyphicon-info-sign              { &:before { content: "\e086"; } }
-.glyphicon-screenshot             { &:before { content: "\e087"; } }
-.glyphicon-remove-circle          { &:before { content: "\e088"; } }
-.glyphicon-ok-circle              { &:before { content: "\e089"; } }
-.glyphicon-ban-circle             { &:before { content: "\e090"; } }
-.glyphicon-arrow-left             { &:before { content: "\e091"; } }
-.glyphicon-arrow-right            { &:before { content: "\e092"; } }
-.glyphicon-arrow-up               { &:before { content: "\e093"; } }
-.glyphicon-arrow-down             { &:before { content: "\e094"; } }
-.glyphicon-share-alt              { &:before { content: "\e095"; } }
-.glyphicon-resize-full            { &:before { content: "\e096"; } }
-.glyphicon-resize-small           { &:before { content: "\e097"; } }
-.glyphicon-exclamation-sign       { &:before { content: "\e101"; } }
-.glyphicon-gift                   { &:before { content: "\e102"; } }
-.glyphicon-leaf                   { &:before { content: "\e103"; } }
-.glyphicon-fire                   { &:before { content: "\e104"; } }
-.glyphicon-eye-open               { &:before { content: "\e105"; } }
-.glyphicon-eye-close              { &:before { content: "\e106"; } }
-.glyphicon-warning-sign           { &:before { content: "\e107"; } }
-.glyphicon-plane                  { &:before { content: "\e108"; } }
-.glyphicon-calendar               { &:before { content: "\e109"; } }
-.glyphicon-random                 { &:before { content: "\e110"; } }
-.glyphicon-comment                { &:before { content: "\e111"; } }
-.glyphicon-magnet                 { &:before { content: "\e112"; } }
-.glyphicon-chevron-up             { &:before { content: "\e113"; } }
-.glyphicon-chevron-down           { &:before { content: "\e114"; } }
-.glyphicon-retweet                { &:before { content: "\e115"; } }
-.glyphicon-shopping-cart          { &:before { content: "\e116"; } }
-.glyphicon-folder-close           { &:before { content: "\e117"; } }
-.glyphicon-folder-open            { &:before { content: "\e118"; } }
-.glyphicon-resize-vertical        { &:before { content: "\e119"; } }
-.glyphicon-resize-horizontal      { &:before { content: "\e120"; } }
-.glyphicon-hdd                    { &:before { content: "\e121"; } }
-.glyphicon-bullhorn               { &:before { content: "\e122"; } }
-.glyphicon-bell                   { &:before { content: "\e123"; } }
-.glyphicon-certificate            { &:before { content: "\e124"; } }
-.glyphicon-thumbs-up              { &:before { content: "\e125"; } }
-.glyphicon-thumbs-down            { &:before { content: "\e126"; } }
-.glyphicon-hand-right             { &:before { content: "\e127"; } }
-.glyphicon-hand-left              { &:before { content: "\e128"; } }
-.glyphicon-hand-up                { &:before { content: "\e129"; } }
-.glyphicon-hand-down              { &:before { content: "\e130"; } }
-.glyphicon-circle-arrow-right     { &:before { content: "\e131"; } }
-.glyphicon-circle-arrow-left      { &:before { content: "\e132"; } }
-.glyphicon-circle-arrow-up        { &:before { content: "\e133"; } }
-.glyphicon-circle-arrow-down      { &:before { content: "\e134"; } }
-.glyphicon-globe                  { &:before { content: "\e135"; } }
-.glyphicon-wrench                 { &:before { content: "\e136"; } }
-.glyphicon-tasks                  { &:before { content: "\e137"; } }
-.glyphicon-filter                 { &:before { content: "\e138"; } }
-.glyphicon-briefcase              { &:before { content: "\e139"; } }
-.glyphicon-fullscreen             { &:before { content: "\e140"; } }
-.glyphicon-dashboard              { &:before { content: "\e141"; } }
-.glyphicon-paperclip              { &:before { content: "\e142"; } }
-.glyphicon-heart-empty            { &:before { content: "\e143"; } }
-.glyphicon-link                   { &:before { content: "\e144"; } }
-.glyphicon-phone                  { &:before { content: "\e145"; } }
-.glyphicon-pushpin                { &:before { content: "\e146"; } }
-.glyphicon-usd                    { &:before { content: "\e148"; } }
-.glyphicon-gbp                    { &:before { content: "\e149"; } }
-.glyphicon-sort                   { &:before { content: "\e150"; } }
-.glyphicon-sort-by-alphabet       { &:before { content: "\e151"; } }
-.glyphicon-sort-by-alphabet-alt   { &:before { content: "\e152"; } }
-.glyphicon-sort-by-order          { &:before { content: "\e153"; } }
-.glyphicon-sort-by-order-alt      { &:before { content: "\e154"; } }
-.glyphicon-sort-by-attributes     { &:before { content: "\e155"; } }
-.glyphicon-sort-by-attributes-alt { &:before { content: "\e156"; } }
-.glyphicon-unchecked              { &:before { content: "\e157"; } }
-.glyphicon-expand                 { &:before { content: "\e158"; } }
-.glyphicon-collapse-down          { &:before { content: "\e159"; } }
-.glyphicon-collapse-up            { &:before { content: "\e160"; } }
-.glyphicon-log-in                 { &:before { content: "\e161"; } }
-.glyphicon-flash                  { &:before { content: "\e162"; } }
-.glyphicon-log-out                { &:before { content: "\e163"; } }
-.glyphicon-new-window             { &:before { content: "\e164"; } }
-.glyphicon-record                 { &:before { content: "\e165"; } }
-.glyphicon-save                   { &:before { content: "\e166"; } }
-.glyphicon-open                   { &:before { content: "\e167"; } }
-.glyphicon-saved                  { &:before { content: "\e168"; } }
-.glyphicon-import                 { &:before { content: "\e169"; } }
-.glyphicon-export                 { &:before { content: "\e170"; } }
-.glyphicon-send                   { &:before { content: "\e171"; } }
-.glyphicon-floppy-disk            { &:before { content: "\e172"; } }
-.glyphicon-floppy-saved           { &:before { content: "\e173"; } }
-.glyphicon-floppy-remove          { &:before { content: "\e174"; } }
-.glyphicon-floppy-save            { &:before { content: "\e175"; } }
-.glyphicon-floppy-open            { &:before { content: "\e176"; } }
-.glyphicon-credit-card            { &:before { content: "\e177"; } }
-.glyphicon-transfer               { &:before { content: "\e178"; } }
-.glyphicon-cutlery                { &:before { content: "\e179"; } }
-.glyphicon-header                 { &:before { content: "\e180"; } }
-.glyphicon-compressed             { &:before { content: "\e181"; } }
-.glyphicon-earphone               { &:before { content: "\e182"; } }
-.glyphicon-phone-alt              { &:before { content: "\e183"; } }
-.glyphicon-tower                  { &:before { content: "\e184"; } }
-.glyphicon-stats                  { &:before { content: "\e185"; } }
-.glyphicon-sd-video               { &:before { content: "\e186"; } }
-.glyphicon-hd-video               { &:before { content: "\e187"; } }
-.glyphicon-subtitles              { &:before { content: "\e188"; } }
-.glyphicon-sound-stereo           { &:before { content: "\e189"; } }
-.glyphicon-sound-dolby            { &:before { content: "\e190"; } }
-.glyphicon-sound-5-1              { &:before { content: "\e191"; } }
-.glyphicon-sound-6-1              { &:before { content: "\e192"; } }
-.glyphicon-sound-7-1              { &:before { content: "\e193"; } }
-.glyphicon-copyright-mark         { &:before { content: "\e194"; } }
-.glyphicon-registration-mark      { &:before { content: "\e195"; } }
-.glyphicon-cloud-download         { &:before { content: "\e197"; } }
-.glyphicon-cloud-upload           { &:before { content: "\e198"; } }
-.glyphicon-tree-conifer           { &:before { content: "\e199"; } }
-.glyphicon-tree-deciduous         { &:before { content: "\e200"; } }
-.glyphicon-cd                     { &:before { content: "\e201"; } }
-.glyphicon-save-file              { &:before { content: "\e202"; } }
-.glyphicon-open-file              { &:before { content: "\e203"; } }
-.glyphicon-level-up               { &:before { content: "\e204"; } }
-.glyphicon-copy                   { &:before { content: "\e205"; } }
-.glyphicon-paste                  { &:before { content: "\e206"; } }
-// The following 2 Glyphicons are omitted for the time being because
-// they currently use Unicode codepoints that are outside the
-// Basic Multilingual Plane (BMP). Older buggy versions of WebKit can't handle
-// non-BMP codepoints in CSS string escapes, and thus can't display these two icons.
-// Notably, the bug affects some older versions of the Android Browser.
-// More info: https://github.com/twbs/bootstrap/issues/10106
-// .glyphicon-door                   { &:before { content: "\1f6aa"; } }
-// .glyphicon-key                    { &:before { content: "\1f511"; } }
-.glyphicon-alert                  { &:before { content: "\e209"; } }
-.glyphicon-equalizer              { &:before { content: "\e210"; } }
-.glyphicon-king                   { &:before { content: "\e211"; } }
-.glyphicon-queen                  { &:before { content: "\e212"; } }
-.glyphicon-pawn                   { &:before { content: "\e213"; } }
-.glyphicon-bishop                 { &:before { content: "\e214"; } }
-.glyphicon-knight                 { &:before { content: "\e215"; } }
-.glyphicon-baby-formula           { &:before { content: "\e216"; } }
-.glyphicon-tent                   { &:before { content: "\26fa"; } }
-.glyphicon-blackboard             { &:before { content: "\e218"; } }
-.glyphicon-bed                    { &:before { content: "\e219"; } }
-.glyphicon-apple                  { &:before { content: "\f8ff"; } }
-.glyphicon-erase                  { &:before { content: "\e221"; } }
-.glyphicon-hourglass              { &:before { content: "\231b"; } }
-.glyphicon-lamp                   { &:before { content: "\e223"; } }
-.glyphicon-duplicate              { &:before { content: "\e224"; } }
-.glyphicon-piggy-bank             { &:before { content: "\e225"; } }
-.glyphicon-scissors               { &:before { content: "\e226"; } }
-.glyphicon-bitcoin                { &:before { content: "\e227"; } }
-.glyphicon-btc                    { &:before { content: "\e227"; } }
-.glyphicon-xbt                    { &:before { content: "\e227"; } }
-.glyphicon-yen                    { &:before { content: "\00a5"; } }
-.glyphicon-jpy                    { &:before { content: "\00a5"; } }
-.glyphicon-ruble                  { &:before { content: "\20bd"; } }
-.glyphicon-rub                    { &:before { content: "\20bd"; } }
-.glyphicon-scale                  { &:before { content: "\e230"; } }
-.glyphicon-ice-lolly              { &:before { content: "\e231"; } }
-.glyphicon-ice-lolly-tasted       { &:before { content: "\e232"; } }
-.glyphicon-education              { &:before { content: "\e233"; } }
-.glyphicon-option-horizontal      { &:before { content: "\e234"; } }
-.glyphicon-option-vertical        { &:before { content: "\e235"; } }
-.glyphicon-menu-hamburger         { &:before { content: "\e236"; } }
-.glyphicon-modal-window           { &:before { content: "\e237"; } }
-.glyphicon-oil                    { &:before { content: "\e238"; } }
-.glyphicon-grain                  { &:before { content: "\e239"; } }
-.glyphicon-sunglasses             { &:before { content: "\e240"; } }
-.glyphicon-text-size              { &:before { content: "\e241"; } }
-.glyphicon-text-color             { &:before { content: "\e242"; } }
-.glyphicon-text-background        { &:before { content: "\e243"; } }
-.glyphicon-object-align-top       { &:before { content: "\e244"; } }
-.glyphicon-object-align-bottom    { &:before { content: "\e245"; } }
-.glyphicon-object-align-horizontal{ &:before { content: "\e246"; } }
-.glyphicon-object-align-left      { &:before { content: "\e247"; } }
-.glyphicon-object-align-vertical  { &:before { content: "\e248"; } }
-.glyphicon-object-align-right     { &:before { content: "\e249"; } }
-.glyphicon-triangle-right         { &:before { content: "\e250"; } }
-.glyphicon-triangle-left          { &:before { content: "\e251"; } }
-.glyphicon-triangle-bottom        { &:before { content: "\e252"; } }
-.glyphicon-triangle-top           { &:before { content: "\e253"; } }
-.glyphicon-console                { &:before { content: "\e254"; } }
-.glyphicon-superscript            { &:before { content: "\e255"; } }
-.glyphicon-subscript              { &:before { content: "\e256"; } }
-.glyphicon-menu-left              { &:before { content: "\e257"; } }
-.glyphicon-menu-right             { &:before { content: "\e258"; } }
-.glyphicon-menu-down              { &:before { content: "\e259"; } }
-.glyphicon-menu-up                { &:before { content: "\e260"; } }
-
-
-
-// @import "bootstrap/less/scaffolding.less"
-//
-// Scaffolding
-// --------------------------------------------------
-
-
-// Reset the box-sizing
-//
-// Heads up! This reset may cause conflicts with some third-party widgets.
-// For recommendations on resolving such conflicts, see
-// http://getbootstrap.com/getting-started/#third-box-sizing
-* {
-  .box-sizing(border-box);
-}
-*:before,
-*:after {
-  .box-sizing(border-box);
-}
-
-
-// Body reset
-
-html {
-  font-size: 10px;
-  -webkit-tap-highlight-color: rgba(0,0,0,0);
-}
-
-body {
-  font-family: @font-family-base;
-  font-size: @font-size-base;
-  line-height: @line-height-base;
-  color: @text-color;
-  background-color: @body-bg;
-}
-
-// Reset fonts for relevant elements
-input,
-button,
-select,
-textarea {
-  font-family: inherit;
-  font-size: inherit;
-  line-height: inherit;
-}
-
-
-// Links
-
-a {
-  color: @link-color;
-  text-decoration: none;
-
-  &:hover,
-  &:focus {
-    color: @link-hover-color;
-    text-decoration: @link-hover-decoration;
-  }
-
-  &:focus {
-    .tab-focus();
-  }
-}
-
-
-// Figures
-//
-// We reset this here because previously Normalize had no `figure` margins. This
-// ensures we don't break anyone's use of the element.
-
-figure {
-  margin: 0;
-}
-
-
-// Images
-
-img {
-  vertical-align: middle;
-}
-
-// Responsive images (ensure images don't scale beyond their parents)
-.img-responsive {
-  .img-responsive();
-}
-
-// Rounded corners
-.img-rounded {
-  border-radius: @border-radius-large;
-}
-
-// Image thumbnails
-//
-// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.
-.img-thumbnail {
-  padding: @thumbnail-padding;
-  line-height: @line-height-base;
-  background-color: @thumbnail-bg;
-  border: 1px solid @thumbnail-border;
-  border-radius: @thumbnail-border-radius;
-  .transition(all .2s ease-in-out);
-
-  // Keep them at most 100% wide
-  .img-responsive(inline-block);
-}
-
-// Perfect circle
-.img-circle {
-  border-radius: 50%; // set radius in percents
-}
-
-
-// Horizontal rules
-
-hr {
-  margin-top:    @line-height-computed;
-  margin-bottom: @line-height-computed;
-  border: 0;
-  border-top: 1px solid @hr-border;
-}
-
-
-// Only display content to screen readers
-//
-// See: http://a11yproject.com/posts/how-to-hide-content/
-
-.sr-only {
-  position: absolute;
-  width: 1px;
-  height: 1px;
-  margin: -1px;
-  padding: 0;
-  overflow: hidden;
-  clip: rect(0,0,0,0);
-  border: 0;
-}
-
-// Use in conjunction with .sr-only to only display content when it's focused.
-// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
-// Credit: HTML5 Boilerplate
-
-.sr-only-focusable {
-  &:active,
-  &:focus {
-    position: static;
-    width: auto;
-    height: auto;
-    margin: 0;
-    overflow: visible;
-    clip: auto;
-  }
-}
-
-
-// iOS "clickable elements" fix for role="button"
-//
-// Fixes "clickability" issue (and more generally, the firing of events such as focus as well)
-// for traditionally non-focusable elements with role="button"
-// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
-
-[role="button"] {
-  cursor: pointer;
-}
-
-
-
-// @import "bootstrap/less/type.less"
-//
-// Typography
-// --------------------------------------------------
-
-
-// Headings
-// -------------------------
-
-h1, h2, h3, h4, h5, h6,
-.h1, .h2, .h3, .h4, .h5, .h6 {
-  font-family: @headings-font-family;
-  font-weight: @headings-font-weight;
-  line-height: @headings-line-height;
-  color: @headings-color;
-
-  small,
-  .small {
-    font-weight: normal;
-    line-height: 1;
-    color: @headings-small-color;
-  }
-}
-
-h1, .h1,
-h2, .h2,
-h3, .h3 {
-  margin-top: @line-height-computed;
-  margin-bottom: (@line-height-computed / 2);
-
-  small,
-  .small {
-    font-size: 65%;
-  }
-}
-h4, .h4,
-h5, .h5,
-h6, .h6 {
-  margin-top: (@line-height-computed / 2);
-  margin-bottom: (@line-height-computed / 2);
-
-  small,
-  .small {
-    font-size: 75%;
-  }
-}
-
-h1, .h1 { font-size: @font-size-h1; }
-h2, .h2 { font-size: @font-size-h2; }
-h3, .h3 { font-size: @font-size-h3; }
-h4, .h4 { font-size: @font-size-h4; }
-h5, .h5 { font-size: @font-size-h5; }
-h6, .h6 { font-size: @font-size-h6; }
-
-
-// Body text
-// -------------------------
-
-p {
-  margin: 0 0 (@line-height-computed / 2);
-}
-
-.lead {
-  margin-bottom: @line-height-computed;
-  font-size: floor((@font-size-base * 1.15));
-  font-weight: 300;
-  line-height: 1.4;
-
-  @media (min-width: @screen-sm-min) {
-    font-size: (@font-size-base * 1.5);
-  }
-}
-
-
-// Emphasis & misc
-// -------------------------
-
-// Ex: (12px small font / 14px base font) * 100% = about 85%
-small,
-.small {
-  font-size: floor((100% * @font-size-small / @font-size-base));
-}
-
-mark,
-.mark {
-  background-color: @state-warning-bg;
-  padding: .2em;
-}
-
-// Alignment
-.text-left           { text-align: left; }
-.text-right          { text-align: right; }
-.text-center         { text-align: center; }
-.text-justify        { text-align: justify; }
-.text-nowrap         { white-space: nowrap; }
-
-// Transformation
-.text-lowercase      { text-transform: lowercase; }
-.text-uppercase      { text-transform: uppercase; }
-.text-capitalize     { text-transform: capitalize; }
-
-// Contextual colors
-.text-muted {
-  color: @text-muted;
-}
-.text-primary {
-  .text-emphasis-variant(@brand-primary);
-}
-.text-success {
-  .text-emphasis-variant(@state-success-text);
-}
-.text-info {
-  .text-emphasis-variant(@state-info-text);
-}
-.text-warning {
-  .text-emphasis-variant(@state-warning-text);
-}
-.text-danger {
-  .text-emphasis-variant(@state-danger-text);
-}
-
-// Contextual backgrounds
-// For now we'll leave these alongside the text classes until v4 when we can
-// safely shift things around (per SemVer rules).
-.bg-primary {
-  // Given the contrast here, this is the only class to have its color inverted
-  // automatically.
-  color: #fff;
-  .bg-variant(@brand-primary);
-}
-.bg-success {
-  .bg-variant(@state-success-bg);
-}
-.bg-info {
-  .bg-variant(@state-info-bg);
-}
-.bg-warning {
-  .bg-variant(@state-warning-bg);
-}
-.bg-danger {
-  .bg-variant(@state-danger-bg);
-}
-
-
-// Page header
-// -------------------------
-
-.page-header {
-  padding-bottom: ((@line-height-computed / 2) - 1);
-  margin: (@line-height-computed * 2) 0 @line-height-computed;
-  border-bottom: 1px solid @page-header-border-color;
-}
-
-
-// Lists
-// -------------------------
-
-// Unordered and Ordered lists
-ul,
-ol {
-  margin-top: 0;
-  margin-bottom: (@line-height-computed / 2);
-  ul,
-  ol {
-    margin-bottom: 0;
-  }
-}
-
-// List options
-
-// Unstyled keeps list items block level, just removes default browser padding and list-style
-.list-unstyled {
-  padding-left: 0;
-  list-style: none;
-}
-
-// Inline turns list items into inline-block
-.list-inline {
-  .list-unstyled();
-  margin-left: -5px;
-
-  > li {
-    display: inline-block;
-    padding-left: 5px;
-    padding-right: 5px;
-  }
-}
-
-// Description Lists
-dl {
-  margin-top: 0; // Remove browser default
-  margin-bottom: @line-height-computed;
-}
-dt,
-dd {
-  line-height: @line-height-base;
-}
-dt {
-  font-weight: bold;
-}
-dd {
-  margin-left: 0; // Undo browser default
-}
-
-// Horizontal description lists
-//
-// Defaults to being stacked without any of the below styles applied, until the
-// grid breakpoint is reached (default of ~768px).
-
-.dl-horizontal {
-  dd {
-    &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present
-  }
-
-  @media (min-width: @grid-float-breakpoint) {
-    dt {
-      float: left;
-      width: (@dl-horizontal-offset - 20);
-      clear: left;
-      text-align: right;
-      .text-overflow();
-    }
-    dd {
-      margin-left: @dl-horizontal-offset;
-    }
-  }
-}
-
-
-// Misc
-// -------------------------
-
-// Abbreviations and acronyms
-abbr[title],
-// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257
-abbr[data-original-title] {
-  cursor: help;
-  border-bottom: 1px dotted @abbr-border-color;
-}
-.initialism {
-  font-size: 90%;
-  .text-uppercase();
-}
-
-// Blockquotes
-blockquote {
-  padding: (@line-height-computed / 2) @line-height-computed;
-  margin: 0 0 @line-height-computed;
-  font-size: @blockquote-font-size;
-  border-left: 5px solid @blockquote-border-color;
-
-  p,
-  ul,
-  ol {
-    &:last-child {
-      margin-bottom: 0;
-    }
-  }
-
-  // Note: Deprecated small and .small as of v3.1.0
-  // Context: https://github.com/twbs/bootstrap/issues/11660
-  footer,
-  small,
-  .small {
-    display: block;
-    font-size: 80%; // back to default font-size
-    line-height: @line-height-base;
-    color: @blockquote-small-color;
-
-    &:before {
-      content: '\2014 \00A0'; // em dash, nbsp
-    }
-  }
-}
-
-// Opposite alignment of blockquote
-//
-// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.
-.blockquote-reverse,
-blockquote.pull-right {
-  padding-right: 15px;
-  padding-left: 0;
-  border-right: 5px solid @blockquote-border-color;
-  border-left: 0;
-  text-align: right;
-
-  // Account for citation
-  footer,
-  small,
-  .small {
-    &:before { content: ''; }
-    &:after {
-      content: '\00A0 \2014'; // nbsp, em dash
-    }
-  }
-}
-
-// Addresses
-address {
-  margin-bottom: @line-height-computed;
-  font-style: normal;
-  line-height: @line-height-base;
-}
-
-
-
-// @import "bootstrap/less/code.less"
-//
-// Code (inline and block)
-// --------------------------------------------------
-
-
-// Inline and block code styles
-code,
-kbd,
-pre,
-samp {
-  font-family: @font-family-monospace;
-}
-
-// Inline code
-code {
-  padding: 2px 4px;
-  font-size: 90%;
-  color: @code-color;
-  background-color: @code-bg;
-  border-radius: @border-radius-base;
-}
-
-// User input typically entered via keyboard
-kbd {
-  padding: 2px 4px;
-  font-size: 90%;
-  color: @kbd-color;
-  background-color: @kbd-bg;
-  border-radius: @border-radius-small;
-  box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);
-
-  kbd {
-    padding: 0;
-    font-size: 100%;
-    font-weight: bold;
-    box-shadow: none;
-  }
-}
-
-// Blocks of code
-pre {
-  display: block;
-  padding: ((@line-height-computed - 1) / 2);
-  margin: 0 0 (@line-height-computed / 2);
-  font-size: (@font-size-base - 1); // 14px to 13px
-  line-height: @line-height-base;
-  word-break: break-all;
-  word-wrap: break-word;
-  color: @pre-color;
-  background-color: @pre-bg;
-  border: 1px solid @pre-border-color;
-  border-radius: @border-radius-base;
-
-  // Account for some code outputs that place code tags in pre tags
-  code {
-    padding: 0;
-    font-size: inherit;
-    color: inherit;
-    white-space: pre-wrap;
-    background-color: transparent;
-    border-radius: 0;
-  }
-}
-
-// Enable scrollable blocks of code
-.pre-scrollable {
-  max-height: @pre-scrollable-max-height;
-  overflow-y: scroll;
-}
-
-
-
-// @import "bootstrap/less/grid.less"
-//
-// Grid system
-// --------------------------------------------------
-
-
-// Container widths
-//
-// Set the container width, and override it for fixed navbars in media queries.
-
-.container {
-  .container-fixed();
-
-  @media (min-width: @screen-sm-min) {
-    width: @container-sm;
-  }
-  @media (min-width: @screen-md-min) {
-    width: @container-md;
-  }
-  @media (min-width: @screen-lg-min) {
-    width: @container-lg;
-  }
-}
-
-
-// Fluid container
-//
-// Utilizes the mixin meant for fixed width containers, but without any defined
-// width for fluid, full width layouts.
-
-.container-fluid {
-  .container-fixed();
-}
-
-
-// Row
-//
-// Rows contain and clear the floats of your columns.
-
-.row {
-  .make-row();
-}
-
-
-// Columns
-//
-// Common styles for small and large grid columns
-
-.make-grid-columns();
-
-
-// Extra small grid
-//
-// Columns, offsets, pushes, and pulls for extra small devices like
-// smartphones.
-
-.make-grid(xs);
-
-
-// Small grid
-//
-// Columns, offsets, pushes, and pulls for the small device range, from phones
-// to tablets.
-
-@media (min-width: @screen-sm-min) {
-  .make-grid(sm);
-}
-
-
-// Medium grid
-//
-// Columns, offsets, pushes, and pulls for the desktop device range.
-
-@media (min-width: @screen-md-min) {
-  .make-grid(md);
-}
-
-
-// Large grid
-//
-// Columns, offsets, pushes, and pulls for the large desktop device range.
-
-@media (min-width: @screen-lg-min) {
-  .make-grid(lg);
-}
-
-
-
-// @import "bootstrap/less/tables.less"
-//
-// Tables
-// --------------------------------------------------
-
-
-table {
-  background-color: @table-bg;
-}
-caption {
-  padding-top: @table-cell-padding;
-  padding-bottom: @table-cell-padding;
-  color: @text-muted;
-  text-align: left;
-}
-th {
-  text-align: left;
-}
-
-
-// Baseline styles
-
-.table {
-  width: 100%;
-  max-width: 100%;
-  margin-bottom: @line-height-computed;
-  // Cells
-  > thead,
-  > tbody,
-  > tfoot {
-    > tr {
-      > th,
-      > td {
-        padding: @table-cell-padding;
-        line-height: @line-height-base;
-        vertical-align: top;
-        border-top: 1px solid @table-border-color;
-      }
-    }
-  }
-  // Bottom align for column headings
-  > thead > tr > th {
-    vertical-align: bottom;
-    border-bottom: 2px solid @table-border-color;
-  }
-  // Remove top border from thead by default
-  > caption + thead,
-  > colgroup + thead,
-  > thead:first-child {
-    > tr:first-child {
-      > th,
-      > td {
-        border-top: 0;
-      }
-    }
-  }
-  // Account for multiple tbody instances
-  > tbody + tbody {
-    border-top: 2px solid @table-border-color;
-  }
-
-  // Nesting
-  .table {
-    background-color: @body-bg;
-  }
-}
-
-
-// Condensed table w/ half padding
-
-.table-condensed {
-  > thead,
-  > tbody,
-  > tfoot {
-    > tr {
-      > th,
-      > td {
-        padding: @table-condensed-cell-padding;
-      }
-    }
-  }
-}
-
-
-// Bordered version
-//
-// Add borders all around the table and between all the columns.
-
-.table-bordered {
-  border: 1px solid @table-border-color;
-  > thead,
-  > tbody,
-  > tfoot {
-    > tr {
-      > th,
-      > td {
-        border: 1px solid @table-border-color;
-      }
-    }
-  }
-  > thead > tr {
-    > th,
-    > td {
-      border-bottom-width: 2px;
-    }
-  }
-}
-
-
-// Zebra-striping
-//
-// Default zebra-stripe styles (alternating gray and transparent backgrounds)
-
-.table-striped {
-  > tbody > tr:nth-of-type(odd) {
-    background-color: @table-bg-accent;
-  }
-}
-
-
-// Hover effect
-//
-// Placed here since it has to come after the potential zebra striping
-
-.table-hover {
-  > tbody > tr:hover {
-    background-color: @table-bg-hover;
-  }
-}
-
-
-// Table cell sizing
-//
-// Reset default table behavior
-
-table col[class*="col-"] {
-  position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)
-  float: none;
-  display: table-column;
-}
-table {
-  td,
-  th {
-    &[class*="col-"] {
-      position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)
-      float: none;
-      display: table-cell;
-    }
-  }
-}
-
-
-// Table backgrounds
-//
-// Exact selectors below required to override `.table-striped` and prevent
-// inheritance to nested tables.
-
-// Generate the contextual variants
-.table-row-variant(active; @table-bg-active);
-.table-row-variant(success; @state-success-bg);
-.table-row-variant(info; @state-info-bg);
-.table-row-variant(warning; @state-warning-bg);
-.table-row-variant(danger; @state-danger-bg);
-
-
-// Responsive tables
-//
-// Wrap your tables in `.table-responsive` and we'll make them mobile friendly
-// by enabling horizontal scrolling. Only applies <768px. Everything above that
-// will display normally.
-
-.table-responsive {
-  overflow-x: auto;
-  min-height: 0.01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837)
-
-  @media screen and (max-width: @screen-xs-max) {
-    width: 100%;
-    margin-bottom: (@line-height-computed * 0.75);
-    overflow-y: hidden;
-    -ms-overflow-style: -ms-autohiding-scrollbar;
-    border: 1px solid @table-border-color;
-
-    // Tighten up spacing
-    > .table {
-      margin-bottom: 0;
-
-      // Ensure the content doesn't wrap
-      > thead,
-      > tbody,
-      > tfoot {
-        > tr {
-          > th,
-          > td {
-            white-space: nowrap;
-          }
-        }
-      }
-    }
-
-    // Special overrides for the bordered tables
-    > .table-bordered {
-      border: 0;
-
-      // Nuke the appropriate borders so that the parent can handle them
-      > thead,
-      > tbody,
-      > tfoot {
-        > tr {
-          > th:first-child,
-          > td:first-child {
-            border-left: 0;
-          }
-          > th:last-child,
-          > td:last-child {
-            border-right: 0;
-          }
-        }
-      }
-
-      // Only nuke the last row's bottom-border in `tbody` and `tfoot` since
-      // chances are there will be only one `tr` in a `thead` and that would
-      // remove the border altogether.
-      > tbody,
-      > tfoot {
-        > tr:last-child {
-          > th,
-          > td {
-            border-bottom: 0;
-          }
-        }
-      }
-
-    }
-  }
-}
-
-
-
-// @import "bootstrap/less/forms.less"
-//
-// Forms
-// --------------------------------------------------
-
-
-// Normalize non-controls
-//
-// Restyle and baseline non-control form elements.
-
-fieldset {
-  padding: 0;
-  margin: 0;
-  border: 0;
-  // Chrome and Firefox set a `min-width: min-content;` on fieldsets,
-  // so we reset that to ensure it behaves more like a standard block element.
-  // See https://github.com/twbs/bootstrap/issues/12359.
-  min-width: 0;
-}
-
-legend {
-  display: block;
-  width: 100%;
-  padding: 0;
-  margin-bottom: @line-height-computed;
-  font-size: (@font-size-base * 1.5);
-  line-height: inherit;
-  color: @legend-color;
-  border: 0;
-  border-bottom: 1px solid @legend-border-color;
-}
-
-label {
-  display: inline-block;
-  max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141)
-  margin-bottom: 5px;
-  font-weight: bold;
-}
-
-
-// Normalize form controls
-//
-// While most of our form styles require extra classes, some basic normalization
-// is required to ensure optimum display with or without those classes to better
-// address browser inconsistencies.
-
-// Override content-box in Normalize (* isn't specific enough)
-input[type="search"] {
-  .box-sizing(border-box);
-}
-
-// Position radios and checkboxes better
-input[type="radio"],
-input[type="checkbox"] {
-  margin: 4px 0 0;
-  margin-top: 1px \9; // IE8-9
-  line-height: normal;
-}
-
-input[type="file"] {
-  display: block;
-}
-
-// Make range inputs behave like textual form controls
-input[type="range"] {
-  display: block;
-  width: 100%;
-}
-
-// Make multiple select elements height not fixed
-select[multiple],
-select[size] {
-  height: auto;
-}
-
-// Focus for file, radio, and checkbox
-input[type="file"]:focus,
-input[type="radio"]:focus,
-input[type="checkbox"]:focus {
-  .tab-focus();
-}
-
-// Adjust output element
-output {
-  display: block;
-  padding-top: (@padding-base-vertical + 1);
-  font-size: @font-size-base;
-  line-height: @line-height-base;
-  color: @input-color;
-}
-
-
-// Common form controls
-//
-// Shared size and type resets for form controls. Apply `.form-control` to any
-// of the following form controls:
-//
-// select
-// textarea
-// input[type="text"]
-// input[type="password"]
-// input[type="datetime"]
-// input[type="datetime-local"]
-// input[type="date"]
-// input[type="month"]
-// input[type="time"]
-// input[type="week"]
-// input[type="number"]
-// input[type="email"]
-// input[type="url"]
-// input[type="search"]
-// input[type="tel"]
-// input[type="color"]
-
-.form-control {
-  display: block;
-  width: 100%;
-  height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)
-  padding: @padding-base-vertical @padding-base-horizontal;
-  font-size: @font-size-base;
-  line-height: @line-height-base;
-  color: @input-color;
-  background-color: @input-bg;
-  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214
-  border: 1px solid @input-border;
-  border-radius: @input-border-radius; // Note: This has no effect on s in CSS.
-  .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));
-  .transition(~"border-color ease-in-out .15s, box-shadow ease-in-out .15s");
-
-  // Customize the `:focus` state to imitate native WebKit styles.
-  .form-control-focus();
-
-  // Placeholder
-  .placeholder();
-
-  // Disabled and read-only inputs
-  //
-  // HTML5 says that controls under a fieldset > legend:first-child won't be
-  // disabled if the fieldset is disabled. Due to implementation difficulty, we
-  // don't honor that edge case; we style them as disabled anyway.
-  &[disabled],
-  &[readonly],
-  fieldset[disabled] & {
-    background-color: @input-bg-disabled;
-    opacity: 1; // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655
-  }
-
-  &[disabled],
-  fieldset[disabled] & {
-    cursor: @cursor-disabled;
-  }
-
-  // Reset height for `textarea`s
-  textarea& {
-    height: auto;
-  }
-}
-
-
-// Search inputs in iOS
-//
-// This overrides the extra rounded corners on search inputs in iOS so that our
-// `.form-control` class can properly style them. Note that this cannot simply
-// be added to `.form-control` as it's not specific enough. For details, see
-// https://github.com/twbs/bootstrap/issues/11586.
-
-input[type="search"] {
-  -webkit-appearance: none;
-}
-
-
-// Special styles for iOS temporal inputs
-//
-// In Mobile Safari, setting `display: block` on temporal inputs causes the
-// text within the input to become vertically misaligned. As a workaround, we
-// set a pixel line-height that matches the given height of the input, but only
-// for Safari. See https://bugs.webkit.org/show_bug.cgi?id=139848
-//
-// Note that as of 8.3, iOS doesn't support `datetime` or `week`.
-
-@media screen and (-webkit-min-device-pixel-ratio: 0) {
-  input[type="date"],
-  input[type="time"],
-  input[type="datetime-local"],
-  input[type="month"] {
-    &.form-control {
-      line-height: @input-height-base;
-    }
-
-    &.input-sm,
-    .input-group-sm & {
-      line-height: @input-height-small;
-    }
-
-    &.input-lg,
-    .input-group-lg & {
-      line-height: @input-height-large;
-    }
-  }
-}
-
-
-// Form groups
-//
-// Designed to help with the organization and spacing of vertical forms. For
-// horizontal forms, use the predefined grid classes.
-
-.form-group {
-  margin-bottom: @form-group-margin-bottom;
-}
-
-
-// Checkboxes and radios
-//
-// Indent the labels to position radios/checkboxes as hanging controls.
-
-.radio,
-.checkbox {
-  position: relative;
-  display: block;
-  margin-top: 10px;
-  margin-bottom: 10px;
-
-  label {
-    min-height: @line-height-computed; // Ensure the input doesn't jump when there is no text
-    padding-left: 20px;
-    margin-bottom: 0;
-    font-weight: normal;
-    cursor: pointer;
-  }
-}
-.radio input[type="radio"],
-.radio-inline input[type="radio"],
-.checkbox input[type="checkbox"],
-.checkbox-inline input[type="checkbox"] {
-  position: absolute;
-  margin-left: -20px;
-  margin-top: 4px \9;
-}
-
-.radio + .radio,
-.checkbox + .checkbox {
-  margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing
-}
-
-// Radios and checkboxes on same line
-.radio-inline,
-.checkbox-inline {
-  position: relative;
-  display: inline-block;
-  padding-left: 20px;
-  margin-bottom: 0;
-  vertical-align: middle;
-  font-weight: normal;
-  cursor: pointer;
-}
-.radio-inline + .radio-inline,
-.checkbox-inline + .checkbox-inline {
-  margin-top: 0;
-  margin-left: 10px; // space out consecutive inline controls
-}
-
-// Apply same disabled cursor tweak as for inputs
-// Some special care is needed because