<!DOCTYPE html>
<html>
<head>
<link href="//cdn.jsdelivr.net/picnicss/4.1.1/picnic.min.css" rel="stylesheet">
<link rel="stylesheet" href="style.css">
<meta charset="utf-8">
<title>Mag.JS</title>
</head>
<body>
<nav>
<h1>Hello Mag.JS!</h1> <a target="_tab" href="https://github.com/magnumjs/mag.js">GitHub</a> </nav>
<article class="card">
<header>
<h2>Tabbed Comp of Comps!</h2> </header>
<footer>
<div id="app">
<todos-app>Loading..</todos-app>
</div>
</footer>
</article>
<script src="//rawgit.com/magnumjs/mag.js/master/mag-latest.min.js"></script>
<script src="//rawgit.com/magnumjs/mag.js/master/dist/mag.addons.0.22.min.js"></script>
<script src="//rawgit.com/magnumjs/mag.js/master/src/extends/mag-template.js"></script>
<script src="//rawgit.com/magnumjs/mag.js/master/src/addons/tiny-redux.js"></script>
<script src="tabs/tabs-module.js"></script>
<script src="tabs/tabs-comps.js"></script>
<script src="data-table/data-table-module.js"></script>
<script src="app.js"></script>
</body>
</html>
//Boot App:
var App = {}
var PRODUCTS = [
{category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},
{category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},
{category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},
{category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},
{category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},
{category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}
];
var HEADERS = [{name: "Name", selected: ""},{name: "Price", selected: ""}];
var defaultProps = {
data: ["Products 1", "Products 2", "Products 3"],
selectedTab: 1,
tabContent: function(index) {
if(ProductTable){
return ProductTable({
key: index,
products: PRODUCTS,
headers: HEADERS,
onHeaderClick: function(name){
console.warn("CLICKED", name)
}
})
}
}
}
App.controller = function(props) {
//Load template container
this['todos-app'] = mag(Tabs.templateUrl, Tabs, props)
}
mag.module("app", App, defaultProps)
li:empty,
.hide {
display: none;
}
a {
display: block;
}
a:after {
content: " \bb";
}
.mainButton {
font-size: 1.5em;
}
nav a {
float: right;
margin-top: -50px;
}
body {
background: #fff;
text-align: left;
width: 90%;
max-width: 960px;
margin: 0 auto;
padding: 20px 0 0;
}
nav {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 3em;
padding: 0 .6em;
background: #fff;
box-shadow: 0 0 0.2em rgba(17, 17, 17, 0.2);
z-index: 10000;
transition: all .3s;
transform-style: preserve-3d;
}
header {
font-weight: bold;
position: relative;
border-bottom: 1px solid #eee;
padding: .6em .8em;
}
footer {
padding: .8em;
}
article {
top: 100px;
}
.card {
max-width: 100%;
display: block;
position: relative;
box-shadow: 0;
border-radius: .2em;
border: 1px solid #ccc;
overflow: hidden;
text-align: left;
background: #fff;
margin-bottom: .6em;
padding: 6px;
transition: all .3s ease;
}
/* Tabs */
.tabContainer {
margin: 10px 0;
width: 400px;
}
.tabContainer .digiTabs {
list-style: none;
display: block;
overflow: hidden;
margin: 0;
padding: 0px;
position: relative;
top: 1px;
}
.tabContainer .digiTabs li {
float: left;
background-color: #46AAF7;
border: 1px solid #e1e1e1;
padding: 5px!important;
cursor: pointer;
border-bottom: none;
margin-right: 10px;
font-family: verdana;
font-size: .8em;
font-weight: bold;
color: #fff;
}
.tabContainer .digiTabs .selected {
background-color: #fff;
color: #393939;
}
#tabContent {
padding: 10px;
background-color: #fff;
overflow: hidden;
float: left;
margin-bottom: 10px;
border: 1px solid #e1e1e1;
width: 93%;
}
/* table */
.row-header {
text-align: left;
font-weight: 900;
color: #fff;
background-color: #0074d9;
}
.row-title {
font-weight: bold
}
.row {
width: calc(100% + 2 * 0.6em);
display: table;
table-layout: fixed;
padding-left: 4px;
}
.row.outofstock .name {
color: red;
}
.row:nth-child(even) {
background: rgba(0, 0, 0, 0.05);
}
.row-header div,
.row-cell {
float: left;
width: 50%;
}
.header div {
cursor: pointer;
}
.header div i {
vertical-align:super;
font-size:10px;
}
#Mag.JS
## plunk boilerplate of "Things"
Basic template loader example
with mixing state and stateless components
and observable data store
<div class="tabContainer">
<ul class="digiTabs" id="sidebarTabs">
<li>Tab 1</li>
</ul>
<ul id="tabContent">
<li></li>
</ul>
</div>
var Tabs = {
templateUrl: 'tabs/tabs.html'
}
Tabs.controller = function(props) {
this.didload = () => Tabs.UI.mount()
this.selectedTab = props.selectedTab || 0;
this.$li = {
_onClick: function(e, index) {
this.state.selectedTab = index;
}
}
}
Tabs.contentItems = []
Tabs.view = function(state, props) {
Tabs.UI.nav({
items: props.data.map((item, index) => {
var selected = index === state.selectedTab ? "selected" : ""
return {
_text: item,
_class: selected
}
})
})
if (Tabs.contentItems.length != props.data.length) {
for (var i = 0; i < props.data.length; i++) {
var comp = props.tabContent(i);
if (comp) Tabs.contentItems.push(comp)
}
}
Tabs.UI.content({
visibleIndex: state.selectedTab,
items: Tabs.contentItems
})
}
//UI Components:
Tabs.UI = {
nav: () => {},
content: () => {}
}
//Define
Tabs.UI.navComp = ({items}) => ({
li: items
})
Tabs.UI.contentComp = ({visibleIndex, items}) => ({
$li: items,
li: items.map((item, index)=>{
var display = index === visibleIndex ? "" : "hide"
return {_class: display}
})
})
Tabs.UI.mount = () => {
//Attach
Tabs.UI.nav = mag('digiTabs', Tabs.UI.navComp)
Tabs.UI.content = mag('tabContent', Tabs.UI.contentComp)
}
var ProductTable;
mag.template("data-table/data-table.html")
.then(data=>{
var ProductCategoryRowTemplate = mag.find(data, "ProductCategoryRow")[0]
var ProductCategoryRow = mag(ProductCategoryRowTemplate, ({category})=>({category: category}))
var ProductRowTemplate = mag.find(data, "ProductRow")[0]
var ProductRow = mag(ProductRowTemplate, (props)=>{
var name = props.product.stocked ?
props.product.name : {
_style: 'color: red',
_text: props.product.name
};
var price = props.product.price;
return {name, price};
}, {product: {}})
var ProductTableTemplate = mag.find(data, "ProductTable")[0]
ProductTable = mag(ProductTableTemplate, ({products, headers, onHeaderClick, key})=>{
var lastCategory = null, rows=[], header={div:[]};
if (products) {
header.div = headers.map(function(head){
return {i: head.selected, _text: head.name, _onClick: ()=>onHeaderClick(head.name)}
})
products.forEach(function(product, i) {
if (product.category !== lastCategory) {
rows.push(ProductCategoryRow({
category: product.category,
key: product.category + i + key
}));
}
rows.push(ProductRow({
product: product,
key: product.name + key
}));
lastCategory = product.category;
});
}
return {rows, header};
})
})
<div class="data-table">
<div class="ProductRow">
<div class="row">
<div class="row-cell name">NAME</div>
<div class="row-cell price">PRICE</div>
</div>
</div>
<div class="ProductCategoryRow">
<div class="row row-header">
<category></category>
</div>
</div>
<div class="ProductTable">
<div class="row header row-header">
<div>Name <i></i></div>
</div>
<div class="row rows"></div>
</div>
</div>