Skip to content

Commit

Permalink
Refine settings page (#522)
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanbuck authored Nov 15, 2018
1 parent 1dcd29c commit 26396fb
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 82 deletions.
1 change: 1 addition & 0 deletions assets/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
},
"options_ui": {
"page": "options.html",
"open_in_tab": true,
"chrome_style": true
},
"content_scripts": [
Expand Down
15 changes: 8 additions & 7 deletions assets/options.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script src="options.js"></script>
</body>
<head>
<meta charset="UTF-8" />
<title></title>
</head>
<body>
<div id="app"></div>
<script src="options.js"></script>
</body>
</html>
129 changes: 129 additions & 0 deletions packages/helper-settings/SettingsForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/* eslint-disable react/no-unused-state */

import { h, Component } from 'preact';
import linkState from 'linkstate';

import './style.css';
import { Input, Checkbox } from './components';
import * as storage from './index';

const githubTokenDescription = () => (
<span>
If you want better <strong>Sass, Less or Haskell support</strong> for
private repositories, you&apos;ll need to{' '}
<a href="https://github.com/settings/tokens/new?scopes=repo&description=OctoLinker%20browser%20extension">
create a token
</a>{' '}
with the repo permissions.
</span>
);

export default class Form extends Component {
async componentWillMount() {
this.setState({ ...(await storage.load()) });
}

componentWillUpdate(
nextProps,
{ tokenLoaded, githubToken, errorMessage, ...rest },
) {
storage.save(rest);
}

onBlur(event) {
if (event.target.name === 'githubToken') {
this.validateToken();
}
}

async validateToken() {
const { githubToken } = this.state;

if (!githubToken) {
this.setState({
errorMessage: undefined,
tokenLoaded: false,
});

storage.save({
githubToken: undefined,
});
return;
}

const response = await fetch('https://api.github.com/user', {
headers: { Authorization: `token ${githubToken}` },
}).then(res => res.json());

if (!response.login) {
this.setState({
tokenLoaded: false,
errorMessage: response.message || 'Something went wrong',
});
return;
}

this.setState({
errorMessage: undefined,
tokenLoaded: true,
});

storage.save({
githubToken,
});
}

tokenMessage() {
return <div className="flash flash-success">Token successfuly added</div>;
}

render(props, state) {
const { errorMessage, tokenLoaded } = this.state;

return (
<form
onChange={this.onBlur.bind(this)}
onSubmit={event => event.preventDefault()}
>
{tokenLoaded && this.tokenMessage()}
<Input
type="password"
name="githubToken"
label="Access token"
description={githubTokenDescription()}
value={state.githubToken}
error={errorMessage}
onInput={linkState(this, 'githubToken')}
/>
<Checkbox
name="newWindow"
label="New tab"
description="Open link in a new tab."
checked={state.newWindow}
onClick={linkState(this, 'newWindow')}
/>
<Checkbox
name="newWindowActive"
label="Focus new tab"
description="Focus new tab when opening a link."
checked={state.newWindowActive}
onClick={linkState(this, 'newWindowActive')}
/>
<Checkbox
name="showLinkIndicator"
label="Line indicator"
description="Show an indicator if line contains OctoLinker links."
checked={state.showLinkIndicator}
onClick={linkState(this, 'showLinkIndicator')}
/>
<Checkbox
name="showUpdateNotification"
label="Update notification"
description="Show a notification if a new version is available."
checked={state.showUpdateNotification}
onClick={linkState(this, 'showUpdateNotification')}
/>
</form>
);
}
}
1 change: 1 addition & 0 deletions packages/helper-settings/components/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'primer-core/build/build.css';
import 'primer-forms/build/build.css';
import 'primer-product/build/build.css';

export { default as Input } from './input';
export { default as Checkbox } from './checkbox';
20 changes: 15 additions & 5 deletions packages/helper-settings/components/input.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
/* eslint jsx-a11y/label-has-for: 0 */

import { h } from 'preact';

const validationClassName = error => (error ? ' errored' : '');

export default ({
name,
label,
description,
error,
value,
onInput,
type = 'text',
}) => (
<div className="form-group">
<label htmlFor={name}>
{label}
<dl className={`form-group${validationClassName(error)}`}>
<dt>
<label htmlFor={name} id={name}>
{label}
</label>
</dt>
<dd>
<input
className="form-control"
type={type}
Expand All @@ -19,7 +28,8 @@ export default ({
value={value}
onInput={onInput}
/>
</label>
</dd>
{error && <dd className="error">{error}</dd>}
<p className="note">{description}</p>
</div>
</dl>
);
3 changes: 2 additions & 1 deletion packages/helper-settings/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"linkstate": "^1.1.0",
"preact": "^8.2.5",
"primer-core": "^6.4.0",
"primer-forms": "^1.4.0"
"primer-forms": "^1.4.0",
"primer-product": "^5.7.0"
}
}
89 changes: 20 additions & 69 deletions packages/helper-settings/page.js
Original file line number Diff line number Diff line change
@@ -1,73 +1,24 @@
import { h, render, Component } from 'preact';
import linkState from 'linkstate';
/* eslint-disable react/no-unused-state */

import './style.css';
import { Input, Checkbox } from './components';
import * as storage from './index';
import { h, render } from 'preact';
import SettingsForm from './SettingsForm';

const githubTokenDescription = () => (
<span>
If you want better <strong>Sass, Less or Haskell support</strong> for
private repositories, you&apos;ll need to{' '}
<a href="https://github.com/settings/tokens/new?scopes=repo&description=OctoLinker%20browser%20extension">
create a token
</a>{' '}
with the repo permissions.
</span>
);

class App extends Component {
async componentWillMount() {
const store = { ...(await storage.load()) };
this.setState(store);
}

componentWillUpdate(nextProps, nextState) {
storage.save(nextState);
}

render(props, state) {
return (
<div>
<Input
type="password"
name="githubToken"
label="Access token"
description={githubTokenDescription()}
value={state.githubToken}
onInput={linkState(this, 'githubToken')}
/>
<Checkbox
name="newWindow"
label="New tab"
description="Open link in a new tab."
checked={state.newWindow}
onClick={linkState(this, 'newWindow')}
/>
<Checkbox
name="newWindowActive"
label="Focus new tab"
description="Focus new tab when opening a link."
checked={state.newWindowActive}
onClick={linkState(this, 'newWindowActive')}
/>
<Checkbox
name="showLinkIndicator"
label="Line indicator"
description="Show an indicator if line contains OctoLinker links."
checked={state.showLinkIndicator}
onClick={linkState(this, 'showLinkIndicator')}
/>
<Checkbox
name="showUpdateNotification"
label="Update notification"
description="Show a notification if a new version is available."
checked={state.showUpdateNotification}
onClick={linkState(this, 'showUpdateNotification')}
/>
const App = () => (
<div className="d-flex flex-justify-center p-6">
<div className="Box box-shadow four-fifth column">
<div className="Box-row">
<div className="d-flex">
<img height="54" alt="" src="icon.png" />
<div className="pt-3 px-2">
<h2>OctoLinker settings</h2>
</div>
</div>
</div>
<div className="Box-row">
<SettingsForm />
</div>
);
}
}
</div>
</div>
);

render(<App />, document.body);
render(<App />, document.getElementById('app'));

0 comments on commit 26396fb

Please sign in to comment.