Skip to content

Commit

Permalink
AltManager + WeatherTabs App Example
Browse files Browse the repository at this point in the history
  • Loading branch information
Alvin Sng committed Mar 24, 2015
1 parent bffff73 commit a901e9c
Show file tree
Hide file tree
Showing 17 changed files with 652 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/weathertabs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/js/bundle.js
17 changes: 17 additions & 0 deletions examples/weathertabs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## AltManager example: Weather Tabs App

This is an example React/Flux/Alt app that shows the use of AltManager, a
utility class for Alt.js. AltManager allows for multiple alt instances which is
necessary to build apps that encapsulates a mini app inside of a large app. In
this example we have a simple weather searcher. Each search you make will
create a new tab which itself is a new Alt instance and has its own internal
store & actions. Whatever you do in the alt instance is persisted even after
you move to another tab. You can delete tabs which will delete that alt instance

## Install
1) run `npm run clean`
2) open the index.html file

## Docs
See /utils/AltManager.js for details on how to use AltManager.js
See /mixins/AltManagerMixin.js for details on mixin usage.
90 changes: 90 additions & 0 deletions examples/weathertabs/css/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
body {
font-family: 'Lato', sans-serif, "Arial";
font-size: 16px;
background: #eee;
margin: 0;
}

h1 {
background: #333;
margin: 0;
padding: 20px 20px;
color: #eee;
border-bottom: solid 3px #aaa;
}

.search-box {
width: 600px;
margin: 40px auto 60px auto;
}

.search-location {
padding: 6px;
width: 380px;
margin-right: 10px;
font-size: 20px;
border-radius: 3px;
border: solid 1px #ccc;
}

button {
font-size: 20px;
padding: 6px 14px;
background: #333;
color: #eee;
border: solid 1px #999;
border-radius: 3px;
}

.content {
padding: 0 20px;
}

.pull-right {
float:right;
}

.weather-tab {
padding: 20px;
background: #ccc;
border-radius: 3px;
}

.loading img {
margin: 0 auto;
display: block;
padding: 50px 0;
}

.nav {
list-style: none;
padding: 0;
margin: 0 20px;
}

.nav li {
display: inline;
margin: 0;
font-size: 20px;
padding: 10px 0;
background: #333;
position: relative;
bottom: 10px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}

.nav li a {
color: white;
padding: 0 1em;
text-decoration: none;
}

.nav li.selected {
background: #ccc;
padding-top: 18px;
}

.nav li.selected a {
color: #000;
}
Binary file added examples/weathertabs/images/loading.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions examples/weathertabs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AltManager - Weather Tabs App</title>
<link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Lato" />
<link rel="stylesheet" type="text/css" href="css/app.css" />
</head>
<body>
<section id="weather-tabs"></section>
<script src="js/bundle.js"></script>
</body>
</html>
12 changes: 12 additions & 0 deletions examples/weathertabs/js/actions/AppActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
var alt = require('../alt')

module.exports = alt.createActions(class AppActions {
constructor() {
this.generateActions(
'setManager',
'addLocation',
'setLocation',
'deleteLocation'
);
}
});
33 changes: 33 additions & 0 deletions examples/weathertabs/js/actions/WeatherActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
var $ = require('jquery');

class WeatherActions {
constructor() {
this.generateActions(
'setLoading',
'setWeather',
'showRaw'
);
}

loadWeather(location) {
this.dispatch(location);
$.ajax('http://api.openweathermap.org/data/2.5/weather', {
crossDomain: true,
data: { q: location },
success: (data) => {
// we put in a fake delay here to show the loading icon
setTimeout(() => {
if (data.weather) {
this.actions.setWeather(data);
}
this.actions.setLoading(false);
}, 500);
},
error: () => {
this.actions.setLoading(false);
}
});
}
}

module.exports = WeatherActions;
2 changes: 2 additions & 0 deletions examples/weathertabs/js/alt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
var Alt = require('../../../');
module.exports = new Alt();
7 changes: 7 additions & 0 deletions examples/weathertabs/js/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
var React = require('react');
var App = require('./components/App.jsx');

React.render(
React.createElement(App),
document.getElementById('weather-tabs')
);
82 changes: 82 additions & 0 deletions examples/weathertabs/js/components/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
var React = require('react');
var ReactStateMagicMixin = require('../../../../mixins/ReactStateMagicMixin');
var Alt = require('../../../../');
var AltManager = require('../../../../utils/AltManager');
var AppActions = require('../actions/AppActions');
var AppStore = require('../stores/AppStore');
var WeatherTab = require('./WeatherTab.jsx');

var manager = new AltManager(Alt);
AppActions.setManager(manager);

