A simple single page application, loading page components into a router component, dependant on route selected. Using attributes to configure the application we can pass in run time requirements as attributes. Bootstraped from a bootstrap file, by importing into a bigger application or direct as html script (ensure you build fallback for IE support).
<my-single-page-app></my-single-page-app>
<!-- Polyfill -->
<script src="/node_modules/promise-polyfill/dist/polyfill.min.js"></script>
<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
<!-- Bootstrap component only, ensure you have built fallback for IE support too (.js)! -->
<script type="module" src="./your/path/my-app.mjs"></script>
<script nomodule src="./your/path/my-app.js"></script>
<!-- Or add your switch import to a bootstrap js file/app using ES6 import and use that instead of the component directly... -->
<script type="module" src="./your/path/index.mjs"></script>
<script nomodule src="./your/path/index.js"></script>
<!-- example basic fouc resolution -->
<style>
[fouc] { opacity: 0; transition: opacity 200ms ease-in-out; }
[fouc="loaded"] { opacity: 1; }
</style>
...
<div class="info">
<div class="class">
<div class="row" fouc>
<div class="col-sm-12">
<my-single-page-app></my-single-page-app>
</div>
</div>
</div>
</div>
...
<!-- fouc for individual components -->
<script> setTimeout(() => document.querySelector('[fouc]').setAttribute('fouc', 'loaded'), 1000); </script>
import { CustomHTMLElement, html } from '../../../node_modules/custom-web-component/index.js';
// CustomWebComponents
import '../Components/my-router.mjs';
/** @ROUTES */
import '../Pages/test/page-test-index.mjs';
import '../Pages/test/page-test-one.mjs';
import '../Pages/test/page-test-two.mjs';
import '../Pages/test/page-test-three.mjs';
import '../Pages/test/page-test-four.mjs';
import '../Pages/test/page-test-five.mjs';
import '../Pages/not/page-not-found.mjs';
/**
* @public @name MySinglePageApp
* @extends CustomHTMLElement
* @description Application Web Component, main application gateway, the root web component that starts the application
* @author Paul Smith <[email protected]>
* @copyright 2018 Paul Smith (ulsmith.net)
* @license MIT
*
* @example HTML
* <my-single-page-app>Loading...</my-single-page-app>
*/
class MySinglePageApp extends CustomHTMLElement {
/**
* @public @constructor @name constructor
* @description Process called function triggered when component is instantiated (but not ready or in DOM, must call super() first)
*/
constructor() {
super();
this._route;
this._routes = [
{ component: 'page-test-index', path: 'home', label: 'Home' },
{ component: 'page-test-one', path: 'one', label: 'One' },
{ component: 'page-test-two', path: 'two', label: 'Two' },
{ component: 'page-test-three', path: 'three', label: 'Three' },
{ component: 'page-test-four', path: 'four', label: 'Four' },
{ component: 'page-test-five', path: 'five', label: 'Five' },
{ component: 'page-not-found', path: '404', label: '404', hidden: true }
];
}
/**
* @public @name template
* @description Template function to return web component HTML template
*
* @return {TemplateResult} HTML template result
*/
static template() {
return html`
<style>
:host { display: block; width: 100%; height: 100%; }
ul {
list-style-type: none;
margin: 10px 0px;
padding: 0;
}
li {
display: inline-block;
background: red;
padding: 4px 8px;
margin: 2px;
}
a {
color: white;
text-decoration: none;
}
[active] {
background: #444;
}
.header {
width: 100%;
background: orange;
padding: 20px;
box-sizing: border-box;
color: white;
}
.footer {
width: 100%;
background: #444;
padding: 20px;
box-sizing: border-box;
color: white;
}
</style>
<div class="header">
<h1>Header Goes Here</h1>
</div>
${this._route ? html`
<ul>
<li ?active="${this._route.path === 'home'}"><a href="#home">Home</a></li>
<li ?active="${this._route.path === 'one'}"><a href="#one">One</a></li>
<li ?active="${this._route.path === 'two'}"><a href="#two">Two</a></li>
<li ?active="${this._route.path === 'three'}"><a href="#three">Three</a></li>
<li ?active="${this._route.path === 'four'}"><a href="#four">Four</a></li>
<li ?active="${this._route.path === 'five'}"><a href="#five">Five</a></li>
<li><a href="#abcxyz">AbcXyz</a></li>
</ul>
` : ''}
<my-router .route="${this._route}" .routes="${this._routes}" default="home" not-found="404" @change="${this._changeRoute.bind(this)}"></my-router>
<div class="footer">
<p>Footer Goes Here</p>
</div>
`;
}
/**
* @private @name _changeRoute
* @description Change the route of the application
*
* @param {String} path The path of the route
*/
_changeRoute(ev) {
this._route = ev.detail;
this.updateTemplate();
window.scrollTo({ top: 0, behavior: 'smooth' });
}
}
// define the new custom element
customElements.define('my-single-page-app', MySinglePageApp);