diff --git a/db/comalyr.svg b/db/comalyr.svg
new file mode 100644
index 0000000..800796f
--- /dev/null
+++ b/db/comalyr.svg
@@ -0,0 +1,7 @@
+
diff --git a/server/db/db.js b/server/db/db.js
index 0b00f6b..ea184f0 100644
--- a/server/db/db.js
+++ b/server/db/db.js
@@ -3,6 +3,7 @@ import chalk from 'chalk';
import path from 'path';
import Titles from "./model/Titles.js"
+import Networks from "./model/Networks.js"
import Members from './model/Members.js'
import Tokens from './model/Tokens.js'
import Payments from "./model/Payments.js"
@@ -12,6 +13,7 @@ import Messages from "./model/Messages/Messages.js"
export default class Database {
titles = new Titles()
+ networks = new Networks()
members = new Members()
tokens = new Tokens()
payments = new Payments()
@@ -20,8 +22,9 @@ export default class Database {
messages = new Messages()
fromID = {
- "HY": this.titles,
"MEMBER": this.members,
+ "NETWORK": this.networks,
+ "TITLE": this.titles,
"TOKEN": this.tokens,
"PAYMENT": this.payments,
"POST": this.posts,
diff --git a/server/db/model/Members.js b/server/db/model/Members.js
index a0f0b6b..7de4f51 100644
--- a/server/db/model/Members.js
+++ b/server/db/model/Members.js
@@ -22,6 +22,7 @@ export default class Members extends OrderedObject {
),
joined: z.string(),
address: this.addressSchema,
+ networks: z.array(z.number())
})
isHashed = (s) => {return s.startsWith("$argon2")}
diff --git a/server/db/model/Networks.js b/server/db/model/Networks.js
new file mode 100644
index 0000000..e544ee8
--- /dev/null
+++ b/server/db/model/Networks.js
@@ -0,0 +1,39 @@
+import OrderedObject from "./OrderedObject.js"
+import { z } from 'zod';
+
+export default class Networks extends OrderedObject {
+ prefix = `NETWORK`
+
+ schema = z.object({
+ id: z.number(),
+ name: z.string(),
+ })
+
+ save(n) {
+ let id = `${this.prefix}-${n.id}`
+ let result = this.schema.safeParse(n)
+ if(result.success) {
+ try {
+ super.add(id, n)
+ } catch(e) {
+ console.error(e)
+ throw e
+ }
+ } else {
+ console.error(result.error)
+ throw new global.ServerError(400, "Invalid Member Data!");
+ }
+ }
+
+ add(n) {
+ let toSave = {
+ id: this.entries.length+1,
+ ...n
+ }
+ this.save(toSave)
+ }
+
+ get(id) {
+ return this.entries[this.ids[`${this.prefix}-${id}`]]
+ }
+}
\ No newline at end of file
diff --git a/server/index.js b/server/index.js
index 18db27c..0557a11 100644
--- a/server/index.js
+++ b/server/index.js
@@ -24,7 +24,7 @@ class Server {
registerRoutes(router) {
/* Stripe */
- router.post("/create-checkout-session", PaymentsHandler.danceTicket)
+ router.post("/create-checkout-session", PaymentsHandler.newSubscription)
router.post("/webhook", express.raw({ type: "application/json" }), PaymentsHandler.webhook)
/* Auth */
@@ -33,7 +33,6 @@ class Server {
router.get('/signout', this.auth.logout)
/* Site */
- router.get('/signup', this.verifyToken, this.get)
router.post('/signup', this.verifyToken, this.newUserSubmission)
router.get('/db/images/*', this.getUserImage)
router.get('/*', this.get)
diff --git a/server/payments.js b/server/payments.js
index ad3ef54..1f71f7a 100644
--- a/server/payments.js
+++ b/server/payments.js
@@ -6,22 +6,22 @@ const stripe = new Stripe(process.env.STRIPE_SECRET);
export default class PaymentsHandler {
- static async danceTicket(req, res) {
+ static async newSubscription(req, res) {
try {
const session = await stripe.checkout.sessions.create({
mode: "payment",
payment_method_types: ["card"],
metadata: {
- productId: "austin_winter_ball_2025_ticket"
+ productId: "50_month_sub"
},
line_items: [
{
price_data: {
currency: "usd",
product_data: {
- name: "Hyperia Winter Ball"
+ name: "Monthly Subscription"
},
- unit_amount: 3500
+ unit_amount: 5000
},
quantity: 1
}
diff --git a/ui/_/code/shared.css b/ui/_/code/shared.css
index c241044..5edf8de 100644
--- a/ui/_/code/shared.css
+++ b/ui/_/code/shared.css
@@ -5,7 +5,8 @@
--gold: #FEBA7D;
--divider: #bb7c36;
--green: #0857265c;
- --red: #E84343;
+ --red: #CE0000;
+ --redorange: #ff2e00;
--brown: #812A18;
--darkbrown: #3f0808;
@@ -14,12 +15,18 @@
@media (prefers-color-scheme: dark) {
:root {
- --main: var(--brown);
- --accent: var(--gold);
+ --main: #000000;
+ --accent: #453C33;
--accent2: var(--gold);
}
}
+:root.red {
+ --main: var(--red);
+ --accent: #6a0000;
+ --accent2: var(--green);
+}
+
@font-face {
font-family: 'Canterbury';
src: url('/_/fonts/Canterbury/Canterbury.ttf') format('truetype');
@@ -84,6 +91,7 @@ a:active {
}
button {
+ font-family: inherit;
background-color: transparent;
color: var(--accent);
padding: 0.5em;
@@ -102,6 +110,7 @@ input {
}
input::placeholder {
+ font-family: "Nanum";
color: var(--accent)
}
diff --git a/ui/_/icons/forum.svg b/ui/_/icons/forum.svg
new file mode 100644
index 0000000..eddf4cb
--- /dev/null
+++ b/ui/_/icons/forum.svg
@@ -0,0 +1,9 @@
+
diff --git a/ui/_/icons/house.svg b/ui/_/icons/house.svg
new file mode 100644
index 0000000..f2e6f86
--- /dev/null
+++ b/ui/_/icons/house.svg
@@ -0,0 +1,4 @@
+
diff --git a/ui/_/icons/nodes.svg b/ui/_/icons/nodes.svg
new file mode 100644
index 0000000..b04a17a
--- /dev/null
+++ b/ui/_/icons/nodes.svg
@@ -0,0 +1,11 @@
+
diff --git a/ui/_/icons/people.svg b/ui/_/icons/people.svg
new file mode 100644
index 0000000..9ec5c7f
--- /dev/null
+++ b/ui/_/icons/people.svg
@@ -0,0 +1,3 @@
+
diff --git a/ui/_/icons/quill.svg b/ui/_/icons/quill.svg
index 065e6a5..1bace50 100644
--- a/ui/_/icons/quill.svg
+++ b/ui/_/icons/quill.svg
@@ -2,4 +2,4 @@
-
+
\ No newline at end of file
diff --git a/ui/_/icons/quillblack.svg b/ui/_/icons/quillblack.svg
new file mode 100644
index 0000000..aa36be4
--- /dev/null
+++ b/ui/_/icons/quillblack.svg
@@ -0,0 +1,5 @@
+
diff --git a/ui/desktop/apps/Forum/Forum.js b/ui/desktop/apps/Forum/Forum.js
index 0a26881..0f7fc26 100644
--- a/ui/desktop/apps/Forum/Forum.js
+++ b/ui/desktop/apps/Forum/Forum.js
@@ -87,8 +87,8 @@ class Forum extends Shadow {
.gap(0.5, em)
.width(100, pct)
.height(100, vh)
- .alignHorizontal("center")
- .alignVertical("end")
+ .horizontalAlign("center")
+ .verticalAlign("end")
})
.width(100, "%")
.height(87, vh)
diff --git a/ui/desktop/apps/Messages/Messages.js b/ui/desktop/apps/Messages/Messages.js
index dd288a6..350c880 100644
--- a/ui/desktop/apps/Messages/Messages.js
+++ b/ui/desktop/apps/Messages/Messages.js
@@ -72,8 +72,8 @@ class Messages extends Shadow {
})
.gap(1, em)
.width(100, pct)
- .alignHorizontal("center")
- .alignVertical("end")
+ .horizontalAlign("center")
+ .verticalAlign("end")
})
.onAppear(async () => {
let res = await Socket.send({app: "MESSAGES", operation: "GET"})
@@ -121,8 +121,8 @@ class Messages extends Shadow {
})
.gap(1, em)
- .alignVertical("center")
- .alignHorizontal("center")
+ .verticalAlign("center")
+ .horizontalAlign("center")
.backgroundColor("black")
.border("1px solid var(--accent)")
.position("fixed")
diff --git a/ui/desktop/components/AppMenu.js b/ui/desktop/components/AppMenu.js
index 96a507e..141f62a 100644
--- a/ui/desktop/components/AppMenu.js
+++ b/ui/desktop/components/AppMenu.js
@@ -25,9 +25,8 @@ css(`
border-radius: 5px;
text-underline-offset: 5px;
}
- app-menu p:hover {
- text-decoration: underline;
- transform: translateY(-5%)
+ app-menu img:hover {
+ border: "1px solid black";
}
app-menu p.touched {
text-decoration: underline;
@@ -56,19 +55,14 @@ class AppMenu extends Shadow {
render() {
VStack(() => {
HStack(() => {
- p("Forum")
- p("Messages")
- p("Market")
- p("Jobs")
+ img("/_/icons/house.svg", "1.5em")
+ img("/_/icons/nodes.svg", "1.5em")
+ img("/_/icons/forum.svg", "1.5em")
+ img("/_/icons/people.svg", "1.5em")
})
.justifyContent("center")
- .gap(1.5, em)
+ .gap(3, em)
.paddingRight(2, em)
-
- img("/_/images/divider.svg", "40vw")
- .attr({
- "id": "divider",
- })
})
.gap(0.5, em)
.onNavigate(() => {
@@ -81,14 +75,14 @@ class AppMenu extends Shadow {
}
})
.onAppear(() => {
- Array.from(this.querySelectorAll("p")).forEach((el) => {
+ 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 p")) {
+ if(!target.matches("app-menu img")) {
return
}
diff --git a/ui/desktop/components/Home.js b/ui/desktop/components/Home.js
index 54fe664..9ab2f5f 100644
--- a/ui/desktop/components/Home.js
+++ b/ui/desktop/components/Home.js
@@ -8,23 +8,17 @@ class Home extends Shadow {
render() {
ZStack(() => {
- img("/_/icons/logo.svg", "2.5em")
- .position("fixed")
- .left(3, em)
- .top(3, vh)
- .zIndex(3)
- .onClick(() => {
- window.navigateTo("/")
- })
-
- div()
- .width(100, vw)
- .height(100, vh)
- .margin(0)
- .backgroundImage("/_/images/the_return.webp")
- .backgroundSize("cover")
- .backgroundPosition("48% 65%")
- .backgroundRepeat("no-repeat")
+
+ VStack(() => {
+ img(document.documentElement.classList.contains("red") ? "/_/icons/quillblack.svg" : "/_/icons/quill.svg", "2.5em")
+ .position("fixed")
+ .left(3, em)
+ .top(3, vh)
+ .zIndex(3)
+ .onClick(() => {
+ window.navigateTo("/")
+ })
+ })
switch(window.location.pathname) {
case "/":
@@ -82,7 +76,7 @@ class Home extends Shadow {
.gap(1, em)
.xRight(2, em).y(2.3, em)
.position("fixed")
- .alignVertical("center")
+ .verticalAlign("center")
})
}
diff --git a/ui/desktop/index.html b/ui/desktop/index.html
index fe8fbe8..7d7cc78 100644
--- a/ui/desktop/index.html
+++ b/ui/desktop/index.html
@@ -3,7 +3,7 @@
Parchment
-
+
diff --git a/ui/mobile/apps/Forum/Forum.js b/ui/mobile/apps/Forum/Forum.js
index 8ee2f0b..a507efc 100644
--- a/ui/mobile/apps/Forum/Forum.js
+++ b/ui/mobile/apps/Forum/Forum.js
@@ -52,8 +52,8 @@ class Forum extends Shadow {
.gap(0.5, em)
.width(100, pct)
.height(100, vh)
- .alignHorizontal("center")
- .alignVertical("end")
+ .horizontalAlign("center")
+ .verticalAlign("end")
})
.onAppear(() => document.body.style.backgroundColor = "var(--darkbrown)")
.width(100, pct)
diff --git a/ui/mobile/apps/Messages/Messages.js b/ui/mobile/apps/Messages/Messages.js
index dd288a6..350c880 100644
--- a/ui/mobile/apps/Messages/Messages.js
+++ b/ui/mobile/apps/Messages/Messages.js
@@ -72,8 +72,8 @@ class Messages extends Shadow {
})
.gap(1, em)
.width(100, pct)
- .alignHorizontal("center")
- .alignVertical("end")
+ .horizontalAlign("center")
+ .verticalAlign("end")
})
.onAppear(async () => {
let res = await Socket.send({app: "MESSAGES", operation: "GET"})
@@ -121,8 +121,8 @@ class Messages extends Shadow {
})
.gap(1, em)
- .alignVertical("center")
- .alignHorizontal("center")
+ .verticalAlign("center")
+ .horizontalAlign("center")
.backgroundColor("black")
.border("1px solid var(--accent)")
.position("fixed")
diff --git a/ui/public/pages/Events.js b/ui/public/pages/Events.js
deleted file mode 100644
index 15612d5..0000000
--- a/ui/public/pages/Events.js
+++ /dev/null
@@ -1,325 +0,0 @@
-class Events extends Shadow {
-
- events = [
- {
- date: `January 23, 2025`,
- title: `Hyperia Winter Ball`,
- description: `Join us in Austin, Texas for a dance. Live music and drinks will be included.
Admission for men is $50, women are free. Open to the public.`,
- location: `Austin, TX`
- }
- ]
-
- render() {
- ZStack(() => {
- VStack(() => {
-
- h1("HYPERIA")
- .marginBottom(0, em)
-
- p("Public Events")
- .fontSize(1.2, em)
- .marginBottom(2, em)
-
- const Stack = window.isMobile() ? VStack : HStack
- Stack(() => {
-
- VStack(() => {
- p(`January 23, 2025`)
-
- p(`Hyperia Winter Ball`)
- .fontSize(1.2, em)
-
- p(`Austin, TX`)
-
- })
-
- p(`Join us in Austin, Texas for a great dance, with free drinks and live music.
Admission: $35 for men, women are free.`)
- .marginRight(4, em)
-
- HStack(() => {
- img("/_/icons/creditcards/visa.svg")
- img("/_/icons/creditcards/mastercard.svg")
- img("/_/icons/creditcards/discover.svg")
- img("/_/icons/creditcards/amex.svg")
- })
- .alignSelf("flex-start")
- .height(2, em)
- .maxWidth(40, vw)
-
- button("Buy Ticket")
- .color("var(--darkbrown")
- .border("1px solid #ab2f007d")
- .background('var(--green)')
- .marginLeft("auto")
- .onClick(async function() {
- this.innerText = "Loading..."
- const res = await fetch("/create-checkout-session", { method: "POST" });
- const data = await res.json();
- window.location = data.url;
- })
- })
- .gap(3, em)
- .color("var(--darkbrown)")
- .background(`var(--accent)`)
- .padding(1, em)
- .borderRadius(12, px)
- .border("2px solid #ab2f007d")
- })
- .marginLeft(window.isMobile() ? 0 : 15, vmax)
- .marginRight(window.isMobile() ? 0 : 15, vmax)
- .marginTop(10, vmax)
-
- HStack(() => {
- p("Privacy Policy")
- .onHover(function (hovering) {
- if(hovering) {
- this.style.color = "var(--darkbrown)"
- } else {
- this.style.color = ""
- }
- })
- .onClick(() => {
- this.$("#policyWindow").style.display = "flex"
- })
- p("Refund and Return Policy")
- .onHover(function (hovering) {
- if(hovering) {
- this.style.color = "var(--darkbrown)"
- } else {
- this.style.color = ""
- }
- })
- .onClick(() => {
- this.$("#refundWindow").style.display = "flex"
- })
- p("Contact Us")
- .onHover(function (hovering) {
- if(hovering) {
- this.style.color = "var(--darkbrown)"
- } else {
- this.style.color = ""
- }
- })
- .onClick(() => {
- this.$("#contactWindow").style.display = "flex"
- })
- })
- .x(50, vw).yBottom(0, vh)
- .center()
- .gap(2, em)
- .opacity(0.5)
- .cursor("default")
- })
-
- VStack(() => {
-
- p("Privacy Policy")
- .fontSize(2, em)
- .fontWeight(600)
- .marginBottom(1, em)
-
- p("We value your privacy. This Privacy Policy explains how we collect, use, store, and protect your information when you use our website or services.")
-
- p("1. Information We Collect")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("• Personal information you provide, such as your name, email address, or other contact details.")
- p("• Automatically collected data, including IP address, browser type, device information, and usage statistics.")
- p("• Cookies or similar tracking technologies that help us improve the user experience.")
-
- p("2. How We Use Your Information")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("• To operate and improve our website and services.")
- p("• To communicate with you about updates, support requests, or account-related matters.")
- p("• To maintain security, prevent fraud, and ensure proper functionality.")
-
- p("3. How We Share Information")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("We do not sell your personal information. We may share data only with trusted service providers who help us operate the platform, or when required by law.")
-
- p("4. Data Storage & Security")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("We use reasonable technical and administrative safeguards to protect your information. However, no system is completely secure, and we cannot guarantee absolute protection.")
-
- p("5. Cookies")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("Our site may use cookies to remember preferences, analyze traffic, and enhance usability. You can disable cookies in your browser settings, but some features may stop working.")
-
- p("6. Your Rights")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("Depending on your location, you may have rights to access, update, delete, or request a copy of your personal data. Contact us if you wish to exercise these rights.")
-
- p("7. Third-Party Links")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("Our website may contain links to third-party sites. We are not responsible for their content or privacy practices.")
-
- p("8. Changes to This Policy")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("We may update this Privacy Policy from time to time. Updated versions will be posted on this page with the effective date.")
-
- p("9. Contact Us")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("If you have any questions about this Privacy Policy, feel free to contact us at info@hyperia.so.")
-
- p("x")
- .onClick(function (done) {
- if(done) {
- this.parentElement.style.display = "none"
- }
- })
- .color("var(--red)")
- .xRight(1, em).y(1, em)
- .fontSize(2, em)
- .cursor("pointer")
-
- })
- .x(50, vw).y(50, vh)
- .width(70, vw).height(70, vh)
- .center()
- .backgroundColor("var(--accent)")
- .display("none")
- .overflow("scroll")
- .padding(1, em)
- .border("3px solid black")
- .color("var(--darkbrown)")
- .attr({ id: "policyWindow" })
-
- VStack(() => {
-
- p("Refund & Return Policy")
- .fontSize(2, em)
- .fontWeight(600)
- .marginBottom(1, em)
-
- p("1. Eligibility for Refunds")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("• Refund requests may be considered when submitted within 14 days of purchase.")
- p("• To qualify, you must provide proof of purchase and a valid reason for the request.")
- p("• Certain digital products or services may be non-refundable once accessed or downloaded.")
-
- p("2. Non-Refundable Items")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("• Products or services that have already been delivered, downloaded, or accessed in full.")
- p("• Custom work, personalized items, or one-time service fees.")
- p("• Any promotional or discounted items, unless required by law.")
-
- p("3. Returns (If Applicable)")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("• Physical items must be returned in their original condition.")
- p("• You are responsible for return shipping costs unless the item was defective or incorrect.")
- p("• Items damaged through misuse or neglect cannot be returned.")
-
- p("4. Processing Refunds")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("• Approved refunds are issued to the original payment method.")
- p("• Processing times may vary depending on your bank or payment provider.")
- p("• We will notify you once your refund has been initiated.")
-
- p("5. Cancellations")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("• Orders or subscriptions may be cancelled before fulfillment or renewal.")
- p("• If Hyperia declare a cancellation of any product or event, a refund will be issued to all parties.")
-
- p("6. Contact for Refund Requests")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("If you need to request a refund, return an item, or cancel an order, please contact us at info@hyperia.so. Include your order number and relevant details so we can assist you promptly.")
-
- p("7. Policy Updates")
- .fontWeight(600)
- .marginTop(1, em)
-
- p("We may update this Refund & Return Policy from time to time. Any changes will be posted on this page with the effective date.")
-
- p("x")
- .onClick(function (done) {
- if(done) {
- this.parentElement.style.display = "none"
- }
- })
- .color("var(--red)")
- .xRight(1, em).y(1, em)
- .fontSize(2, em)
- .cursor("pointer")
-
- })
- .x(50, vw).y(50, vh)
- .width(70, vw).height(70, vh)
- .center()
- .backgroundColor("var(--accent)")
- .display("none")
- .overflow("scroll")
- .padding(1, em)
- .border("3px solid black")
- .color("var(--darkbrown)")
- .attr({ id: "refundWindow" })
-
-
- VStack(() => {
-
- p("Contact Us")
- .fontSize(2, em)
- .fontWeight(600)
- .marginBottom(1, em)
-
- p("Email: info@hyperia.so")
- p("Phone: 813-373-9100")
- p("Address: 2014 E 9th St, Unit A, Austin TX")
-
- p("x")
- .onClick(function (done) {
- if(done) {
- this.parentElement.style.display = "none"
- }
- })
- .color("var(--red)")
- .xRight(1, em).y(1, em)
- .fontSize(2, em)
- .cursor("pointer")
-
- })
- .gap(2, em)
- .x(50, vw).y(50, vh)
- .width(50, vw).height(50, vh)
- .center()
- .backgroundColor("var(--accent)")
- .display("none")
- .overflow("scroll")
- .padding(1, em)
- .border("3px solid black")
- .color("var(--darkbrown)")
- .attr({ id: "contactWindow" })
-
-
- }
-}
-
-register(Events)
\ No newline at end of file
diff --git a/ui/public/pages/Home.js b/ui/public/pages/Home.js
index f7a1b02..b9def48 100644
--- a/ui/public/pages/Home.js
+++ b/ui/public/pages/Home.js
@@ -1,9 +1,6 @@
-import "../components/NavBar.js"
-import "./SignupForm.js"
-import "./Why.js"
-import "./Events.js"
-import "./Join.js"
+import "./SignUp.js"
import "./SignIn.js"
+import "./SignupForm.js"
import "./Success.js"
class Home extends Shadow {
@@ -55,7 +52,6 @@ class Home extends Shadow {
.fontSize(1.2, em)
.cursor("default")
.onHover(function (hovering) {
- console.log("hover")
if(hovering) {
this.style.background = "var(--red)"
this.style.color = "black"
@@ -75,7 +71,6 @@ class Home extends Shadow {
.fontSize(1.2, em)
.cursor("default")
.onHover(function (hovering) {
- console.log("hover")
if(hovering) {
this.style.background = "var(--red)"
this.style.color = "black"
@@ -110,7 +105,6 @@ class Home extends Shadow {
.marginHorizontal(27, vw)
.width(46, vw)
.marginTop(10, vh)
- .fontFamily("Nanum")
}
render() {
@@ -121,28 +115,22 @@ class Home extends Shadow {
case "/":
this.MainContent()
break;
- case "/why":
- Why()
- break;
- case "/events":
- Events()
- break;
- case "/join":
- Join()
+ case "/signup":
+ SignUp()
break;
case "/success":
Success()
break;
default:
- if(window.location.pathname.startsWith("/signup")) {
+ if(window.location.pathname.startsWith("/free")) {
SignupForm()
} else if(window.location.pathname.startsWith("/login")) {
SignIn()
}
}
-
})
+ .fontFamily("Nanum")
.onNavigate(() => {
this.rerender()
})
diff --git a/ui/public/pages/SignUp.js b/ui/public/pages/SignUp.js
new file mode 100644
index 0000000..0b243df
--- /dev/null
+++ b/ui/public/pages/SignUp.js
@@ -0,0 +1,31 @@
+class SignUp extends Shadow {
+ render() {
+ VStack(() => {
+
+ h2("$50 / Month Subscription")
+ .color("var(--red)")
+
+ p(" - Access to Parchment Online and Parchment Desktop")
+ p(" - Ability to Create Networks")
+ p(" - Up to 5GB Storage Space")
+
+ button("Buy")
+ .color("var(--red")
+ .border("1px solid var(--red)")
+ .marginLeft("auto")
+ .fontSize(1.1, em)
+ .onClick(async function() {
+ this.innerText = "Loading..."
+ const res = await fetch("/create-checkout-session", { method: "POST" });
+ const data = await res.json();
+ window.location = data.url;
+ })
+ .marginTop(2, em)
+ })
+ .x(50, vw).y(50, vh).center()
+ .border("1px solid var(--red)")
+ .padding(1, em)
+ }
+}
+
+register(SignUp)
\ No newline at end of file
diff --git a/ui/public/pages/SignupForm.js b/ui/public/pages/SignupForm.js
index 0e466b2..56a9bc3 100644
--- a/ui/public/pages/SignupForm.js
+++ b/ui/public/pages/SignupForm.js
@@ -12,7 +12,7 @@ class SignupForm extends Shadow {
render() {
ZStack(() => {
form(() => {
-
+
VStack(() => {
p()
@@ -23,20 +23,20 @@ class SignupForm extends Shadow {
.background("var(--accent)")
HStack(() => {
-
+
VStack(() => {
- input("First Name*")
- .attr({name: "firstName", type: "name", required: "true"})
- .styles(this.inputStyles)
-
- input("Last Name*")
- .attr({name: "lastName", type: "name", required: "true"})
- .styles(this.inputStyles)
-
input("Email*")
.attr({name: "email", type: "email", required: "true"})
.styles(this.inputStyles)
-
+
+ input("First Name*")
+ .attr({name: "firstName", type: "name", required: "true"})
+ .styles(this.inputStyles)
+
+ input("Last Name*")
+ .attr({name: "lastName", type: "name", required: "true"})
+ .styles(this.inputStyles)
+
input("Password*")
.attr({name: "password", type: "password", required: "true"})
.styles(this.inputStyles)