diff --git a/README.md b/README.md index d854a54..4d9846e 100644 --- a/README.md +++ b/README.md @@ -75,10 +75,16 @@ Some basic configuration options can be found in the file `index.jsx` in the top * `tempUnit` `{String}` - CPU temperature unit, either `C` (Celsius) or `F` (Fahrenheit) +* `position` `{String}` - Screen corner position, either `top-left`, `top-right`, `bottom-left` or `bottom-right` + * `top` `{String}` - Top position in px (e.g. `100px`) * `left` `{String}` - Left position in px (e.g. `100px`) +* `bottom` `{String}` - Bottom position in px (e.g. `100px`) + +* `right` `{String}` - Right position in px (e.g. `100px`) + * `animations` `{Boolean}` - Icon animations flag, either `true` or `false` * `width` `{Number}` - Stat donut chart width in px (e.g. `74`) diff --git a/index.css b/index.css index d8b5232..d19e8f0 100644 --- a/index.css +++ b/index.css @@ -6,9 +6,26 @@ } .stats { + position: absolute; display: flex; } +.stats.top-left { + justify-content: flex-start; +} + +.stats.top-right { + justify-content: flex-end; +} + +.stats.bottom-left { + justify-content: flex-start; +} + +.stats.bottom-right { + justify-content: flex-end; +} + .stat { position: relative; } diff --git a/index.jsx b/index.jsx index 41da194..ea83bd5 100644 --- a/index.jsx +++ b/index.jsx @@ -38,9 +38,12 @@ const config = { ], /* Temperature unit, either 'C' or 'F' */ tempUnit: 'C', - /* Widget position (absolute) */ + /* Widget position */ + position: 'top-left', top: '320px', left: '14px', + bottom: '0px', + right: '0px', /* Stat position */ width: '72', height: '40', @@ -71,8 +74,6 @@ export const className = ` font-family: 'Helvetica Neue'; font-size: 16px; color: ${config.color}; - top: ${config.top}; - left: ${config.left}; `; const isEmpty = (value) => { diff --git a/src/components/Stats.jsx b/src/components/Stats.jsx index cf4b5ce..fd67c84 100644 --- a/src/components/Stats.jsx +++ b/src/components/Stats.jsx @@ -146,6 +146,21 @@ class Stats extends React.Component { return key.replace(/\./, '-'); } + getPosition(config) { + switch(config.position) { + case 'top-left': + return {top: config.top, left: config.left} + case 'bottom-left': + return {bottom: config.bottom, left: config.left} + case 'top-right': + return {top: config.top, right: config.right} + case 'bottom-right': + return {bottom: config.bottom, right: config.right} + default: + return {top: config.top, left: config.left} + } + } + isObject(obj) { return typeof obj === 'object' && obj !== null; } @@ -169,9 +184,12 @@ class Stats extends React.Component { } render() { - let parsedData = IStatsParser.parse(this.props.output), + let config = this.props.config, + clsName = 'stats', + position = this.getPosition(config), + parsedData = IStatsParser.parse(this.props.output), data = Transformer.transform(parsedData), - stats = this.props.config.stats + stats = config.stats .filter(item => { let key = this.isObject(item) ? item.key : item, ref = this.getRef(key); @@ -182,7 +200,7 @@ class Stats extends React.Component { this.resetFanAnimation(data, key); return }); + if (config.position + && config.position.match(/(top|bottom)-(left|right)/)) { + clsName += ' ' + config.position; + } + return ( -
+
{stats}
diff --git a/src/components/__tests__/Constants.res.js b/src/components/__tests__/Constants.res.js index 41147b6..2f11a5d 100644 --- a/src/components/__tests__/Constants.res.js +++ b/src/components/__tests__/Constants.res.js @@ -31,9 +31,12 @@ export let config = { ], /* Temperature unit, either 'C' or 'F' */ tempUnit: 'C', - /* Widget position (absolute) */ - top: '320px', - left: '10px', + /* Widget position */ + position: 'top-left', + top: '0px', + left: '0px', + bottom: '0px', + right: '0px', /* Enable animations */ animations: true, /* Stat position */ diff --git a/src/components/__tests__/Stat.test.js b/src/components/__tests__/Stat.test.js index cde5cc4..fd92610 100644 --- a/src/components/__tests__/Stat.test.js +++ b/src/components/__tests__/Stat.test.js @@ -49,7 +49,7 @@ describe('Stat component', () => { }); test('does not render stat without percentage', () => { - render(< Stat />); + render(); const element = document.querySelector('.stat'); @@ -57,4 +57,23 @@ describe('Stat component', () => { expect(element).not.toBeInTheDocument(); }); + test('does render stat with 0 percentage', () => { + render(); + + const element = document.querySelector('.stat'), + icon = document.querySelector('i.icon'), + text = document.querySelector('.text'); + + expect(element).not.toBeNull(); + expect(element).toBeInTheDocument(); + expect(element).toHaveClass('title'); + + // icon + expect(icon).not.toBeNull(); + expect(icon).toHaveClass('cpu'); + + // text + expect(text).not.toBeNull(); + expect(text).toHaveTextContent('0%'); + }); }); diff --git a/src/components/__tests__/Stats.test.js b/src/components/__tests__/Stats.test.js index 04f1992..c74dd9b 100644 --- a/src/components/__tests__/Stats.test.js +++ b/src/components/__tests__/Stats.test.js @@ -215,36 +215,46 @@ describe('Stats component', () => { expect(stats.length).toEqual(0); }); - test('renders fan with zero value', () => { - let cfg = Object.assign({}, config, { - animations: false, - stats: [ - 'cpu.cpu-temp', - 'fan.fan-0-speed' - ] - }); - - let output ='--- CPU Stats ---\n' + - 'CPU temp: 47.63°C ▁▂▃▅▆▇\n' + - '\n' + - '--- Fan Stats ---\n' + - 'Total fans in system: 1\n' + - 'Fan 0 speed: 0 RPM ▁▂▃▅▆▇\n' + - 'For more stats run `istats extra` and follow the instructions.'; - - render(); + function verifyPositionClass(config, output, expectedClass) { + render(); - const element = document.querySelector('.stats'), - stats = document.querySelectorAll('.stat'); + const element = document.querySelector('.stats'); expect(element).not.toBeNull(); expect(element).toBeInTheDocument(); + expect(element).toHaveClass(expectedClass); + } - expect(stats).not.toBeNull(); - expect(stats).toBeInstanceOf(NodeList); - expect(stats.length).toEqual(2); + test('renders stats position top-left', () => { + verifyPositionClass(config, output, 'top-left'); + }); - expect(stats[0].classList.contains(CLS_CPU_TEMP)).toBe(true); - expect(stats[1].classList.contains(CLS_FAN_0_SPEED)).toBe(true); + test('renders stats position top-right', () => { + Object.assign(config, {position: 'top-right'}); + verifyPositionClass(config, output, 'top-right'); + }); + + test('renders stats position bottom-left', () => { + Object.assign(config, {position: 'bottom-left'}); + verifyPositionClass(config, output, 'bottom-left'); + }); + + test('renders stats position bottom-right', () => { + Object.assign(config, {position: 'bottom-right'}); + verifyPositionClass(config, output, 'bottom-right'); + }); + + test('renders stats position default', () => { + Object.assign(config, {position: undefined}); + + render(); + + const element = document.querySelector('.stats'); + + expect(element).not.toBeNull(); + expect(element).toBeInTheDocument(); + expect(element).toHaveClass('stats'); + expect(element).not.toHaveClass('top-left'); }); + });