Restructure app initiation
- Split initialization steps into their own files. - Use Choo routes instead of viewManager to properly set up 404 - Add styling for different colors of Picnic cards
This commit is contained in:
parent
49ab635660
commit
b093595f1d
|
@ -0,0 +1,27 @@
|
||||||
|
export const appListeners = (app, state, emitter) => {
|
||||||
|
emitter.on('DOMContentLoaded', () => {
|
||||||
|
document.title = app.siteConfig.siteName;
|
||||||
|
// Emitter listeners
|
||||||
|
emitter.on('render', callback => {
|
||||||
|
app.setSessionState();
|
||||||
|
// This is a dirty hack to get the callback to call *after* re-rendering.
|
||||||
|
if (callback && typeof callback === "function") {
|
||||||
|
setTimeout(() => {
|
||||||
|
callback();
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
emitter.on('change-view', newView => {
|
||||||
|
// Change the view and call render. Makes it easier to call within views.
|
||||||
|
state.currentView = newView;
|
||||||
|
emitter.emit('render', () => { });
|
||||||
|
});
|
||||||
|
|
||||||
|
emitter.on('set-language', newLanguage => {
|
||||||
|
app.setSettingsItem('lang', newLanguage);
|
||||||
|
state.language = newLanguage;
|
||||||
|
emitter.emit('render', () => { });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { I18n } from './i18n';
|
||||||
|
import { globalView } from './views/global';
|
||||||
|
import { homeView } from './views/home';
|
||||||
|
import { loginView } from './views/login';
|
||||||
|
import { searchView } from './views/search';
|
||||||
|
import { errorView } from './views/404';
|
||||||
|
|
||||||
|
export const appRoutes = (app) => {
|
||||||
|
const i18n = new I18n(app.state); // Global I18n class passed to all views
|
||||||
|
|
||||||
|
app.route('/', (state, emit) => globalView(state, emit, i18n, homeView));
|
||||||
|
|
||||||
|
app.route('/login', (state, emit) => globalView(state, emit, i18n, loginView));
|
||||||
|
|
||||||
|
app.route('/search', (state, emit) => globalView(state, emit, i18n, searchView));
|
||||||
|
|
||||||
|
app.route('/404', (state, emit) => globalView(state, emit, i18n, errorView));
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
export const appState = (app, state, emitter) => {
|
||||||
|
const sessionState = app.getSessionState();
|
||||||
|
if (sessionState) {
|
||||||
|
Object.keys(sessionState).forEach(key => {
|
||||||
|
if (typeof state[key] === 'undefined') {
|
||||||
|
state[key] = sessionState[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Default state variables
|
||||||
|
state.currentView = 'home';
|
||||||
|
state.language = app.getSettingsItem('lang') ? app.getSettingsItem('lang') : (navigator.language || navigator.userLanguage).split('-')[0];
|
||||||
|
state.viewStates = {};
|
||||||
|
state.isLoggedIn = false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
export const appUtilities = (app) => {
|
||||||
|
app.getSettingsItem = settingsKey => {
|
||||||
|
let savedSettings = window.localStorage.getItem('settings');
|
||||||
|
if (savedSettings) {
|
||||||
|
savedSettings = JSON.parse(savedSettings);
|
||||||
|
if (typeof savedSettings[settingsKey] !== 'undefined') {
|
||||||
|
return savedSettings[settingsKey];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
app.setSettingsItem = (settingsKey, value) => {
|
||||||
|
let savedSettings = window.localStorage.getItem('settings');
|
||||||
|
if (savedSettings) {
|
||||||
|
savedSettings = JSON.parse(savedSettings);
|
||||||
|
} else {
|
||||||
|
savedSettings = {};
|
||||||
|
}
|
||||||
|
savedSettings[settingsKey] = value;
|
||||||
|
return window.localStorage.setItem('settings', JSON.stringify(savedSettings));
|
||||||
|
}
|
||||||
|
app.getSessionState = () => {
|
||||||
|
let sessionState = window.sessionStorage.getItem('sessionState');
|
||||||
|
if (sessionState) {
|
||||||
|
return JSON.parse(sessionState);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
app.setSessionState = () => {
|
||||||
|
return window.sessionStorage.setItem('sessionState', JSON.stringify(app.state));
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,10 @@
|
||||||
"logged_out_recent_updates": "Recent Updates",
|
"logged_out_recent_updates": "Recent Updates",
|
||||||
"logged_out_join_now": "Join Now!"
|
"logged_out_join_now": "Join Now!"
|
||||||
},
|
},
|
||||||
|
"404": {
|
||||||
|
"header": "Oops!",
|
||||||
|
"subheader": "It looks like the page you requested doesn't exist. Please try a different one!"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"log_in": "Log In",
|
"log_in": "Log In",
|
||||||
"email": "Email",
|
"email": "Email",
|
||||||
|
|
87
app/index.js
87
app/index.js
|
@ -3,7 +3,10 @@ import 'babel-polyfill';
|
||||||
import choo from 'choo';
|
import choo from 'choo';
|
||||||
|
|
||||||
import config from './config.json';
|
import config from './config.json';
|
||||||
import { viewManager } from './views/manager';
|
import { appRoutes } from './appRoutes';
|
||||||
|
import { appListeners } from './appListeners';
|
||||||
|
import { appState } from './appState.js';
|
||||||
|
import { appUtilities } from './appUtilities.js';
|
||||||
|
|
||||||
const app = choo();
|
const app = choo();
|
||||||
|
|
||||||
|
@ -13,88 +16,18 @@ if (process.env.NODE_ENV !== 'production') {
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use((state, emitter) => {
|
app.use((state, emitter) => {
|
||||||
app.getSettingsItem = settingsKey => {
|
app.siteConfig = config;
|
||||||
let savedSettings = window.localStorage.getItem('settings');
|
appUtilities(app);
|
||||||
if (savedSettings) {
|
|
||||||
savedSettings = JSON.parse(savedSettings);
|
|
||||||
if (typeof savedSettings[settingsKey] !== 'undefined') {
|
|
||||||
return savedSettings[settingsKey];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
app.setSettingsItem = (settingsKey, value) => {
|
|
||||||
let savedSettings = window.localStorage.getItem('settings');
|
|
||||||
if (savedSettings) {
|
|
||||||
savedSettings = JSON.parse(savedSettings);
|
|
||||||
} else {
|
|
||||||
savedSettings = {};
|
|
||||||
}
|
|
||||||
savedSettings[settingsKey] = value;
|
|
||||||
return window.localStorage.setItem('settings', JSON.stringify(savedSettings));
|
|
||||||
}
|
|
||||||
app.getSessionState = () => {
|
|
||||||
let sessionState = window.sessionStorage.getItem('sessionState');
|
|
||||||
if (sessionState) {
|
|
||||||
return JSON.parse(sessionState);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
app.setSessionState = () => {
|
|
||||||
return window.sessionStorage.setItem('sessionState', JSON.stringify(app.state));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// App state and emitters
|
|
||||||
app.use((state, emitter) => {
|
app.use((state, emitter) => {
|
||||||
const sessionState = app.getSessionState();
|
appState(app, state);
|
||||||
if (sessionState) {
|
|
||||||
Object.keys(sessionState).forEach(key => {
|
|
||||||
if (typeof state[key] === 'undefined') {
|
|
||||||
state[key] = sessionState[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Default state variables
|
|
||||||
state.currentView = 'home';
|
|
||||||
state.language = app.getSettingsItem('lang') ? app.getSettingsItem('lang') : (navigator.language || navigator.userLanguage).split('-')[0];
|
|
||||||
state.viewStates = {};
|
|
||||||
state.isLoggedIn = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listeners
|
// Listeners
|
||||||
emitter.on('DOMContentLoaded', () => {
|
appListeners(app, state, emitter);
|
||||||
document.title = config.siteName;
|
|
||||||
// Emitter listeners
|
|
||||||
emitter.on('render', callback => {
|
|
||||||
app.setSessionState();
|
|
||||||
// This is a dirty hack to get the callback to call *after* re-rendering.
|
|
||||||
if (callback && typeof callback === "function") {
|
|
||||||
setTimeout(() => {
|
|
||||||
callback();
|
|
||||||
}, 50);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
emitter.on('change-view', newView => {
|
|
||||||
// Change the view and call render. Makes it easier to call within views.
|
|
||||||
state.currentView = newView;
|
|
||||||
emitter.emit('render', () => {});
|
|
||||||
});
|
|
||||||
|
|
||||||
emitter.on('set-language', newLanguage => {
|
|
||||||
app.setSettingsItem('lang', newLanguage);
|
|
||||||
state.language = newLanguage;
|
|
||||||
emitter.emit('render', () => {});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// For the main screen, pass the viewManager function in viewManager.js,
|
// Routes
|
||||||
// which is given the app's state from above and the emitter.emit method that
|
appRoutes(app);
|
||||||
// triggers the app's emitter listeners.
|
|
||||||
app.route('/', viewManager);
|
|
||||||
app.route('/:page', viewManager);
|
|
||||||
app.route('/404', viewManager);
|
|
||||||
|
|
||||||
app.mount('body'); // Overwrite the `<body>` tag with the content of the Choo app
|
app.mount('body'); // Overwrite the `<body>` tag with the content of the Choo app
|
||||||
|
|
|
@ -107,12 +107,38 @@ footer nav {
|
||||||
margin: 0 0 0 auto;
|
margin: 0 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card.info {
|
.card {
|
||||||
background: $picnic-info;
|
&.info {
|
||||||
color: $picnic-white;
|
background: $picnic-info;
|
||||||
|
|
||||||
* {
|
|
||||||
color: $picnic-white;
|
color: $picnic-white;
|
||||||
|
|
||||||
|
* {
|
||||||
|
color: $picnic-white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.success {
|
||||||
|
background: $picnic-success;
|
||||||
|
color: $picnic-white;
|
||||||
|
|
||||||
|
* {
|
||||||
|
color: $picnic-white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.warning {
|
||||||
|
background: $picnic-warning;
|
||||||
|
color: $picnic-white;
|
||||||
|
|
||||||
|
* {
|
||||||
|
color: $picnic-white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.error {
|
||||||
|
background: $picnic-error;
|
||||||
|
color: $picnic-white;
|
||||||
|
|
||||||
|
* {
|
||||||
|
color: $picnic-white;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import html from 'choo/html';
|
||||||
|
|
||||||
|
export const errorView = (state, emit, i18n) => {
|
||||||
|
return html`<section class="error card">
|
||||||
|
<header>
|
||||||
|
<h1>${i18n.__('404.header')}</h1>
|
||||||
|
</header>
|
||||||
|
<footer>
|
||||||
|
<h2>${i18n.__('404.subheader')}</h2>
|
||||||
|
</footer>
|
||||||
|
</section>`;
|
||||||
|
}
|
|
@ -2,34 +2,9 @@ import html from 'choo/html';
|
||||||
|
|
||||||
import headerImage from '../../dev/images/header.png';
|
import headerImage from '../../dev/images/header.png';
|
||||||
|
|
||||||
import { I18n } from '../i18n';
|
export const globalView = (state, emit, i18n, view) => {
|
||||||
import { homeView } from './home';
|
|
||||||
import { loginView } from './login';
|
|
||||||
import { searchView } from './search';
|
|
||||||
|
|
||||||
export const viewManager = (state, emit) => {
|
|
||||||
const i18n = new I18n(state); // Global I18n class passed to all views
|
|
||||||
// In viewManager all we are doing is checking the app's state
|
|
||||||
// and passing the state and emit to the relevant view.
|
|
||||||
let htmlContent = html`<div>loading</div>`;
|
|
||||||
switch (state.params.page) {
|
|
||||||
case 'home':
|
|
||||||
default: {
|
|
||||||
htmlContent = homeView(state, emit, i18n);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'login': {
|
|
||||||
htmlContent = loginView(state, emit, i18n);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'search': {
|
|
||||||
htmlContent = searchView(state, emit, i18n);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a wrapper for view content that includes global header/footer
|
// Create a wrapper for view content that includes global header/footer
|
||||||
let view = html`<body>
|
return html`<body>
|
||||||
<header>
|
<header>
|
||||||
<nav>
|
<nav>
|
||||||
<div class="brand">
|
<div class="brand">
|
||||||
|
@ -58,7 +33,7 @@ export const viewManager = (state, emit) => {
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main class="container">
|
<main class="container">
|
||||||
${htmlContent}
|
${view(state, emit, i18n)}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
|
@ -74,6 +49,4 @@ export const viewManager = (state, emit) => {
|
||||||
</nav>
|
</nav>
|
||||||
</footer>
|
</footer>
|
||||||
</body>`;
|
</body>`;
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue