Skip to content
This repository has been archived by the owner on Oct 18, 2023. It is now read-only.

Commit

Permalink
#34 - Add support for easy top-left-bottom-right positioning
Browse files Browse the repository at this point in the history
  • Loading branch information
Roland Schaer committed Oct 15, 2019
1 parent 3bf2890 commit a362620
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 36 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`)
Expand Down
17 changes: 17 additions & 0 deletions index.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
7 changes: 4 additions & 3 deletions index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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) => {
Expand Down
31 changes: 27 additions & 4 deletions src/components/Stats.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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);
Expand All @@ -182,7 +200,7 @@ class Stats extends React.Component {
this.resetFanAnimation(data, key);

return <Stat
config={this.props.config}
config={config}
title={this.getClassName(key)}
icon={this.isObject(item) ? (item.icon || this.DEFAULT_ICON ) : this.getIcon(data, key)}
percentage={this.getPercentage(data, key)}
Expand All @@ -191,8 +209,13 @@ class Stats extends React.Component {
/>
});

if (config.position
&& config.position.match(/(top|bottom)-(left|right)/)) {
clsName += ' ' + config.position;
}

return (
<div className="stats">
<div className={clsName} style={position}>
<link rel="stylesheet" type="text/css" href="istats.widget/index.css"></link>
{stats}
</div>
Expand Down
9 changes: 6 additions & 3 deletions src/components/__tests__/Constants.res.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
21 changes: 20 additions & 1 deletion src/components/__tests__/Stat.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,31 @@ describe('Stat component', () => {
});

test('does not render stat without percentage', () => {
render(< Stat />);
render(<Stat />);

const element = document.querySelector('.stat');

expect(element).toBeNull();
expect(element).not.toBeInTheDocument();
});

test('does render stat with 0 percentage', () => {
render(<Stat config={config} title={"title"} icon={"cpu"} percentage={0} key={"key"} value={"0%"} />);

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%');
});
});
60 changes: 35 additions & 25 deletions src/components/__tests__/Stats.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(<Stats config={cfg} output={output} />);
function verifyPositionClass(config, output, expectedClass) {
render(<Stats config={config} output={output} />);

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(<Stats config={config} output={output} />);

const element = document.querySelector('.stats');

expect(element).not.toBeNull();
expect(element).toBeInTheDocument();
expect(element).toHaveClass('stats');
expect(element).not.toHaveClass('top-left');
});

});

0 comments on commit a362620

Please sign in to comment.