Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
mcwhittemore committed Apr 21, 2017
0 parents commit ca18721
Show file tree
Hide file tree
Showing 12 changed files with 24,168 additions and 0 deletions.
21,571 changes: 21,571 additions & 0 deletions build/app.js

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"scripts": {
"build": "browserify -t [ babelify --presets [ react ] ] src/index.js -o build/app.js",
"watch": "watchify -t [ babelify --presets [ react ] ] src/index.js -o build/app.js"
},
"dependencies": {
"babel-preset-react": "^6.24.1",
"babelify": "^7.3.0",
"browserify": "^14.3.0",
"husky": "^0.13.3",
"prettier": "^1.1.0",
"react": "^15.5.4",
"react-dom": "^15.5.4",
"watchify": "^3.9.0",
"xhr": "^2.4.0"
},
"lint-staged": {
"*.js": [
"prettier --single-quote --write",
"git add"
]
}
}
16 changes: 16 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Image Corpus React App

A simple js file that can be included into a page to make that page into an image corpus app

## Website

- [x] add photos
- [x] list photos
- [x] tag photos
- [ ] edit tags
- [ ] delete tags
- [ ] delete photos
- [ ] filter photos
- [ ] add `x,y` location labels
- [ ] delete `x,y` location labels

83 changes: 83 additions & 0 deletions src/api/images.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
var xhr = require('xhr');

var api = module.exports = {};

var repo = null;
var file = null;
var token = null;

api.config = function(r, f, t) {
repo = r || repo;
file = f || file;
token = t || token;
};

api.add = function(img, cb) {
if (repo === null) setTimeout(() => cb(new Error('Not configured')));
api.load(function(err, about) {
if (err) return cb(err);
var images;
try {
images = JSON.parse(atob(about.content));
}
catch(err) {
return cb(err);
}
var m = images.filter(i => i.src === img.src);
if (m.length) return cb(new Error('Image is already in the database'));
images = [img].concat(images);
xhr(
{
uri: `https://api.github.com/repos/${repo}/contents/${file}?access_token=${token}`,
method: 'PUT',
json: { message: `adding ${img.src} to the database`,
content: btoa(JSON.stringify(images, null, 2)),
sha: about.sha
}
},
function(err, resp, body) {
if (err) return cb(err);
if (typeof body === 'string') body = JSON.parse(body);
if (resp.statusCode >= 400) return cb(new Error(body.message));
cb(null, images);
}
)

});
};

api.loadRaw = function(cb) {
if (repo === null) setTimeout(() => cb(new Error('Not configured')));
var ts = token ? `?access_token=${token}` : '';
xhr(
{
uri: `https://api.github.com/repos/${repo}/contents/${file}${ts}`,
headers: {
accept: 'application/vnd.github.VERSION.raw'
}
},
function(err, resp, body) {
if (err) return cb(err);
cb(null, JSON.parse(body));
}
);
}

api.load = function(cb) {
if (repo === null) setTimeout(() => cb(new Error('Not configured')));
var ts = token ? `?access_token=${token}` : '';
xhr(
{
uri: `https://api.github.com/repos/${repo}/contents/${file}${ts}`,
headers: {
accept: 'application/json'
}
},
function(err, resp, body) {
if (err) return cb(err);
cb(null, JSON.parse(body));
}
);
}


43 changes: 43 additions & 0 deletions src/api/load.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
var xhr = require('xhr');

var apiUser = require('./user');
var apiImages = require('./images');

module.exports = function(opts, cb) {
apiUser.load(function(err, user) {
if (err) return cb(err);
opts.user = user || null;
if (opts.user !== null) apiImages.config(null, null, opts.user.token);
loadData(opts, function(err, data) {
if (err) return cb(err);
loadImages(data, cb);
});
});
};

function loadData(opts, cb) {
var ts = opts.user ? `?access_token=${opts.user.token}` : '';
xhr(
{
uri: `https://api.github.com/repos/${opts.repo}/contents/${opts.config}${ts}`,
headers: {
accept: 'application/vnd.github.VERSION.raw'
}
},
function(err, resp, body) {
if (err) return cb(err);
var config = JSON.parse(body);
opts.configData = config;
cb(null, opts);
}
);
}

function loadImages(opts, cb) {
apiImages.config(opts.repo, opts.configData.images)
apiImages.loadRaw(function(err, images) {
if (err) cb(err);
opts.images = images;
cb(null, opts);
});
}
65 changes: 65 additions & 0 deletions src/api/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
var xhr = require('xhr');

