From 451f81d3602fa8466fdf096548f982f6c859f136 Mon Sep 17 00:00:00 2001 From: raymondmouthaan Date: Sat, 16 Mar 2019 13:44:33 +0100 Subject: [PATCH 1/3] New Themes added: grey, brown, amber, teal, navi-blue, cyan and deep-purple --- config.schema.json | 11 +++++++++-- src/hb.ts | 9 ++++++++- ui/package-lock.json | 41 ++++++++++++++++++++++++++++++----------- ui/src/scss/themes.scss | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 14 deletions(-) diff --git a/config.schema.json b/config.schema.json index 41254a9b9..e612d8616 100644 --- a/config.schema.json +++ b/config.schema.json @@ -41,7 +41,14 @@ { "title": "Blue", "enum": ["blue"] }, { "title": "Blue-grey", "enum": ["blue-grey"] }, { "title": "Green", "enum": ["green"] }, - { "title": "Orange", "enum": ["orange"] } + { "title": "Orange", "enum": ["orange"] }, + { "title": "Grey", "enum": ["grey"] }, + { "title": "Brown", "enum": ["brown"] }, + { "title": "Amber", "enum": ["amber"] }, + { "title": "Teal", "enum": ["teal"] }, + { "title": "Navi-blue", "enum": ["navi-blue"] }, + { "title": "Cyan", "enum": ["cyan"] }, + { "title": "Deep-purple", "enum": ["deep-purple"] } ], "required": true }, @@ -241,4 +248,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/hb.ts b/src/hb.ts index dfcd27d87..0170ef548 100644 --- a/src/hb.ts +++ b/src/hb.ts @@ -57,7 +57,14 @@ class HomebridgeUI { 'blue', 'blue-grey', 'green', - 'orange' + 'orange', + 'grey', + 'brown', + 'amber', + 'teal', + 'navi-blue', + 'cyan', + 'deep-purple' ]; } diff --git a/ui/package-lock.json b/ui/package-lock.json index b4c1e66d1..6a1a5bd96 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -3521,7 +3521,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -3542,12 +3543,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3562,17 +3565,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -3689,7 +3695,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -3701,6 +3708,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3715,6 +3723,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3722,12 +3731,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3746,6 +3757,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -3826,7 +3838,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -3838,6 +3851,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3923,7 +3937,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -3959,6 +3974,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3978,6 +3994,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4021,12 +4038,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, diff --git a/ui/src/scss/themes.scss b/ui/src/scss/themes.scss index a0b3d77c3..17ff7eb52 100644 --- a/ui/src/scss/themes.scss +++ b/ui/src/scss/themes.scss @@ -30,6 +30,35 @@ } } +.config-ui-x-navi-blue { + .bg-primary { + background-color: #000070 !important; + } + + .primary-text { + color: #000099; + } + + .btn-primary { + background-color: #000099 !important; + } + + .badge-primary { + background-color: #000070 !important; + } + + a { + &.card-link { + color: #000000; + + &:hover { + color: #000070; + } + } + } +} + + @include make-theme('red', #F44336, #D32F2F); @include make-theme('pink', #e91e63, #c2185b); @include make-theme('purple', #9c27b0, #7b1fa2); @@ -38,3 +67,9 @@ @include make-theme('blue-grey', #607d8b, #455a64); @include make-theme('green', #4caf50, #388e3c); @include make-theme('orange', #ff9800, #ef6c00); +@include make-theme('grey', #9e9e9e, #616161); +@include make-theme('brown', #795548, #4e342e); +@include make-theme('amber', #ffc107, #ff8f00); +@include make-theme('teal', #009688, #00695c); +@include make-theme('cyan', #00bcd4, #00838f); +@include make-theme('deep-purple', #673ab7, #4527a0); From eba7a276038ed57c19d4ef9bb568bddf61a80e8e Mon Sep 17 00:00:00 2001 From: raymondmouthaan Date: Sat, 16 Mar 2019 13:50:03 +0100 Subject: [PATCH 2/3] New Themes added: grey, brown, amber, teal, navi-blue, cyan and deep-purple --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2548b054e..8e28b3b0b 100755 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Add this to your homebridge `config.json` file * `sudo` - [See below for details](#sudo-mode). * `restart` - The command to run when a restart request is sent from the browser. If not populated it will just terminate the Homebridge process and let your process manager (like systemd) restart it. * `temp` - The path to the file that can display your current CPU temperature in WEB UI. eg. `/sys/class/thermal/thermal_zone0/temp` -* `theme` - The colour scheme to use. Possible values: `red`, `pink`, `purple`, `indigo`, `blue`, `blue-grey`, `green`, `orange`. Defaults to `red`. +* `theme` - The colour scheme to use. Possible values: `red`, `pink`, `purple`, `indigo`, `blue`, `blue-grey`, `green`, `orange`, `grey`, `brown`, `amber`, `teal`, `navi-blue`, `cyan` and `deep-purple`. Defaults to `red`. * `ssl` - [See below for details](#enabling-ssl) ## Accessory Control From 8b045272568cf9f569719bc9caa230b36e9fe965 Mon Sep 17 00:00:00 2001 From: raymondmouthaan Date: Mon, 18 Mar 2019 20:49:01 +0100 Subject: [PATCH 3/3] [add] New theme: dark-mode --- README.md | 14 +- config.schema.json | 3 +- src/hb.ts | 613 ++++++++++++++++++++-------------------- ui/src/scss/themes.scss | 85 ++++++ 4 files changed, 408 insertions(+), 307 deletions(-) diff --git a/README.md b/README.md index 8e28b3b0b..73d357a59 100755 --- a/README.md +++ b/README.md @@ -43,7 +43,19 @@ Add this to your homebridge `config.json` file * `sudo` - [See below for details](#sudo-mode). * `restart` - The command to run when a restart request is sent from the browser. If not populated it will just terminate the Homebridge process and let your process manager (like systemd) restart it. * `temp` - The path to the file that can display your current CPU temperature in WEB UI. eg. `/sys/class/thermal/thermal_zone0/temp` -* `theme` - The colour scheme to use. Possible values: `red`, `pink`, `purple`, `indigo`, `blue`, `blue-grey`, `green`, `orange`, `grey`, `brown`, `amber`, `teal`, `navi-blue`, `cyan` and `deep-purple`. Defaults to `red`. +* `theme` - The colour scheme to use. Possible values: + + | | | + |---------------|-------------------| + | `amber` | `grey` | + | `blue` | `indigo` | + | `blue-grey` | `navi-blue` | + | `brown` | `orange` | + | `cyan` | `pink` | + | `dark-mode` | `purple` | + | `deep-purple` | `red` (default) | + | `green` | `teal` | + * `ssl` - [See below for details](#enabling-ssl) ## Accessory Control diff --git a/config.schema.json b/config.schema.json index e612d8616..975d65228 100644 --- a/config.schema.json +++ b/config.schema.json @@ -48,7 +48,8 @@ { "title": "Teal", "enum": ["teal"] }, { "title": "Navi-blue", "enum": ["navi-blue"] }, { "title": "Cyan", "enum": ["cyan"] }, - { "title": "Deep-purple", "enum": ["deep-purple"] } + { "title": "Deep-purple", "enum": ["deep-purple"] }, + { "title": "Dark-mode", "enum": ["dark-mode"] } ], "required": true }, diff --git a/src/hb.ts b/src/hb.ts index 0170ef548..06a24e1c4 100644 --- a/src/hb.ts +++ b/src/hb.ts @@ -5,359 +5,362 @@ import * as color from 'bash-color'; import * as commander from 'commander'; import * as semver from 'semver'; -import { WSS } from './wss'; +import {WSS} from './wss'; class HomebridgeUI { - public ui: any; - public pluginName: string; - public homebridgeVersion: string; - public homebridgeInsecure: boolean; - public homebridgeNpmPkg: string; - public homebridgeFork: string; - public homebridgeConfig: HomebridgeConfigType; - public runningInDocker: boolean; - public runningInLinux: boolean; - public linuxServerOpts: { restart?: string; shutdown?: string; }; - public enableTerminalAccess: boolean; - public ableToConfigureSelf: boolean; - public configPath: string; - public authPath: string; - public storagePath: string; - public pluginPath: string; - public port: number | string; - public proxyHost: string; - public logOpts: { - method: 'file' | 'systemd' | 'custom'; - path?: string; - service?: string; - command?: string; - tail?: string; /** @deprecated since 5.6.0 */ - systemd?: string; /** @deprecated since 5.6.0 */ - } | string; - public restartCmd; - public useSudo: boolean; - public authMethod: string | boolean; - public formAuth: boolean; - public theme: string; - public loginWallpaper: string; - public availableThemes: string[]; - public temperatureFile: string; - public temperatureUnits: 'c' | 'f'; - public accessoryLayoutPath: string; - public wss: WSS; - - constructor() { - this.ui = fs.readJSONSync(path.resolve(__dirname, '../package.json')); - - this.availableThemes = [ - 'red', - 'pink', - 'purple', - 'indigo', - 'blue', - 'blue-grey', - 'green', - 'orange', - 'grey', - 'brown', - 'amber', - 'teal', - 'navi-blue', - 'cyan', - 'deep-purple' - ]; - } - - public init(setup) { - this.configPath = setup.configPath; - this.authPath = path.join(setup.storagePath, 'auth.json'); - this.storagePath = setup.storagePath; - this.accessoryLayoutPath = path.resolve(setup.storagePath, 'accessories', 'uiAccessoriesLayout.json'); - this.homebridgeVersion = setup.homebridgeVersion; - - this.parseConfig(setup.config); - this.parseCommandLineArgs(); - } - - private parseConfig(config) { - this.pluginName = config.name || this.ui.name; - this.port = config.port || 8080; - this.proxyHost = config.proxyHost; - this.logOpts = config.log; - this.restartCmd = config.restart; - this.useSudo = config.sudo; - this.authMethod = config.auth; - this.homebridgeFork = config.fork; - this.homebridgeNpmPkg = config.homebridgeNpmPkg || 'homebridge'; - this.homebridgeInsecure = config.homebridgeInsecure; - this.pluginPath = config.pluginPath; - this.runningInDocker = Boolean(process.env.HOMEBRIDGE_CONFIG_UI === '1'); - this.runningInLinux = (!this.runningInDocker && os.platform() === 'linux'); - this.linuxServerOpts = config.linux || {}; - this.enableTerminalAccess = this.runningInDocker || Boolean(process.env.HOMEBRIDGE_CONFIG_UI_TERMINAL === '1'); - this.ableToConfigureSelf = (!this.runningInDocker || semver.satisfies(process.env.CONFIG_UI_VERSION, '>=3.5.5')); - this.loginWallpaper = config.loginWallpaper; - this.temperatureUnits = config.tempUnits || 'c'; - - if (config.auth === 'none' || config.auth === false) { - this.formAuth = false; - } else if (config.auth === 'basic') { - this.formAuth = false; - } else { - this.formAuth = true; + public ui: any; + public pluginName: string; + public homebridgeVersion: string; + public homebridgeInsecure: boolean; + public homebridgeNpmPkg: string; + public homebridgeFork: string; + public homebridgeConfig: HomebridgeConfigType; + public runningInDocker: boolean; + public runningInLinux: boolean; + public linuxServerOpts: { restart?: string; shutdown?: string; }; + public enableTerminalAccess: boolean; + public ableToConfigureSelf: boolean; + public configPath: string; + public authPath: string; + public storagePath: string; + public pluginPath: string; + public port: number | string; + public proxyHost: string; + public logOpts: { + method: 'file' | 'systemd' | 'custom'; + path?: string; + service?: string; + command?: string; + tail?: string; /** @deprecated since 5.6.0 */ + systemd?: string; /** @deprecated since 5.6.0 */ + } | string; + public restartCmd; + public useSudo: boolean; + public authMethod: string | boolean; + public formAuth: boolean; + public theme: string; + public loginWallpaper: string; + public availableThemes: string[]; + public temperatureFile: string; + public temperatureUnits: 'c' | 'f'; + public accessoryLayoutPath: string; + public wss: WSS; + + constructor() { + this.ui = fs.readJSONSync(path.resolve(__dirname, '../package.json')); + + this.availableThemes = [ + 'red', + 'pink', + 'purple', + 'indigo', + 'blue', + 'blue-grey', + 'green', + 'orange', + 'grey', + 'brown', + 'amber', + 'teal', + 'navi-blue', + 'cyan', + 'deep-purple', + 'dark-mode' + ]; } - // check theme is valid - if (config.theme && this.availableThemes.find(x => x === config.theme)) { - this.theme = config.theme; - } else if (config.theme) { - // delay the output of the warning message so it does not get lost under homebridge setup details - setTimeout(() => { - this.warn(`Invalid theme in config.json. Possible options are: ${this.availableThemes.join(', ')}`); - }, 2000); - this.theme = 'red'; - } else { - this.theme = 'red'; - } + public init(setup) { + this.configPath = setup.configPath; + this.authPath = path.join(setup.storagePath, 'auth.json'); + this.storagePath = setup.storagePath; + this.accessoryLayoutPath = path.resolve(setup.storagePath, 'accessories', 'uiAccessoriesLayout.json'); + this.homebridgeVersion = setup.homebridgeVersion; - // check the path to the temp file actually exists - if (config.temp && fs.existsSync(config.temp)) { - this.temperatureFile = config.temp; - } else if (config.temp) { - // delay the output of the warning message so it does not get lost under homebridge setup details - setTimeout(() => { - this.warn(`WARNING: Configured path to temp file does not exist: ${config.temp}`); - this.warn(`WARNING: CPU Temp will not be displayed`); - }, 2000); + this.parseConfig(setup.config); + this.parseCommandLineArgs(); } - } - - private parseCommandLineArgs() { - // parse plugin path argument from homebridge - commander - .allowUnknownOption() - .option('-P, --plugin-path [path]', '', (p) => this.pluginPath = p) - .option('-I, --insecure', '', () => this.homebridgeInsecure = true) - .parse(process.argv); - } - - public async refreshHomebridgeConfig() { - try { - this.homebridgeConfig = await import(this.configPath); - } catch (e) { - this.homebridgeConfig = { - bridge: { - name: 'Homebridge', - port: 51826 + + private parseConfig(config) { + this.pluginName = config.name || this.ui.name; + this.port = config.port || 8080; + this.proxyHost = config.proxyHost; + this.logOpts = config.log; + this.restartCmd = config.restart; + this.useSudo = config.sudo; + this.authMethod = config.auth; + this.homebridgeFork = config.fork; + this.homebridgeNpmPkg = config.homebridgeNpmPkg || 'homebridge'; + this.homebridgeInsecure = config.homebridgeInsecure; + this.pluginPath = config.pluginPath; + this.runningInDocker = Boolean(process.env.HOMEBRIDGE_CONFIG_UI === '1'); + this.runningInLinux = (!this.runningInDocker && os.platform() === 'linux'); + this.linuxServerOpts = config.linux || {}; + this.enableTerminalAccess = this.runningInDocker || Boolean(process.env.HOMEBRIDGE_CONFIG_UI_TERMINAL === '1'); + this.ableToConfigureSelf = (!this.runningInDocker || semver.satisfies(process.env.CONFIG_UI_VERSION, '>=3.5.5')); + this.loginWallpaper = config.loginWallpaper; + this.temperatureUnits = config.tempUnits || 'c'; + + if (config.auth === 'none' || config.auth === false) { + this.formAuth = false; + } else if (config.auth === 'basic') { + this.formAuth = false; + } else { + this.formAuth = true; + } + + // check theme is valid + if (config.theme && this.availableThemes.find(x => x === config.theme)) { + this.theme = config.theme; + } else if (config.theme) { + // delay the output of the warning message so it does not get lost under homebridge setup details + setTimeout(() => { + this.warn(`Invalid theme in config.json. Possible options are: ${this.availableThemes.join(', ')}`); + }, 2000); + this.theme = 'red'; + } else { + this.theme = 'red'; + } + + // check the path to the temp file actually exists + if (config.temp && fs.existsSync(config.temp)) { + this.temperatureFile = config.temp; + } else if (config.temp) { + // delay the output of the warning message so it does not get lost under homebridge setup details + setTimeout(() => { + this.warn(`WARNING: Configured path to temp file does not exist: ${config.temp}`); + this.warn(`WARNING: CPU Temp will not be displayed`); + }, 2000); } - }; - this.error(`Failed to load ${this.configPath} - ${e.message}`); } - if (!this.homebridgeConfig.bridge.port) { - this.error('Homebridge config.json error: bridge.port missing.'); + private parseCommandLineArgs() { + // parse plugin path argument from homebridge + commander + .allowUnknownOption() + .option('-P, --plugin-path [path]', '', (p) => this.pluginPath = p) + .option('-I, --insecure', '', () => this.homebridgeInsecure = true) + .parse(process.argv); } - } - public async updateConfig(config) { - const now = new Date(); + public async refreshHomebridgeConfig() { + try { + this.homebridgeConfig = await import(this.configPath); + } catch (e) { + this.homebridgeConfig = { + bridge: { + name: 'Homebridge', + port: 51826 + } + }; + this.error(`Failed to load ${this.configPath} - ${e.message}`); + } - if (!config) { - config = {}; + if (!this.homebridgeConfig.bridge.port) { + this.error('Homebridge config.json error: bridge.port missing.'); + } } - if (!config.bridge) { - config.bridge = {}; - } + public async updateConfig(config) { + const now = new Date(); - if (!config.bridge.name) { - config.bridge.name = 'Homebridge'; - } + if (!config) { + config = {}; + } - if (!config.bridge.port) { - config.bridge.port = 51826; - } + if (!config.bridge) { + config.bridge = {}; + } - if (!config.bridge.username) { - config.bridge.username = this.generateUsername(); - } + if (!config.bridge.name) { + config.bridge.name = 'Homebridge'; + } - if (!config.bridge.pin) { - config.bridge.pin = this.generatePin(); + if (!config.bridge.port) { + config.bridge.port = 51826; + } + + if (!config.bridge.username) { + config.bridge.username = this.generateUsername(); + } + + if (!config.bridge.pin) { + config.bridge.pin = this.generatePin(); + } + + if (!config.accessories) { + config.accessories = []; + } + + if (!config.platforms) { + config.platforms = []; + } + + // create backup of existing config + await fs.rename(this.configPath, `${this.configPath}.${now.getTime()}`); + + // save config file + fs.writeJsonSync(this.configPath, config, {spaces: 4}); + + this.log('Changes to config.json saved.'); + + return config; } - if (!config.accessories) { - config.accessories = []; + public async listConfigBackups() { + const dirContents = await fs.readdir(this.storagePath); + + const backups = dirContents + .filter(x => x.indexOf('config.json.') === 0) + .sort() + .reverse() + .map(x => { + const ext = x.split('.'); + if (ext.length === 3 && !isNaN(ext[2] as any)) { + return { + id: ext[2], + timestamp: new Date(parseInt(ext[2], 10)), + file: x + }; + } else { + return null; + } + }) + .filter((x => x && !isNaN(x.timestamp.getTime()))); + + return backups; } - if (!config.platforms) { - config.platforms = []; + public async getConfigBackup(backupId: string) { + // check backup file exists + if (!fs.existsSync(this.configPath + '.' + parseInt(backupId, 10))) { + throw new Error(`Backup ${backupId} Not Found`); + } + + // read source backup + return await fs.readFile(this.configPath + '.' + parseInt(backupId, 10)); } - // create backup of existing config - await fs.rename(this.configPath, `${this.configPath}.${now.getTime()}`); + public async deleteAllConfigBackups() { + const backups = await this.listConfigBackups(); - // save config file - fs.writeJsonSync(this.configPath, config, { spaces: 4 }); + // delete each backup file + await backups.forEach(async (backupFile) => { + await fs.unlink(path.resolve(this.storagePath, backupFile.file)); + }); + } - this.log('Changes to config.json saved.'); + public async resetHomebridgeAccessory() { + // load config file + const config: HomebridgeConfigType = await fs.readJson(this.configPath); - return config; - } + // generate new random username and pin + if (config.bridge) { + config.bridge.pin = this.generatePin(); + config.bridge.username = this.generateUsername(); - public async listConfigBackups() { - const dirContents = await fs.readdir(this.storagePath); + this.log(`Homebridge Reset: New Username: ${config.bridge.username}`); + this.log(`Homebridge Reset: New Pin: ${config.bridge.pin}`); - const backups = dirContents - .filter(x => x.indexOf('config.json.') === 0) - .sort() - .reverse() - .map(x => { - const ext = x.split('.'); - if (ext.length === 3 && !isNaN(ext[2] as any)) { - return { - id: ext[2], - timestamp: new Date(parseInt(ext[2], 10)), - file: x - }; + // save config file + await this.updateConfig(config); } else { - return null; + this.error('Homebridge Reset: Could not reset homebridge username or pin. Config format invalid.'); } - }) - .filter((x => x && !isNaN(x.timestamp.getTime()))); - return backups; - } + // remove accessories and persist directories + await fs.remove(path.resolve(this.storagePath, 'accessories')); + await fs.remove(path.resolve(this.storagePath, 'persist')); - public async getConfigBackup(backupId: string) { - // check backup file exists - if (!fs.existsSync(this.configPath + '.' + parseInt(backupId, 10))) { - throw new Error(`Backup ${backupId} Not Found`); + this.log(`Homebridge Reset: "persist" directory removed.`); + this.log(`Homebridge Reset: "accessories" directory removed.`); } - // read source backup - return await fs.readFile(this.configPath + '.' + parseInt(backupId, 10)); - } - - public async deleteAllConfigBackups() { - const backups = await this.listConfigBackups(); + private generatePin() { + let code: string | Array = Math.floor(10000000 + Math.random() * 90000000) + ''; + code = code.split(''); + code.splice(3, 0, '-'); + code.splice(6, 0, '-'); + code = code.join(''); + return code; + } - // delete each backup file - await backups.forEach(async(backupFile) => { - await fs.unlink(path.resolve(this.storagePath, backupFile.file)); - }); - } + private generateUsername() { + const hexDigits = '0123456789ABCDEF'; + let username = '0E:'; + for (let i = 0; i < 5; i++) { + username += hexDigits.charAt(Math.round(Math.random() * 15)); + username += hexDigits.charAt(Math.round(Math.random() * 15)); + if (i !== 4) { + username += ':'; + } + } + return username; + } - public async resetHomebridgeAccessory() { - // load config file - const config: HomebridgeConfigType = await fs.readJson(this.configPath); + public async getAccessoryLayout(user) { + if (fs.existsSync(this.accessoryLayoutPath)) { + const accessoryLayout = await fs.readJson(this.accessoryLayoutPath); + if (user in accessoryLayout) { + return accessoryLayout[user]; + } + } + return [ + { + name: 'Default Room', + services: [] + } + ]; + } - // generate new random username and pin - if (config.bridge) { - config.bridge.pin = this.generatePin(); - config.bridge.username = this.generateUsername(); + public async updateAccessoryLayout(user, layout) { + let accessoryLayout; - this.log(`Homebridge Reset: New Username: ${config.bridge.username}`); - this.log(`Homebridge Reset: New Pin: ${config.bridge.pin}`); + try { + accessoryLayout = await fs.readJson(this.accessoryLayoutPath); + } catch (e) { + accessoryLayout = {}; + } - // save config file - await this.updateConfig(config); - } else { - this.error('Homebridge Reset: Could not reset homebridge username or pin. Config format invalid.'); + accessoryLayout[user] = layout; + fs.writeJsonSync(this.accessoryLayoutPath, accessoryLayout); + this.log(`[${user}] Accessory layout changes saved.`); + return layout; } - // remove accessories and persist directories - await fs.remove(path.resolve(this.storagePath, 'accessories')); - await fs.remove(path.resolve(this.storagePath, 'persist')); - - this.log(`Homebridge Reset: "persist" directory removed.`); - this.log(`Homebridge Reset: "accessories" directory removed.`); - } - - private generatePin() { - let code: string | Array = Math.floor(10000000 + Math.random() * 90000000) + ''; - code = code.split(''); - code.splice(3, 0, '-'); - code.splice(6, 0, '-'); - code = code.join(''); - return code; - } - - private generateUsername() { - const hexDigits = '0123456789ABCDEF'; - let username = '0E:'; - for (let i = 0; i < 5; i++) { - username += hexDigits.charAt(Math.round(Math.random() * 15)); - username += hexDigits.charAt(Math.round(Math.random() * 15)); - if (i !== 4) { username += ':'; } - } - return username; - } - - public async getAccessoryLayout(user) { - if (fs.existsSync(this.accessoryLayoutPath)) { - const accessoryLayout = await fs.readJson(this.accessoryLayoutPath); - if (user in accessoryLayout) { - return accessoryLayout[user]; - } + public log(...params) { + console.log( + color.white(`[${new Date().toLocaleString()}]`), color.cyan(`[${this.pluginName}]`), ...params + ); } - return [ - { - name: 'Default Room', - services: [] - } - ]; - } - - public async updateAccessoryLayout(user, layout) { - let accessoryLayout; - - try { - accessoryLayout = await fs.readJson(this.accessoryLayoutPath); - } catch (e) { - accessoryLayout = {}; + + public warn(...params) { + console.warn( + color.white(`[${new Date().toLocaleString()}]`), color.cyan(`[${this.pluginName}]`), color.yellow(params.join(' ')) + ); } - accessoryLayout[user] = layout; - fs.writeJsonSync(this.accessoryLayoutPath, accessoryLayout); - this.log(`[${user}] Accessory layout changes saved.`); - return layout; - } - - public log(...params) { - console.log( - color.white(`[${new Date().toLocaleString()}]`), color.cyan(`[${this.pluginName}]`), ...params - ); - } - - public warn(...params) { - console.warn( - color.white(`[${new Date().toLocaleString()}]`), color.cyan(`[${this.pluginName}]`), color.yellow(params.join(' ')) - ); - } - - public error(...params) { - console.error( - color.white(`[${new Date().toLocaleString()}]`), color.cyan(`[${this.pluginName}]`), color.red(params.join(' ')) - ); - } + public error(...params) { + console.error( + color.white(`[${new Date().toLocaleString()}]`), color.cyan(`[${this.pluginName}]`), color.red(params.join(' ')) + ); + } } export interface HomebridgeConfigType { - bridge: { - name: string; - username?: string; - port: number; - pin?: string; - }; - platforms?: { - name: string; - platform: string; - }[]; - accessories?: { - accessory: string; - name: string; - }[]; + bridge: { + name: string; + username?: string; + port: number; + pin?: string; + }; + platforms?: { + name: string; + platform: string; + }[]; + accessories?: { + accessory: string; + name: string; + }[]; } export const hb = new HomebridgeUI(); diff --git a/ui/src/scss/themes.scss b/ui/src/scss/themes.scss index 17ff7eb52..bccc44b2c 100644 --- a/ui/src/scss/themes.scss +++ b/ui/src/scss/themes.scss @@ -58,6 +58,91 @@ } } +.config-ui-x-dark-mode { + + background-color: #2b2b2b !important; + + + .bg-primary { + background-color: #2b2b2b !important; + } + + .primary-text { + color: #586c91; + } + + .btn-primary { + background-color: #586c91 !important; + } + + .badge-primary { + background-color: #2b2b2b !important; + } + + .card { + color: #586c91; + background-color: #333333 !important; + } + + .ace_content { + background-color: #3c3c3c !important; + } + + .ace_text-layer { + color: #9876aa !important; + } + + .ace_gutter { + background-color: #3c3c3c !important; + } + + .ace_gutter-cell { + color: #9e9e9e !important; + } + + .ace_string { + color: #608759 !important; + } + + .ace_numeric { + color: #6897bb !important; + } + + .ace_boolean { + color: #cc7832 !important; + font-weight: bold; + } + + a { + &.card-link { + color: #9e9e9e; + + &:hover { + color: #95a6d9; + } + } + } + + .modal-header { + background-color: #3c3c3c; + } + + .modal-title { + color: #586c91; + } + + .modal-body { + background-color: #3c3c3c; + } + + .modal-footer { + background-color: #3c3c3c; + } + + .w-100 { + color: #9e9e9e; + } +} @include make-theme('red', #F44336, #D32F2F); @include make-theme('pink', #e91e63, #c2185b);