<!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>Modaling Things!</h2>
</header>
<footer>
<app>
<button>EDIT BOX MODAL</button>
<div id="modalme">
<modaler></modaler>
</div>
</app>
<!-- inline templates -->
<div class="templates hide">
<box-modal-template>
<mymodal>
<input/>
</mymodal>
</box-modal-template>
</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="mini-redux.js"></script>
<script src="redux-app-store.js"></script>
<script src="modal/modal-conductor.js"></script>
<script src="modal/modal-wrapper.js"></script>
<script src="modal/box-details-modal.js"></script>
<script src="app.js"></script>
</body>
</html>
//App entry container
var defaultProps = {appState: {}}
var App = mag.module(document.querySelector("app"), {
controller: function() {
return {
button: {
_onClick: e => {
store.dispatch({
type: "OPEN-MODAL",
name: "box-details"
})
}
}
}
},
view: function(state, props) {
ModalConductor({...props,
isOpen: props.appState.modalOpen,
modalName: props.appState.modalName
})
}
}, defaultProps)
//Update props with dispatch action
App.getProps().hideModal = function() {
store.dispatch({
type: "HIDE-MODAL"
})
}
store.subscribe((action, state) => {
App.getProps().appState = state
App.draw()
})
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;
}
.valid {
border-color:green;
}
.invalid {
border-color:red;
}
/* modal */
.modal {
position: fixed;
top: 100px;
left: 50%;
width: 80%;
z-index: 100;
background-color: transparent;
}
.modal .wrapper {
position: relative;
left: -50%;
background-color: #fff;
padding: 10px;
border: solid 2px #444;
border-radius: 10px;
}
.modal .content {
margin-bottom: 0;
margin-bottom: 0;
overflow-x: hidden;
overflow-y: scroll;
}
.modal .close-modal {
/* float: right; */
position: relative;
right: -7px;
bottom: 35px;
}
#MagJS
https://github.com/magnumjs/mag.js
Example of Hierarchical structure of components and reuse
//Modal wrapper Comp
let ModalWrapper;
mag.template("modal/modal-template.html")
.then(data => {
var defaultProps = {
title: '',
showOk: true,
okText: 'OK',
okDisabled: false,
width: 400,
onOk: () => {}
};
ModalWrapper = mag(data, props => {
const handleBackgroundClick = e => {
if (e.target === e.currentTarget) props.hideModal();
}
const onOk = () => {
props.onOk();
props.hideModal();
}
const okButton = props.showOk ? ({
"ok": {
_onClick: onOk,
_disabled: props.okDisabled,
_text: props.okText
}
}) : null;
return ({
h1: props.title,
div: {
_onClick: handleBackgroundClick
},
close: {
_onClick: props.hideModal
},
...props, // pass through props like children...
...okButton
})
}, defaultProps)
})
var BoxDetailsModal = mag("box-modal-template", {
controller: function(props) {
//set Intial state
this.isValid = true
},
onIdChange: function(e) {
// vastly simplified logic
this.state.isValid = /^[A-Za-z][A-Za-z0-9-_]*$/.test(e.target.value)
// update something...
},
view: function(state, props) {
state.mymodal = ModalWrapper({
...props,
title: "Edit text item",
width: 800,
okDisabled: !this.state.isValid
})
state.input = {
_value: this.props.id,
_class: state.isValid ? "valid" : "invalid",
_onInput: this.onIdChange
}
}
})
var ModalConductor = mag("modalme", props => {
var Modals = {
"box-details": BoxDetailsModal
}
if (props.isOpen && Modals[props.modalName]) {
return {modaler: Modals[props.modalName]({...props
})}
} else if(props.isOpen === false) {
return {modaler:null}
}
})
var createStore = function(intialState, reducer) {
var currentState = intialState;
var currentReducer = reducer;
var listeners = [];
function subscribe(listener) {
listeners.push(listener)
return function unsubscribe() {
var index = listeners.indexOf(listener)
listeners.splice(index, 1)
}
}
function dispatch(action) {
currentState = currentReducer(currentState, action)
listeners.forEach(listener => listener(action, currentState))
}
//Init:
dispatch({})
return {
subscribe,
dispatch,
getState: () => currentState
}
}
//Reducer:
var initialAppState = {
modalOpen: false
}
var store = createStore(initialAppState, function(state, action) {
switch (action.type) {
case "OPEN-MODAL":
return {
...state,
modalOpen: true,
modalName: action.name
}
case "HIDE-MODAL":
return {
...state,
modalOpen: false
}
default:
return state
}
})
<div class="modal">
<div class="wrapper">
<header>
<h1></h1>
<button class="close">Close</button>
</header>
<children></children>
<button class="ok"></button>
</div>
</div>