switching networks works, established server functions
This commit is contained in:
4
db/personal/1/db.json
Normal file
4
db/personal/1/db.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"nodes": {},
|
||||||
|
"edges": {}
|
||||||
|
}
|
||||||
31
notes.js
31
notes.js
@@ -7,15 +7,36 @@ img(`db/images/${networks[i].logo}`, "2.25em", "2.25em")
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.cursor("default")
|
.cursor("default")
|
||||||
.DEFAULT()
|
.Default()
|
||||||
.opacity(0)
|
.opacity(0)
|
||||||
.borderLeft(0)
|
.borderLeft(0)
|
||||||
.paddingLeft(10, px)
|
.paddingLeft(10, px)
|
||||||
.HOVERED()
|
.Hovered()
|
||||||
.opacity(0.8)
|
.opacity(0.8)
|
||||||
.classStyle("selected")
|
.Watch(global.currentNetwork)
|
||||||
.borderLeft("1px solid var(--accent)")
|
.If((val) => val === this.getAttribute("network"))
|
||||||
.paddingLeft(9, px)
|
.borderLeft("1px solid black")
|
||||||
|
.paddingLeft(9, px)
|
||||||
|
.ElseIf((val) => val !== this.getAttribute("network"))
|
||||||
|
.borderLeft("0")
|
||||||
|
.paddingLeft(10, px)
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
ZStack(() => {
|
||||||
|
Watch(global.currentNetwork)
|
||||||
|
.Case("Dashboard", () => {
|
||||||
|
Dashboard()
|
||||||
|
})
|
||||||
|
.Case("People", () => {
|
||||||
|
People()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.overflow("scroll")
|
||||||
|
.position("absolute")
|
||||||
|
.onEvent("resize", () => {
|
||||||
|
this.rerender()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export default class AuthHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getProfile(req, res) {
|
getProfile(req, res) {
|
||||||
const token = req.cookies.auth_token;
|
const token = req.cookies?.auth_token;
|
||||||
if (!token) return res.status(401).send({ error: "No auth token" });
|
if (!token) return res.status(401).send({ error: "No auth token" });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -42,7 +42,13 @@ export default class AuthHandler {
|
|||||||
return db.networks.get(c.to)
|
return db.networks.get(c.to)
|
||||||
})
|
})
|
||||||
|
|
||||||
res.send({ email: user.email, name: user.firstName + " " + user.lastName, networks: userOrgs});
|
res.send({
|
||||||
|
id: user.id,
|
||||||
|
email: user.email,
|
||||||
|
name: user.firstName + " " + user.lastName,
|
||||||
|
networks: userOrgs,
|
||||||
|
apps: user.apps
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error getting profile: ", e)
|
console.error("Error getting profile: ", e)
|
||||||
res.status(401).send({ error: "Invalid token" });
|
res.status(401).send({ error: "Invalid token" });
|
||||||
|
|||||||
@@ -3,9 +3,13 @@ import chalk from 'chalk';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {nodeModels, edgeModels} from './model/import.js'
|
import {nodeModels, edgeModels} from './model/import.js'
|
||||||
import Edge from "./model/edge.js"
|
import Edge from "./model/edge.js"
|
||||||
|
import { fileURLToPath } from "url"
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||||
|
|
||||||
export default class Database {
|
export default class Database {
|
||||||
|
|
||||||
|
PERSONAL_DATA_PATH = path.join(__dirname, '../../db/personal')
|
||||||
|
|
||||||
nodes = new Array(10000).fill(0);
|
nodes = new Array(10000).fill(0);
|
||||||
edges = new Array(10000).fill(0);
|
edges = new Array(10000).fill(0);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
import argon2 from 'argon2';
|
import argon2 from 'argon2';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
@@ -15,6 +17,7 @@ export default class Member {
|
|||||||
firstName: z.string(),
|
firstName: z.string(),
|
||||||
lastName: z.string(),
|
lastName: z.string(),
|
||||||
password: z.string(),
|
password: z.string(),
|
||||||
|
apps: z.array(z.string()),
|
||||||
created: z.string()
|
created: z.string()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -48,6 +51,17 @@ export default class Member {
|
|||||||
return members
|
return members
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getPersonalData(id) {
|
||||||
|
const filePath = path.join(global.db.PERSONAL_DATA_PATH, id, "db.json");
|
||||||
|
|
||||||
|
const [raw] = await Promise.all([
|
||||||
|
fs.promises.readFile(filePath, "utf8"),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const result = raw.trim() ? JSON.parse(raw) : [];
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
getByID(id) {
|
getByID(id) {
|
||||||
if(typeof id === 'string') {
|
if(typeof id === 'string') {
|
||||||
id = id.split("-")[1]
|
id = id.split("-")[1]
|
||||||
|
|||||||
@@ -38,10 +38,25 @@ class Server {
|
|||||||
router.post('/free', this.newUserSubmission)
|
router.post('/free', this.newUserSubmission)
|
||||||
router.get('/db/images/*', this.getUserImage)
|
router.get('/db/images/*', this.getUserImage)
|
||||||
router.get('/app/orgdata/*', this.getOrgData)
|
router.get('/app/orgdata/*', this.getOrgData)
|
||||||
|
router.get('/app/mydata/*', this.getPersonalData)
|
||||||
router.get('/*', this.get)
|
router.get('/*', this.get)
|
||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPersonalData = async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const memberId = req.params[0]
|
||||||
|
|
||||||
|
let data = await global.db.members.getPersonalData(memberId)
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
data
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getOrgData = async (req, res, next) => {
|
getOrgData = async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const networkId = req.params[0]
|
const networkId = req.params[0]
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { WebSocket, WebSocketServer } from 'ws';
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
|
|
||||||
|
import * as serverFunctions from "../../ui/_/code/bridge/serverFunctions.js"
|
||||||
import ForumHandler from "./handlers/ForumHandler.js"
|
import ForumHandler from "./handlers/ForumHandler.js"
|
||||||
import MessagesHandler from "./handlers/MessagesHandler.js"
|
import MessagesHandler from "./handlers/MessagesHandler.js"
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ export default class Socket {
|
|||||||
wss;
|
wss;
|
||||||
messageSchema = z.object({
|
messageSchema = z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
app: z.string(),
|
app: z.string().optional(),
|
||||||
operation: z.string().optional(),
|
operation: z.string().optional(),
|
||||||
msg: z.union([
|
msg: z.union([
|
||||||
z.object({}).passthrough(), // allows any object
|
z.object({}).passthrough(), // allows any object
|
||||||
@@ -67,7 +68,7 @@ export default class Socket {
|
|||||||
const text = msg.toString();
|
const text = msg.toString();
|
||||||
const req = JSON.parse(text);
|
const req = JSON.parse(text);
|
||||||
if(!this.messageSchema.safeParse(req).success) throw new Error("Socket.handleMessage: Incoming ws message has incorrect format!")
|
if(!this.messageSchema.safeParse(req).success) throw new Error("Socket.handleMessage: Incoming ws message has incorrect format!")
|
||||||
|
|
||||||
let responseData;
|
let responseData;
|
||||||
switch (req.app) {
|
switch (req.app) {
|
||||||
case "FORUM":
|
case "FORUM":
|
||||||
@@ -79,7 +80,12 @@ export default class Socket {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
console.error("unknown ws message")
|
if(!req.app) {
|
||||||
|
let func = req.msg
|
||||||
|
responseData = serverFunctions[func.name](...args)
|
||||||
|
} else {
|
||||||
|
console.error("unknown ws message")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let response = {
|
let response = {
|
||||||
|
|||||||
38
ui/_/code/bridge/bridge.js
Normal file
38
ui/_/code/bridge/bridge.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
const IS_NODE =
|
||||||
|
typeof process !== "undefined" &&
|
||||||
|
process.versions?.node != null
|
||||||
|
|
||||||
|
async function bridgeSend(name, args) {
|
||||||
|
// Example browser implementation: send function call to server
|
||||||
|
const res = await global.Socket.send({
|
||||||
|
name: name,
|
||||||
|
args: args
|
||||||
|
})
|
||||||
|
|
||||||
|
const json = await res.json()
|
||||||
|
if (!res.ok) throw new Error(json.error)
|
||||||
|
return json.result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps an object of functions so that:
|
||||||
|
* - Node calls the real function
|
||||||
|
* - Browser calls bridgeSend
|
||||||
|
*/
|
||||||
|
export function createBridge(funcs) {
|
||||||
|
return new Proxy(funcs, {
|
||||||
|
get(target, prop) {
|
||||||
|
const orig = target[prop]
|
||||||
|
|
||||||
|
if (typeof orig !== "function") return orig
|
||||||
|
|
||||||
|
return function (...args) {
|
||||||
|
if (IS_NODE) {
|
||||||
|
return orig(...args)
|
||||||
|
} else {
|
||||||
|
return bridgeSend(prop, args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
11
ui/_/code/bridge/serverFunctions.js
Normal file
11
ui/_/code/bridge/serverFunctions.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import fs from "fs"
|
||||||
|
import { createBridge } from "./bridge.js"
|
||||||
|
|
||||||
|
const handlers = {
|
||||||
|
getProfile(one, two) {
|
||||||
|
fs.writeFileSync("output.txt", `${one} ${two}`)
|
||||||
|
return "written to disk"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const { getProfile } = createBridge(handlers)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Sam Russell
|
Sam Russell
|
||||||
Captured Sun
|
Captured Sun
|
||||||
|
1.16.26 - Moving nav event dispatch out of pushState, adding null feature to attr()
|
||||||
1.5.26 - Switching verticalAlign and horizontalAlign names, adding borderVertical and Horizontal
|
1.5.26 - Switching verticalAlign and horizontalAlign names, adding borderVertical and Horizontal
|
||||||
12.26.25 - State for arrays, nested objects. State for stacks (Shadow-only)
|
12.26.25 - State for arrays, nested objects. State for stacks (Shadow-only)
|
||||||
12.17.25 - [Hyperia] - adding width, height functions. adding "e" to onClick. adding the non-window $$ funcs.
|
12.17.25 - [Hyperia] - adding width, height functions. adding "e" to onClick. adding the non-window $$ funcs.
|
||||||
@@ -27,7 +28,6 @@ let oldPushState = history.pushState;
|
|||||||
history.pushState = function pushState() {
|
history.pushState = function pushState() {
|
||||||
let ret = oldPushState.apply(this, arguments);
|
let ret = oldPushState.apply(this, arguments);
|
||||||
window.dispatchEvent(new Event('pushstate'));
|
window.dispatchEvent(new Event('pushstate'));
|
||||||
window.dispatchEvent(new Event('navigate'));
|
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,8 +53,8 @@ window.setQuery = function(key, value) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
window.navigateTo = function(url) {
|
window.navigateTo = function(url) {
|
||||||
window.dispatchEvent(new Event('navigate'));
|
|
||||||
window.history.pushState({}, '', url);
|
window.history.pushState({}, '', url);
|
||||||
|
window.dispatchEvent(new Event('navigate'));
|
||||||
}
|
}
|
||||||
|
|
||||||
window.setLocation = function(url) {
|
window.setLocation = function(url) {
|
||||||
@@ -1197,7 +1197,11 @@ HTMLElement.prototype.attr = function(attributes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(attributes)) {
|
for (const [key, value] of Object.entries(attributes)) {
|
||||||
this.setAttribute(key, value);
|
if(value === null) {
|
||||||
|
this.removeAttribute(key)
|
||||||
|
} else {
|
||||||
|
this.setAttribute(key, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,62 +1,61 @@
|
|||||||
class Connection {
|
class Connection {
|
||||||
connectionTries = 0
|
connectionTries = 0;
|
||||||
ws;
|
ws;
|
||||||
linkCreated;
|
receiveCB;
|
||||||
wsStatus;
|
|
||||||
|
|
||||||
constructor(receiveCB) {
|
constructor(receiveCB) {
|
||||||
this.init()
|
this.receiveCB = receiveCB;
|
||||||
this.receiveCB = receiveCB
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init = async () => {
|
||||||
if(window.location.hostname.includes("local")) {
|
return new Promise((resolve, reject) => {
|
||||||
this.ws = new WebSocket("ws://" + window.location.host)
|
const url = window.location.hostname.includes("local")
|
||||||
} else {
|
? "ws://" + window.location.host
|
||||||
this.ws = new WebSocket("wss://" + window.location.hostname + window.location.pathname)
|
: "wss://" + window.location.hostname + window.location.pathname;
|
||||||
}
|
|
||||||
this.ws.addEventListener('open', () => {
|
this.ws = new WebSocket(url);
|
||||||
this.connectionTries = 0
|
|
||||||
console.log("Websocket connection established.");
|
this.ws.addEventListener('open', () => {
|
||||||
this.ws.addEventListener('message', this.receiveCB)
|
this.connectionTries = 0;
|
||||||
|
console.log("WebSocket connection established.");
|
||||||
|
this.ws.addEventListener('message', this.receiveCB);
|
||||||
|
resolve(this.ws); // resolve when open
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ws.addEventListener('close', () => {
|
||||||
|
console.log('WebSocket closed');
|
||||||
|
this.checkOpen(); // attempt reconnection
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ws.addEventListener('error', (err) => {
|
||||||
|
console.error('WebSocket error', err);
|
||||||
|
reject(err); // reject if error occurs
|
||||||
|
});
|
||||||
});
|
});
|
||||||
this.ws.addEventListener("close", () => {
|
|
||||||
this.checkOpen();
|
|
||||||
console.log('Websocket Closed')
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkOpen() {
|
checkOpen = async () => {
|
||||||
if (this.ws.readyState === WebSocket.OPEN) {
|
if (this.ws.readyState === WebSocket.OPEN) {
|
||||||
return true
|
return true;
|
||||||
} else {
|
} else {
|
||||||
await this.sleep(this.connectionTries < 20 ? 5000 : 60000)
|
await this.sleep(this.connectionTries < 20 ? 5000 : 60000);
|
||||||
this.connectionTries++
|
this.connectionTries++;
|
||||||
console.log('Reestablishing connection')
|
console.log('Reestablishing connection');
|
||||||
this.init()
|
await this.init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep = (time) => {
|
sleep = (time) => new Promise(resolve => setTimeout(resolve, time));
|
||||||
return new Promise(resolve => {
|
|
||||||
setTimeout(resolve, time);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
send = (msg) => {
|
send = (msg) => {
|
||||||
console.log("sending")
|
|
||||||
if (this.ws.readyState === WebSocket.OPEN) {
|
if (this.ws.readyState === WebSocket.OPEN) {
|
||||||
this.ws.send(msg);
|
this.ws.send(msg);
|
||||||
}
|
} else if (this.connectionTries === 0) {
|
||||||
else if(this.connectionTries === 0) {
|
setTimeout(() => this.send(msg), 100);
|
||||||
setTimeout(() => {
|
} else {
|
||||||
this.send(msg)
|
console.error('No WebSocket connection: Cannot send message');
|
||||||
}, 100)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.error('No websocket connection: Cannot send message');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Connection
|
export default Connection;
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ export default class Socket {
|
|||||||
this.connection = new Connection(this.receive);
|
this.connection = new Connection(this.receive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
await this.connection.init()
|
||||||
|
}
|
||||||
|
|
||||||
isOpen() {
|
isOpen() {
|
||||||
if(this.connection.checkOpen()) {
|
if(this.connection.checkOpen()) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
1
ui/_/code/ws/shim/fs.js
Normal file
1
ui/_/code/ws/shim/fs.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export default {}
|
||||||
@@ -20,6 +20,15 @@ class Dashboard extends Shadow {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
VStack(() => {
|
VStack(() => {
|
||||||
|
|
||||||
|
if(window.location.pathname.startsWith("/my")) {
|
||||||
|
h1(global.profile.name);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else if(!window.location.pathname.includes("comalyr")) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
h1("Website Inquiries");
|
h1("Website Inquiries");
|
||||||
|
|
||||||
p("Contact Us")
|
p("Contact Us")
|
||||||
@@ -41,7 +50,7 @@ class Dashboard extends Shadow {
|
|||||||
.maxWidth(95, pct)
|
.maxWidth(95, pct)
|
||||||
.gap(8);
|
.gap(8);
|
||||||
|
|
||||||
window.currentNetwork.data.contact.forEach((entry) => {
|
global.currentNetwork.data.contact.forEach((entry) => {
|
||||||
HStack(() => {
|
HStack(() => {
|
||||||
this.cell("time", entry.time);
|
this.cell("time", entry.time);
|
||||||
this.cell("fname", entry.fname);
|
this.cell("fname", entry.fname);
|
||||||
@@ -74,7 +83,7 @@ class Dashboard extends Shadow {
|
|||||||
.maxWidth(95, pct)
|
.maxWidth(95, pct)
|
||||||
.gap(8);
|
.gap(8);
|
||||||
|
|
||||||
window.currentNetwork.data.join.forEach((entry) => {
|
global.currentNetwork.data.join.forEach((entry) => {
|
||||||
HStack(() => {
|
HStack(() => {
|
||||||
this.cell("time", entry.time);
|
this.cell("time", entry.time);
|
||||||
this.cell("fname", entry.fname);
|
this.cell("fname", entry.fname);
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class Forum extends Shadow {
|
|||||||
.fontSize(1, em)
|
.fontSize(1, em)
|
||||||
.onKeyDown(function (e) {
|
.onKeyDown(function (e) {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
window.Socket.send({app: "FORUM", operation: "SEND", msg: {forum: "HY", text: this.value }})
|
global.Socket.send({app: "FORUM", operation: "SEND", msg: {forum: "HY", text: this.value }})
|
||||||
this.value = ""
|
this.value = ""
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class Messages extends Shadow {
|
|||||||
.fontSize(1, em)
|
.fontSize(1, em)
|
||||||
.onKeyDown((e) => {
|
.onKeyDown((e) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
window.Socket.send({app: "MESSAGES", operation: "SEND", msg: { conversation: `CONVERSATION-${this.selectedConvoID}`, text: e.target.value }})
|
global.Socket.send({app: "MESSAGES", operation: "SEND", msg: { conversation: `CONVERSATION-${this.selectedConvoID}`, text: e.target.value }})
|
||||||
e.target.value = ""
|
e.target.value = ""
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -104,7 +104,7 @@ class Messages extends Shadow {
|
|||||||
.color("var(--accent)")
|
.color("var(--accent)")
|
||||||
.onKeyDown(function (e) {
|
.onKeyDown(function (e) {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
window.Socket.send({app: "MESSAGES", operation: "ADDCONVERSATION", msg: {email: this.value }})
|
global.Socket.send({app: "MESSAGES", operation: "ADDCONVERSATION", msg: {email: this.value }})
|
||||||
this.value = ""
|
this.value = ""
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class MessagesPanel extends Shadow {
|
|||||||
if(this.messages) {
|
if(this.messages) {
|
||||||
for(let i=0; i<this.messages.length; i++) {
|
for(let i=0; i<this.messages.length; i++) {
|
||||||
let message = this.messages[i]
|
let message = this.messages[i]
|
||||||
let fromMe = window.profile.email === message.from.email
|
let fromMe = global.profile.email === message.from.email
|
||||||
VStack(() => {
|
VStack(() => {
|
||||||
HStack(() => {
|
HStack(() => {
|
||||||
p(message.from.firstName + " " + message.from.lastName)
|
p(message.from.firstName + " " + message.from.lastName)
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class MessagesSidebar extends Shadow {
|
|||||||
let membersString = ""
|
let membersString = ""
|
||||||
for(let i=0; i<members.length; i++) {
|
for(let i=0; i<members.length; i++) {
|
||||||
let member = members[i]
|
let member = members[i]
|
||||||
if(member.email === window.profile.email) {
|
if(member.email === global.profile.email) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(members.length > 2) {
|
if(members.length > 2) {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ class People extends Shadow {
|
|||||||
.fontWeight("bold")
|
.fontWeight("bold")
|
||||||
.marginBottom(2, em)
|
.marginBottom(2, em)
|
||||||
|
|
||||||
for(let i = 0; i < window.currentNetwork.data.members.length; i++) {
|
for(let i = 0; i < global.currentNetwork.data.members.length; i++) {
|
||||||
let member = window.currentNetwork.data.members[i]
|
let member = global.currentNetwork.data.members[i]
|
||||||
HStack(() => {
|
HStack(() => {
|
||||||
p(member.firstName + " " + member.lastName)
|
p(member.firstName + " " + member.lastName)
|
||||||
.width(10, pct)
|
.width(10, pct)
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ class AppMenu extends Shadow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HStack(() => {
|
HStack(() => {
|
||||||
let currentNetwork = window.currentNetwork
|
let currentNetwork = global.currentNetwork
|
||||||
if(!currentNetwork) return
|
if(!currentNetwork) return
|
||||||
let currentApp = window.currentApp
|
let currentApp = global.currentApp
|
||||||
|
|
||||||
for(let i = 0; i < currentNetwork.apps.length; i++) {
|
for(let i = 0; i < currentNetwork.apps.length; i++) {
|
||||||
let app = currentNetwork.apps[i]
|
let app = currentNetwork.apps[i]
|
||||||
@@ -27,7 +27,7 @@ class AppMenu extends Shadow {
|
|||||||
.paddingBottom(currentApp === app ? 4 : 5, px)
|
.paddingBottom(currentApp === app ? 4 : 5, px)
|
||||||
.borderBottom(currentApp === app ? "1px solid var(--accent)" : "")
|
.borderBottom(currentApp === app ? "1px solid var(--accent)" : "")
|
||||||
.onClick((done) => {
|
.onClick((done) => {
|
||||||
if(done) window.openApp(app)
|
if(done) global.openApp(app)
|
||||||
})
|
})
|
||||||
.onHover(function (hovering) {
|
.onHover(function (hovering) {
|
||||||
if(hovering) {
|
if(hovering) {
|
||||||
@@ -49,6 +49,10 @@ class AppMenu extends Shadow {
|
|||||||
// console.log("app hello?") // BUG: Quill is not acknowledging this event unless there is something else in the function body
|
// console.log("app hello?") // BUG: Quill is not acknowledging this event unless there is something else in the function body
|
||||||
this.rerender()
|
this.rerender()
|
||||||
})
|
})
|
||||||
|
.onEvent("networkchange", () => {
|
||||||
|
// console.log(global.currentApp)
|
||||||
|
this.rerender()
|
||||||
|
})
|
||||||
.position("fixed")
|
.position("fixed")
|
||||||
.x(0).yBottom(0)
|
.x(0).yBottom(0)
|
||||||
.width(100, vw)
|
.width(100, vw)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class AppWindow extends Shadow {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
ZStack(() => {
|
ZStack(() => {
|
||||||
switch(window.currentApp) {
|
switch(global.currentApp) {
|
||||||
case "Dashboard":
|
case "Dashboard":
|
||||||
Dashboard()
|
Dashboard()
|
||||||
break;
|
break;
|
||||||
@@ -33,17 +33,20 @@ class AppWindow extends Shadow {
|
|||||||
})
|
})
|
||||||
.overflow("scroll")
|
.overflow("scroll")
|
||||||
.position("absolute")
|
.position("absolute")
|
||||||
.onEvent("resize", () => {
|
|
||||||
this.rerender()
|
|
||||||
})
|
|
||||||
.width(window.innerWidth - this.calculateWidth(), px)
|
.width(window.innerWidth - this.calculateWidth(), px)
|
||||||
.height(window.innerHeight - this.calculateHeight(), px)
|
.height(window.innerHeight - this.calculateHeight(), px)
|
||||||
.background("var(--app)")
|
.background("var(--app)")
|
||||||
.x(this.calculateWidth(), px)
|
.x(this.calculateWidth(), px)
|
||||||
.yBottom(this.calculateHeight(), px)
|
.yBottom(this.calculateHeight(), px)
|
||||||
|
.onEvent("resize", () => {
|
||||||
|
this.rerender()
|
||||||
|
})
|
||||||
.onEvent("appchange", () => {
|
.onEvent("appchange", () => {
|
||||||
this.rerender()
|
this.rerender()
|
||||||
})
|
})
|
||||||
|
.onEvent("networkchange", () => {
|
||||||
|
this.rerender()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class ProfileMenu extends Shadow {
|
|||||||
p("Email: ")
|
p("Email: ")
|
||||||
.fontWeight("bold")
|
.fontWeight("bold")
|
||||||
|
|
||||||
p(window.profile?.email)
|
p(global.profile?.email)
|
||||||
})
|
})
|
||||||
.gap(1, em)
|
.gap(1, em)
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ class ProfileMenu extends Shadow {
|
|||||||
p("Name: ")
|
p("Name: ")
|
||||||
.fontWeight("bold")
|
.fontWeight("bold")
|
||||||
|
|
||||||
p(window.profile?.name)
|
p(global.profile?.name)
|
||||||
})
|
})
|
||||||
.gap(1, em)
|
.gap(1, em)
|
||||||
|
|
||||||
@@ -37,8 +37,8 @@ class ProfileMenu extends Shadow {
|
|||||||
.center()
|
.center()
|
||||||
.display("none")
|
.display("none")
|
||||||
.onAppear(async () => {
|
.onAppear(async () => {
|
||||||
if(!window.profile) {
|
if(!global.profile) {
|
||||||
window.profile = await this.fetchProfile()
|
global.profile = await this.fetchProfile()
|
||||||
this.rerender()
|
this.rerender()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,18 +1,43 @@
|
|||||||
class Sidebar extends Shadow {
|
class Sidebar extends Shadow {
|
||||||
currentNetwork = null
|
|
||||||
|
toggleSelectedStyles(el) {
|
||||||
|
let currentlySelected = $("img[selected]")
|
||||||
|
if(currentlySelected) {
|
||||||
|
currentlySelected.removeAttribute("selected")
|
||||||
|
currentlySelected.style.borderLeft = ""
|
||||||
|
currentlySelected.style.paddingLeft = "10px"
|
||||||
|
}
|
||||||
|
|
||||||
|
el.setAttribute("selected", "")
|
||||||
|
el.style.borderLeft = "1px solid var(--accent)"
|
||||||
|
el.style.paddingLeft = "9px"
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
VStack(() => {
|
VStack(() => {
|
||||||
|
let selected = window.location.pathname.startsWith("/my")
|
||||||
|
|
||||||
img(document.documentElement.classList.contains("red") ? "/_/icons/quillblack.svg" : "/_/icons/quill.svg", "2.5em", "2.5em")
|
img(document.documentElement.classList.contains("red") ? "/_/icons/quillblack.svg" : "/_/icons/quill.svg", "2.5em", "2.5em")
|
||||||
.marginTop(6, vh)
|
.marginTop(6, vh)
|
||||||
.marginBottom(2, vh)
|
.marginBottom(2, vh)
|
||||||
|
.attr({selected: selected ? "" : null})
|
||||||
|
.paddingRight(0.5, em)
|
||||||
|
.paddingLeft(selected ? 9 : 10, px)
|
||||||
|
.borderLeft(selected ? "1px solid var(--accent)" : "0")
|
||||||
|
.onClick((done, e) => {
|
||||||
|
if(done) {
|
||||||
|
this.toggleSelectedStyles(e.target)
|
||||||
|
window.navigateTo("/my")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
let networks = window.profile.networks
|
let networks = global.profile.networks
|
||||||
for(let i=0; i<networks.length; i++) {
|
for(let i=0; i<networks.length; i++) {
|
||||||
let selected = window.location.pathname.startsWith("/" + networks[i].abbreviation)
|
let selected = window.location.pathname.startsWith("/" + networks[i].abbreviation)
|
||||||
|
|
||||||
img(`/db/images/${networks[i].logo}`, "2.25em", "2.25em")
|
img(`/db/images/${networks[i].logo}`, "2.25em", "2.25em")
|
||||||
.marginTop(3, vh)
|
.marginTop(3, vh)
|
||||||
|
.attr({selected: selected ? "" : null})
|
||||||
.paddingRight(0.5, em)
|
.paddingRight(0.5, em)
|
||||||
.paddingLeft(selected ? 9 : 10, px)
|
.paddingLeft(selected ? 9 : 10, px)
|
||||||
.borderLeft(selected ? "1px solid var(--accent)" : "0")
|
.borderLeft(selected ? "1px solid var(--accent)" : "0")
|
||||||
@@ -23,11 +48,10 @@ class Sidebar extends Shadow {
|
|||||||
this.style.opacity = ""
|
this.style.opacity = ""
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.onClick(function (finished) {
|
.onClick((done, e) => {
|
||||||
if(finished) {
|
if(done) {
|
||||||
this.setAttribute("selected", "")
|
this.toggleSelectedStyles(e.target)
|
||||||
this.style.borderLeft = "1px solid var(--accent)"
|
window.navigateTo(`/${networks[i].abbreviation}`)
|
||||||
this.style.paddingLeft = "9px"
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.cursor("default")
|
.cursor("default")
|
||||||
@@ -41,7 +65,7 @@ class Sidebar extends Shadow {
|
|||||||
.borderRight("1px solid var(--accent)")
|
.borderRight("1px solid var(--accent)")
|
||||||
.zIndex(3)
|
.zIndex(3)
|
||||||
.onEvent("themechange", () => {
|
.onEvent("themechange", () => {
|
||||||
console.log("change")
|
console.log("why is this needed smg")
|
||||||
this.rerender()
|
this.rerender()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<script type="importmap">
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"fs": "/_/code/ws/shim/fs.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<script src="/_/code/quill.js"></script>
|
<script src="/_/code/quill.js"></script>
|
||||||
<script src="/_/code/zod.js"></script>
|
<script src="/_/code/zod.js"></script>
|
||||||
<script type="module" src="75820185/index.js"></script>
|
<script type="module" src="75820185/index.js"></script>
|
||||||
|
|||||||
@@ -1,118 +1,149 @@
|
|||||||
import Socket from "/_/code/ws/Socket.js"
|
import Socket from "/_/code/ws/Socket.js"
|
||||||
import "./Home.js"
|
import "./Home.js"
|
||||||
|
|
||||||
import util from "./util.js"
|
import util from "./util.js"
|
||||||
window.util = util
|
|
||||||
|
|
||||||
window.Socket = new Socket()
|
let Global = class {
|
||||||
|
Socket = new Socket()
|
||||||
|
profile = null
|
||||||
|
currentNetwork = ""
|
||||||
|
currentApp = ""
|
||||||
|
util = util
|
||||||
|
|
||||||
window.currentNetwork = ""
|
openApp = function(appName) {
|
||||||
window.currentApp = ""
|
const appUrl = appName.charAt(0).toLowerCase() + appName.slice(1);
|
||||||
|
let parts = window.location.pathname.split('/').filter(Boolean);
|
||||||
async function openNetworkAndApp() {
|
let newPath = "/" + parts[0] + "/" + appUrl
|
||||||
|
window.navigateTo(newPath)
|
||||||
if(window.currentNetwork !== networkFromPath()) {
|
|
||||||
window.currentNetwork = networkFromPath()
|
|
||||||
const event = new CustomEvent('networkchanged', {
|
|
||||||
detail: { name: currentNetwork }
|
|
||||||
});
|
|
||||||
window.dispatchEvent(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!window.currentNetwork.data) {
|
|
||||||
let appData = await fetch("/app/orgdata/" + window.profile.networks[0].id, {method: "GET"})
|
|
||||||
let json = await appData.json()
|
|
||||||
window.currentNetwork.data = json
|
|
||||||
}
|
|
||||||
|
|
||||||
if(window.currentApp !== appFromPath()) {
|
|
||||||
window.currentApp = appFromPath()
|
|
||||||
const event = new CustomEvent('appchange', {
|
const event = new CustomEvent('appchange', {
|
||||||
detail: { name: window.currentApp }
|
detail: { name: appName }
|
||||||
});
|
});
|
||||||
window.dispatchEvent(event)
|
window.dispatchEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(window.currentNetwork) { // 2 navigates fire on load: 1 initial, and one after the org redirect
|
async fetchAppData() {
|
||||||
document.title = `${window.currentNetwork.abbreviation} | Parchment`
|
let personalSpace = this.currentNetwork === this.profile
|
||||||
|
let appData = await fetch(`/app/${personalSpace ? "my" : "org"}data/` + this.currentNetwork.id, {method: "GET"})
|
||||||
|
let json = await appData.json()
|
||||||
|
return json
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("navigate", openNetworkAndApp)
|
onNavigate = async () => {
|
||||||
|
|
||||||
window.openApp = function(appName) {
|
let selectedNetwork = this.networkFromPath()
|
||||||
const appUrl = appName.charAt(0).toLowerCase() + appName.slice(1);
|
let selectedApp = this.appFromPath()
|
||||||
let parts = window.location.pathname.split('/').filter(Boolean);
|
|
||||||
let newPath = "/" + parts[0] + "/" + appUrl
|
|
||||||
window.navigateTo(newPath)
|
|
||||||
const event = new CustomEvent('appchange', {
|
|
||||||
detail: { name: appName }
|
|
||||||
});
|
|
||||||
window.dispatchEvent(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
window.networkFromPath = function () {
|
if(!selectedNetwork) {
|
||||||
const pathname = window.location.pathname;
|
if(this.profile.networks.length > 0) {
|
||||||
const firstSegment = pathname.split('/').filter(Boolean)[0] || '';
|
let path = `/${this.getDefaultNetworkName()}/${this.getDefaultAppName()}`
|
||||||
let networks = window.profile?.networks
|
history.replaceState({}, '', path)
|
||||||
for(let i = 0; i < networks.length; i++) {
|
}
|
||||||
let network = networks[i]
|
} else if(!selectedApp) {
|
||||||
if(network.abbreviation === firstSegment) {
|
if(this.currentNetwork === window.profile) {
|
||||||
return network
|
history.replaceState({}, '', `${window.location.pathname}/${window.profile.apps[0]}`)
|
||||||
|
} else {
|
||||||
|
history.replaceState({}, '', `${window.location.pathname}/${this.getDefaultAppName()}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedNetwork = this.networkFromPath()
|
||||||
|
selectedApp = this.appFromPath()
|
||||||
|
|
||||||
|
let networkChanged = this.currentNetwork !== selectedNetwork
|
||||||
|
let appChanged = this.currentApp !== selectedApp
|
||||||
|
if(networkChanged) {
|
||||||
|
this.currentNetwork = selectedNetwork
|
||||||
|
this.currentApp = selectedApp
|
||||||
|
const event = new CustomEvent('networkchange', {
|
||||||
|
detail: { name: this.currentNetwork }
|
||||||
|
});
|
||||||
|
window.dispatchEvent(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this.currentNetwork.data) {
|
||||||
|
this.currentNetwork.data = await this.fetchAppData()
|
||||||
|
}
|
||||||
|
|
||||||
|
if(appChanged && !networkChanged) {
|
||||||
|
this.currentApp = selectedApp
|
||||||
|
const event = new CustomEvent('appchange', {
|
||||||
|
detail: { name: this.currentApp }
|
||||||
|
});
|
||||||
|
window.dispatchEvent(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
document.title = (this.currentNetwork === this.profile) ? "Parchment" : `${this.currentNetwork.abbreviation} | Parchment`
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentNetworkAndApp() {
|
||||||
|
this.currentNetwork = this.networkFromPath()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
getDefaultNetworkName() {
|
||||||
|
let defaultNetwork = this.profile.networks[0]
|
||||||
|
return defaultNetwork.abbreviation
|
||||||
|
}
|
||||||
|
|
||||||
|
getDefaultAppName() {
|
||||||
|
let defaultNetwork = this.profile.networks[0]
|
||||||
|
return defaultNetwork.apps[0].toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
networkFromPath = function () {
|
||||||
|
const pathname = window.location.pathname;
|
||||||
|
const firstSegment = pathname.split('/').filter(Boolean)[0] || '';
|
||||||
|
if(firstSegment === "my") {
|
||||||
|
return this.profile
|
||||||
|
} else {
|
||||||
|
let networks = this.profile.networks
|
||||||
|
for(let i = 0; i < networks.length; i++) {
|
||||||
|
let network = networks[i]
|
||||||
|
if(network.abbreviation === firstSegment) {
|
||||||
|
return network
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
window.appFromPath = function() {
|
appFromPath = function() {
|
||||||
const pathname = window.location.pathname;
|
const pathname = window.location.pathname;
|
||||||
const segments = pathname.split('/').filter(Boolean);
|
const segments = pathname.split('/').filter(Boolean);
|
||||||
const secondSegment = segments[1] || "";
|
const secondSegment = segments[1] || ""
|
||||||
const capitalized = secondSegment.charAt(0).toUpperCase() + secondSegment.slice(1);
|
const capitalized = secondSegment.charAt(0).toUpperCase() + secondSegment.slice(1);
|
||||||
return capitalized
|
return capitalized
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getProfile() {
|
async getProfile() {
|
||||||
try {
|
try {
|
||||||
const res = await fetch("/profile", {
|
const res = await fetch("/profile", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) throw new Error("Failed to fetch profile");
|
if (!res.ok) throw new Error("Failed to fetch profile");
|
||||||
|
|
||||||
const profile = await res.json();
|
const profile = await res.json();
|
||||||
console.log("getProfile: ", profile);
|
console.log("getProfile: ", profile);
|
||||||
window.profile = profile
|
this.profile = profile
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
window.addEventListener("navigate", this.onNavigate)
|
||||||
|
|
||||||
|
this.getProfile().then(async () => {
|
||||||
|
|
||||||
|
await this.onNavigate()
|
||||||
|
|
||||||
|
Home()
|
||||||
|
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInitialNetworkPath() {
|
window.global = new Global()
|
||||||
let path = ""
|
|
||||||
let defaultNetwork = window.profile.networks[0]
|
|
||||||
|
|
||||||
if(!networkFromPath()) {
|
|
||||||
path += (defaultNetwork.abbreviation + "/")
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!appFromPath()) {
|
|
||||||
let defaultApp = defaultNetwork.apps[0]
|
|
||||||
path += defaultApp.toLowerCase()
|
|
||||||
}
|
|
||||||
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
getProfile().then(async () => {
|
|
||||||
|
|
||||||
if(window.profile.networks.length > 0) {
|
|
||||||
let path = getInitialNetworkPath()
|
|
||||||
window.navigateTo(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
Home()
|
|
||||||
})
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
class Connection {
|
|
||||||
connectionTries = 0
|
|
||||||
ws;
|
|
||||||
linkCreated;
|
|
||||||
wsStatus;
|
|
||||||
|
|
||||||
constructor(receiveCB) {
|
|
||||||
this.init()
|
|
||||||
this.receiveCB = receiveCB
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
if(window.location.hostname.includes("local")) {
|
|
||||||
this.ws = new WebSocket("ws://" + window.location.host)
|
|
||||||
} else {
|
|
||||||
this.ws = new WebSocket("wss://" + window.location.hostname + window.location.pathname)
|
|
||||||
}
|
|
||||||
this.ws.addEventListener('open', () => {
|
|
||||||
this.connectionTries = 0
|
|
||||||
console.log("Websocket connection established.");
|
|
||||||
this.ws.addEventListener('message', this.receiveCB)
|
|
||||||
});
|
|
||||||
this.ws.addEventListener("close", () => {
|
|
||||||
this.checkOpen();
|
|
||||||
console.log('Websocket Closed')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async checkOpen() {
|
|
||||||
if (this.ws.readyState === WebSocket.OPEN) {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
await this.sleep(this.connectionTries < 20 ? 5000 : 60000)
|
|
||||||
this.connectionTries++
|
|
||||||
console.log('Reestablishing connection')
|
|
||||||
this.init()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sleep = (time) => {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
setTimeout(resolve, time);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
send = (msg) => {
|
|
||||||
console.log("sending")
|
|
||||||
if (this.ws.readyState === WebSocket.OPEN) {
|
|
||||||
this.ws.send(msg);
|
|
||||||
}
|
|
||||||
else if(this.connectionTries === 0) {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.send(msg)
|
|
||||||
}, 100)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.error('No websocket connection: Cannot send message');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connection
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
import Connection from "./Connection.js";
|
|
||||||
|
|
||||||
export default class Socket {
|
|
||||||
connection;
|
|
||||||
disabled = true;
|
|
||||||
requestID = 1;
|
|
||||||
pending = new Map();
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.connection = new Connection(this.receive);
|
|
||||||
}
|
|
||||||
|
|
||||||
isOpen() {
|
|
||||||
if(this.connection.checkOpen()) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
send(msg) {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const id = (++this.requestID).toString();
|
|
||||||
this.pending.set(id, resolve);
|
|
||||||
this.connection.send(JSON.stringify({ id, ...msg }));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
receive = (event) => {
|
|
||||||
const msg = JSON.parse(event.data);
|
|
||||||
if (msg.id && this.pending.has(msg.id)) {
|
|
||||||
this.pending.get(msg.id)(msg);
|
|
||||||
this.pending.delete(msg.id);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
this.onBroadcast(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onBroadcast(msg) {
|
|
||||||
window.dispatchEvent(new CustomEvent(msg.event, {
|
|
||||||
detail: msg.msg
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,8 +8,8 @@ class Home extends Shadow {
|
|||||||
ZStack(() => {
|
ZStack(() => {
|
||||||
|
|
||||||
ZStack(() => {
|
ZStack(() => {
|
||||||
console.log(window.currentApp)
|
console.log(global.currentApp)
|
||||||
switch(window.currentApp) {
|
switch(global.currentApp) {
|
||||||
case "Dashboard":
|
case "Dashboard":
|
||||||
Dashboard()
|
Dashboard()
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
class Dashboard extends Shadow {
|
class Dashboard extends Shadow {
|
||||||
render() {
|
render() {
|
||||||
VStack(() => {
|
VStack(() => {
|
||||||
console.log(window.currentNetwork)
|
console.log(global.currentNetwork)
|
||||||
})
|
})
|
||||||
.width(100, pct)
|
.width(100, pct)
|
||||||
.height(100, pct)
|
.height(100, pct)
|
||||||
|
|||||||
@@ -4,45 +4,45 @@ import "./Home.js"
|
|||||||
import util from "./util.js"
|
import util from "./util.js"
|
||||||
window.util = util
|
window.util = util
|
||||||
|
|
||||||
window.Socket = new Socket()
|
global.Socket = new Socket()
|
||||||
|
|
||||||
window.currentNetwork = ""
|
global.currentNetwork = ""
|
||||||
window.currentApp = ""
|
global.currentApp = ""
|
||||||
|
|
||||||
async function openNetworkAndApp() {
|
async function openNetworkAndApp() {
|
||||||
// console.log("currentApp: ", currentApp, "currentnet: ", currentNetwork, "nfrompath: ", networkFromPath(), "afrompath", appFromPath())
|
// console.log("currentApp: ", currentApp, "currentnet: ", currentNetwork, "nfrompath: ", networkFromPath(), "afrompath", appFromPath())
|
||||||
|
|
||||||
if(window.currentNetwork !== networkFromPath()) {
|
if(global.currentNetwork !== networkFromPath()) {
|
||||||
window.currentNetwork = networkFromPath()
|
global.currentNetwork = networkFromPath()
|
||||||
const event = new CustomEvent('networkchanged', {
|
const event = new CustomEvent('networkchange', {
|
||||||
detail: { name: currentNetwork }
|
detail: { name: currentNetwork }
|
||||||
});
|
});
|
||||||
window.dispatchEvent(event)
|
window.dispatchEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!window.currentNetwork.data) {
|
if(!global.currentNetwork.data) {
|
||||||
let appData = await fetch("/app/orgdata/" + window.profile.networks[0].id, {method: "GET"})
|
let appData = await fetch("/app/orgdata/" + global.profile.networks[0].id, {method: "GET"})
|
||||||
let json = await appData.json()
|
let json = await appData.json()
|
||||||
window.currentNetwork.data = json
|
global.currentNetwork.data = json
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("current: ", window.currentApp, "afrompath: ", appFromPath())
|
console.log("current: ", global.currentApp, "afrompath: ", appFromPath())
|
||||||
if(window.currentApp !== appFromPath()) {
|
if(global.currentApp !== appFromPath()) {
|
||||||
window.currentApp = appFromPath()
|
global.currentApp = appFromPath()
|
||||||
const event = new CustomEvent('appchange', {
|
const event = new CustomEvent('appchange', {
|
||||||
detail: { name: window.currentApp }
|
detail: { name: global.currentApp }
|
||||||
});
|
});
|
||||||
window.dispatchEvent(event)
|
window.dispatchEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(window.currentNetwork) { // 2 navigates fire on load: 1 initial, and one after the org redirect
|
if(global.currentNetwork) { // 2 navigates fire on load: 1 initial, and one after the org redirect
|
||||||
document.title = `${window.currentNetwork.abbreviation} | Parchment`
|
document.title = `${global.currentNetwork.abbreviation} | Parchment`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("navigate", openNetworkAndApp)
|
window.addEventListener("navigate", openNetworkAndApp)
|
||||||
|
|
||||||
window.openApp = function(appName) {
|
global.currentApp = function(appName) {
|
||||||
const appUrl = appName.charAt(0).toLowerCase() + appName.slice(1);
|
const appUrl = appName.charAt(0).toLowerCase() + appName.slice(1);
|
||||||
let parts = window.location.pathname.split('/').filter(Boolean);
|
let parts = window.location.pathname.split('/').filter(Boolean);
|
||||||
let newPath = "/" + parts[0] + "/" + appUrl
|
let newPath = "/" + parts[0] + "/" + appUrl
|
||||||
@@ -56,7 +56,7 @@ window.openApp = function(appName) {
|
|||||||
window.networkFromPath = function () {
|
window.networkFromPath = function () {
|
||||||
const pathname = window.location.pathname;
|
const pathname = window.location.pathname;
|
||||||
const firstSegment = pathname.split('/').filter(Boolean)[0] || '';
|
const firstSegment = pathname.split('/').filter(Boolean)[0] || '';
|
||||||
let networks = window.profile?.networks
|
let networks = global.profile?.networks
|
||||||
for(let i = 0; i < networks.length; i++) {
|
for(let i = 0; i < networks.length; i++) {
|
||||||
let network = networks[i]
|
let network = networks[i]
|
||||||
if(network.abbreviation === firstSegment) {
|
if(network.abbreviation === firstSegment) {
|
||||||
@@ -87,7 +87,7 @@ async function getProfile() {
|
|||||||
|
|
||||||
const profile = await res.json();
|
const profile = await res.json();
|
||||||
console.log("getProfile: ", profile);
|
console.log("getProfile: ", profile);
|
||||||
window.profile = profile
|
global.profile = profile
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,7 @@ async function getProfile() {
|
|||||||
|
|
||||||
function getInitialNetworkPath() {
|
function getInitialNetworkPath() {
|
||||||
let path = ""
|
let path = ""
|
||||||
let defaultNetwork = window.profile.networks[0]
|
let defaultNetwork = global.profile.networks[0]
|
||||||
|
|
||||||
if(!networkFromPath()) {
|
if(!networkFromPath()) {
|
||||||
path += (defaultNetwork.abbreviation + "/")
|
path += (defaultNetwork.abbreviation + "/")
|
||||||
@@ -111,7 +111,7 @@ function getInitialNetworkPath() {
|
|||||||
|
|
||||||
getProfile().then(async () => {
|
getProfile().then(async () => {
|
||||||
|
|
||||||
if(window.profile.networks.length > 0) {
|
if(global.profile.networks.length > 0) {
|
||||||
let path = getInitialNetworkPath()
|
let path = getInitialNetworkPath()
|
||||||
window.navigateTo(path)
|
window.navigateTo(path)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,10 +35,12 @@ class Home extends Shadow {
|
|||||||
p("Parchment is a platform for small to medium-sized communities.")
|
p("Parchment is a platform for small to medium-sized communities.")
|
||||||
.color("var(--quillred)")
|
.color("var(--quillred)")
|
||||||
.borderTop("1px solid var(--quillred)")
|
.borderTop("1px solid var(--quillred)")
|
||||||
|
.verticalAlign("center")
|
||||||
.borderHorizontal("1px solid var(--quillred)")
|
.borderHorizontal("1px solid var(--quillred)")
|
||||||
.height(5, em)
|
.height(5, em)
|
||||||
.fontSize(window.isMobile() ? 1.5 : 1.2, vmax)
|
.fontSize(window.isMobile() ? 2 : 1.2, vmax)
|
||||||
.paddingTop(2, vmax)
|
.paddingTop(2, vmax)
|
||||||
|
.paddingBottom(window.isMobile() ? 1 : 0, em)
|
||||||
.paddingHorizontal(2, vmax)
|
.paddingHorizontal(2, vmax)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user