diff --git a/db/comalyr.svg b/db/images/comalyr.svg
similarity index 100%
rename from db/comalyr.svg
rename to db/images/comalyr.svg
diff --git a/db/images/hyperia.svg b/db/images/hyperia.svg
new file mode 100644
index 0000000..67b933e
--- /dev/null
+++ b/db/images/hyperia.svg
@@ -0,0 +1,38 @@
+
diff --git a/notes.js b/notes.js
new file mode 100644
index 0000000..dcc75ef
--- /dev/null
+++ b/notes.js
@@ -0,0 +1,62 @@
+img(`db/images/${networks[i].logo}`, "2.25em", "2.25em")
+ .marginTop(3, vh)
+ .paddingRight(0.5, em)
+ .onClick(function (finished) {
+ if(finished) {
+ this.setAttribute("selected", "")
+ }
+ })
+ .cursor("default")
+ .DEFAULT()
+ .opacity(0)
+ .borderLeft(0)
+ .paddingLeft(10, px)
+ .HOVERED()
+ .opacity(0.8)
+ .classStyle("selected")
+ .borderLeft("1px solid var(--accent)")
+ .paddingLeft(9, px)
+
+
+
+quill gotchas
+ image width / height
+ forgetting to put a "/" at the beginning of the url for window.navigateTo (if you don't want to add to the existing url)
+ forgetting to define the event callback with or without the word "function", like so:
+
+ if you want "this" to be scoped to the element the listener is on:
+ .onClick(function (finished) {
+ if(finished) {
+ this.setAttribute("selected", "")
+ }
+ })
+
+ if you want "this" to be scoped to the parent shadow:
+ .onClick((finished) => {
+ if(finished) {
+ this.setAttribute("selected", "")
+ }
+ })
+
+
+window.svg = async function svg(src, width, height) {
+ const res = await fetch(src);
+ const svgText = await res.text();
+
+ let container = document.createElement("div")
+ container.innerHTML = svgText;
+
+ const svg = container.querySelector("svg");
+ if(width)
+ svg.setAttribute("width", width);
+ if(height)
+ svg.setAttribute("height", height);
+
+ svg.style.display = "block";
+ svg.setAttribute("aria-hidden", "true");
+
+ quill.render(container)
+ return container
+}
+
+rendered 1 svg but gave an error on the attr() function
\ No newline at end of file
diff --git a/server/db/model/network.js b/server/db/model/network.js
index 93b82a8..a6f7017 100644
--- a/server/db/model/network.js
+++ b/server/db/model/network.js
@@ -12,7 +12,8 @@ export default class Network {
id: z.number(),
name: z.string(),
apps: z.array(z.string()),
- logo: z.string()
+ logo: z.string(),
+ abbreviation: z.string()
})
.strict()
diff --git a/server/index.js b/server/index.js
index d1c9236..0f6021a 100644
--- a/server/index.js
+++ b/server/index.js
@@ -97,9 +97,14 @@ class Server {
});
return match ? path.join(dir, match) : null;
}
- let filePath = getFileByNumber(path.join(this.DBPath, "images"), path.basename(req.url))
- res.sendFile(filePath)
+ let filePath = path.join(this.DBPath, "images", path.basename(req.url))
+
+ if(filePath) {
+ res.sendFile(filePath)
+ } else {
+ return res.status(404).json({error: "Can't find image"})
+ }
}
get = async (req, res) => {
diff --git a/ui/_/code/quill.js b/ui/_/code/quill.js
index 19242eb..c8a0f7a 100644
--- a/ui/_/code/quill.js
+++ b/ui/_/code/quill.js
@@ -51,12 +51,17 @@ window.setQuery = function(key, value) {
return newUrl;
};
-
+
window.navigateTo = function(url) {
window.dispatchEvent(new Event('navigate'));
window.history.pushState({}, '', url);
}
+window.setLocation = function(url) {
+ window.dispatchEvent(new Event('navigate'));
+ window.history.replaceState({}, '', url);
+}
+
/* $ SELECTOR */
HTMLElement.prototype.$ = function(selector) {
@@ -91,8 +96,6 @@ console.green = function(message) {
}
/* GET CSS VARIABLES FOR DARK OR LIGHT MODE */
-window.darkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
-document.documentElement.classList.add(darkMode ? 'dark' : 'light');
window.getColor = function(name) {
const rootStyles = getComputedStyle(document.documentElement);
@@ -815,6 +818,20 @@ window.input = function(placeholder = "", width, height) {
return el
}
+window.select = function(cb) {
+ let el = document.createElement("select")
+ el.render = cb
+ quill.render(el)
+ return el
+}
+
+window.option = function(placeholder = "") {
+ let el = document.createElement("option")
+ el.innerText = placeholder
+ quill.render(el)
+ return el
+}
+
window.label = function(inside) {
let el = document.createElement("label")
if(typeof inside === "string") {
@@ -1034,7 +1051,7 @@ HTMLElement.prototype.onInput = function(cb) {
};
HTMLElement.prototype.onChange = function(cb) {
- if(!this.matches('input, textarea, [contenteditable=""], [contenteditable="true"]'))
+ if(!this.matches('input, textarea, select, [contenteditable=""], [contenteditable="true"]'))
throw new Error("Can't put input event on non-input element!")
this._storeListener("change", cb);
return this;
diff --git a/ui/_/code/shared.css b/ui/_/code/shared.css
index ebe0f26..1816c45 100644
--- a/ui/_/code/shared.css
+++ b/ui/_/code/shared.css
@@ -1,8 +1,10 @@
:root {
- --main: var(--brown);
- --accent: var(--gold);
- --accent2: var(--green);
+ --main: var(--parchment);
+ --app: var(--parchment);
+ --accent: black;
+ --accent2: black;
+ --parchment: #FFEBCC;
--gold: #FEBA7D;
--divider: #bb7c36;
--green: #0857265c;
@@ -11,15 +13,15 @@
--brown: #812A18;
--darkbrown: #3f0808;
- --house-src: "/_/icons/house.svg";
- --nodes-src: "/_/icons/nodes.svg";
- --forum-src: "/_/icons/forum.svg";
- --people-src: "/_/icons/people.svg";
+ --house-src: /_/icons/house.svg;
+ --nodes-src: /_/icons/nodes.svg;
+ --forum-src: /_/icons/forum.svg;
+ --people-src: /_/icons/people.svg;
}
-@media (prefers-color-scheme: dark) {
-:root {
+:root.dark {
--main: #000000;
+ --app: #180404;
--accent: #695b4d;
--accent2: var(--gold);
@@ -28,12 +30,23 @@
--forum-src: /_/icons/forumdark.svg;
--people-src: /_/icons/peopledark.svg;
}
-}
:root.red {
--main: var(--red);
- --accent: #6a0000;
+ --app: var(--red);
+ --accent: black;
--accent2: var(--green);
+
+ --house-src: /_/icons/house.svg;
+ --nodes-src: /_/icons/nodes.svg;
+ --forum-src: /_/icons/forum.svg;
+ --people-src: /_/icons/people.svg;
+
+ --quill-src: /_/icons/people.svg;
+}
+
+:root.public {
+ --accent: var(--gold);
}
@font-face {
diff --git a/ui/_/icons/house.svg b/ui/_/icons/house.svg
index f2e6f86..f1916d4 100644
--- a/ui/_/icons/house.svg
+++ b/ui/_/icons/house.svg
@@ -1,4 +1,4 @@
diff --git a/ui/_/icons/nodesblack.svg b/ui/_/icons/nodesblack.svg
deleted file mode 100644
index 51c5e6b..0000000
--- a/ui/_/icons/nodesblack.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
diff --git a/ui/_/icons/people.svg b/ui/_/icons/people.svg
index 9ec5c7f..f2b266a 100644
--- a/ui/_/icons/people.svg
+++ b/ui/_/icons/people.svg
@@ -1,3 +1,3 @@
-
+
\ No newline at end of file
diff --git a/ui/_/icons/peopleblack.svg b/ui/_/icons/peopleblack.svg
deleted file mode 100644
index e05077c..0000000
--- a/ui/_/icons/peopleblack.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/ui/desktop/Home.js b/ui/desktop/Home.js
index b1ef75d..a2eee4c 100644
--- a/ui/desktop/Home.js
+++ b/ui/desktop/Home.js
@@ -9,43 +9,49 @@ class Home extends Shadow {
ZStack(() => {
Sidebar()
-
- switch(window.location.pathname) {
- case "/":
- AppWindow()
- AppMenu()
- break
- case "/app/jobs":
- AppWindow("Jobs")
- AppMenu("Jobs")
- break;
- case "/app/messages":
- AppWindow("Messages")
- AppMenu("Messages")
- break;
- case "/app/market":
- AppWindow("Market")
- AppMenu("Market")
- break;
- case "/app/forum":
- AppWindow("Forum")
- AppMenu("Forum")
- break;
- default:
- throw new Error("Unknown route!")
- }
-
+
+ AppMenu()
+
+ AppWindow()
HStack(() => {
- // ProfileButton()
- // .zIndex(1)
- // .cursor("default")
-
+ let selected = document.documentElement.className
+ console.log(selected)
+ select(() => {
+ option("")
+ option("Light").attr({value: "light"})
+ option("Dark").attr({value: "dark"})
+ option("Red").attr({value: "red"})
+
+ $(`option[value=${selected}]`).selected = "true"
+ })
+ .outline("none")
+ .background("transparent")
+ .height(2, em)
+ .color("var(--accent)")
+ .border("1px solid var(--accent)")
+ .attr({value: "dark"})
+ .onChange((e) => {
+ console.log("onchange")
+ document.documentElement.className = e.target.value
+ localStorage.setItem("theme", e.target.value);
+ const event = new CustomEvent('themechange', {
+ detail: {}
+ });
+ window.dispatchEvent(event)
+ })
+ .onHover(function (hovering) {
+ if(hovering) {
+ this.style.background = "var(--green)"
+ } else {
+ this.style.background = "transparent"
+ }
+ })
+
a("/signout", "Sign Out")
.background("transparent")
- .border(window.location.pathname === "/" ? "1px solid var(--tan)" : "0.5px solid #bb7c36")
- .color(window.location.pathname === "/" ? "var(--tan)" : "var(--accent)")
- .borderRadius(5, px)
+ .border("1px solid var(--accent")
+ .color("var(--accent)")
.onHover(function (hovering) {
if(hovering) {
this.style.background = "var(--green)"
@@ -53,15 +59,6 @@ class Home extends Shadow {
this.style.background = ""
}
})
- .onNavigate(function () {
- if(window.location.pathname === "/") {
- this.style.border = "1px solid var(--tan)"
- this.style.color = "var(--tan)"
- } else {
- this.style.border = "0.5px solid #bb7c36"
- this.style.color = "var(--accent)"
- }
- })
})
.gap(1, em)
.xRight(2, em).y(2.3, em)
diff --git a/ui/desktop/apps/Dashboard/Dashboard.js b/ui/desktop/apps/Dashboard/Dashboard.js
new file mode 100644
index 0000000..c58ccbc
--- /dev/null
+++ b/ui/desktop/apps/Dashboard/Dashboard.js
@@ -0,0 +1,11 @@
+class Dashboard extends Shadow {
+ render() {
+ VStack(() => {
+
+ })
+ .width(100, pct)
+ .height(100, pct)
+ }
+}
+
+register(Dashboard)
\ No newline at end of file
diff --git a/ui/desktop/components/AppMenu.js b/ui/desktop/components/AppMenu.js
index 83d1419..7832973 100644
--- a/ui/desktop/components/AppMenu.js
+++ b/ui/desktop/components/AppMenu.js
@@ -1,17 +1,8 @@
-css(`
- app-menu img:hover {
- opacity: 0.8;
- }
-`)
-
-register(
-
class AppMenu extends Shadow {
- selected;
- constructor(selected) {
- super()
- this.selected = selected
+ images = {
+ "Dashboard": {src: "house-src", size: "1.5em"},
+ "People": {src: "people-src", size: "1.7em"}
}
render() {
@@ -22,76 +13,49 @@ class AppMenu extends Shadow {
.getPropertyValue("--" + value)
.trim();
}
+
HStack(() => {
- img(cssVariable("house-src"), "1.5em")
- img(cssVariable("people-src"), "1.7em")
+ let currentNetwork = window.currentNetwork
+ if(!currentNetwork) return
+ let currentApp = window.currentApp
+
+ for(let i = 0; i < currentNetwork.apps.length; i++) {
+ let app = currentNetwork.apps[i]
+ img(cssVariable(this.images[app].src), this.images[app].size)
+ .attr({app: app})
+ .padding(0.3, em)
+ .paddingBottom(currentApp === app ? 4 : 5, px)
+ .borderBottom(currentApp === app ? "1px solid var(--accent)" : "")
+ .onClick((done) => {
+ if(done) window.openApp(app)
+ })
+ .onHover(function (hovering) {
+ if(hovering) {
+ this.style.opacity = 0.8
+ } else {
+ this.style.opacity = ""
+ }
+ })
+ }
})
.justifyContent("center")
.gap(3.5, em)
.paddingRight(2, em)
})
+ .onEvent("themechange", () => {
+ this.rerender()
+ })
+ .onEvent("appchanged", () => {
+ console.log("event firing successfully")
+ this.rerender()
+ })
.position("fixed")
.x(0).yBottom(0)
.width(100, vw)
- .paddingVertical(1, em)
- .borderTop("0.5px solid var(--accent)")
- .onNavigate(() => {
- if(window.location.pathname === "/") {
- this.styleMaximized()
- $("app-window").close()
- } else {
- this.styleMinimized()
- $("app-window").open(this.selected)
- }
- })
- .onAppear(() => {
- Array.from(this.querySelectorAll("img")).forEach((el) => {
- el.addEventListener("mousedown", (e) => {
- el.classList.add("touched")
- })
- })
- window.addEventListener("mouseup", (e) => {
- let target = e.target
- if(!target.matches("app-menu img")) {
- return
- }
-
- target.classList.remove("touched")
-
- if(target.classList.contains("selected")) {
- this.selected = ""
- window.navigateTo("/")
- } else {
- this.selected = target.innerText
- window.navigateTo("/app/" + target.innerText.toLowerCase())
- }
- })
- })
-
- if(this.selected) {
- this.styleMinimized()
- }
- }
-
- styleMaximized() {
- $$("app-menu p").forEach((el) => {
- el.classList.remove("selected")
- })
- this.classList.remove("minimized")
- $("#divider").style.display = ""
- }
-
- styleMinimized() {
- $$("app-menu p").forEach((el) => {
- if(el.innerText !== this.selected) {
- el.classList.remove("selected")
- } else {
- el.classList.add("selected")
- }
- })
- this.classList.add("minimized")
- $("#divider").style.display = "none"
+ .height(2.5, em)
+ .paddingVertical(0.7, em)
+ .borderTop("1px solid var(--accent)")
}
}
-, "app-menu")
\ No newline at end of file
+register(AppMenu, "app-menu")
\ No newline at end of file
diff --git a/ui/desktop/components/AppWindow.js b/ui/desktop/components/AppWindow.js
index 3f34b4a..6ca2b25 100644
--- a/ui/desktop/components/AppWindow.js
+++ b/ui/desktop/components/AppWindow.js
@@ -1,3 +1,4 @@
+import "../apps/Dashboard/Dashboard.js"
import "../apps/Forum/Forum.js"
import "../apps/Tasks/Tasks.js"
import "../apps/Messages/Messages.js"
@@ -5,16 +6,25 @@ import "../apps/Market/Market.js"
import "../apps/Jobs/Jobs.js"
class AppWindow extends Shadow {
- app;
- constructor(app) {
- super()
- this.app = app
+ calculateWidth() {
+ let sidebar = $("sidebar-").getBoundingClientRect()
+ let w = sidebar.width
+ return w
+ }
+
+ calculateHeight() {
+ let appmenu = $("app-menu").getBoundingClientRect()
+ let h = appmenu.height
+ return h
}
render() {
ZStack(() => {
- switch(this.app) {
+ switch(window.currentApp) {
+ case "Dashboard":
+ Dashboard()
+ break;
case "Forum":
Forum()
break;
@@ -30,25 +40,13 @@ class AppWindow extends Shadow {
}
})
.position("fixed")
- .display(this.app ? 'block' : 'none')
- .width(100, "vw")
- .height(100, "vh")
- .background("#591d10")
- .x(0)
- .y(0)
- // .backgroundImage("/_/images/fabric.png")
- // .backgroundSize("33vw auto")
+ .width(window.innerWidth - this.calculateWidth(), px)
+ .height(window.innerHeight - this.calculateHeight(), px)
+ .background("var(--app)")
+ .x(this.calculateWidth(), px)
+ .yBottom(this.calculateHeight(), px)
+ .onEvent("appchange", () => this.rerender())
}
-
- open(app) {
- this.app = app
- this.rerender()
- }
-
- close() {
- this.style.display = "none"
- }
-
}
register(AppWindow, "app-window")
\ No newline at end of file
diff --git a/ui/desktop/components/Sidebar.js b/ui/desktop/components/Sidebar.js
index 62494b8..15c8f68 100644
--- a/ui/desktop/components/Sidebar.js
+++ b/ui/desktop/components/Sidebar.js
@@ -1,47 +1,45 @@
class Sidebar extends Shadow {
+ currentNetwork = null
+
render() {
VStack(() => {
- img(document.documentElement.classList.contains("red") ? "/_/icons/quillblack.svg" : "/_/icons/quill.svg", "2.25em")
- .paddingLeft(3, em)
- .paddingTop(5, vh)
- .onClick(() => {
- window.navigateTo("/")
- })
+ img(document.documentElement.classList.contains("red") ? "/_/icons/quillblack.svg" : "/_/icons/quill.svg", "2.5em", "2.5em")
+ .marginTop(6, vh)
+ .marginBottom(2, vh)
+
+ let networks = window.profile.networks
+ for(let i=0; i {
- if(!window.profile) {
- window.profile = await this.fetchProfile()
- if(profile) {
- this.rerender()
- }
- }
- })
- }
-
- async fetchProfile() {
- try {
- const res = await fetch("/profile", {
- method: "GET",
- credentials: "include",
- headers: {
- "Content-Type": "application/json"
- }
- });
-
- if (!res.ok) throw new Error("Failed to fetch profile");
-
- const profile = await res.json();
- console.log(profile);
- return profile
- } catch (err) {
- console.error(err);
- }
}
}
diff --git a/ui/desktop/index.html b/ui/desktop/index.html
index 7d7cc78..1813cea 100644
--- a/ui/desktop/index.html
+++ b/ui/desktop/index.html
@@ -5,6 +5,15 @@
+
diff --git a/ui/desktop/index.js b/ui/desktop/index.js
index a02be9c..5688cd4 100644
--- a/ui/desktop/index.js
+++ b/ui/desktop/index.js
@@ -5,4 +5,96 @@ import util from "./util.js"
window.util = util
window.Socket = new Socket()
-Home()
\ No newline at end of file
+
+window.currentNetwork = ""
+window.currentApp = ""
+
+window.addEventListener("navigate", () => {
+ if(window.currentNetwork !== selectedNetwork()) {
+ window.currentNetwork = selectedNetwork()
+ const event = new CustomEvent('networkchanged', {
+ detail: { name: currentNetwork }
+ });
+ window.dispatchEvent(event)
+ }
+
+ if(window.currentApp !== selectedApp()) {
+ window.currentApp = selectedApp()
+ const event = new CustomEvent('appchanged', {
+ detail: { name: window.currentApp }
+ });
+ window.dispatchEvent(event)
+ }
+
+ document.title = `${window.currentNetwork.abbreviation} | Parchment`
+})
+
+window.selectedNetwork = function () {
+ const pathname = window.location.pathname;
+ const firstSegment = pathname.split('/').filter(Boolean)[0] || '';
+ let networks = window.profile?.networks
+ for(let i = 0; i < networks.length; i++) {
+ let network = networks[i]
+ if(network.abbreviation === firstSegment) {
+ return network
+ }
+ }
+}
+
+window.selectedApp = function() {
+ const pathname = window.location.pathname;
+ const segments = pathname.split('/').filter(Boolean);
+ const secondSegment = segments[1] || "";
+ const capitalized = secondSegment.charAt(0).toUpperCase() + secondSegment.slice(1);
+ return capitalized
+}
+
+window.openApp = function(appName) {
+ const appUrl = appName.charAt(0).toLowerCase() + appName.slice(1);
+ let parts = window.location.pathname.split('/').filter(Boolean);
+ let newPath = "/" + parts[0] + "/" + appUrl
+ console.log(newPath)
+ window.navigateTo(newPath)
+ // window.history.replaceState({}, '', newPath);
+ const event = new CustomEvent('appchanged', {
+ detail: { name: appName }
+ });
+ window.dispatchEvent(event)
+}
+
+async function getProfile() {
+ try {
+ const res = await fetch("/profile", {
+ method: "GET",
+ credentials: "include",
+ headers: {
+ "Content-Type": "application/json"
+ }
+ });
+
+ if (!res.ok) throw new Error("Failed to fetch profile");
+
+ const profile = await res.json();
+ console.log(profile);
+ window.profile = profile
+ } catch (err) {
+ console.error(err);
+ }
+}
+
+getProfile().then(() => {
+ let path = "";
+ let defaultNetwork = window.profile.networks[0]
+
+ if(!selectedNetwork()) {
+ path += (defaultNetwork.abbreviation + "/")
+ }
+
+ if(!selectedApp()) {
+ let defaultApp = defaultNetwork.apps[0]
+ path += defaultApp.toLowerCase()
+ }
+
+ window.navigateTo(path)
+ Home()
+})
\ No newline at end of file
diff --git a/ui/public/index.html b/ui/public/index.html
index 25d29f6..f51ed57 100644
--- a/ui/public/index.html
+++ b/ui/public/index.html
@@ -1,5 +1,5 @@
-
+
Parchment
diff --git a/ui/public/pages/Home.js b/ui/public/pages/Home.js
index e7d2127..b6eda06 100644
--- a/ui/public/pages/Home.js
+++ b/ui/public/pages/Home.js
@@ -14,7 +14,7 @@ class Home extends Shadow {
.fontFamily("Nabla")
.fontSize(6.5, em)
.marginLeft(1, rem)
- .color("var(--accent2)")
+ .color("var(--accent)")
})
.marginBottom(1, rem)
@@ -24,7 +24,7 @@ class Home extends Shadow {
HStack(() => {
span("The Community OS")
.fontFamily("Canterbury")
- .color("var(--accent2)")
+ .color("var(--accent)")
.fontSize(2.5, em)
.paddingBottom(1, rem)
})