var api = module.exports = {};

api.save = function(data, cb) {
var error = null;
try {
localStorage.setItem('user-token', data.token);
} catch (err) {
error = err;
}
setTimeout(function() {
cb(error);
});
};

api.load = function(cb) {
var token = localStorage.getItem('user-token');
if (token === null) {
return setTimeout(() => cb(null, null));
}

api.getGithubUser(token, function(err, data) {
if (err) return cb(err);
cb(null, data);
});
};

api.getGithubUser = function(token, cb) {
xhr(
{
url: `https://api.github.com/user?access_token=${token}`
},
function(err, resp, body) {
if (err) return cb(err);
body = JSON.parse(body);
if (resp.statusCode >= 400) return cb(new Error(body.message));
cb(null, {
avatar: body.avatar_url,
login: body.login,
token: token
});
}
);
};

/*
function loadData(opts, cb) {
xhr(
{
uri: `https://api.github.com/repos/${opts.repo}/contents/${opts.config}`,
headers: {
accept: 'application/vnd.github.VERSION.raw'
}
},
function(err, resp, body) {
if (err) return cb(err);
var config = JSON.parse(body);
opts.configData = config;
cb(null, opts);
}
);
}
*/

80 changes: 80 additions & 0 deletions src/image-corpus-app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
var React = require('react');

var Message = require('./message');
var User = require('./user');
var Images = require('./images');

var loadData = require('./api/load');
var apiImages = require('./api/images');
var apiUser = require('./api/user');

class ImageCorpusApp extends React.Component {
constructor(props) {
super(props);
this.state = {
loaded: false,
images: [],
config: null,
user: null,
error: null
};
}
dataLoaded(err, opts) {
if (err) return this.setState({ loaded: true, error: err.message });
this.setState({
loaded: true,
config: opts.configData,
images: opts.images,
user: opts.user,
clearError: null
});
}
componentDidMount() {
loadData(
{ repo: this.props.repo, config: this.props.config },
this.dataLoaded.bind(this)
);

var ce = setInterval(() => {
if (this.state.error !== null) {
this.setState({error: null});
}
}, 1000);

this.setState({clearError:ce});
}
componentWillUnmount() {
if (this.state.clearError) clearInterval(this.state.clearError);
}
setUser(data) {
apiUser.save(data, (error) => {
if (error) return this.setState({error});
this.setState({ user: data });
});
}
addImage(img) {
apiImages.add(img, (error, imgs) => {
if (error) return this.setState({error});
this.setState({ images: imgs });
});
}
render() {
if (this.state.loaded === false) return <Message msg='Loading...' />;
if (this.state.error !== null) return <Message msg={this.state.error.message} />;
var config = this.state.config;
return (
<div className='m0'>
<div className='grid prose bg-teal-light'>
<div className='col--10'>
<h1 className='m6'>{config.name}</h1>
<p className='px12'>{config.description}</p>
</div>
<User user={this.state.user} update={this.setUser.bind(this)} add={this.addImage.bind(this)} />
</div>
<Images images={this.state.images} />
</div>
);
}
}

module.exports = ImageCorpusApp;
18 changes: 18 additions & 0 deletions src/images.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
var React = require('react');

class Image extends React.Component {
render() {
var img = this.props.data;
return <div className='m6 bg-gray-light p6 w240'>
<img src={img.src} width='100%' />
<div>
{img.tags.map((t, i) => <div key={`${t}-${i}`} className='round-bold bg-green-light inline-block p3 m3'>{t}</div>)}
</div>
</div>;
}
}

module.exports = (props) => <div className='grid mx3'>
{props.images.map(img => <Image key={img.src} data={img} />)}
</div>;

14 changes: 14 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
var ReactDOM = require('react-dom');
var React = require('react');

var ImageCorpusApp = require('./image-corpus-app');

var de = document.getElementById('app');

var repo = de.getAttribute('data-repo');
var config = de.getAttribute('data-config');

ReactDOM.render(
<ImageCorpusApp repo={repo} config={config} />,
de
);
16 changes: 16 additions & 0 deletions src/message.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
var React = require('react');

module.exports = (props) => {
return (
<div className="grid grid--gut12 absolute top left bottom right">
<div className="col col--4" />
<div
className="col col--4 align-center relative"
style={{ top: '50%', height: '50%' }}
>
{props.msg}
</div>
<div className="col col--4" />
</div>
);
};
Loading

0 comments on commit ca18721

Please sign in to comment.