pivot-editor/index.html
2021-05-29 11:20:11 -04:00

411 lines
12 KiB
HTML
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="N.js"></script>
<script src="Pivot.js"></script>
</head>
<body>
<div id="app"></div>
<!-- rendering -->
<script>
var Render = function(){};
</script>
<script type="module">
Pivot.Init(
["id", "type-a", "type-b", "count", "extra"],
["label", "label", "label", "sum", "sum"],
[
["#1", "a", "long", 1, 4],
["#2", "b", "long", 2, 4],
["#3", "b", "short", 2, 4],
["#4", "a", "long", 3, 4],
["#5", "b", "short", 1, 4],
["#6", "a", "short", 0, 4],
["#7", "b", "short", 7, 4]
]
);
import { h, render, createContext, Fragment } from 'https://cdn.skypack.dev/preact';
import { useReducer, useState } from 'https://cdn.skypack.dev/preact/hooks';
import { css, cx } from 'https://cdn.skypack.dev/@emotion/css';
import htm from 'https://unpkg.com/htm?module';
const html = htm.bind(h);
let PivotForm = props =>
{
let styles = css`
position:realtive;
box-sizing: border-box;
padding: 10px;
color:black;
font-family:sans-serif;
.Title
{
font-size:24px;
font-weight:100;
}
.Section
{
padding:10px 0 10px 0;
.Heading
{
display:inline-block;
color:#666;
font-family:sans-serif;
font-size:12px;
font-weight:900;
text-transform:uppercase;
}
.Group
{
display:inline-block;
padding:5px;
border-radius:5px;
margin:3px;
background:rgba(0, 0, 0, 0.3)
}
}
`;
let pivotColumns = N.Step(Pivot.Schema, "label")||[];
let pivotColumnsUsed = N.Step(Pivot.Proto, "used-pivot")||[];
let sumColumns = N.Step(Pivot.Schema, "sum")||[];
//let sumColumnsUsed = N.Step(Pivot.Proto, "used-sum")||[];
let indiciesPivot = pivotColumnsUsed.map(node=>node.Meta.Index);
let indiciesSum = sumColumns.map(node=>node.Meta.Index);
//let indiciesSum = sumColumnsUsed.map(node=>node.Meta.Index);
let displayPivotsAll = html`
<div class="Section">
<div class="Heading">Available Columns</div>
<div class="Group">
${pivotColumns.map( columnPivot =>
{
let attributes = {};
if(N.Step(columnPivot, "used-pivot", false))
{
attributes.disabled = true;
}
else
{
attributes.onClick = e=>
{
N.Connect(Pivot.Proto, columnPivot, "used-pivot");
Render();
}
}
return html`<button ...${attributes}>${columnPivot.Meta.Label}</button>`;
})}
</div>
</div>
`;
let displayPivotsPending = null;
if(pivotColumnsUsed.length)
{
displayPivotsPending = html`
<div class="Section">
<div class="Heading">Pending Pivot</div>
<div class="Group">
${pivotColumnsUsed.map(columnPivot=>html`
<button onClick=${e=>{N.Disconnect(Pivot.Proto, columnPivot, "used-pivot");Render();}}>
${columnPivot.Meta.Label}
</button>
`)}
</div>
<button onClick=${e=>{
N.Disconnect(Pivot.Proto, null, "used-pivot");
N.Disconnect(Pivot.Proto, null, "used-sum");
Pivot.Create(indiciesPivot, indiciesSum);
Render();
}}>Create</button>
</div>
`;
}
return html`
<div class=${styles}>
<div class="Title">Create New Pivot</div>
${displayPivotsAll}
${displayPivotsPending}
</div>
`;
}
let Section = props =>
{
let styles = css`
.Heading
{
padding:6px 0 6px 0;
color:#666;
font-weight:900;
font-size:12px;
text-transform:uppercase;
cursor:pointer;
span
{
display:inline-block;
width:20px;
height:20px;
margin-right:10px;
border-radius:20px;
background:black;
color:white;
text-align:center;
}
}
.Heading:hover
{
color:black;
}
.Body
{
position:relative;
padding:10px 0 20px 30px;
&::before
{
content: " ";
display:block;
position:absolute;
top:-8px;
left:8px;
width:3px;
height:100%;
background:black;
}
}
`;
let [openGet, openSet] = useState(false);
return html`
<div class=${styles}>
<div class="Heading" onClick=${e=>openSet(!openGet)}>
<span>${openGet ? `` : `+`}</span>
${props.label}
</div>
${ openGet ? html`<div class="Body">${props.children}</div>` : null }
</div>
`;
}
let ModificationsIcon = ({node}) =>
{
let modsUp = N.Step(node, "ModifyUp", false)||[];
let modsDown = N.Step(node, "ModifyDown", false)||[];
let modsAt = N.Step(node, "ModifyAt", false)||[];
let modsOut = N.Step(node, "ModifyOut", false)||[];
let padding = 7;
let icon = 0;
let styles = css`
position:relative;
display:inline-block;
vertical-align:middle;
width:${padding*2 + icon}px;
height:${padding*2 + icon}px;
margin:${padding};
.Icon
{
position:absolute;
display:inline-block;
width:${padding*2 + icon}px;
height:${padding*2 + icon}px;
text-align:center;
font-size:9px;
font-family:sans-serif;
font-weight:900;
line-height:${padding*2 + icon}px;
&::after
{
content:" ";
display:block;
position:absolute;
width:${icon}px;
height:${icon}px;
border:${padding}px solid transparent;
}
&.Down
{
left:0;
bottom:100%;
&::after
{
top:100%;
border-top-color:green;
border-bottom:0px solid transparent;
}
}
&.At
{
top:0;
left:100%;
&::after
{
top:0;
right:100%;
border-right-color:red;
border-left:0px solid transparent;
}
}
&.Up
{
left:0;
top:100%;
&::after
{
bottom:100%;
border-bottom-color:orange;
border-top:0px solid transparent;
}
}
&.Out
{
top:0;
right:100%;
&::after
{
top:0;
left:100%;
border-left-color:grey;
border-right:0px solid transparent;
}
}
}
`;
return html`
<div class=${styles}>
${modsDown.length ? html`<div class="Icon Down">${modsDown.length}</div>` : null}
${modsAt.length ? html`<span class="Icon At">${modsAt.length}</span>` : null}
${modsUp.length ? html`<span class="Icon Up">${modsUp.length}</span>` : null}
${modsOut.length ? html`<span class="Icon Out">${modsOut.length}</span>` : null}
</div>
`;
};
let PivotBranch = props =>
{
let row = props.node.Meta.Row;
let displayCells = row.map(column=>h("td", null, column));
let displayCellsModify = row.map(column=>false);
props.node.Meta.IndexSum.forEach(i=>
{
displayCellsModify[i] = html`<td><input type="number" value=${row[i]}/></td>`;
});
displayCellsModify.forEach((cell, i)=>
{
if(!cell)
{
displayCellsModify[i] = html`<td>${row[i]}</td>`
}
});
let modifier = N.Step(props.node, "ModifyAt", false);
let modifierDisplay = false;
if(modifier)
{
modifierDisplay = html`<button onClick=${e=>{Pivot.Unmodify(modifier[0]); Render();}}>-</button>`;
}
else
{
modifierDisplay = html`<button onClick=${e=>{Pivot.Modify(props.node); Render();}}>+</button>`;
}
return html`
<tbody>
<tr>
<td>
<${ModificationsIcon} node=${props.node}><//>
<strong class=${css`margin-left:${props.node.Meta.Depth*10}px;`}>${props.node.Meta.Label}</strong>
${modifierDisplay}
</td>
${displayCells}
</tr>
</tbody>
`;
};
let PivotRoot = ({pivot}) =>
{
let stylesRoot = css`
display:block;
box-sizing:border-box;
padding:15px;
font-family:sans-serif;
`;
let stylesHeading = css`
margin: 0 0 15px 0;
font-weight:0;
font-size:24px;
`;
let modifiers = N.Step(pivot, "ModifyUp", false) || [];
let handleDelete = ()=>
{
Pivot.Delete(pivot);
Render();
};
let rows = [];
N.ID.Walk++;
N.Walk(n=>rows.push(h(PivotBranch, {node:n}, null)), pivot, "Hierarchy");
return html`
<div class=${stylesRoot}>
<div key="heading" class=${stylesHeading}>${pivot.Meta.Label}</div>
<${Section} key="settings" label=${`Settings`}>
<button onClick=${handleDelete}>Destroy Pivot</button>
<//>
<${Section} key="tree" label=${"Tree"}>
<table>
${rows}
</table>
<//>
</div>
`;
};
let ElRoot = props =>
{
let pivots = N.Step(Pivot.Root, "Pivot")||[];
return h("div", null, [
h(PivotForm),
pivots.map(pivot=>h(PivotRoot, {key:pivot.Meta.Label, pivot}))
])
};
Render = () => render(h(ElRoot), document.querySelector("#app"));
Render();
</script>
<script>
Pivot.Create([1, 2], [3, 4]);
let pivot = N.Path([0], Pivot.Root, "Pivot");
let node = N.Path([0, 1], pivot, "Hierarchy");
Pivot.Modify(node);
Pivot.Create([2, 1], [3, 4]);
Render();
</script>
</body>
</html>