diff --git a/server/index.ts b/server/index.ts
index 48d2d21..c4c8b03 100644
--- a/server/index.ts
+++ b/server/index.ts
@@ -319,14 +319,17 @@ app.get("/", async (c) => {
});
// Create new space page
-app.get("/new", async (c) => {
- const file = Bun.file(resolve(DIST_DIR, "index.html"));
+app.get("/create-space", async (c) => {
+ const file = Bun.file(resolve(DIST_DIR, "create-space.html"));
if (await file.exists()) {
return new Response(file, { headers: { "Content-Type": "text/html" } });
}
return c.text("Create space", 200);
});
+// Legacy redirect
+app.get("/new", (c) => c.redirect("/create-space", 301));
+
// Space root: /:space → redirect to /:space/canvas
app.get("/:space", (c) => {
const space = c.req.param("space");
diff --git a/vite.config.ts b/vite.config.ts
index e295fb0..896441c 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -704,6 +704,7 @@ export default defineConfig({
input: {
index: resolve(__dirname, "./website/index.html"),
canvas: resolve(__dirname, "./website/canvas.html"),
+ "create-space": resolve(__dirname, "./website/create-space.html"),
},
},
modulePreload: {
diff --git a/website/create-space.html b/website/create-space.html
new file mode 100644
index 0000000..d3c241d
--- /dev/null
+++ b/website/create-space.html
@@ -0,0 +1,317 @@
+
+
+
+
+
+
+ Create a Space — rSpace
+
+
+
+
+
+
+
+
+
Create a Space
+
Start a collaborative community space with all the r* tools built in.
+
+
+
+
← Back to rSpace
+
+
+
+
+
+
diff --git a/website/index.html b/website/index.html
index 9ca9d78..888c994 100644
--- a/website/index.html
+++ b/website/index.html
@@ -52,75 +52,47 @@
margin-bottom: 3rem;
}
- .create-form {
+ .cta-buttons {
display: flex;
- flex-direction: column;
gap: 1rem;
- background: rgba(255, 255, 255, 0.05);
- padding: 2rem;
- border-radius: 16px;
- border: 1px solid rgba(255, 255, 255, 0.1);
+ justify-content: center;
+ flex-wrap: wrap;
}
- .form-group {
- display: flex;
- flex-direction: column;
- gap: 0.5rem;
- text-align: left;
- }
-
- label {
- font-size: 0.875rem;
- color: #94a3b8;
- }
-
- input {
- padding: 12px 16px;
+ .cta-primary {
+ display: inline-block;
+ padding: 14px 32px;
border-radius: 8px;
- border: 1px solid rgba(255, 255, 255, 0.2);
- background: rgba(255, 255, 255, 0.05);
- color: white;
- font-size: 1rem;
- }
-
- input:focus {
- outline: none;
- border-color: #14b8a6;
- }
-
- input::placeholder {
- color: #64748b;
- }
-
- .slug-preview {
- font-size: 0.875rem;
- color: #64748b;
- margin-top: 0.25rem;
- }
-
- .slug-preview span {
- color: #14b8a6;
- }
-
- button {
- padding: 14px 28px;
- border-radius: 8px;
- border: none;
background: linear-gradient(135deg, #14b8a6, #0d9488);
color: white;
font-size: 1rem;
font-weight: 600;
- cursor: pointer;
+ text-decoration: none;
transition: transform 0.2s, box-shadow 0.2s;
}
- button:hover {
+ .cta-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(20, 184, 166, 0.3);
}
- button:active {
- transform: translateY(0);
+ .cta-secondary {
+ display: inline-block;
+ padding: 14px 32px;
+ border-radius: 8px;
+ background: rgba(255, 255, 255, 0.05);
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ color: #94a3b8;
+ font-size: 1rem;
+ font-weight: 600;
+ text-decoration: none;
+ transition: transform 0.2s, border-color 0.2s, color 0.2s;
+ }
+
+ .cta-secondary:hover {
+ transform: translateY(-2px);
+ border-color: rgba(255, 255, 255, 0.4);
+ color: white;
}
.features {
@@ -149,17 +121,6 @@
color: #64748b;
}
- .error {
- color: #ef4444;
- font-size: 0.875rem;
- margin-top: 0.5rem;
- }
-
- .success {
- color: #22c55e;
- font-size: 0.875rem;
- }
-
/* EncryptID & Ecosystem Sections */
.section {
@@ -354,30 +315,10 @@
rSpace
Collaborative community spaces powered by FolkJS
-
+
@@ -580,94 +521,14 @@
import { RStackIdentity } from "@shared/components/rstack-identity";
import { RStackAppSwitcher } from "@shared/components/rstack-app-switcher";
import { RStackSpaceSwitcher } from "@shared/components/rstack-space-switcher";
- import { requireAuth, isAuthenticated, getAccessToken } from "@shared/components/rstack-identity";
- // Register shell header components
RStackIdentity.define();
RStackAppSwitcher.define();
RStackSpaceSwitcher.define();
- // Load module list for app switcher
fetch("/api/modules").then(r => r.json()).then(data => {
document.querySelector("rstack-app-switcher")?.setModules(data.modules || []);
}).catch(() => {});
-
- const nameInput = document.getElementById("community-name");
- const slugInput = document.getElementById("community-slug");
- const slugPreview = document.getElementById("slug-preview");
- const form = document.getElementById("create-form");
- const errorMessage = document.getElementById("error-message");
-
- // Auto-generate slug from name
- nameInput.addEventListener("input", () => {
- const slug = nameInput.value
- .toLowerCase()
- .replace(/[^a-z0-9]+/g, "-")
- .replace(/^-|-$/g, "");
- slugInput.value = slug;
- slugPreview.textContent = slug ? `${slug}.rspace.online` : "___.rspace.online";
- });
-
- slugInput.addEventListener("input", () => {
- const slug = slugInput.value.toLowerCase().replace(/[^a-z0-9-]/g, "");
- slugInput.value = slug;
- slugPreview.textContent = slug ? `${slug}.rspace.online` : "___.rspace.online";
- });
-
- async function submitCreateCommunity() {
- errorMessage.style.display = "none";
-
- const name = nameInput.value.trim();
- const slug = slugInput.value.trim();
-
- if (!name || !slug) {
- errorMessage.textContent = "Please fill in all fields";
- errorMessage.style.display = "block";
- return;
- }
-
- const token = getAccessToken();
- if (!token) {
- errorMessage.textContent = "Authentication token missing. Please sign in again.";
- errorMessage.style.display = "block";
- return;
- }
-
- try {
- const response = await fetch("/api/communities", {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- "Authorization": `Bearer ${token}`,
- },
- body: JSON.stringify({ name, slug }),
- });
-
- const data = await response.json();
-
- if (!response.ok) {
- throw new Error(data.error || "Failed to create community");
- }
-
- // Redirect to the new community space
- window.location.href = data.url;
- } catch (err) {
- errorMessage.textContent = err.message;
- errorMessage.style.display = "block";
- }
- }
-
- form.addEventListener("submit", (e) => {
- e.preventDefault();
-
- // If not authenticated, show auth modal; after success, re-submit
- if (!isAuthenticated()) {
- requireAuth(() => submitCreateCommunity());
- return;
- }
-
- submitCreateCommunity();
- });