JSFiddle - React, Tailwind, and code Playground
DPadComponentMockup
by Retsam19
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<div class="main">
<!-- ko template: {
name: "layout",
data: main
} -->
<!-- /ko -->
</div>
<template id="layout">
<div class="layout" data-bind="
css: directionStyle
">
<!-- ko template: {
name: 'layout-cell',
foreach: cells
} -->
<!-- /ko -->
<!--<div class="overlay"></div>-->
</div>
</template>
<template id="layout-cell">
<div class="layout-cell" data-bind="
css: {
'stretch': !isFixed
},
style: {
flexBasis: flexBasis
}
">
<!-- ko if: !isFixed -->
<!-- ko if: content -->
<!-- ko template: {
name: 'layout',
data: content
} -->
<!-- /ko -->
<!-- /ko -->
<!-- ko ifnot: content -->
<!-- ko template: {
name: 'dpad',
data: dpad
} -->
<!-- /ko -->
<!-- /ko -->
<!-- /ko -->
</div>
</template>
<template id="dpad">
<div class="dpad">
<div class="quarter quarter1" data-bind="
click: clickHandler('up')
"></div>
<div class="quarter quarter2" data-bind="
click: clickHandler('right')
"></div>
<div class="quarter quarter3" data-bind="
click: clickHandler('left')
"></div>
<div class="quarter quarter4" data-bind="
click: clickHandler('down')
"></div>
<div class="cutout"></div>
</div>
</template>
SCSS
html, body {
height: 100%
}
.main {
display: flex;
height: 100%;
}
.layout {
/* position: relative; */
flex-grow: 1;
border: 1px solid black;
display: flex;
}
.layout-column {
flex-direction: column;
}
.layout-row {
flex-direction: row;
}
.layout-cell {
display: flex;
background-color: rgba(0, 0, 255, 10%);
outline: 1px solid green;
flex-grow: 0;
&.stretch {
flex-grow: 1;
}
}
/*
.overlay {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
display: flex;
align-items: center;
background-color: rgba(255, 0, 0, 30%);
} */
/**
* Quarter Circles
*/
.dpad {
align-self: center;
position:relative;
width:100px;
height:100px;
margin:0 auto;
}
.quarter {
position:absolute;
width:50%;
height:50%;
transform: rotate(45deg);
cursor: pointer;
}
.quarter:hover {
background-color:pink;
}
.quarter1 {
top:0;
left:0;
background-color: #CCC;
border-radius:100% 0 0 0;
transform-origin: bottom right;
}
.quarter2 {
top:0;
right:0;
background-color: #DDD;
border-radius:0 100% 0 0;
transform-origin: bottom left;
}
.quarter3 {
bottom:0;
left:0;
background-color: #DDD;
border-radius:0 0 0 100%;
transform-origin: top right;
}
.quarter4 {
bottom:0;
right:0;
background-color: #CCC;
border-radius:0 0 100% 0 ;
transform-origin: top left;
}
.cutout {
width:50%;
height:50%;
background-color:white;
position:absolute;
top:25%;
left:25%;
border-radius:50%;
/* pointer-events:none; */
cursor: default;
}
Babel + JSX
const ROW = "row";
const COL = "column";
class LayoutContainer {
constructor (data) {
this.direction = data.direction;
console.log(`Cosnstructed new ${this.direction} layout`)
this.directionStyle = `layout-${this.direction}`;
const makeChild = (data) => new LayoutCell(data, addCell);
const addCell = (sourceCell, direction) => {
console.log(`${direction} clicked`);
if(this.direction === ROW && (direction === "up" || direction === "down") ||
this.direction === COL && (direction === "left" || direction === "right")) {
const fixedCellFirst = direction === "up" || direction === "left";
const newLayoutData = {
direction: this.direction === ROW ? COL : ROW,
cells: [{
isFixed: fixedCellFirst
}, {
isFixed: !fixedCellFirst
}]
};
sourceCell.content(new LayoutContainer(newLayoutData));
} else {
console.log(`Adding sibling ${direction}`)
const sourceCellIndex = this.cells().indexOf(sourceCell);
//Adding a sibling to the source cell
const newCellIndex = (direction === "up" || direction === "left") ?
sourceCellIndex : //Add before
sourceCellIndex + 1; //Add after
this.cells.splice(newCellIndex, 0, makeChild({isFixed: true}))
}
}
this.cells = ko.observableArray(data.cells.map(makeChild));
}
}
class LayoutCell {
constructor(data, addCell) {
this.isFixed = data.isFixed;
this.content = ko.observable(data.content && new LayoutContainer(data.content));
this.flexBasis = this.isFixed ? "100px" : "fill";
this.dpad = {
clickHandler: (direction) => () => {
addCell(this, direction)
}
};
}
}
const holyGrailData = {
direction: COL,
cells: [{
isFixed: true
}, {
isFixed: false,
content: {
direction: ROW,
cells: [{
isFixed: true
...