diff --git a/capacitor.config.json b/capacitor.config.json
index 14befbe..532b34f 100644
--- a/capacitor.config.json
+++ b/capacitor.config.json
@@ -5,10 +5,6 @@
"ios": {
"allowsBackForwardNavigationGestures": true
},
- "server": {
- "url": "http://sam.local:5173",
- "cleartext": true
- },
"plugins": {
"SplashScreen": {
"launchAutoHide": true
diff --git a/ios/App/App/Info.plist b/ios/App/App/Info.plist
index 65f8357..8e8d560 100644
--- a/ios/App/App/Info.plist
+++ b/ios/App/App/Info.plist
@@ -29,6 +29,12 @@
NSAllowsLocalNetworking
+ NSLocationAlwaysAndWhenInUseUsageDescription
+ Used to find keep local information relevant.
+ NSLocationWhenInUseUsageDescription
+ Used to find forums and communities near you
+ NSPhotoLibraryUsageDescription
+ Access your photos to set a profile picture and share with others
UIBackgroundModes
remote-notification
@@ -41,6 +47,8 @@
armv7
+ UIRequiresFullScreen
+
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
@@ -49,15 +57,7 @@
UIInterfaceOrientationPortrait
- UIRequiresFullScreen
-
UIViewControllerBasedStatusBarAppearance
- NSPhotoLibraryUsageDescription
- Access your photos to set a profile picture and share with others
- NSLocationAlwaysAndWhenInUseUsageDescription
- Used to find keep local information relevant.
- NSLocationWhenInUseUsageDescription
- Used to find forums and communities near you
diff --git a/ios/App/Podfile b/ios/App/Podfile
index 015c5f4..c4695eb 100644
--- a/ios/App/Podfile
+++ b/ios/App/Podfile
@@ -12,6 +12,7 @@ def capacitor_pods
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCamera', :path => '../../node_modules/@capacitor/camera'
+ pod 'CapacitorFilesystem', :path => '../../node_modules/@capacitor/filesystem'
pod 'CapacitorGeolocation', :path => '../../node_modules/@capacitor/geolocation'
pod 'CapacitorGoogleMaps', :path => '../../node_modules/@capacitor/google-maps'
pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
diff --git a/ios/App/Podfile.lock b/ios/App/Podfile.lock
index d13a4a2..13b1afa 100644
--- a/ios/App/Podfile.lock
+++ b/ios/App/Podfile.lock
@@ -4,6 +4,9 @@ PODS:
- CapacitorCamera (7.0.2):
- Capacitor
- CapacitorCordova (7.4.4)
+ - CapacitorFilesystem (7.1.8):
+ - Capacitor
+ - IONFilesystemLib (~> 1.1.1)
- CapacitorGeolocation (7.1.5):
- Capacitor
- IONGeolocationLib (= 1.0.1)
@@ -26,12 +29,14 @@ PODS:
- GoogleMaps/Base (8.4.0)
- GoogleMaps/Maps (8.4.0):
- GoogleMaps/Base
+ - IONFilesystemLib (1.1.2)
- IONGeolocationLib (1.0.1)
DEPENDENCIES:
- "Capacitor (from `../../node_modules/@capacitor/ios`)"
- "CapacitorCamera (from `../../node_modules/@capacitor/camera`)"
- "CapacitorCordova (from `../../node_modules/@capacitor/ios`)"
+ - "CapacitorFilesystem (from `../../node_modules/@capacitor/filesystem`)"
- "CapacitorGeolocation (from `../../node_modules/@capacitor/geolocation`)"
- "CapacitorGoogleMaps (from `../../node_modules/@capacitor/google-maps`)"
- "CapacitorHaptics (from `../../node_modules/@capacitor/haptics`)"
@@ -43,6 +48,7 @@ SPEC REPOS:
trunk:
- Google-Maps-iOS-Utils
- GoogleMaps
+ - IONFilesystemLib
- IONGeolocationLib
EXTERNAL SOURCES:
@@ -52,6 +58,8 @@ EXTERNAL SOURCES:
:path: "../../node_modules/@capacitor/camera"
CapacitorCordova:
:path: "../../node_modules/@capacitor/ios"
+ CapacitorFilesystem:
+ :path: "../../node_modules/@capacitor/filesystem"
CapacitorGeolocation:
:path: "../../node_modules/@capacitor/geolocation"
CapacitorGoogleMaps:
@@ -69,6 +77,7 @@ SPEC CHECKSUMS:
Capacitor: 09d9ff8e9618e8c4b3cab2bbee34a17215dd2fef
CapacitorCamera: 6e18d54c8ab30d7dc7b8cd93d96f9b4f57e9202a
CapacitorCordova: bf648a636f3c153f652d312ae145fb508b6ffced
+ CapacitorFilesystem: f54cd6b76be06fa7ceb219cf313d32e0d626ea87
CapacitorGeolocation: b96474c3259dd4a294227ea8ec19140b1837cceb
CapacitorGoogleMaps: 20b5445a532f80dbb120fa99941fd094bcc88af6
CapacitorHaptics: d17da7dd984cae34111b3f097ccd3e21f9feec62
@@ -77,8 +86,9 @@ SPEC CHECKSUMS:
CapacitorSplashScreen: d06ae8804808e9f649a08e7bb7f283c77b688084
Google-Maps-iOS-Utils: 66d6de12be1ce6d3742a54661e7a79cb317a9321
GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d
+ IONFilesystemLib: 21a63377696b2d8fab5632ecfb7d2ac67bddb68a
IONGeolocationLib: 20f9d0248a0b5264511fb57a37e25dd2badf797a
-PODFILE CHECKSUM: 7fad0e16088b635c7bc1980fea245d4a60cc4bbe
+PODFILE CHECKSUM: 32ad5bbf56056f7ee8d159f9eae42fe03e911a61
COCOAPODS: 1.15.2
diff --git a/package.json b/package.json
index 0a52829..8df5c73 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
"dependencies": {
"@capacitor/camera": "^7.0.2",
"@capacitor/core": "^7.4.4",
+ "@capacitor/filesystem": "^7.1.8",
"@capacitor/geolocation": "^7.1.5",
"@capacitor/google-maps": "^7.2.0",
"@capacitor/haptics": "^7.0.3",
diff --git a/src/.env.development b/src/.env.development
index 9206f33..6cf4f39 100644
--- a/src/.env.development
+++ b/src/.env.development
@@ -1 +1 @@
-VITE_API_URL=https://frm.so
\ No newline at end of file
+VITE_API_URL=http://localhost:10002
\ No newline at end of file
diff --git a/src/Home/AuthPage/AuthPage.js b/src/Home/AuthPage/AuthPage.js
deleted file mode 100644
index 5f58f19..0000000
--- a/src/Home/AuthPage/AuthPage.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import { Preferences } from '@capacitor/preferences';
-import "./Login.js";
-import "./Signup.js"
-import "./EnterCode.js"
-
-class AuthPage extends Shadow {
- inputStyles(el) {
- return el
- .background("var(--main)")
- .color("var(--text)")
- .border("1px solid var(--accent)")
- .fontSize(0.9, rem)
- .backgroundColor("var(--searchbackground)")
- .borderRadius(12, px)
- .outline("none")
- .onTouch((start) => {
- if(start) {
- this.style.backgroundColor = "var(--accent)"
- } else {
- this.style.backgroundColor = "var(--searchbackground)"
- }
- })
- }
-
- render() {
- VStack(() => {
- img(window.matchMedia('(prefers-color-scheme: dark)').matches ? "/_/icons/columnwhite.svg" : "/_/icons/logo.svg", window.isMobile() ? "5vmax" : "3vmax")
- .marginTop(5, em)
- .marginLeft(2, em)
- .onClick((done) => {
- window.navigateTo("/")
- })
-
- HStack(() => {
- p("Login")
- .state(this, "selected", function (selected) {
- if(selected === "1") {
- this.fontWeight("bold")
- this.background("var(--loginButton)")
- } else {
- this.fontWeight("normal")
- this.background("transparent")
- }
- })
- .padding(0.75, em)
- .borderRadius(12, px)
- .onTap(() => {
- this.attr("selected", "1")
- })
-
- p("Enter Code")
- .state(this, "selected", function (selected) {
- if(selected === "2") {
- this.fontWeight("bold")
- this.background("var(--loginButton)")
- } else {
- this.fontWeight("normal")
- this.background("transparent")
- }
- })
- .padding(0.75, em)
- .borderRadius(12, px)
- .onTap(() => {
- this.attr("selected", "2")
- })
- })
- .fontFamily("Arial")
- .padding(0.25, em)
- .borderRadius(12, px)
- .background("var(--loginBackground)")
- .color("var(--text)")
- .horizontalAlign("center")
- .margin("auto")
- .marginTop(7.5, em)
- .marginBottom(2, em)
- .gap(0.5, em)
-
- ZStack(() => {
-
- Login()
- .state(this, "selected", function (selected) {
- if(selected === "1") {
- this.display("")
- } else {
- this.display("none")
- }
- })
-
- EnterCode()
- .state(this, "selected", function (selected) {
- if(selected === "2") {
- this.display("flex")
- } else {
- this.display("none")
- }
- })
- })
- })
- .attr("selected", "1")
- .width(100, vw)
- .height(100, vh)
- .margin(0)
- }
-}
-
-register(AuthPage)
\ No newline at end of file
diff --git a/src/Home/AuthPage/EnterCode.js b/src/Home/AuthPage/EnterCode.js
deleted file mode 100644
index 7179e3c..0000000
--- a/src/Home/AuthPage/EnterCode.js
+++ /dev/null
@@ -1,101 +0,0 @@
-import util from "../../util.js"
-import "./Signup.js"
-
-class EnterCode extends Shadow {
- inputStyles(el) {
- return el
- .background("var(--main)")
- .color("var(--text)")
- .border("1px solid var(--accent)")
- .fontSize(0.9, rem)
- .backgroundColor("var(--searchbackground)")
- .borderRadius(12, px)
- .outline("none")
- .onTouch((start) => {
- if (start) {
- this.style.backgroundColor = "var(--accent)"
- } else {
- this.style.backgroundColor = "var(--searchbackground)"
- }
- })
- }
-
- render() {
- VStack(() => {
-
- VStack(() => {
- p("Enter the code given to you by your organization.")
- .color("#614945")
- .maxWidth(70, vw)
- .marginTop(3, em)
-
- input("Code", "70vw")
- .attr({ name: "firstName", type: "text" })
- .margin("auto")
- .marginVertical(1, em)
- .padding(1, em)
- .styles(this.inputStyles)
-
- button("==>")
- .padding(1, em)
- .fontSize(0.9, rem)
- .borderRadius(12, px)
- .background("var(--searchbackground)")
- .color("var(--text)")
- .border("1px solid var(--accent)")
- .boxSizing("border-box")
- .onTouch(function (start) {
- if (start) {
- this.style.backgroundColor = "var(--accent)"
- } else {
- this.style.backgroundColor = "var(--searchbackground)"
- }
- })
- .onClick((done) => {
- if (done) this.submit()
- })
- })
- .state(this, "codeaccepted", function (accepted) {
- if(!accepted) {
- this.display("flex")
- } else {
- this.display("none")
- }
- })
-
- Signup()
- .state(this, "codeaccepted", function (accepted) {
- if(accepted) {
- this.display("")
- } else {
- this.display("none")
- }
- })
- })
- .horizontalAlign("center")
- .display("flex")
-
- this.style.display = "flex"
- }
-
- async submit() {
- console.log("submit")
- const res = await fetch(`${util.HOST}/auth/joincode`, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json', "Accept": "application/json", "X-Client": "mobile" },
- body: JSON.stringify({ code: this.$("input").value })
- });
-
- if (res.ok) {
- console.log("got join code succ")
- this.attr("codeaccepted", "true")
- let { networkId } = await res.json()
- $("signup-").attr("networkid", networkId)
- } else {
- const { error } = await res.json();
- console.error(error)
- }
- }
-}
-
-register(EnterCode)
\ No newline at end of file
diff --git a/src/Home/AuthPage/Login.js b/src/Home/AuthPage/Login.js
deleted file mode 100644
index b17e082..0000000
--- a/src/Home/AuthPage/Login.js
+++ /dev/null
@@ -1,147 +0,0 @@
-import { Preferences } from '@capacitor/preferences';
-import util from "../../util.js"
-
-class Login extends Shadow {
- inputStyles(el) {
- return el
- .background("var(--main)")
- .color("var(--text)")
- .border("1px solid var(--accent)")
- .fontSize(0.9, rem)
- .backgroundColor("var(--searchbackground)")
- .borderRadius(12, px)
- .outline("none")
- .onTouch((start) => {
- if (start) {
- this.style.backgroundColor = "var(--accent)"
- } else {
- this.style.backgroundColor = "var(--searchbackground)"
- }
- })
- }
-
- render() {
- form(() => {
- VStack(() => {
- input("Email", "70vw")
- .attr({ name: "email", type: "email" })
- .margin("auto")
- .marginVertical(1, em)
- .padding(1, em)
- .styles(this.inputStyles)
-
- input("Password", "70vw")
- .attr({ name: "password", type: "password" })
- .margin("auto")
- .marginVertical(1, em)
- .padding(1, em)
- .styles(this.inputStyles)
-
- HStack(() => {
- button("==>")
- .padding(1, em)
- .fontSize(0.9, rem)
- .borderRadius(12, px)
- .background("var(--searchbackground)")
- .color("var(--text)")
- .border("1px solid var(--accent)")
- .boxSizing("border-box")
- .onTouch(function (start) {
- if (start) {
- this.style.backgroundColor = "var(--accent)"
- } else {
- this.style.backgroundColor = "var(--searchbackground)"
- }
- })
- })
- .width(70, vw)
- .margin("auto")
- .fontSize(0.9, rem)
- .paddingLeft(0, em)
- .paddingRight(2, em)
- .marginVertical(1, em)
- .border("1px solid transparent")
-
- p("")
- .state("errortype", function (type) {
- const messages = {
- email: "Please enter a valid email.",
- password: "Please enter a valid password.",
- emailwrong: "Could not find an account with this email.",
- passwordwrong: "Incorrect password.",
- };
-
- if(messages[type]) {
- this.display("")
- this.innerText = messages[type]
- } else {
- this.display("none")
- this.innerText = ""
- }
- })
- .margin("auto")
- .marginTop(1, em)
- .color("var(--text)")
- .fontFamily("Arial")
- .opacity(.7)
- .padding(0.5, em)
- .backgroundColor("var(--darkred)")
- .display("none")
-
- })
- })
- .height(100, pct)
- .onSubmit(async (e) => {
- e.preventDefault();
- const data = {
- email: e.target.$('[name="email"]').value,
- password: e.target.$('[name="password"]').value,
- };
- await this.requestLogin(data);
- })
- }
-
- isValidEmail = (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
- isValidPassword = (password) => password.length >= 7;
-
- async requestLogin(data) {
- const emailValid = this.isValidEmail(data.email.trim() || "");
- const passValid = this.isValidPassword(data.password.trim() || "");
-
- if (!emailValid || !passValid) {
- console.log("invalid", emailValid)
- const errorType = !emailValid ? 'email' : 'password';
-
- this.$("p").attr({ errorType });
- return;
- } else {
- this.$("p").attr({ errorType: "" });
- }
-
- const res = await fetch(`${util.HOST}/auth/login`, {
- method: "POST",
- headers: { "Content-Type": "application/json", "X-Client": "mobile" },
- body: JSON.stringify({
- email: data["email"],
- password: data["password"]
- })
- });
-
- if (res.ok) {
- const { token } = await res.json();
- await Preferences.set({ key: 'auth_token', value: token });
- global.renderHome();
- } else {
- const { error } = await res.json();
- this.errorMessage = error;
- console.error(error)
- if(error.includes("email")) {
- this.$("p").attr({ errorType: "emailwrong" });
- } else {
- this.$("p").attr({ errorType: "passwordwrong" });
- }
- }
- }
-}
-
-register(Login)
\ No newline at end of file
diff --git a/src/Home/AuthPage/Signup.js b/src/Home/AuthPage/Signup.js
deleted file mode 100644
index 298a28b..0000000
--- a/src/Home/AuthPage/Signup.js
+++ /dev/null
@@ -1,214 +0,0 @@
-import { Preferences } from '@capacitor/preferences';
-import util from "../../util.js"
-
-class Signup extends Shadow {
- inputStyles(el) {
- return el
- .background("var(--main)")
- .color("var(--text)")
- .border("1px solid var(--accent)")
- .fontSize(0.9, rem)
- .backgroundColor("var(--searchbackground)")
- .borderRadius(12, px)
- .outline("none")
- .onTouch((start) => {
- if (start) {
- this.style.backgroundColor = "var(--accent)"
- } else {
- this.style.backgroundColor = "var(--searchbackground)"
- }
- })
- }
-
- render() {
- form(() => {
- VStack(() => {
- input("First Name", "70vw")
- .attr({ name: "firstName", type: "text" })
- .margin("auto")
- .marginVertical(1, em)
- .padding(1, em)
- .styles(this.inputStyles)
- input("Last Name", "70vw")
- .attr({ name: "lastName", type: "text" })
- .margin("auto")
- .marginVertical(1, em)
- .padding(1, em)
- .styles(this.inputStyles)
- input("Email", "70vw")
- .attr({ name: "email", type: "email" })
- .margin("auto")
- .marginVertical(1, em)
- .padding(1, em)
- .styles(this.inputStyles)
- input("Password", "70vw")
- .attr({ name: "password", type: "password" })
- .margin("auto")
- .marginVertical(1, em)
- .padding(1, em)
- .styles(this.inputStyles)
- input("Confirm Password", "70vw")
- .attr({ name: "confirmPassword", type: "password" })
- .margin("auto")
- .marginVertical(1, em)
- .padding(1, em)
- .styles(this.inputStyles)
- p("")
- .state("errormessage", function (msg) {
- if(msg) {
- this.display("")
- this.innerText = msg
- } else {
- this.display("none")
- this.innerText = ""
- }
- })
- .margin("auto")
- .marginTop(1, em)
- .color("var(--text)")
- .fontFamily("Arial")
- .opacity(.7)
- .padding(0.5, em)
- .backgroundColor("var(--darkred)")
- .display("none")
- HStack(() => {
- button("==>")
- .padding(1, em)
- .fontSize(0.9, rem)
- .borderRadius(12, px)
- .background("var(--searchbackground)")
- .color("var(--text)")
- .border("1px solid var(--accent)")
- .boxSizing("border-box")
- .onTouch(function (start) {
- if (start) {
- this.style.backgroundColor = "var(--accent)"
- } else {
- this.style.backgroundColor = "var(--searchbackground)"
- }
- })
- })
- .width(70, vw)
- .margin("auto")
- .fontSize(0.9, rem)
- .paddingLeft(0, em)
- .paddingRight(2, em)
- .marginVertical(1, em)
- .marginBottom(10, em)
- .border("1px solid transparent")
- })
- })
- .height(100, pct)
- .onSubmit(async (e) => {
- e.preventDefault();
- const data = new FormData(e.target);
- if (this.verifyInput(data)) {
- await this.requestSignup(data);
- } else {
- console.log(this.errorMessage)
- }
- })
- }
-
- /*
- *******************************************************************************
- NO LONGER WORKS - SEE AUTH ENDPOINT IN SERVER
- *******************************************************************************
- */
- async requestSignup(data) {
- const networkId = this.attr("networkid");
- const res = await fetch(`${util.HOST}/auth/signup`, {
- method: "POST",
- headers: { "Content-Type": "application/json", "X-Client": "mobile" },
- body: JSON.stringify({
- networkId: networkId,
- firstName: data.get("firstName"),
- lastName: data.get("lastName"),
- email: data.get("email"),
- password: data.get("password")
- })
- });
-
- if (res.ok) {
- const { token } = await res.json();
- await Preferences.set({ key: 'auth_token', value: token });
- global.renderHome();
- } else {
- const { error } = await res.json();
- console.error(error)
- this.$("p").attr("errormessage", error)
- }
- }
-
- verifyInput(data) {
- const firstName = data.get("firstName");
- const lastName = data.get("lastName");
- const email = data.get("email");
- const password = data.get("password");
- const confirmPassword = data.get("confirmPassword");
-
- if (!firstName || firstName.trim() === "") {
- this.$("p").attr("errormessage", "First name is required.")
- return false
- } else if (firstName.trim().length < 2) {
- this.$("p").attr("errormessage", "First name must be at least 2 characters.")
- return false
- } else if (!/^[a-zA-Z\s'-]+$/.test(firstName.trim())) {
- this.$("p").attr("errormessage", "First name contains invalid characters.")
- return false
- }
-
- if (!lastName || lastName.trim() === "") {
- this.$("p").attr("errormessage", "Last name is required.")
- return false
- } else if (lastName.trim().length < 2) {
- this.$("p").attr("errormessage", "Last name must be at least 2 characters.")
- return false
- } else if (!/^[a-zA-Z\s'-]+$/.test(lastName.trim())) {
- this.$("p").attr("errormessage", "Last name contains invalid characters.")
- return false
- }
-
- if (!email || email.trim() === "") {
- this.$("p").attr("errormessage", "Email is required.")
- return false
- } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.trim())) {
- this.$("p").attr("errormessage", "Please enter a valid email address.")
- return false
- }
-
- let passwordError = `Password must be at least 7 characters and include an uppercase letter, a lowercase letter, a number, and a special character (!@#$%^&*(),.?":{}|<>)`
-
- if (!password) {
- this.$("p").attr("errormessage", "Password is required.")
- return false
- } else if (password.length < 7) {
- this.$("p").attr("errormessage", passwordError)
- return false
- } else if (!/[A-Z]/.test(password)) {
- this.$("p").attr("errormessage", passwordError)
- return false
- } else if (!/[a-z]/.test(password)) {
- this.$("p").attr("errormessage", passwordError)
- return false
- } else if (!/[0-9]/.test(password)) {
- this.$("p").attr("errormessage", passwordError)
- return false
- } else if (!/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
- this.$("p").attr("errormessage", passwordError)
- return false
- }
-
- if (!confirmPassword) {
- this.$("p").attr("errormessage", "Please confirm your password.")
- return false
- } else if (confirmPassword !== password) {
- this.$("p").attr("errormessage", "Passwords do not match.")
- return false
- }
-
- return true;
- }
-}
-
-register(Signup)
\ No newline at end of file
diff --git a/src/Home/ConnectionError.js b/src/Home/ConnectionError.js
deleted file mode 100644
index dea7068..0000000
--- a/src/Home/ConnectionError.js
+++ /dev/null
@@ -1,23 +0,0 @@
-class ConnectionError extends Shadow {
-
- render() {
- VStack(() => {
- img("/_/icons/column.svg", window.isMobile() ? "5vmax" : "3vmax")
- .position("absolute")
- .top(2, em)
- .left(2, em)
- .onClick((done) => {
- window.navigateTo("/")
- })
-
- p("Error connecting to server. Please try again later!")
- })
- .verticalAlign("center")
- .paddingHorizontal(20, vw)
- .backgroundColor("var(--main)")
- .overflowX("hidden")
- .height(100, vh)
- }
-}
-
-register(ConnectionError)
\ No newline at end of file
diff --git a/src/Home/Home.js b/src/Home/Home.js
deleted file mode 100644
index 6d15977..0000000
--- a/src/Home/Home.js
+++ /dev/null
@@ -1,155 +0,0 @@
-import "../components/Sidebar.js"
-import "../components/AppMenu.js"
-import "../components/AppWindowContainer.js"
-
-css(`
- #homeContainer {
- -webkit-user-select: none;
- }
-`)
-
-/*
-Sidebar Functionality Checklist:
-- Open on Top left network logo touch (WITH transition)
-- Follow finger on swipe from left side of the screen
-- Open if finger swipw travels far enough to the right (WITH velocity-based transition)
-- Re-close if not opened enough of the way (WITH transition)
-
-- Close on touch of home contents (WITH transition)
-- Follow finger on swipe beginning near or anywhere on right of divider between sidebar and home contents
-- Close if finger swipe travels far enough to the left (WITH velocity-based transition)
-- Re-open if not closed enough of the way (WITH transition)
-*/
-
-class Home extends Shadow {
-
- dragStartX = null
- sidebarOpen = false
-
- SIDEBAR_FULL_OPEN = (window.outerWidth * 5) / 6
- SIDEBAR_START_THRESHOLD = window.outerWidth / 10
- SIDEBAR_CLOSE_DECISION = (window.outerWidth * 2) / 3
- SIDEBAR_OPEN_DECISION = (window.outerWidth / 3)
-
- constructor() {
- super()
- }
-
- render() {
- ZStack(() => {
- Sidebar(this.SIDEBAR_FULL_OPEN)
-
- ZStack(() => {
-
- VStack(() => {
- AppWindowContainer()
-
- AppMenu()
- })
- .height(100, pct)
- .minHeight(0)
- })
- .left(0, px)
- .backgroundColor("var(--main)")
- .overflowX("hidden")
- .height(window.visualViewport.height, px)
- .position("fixed")
- .borderLeft("1px solid var(--accent)")
- .onTouch((start, e) => {
- if(this.sidebarOpen) {
- this.sidebarOpenTouch(start, e)
- } else {
- this.sidebarClosedTouch(start, e)
- }
- })
- .attr({ id: "homeContainer" })
- })
- .userSelect("none")
- }
-
- openSidebar(duration = 200) {
- const home = this.$("#homeContainer");
- home.style.transition = `left ${duration}ms`;
- home.style.left = `${this.SIDEBAR_FULL_OPEN}px`;
- this.sidebarOpen = true;
- this.dragStartX = null
- setTimeout(() => home.style.transition = "", duration);
- }
-
- closeSidebar(duration = 200) {
- const home = this.$("#homeContainer");
- home.style.transition = `left ${duration}ms`;
- home.style.left = "0px";
- this.sidebarOpen = false;
- this.dragStartX = null
- setTimeout(() => home.style.transition = "", duration);
- }
-
- sidebarOpenTouch(start, e) {
- if(start) {
- let amount = e.targetTouches[0].clientX
- if(amount > (this.SIDEBAR_FULL_OPEN - this.SIDEBAR_START_THRESHOLD)) {
- this.dragStartX = e.touches[0].clientX
- this.dragStartTime = Date.now(); // ⬅ track start time
- e.stopPropagation();
- document.addEventListener("touchmove", this.moveSidebar)
- }
- } else {
- if(!this.dragStartX) return;
-
- let endX = e.changedTouches[0].clientX
- let duration = this.getDuration(this.dragStartX, endX);
- if(Math.abs(this.dragStartX - endX) < 5) { // 2 conditions are separated so this one doesn't close instantly
- this.closeSidebar()
- } else if(endX < this.SIDEBAR_CLOSE_DECISION) {
- this.closeSidebar(duration)
- } else {
- this.openSidebar(duration)
- }
-
- document.removeEventListener("touchmove", this.moveSidebar)
- }
- }
-
- sidebarClosedTouch(start, e) {
- if(start) {
- let amount = e.targetTouches[0].clientX
- if(amount < this.SIDEBAR_START_THRESHOLD) {
- this.dragStartX = e.touches[0].clientX
- this.dragStartTime = Date.now();
- e.stopPropagation();
- document.addEventListener("touchmove", this.moveSidebar)
- }
- } else {
- if(!this.dragStartX) return;
-
- let endX = e.changedTouches[0].clientX
- let duration = this.getDuration(this.dragStartX, endX);
- if(endX > this.SIDEBAR_OPEN_DECISION) {
- this.openSidebar(duration)
- } else {
- this.closeSidebar(duration)
- }
-
- document.removeEventListener("touchmove", this.moveSidebar)
- }
- }
-
- moveSidebar = (e) => {
- let amount = e.targetTouches[0].clientX
- if(e.targetTouches[0] && amount < this.SIDEBAR_FULL_OPEN) {
- this.$("#homeContainer").style.left = `${amount}px`
- }
- }
-
- getDuration(startX, endX) {
- const distance = Math.abs(endX - startX);
- const elapsed = Date.now() - this.dragStartTime;
- const velocity = distance / elapsed; // px per ms
-
- const duration = Math.round(distance / velocity); // time to cover remaining distance
- return Math.min(Math.max(duration, 50), 200); // clamp between 50ms and 200ms
- }
-}
-
-register(Home)
\ No newline at end of file
diff --git a/src/Home/Login.js b/src/Home/Login.js
deleted file mode 100644
index 5c65b80..0000000
--- a/src/Home/Login.js
+++ /dev/null
@@ -1,61 +0,0 @@
-class Login extends Shadow {
- inputStyles(el) {
- return el
- .background("var(--main)")
- .color("var(--text)")
- .border("1px solid var(--accent)")
- .fontSize(0.9, rem)
- .backgroundColor("var(--accentdark)")
- .borderRadius(12, px)
- .outline("none")
- .onTouch((start) => {
- if(start) {
- this.style.backgroundColor = "var(--accent)"
- } else {
- this.style.backgroundColor = "var(--accentdark)"
- }
- })
- }
-
- render() {
- ZStack(() => {
- img(window.matchMedia('(prefers-color-scheme: dark)') ? "/_/icons/columnwhite.svg" : "/_/icons/logo.svg", window.isMobile() ? "5vmax" : "3vmax")
- .position("absolute")
- .top(5, em)
- .left(2, em)
- .onClick((done) => {
- window.navigateTo("/")
- })
-
- form(() => {
- input("Email", "70vw")
- .attr({name: "email", type: "email"})
- .margin(1, em)
- .padding(1, em)
- .styles(this.inputStyles)
- input("Password", "70vw")
- .attr({name: "password", type: "password"})
- .margin(1, em)
- .padding(1, em)
- .styles(this.inputStyles)
- button("==>")
- .margin(1, em)
- .padding(1, em)
- .fontSize(0.9, rem)
- .borderRadius(12, px)
- .background("var(--accent)")
- .color("var(--text)")
- .border("1px solid var(--accent)")
- })
- .attr({action: "/login", method: "POST"})
- .x(50, vw).y(50, vh)
- .center()
- })
- .background("var(--main)")
- .width(100, vw)
- .height(100, pct)
- .margin(0)
- }
-}
-
-register(Login)
\ No newline at end of file
diff --git a/src/Profile/Profile.js b/src/Profile/Profile.js
deleted file mode 100644
index f0bbc3f..0000000
--- a/src/Profile/Profile.js
+++ /dev/null
@@ -1,222 +0,0 @@
-import util from "../util";
-
-css(`
- profile- textarea::-webkit-scrollbar {
- display: none;
- width: 0px;
- height: 0px;
- }
-
- profile- textarea::-webkit-scrollbar-thumb {
- background: transparent;
- }
-
- profile- textarea::-webkit-scrollbar-track {
- background: transparent;
- }
-`)
-
-class Profile extends Shadow {
- constructor() {
- super()
- this.profile = global.profile
- this.bioText = global.profile.bio ?? ""
- }
-
- render() {
- ZStack(() => {
- div("➩")
- .width(3, rem)
- .height(3, rem)
- .borderRadius(50, pct)
- .border("1.5px solid var(--divider)")
- .position("absolute")
- .fontSize(2, em)
- .transform("rotate(180deg)")
- .top(3, rem)
- .left(2, rem)
- .zIndex(1001)
- .display("flex")
- .alignItems("center")
- .justifyContent("center")
- .transition("scale .2s")
- .state("touched", function (touched) {
- if(touched) {
- this.scale("1.5")
- this.color("var(--darkaccent)")
- this.backgroundColor("var(--divider)")
- } else {
- this.scale("")
- this.color("var(--divider)")
- this.backgroundColor("var(--darkaccent)")
- }
- })
- .onTouch(function (start) {
- if(start) {
- this.attr({touched: "true"})
- } else {
- this.attr({touched: ""})
- }
- })
- .onClick((done) => {
- if(done)
- $("appwindowcontainer-").closeProfile()
- })
-
- form(() => {
- input("Image Upload", "0px", "0px")
- .attr({ name: "image-upload", type: "file" })
- .display("none")
- .visibility("hidden")
- .onChange((e) => {
- this.handleUpload(e.target.files[0]);
- })
-
- VStack(() => {
- HStack(() => {
- if (global.profile.image_path) {
- img(`${util.HOST}${global.profile.image_path}`, "10em", "10em")
- .borderRadius(100, pct)
- }
- })
- .boxSizing("border-box")
- .height(10, em)
- .width(10, em)
- .border("1px solid var(--accent)")
- .borderRadius(100, pct)
- .background("var(--darkaccent)")
- .onTap(() => {
- const inputSelector = this.$('[name="image-upload"]');
- inputSelector.click()
- })
-
- p("Tap to edit")
- .color("var(--headertext)")
- .opacity(0.5)
- .marginTop(0.5, em)
-
- h1(this.profile.first_name + " " + this.profile.last_name)
- .color("var(--headertext")
- .width(70, pct)
- .marginVertical(0.25, em)
- .textAlign("center")
-
- p("Joined " + this.convertDate(this.profile.created))
- .color("var(--headertext)")
- .marginBottom(0.5, em)
-
- h2("Bio")
- .color("var(--headertext")
- .margin(0)
- .paddingVertical(0.9, em)
- .borderTop("2px solid var(--divider)")
- .width(70, pct)
- .textAlign("center")
-
- textarea(this.bioText ? this.bioText : "Tap to start typing...")
- .attr({ name: "bioinput" })
- .padding(1, em)
- .width(90, pct)
- .height(15, em)
- .boxSizing("border-box")
- .background("var(--searchbackground)")
- .color("var(--darktext)")
- .border("1px solid color-mix(in srgb, var(--accent) 60%, transparent)")
- .borderRadius(12, px)
- .fontFamily("Arial")
- .fontSize(1.1, em)
- .outline("none")
- .onAppear((e) => {
- if (this.bioText) {
- $("profile- textarea").innerText = this.bioText
- }
- })
- .lineHeight(1.2, em)
-
- button("Save Bio")
- .padding(1, em)
- .fontSize(1.1, em)
- .borderRadius(12, px)
- .background("var(--searchbackground)")
- .color("var(--text)")
- .border("1px solid var(--accent)")
- .boxSizing("border-box")
- .marginVertical(0.75, em)
- })
- .horizontalAlign("center")
- .marginTop(5, em)
- })
- .onSubmit(async (e) => {
- e.preventDefault();
- const newBio = new FormData(e.target).get("bioinput");
- console.log(this.profile)
- if (newBio.trim() !== this.profile.bio?.trim()) {
- const result = await server.editBio(newBio, this.profile.id)
- const { bio, updated_at } = result.data
- global.profile.bio = bio
- global.profile.updated_at = updated_at
- this.profile = global.profile
- }
- })
- })
- .backgroundColor("var(--main)")
- .overflowX("hidden")
- .height(window.visualViewport.height - 20, px)
- .boxSizing("border-box")
- .width(100, pct)
- .position("fixed")
- .top(100, vh)
- .zIndex(5)
- .transition("top .4s ")
- .pointerEvents("none")
- }
-
- async handleUpload(file) {
- try {
- const body = new FormData();
- body.append('image', file);
- const res = await util.authFetch(`${util.HOST}/profile/upload-image`, {
- method: "POST",
- credentials: "include",
- headers: {
- "Accept": "application/json"
- },
- body: body
- });
-
- if(res.status === 401) {
- return res.status
- }
- if (!res.ok) return res.status;
- const data = await res.json()
- global.profile = data.member
- console.log(global.profile)
- } catch (err) { // Network error / Error reaching server
- console.error(err);
- }
- }
-
- convertDate(rawDate) {
- const parsed = new Date(rawDate);
-
- if (isNaN(parsed.getTime())) return rawDate;
-
- const month = parsed.toLocaleString("en-US", { month: "long", timeZone: "UTC" });
- const day = parsed.getUTCDate();
- const year = parsed.getUTCFullYear();
-
- const ordinal = (n) => {
- const mod100 = n % 100;
- if (mod100 >= 11 && mod100 <= 13) return `${n}th`;
- switch (n % 10) {
- case 1: return `${n}st`;
- case 2: return `${n}nd`;
- case 3: return `${n}rd`;
- default: return `${n}th`;
- }
- };
- return `${month} ${ordinal(day)}, ${year}`;
- }
-}
-
-register(Profile)
\ No newline at end of file
diff --git a/src/_/code/ws/Connection.js b/src/_/code/ws/Connection.js
deleted file mode 100644
index f1ff450..0000000
--- a/src/_/code/ws/Connection.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import { Preferences } from '@capacitor/preferences';
-import util from "../../../util.js"
-
-class Connection {
- connectionTries = 0;
- ws;
- receiveCB;
-
- constructor(receiveCB) {
- this.receiveCB = receiveCB;
- }
-
- init = async () => {
- const { value: token } = await Preferences.get({ key: 'auth_token' });
- return new Promise((resolve, reject) => {
- let url = ""
- if(util.HOST) {
- url = "wss://" + util.HOST.replace(/^https?:\/\//, '') + "/ws" + `?token=${token}`;
- } else {
- url = "ws://" + window.location.host + "/ws"
- }
-
- this.ws = new WebSocket(url);
-
- this.ws.addEventListener('open', () => {
- 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
- });
- });
- }
-
- checkOpen = async () => {
- if (this.ws.readyState === WebSocket.OPEN) {
- return true;
- } else {
- await this.sleep(this.connectionTries < 20 ? 5000 : 60000);
- this.connectionTries++;
- console.log('Reestablishing connection');
- await this.init();
- }
- }
-
- sleep = (time) => new Promise(resolve => setTimeout(resolve, time));
-
- send = (msg) => {
- 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;
diff --git a/src/_/code/ws/Socket.js b/src/_/code/ws/Socket.js
deleted file mode 100644
index 55c249c..0000000
--- a/src/_/code/ws/Socket.js
+++ /dev/null
@@ -1,49 +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);
- }
-
- async init() {
- await this.connection.init()
- }
-
- 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
- }));
- }
-}
\ No newline at end of file
diff --git a/src/_/code/ws/shim/fs.js b/src/_/code/ws/shim/fs.js
deleted file mode 100644
index 56004c9..0000000
--- a/src/_/code/ws/shim/fs.js
+++ /dev/null
@@ -1 +0,0 @@
-export default {}
\ No newline at end of file
diff --git a/src/_/imgs/logo.png b/src/_/imgs/logo.png
deleted file mode 100644
index b7895e9..0000000
Binary files a/src/_/imgs/logo.png and /dev/null differ
diff --git a/src/apps/Forum/Forum.js b/src/apps/Forum/Forum.js
deleted file mode 100644
index e5fa756..0000000
--- a/src/apps/Forum/Forum.js
+++ /dev/null
@@ -1,83 +0,0 @@
-// import './ForumPanel.js'
-
-// css(`
-// forum- {
-// font-family: 'Bona';
-// }
-
-// forum- input::placeholder {
-// font-family: 'Bona Nova';
-// font-size: 0.9em;
-// color: var(--accent);
-// }
-
-// input::placeholder {
-// font-family: Arial;
-// }
-
-// input[type="checkbox"] {
-// appearance: none; /* remove default style */
-// -webkit-appearance: none;
-// width: 1em;
-// height: 1em;
-// border: 1px solid var(--accent);
-// }
-
-// input[type="checkbox"]:checked {
-// background-color: var(--red);
-// }
-// `)
-
-// class Forum extends Shadow {
-// render() {
-// ZStack(() => {
-// VStack(() => {
-
-// ForumPanel()
-
-// input("Message", "70%")
-// .paddingVertical(0.75, em)
-// .boxSizing("border-box")
-// .paddingHorizontal(2, em)
-// .color("var(--accent)")
-// .background("black")
-// .marginBottom(1, em)
-// .border("0.5px solid #6f5e4e")
-// .borderRadius(100, px)
-// .fontFamily("Arial")
-// .fontSize(1, em)
-// .onKeyDown(async function(e) {
-// if (e.key === "Enter") {
-// let msg = {
-// forum: global.currentNetwork.abbreviation,
-// text: this.value
-// }
-// await global.socket.send({
-// app: "FORUM",
-// operation: "SEND",
-// msg: msg
-// })
-// this.value = ""
-// }
-// })
-// })
-// .gap(0.5, em)
-// .boxSizing("border-box")
-// .width(100, pct)
-// .height(100, pct)
-// .horizontalAlign("center")
-// .verticalAlign("end")
-// .minHeight(0)
-// })
-// .backgroundColor("var(--main)")
-// .boxSizing("border-box")
-// .paddingVertical(1, em)
-// .width(100, pct)
-// .minHeight(0)
-// .flex("1 1 auto")
-// }
-
-
-// }
-
-// register(Forum)
\ No newline at end of file
diff --git a/src/apps/Forum/ForumPanel.js b/src/apps/Forum/ForumPanel.js
deleted file mode 100644
index eef24e2..0000000
--- a/src/apps/Forum/ForumPanel.js
+++ /dev/null
@@ -1,193 +0,0 @@
-// import "../../components/LoadingCircle.js"
-
-// css(`
-// forumpanel- {
-// scrollbar-width: none;
-// -ms-overflow-style: none;
-// }
-
-// forumpanel-::-webkit-scrollbar {
-// display: none;
-// width: 0px;
-// height: 0px;
-// }
-
-// forumpanel-::-webkit-scrollbar-thumb {
-// background: transparent;
-// }
-
-// forumpanel-::-webkit-scrollbar-track {
-// background: transparent;
-// }
-// `)
-
-// class ForumPanel extends Shadow {
-// messages = []
-// isSending = false
-
-// render() {
-// VStack(() => {
-// if(this.messages.length > 0) {
-// let previousDate = null
-
-// for(let i=0; i {
-// HStack(() => {
-// h3(isMe ? "Me" : message.sentBy)
-// .color(isMe ? "var(--quillred)" : "var(--brown")
-// .margin(0)
-
-// h3(`${date} ${time}`)
-// .opacity(0.5)
-// .color("var(--brown)")
-// .margin(0)
-// .marginLeft(0.5, em)
-// .fontSize(1, em)
-
-// if (message.edited) {
-// p("(edited)")
-// .color("var(--brown)")
-// .letterSpacing(0.8, "px")
-// .opacity(0.8)
-// .fontWeight("bold")
-// .paddingLeft(0.25, em)
-// .fontSize(0.9, em)
-// }
-// })
-// .verticalAlign("center")
-// .marginBottom(0.1, em)
-
-// p(message.text)
-// .color("var(--accent)")
-// .borderLeft("1.5px solid var(--divider)")
-// .borderBottomLeftRadius("7.5px")
-// .paddingLeft(0.5, em)
-// .marginHorizontal(0.2, em)
-// .paddingVertical(0.2, em)
-// .boxSizing("border-box")
-// })
-// .marginBottom(0.05, em)
-// .onClick(async (finished, e) => {
-// if (finished) {
-// console.log(message.id)
-// let msg = {
-// forum: global.currentNetwork.abbreviation,
-// id: message.id,
-// text: "EDITED TEXT TEST!"
-// }
-// await global.socket.send({
-// app: "FORUM",
-// operation: "PUT",
-// msg: msg
-// })
-// }
-// })
-// }
-// } else {
-// LoadingCircle()
-// }
-// })
-// .gap(1, em)
-// .fontSize(1.1, em)
-// .boxSizing("border-box")
-// .flex("1 1 auto")
-// .minHeight(0)
-// .overflowY("auto")
-// .width(100, pct)
-// .paddingBottom(2, em)
-// .paddingHorizontal(4, pct)
-// .backgroundColor("var(--main)")
-// .onAppear(async () => {
-// requestAnimationFrame(() => {
-// this.scrollTo({ top: 0, behavior: "smooth" });
-// });
-// if (!this.isSending) {
-// this.isSending = true
-// let res = await global.socket.send({
-// app: "FORUM",
-// operation: "GET",
-// msg: {
-// forum: global.currentNetwork.abbreviation,
-// by: "network",
-// authorId: -999 // default
-// }
-// })
-// if(!res) console.error("failed to get messages")
-// if(res.msg.length > 0 && this.messages.length === 0) {
-// this.messages = res.msg.reverse()
-// this.rerender()
-// }
-// this.isSending = false
-// }
-// })
-// .onEvent("new-post", this.onNewPost)
-// .onEvent("deleted-post", this.onDeletedPost)
-// .onEvent("edited-post", this.onEditedPost)
-// }
-
-// onNewPost = (e) => {
-// let newPost = e.detail
-// if (this.messages && !this.messages.some(post => post.id === newPost.id)) {
-// this.messages.unshift(newPost)
-// this.rerender()
-// }
-// }
-
-// onDeletedPost = (e) => {
-// let deletedId = e.detail
-// const i = this.messages.findIndex(post => post.id === deletedId)
-// if (i !== -1) this.messages.splice(i, 1);
-// this.rerender()
-// }
-
-// onEditedPost = (e) => {
-// let editedPost = e.detail
-// const i = this.messages.findIndex(post => post.id === editedPost.id)
-// if (i !== -1) {
-// this.messages.splice(i, 1)
-// this.messages.unshift(editedPost)
-// }
-
-// this.rerender()
-// }
-
-// parseDate(str) {
-// // Format: MM.DD.YYYY-HH:MM:SSxxxxxx(am|pm)
-// const match = str.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})-(\d{1,2}):(\d{2}).*(am|pm)$/i);
-// if (!match) return null;
-
-// const [, mm, dd, yyyy, hh, min, ampm] = match;
-// const date = `${mm}/${dd}/${yyyy}`;
-// const time = `${hh}:${min}${ampm.toLowerCase()}`;
-
-// return { date, time };
-// }
-
-// formatTime(str) {
-// const match = str.match(/-(\d+:\d+):\d+.*(am|pm)/i);
-// if (!match) return null;
-
-// const [_, hourMin, ampm] = match;
-// return hourMin + ampm.toLowerCase();
-// }
-// }
-
-// register(ForumPanel)
\ No newline at end of file
diff --git a/src/apps/Market/Market.js b/src/apps/Market/Market.js
deleted file mode 100644
index e3bceeb..0000000
--- a/src/apps/Market/Market.js
+++ /dev/null
@@ -1,105 +0,0 @@
-import "./MarketSidebar.js"
-import "./MarketGrid.js"
-
-css(`
- market- {
- font-family: 'Bona';
- }
-
- market- input::placeholder {
- font-family: 'Bona Nova';
- font-size: 0.9em;
- color: var(--accent);
- }
-
- input[type="checkbox"] {
- appearance: none; /* remove default style */
- -webkit-appearance: none;
- width: 1em;
- height: 1em;
- border: 1px solid var(--accent);
- }
-
- input[type="checkbox"]:checked {
- background-color: var(--red);
- }
-`)
-
-class Market extends Shadow {
-
- listings = [
- {
- title: "Shield Lapel Pin",
- stars: "5",
- reviews: 1,
- price: "$12",
- company: "Hyperia",
- type: "new",
- image: "/db/images/1",
- madeIn: "America"
- }
- ]
-
- render() {
- ZStack(() => {
- HStack(() => {
- MarketSidebar()
-
- MarketGrid(this.listings)
- })
- .width(100, "%")
- .x(0).y(13, vh)
-
- HStack(() => {
- input("Search for products... (Coming Soon!)", "45vw")
- .attr({
- "type": "text",
- "disabled": "true"
- })
- .fontSize(1.1, em)
- .paddingLeft(1.3, em)
- .background("transparent")
- .border("0.5px solid var(--divider)")
- .outline("none")
- .color("var(--accent)")
- .opacity(0.5)
- .borderRadius(10, px)
- .background("grey")
- .cursor("not-allowed")
-
- button("+ Add Item")
- .width(7, em)
- .marginLeft(1, em)
- .borderRadius(10, px)
- .background("transparent")
- .border("0.5px solid var(--accent2)")
- .color("var(--accent)")
- .fontFamily("Bona Nova")
- .onHover(function (hovering) {
- if(hovering) {
- this.style.background = "var(--green)"
-
- } else {
- this.style.background = "transparent"
-
- }
- })
- .onClick((clicking) => {
- console.log(this, "clicked")
- })
-
- })
- .x(55, vw).y(4, vh)
- .position("absolute")
- .transform("translateX(-50%)")
- })
- .width(100, "%")
- .height(100, "%")
- }
-
- connectedCallback() {
- // Optional additional logic
- }
-}
-
-register(Market)
diff --git a/src/apps/Market/MarketGrid.js b/src/apps/Market/MarketGrid.js
deleted file mode 100644
index 8740f9e..0000000
--- a/src/apps/Market/MarketGrid.js
+++ /dev/null
@@ -1,140 +0,0 @@
-class MarketGrid extends Shadow {
- listings;
-
- constructor(listings) {
- super()
- this.listings = listings
- }
-
- boldUntilFirstSpace(text) {
- if(!text) return
- const index = text.indexOf(' ');
- if (index === -1) {
- // No spaces — bold the whole thing
- return `${text}`;
- }
- return `${text.slice(0, index)}${text.slice(index)}`;
- }
-
- render() {
- VStack(() => {
- h3("Results")
- .marginTop(0.1, em)
- .marginBottom(1, em)
- .marginLeft(0.4, em)
- .color("var(--accent)")
- .opacity(0.7)
-
- if (this.listings.length > 0) {
- ZStack(() => {
- // BuyModal()
-
- let params = new URLSearchParams(window.location.search);
-
- const hyperiaMade = params.get("hyperia-made") === "true";
- const americaMade = params.get("america-made") === "true";
- const newItem = params.get("new") === "true";
- const usedItem = params.get("used") === "true";
-
-
- let filtered = this.listings;
- if (hyperiaMade) {
- filtered = filtered.filter(item => item.madeIn === "Hyperia");
- }
- if (americaMade) {
- filtered = filtered.filter(item => item.madeIn === "America");
- }
- if (newItem) {
- filtered = filtered.filter(item => item.type === "new");
- }
- if (usedItem) {
- filtered = filtered.filter(item => item.type === "used");
- }
-
- for (let i = 0; i < filtered.length; i++) {
- const rating = filtered[i].stars
- const percent = (rating / 5)
-
- VStack(() => {
- img(filtered[i].image)
- .marginBottom(0.5, em)
-
- p(filtered[i].company)
- .marginBottom(0.5, em)
-
- p(filtered[i].title)
- .fontSize(1.2, em)
- .fontWeight("bold")
- .marginBottom(0.5, em)
-
- HStack(() => {
- p(filtered[i].stars)
- .marginRight(0.2, em)
-
- ZStack(() => {
- div("★★★★★") // Empty stars (background)
- .color("#ccc")
-
- div("★★★★★") // Filled stars (foreground, clipped by width)
- .color("#ffa500")
- .position("absolute")
- .top(0)
- .left(0)
- .whiteSpace("nowrap")
- .overflow("hidden")
- .width(percent * 5, em)
- })
- .display("inline-block")
- .position("relative")
- .fontSize(1.2, em)
- .lineHeight(1)
-
- p(filtered[i].reviews)
- .marginLeft(0.2, em)
- })
- .marginBottom(0.5, em)
-
- p(filtered[i].price)
- .fontSize(1.75, em)
- .marginBottom(0.5, em)
-
- button("Coming Soon!")
- .onClick((finished) => {
- if(finished) {
-
- }
- })
- .onHover(function (hovering) {
- if(hovering) {
- this.style.backgroundColor = "var(--green)"
- } else {
- this.style.backgroundColor = ""
- }
- })
-
- })
- .padding(1, em)
- .border("1px solid var(--accent2)")
- .borderRadius(5, "px")
- }
- })
- .display("grid")
- .gridTemplateColumns("repeat(auto-fill, minmax(250px, 1fr))")
- .gap(1, em)
- } else {
- p("No Listings!")
- }
- })
- .onQueryChanged(() => {
- console.log("query did change yup")
- this.rerender()
- })
- .height(100, vh)
- .paddingLeft(2, em)
- .paddingRight(2, em)
- .gap(0, em)
- .width(100, "%")
- }
-}
-
-register(MarketGrid)
\ No newline at end of file
diff --git a/src/apps/Market/MarketSidebar.js b/src/apps/Market/MarketSidebar.js
deleted file mode 100644
index 9324618..0000000
--- a/src/apps/Market/MarketSidebar.js
+++ /dev/null
@@ -1,85 +0,0 @@
-class MarketSidebar extends Shadow {
-
- handleChecked(e) {
- let checked = e.target.checked
- let label = $(`label[for="${e.target.id}"]`).innerText
- if(checked) {
- window.setQuery(label.toLowerCase(), true)
- } else {
- window.setQuery(label.toLowerCase(), null)
- }
- }
-
- render() {
- VStack(() => {
-
- p("Make")
-
- HStack(() => {
- input()
- .attr({
- "type": "checkbox",
- "id": "hyperia-check"
- })
- .onChange(this.handleChecked)
- label("Hyperia-Made")
- .attr({
- "for": "hyperia-check"
- })
- .marginLeft(0.5, em)
- })
-
- HStack(() => {
- input()
- .attr({
- "type": "checkbox",
- "id": "america-check"
- })
- .onChange(this.handleChecked)
- label("America-Made")
- .attr({
- "for": "america-check"
- })
- .marginLeft(0.5, em)
- })
-
- p("Condition")
-
- HStack(() => {
- input()
- .attr({
- "type": "checkbox",
- "id": "new-check"
- })
- .onChange(this.handleChecked)
- label("New")
- .attr({
- "for": "new-check"
- })
- .marginLeft(0.5, em)
- })
-
- HStack(() => {
- input()
- .attr({
- "type": "checkbox",
- "id": "used-check"
- })
- .onChange(this.handleChecked)
- label("Used")
- .attr({
- "for": "used-check"
- })
- .marginLeft(0.5, em)
- })
- })
- .paddingTop(12, vh)
- .paddingLeft(3, em)
- .paddingRight(3, em)
- .gap(1, em)
- .minWidth(10, vw)
- .userSelect('none')
- }
-}
-
-register(MarketSidebar)
\ No newline at end of file
diff --git a/src/apps/Messages/Messages.js b/src/apps/Messages/Messages.js
deleted file mode 100644
index 939ff72..0000000
--- a/src/apps/Messages/Messages.js
+++ /dev/null
@@ -1,189 +0,0 @@
-import "./MessagesSidebar.js"
-import "./MessagesPanel.js"
-
-css(`
- messages- {
- font-family: 'Bona';
- }
-
- messages- input::placeholder {
- font-family: 'Bona Nova';
- font-size: 0.9em;
- color: var(--accent);
- }
-
- input[type="checkbox"] {
- appearance: none; /* remove default style */
- -webkit-appearance: none;
- width: 1em;
- height: 1em;
- border: 1px solid var(--accent);
- }
-
- input[type="checkbox"]:checked {
- background-color: var(--red);
- }
-`)
-
-class Messages extends Shadow {
- conversations = []
- selectedConvoID = null
- onConversationSelect(i) {
- console.log("convo selected: ", i)
- this.selectedConvoID = i
- this.$("messagessidebar-").rerender()
- this.$("messagespanel-").rerender()
- }
-
- getConvoFromID(id) {
- for(let i=0; i {
- HStack(() => {
- MessagesSidebar(this.conversations, this.selectedConvoID, this.onConversationSelect)
-
- VStack(() => {
- if(this.getConvoFromID(this.selectedConvoID)) {
- MessagesPanel(this.getConvoFromID(this.selectedConvoID).messages)
- } else {
- MessagesPanel()
- }
-
- input("Send Message", "93%")
- .paddingVertical(1, em)
- .paddingHorizontal(2, em)
- .color("var(--accent)")
- .background("var(--darkbrown)")
- .marginBottom(6, em)
- .border("none")
- .fontSize(1, em)
- .onKeyDown((e) => {
- if (e.key === "Enter") {
- global.socket.send({app: "MESSAGES", operation: "SEND", msg: { conversation: `CONVERSATION-${this.selectedConvoID}`, text: e.target.value }})
- e.target.value = ""
- }
- })
- })
- .gap(1, em)
- .width(100, pct)
- .horizontalAlign("center")
- .verticalAlign("end")
- })
- .onAppear(async () => {
- let res = await global.socket.send({app: "MESSAGES", operation: "GET"})
- if(!res) console.error("failed to get messages")
-
- if(res.msg.length > 0 && this.conversations.length === 0) {
- this.conversations = res.msg
- this.selectedConvoID = this.conversations[0].id
- this.rerender()
- }
-
- window.addEventListener("new-message", (e) => {
- let convoID = e.detail.conversationID
- let messages = e.detail.messages
- let convo = this.getConvoFromID(convoID)
- convo.messages = messages
- this.rerender()
- })
- })
- .width(100, pct)
- .height(87, pct)
- .x(0).y(13, pct)
-
- VStack(() => {
- p("Add Message")
-
- input("enter email...")
- .color("var(--accent)")
- .onKeyDown(function (e) {
- if (e.key === "Enter") {
- global.socket.send({app: "MESSAGES", operation: "ADDCONVERSATION", msg: {email: this.value }})
- this.value = ""
- }
- })
-
- p("x")
- .onClick(function (done) {
- if(done) {
- this.parentElement.style.display = "none"
- }
- })
- .xRight(2, em).y(2, em)
- .fontSize(1.4, em)
- .cursor("pointer")
-
- })
- .gap(1, em)
- .verticalAlign("center")
- .horizontalAlign("center")
- .backgroundColor("black")
- .border("1px solid var(--accent)")
- .position("fixed")
- .x(50, vw).y(50, pct)
- .center()
- .width(60, vw)
- .height(60, pct)
- .display("none")
- .attr({id: "addPanel"})
-
- HStack(() => {
- input("Search messages... (Coming Soon!)", "45vw")
- .attr({
- "type": "text",
- "disabled": "true"
- })
- .fontSize(1.1, em)
- .paddingLeft(1.3, em)
- .background("transparent")
- .border("0.5px solid var(--divider)")
- .outline("none")
- .color("var(--accent)")
- .opacity(0.5)
- .borderRadius(10, px)
- .background("grey")
- .cursor("not-allowed")
-
- button("+ New Message")
- .width(13, em)
- .marginLeft(1, em)
- .borderRadius(10, px)
- .background("transparent")
- .border("0.5px solid var(--divider)")
- .color("var(--accent)")
- .fontFamily("Bona Nova")
- .onHover(function (hovering) {
- if(hovering) {
- this.style.background = "var(--green)"
-
- } else {
- this.style.background = "transparent"
-
- }
- })
- .onClick((done) => {
- console.log("click")
- if(done) {
- this.$("#addPanel").style.display = "flex"
- }
- console.log(this, "clicked")
- })
-
- })
- .x(55, vw).y(4, pct)
- .position("absolute")
- .transform("translateX(-50%)")
- })
- .boxSizing("border-box")
- .height(100, pct)
- .width(100, pct)
- }
-}
-
-register(Messages)
\ No newline at end of file
diff --git a/src/apps/Messages/MessagesPanel.js b/src/apps/Messages/MessagesPanel.js
deleted file mode 100644
index b608212..0000000
--- a/src/apps/Messages/MessagesPanel.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import "../../components/LoadingCircle.js"
-
-class MessagesPanel extends Shadow {
- messages
-
- constructor(messages) {
- super()
- this.messages = messages
- }
-
- render() {
- VStack(() => {
- if(this.messages) {
- for(let i=0; i {
- HStack(() => {
- p(message.from.firstName + " " + message.from.lastName)
- .fontWeight("bold")
- .marginBottom(0.3, em)
-
- p(util.formatTime(message.time))
- .opacity(0.2)
- .marginLeft(1, em)
- })
- p(message.text)
- })
- .paddingVertical(0.5, em)
- .marginLeft(fromMe ? 70 : 0, pct)
- .paddingRight(fromMe ? 10 : 0, pct)
- .marginRight(fromMe ? 0 : 70, pct)
- .paddingLeft(fromMe ? 5 : 10, pct)
- .background(fromMe ? "var(--brown)" : "var(--green)")
- }
- } else {
- LoadingCircle()
- }
- })
- .onAppear(async () => {
- requestAnimationFrame(() => {
- this.scrollTop = this.scrollHeight
- });
- })
- .gap(1, em)
- .position("relative")
- .overflow("scroll")
- .height(95, pct)
- .width(100, pct)
- .paddingTop(2, em)
- .paddingBottom(2, em)
- .backgroundColor("var(--darkbrown)")
- }
-}
-
-register(MessagesPanel)
\ No newline at end of file
diff --git a/src/apps/Messages/MessagesSidebar.js b/src/apps/Messages/MessagesSidebar.js
deleted file mode 100644
index 453a91d..0000000
--- a/src/apps/Messages/MessagesSidebar.js
+++ /dev/null
@@ -1,73 +0,0 @@
-class MessagesSidebar extends Shadow {
- conversations = []
- selectedConvoID
- onSelect
-
- constructor(conversations, selectedConvoID, onSelect) {
- super()
- this.conversations = conversations
- this.selectedConvoID = selectedConvoID
- this.onSelect = onSelect
- }
-
- render() {
- VStack(() => {
- this.conversations.forEach((convo, i) => {
-
- VStack(() => {
- HStack(() => {
-
- p(this.makeConvoTitle(convo.between))
- .textAlign("left")
- .marginLeft(0.5, inches)
- .paddingTop(0.2, inches)
- .width(100, pct)
- .marginTop(0)
- .fontSize(1, em)
- .fontWeight("bold")
-
- p(util.formatTime(convo.messages.last.time))
- .paddingTop(0.2, inches)
- .fontSize(0.8, em)
- .marginRight(0.1, inches)
- .color("var(--divider")
- })
- .justifyContent("space-between")
- .marginBottom(0)
-
- p(convo.messages.last.text)
- .fontSize(0.8, em)
- .textAlign("left")
- .marginLeft(0.5, inches)
- .marginBottom(2, em)
- .color("var(--divider)")
- })
- .background(convo.id === this.selectedConvoID ? "var(--darkbrown)" : "")
- .onClick(() => {
- this.onSelect(i)
- })
- })
- })
- .minWidth(15, vw)
- .height(100, vh)
- .gap(0, em)
- }
-
- makeConvoTitle(members) {
- let membersString = ""
- for(let i=0; i 2) {
- membersString += member.firstName
- } else {
- membersString += member.firstName + " " + member.lastName
- }
- }
- return membersString
- }
-}
-
-register(MessagesSidebar)
\ No newline at end of file
diff --git a/src/apps/People/People.js b/src/apps/People/People.js
deleted file mode 100644
index abe7dfd..0000000
--- a/src/apps/People/People.js
+++ /dev/null
@@ -1,105 +0,0 @@
-css(`
- people- {
- font-family: 'Arial';
- }
-
- people- h1 {
- font-family: 'Bona';
- }
-
- people- p {
- color: var(--accent);
- }
-
- people- p b {
- color: var(--darkbrown);
- }
-`)
-
-class People extends Shadow {
- people = "";
-
- constructor() {
- super()
- this.people = global.currentNetwork.data.members;
- }
-
- render() {
- VStack(() => {
- h1("People")
- .color("rgb(158 136 105)")
- .textAlign("center")
-
- if (this.people == "") {
- LoadingCircle()
- } else if (this.people.length > 0) {
- for (let i = 0; i < this.people.length; i++) {
- HStack(() => {
- HStack(() => { })
- .boxSizing("border-box")
- .height(3.5, em)
- .width(3.5, em)
- .padding(0.5, em)
- .border("1px solid var(--accent)")
- .borderRadius(100, pct)
- .background("black")
-
- VStack(() => {
- h3(this.people[i].firstName + " " + this.people[i].lastName)
- .color("var(--brown)")
- .fontSize(1.2, em)
- .fontWeight("bold")
- .marginVertical(0, em)
- p("Member since: " + " " + this.convertDate(this.people[i].created))
- })
- .verticalAlign("center")
- .gap(0.5, em)
- })
- .height(3.5, em)
- .padding(0.75, em)
- .gap(1, em)
- }
- } else {
- h2("No Members")
- .color("var(--brown)")
- .fontWeight("bold")
- .marginTop(7.5, em)
- .marginBottom(0.5, em)
- .textAlign("center")
- p("Invite people to this network!")
- .textAlign("center")
- .color("var(--darkbrown)")
- }
- })
- .position("relative")
- .boxSizing("border-box")
- .paddingVertical(1, em)
- .height(100, pct)
- .width(100, pct)
- }
-
- convertDate(rawDate) {
- const date = rawDate.split("-", 1)[0]; // "01.31.2026
- const [mm, dd, yyyy] = date.split(".").map(Number);
-
- const months = [
- "January", "February", "March", "April", "May", "June",
- "July", "August", "September", "October", "November", "December"
- ];
-
- const ordinal = (n) => {
- const mod100 = n % 100;
- if (mod100 >= 11 && mod100 <= 13) return `${n}th`;
- switch (n % 10) {
- case 1: return `${n}st`;
- case 2: return `${n}nd`;
- case 3: return `${n}rd`;
- default: return `${n}th`;
- }
- };
-
- return `${months[mm - 1]} ${ordinal(dd)}, ${yyyy}`;
- }
-}
-
-register(People)
\ No newline at end of file
diff --git a/src/apps/Tasks/Tasks.js b/src/apps/Tasks/Tasks.js
deleted file mode 100644
index 4b0e733..0000000
--- a/src/apps/Tasks/Tasks.js
+++ /dev/null
@@ -1,153 +0,0 @@
-css(`
- tasks- {
- font-family: 'Bona';
- }
-
- tasks- input::placeholder {
- font-family: 'Bona Nova';
- font-size: 0.9em;
- color: var(--accent);
- }
-
- input[type="checkbox"] {
- appearance: none; /* remove default style */
- -webkit-appearance: none;
- width: 1em;
- height: 1em;
- border: 1px solid var(--accent);
- }
-
- input[type="checkbox"]:checked {
- background-color: var(--red);
- }
-`)
-
-class Tasks extends Shadow {
- projects = [
- {
- "title": "Blockcatcher",
- "tasks": {}
- }
- ]
- columns = [
- {
- "title": "backlog",
- "tasks": {}
- }
- ]
-
- render() {
- ZStack(() => {
- HStack(() => {
- VStack(() => {
- h3("Projects")
- .marginTop(0)
- .marginBottom(1, em)
- .marginLeft(0.4, em)
-
- if (this.projects.length >= 1) {
- for(let i = 0; i < this.projects.length; i++) {
- p(this.projects[i].title)
- }
- } else {
- p("No Projects!")
- }
- })
- .height(100, vh)
- .paddingLeft(2, em)
- .paddingRight(2, em)
- .paddingTop(2, em)
- .gap(0, em)
- .borderRight("0.5px solid var(--accent2)")
-
- HStack(() => {
- if (this.columns.length >= 1) {
- for(let i = 0; i < this.columns.length; i++) {
- p(this.columns[i].name)
- }
- } else {
- p("No Conversations!")
- }
- })
- .height(100, vh)
- .paddingLeft(2, em)
- .paddingRight(2, em)
- .paddingTop(2, em)
- .gap(0, em)
- .borderRight("0.5px solid var(--accent2)")
- })
- .width(100, "%")
- .x(0).y(13, vh)
- .borderTop("0.5px solid var(--accent2)")
-
- p("0 Items")
- .position("absolute")
- .x(50, vw).y(50, vh)
- .transform("translate(-50%, -50%)")
-
- HStack(() => {
- input("Search tasks...", "45vw")
- .attr({
- "type": "text"
- })
- .fontSize(1.1, em)
- .paddingLeft(1.3, em)
- .background("transparent")
- .border("0.5px solid var(--accent2)")
- .outline("none")
- .color("var(--accent)")
- .borderRadius(10, px)
-
- button("Search")
- .marginLeft(2, em)
- .borderRadius(10, px)
- .background("transparent")
- .border("0.5px solid var(--accent2)")
- .color("var(--accent)")
- .fontFamily("Bona Nova")
- .onHover(function (hovering) {
- if(hovering) {
- this.style.background = "var(--green)"
-
- } else {
- this.style.background = "transparent"
-
- }
- })
-
- button("+ New Task")
- .width(9, em)
- .marginLeft(1, em)
- .borderRadius(10, px)
- .background("transparent")
- .border("0.5px solid var(--accent2)")
- .color("var(--accent)")
- .fontFamily("Bona Nova")
- .onHover(function (hovering) {
- if(hovering) {
- this.style.background = "var(--green)"
-
- } else {
- this.style.background = "transparent"
-
- }
- })
- .onClick((clicking) => {
- console.log(this, "clicked")
- })
-
- })
- .x(55, vw).y(4, vh)
- .position("absolute")
- .transform("translateX(-50%)")
- })
- .width(100, "%")
- .height(100, "%")
- }
-
- connectedCallback() {
- // Optional additional logic
- }
-}
-
-register(Tasks)
\ No newline at end of file
diff --git a/src/components/AppMenu.js b/src/components/AppMenu.js
deleted file mode 100644
index d403a81..0000000
--- a/src/components/AppMenu.js
+++ /dev/null
@@ -1,72 +0,0 @@
-import { Haptics, ImpactStyle } from '@capacitor/haptics';
-import util from "../util.js"
-
-class AppMenu extends Shadow {
- selected = ""
- apps = global.currentNetwork.apps.filter(app => (app !== "Settings" && app !== "Website"))
- darkMode = window.matchMedia('(prefers-color-scheme: dark)').matches
-
- getImageURL(appName) {
- let imgUrl = `${util.HOST}/apps/${appName}/icons/${appName}`
- if(this.darkMode) {
- imgUrl += "light"
- }
- imgUrl += ".svg"
- imgUrl = imgUrl.toLowerCase()
- return imgUrl
- }
-
- onNewSelection() {
- this.$$("img").forEach((image) => {
- image.style.borderBottom = "1px solid transparent"
- const appName = image.attributes.app.value
- if (appName === global.currentApp()) {
- image.style.borderBottom = "1px solid var(--text)"
- }
- image.src = this.getImageURL(appName)
- })
- }
-
- render() {
- let apps = this.apps
- let appCount = apps.length
- let horizontalMargin = {
- 1: 50,
- 2: 10,
- 3: 2,
- 4: 1.5,
- 5: 0.5
- }[appCount] ?? 4
-
- HStack(() => {
-
- for(let i = 0; i < apps.length; i++) {
- let app = apps[i]
-
- img(this.getImageURL(app), "1.3em")
- .attr({app: app})
- .padding(0.5, em)
- .borderBottom(global.currentApp() === app ? "1px solid var(--text)" : "1px solid transparent")
- .onTouch(async (done, e) => {
- if(done) {
- global.openApp(app)
- this.onNewSelection()
- await Haptics.impact({ style: ImpactStyle.Light });
- }
- })
- }
- })
- .display("grid")
- .gridTemplateColumns(`repeat(${apps.filter(app => app !== "Settings").length}, 1fr)`)
- .placeItems("center")
- .borderTop("0.5px solid var(--divider)")
- .height("auto")
- .zIndex(1)
- .paddingTop(0.5, em)
- .paddingBottom(2, em)
- .width(100, vw)
- .boxSizing("border-box")
- }
-}
-
-register(AppMenu)
\ No newline at end of file
diff --git a/src/components/AppWindow.js b/src/components/AppWindow.js
deleted file mode 100644
index c7da9d5..0000000
--- a/src/components/AppWindow.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import util from "../util.js"
-
-class AppWindow extends Shadow {
- render() {
- ZStack(() => {
- let app = global.currentApp()
- if(window[app]) {
- window[app]()
- } else {
- this.getCustomApp(app)
- }
- })
- .height(100, pct)
- .overflowY("scroll")
- .onNavigate(() => {
- this.rerender()
- })
- }
-
- async getCustomApp(app) {
- await import(`${util.HOST}/apps/${app.toLowerCase()}/${app.toLowerCase()}.js`);
- if(window[app]) {
- this.rerender()
- } else {
- console.error("Could not get app: ", app)
- }
- }
-}
-
-register(AppWindow)
\ No newline at end of file
diff --git a/src/components/AppWindowContainer.js b/src/components/AppWindowContainer.js
deleted file mode 100644
index 2a3d212..0000000
--- a/src/components/AppWindowContainer.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import "./AppWindow.js"
-import "../Profile/Profile.js"
-import "./TopBar.js"
-
-class AppWindowContainer extends Shadow {
- render() {
- ZStack(() => {
-
- VStack(() => {
- TopBar()
-
- AppWindow()
- })
- .width(100, pct)
- .gap(0)
-
- Profile()
- .zIndex(3)
- })
- .height(100, pct)
- .overflowY("hidden")
- .display("flex")
- .position("relative")
- }
-
- openProfile() {
- this.$("profile-").top(20, px)
- this.$("profile-").pointerEvents("auto")
- }
-
- closeProfile() {
- this.$("profile-").top(100, vh)
- this.$("profile-").pointerEvents("none")
- }
-}
-
-register(AppWindowContainer)
\ No newline at end of file
diff --git a/src/components/Sidebar.js b/src/components/Sidebar.js
deleted file mode 100644
index 93c1c84..0000000
--- a/src/components/Sidebar.js
+++ /dev/null
@@ -1,184 +0,0 @@
-import util from "../util"
-import "./Toggle.js"
-
-class Sidebar extends Shadow {
- SIDEBAR_WIDTH
-
- constructor(width) {
- super()
- this.SIDEBAR_WIDTH = width
- this.showCalendarControls = global.currentApp() === "Calendar";
- }
-
- CalendarControls() {
- const getButton = (label) => {
- return button(label)
- .fontSize(1.2, em)
- .paddingVertical(0.45, em)
- .paddingHorizontal(0.8, em)
- .border("1px solid var(--divider)")
- .borderRadius(0.6, em)
- .background("var(--accent)")
- .color("var(--headertext)")
- .cursor("pointer")
- }
-
- return VStack(() => {
- p("Calendar View")
- .fontSize(1, em)
- .fontWeight("bold")
- .color("var(--headertext)")
- .fontFamily("Arial")
- .textAlign("Center")
- .marginBottom(0.5, em)
- HStack(() => {
- getButton("day")
- .onTap(() => {
- if ($("calendar-").changeView("day")) {
- $("home-").closeSidebar();
- }
- })
- getButton("week")
- .onTap(() => {
- if ($("calendar-").changeView("week")) {
- $("home-").closeSidebar();
- }
- })
- getButton("month")
- .onTap(() => {
- if ($("calendar-").changeView("month")) {
- $("home-").closeSidebar();
- }
- })
- })
- .gap(0.5, em)
- .justifyContent("center")
- })
- .width(100, pct)
- }
-
- SidebarItem(text) {
- return p(text)
- .fontSize(1.2, em)
- .fontWeight("bold")
- .color("var(--headertext)")
- .fontFamily("Arial")
- .marginLeft(1, em)
- .marginTop(2, em)
- .onTap(function (done) {
- if (done) {
- if (this.innerText === "Logout") {
- global.onLogout()
- $("home-").closeSidebar();
- return
- }
- }
- })
- }
-
- render() {
- VStack(() => {
- HStack(() => {
- if (global.profile.image_path) {
- img(`${util.HOST}${global.profile.image_path}`, "10em", "10em")
- .borderRadius(100, pct)
- }
- })
- .boxSizing("border-box")
- .height(10, em)
- .width(10, em)
- .border("1px solid var(--accent)")
- .borderRadius(100, pct)
- .background("var(--darkaccent)")
- .alignSelf("center")
- .onClick((done) => {
- if(done)
- this.openProfile()
- })
-
- h2(global.profile.first_name + " " + global.profile.last_name)
- .color("var(--headertext")
- .textAlign("center")
- .marginVertical(0.25, em)
- .paddingBottom(0.5, em)
- .textAlign("center")
- .alignSelf("center")
- .overflowWrap("break-word")
- .wordBreak("break-word")
- .width(100, pct)
- .borderBottom("2px solid var(--divider)")
- .onClick((done) => {
- if(done)
- this.openProfile()
- })
- .paddingBottom(1, em)
-
- if (this.showCalendarControls) {
- this.CalendarControls()
- }
-
- VStack(() => {
- this.SidebarItem("Logout")
-
- Toggle("Enable Push Notifications")
- .marginLeft(1, em)
-
- button("Delete Account")
- .fontSize(0.9, em)
- .marginBottom(2, em)
- .background("var(--darkred)")
- .paddingVertical(1, em)
- .border("none")
- .outline("1px solid var(--divider)")
- .color("var(--text)")
- .onTap((done) => this.deleteAccount())
- })
- .marginTop("auto")
- .gap(2, em)
- })
- .gap(1, em)
- .paddingTop(15, vh)
- .paddingHorizontal(1, em)
- .height(105, vh)
- .top(-5, vh)
- .minWidth(0)
- .boxSizing("border-box")
- .width(this.SIDEBAR_WIDTH, px)
- .borderLeft("1px solid var(--divider)")
- .color("var(--text)")
- .position("fixed")
- .background("var(--sidebar)")
- }
-
- toggleCalendarControls() {
- this.showCalendarControls = !this.showCalendarControls;
- this.rerender();
- }
-
- openProfile() {
- $("appwindowcontainer-").openProfile()
- $("home-").closeSidebar();
- }
-
- async deleteAccount() {
- try {
- const res = await util.authFetch(`${util.HOST}/auth/delete`, {
- method: "DELETE",
- credentials: "include",
- headers: {
- "X-Client": "mobile",
- "Content-Type": "application/json",
- "Accept": "application/json"
- },
- body: JSON.stringify({ memberId: global.profile.id })
- });
-
- if (!res.ok) return;
- global.onLogout()
- } catch (err) {
- console.error(err)
- }
- }
-}
-
-register(Sidebar)
\ No newline at end of file
diff --git a/src/components/Toggle.js b/src/components/Toggle.js
deleted file mode 100644
index 511b0a3..0000000
--- a/src/components/Toggle.js
+++ /dev/null
@@ -1,50 +0,0 @@
-css(`
- .toggle-input {
- appearance: none;
- width: 44px;
- height: 24px;
- background: #ccc;
- border-radius: 12px;
- position: relative;
- cursor: pointer;
- transition: background 0.2s;
- }
-
- .toggle-input::after {
- content: '';
- position: absolute;
- width: 20px;
- height: 20px;
- background: white;
- border-radius: 50%;
- top: 2px;
- left: 2px;
- transition: left 0.2s;
- }
-
- .toggle-input:checked {
- background: var(--darkred);
- }
-
- .toggle-input:checked::after {
- left: 22px;
- }
-`)
-
-class Toggle extends Shadow {
- render() {
- HStack(() => {
- input("", "44px", "24px")
- .attr({ type: "checkbox", checked: global.profile.preferences.notifications ? "" : null, class: "toggle-input"})
- .onChange(async (e) => {
- await server.updateNotificationPreferences(global.profile.id, e.target.checked)
- })
- p("Enable Push Notifications")
- .color("var(--text)")
- })
- .verticalAlign("center")
- .gap(10, px)
- }
-}
-
-register(Toggle)
\ No newline at end of file
diff --git a/src/components/TopBar.js b/src/components/TopBar.js
deleted file mode 100644
index 1865fe6..0000000
--- a/src/components/TopBar.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import util from "../util.js"
-
-class TopBar extends Shadow {
- render() {
- HStack(() => {
- if (global.currentNetwork.logo) {
- img(`${util.HOST}/db/images/${global.currentNetwork.logo}`, "2.5em", "2.5em")
- .borderRadius("50", pct)
- .objectFit("cover")
- .padding(0.3, em)
- .background("var(--accent)")
- .onTouch(function (start) {
- if(start) {
- this.style.scale = "0.8"
- } else if(start === false) {
- this.style.scale = ""
- if (!$("home-").sidebarOpen) {
- $("home-").openSidebar()
- }
- }
- })
- } else {
- HStack(() => { })
- .height(2.5, em)
- .width(2.5, em)
- .padding(0.3, em)
- .background("var(--accent)")
- .borderRadius("50", pct)
- }
-
- p()
- .state("app", function () {
- this.innerText = global.currentApp()
- })
- .color("var(--headertext)")
- .textAlign("center")
- .fontFamily("Arial")
- .fontSize("clamp(0.8rem, 40cqw, 7cqw)")
- .fontWeight("bold")
- })
- .containerType("inline-size")
- .paddingLeft(1, em)
- .paddingBottom(1.5, em)
- .verticalAlign("center")
- .gap(0.5, em)
- .marginTop(4, em)
- .onNavigate(() => {
- $("sidebar-").toggleCalendarControls();
- this.$("p").attr({app: global.currentApp()})
- })
- }
-}
-
-register(TopBar)
\ No newline at end of file
diff --git a/src/index.html b/src/index.html
index e64185b..21b3a99 100644
--- a/src/index.html
+++ b/src/index.html
@@ -19,13 +19,28 @@
src="https://unpkg.com/@ionic/pwa-elements@latest/dist/ionicpwaelements/ionicpwaelements.js"
>
-
-
-
+
-