Compare commits

..

1 Commits

Author SHA1 Message Date
b6c80af059 http api actually works 2025-11-01 09:58:06 -04:00
20 changed files with 281 additions and 689 deletions

465
app.js
View File

@ -1,8 +1,32 @@
/** @import * as TYPES from "./graph/types.ts" */
import * as FSHandle from "./store-directory-handle.js";
import Styles from "./styles.js";
const {DOM, Div, Tag} = Styles;
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)"
}
});
async function PickHandle()
{
@ -20,21 +44,11 @@ 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.", e)
console.log("the handle exists, but the request failed. the service work must not be ready yet.")
rooms.val = {};
}
}
@ -45,281 +59,45 @@ async function LoadHandleFiles()
}
}
/** @type {Van.State<Record<string, TYPES.GraphParts>>} */
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.Dig(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<TYPES.User|false>} */
const loggedIn = van.state(false);
const blocking = van.state(false);
const showDesks = van.state(true, "desks");
/** @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 row = [DOM.th(part.name)];
for(const [pass, data] of part.pass)
{
row.push(DOM.td.Part(data.work.map(w=>Div.Plain(w[1]) )))
}
rows.push(DOM.tr(row))
});
return DOM.table.GapVertical(rows);
}
//const deskRender = van.state(0);
/** @type {(part:TYPES.Part, pass:TYPES.Pass, closeHandler:()=>void)=>HTMLElement} */
function PartEditor(part, pass, closeHandler)
{
const partPass = part.pass?.get(pass);
const hist = van.state(false);
const edit = van.state(false);
const upper = ()=>{
if(partPass?.work.length)
{
return DOM.div(
DOM.button(
{
onclick()
{
hist.val=!hist.val;
}
}, ()=>(hist.val ? "hide" : "show")+" changes"
),
hist.val ? partPass.work.map(w=>{
const date = new Date(w[0]);
return DOM.div(`${date.getMonth()}/${date.getDate()}`, DOM.strong(w[1]), w[2].name);
}) : ""
);
}
else
{
return "";
}
}
const lower = ()=>
{
return DOM.div(
()=>{
return loggedIn.rawVal ? DOM.button(
{onclick(){edit.val = !edit.val;}},
()=>(edit.val ? "cancel" : "make") + " changes"
) : DOM.p("log in to make changes")
},
()=>{
const textarea = DOM.textarea()
return edit.val ? DOM.div(
textarea,
DOM.button({
onclick(){
if(loggedIn.rawVal && partPass)
{
blocking.val = true;
partPass.make(loggedIn.rawVal, textarea.value).then(()=>{
blocking.val = false;
//deskRender.val++;
})
}
else
{
return false;
}
}
}, "save changes")
) : ""
}
)
}
const self = DOM.div(
upper,
()=>DOM.button({onclick(e){e.stopPropagation(); closeHandler(this.parentElement)}}, "close"),
DOM.div(
()=>{
if(partPass)
{
return partPass.work.find((w)=>w[0] == partPass.time)?.[1] || ""
}
return "(no data yet)";
}
),
lower,
);
return self;
}
/** @type {(inDesks:Record<string, TYPES.Desk>)=>HTMLElement} */
function Desks(inDesks)
{
return Div.PartGroup(
Object.entries(inDesks).map(([desk_id, desk])=>{
//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))
{
userInRole = true;
}
}
if(!userInRole)
{
return null;
}
}
const work = [];
for(const [pass, scan] of desk.pass)
{
// at least one but not all need fields are empty
const caution = scan.need_empty.length>0 && scan.need_empty.length<desk.need.length;
work.push(DOM.tr(
DOM.td(pass.name),
desk.need.map((part, index, array)=>
{
const partPass = part.pass.get(pass);
if(!partPass){ return null }
const latest = partPass.work.find(t=>t[0] == partPass.time)?.[1];
const attributes = {};
if(latest)
{
attributes.class = Tag("PartGood")
}
else
{
attributes.class = Tag("PartEmpty")
}
if(scan.need_dirty.includes(index))
{
attributes.class = Tag("PartDirty")
}
return DOM.td(
Div.Part(
attributes,
latest
)
);
}),
DOM.td(
Div.Icon("⇉"),
scan.due_date ? Div.Part(
scan.due_date.toLocaleDateString(),
scan.due_date.toLocaleTimeString()
) : " "
),
desk.make.map((part, index, array)=>
{
const partPass = part.pass.get(pass);
if(!partPass){ return null }
const latest = partPass.work.find(t=>t[0] == partPass.time)?.[1];
const attr = "data-editing"
function close(editor){
editor.remove();
this.setAttribute(attr, "false");
}
const attributes = {
onclick(){
const check = this.getAttribute(attr);
if(check !== "true")
{
this.setAttribute(attr, "true");
this.appendChild(PartEditor(part, pass, close.bind(this)));
}
}
};
if(latest)
{
attributes.class = Tag("PartGood")
}
else
{
attributes.class = Tag("PartEmpty")
}
if( (desk.need.length==0 && !latest) || scan.make_dirty.includes(index))
{
if(!latest && caution)
{
attributes.class = Tag("PartCaution")
}
else
{
attributes.class = Tag("PartDirty");
}
}
return DOM.td(
Div.Part(
attributes,
latest
)
);
}),
))
}
return Div.DeskContainer(
DOM.h3(desk.name),
DOM.table.GapHorizontal(
DOM.thead(
DOM.tr(
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} */
function Room(room_id, graphParts)
{
@ -331,6 +109,10 @@ function Room(room_id, graphParts)
Div.Plain("Users:"),
Div.PartGroup(
Object.entries(graphParts.User).map(([user_id, user])=>{
return ()=>{
//rerender.val;
return Div.Part(
DOM.div.Plain(user.name),
()=>{
@ -342,21 +124,132 @@ function Room(room_id, graphParts)
)
},
)
}
})
),
()=>{
return DOM.button({onclick(){
showDesks.val = !showDesks.val;
}}, showDesks.val ? "Show Parts" : "Show Desks")
},
Div.Plain("Passes:"),
Div.PartGroup(
Object.entries(graphParts.Pass).map(([pass_id, pass])=>{
return ()=>{
console.log("rerendering...", rerender.rawVal);
()=>{
rerender.val;
return showDesks.val ? Desks(graphParts.Desk) : Parts(graphParts.Part, graphParts.Pass);
},
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)
{
blocking.val = true;
data.make(loggedIn.val, "NEW").then(()=>{
blocking.val = false;
rerender.val++;
});
}
}}, "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
)
}
}),
),
()=>{
return blocking.val ? Div.BlockScreen() : null

View File

@ -1,43 +0,0 @@
//@ts-check
import CreateAllRooms, {Room} from "../../graph/graph.js";
const user = {
u1:"Seth T",
u4:"Sarah S",
u5:"Adam M",
u6:"Matt Y",
u7:"Seth F",
u8:"Brittany F"
};
export default CreateAllRooms({
room_01:Room({
user,
role:{
dev:["Development", "u1"],
write:["Writing", "u5"],
admin:["Admin", "u4"]
},
part:{
p1:["Page title"],
p2:["Page slug"],
p3:["Page preview"],
p4:["Page Project"],
p5:["Page Corrections", "loop"],
},
desk:{
d1:["Write page metas", ["admin", "write"], { }, "p1", "p2"],
d2:["Build Page preview", ["admin", "dev" ], {p1:1, p2:1, p5:4}, "p3", "p4"],
d3:["Proof Page", ["admin", "write"], {p3:1, }, "p5" ]
},
pass:{
pass_01:["January"],
//pass_02:["February"],
//pass_03:["March"],
//pass_04:["April"],
//pass_05:["May"],
//pass_06:["June"],
//pass_07:["July"],
}
})
});

View File

@ -1,7 +1,4 @@
/** @import * as TYPES from "./types.ts" */
import * as FSAccess from "../store-directory-handle.js";
export const noop = "no-op";
/** @type {TYPES.GraphBuilder} */
export function Room({user, role, part, desk, pass})
@ -34,9 +31,8 @@ export function Room({user, role, part, desk, pass})
const PartList = part;
for(let partId in part)
{
const [name, loop] = part[partId];
PartList[partId] = /** @type {TYPES.Part} */({name, id:partId, need:[], make:[], pass:new Map(), loop:loop});
const name = part[partId];
PartList[partId] = /** @type {TYPES.Part} */({name, id:partId, need:[], make:[], pass:new Map()});
}
// mutate desks
@ -45,7 +41,7 @@ export function Room({user, role, part, desk, pass})
const DeskList = desk;
for(let deskId in desk)
{
const [name, roleIDs, needObj, ...makePartIDs] = desk[deskId];
const [name, roleIDs, mode, needObj, ...makePartIDs] = desk[deskId];
/** @type {TYPES.Part[]}*/ const need =[];
/** @type {number[]}*/ const time =[];
@ -53,6 +49,7 @@ export function Room({user, role, part, desk, pass})
const deskObj = {
name,
id:deskId,
mode,
need,
time,
make:[],
@ -105,21 +102,12 @@ export function Room({user, role, part, desk, pass})
{
this.time = Date.now();
const handle = await FSAccess.getDirectoryHandle();
const path = ["store", context.Path, passID, user.id+".json"];
let text = await FSAccess.Read(handle, path) || "{}";
/** @type {TYPES.UserPassFile} */
const json = JSON.parse(text);
const body = JSON.stringify({
[partObj.id]:[this.time, data]
})
let field = json[partObj.id];
if(!field)
{
field = [];
json[partObj.id] = field;
}
field.push([this.time, data]);
text = JSON.stringify(json, null, 2);
await FSAccess.Write(handle, path, text);
const http = await fetch(`./store/${context.Path}/${passID}/${user.id}.json`, {method:"PUT", body});
console.log(http);
this.work.push(/** @type {TYPES.Work}*/([this.time, data, user]));
partObj.make.forEach((arg)=>{Scan(arg, passObj)});
@ -139,10 +127,9 @@ export function Room({user, role, part, desk, pass})
const [userID, userObject] = userData[i];
try
{
const handle = await FSAccess.getDirectoryHandle();
const text = await FSAccess.Read(handle, ["store", context.Path, passID, userID+".json"]);
const http = await fetch(`./store/${context.Path}/${passID}/${userID}.json`);
/** @type {TYPES.UserPassFile} */
const json = JSON.parse(text);
const json = await http.json();
Object.entries(json).forEach(([partID, payload])=>{
@ -162,7 +149,6 @@ export function Room({user, role, part, desk, pass})
{
passCheck.time = latest;
}
//payload.sort()
passCheck.work = /** @type {TYPES.Work[]}*/(payload);
}
@ -222,93 +208,39 @@ const Scan =(desk, pass)=>
const dirtyNeed = [];
const dirtyMake = [];
const emptyNeed = [];
const emptyMake = [];
let makeMin = Infinity;
let needMax = -Infinity;
// added for estimation
let estMin = Infinity;
let estMax = -Infinity;
let estSum = 0;
/*
Loop parts:
- always considered clean when the leading value is a no-op
- as a need, considered clean when empty
*/
/** @type {(part:TYPES.Part)=>[time:number, value:string|undefined, part:TYPES.Part]} */
const lookup =(part)=>
{
const partPass = part.pass.get(pass);
const partPassTime = partPass?.time || 0;
const partPassValue = partPass?.work.find(t=>t[0] == partPassTime)?.[1];
return [partPassTime, partPassValue, part];
}
// update needMax
for(let i=0; i<desk.need.length; i++)
{
const [time, value, part] = lookup(desk.need[i]);
if(part.loop)
{
if(!value || value == noop)
{
continue;
}
const part = desk.need[i];
const partPassTime = part.pass.get(pass)?.time || 0;
if(partPassTime > needMax) needMax = partPassTime;
}
if(time > needMax) needMax = time;
if(!time) emptyNeed.push(i);
}
// update makeMin AND dirtyMakes
// update makeMin AND dirty check makes
for(let i=0; i<desk.make.length; i++)
{
const [time] = lookup(desk.make[i]);
if(time < makeMin) makeMin = time;
if(time < needMax) dirtyMake.push(i);
if(!time) emptyMake.push(i)
const part = desk.make[i];
const partPassTime = part.pass.get(pass)?.time || 0;
if(partPassTime < makeMin) makeMin = partPassTime;
if(partPassTime < needMax)
{
dirtyMake.push(i);
}
}
// dirtyNeeds
// dirty check needs
for(let i=0; i<desk.need.length; i++)
{
const [time, value, part] = lookup(desk.need[i]);
if(part.loop)
{
if(!value || value == noop)
{
continue;
}
}
if(time > makeMin)
const part = desk.need[i];
const partPassTime = part.pass.get(pass)?.time || 0;
if(partPassTime > makeMin)
{
dirtyNeed.push(i);
// estimation
if(time < estMin) estMin = time;
const allottedTime = desk.time[i] * 1000 * 60 * 60;
const projectedTime = time + allottedTime;
estSum += allottedTime;
if(projectedTime > estMax) estMax = projectedTime;
}
}
estSum += estMin;
let stamp = estSum;
if(estMax > estSum)
{
stamp = estMax;
}
desk.pass.set(pass, {need_dirty:dirtyNeed, make_dirty:dirtyMake, need_empty:emptyNeed, make_empty:emptyMake, due_date:isFinite(stamp) ? new Date(stamp) : undefined})
desk.pass.set(pass, {need:dirtyNeed, make:dirtyMake})
};

View File

@ -1,17 +1,17 @@
export type User = {name:string, id:string, desk:Set<Desk>};
export type Role = {name:string, id:string, user:User[]};
export type Desk = {name:string, id:string, need:Part[], time:number[], make:Part[], pass:Map<Pass, Scan>, role:Role[]};
export type Desk = {name:string, id:string, need:Part[], time:number[], make:Part[], pass:Map<Pass, Flag>, mode:string, role:Role[]};
export type Pass = {name:string, id:string, path:string, live:boolean, load:()=>Promise<void>, dump:()=>void};
export type Part = {name:string, id:string, pass:Map<Pass, {time:number, work:Work[], make:(user:User, data:string)=>Promise<void>}>, need:Desk[], make:Desk[], loop?:boolean};
export type Part = {name:string, id:string, pass:Map<Pass, {time:number, work:Work[], make:(user:User, data:string)=>Promise<void>}>, need:Desk[], make:Desk[]};
export type Work = [time:number, data:string, user:User];
export type Scan = {need_dirty:number[], make_dirty:number[], need_empty:number[], make_empty:number[], due_date?:Date}
export type Flag = {need:number[], make:number[]}
export type GraphBuilder=
<
Users extends Record<string, string>,
Roles extends Record<string, [ name:string, ...users:Array<keyof Users>]>,
Parts extends Record<string, [ name:string, loop?:"loop"] >,
Desks extends Record<string, [ name:string, roles:Array<keyof Roles>, need:Partial<Record<keyof Parts, number>>, ...make:Array<keyof Parts>]>,
Parts extends Record<string, string>,
Desks extends Record<string, [ name:string, roles:Array<keyof Roles>, mode:"all"|"one", need:Partial<Record<keyof Parts, number>>, ...make:Array<keyof Parts>]>,
>
(
params:{

View File

@ -3,46 +3,6 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
/* Basic CSS Reset */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
height: 100%;
font-family: sans-serif;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
img, picture, video, canvas, svg {
display: block;
max-width: 100%;
}
input, button, textarea, select {
font: inherit;
}
a {
text-decoration: none;
color: inherit;
}
ul, ol {
list-style: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
</style>
</head>
<body>
<script>

View File

@ -1,43 +1,25 @@
//@ts-check
import CreateAllRooms, {Room} from "../../graph/graph.js";
import Rooms, {Room} from "../../graph/graph.js";
import User from "./user.js";
const user = {
u1:"Seth T",
u4:"Sarah S",
u5:"Adam M",
u6:"Matt Y",
u7:"Seth F",
u8:"Brittany F"
};
export default CreateAllRooms({
export default Rooms({
room_01:Room({
user,
user:User,
role:{
dev:["Development", "u1"],
write:["Writing", "u5"],
admin:["Admin", "u4"]
dev:["Development", "u1"]
},
part:{
p1:["Page title"],
p2:["Page slug"],
p3:["Page preview"],
p4:["Page Project"],
p5:["Page Corrections", "loop"],
p1:"Page title",
p2:"Page slug",
p3:"Page preview",
},
desk:{
d1:["Write page metas", ["admin", "write"], { }, "p1", "p2"],
d2:["Build Page preview", ["admin", "dev" ], {p1:1, p2:1, p5:1}, "p3", "p4"],
d3:["Proof Page", ["admin", "write"], {p3:1, }, "p5" ]
d1:["Write page metas", ["dev"], "all", {}, "p1", "p2"],
d2:["Build Page preview", ["dev"], "all", {p1:1, p2:1}, "p3"]
},
pass:{
pass_01:["January"],
//pass_02:["February"],
//pass_03:["March"],
//pass_04:["April"],
//pass_05:["May"],
//pass_06:["June"],
//pass_07:["July"],
pass_02:["February"]
}
})
});

View File

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

View File

@ -0,0 +1,9 @@
{
"p1":
[
[123, "data"],
[456, "more data"],
[789, "even more data"],
[101112, "even more data"]
]
}

View File

@ -0,0 +1,8 @@
{
"p2":
[
[123, "data"],
[456, "more data"],
[789, "even more data"]
]
}

View File

@ -1,14 +0,0 @@
{
"p1": [
[
1762196165935,
"normal title"
]
],
"p2": [
[
1762196173135,
"normal slug"
]
]
}

View File

@ -1,8 +0,0 @@
{
"p4": [
[
1762193485093,
"Make made Late"
]
]
}

View File

@ -1,8 +0,0 @@
{
"p1": [
[
1762186057868,
"Need made Early"
]
]
}

View File

@ -1,14 +0,0 @@
{
"p4": [
[
1762196034794,
"Make made Early"
]
],
"p1": [
[
1762196047017,
"Need made Late"
]
]
}

View File

@ -1,14 +0,0 @@
{
"p3": [
[
1762196236384,
"complete 3"
]
],
"p4": [
[
1762196245327,
"complete 4"
]
]
}

View File

@ -1,14 +0,0 @@
{
"p1": [
[
1762196209704,
"complete 1"
]
],
"p2": [
[
1762196217319,
"complete 2"
]
]
}

View File

@ -1,18 +0,0 @@
{
"p3": [
[
1762196341950,
"complete 3"
]
],
"p4": [
[
1762196348950,
"complete 4"
],
[
1762196393702,
"complete Later"
]
]
}

View File

@ -1,18 +0,0 @@
{
"p1": [
[
1762196328127,
"complete 1"
]
],
"p2": [
[
1762196335342,
"complete 2"
],
[
1762196363079,
"complete Late"
]
]
}

View File

@ -1,8 +0,0 @@
{
"p1": [
[
1762201681431,
"underway"
]
]
}

View File

@ -21,21 +21,47 @@ async function Interceptor(event)
const pathname = url.pathname.substring(1);
let parts = pathname.split("/");
if(parts[0] == "graph")
if(parts[0] == "graph" || parts[0] == "store")
{
console.log("intercept:", pathname);
const handle = await FSAccess.getDirectoryHandle();
if(event.request.method == "PUT")
{
console.log("put operation");
const payloadJSON = await event.request.clone().json();
let text = await FSAccess.Read(handle, parts) || "{}";
const fileJSON = JSON.parse(text);
for(const key in payloadJSON)
{
const value = payloadJSON[key];
let field = fileJSON[key];
if(!field)
{
field = [];
fileJSON[key] = field;
}
field.push(value);
}
console.log(`incoming:`, payloadJSON);
console.log(`outgoing:`, fileJSON);
text = JSON.stringify(fileJSON, null, 2);
const result = await FSAccess.Write(handle, parts, text);
return new Response(result+"", options);
}
const text = await FSAccess.Read(handle, parts);
if(text)
{
console.log("successful intercept:", pathname);
return new Response(text, options);
}
else
{
console.log("failed intercept:", pathname);
}
}

View File

@ -1,64 +0,0 @@
export default Gale({
Title:{
padding:"2rem",
background: "blue",
color:"white"
},
Plain:{},
PartGroup:{
display: `flex`,
flexWrap: `wrap`
},
Icon:{
background:"black",
color:"white",
borderRadius:"2rem",
fontWeight:"bolder",
padding:"0 0.8rem",
margin:"0 1rem"
},
Part:{
border: `1px solid black`,
borderRadius: `5px`,
padding: `0.5rem 1rem`,
minHeight: "2rem",
},
PartGood:{
background:"#009b2e",
color:"white",
},
PartEmpty:{
background:"#ddd"
},
PartDirty:{
background:"red",
color:"white",
fontWeight:"bold"
},
PartCaution:{
background:"yellow",
color:"black",
},
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`
},
GapHorizontal:{
borderCollapse:"separate",
borderSpacing:"0.3rem 2rem",
},
GapVertical:{
borderCollapse:"separate",
borderSpacing:"2rem 0.2rem",
}
});