Compare commits

...

2 Commits

Author SHA1 Message Date
f47ab32d68 input controls 2025-11-02 13:47:12 -05:00
396ad5b3c9 table layout started 2025-11-01 15:55:24 -04:00
4 changed files with 219 additions and 149 deletions

246
app.js
View File

@ -1,32 +1,8 @@
/** @import * as TYPES from "./graph/types.ts" */
import * as FSHandle from "./store-directory-handle.js";
const {Div, DOM} = Gale({
Title:{
padding:"2rem",
background: "blue",
color:"white"
},
Plain:{},
PartGroup:{
display: `flex`,
flexWrap: `wrap`
},
Part:{
border: `1px solid black`,
borderRadius: `5px`,
padding: `1rem`
},
BlockScreen:{
position: "fixed",
zIndex: "9999",
top: "0",
left: "0",
width: "100%",
height: "100%",
background: "rgba(128, 128, 128, 0.5)"
}
});
import Styles from "./styles.js";
const {DOM, Div, Tag} = Styles;
async function PickHandle()
{
@ -44,11 +20,21 @@ async function LoadHandleFiles()
const module = await import("./graph/room.js"+"?bust="+Math.random());
/** @type {Record<string, TYPES.GraphParts>} */
const read = module.default();
for(const roomKey in read)
{
const room = read[roomKey]
for(const pass in room.Pass)
{
await room.Pass[pass].load();
}
}
rooms.val = read;
}
catch(_e)
catch(e)
{
console.log("the handle exists, but the request failed. the service work must not be ready yet.")
console.log("the handle exists, but the request failed. the service work must not be ready yet.", e)
rooms.val = {};
}
}
@ -71,73 +57,87 @@ const loggedIn = van.state(false);
const blocking = van.state(false);
const showDesks = van.state(true);
const showDesks = van.state(true, "desks");
/** @type {(inParts:Record<string, TYPES.Part>)=>HTMLElement} */
function Parts(inParts)
function Input(handler=(str)=>{})
{
return Div.Plain(
Div.Plain("Parts"),
Div.PartGroup(
const input = DOM.textarea({style:"vertical-align:text-top; width:500px; height:200px;"});
let submitButton = Div.Plain(DOM.button({onclick(){
handler(input.value);
input.value = "";
mountPoint.remove();
}}, "submit value"));
let cancelButton = DOM.button({onclick(){
input.value = "";
mountPoint.remove();
}}, "cancel")
const mountPoint = Div.Plain({onclick(e){e.stopPropagation();}}, input, cancelButton, submitButton);
return mountPoint;
}
/** @type {(inParts:Record<string, TYPES.Part>, inPasses:Record<string, TYPES.Pass>)=>HTMLElement} */
function Parts(inParts, inPasses)
{
const rows = [];
const row = [DOM.th()]
for(const pass in inPasses)
{
row.push(DOM.th(inPasses[pass].name));
}
rows.push(DOM.thead(row));
Object.entries(inParts).map(([part_id, part])=>{
const work = []
const row = [DOM.th(part.name)];
for(const [pass, data] of part.pass)
{
work.push(Div.Part(
DOM.h5(pass.name),
DOM.p(data.time),
data.work.map(([time, data, user])=>Div.Plain(
DOM.span(time),
" ",
DOM.strong(data),
)),
Div.Plain(
loggedIn.val ? DOM.button({onclick(){
blocking.val = true;
loggedIn.val && data.make(loggedIn.val, "NEW").then(()=>{
blocking.val = false;
});
}}, "Add work!")
: null
)
))
row.push(DOM.td.Part(data.work.map(w=>Div.Plain(w[1]) )))
}
rows.push(DOM.tr(row))
});
return Div.Part(
DOM.h3(part.name),
...work,
);
}),
)
)
return DOM.table.GapVertical(rows);
}
const deskRender = van.state(0);
/** @type {(inDesks:Record<string, TYPES.Desk>)=>HTMLElement} */
function Desks(inDesks)
{
return Div.Plain(
Div.Plain("Desks"),
Div.PartGroup(
return Div.PartGroup(
Object.entries(inDesks).map(([desk_id, desk])=>{
loggedIn.val;
if(loggedIn.val)
deskRender.val;
console.log("reredering desk", desk.name);
if (loggedIn.val)
{
let userInRole = false;
for(const role of desk.role)
{
if(!role.user.includes(loggedIn.val))
if(role.user.includes(loggedIn.val))
{
userInRole = true;
}
}
if(!userInRole)
{
return null;
}
}
}
/** @type {(part:TYPES.Part, index:number, pass:TYPES.Pass, dirty:number[])=>HTMLElement|null} */
const Iterator = (part, index, pass, dirty)=>{
/** @type {(part:TYPES.Part, index:number, pass:TYPES.Pass, dirty:number[], type:"need"|"make")=>HTMLElement|null} */
const Iterator = (part, index, pass, dirty, type)=>{
const partPass = part.pass.get(pass);
if(partPass)
@ -145,11 +145,35 @@ function Desks(inDesks)
const time = partPass.time;
const latest = partPass.work.find(t=>t[0] == time);
return Div.Plain(
part.name,
DOM.p( dirty.includes(index) ? "Dirty" : "Good!" ),
const attributes = {
class: dirty.includes(index) ? Tag("DeskDirty") : "",
};
if(type == "make")
{
attributes.onclick=function(){
loggedIn.rawVal && van.add(this, Input((str)=>{
if(loggedIn.rawVal)
{
blocking.val = true;
partPass.make(loggedIn.rawVal, str).then(()=>{
deskRender.val++;
blocking.val = false;
})
}
else
{
return false;
}
}));
}
}
return DOM.td(
Div.Part(
time, " ", latest?.[1] || ""
attributes,
latest?.[1] || ""
)
);
}
@ -159,29 +183,30 @@ function Desks(inDesks)
const work = [];
for(const [pass, dirty] of desk.pass)
{
work.push(Div.Part(
DOM.h5(pass.name),
Div.Part(
DOM.h4("Need:"),
desk.need.map((part, index)=>Iterator(part, index, pass, dirty.need))
),
Div.Part(
DOM.h4("Make:"),
desk.make.map((part, index)=>Iterator(part, index, pass, dirty.make))
)
work.push(DOM.tr(
DOM.td(pass.name),
desk.need.map((part, index)=>Iterator(part, index, pass, dirty.need, "need")),
DOM.td("->"),
desk.make.map((part, index)=>Iterator(part, index, pass, dirty.make, "make"))
))
}
return Div.Part(
return Div.DeskContainer(
DOM.h3(desk.name),
DOM.table.GapHorizontal(
DOM.thead(
DOM.th(),
desk.need.map((part, index)=>DOM.th(part.name)),
DOM.th(),
desk.make.map((part, index)=>DOM.th(part.name))
),
work
)
)
}),
)
)
}
/** @type {(room_id:string, graphParts:TYPES.GraphParts)=>HTMLElement} */
@ -211,29 +236,30 @@ function Room(room_id, graphParts)
})
),
Div.Plain("Passes:"),
Div.PartGroup(
Object.entries(graphParts.Pass).map(([pass_id, pass])=>{
return ()=>{
console.log("rerendering...", rerender.rawVal);
rerender.val;
return Div.Part(
DOM.div.Plain(pass.name),
()=>{
return DOM.button.Plain(
{async onclick(){
await pass[pass.live ? "dump" : "load"]();
rerender.val++
}},
pass.live ? "Dump" : "Load"
)
},
)
}
})
),
// Div.Plain("Passes:"),
// Div.PartGroup(
// Object.entries(graphParts.Pass).map(([pass_id, pass])=>{
// return ()=>{
// console.log("rerendering...", rerender.rawVal);
//
// rerender.val;
//
// return Div.Part(
// DOM.div.Plain(pass.name),
// ()=>{
// return DOM.button.Plain(
// {async onclick(){
// await pass[pass.live ? "dump" : "load"]();
// rerender.val++
// }},
// pass.live ? "Dump" : "Load"
// )
// },
// )
// }
// })
// ),
()=>{
return DOM.button({onclick(){
@ -243,7 +269,7 @@ function Room(room_id, graphParts)
()=>{
rerender.val;
return showDesks.val ? Desks(graphParts.Desk) : Parts(graphParts.Part);
return showDesks.val ? Desks(graphParts.Desk) : Parts(graphParts.Part, graphParts.Pass);
},

View File

@ -1,13 +1,19 @@
//@ts-check
import Rooms, {Room} from "../../graph/graph.js";
import User from "./user.js";
import CreateAllRooms, {Room} from "../../graph/graph.js";
export default Rooms({
const user = {
u1:"Seth Trowbridge",
u4:"Sarah Sharp",
u5:"Adam Marshall",
}
export default CreateAllRooms({
room_01:Room({
user:User,
user,
role:{
dev:["Development", "u1"],
write:["Writing", "u2", "u3"],
write:["Writing", "u5"],
admin:["Admin", "u4"]
},
part:{
p1:"Page title",
@ -15,8 +21,8 @@ export default Rooms({
p3:"Page preview",
},
desk:{
d1:["Write page metas", ["write"], "all", {}, "p1", "p2"],
d2:["Build Page preview", ["dev"], "all", {p1:1, p2:1}, "p3"]
d1:["Write page metas", ["admin", "write"], "all", {}, "p1", "p2"],
d2:["Build Page preview", ["admin", "dev"], "all", {p1:1, p2:1}, "p3" ]
},
pass:{
pass_01:["January"],

View File

@ -1,5 +0,0 @@
export default {
u1:"seth",
u2:"seth2",
u3:"seth3"
}

43
styles.js Normal file
View File

@ -0,0 +1,43 @@
export default Gale({
Title:{
padding:"2rem",
background: "blue",
color:"white"
},
Plain:{},
PartGroup:{
display: `flex`,
flexWrap: `wrap`
},
Part:{
border: `1px solid black`,
borderRadius: `5px`,
padding: `1rem`
},
BlockScreen:{
position: "fixed",
zIndex: "9999",
top: "0",
left: "0",
width: "100%",
height: "100%",
background: "rgba(128, 128, 128, 0.5)"
},
DeskContainer:{
border: `1px solid black`,
borderRadius: `5px`,
padding: `1rem`
},
DeskDirty:{
background:"tomato",
color:"white"
},
GapHorizontal:{
borderCollapse:"separate",
borderSpacing:"0 2rem"
},
GapVertical:{
borderCollapse:"separate",
borderSpacing:"2rem 0.2rem"
}
});