module.exports = React.createClass({

displayName: 'App',
mixins: [ReactStateMagicMixin],
statics: { registerStore: AppStore },

render: function() {
var locationLinks = [];
var weatherApp = null;

if (this.state.location) {
weatherApp = (
<WeatherTab
alt={manager.getOrCreate(this.state.location)}
location={this.state.location} />
);
}

for (var location in manager.all()) {
locationLinks.push(
<li
key={location}
className={location === this.state.location ? 'selected' : null}>
<a href="javascript:void(0);" onClick={this._onClickLocation.bind(this, location)}>
{location}
</a>
</li>
);
}

return (
<div>
<h1>AltManager - Weather Tabs App</h1>
<div className="content">
<p>
This is an example React/Flux/Alt app that shows the use of AltManager, a
utility class for Alt.js. AltManager allows for multiple alt instances which is
necessary to build apps that encapsulates a mini app inside of a large app. In
this example we have a simple weather searcher. Each search you make will
create a new tab which itself is a new Alt instance and has its own internal
store & actions. Whatever you do in the alt instance is persisted even after
you move to another tab. You can delete tabs which will delete that alt instance
</p>
<form className="search-box" onSubmit={this._onClickSubmit}>
<input
type="text"
className="search-location"
placeholder="Location eg. New York City, NY"/>
<button>Search Weather</button>
</form>
<ul className="nav">{locationLinks}</ul>
{weatherApp}
</div>
</div>
);
},

componentDidMount: function() {
// we load San Francisco, CA on page load as an example
AppActions.addLocation('San Francisco, CA');
},

_onClickSubmit: function(e) {
e.preventDefault();
AppActions.addLocation(e.target.children[0].value.trim());
},

_onClickLocation: function(location) {
AppActions.setLocation(location);
}
});
68 changes: 68 additions & 0 deletions examples/weathertabs/js/components/WeatherTab.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
var React = require('react');
var AltManagerMixin = require('../../../../mixins/AltManagerMixin');
var AppActions = require('../actions/AppActions');
var WeatherActions = require('../actions/WeatherActions');
var WeatherStore = require('../stores/WeatherStore');

module.exports = React.createClass({

displayName: 'WeatherTab',

mixins: [AltManagerMixin],
statics: { registerStore: WeatherStore, registerAction: WeatherActions },

onNewAlt: function(state, newProps) {
// load weather if none exists
if (!state.location && !state.loading) {
this.action.loadWeather(newProps.location);
}
},

_onClickShowRaw: function() {
this.action.showRaw(!this.state.showRaw);
},

onClickDelete: function() {
AppActions.deleteLocation(this.props.location);
},

getWeatherContent: function() {
if (this.state.loading) {
return <div className="loading"><img src="images/loading.gif" /></div>;
}

if (!this.state.weather) {
return <p>Error loading weather data, check location</p>;
}

var weather = this.state.weather;
var rawData = null;
var showText = 'Show Raw JSON';
if (this.state.showRaw) {
rawData = <pre>{JSON.stringify(weather, null, 4)}</pre>;
showText = 'Hide Raw JSON';
}

return (
<div className="weather-data">
<h3>Current Temp: {weather.main.temp}K, {weather.weather[0].description}</h3>
<button onClick={this._onClickShowRaw}>
{showText}
</button>
{rawData}
</div>
);
},

render: function() {
return (
<div className="weather-tab">
<button className="pull-right" onClick={this.onClickDelete}>
Close Tab
</button>
<h2>Weather For {this.state.location}</h2>
{this.getWeatherContent()}
</div>
);
},
});
33 changes: 33 additions & 0 deletions examples/weathertabs/js/stores/AppStore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
var alt = require('../alt');

var AppActions = require('../actions/AppActions');

module.exports = alt.createStore(class AppStore {
constructor() {
this.bindActions(AppActions);
this.location = null;
this.manager = null;
}

setManager(manager) {
this.manager = manager;
}

addLocation(location) {
this.manager.getOrCreate(location);
this.location = location;
}

setLocation(location) {
this.location = location;
}

deleteLocation(location) {
this.manager.delete(location);
this.location = null;
for (var i in this.manager.all()) {
this.location = i;
break;
}
}
});
28 changes: 28 additions & 0 deletions examples/weathertabs/js/stores/WeatherStore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class WeatherStore {
constructor(alt) {
this.bindActions(alt.getActions('WeatherActions'));
this.loading = false;
this.weather = null;
this.showRaw = false;
this.location = null;
}

loadWeather(location) {
this.location = location;
this.loading = true;
}

setLoading(isLoading) {
this.loading = isLoading
}

setWeather(weather) {
this.weather = weather;
}

showRaw(showRaw) {
this.showRaw = showRaw;
}
}

module.exports = WeatherStore;
Loading

0 comments on commit a901e9c

Please sign in to comment.