/** @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` } }); async function PickHandle() { handle = await showDirectoryPicker(); await FSHandle.setDirectoryHandle(handle); await LoadHandleFiles(); } async function LoadHandleFiles() { try { const module = await import("./fsx/data/room.js"+""); /** @type {Record} */ const read = module.default(); rooms.val = read; } catch(_e) { rooms.val = {}; } } /** @type {Van.State>} */ const rooms = van.state({}); let handle = await FSHandle.getDirectoryHandle(); await LoadHandleFiles(); /** @type {(path:string[], part:string, time:number, data:string)=>void} */ async function WRITE(path, part, time, data) { const fileHandle = await FSHandle.drilldown(handle, path, true); if(fileHandle) { const file = await fileHandle.getFile(); const text = await file.text(); let json = {}; if(text) { json = JSON.parse(text); } let partProp = json[part]; if(!partProp) { partProp = []; json[part] = partProp; } partProp.push([time, data]); const writeable = await fileHandle.createWritable(); await writeable.write(JSON.stringify(json, null, 2)); await writeable.close(); } } /** @type {Van.State} */ const loggedIn = van.state(false); /** @type {(room_id:string, graphParts:TYPES.GraphParts)=>HTMLElement} */ function Room(room_id, graphParts) { const rerender = van.state(0); return Div.Plain( Div.Plain("Users:"), Div.PartGroup( Object.entries(graphParts.User).map(([user_id, user])=>{ return ()=>{ rerender.val; return Div.Part( DOM.div.Plain(user.name), ()=>{ return DOM.button.Plain( {async onclick(){ rerender.val++ loggedIn.val = user; }}, loggedIn.val == user ? "this is me" : "impersonate" ) }, ) } }) ), 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("Parts"), Div.PartGroup( Object.entries(graphParts.Part).map(([part_id, part])=>{ return ()=>{ rerender.val; const work = [] 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(){ if(loggedIn.val) { data.make(loggedIn.val, "NEW"); rerender.val++ WRITE(["room", room_id, pass.id, loggedIn.val.id+".json"], part_id, new Date().getTime(), "NEW"); } }}, "Add work!") : null ) )) } return Div.Part( DOM.h3(part.name), ...work, ); } }), ), Div.Plain("Desks"), Div.PartGroup( Object.entries(graphParts.Desk).map(([desk_id, desk])=>{ return ()=>{ rerender.val; /** @type {(part:TYPES.Part, index:number, pass:TYPES.Pass, dirty:number[])=>HTMLElement|null} */ const Iterator = (part, index, pass, dirty)=>{ const partPass = part.pass.get(pass); if(partPass) { 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!" ), Div.Part( time, " ", latest?.[1] || "" ) ); } return null; } 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)) ) )) } return Div.Part( DOM.h3(desk.name), work ) } }), ), ) } function App() { return Div.Plain( DOM.button({onclick:PickHandle}, "Pick Directory"), Object.entries(rooms.val).map(([room_id, graphParts])=> Room(room_id, graphParts) ) ) } van.add(document.body, App);