diff --git a/package-lock.json b/package-lock.json
index 8a14d7ef..c82b1de7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -20,6 +20,7 @@
"@ory/client": "^1.21.3",
"@ory/elements-react": "^1.0.0-next.41",
"@ory/nextjs": "^1.0.0-rc.0",
+ "@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-form": "^0.1.3-rc.7",
"@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-label": "^2.1.2",
@@ -7615,20 +7616,192 @@
}
},
"node_modules/@radix-ui/react-accordion": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.3.tgz",
- "integrity": "sha512-RIQ15mrcvqIkDARJeERSuXSry2N8uYnxkdDetpfmalT/+0ntOXLkFOsh9iwlAsCv+qcmhZjbdJogIm6WBa6c4A==",
+ "version": "1.2.12",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz",
+ "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==",
"license": "MIT",
"dependencies": {
- "@radix-ui/primitive": "1.1.1",
- "@radix-ui/react-collapsible": "1.1.3",
- "@radix-ui/react-collection": "1.1.2",
- "@radix-ui/react-compose-refs": "1.1.1",
- "@radix-ui/react-context": "1.1.1",
- "@radix-ui/react-direction": "1.1.0",
- "@radix-ui/react-id": "1.1.0",
- "@radix-ui/react-primitive": "2.0.2",
- "@radix-ui/react-use-controllable-state": "1.1.0"
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-collapsible": "1.1.12",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/primitive": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
+ "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
+ "license": "MIT"
+ },
+ "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-collapsible": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz",
+ "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-collection": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
+ "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-slot": "1.2.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
+ "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-context": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
+ "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-direction": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
+ "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-id": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
+ "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
+ "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-primitive": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
+ "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.2.3"
},
"peerDependencies": {
"@types/react": "*",
@@ -7645,6 +7818,40 @@
}
}
},
+ "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-use-controllable-state": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
+ "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-effect-event": "0.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+ "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-alert-dialog": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.6.tgz",
@@ -8870,12 +9077,12 @@
}
},
"node_modules/@radix-ui/react-slot": {
- "version": "1.1.3-rc.5",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.3-rc.5.tgz",
- "integrity": "sha512-WwmUDNOa3qV692WUmWXjBDl5BqH4JEC5N0PR4cXbJIxSkNiKYHsM3p6grTvSfjH/LjYptS46R3+u8Vu6gMTRPQ==",
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
+ "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
"license": "MIT",
"dependencies": {
- "@radix-ui/react-compose-refs": "1.1.2-rc.5"
+ "@radix-ui/react-compose-refs": "1.1.2"
},
"peerDependencies": {
"@types/react": "*",
@@ -8888,9 +9095,9 @@
}
},
"node_modules/@radix-ui/react-slot/node_modules/@radix-ui/react-compose-refs": {
- "version": "1.1.2-rc.5",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2-rc.5.tgz",
- "integrity": "sha512-sA8AapytHc1abpubHOGk8Uij8v1CG+bFnhdf3aw+fbMZP43h8/91Vrzd51fRAX1JyEnxEbqU1owG98YT2x/FQw==",
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
+ "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*",
@@ -9163,6 +9370,39 @@
}
}
},
+ "node_modules/@radix-ui/react-use-effect-event": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
+ "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-effect-event/node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+ "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-use-escape-keydown": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz",
@@ -21404,6 +21644,37 @@
}
}
},
+ "node_modules/radix-ui/node_modules/@radix-ui/react-accordion": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.3.tgz",
+ "integrity": "sha512-RIQ15mrcvqIkDARJeERSuXSry2N8uYnxkdDetpfmalT/+0ntOXLkFOsh9iwlAsCv+qcmhZjbdJogIm6WBa6c4A==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.1",
+ "@radix-ui/react-collapsible": "1.1.3",
+ "@radix-ui/react-collection": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.1",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-primitive": "2.0.2",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/radix-ui/node_modules/@radix-ui/react-form": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.2.tgz",
diff --git a/package.json b/package.json
index 9c3d1eb4..92380a89 100644
--- a/package.json
+++ b/package.json
@@ -33,6 +33,7 @@
"@ory/client": "^1.21.3",
"@ory/elements-react": "^1.0.0-next.41",
"@ory/nextjs": "^1.0.0-rc.0",
+ "@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-form": "^0.1.3-rc.7",
"@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-label": "^2.1.2",
diff --git a/public/img/dithered-globe.png b/public/img/dithered-globe.png
new file mode 100644
index 00000000..7279795a
Binary files /dev/null and b/public/img/dithered-globe.png differ
diff --git a/public/img/ringsIcon-dark.svg b/public/img/ringsIcon-dark.svg
new file mode 100644
index 00000000..2aedd145
--- /dev/null
+++ b/public/img/ringsIcon-dark.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/public/img/ringsIcon.svg b/public/img/ringsIcon.svg
new file mode 100644
index 00000000..13234d8b
--- /dev/null
+++ b/public/img/ringsIcon.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/public/logo/logo-dark.svg b/public/logo/logo-dark.svg
new file mode 100644
index 00000000..d8fc3acc
--- /dev/null
+++ b/public/logo/logo-dark.svg
@@ -0,0 +1,12 @@
+
+
+ 48 Slice
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/logo/logo-light.svg b/public/logo/logo-light.svg
new file mode 100644
index 00000000..ee0c9f09
--- /dev/null
+++ b/public/logo/logo-light.svg
@@ -0,0 +1,12 @@
+
+
+ 48 Slice
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/logo/logolockup-dark.svg b/public/logo/logolockup-dark.svg
new file mode 100644
index 00000000..ffd742c4
--- /dev/null
+++ b/public/logo/logolockup-dark.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/logo/logolockup-light.svg b/public/logo/logolockup-light.svg
new file mode 100644
index 00000000..794411f5
--- /dev/null
+++ b/public/logo/logolockup-light.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/[account_id]/IndividualProfilePage.tsx b/src/app/(app)/[account_id]/IndividualProfilePage.tsx
similarity index 100%
rename from src/app/[account_id]/IndividualProfilePage.tsx
rename to src/app/(app)/[account_id]/IndividualProfilePage.tsx
diff --git a/src/app/[account_id]/OrganizationProfilePage.tsx b/src/app/(app)/[account_id]/OrganizationProfilePage.tsx
similarity index 97%
rename from src/app/[account_id]/OrganizationProfilePage.tsx
rename to src/app/(app)/[account_id]/OrganizationProfilePage.tsx
index cf8c870d..28c3c090 100644
--- a/src/app/[account_id]/OrganizationProfilePage.tsx
+++ b/src/app/(app)/[account_id]/OrganizationProfilePage.tsx
@@ -1,5 +1,5 @@
import { Container, Box } from "@radix-ui/themes";
-import { OrganizationProfile } from "../../components/features/profiles/OrganizationProfile";
+import { OrganizationProfile } from "@/components/features/profiles/OrganizationProfile";
import { PendingInvitationBanner } from "@/components/features/memberships/PendingInvitationBanner";
import {
accountsTable,
diff --git a/src/app/[account_id]/[product_id]/(product)/[[...path]]/@readme/loading.tsx b/src/app/(app)/[account_id]/[product_id]/(product)/[[...path]]/@readme/loading.tsx
similarity index 100%
rename from src/app/[account_id]/[product_id]/(product)/[[...path]]/@readme/loading.tsx
rename to src/app/(app)/[account_id]/[product_id]/(product)/[[...path]]/@readme/loading.tsx
diff --git a/src/app/[account_id]/[product_id]/(product)/[[...path]]/@readme/page.tsx b/src/app/(app)/[account_id]/[product_id]/(product)/[[...path]]/@readme/page.tsx
similarity index 100%
rename from src/app/[account_id]/[product_id]/(product)/[[...path]]/@readme/page.tsx
rename to src/app/(app)/[account_id]/[product_id]/(product)/[[...path]]/@readme/page.tsx
diff --git a/src/app/[account_id]/[product_id]/(product)/[[...path]]/layout.tsx b/src/app/(app)/[account_id]/[product_id]/(product)/[[...path]]/layout.tsx
similarity index 100%
rename from src/app/[account_id]/[product_id]/(product)/[[...path]]/layout.tsx
rename to src/app/(app)/[account_id]/[product_id]/(product)/[[...path]]/layout.tsx
diff --git a/src/app/[account_id]/[product_id]/(product)/[[...path]]/loading.tsx b/src/app/(app)/[account_id]/[product_id]/(product)/[[...path]]/loading.tsx
similarity index 100%
rename from src/app/[account_id]/[product_id]/(product)/[[...path]]/loading.tsx
rename to src/app/(app)/[account_id]/[product_id]/(product)/[[...path]]/loading.tsx
diff --git a/src/app/[account_id]/[product_id]/(product)/[[...path]]/page.test.tsx b/src/app/(app)/[account_id]/[product_id]/(product)/[[...path]]/page.test.tsx
similarity index 100%
rename from src/app/[account_id]/[product_id]/(product)/[[...path]]/page.test.tsx
rename to src/app/(app)/[account_id]/[product_id]/(product)/[[...path]]/page.test.tsx
diff --git a/src/app/[account_id]/[product_id]/(product)/[[...path]]/page.tsx b/src/app/(app)/[account_id]/[product_id]/(product)/[[...path]]/page.tsx
similarity index 100%
rename from src/app/[account_id]/[product_id]/(product)/[[...path]]/page.tsx
rename to src/app/(app)/[account_id]/[product_id]/(product)/[[...path]]/page.tsx
diff --git a/src/app/[account_id]/[product_id]/loading.tsx b/src/app/(app)/[account_id]/[product_id]/loading.tsx
similarity index 100%
rename from src/app/[account_id]/[product_id]/loading.tsx
rename to src/app/(app)/[account_id]/[product_id]/loading.tsx
diff --git a/src/app/[account_id]/[product_id]/not-found.tsx b/src/app/(app)/[account_id]/[product_id]/not-found.tsx
similarity index 100%
rename from src/app/[account_id]/[product_id]/not-found.tsx
rename to src/app/(app)/[account_id]/[product_id]/not-found.tsx
diff --git a/src/app/[account_id]/loading.tsx b/src/app/(app)/[account_id]/loading.tsx
similarity index 100%
rename from src/app/[account_id]/loading.tsx
rename to src/app/(app)/[account_id]/loading.tsx
diff --git a/src/app/[account_id]/not-found.tsx b/src/app/(app)/[account_id]/not-found.tsx
similarity index 100%
rename from src/app/[account_id]/not-found.tsx
rename to src/app/(app)/[account_id]/not-found.tsx
diff --git a/src/app/[account_id]/organization/new/layout.tsx b/src/app/(app)/[account_id]/organization/new/layout.tsx
similarity index 100%
rename from src/app/[account_id]/organization/new/layout.tsx
rename to src/app/(app)/[account_id]/organization/new/layout.tsx
diff --git a/src/app/[account_id]/organization/new/loading.tsx b/src/app/(app)/[account_id]/organization/new/loading.tsx
similarity index 100%
rename from src/app/[account_id]/organization/new/loading.tsx
rename to src/app/(app)/[account_id]/organization/new/loading.tsx
diff --git a/src/app/[account_id]/organization/new/page.tsx b/src/app/(app)/[account_id]/organization/new/page.tsx
similarity index 100%
rename from src/app/[account_id]/organization/new/page.tsx
rename to src/app/(app)/[account_id]/organization/new/page.tsx
diff --git a/src/app/[account_id]/page.test.tsx b/src/app/(app)/[account_id]/page.test.tsx
similarity index 100%
rename from src/app/[account_id]/page.test.tsx
rename to src/app/(app)/[account_id]/page.test.tsx
diff --git a/src/app/[account_id]/page.tsx b/src/app/(app)/[account_id]/page.tsx
similarity index 94%
rename from src/app/[account_id]/page.tsx
rename to src/app/(app)/[account_id]/page.tsx
index 607a24f3..17c3af41 100644
--- a/src/app/[account_id]/page.tsx
+++ b/src/app/(app)/[account_id]/page.tsx
@@ -12,7 +12,7 @@
import { Metadata } from "next";
import { notFound } from "next/navigation";
-import { OrganizationProfilePage } from "@/app/[account_id]/OrganizationProfilePage";
+import { OrganizationProfilePage } from "@/app/(app)/[account_id]/OrganizationProfilePage";
import { accountsTable, isOrganizationalAccount } from "@/lib/clients/database";
import { IndividualProfilePage } from "./IndividualProfilePage";
import {
diff --git a/src/app/edit/account/[account_id]/layout.tsx b/src/app/(app)/edit/account/[account_id]/layout.tsx
similarity index 100%
rename from src/app/edit/account/[account_id]/layout.tsx
rename to src/app/(app)/edit/account/[account_id]/layout.tsx
diff --git a/src/app/edit/account/[account_id]/memberships/loading.tsx b/src/app/(app)/edit/account/[account_id]/memberships/loading.tsx
similarity index 100%
rename from src/app/edit/account/[account_id]/memberships/loading.tsx
rename to src/app/(app)/edit/account/[account_id]/memberships/loading.tsx
diff --git a/src/app/edit/account/[account_id]/memberships/page.tsx b/src/app/(app)/edit/account/[account_id]/memberships/page.tsx
similarity index 100%
rename from src/app/edit/account/[account_id]/memberships/page.tsx
rename to src/app/(app)/edit/account/[account_id]/memberships/page.tsx
diff --git a/src/app/edit/account/[account_id]/page.tsx b/src/app/(app)/edit/account/[account_id]/page.tsx
similarity index 100%
rename from src/app/edit/account/[account_id]/page.tsx
rename to src/app/(app)/edit/account/[account_id]/page.tsx
diff --git a/src/app/edit/account/[account_id]/permissions/loading.tsx b/src/app/(app)/edit/account/[account_id]/permissions/loading.tsx
similarity index 100%
rename from src/app/edit/account/[account_id]/permissions/loading.tsx
rename to src/app/(app)/edit/account/[account_id]/permissions/loading.tsx
diff --git a/src/app/edit/account/[account_id]/permissions/page.tsx b/src/app/(app)/edit/account/[account_id]/permissions/page.tsx
similarity index 100%
rename from src/app/edit/account/[account_id]/permissions/page.tsx
rename to src/app/(app)/edit/account/[account_id]/permissions/page.tsx
diff --git a/src/app/edit/account/[account_id]/profile-picture/loading.tsx b/src/app/(app)/edit/account/[account_id]/profile-picture/loading.tsx
similarity index 100%
rename from src/app/edit/account/[account_id]/profile-picture/loading.tsx
rename to src/app/(app)/edit/account/[account_id]/profile-picture/loading.tsx
diff --git a/src/app/edit/account/[account_id]/profile-picture/page.tsx b/src/app/(app)/edit/account/[account_id]/profile-picture/page.tsx
similarity index 100%
rename from src/app/edit/account/[account_id]/profile-picture/page.tsx
rename to src/app/(app)/edit/account/[account_id]/profile-picture/page.tsx
diff --git a/src/app/edit/account/[account_id]/profile/loading.tsx b/src/app/(app)/edit/account/[account_id]/profile/loading.tsx
similarity index 100%
rename from src/app/edit/account/[account_id]/profile/loading.tsx
rename to src/app/(app)/edit/account/[account_id]/profile/loading.tsx
diff --git a/src/app/edit/account/[account_id]/profile/page.tsx b/src/app/(app)/edit/account/[account_id]/profile/page.tsx
similarity index 100%
rename from src/app/edit/account/[account_id]/profile/page.tsx
rename to src/app/(app)/edit/account/[account_id]/profile/page.tsx
diff --git a/src/app/edit/loading.tsx b/src/app/(app)/edit/loading.tsx
similarity index 100%
rename from src/app/edit/loading.tsx
rename to src/app/(app)/edit/loading.tsx
diff --git a/src/app/edit/page.tsx b/src/app/(app)/edit/page.tsx
similarity index 100%
rename from src/app/edit/page.tsx
rename to src/app/(app)/edit/page.tsx
diff --git a/src/app/edit/product/[account_id]/[product_id]/details/page.tsx b/src/app/(app)/edit/product/[account_id]/[product_id]/details/page.tsx
similarity index 100%
rename from src/app/edit/product/[account_id]/[product_id]/details/page.tsx
rename to src/app/(app)/edit/product/[account_id]/[product_id]/details/page.tsx
diff --git a/src/app/edit/product/[account_id]/[product_id]/layout.tsx b/src/app/(app)/edit/product/[account_id]/[product_id]/layout.tsx
similarity index 100%
rename from src/app/edit/product/[account_id]/[product_id]/layout.tsx
rename to src/app/(app)/edit/product/[account_id]/[product_id]/layout.tsx
diff --git a/src/app/edit/product/[account_id]/[product_id]/memberships/page.tsx b/src/app/(app)/edit/product/[account_id]/[product_id]/memberships/page.tsx
similarity index 100%
rename from src/app/edit/product/[account_id]/[product_id]/memberships/page.tsx
rename to src/app/(app)/edit/product/[account_id]/[product_id]/memberships/page.tsx
diff --git a/src/app/edit/product/[account_id]/[product_id]/not-found.tsx b/src/app/(app)/edit/product/[account_id]/[product_id]/not-found.tsx
similarity index 100%
rename from src/app/edit/product/[account_id]/[product_id]/not-found.tsx
rename to src/app/(app)/edit/product/[account_id]/[product_id]/not-found.tsx
diff --git a/src/app/edit/product/[account_id]/[product_id]/page.tsx b/src/app/(app)/edit/product/[account_id]/[product_id]/page.tsx
similarity index 100%
rename from src/app/edit/product/[account_id]/[product_id]/page.tsx
rename to src/app/(app)/edit/product/[account_id]/[product_id]/page.tsx
diff --git a/src/app/edit/product/[account_id]/page.tsx b/src/app/(app)/edit/product/[account_id]/page.tsx
similarity index 100%
rename from src/app/edit/product/[account_id]/page.tsx
rename to src/app/(app)/edit/product/[account_id]/page.tsx
diff --git a/src/app/email-verified/layout.tsx b/src/app/(app)/email-verified/layout.tsx
similarity index 100%
rename from src/app/email-verified/layout.tsx
rename to src/app/(app)/email-verified/layout.tsx
diff --git a/src/app/email-verified/loading.tsx b/src/app/(app)/email-verified/loading.tsx
similarity index 100%
rename from src/app/email-verified/loading.tsx
rename to src/app/(app)/email-verified/loading.tsx
diff --git a/src/app/email-verified/page.tsx b/src/app/(app)/email-verified/page.tsx
similarity index 100%
rename from src/app/email-verified/page.tsx
rename to src/app/(app)/email-verified/page.tsx
diff --git a/src/app/loading.tsx b/src/app/(app)/featured/loading.tsx
similarity index 100%
rename from src/app/loading.tsx
rename to src/app/(app)/featured/loading.tsx
diff --git a/src/app/page.tsx b/src/app/(app)/featured/page.tsx
similarity index 94%
rename from src/app/page.tsx
rename to src/app/(app)/featured/page.tsx
index 5deae1a2..368ddd0d 100644
--- a/src/app/page.tsx
+++ b/src/app/(app)/featured/page.tsx
@@ -18,7 +18,7 @@ export const metadata = {
},
};
-export default async function HomePage() {
+export default async function FeaturedProductsPage() {
// Fetch featured products on the server
const result = await getProducts({
featuredOnly: true,
diff --git a/src/app/feed.xml/route.ts b/src/app/(app)/feed.xml/route.ts
similarity index 100%
rename from src/app/feed.xml/route.ts
rename to src/app/(app)/feed.xml/route.ts
diff --git a/src/app/(app)/layout.tsx b/src/app/(app)/layout.tsx
new file mode 100644
index 00000000..c801183c
--- /dev/null
+++ b/src/app/(app)/layout.tsx
@@ -0,0 +1,20 @@
+import { Box, Container, Flex } from "@radix-ui/themes";
+import { Navigation, Footer } from "@/components";
+
+interface AppLayoutProps {
+ children: React.ReactNode;
+}
+
+export default async function AppLayout({ children }: AppLayoutProps) {
+ return (
+
+
+
+
+ {children}
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/app/auth/logout/route.tsx b/src/app/(app)/logout/route.tsx
similarity index 100%
rename from src/app/auth/logout/route.tsx
rename to src/app/(app)/logout/route.tsx
diff --git a/src/app/onboarding/layout.tsx b/src/app/(app)/onboarding/layout.tsx
similarity index 100%
rename from src/app/onboarding/layout.tsx
rename to src/app/(app)/onboarding/layout.tsx
diff --git a/src/app/onboarding/loading.tsx b/src/app/(app)/onboarding/loading.tsx
similarity index 100%
rename from src/app/onboarding/loading.tsx
rename to src/app/(app)/onboarding/loading.tsx
diff --git a/src/app/onboarding/page.tsx b/src/app/(app)/onboarding/page.tsx
similarity index 100%
rename from src/app/onboarding/page.tsx
rename to src/app/(app)/onboarding/page.tsx
diff --git a/src/app/products/loading.tsx b/src/app/(app)/products/loading.tsx
similarity index 100%
rename from src/app/products/loading.tsx
rename to src/app/(app)/products/loading.tsx
diff --git a/src/app/products/new/layout.tsx b/src/app/(app)/products/new/layout.tsx
similarity index 100%
rename from src/app/products/new/layout.tsx
rename to src/app/(app)/products/new/layout.tsx
diff --git a/src/app/products/new/loading.tsx b/src/app/(app)/products/new/loading.tsx
similarity index 100%
rename from src/app/products/new/loading.tsx
rename to src/app/(app)/products/new/loading.tsx
diff --git a/src/app/products/new/page.tsx b/src/app/(app)/products/new/page.tsx
similarity index 100%
rename from src/app/products/new/page.tsx
rename to src/app/(app)/products/new/page.tsx
diff --git a/src/app/products/page.test.tsx b/src/app/(app)/products/page.test.tsx
similarity index 100%
rename from src/app/products/page.test.tsx
rename to src/app/(app)/products/page.test.tsx
diff --git a/src/app/products/page.tsx b/src/app/(app)/products/page.tsx
similarity index 100%
rename from src/app/products/page.tsx
rename to src/app/(app)/products/page.tsx
diff --git a/src/app/(marketing)/CaseStudyCarousel.tsx b/src/app/(marketing)/CaseStudyCarousel.tsx
new file mode 100644
index 00000000..4e83d1ce
--- /dev/null
+++ b/src/app/(marketing)/CaseStudyCarousel.tsx
@@ -0,0 +1,111 @@
+"use client";
+
+import { useState } from "react";
+import { Blockquote, Box, Flex, Link, Text } from "@radix-ui/themes";
+import styles from "./Landing.module.css";
+
+const CASE_STUDIES = [
+ {
+ content:
+ "We can solve this question for ourselves, but the point of our work is to bring the world's attention to these rural communities and their needs. We want to make sure the data we develop and the insights we generate are accessible to other organizations and people. That's what brought us to Source.",
+ byline:
+ "— Cameron Kruse, Bridges to Prosperity Director of Digital Technology",
+ url: "https://docs.source.coop/case-studies/bridges-to-prosperity",
+ },
+ {
+ content:
+ "I value Source Cooperative as a scalable, practically unlimited in size, data store for open data. I could store the data in a commercial account that I manage, but I prefer using a well-known, discoverable space for storage. I like using Source when it's for a broader public good, one which provides public usefulness.",
+ byline: "— Alex Leith, Auspatious Founder",
+ url: "https://docs.source.coop/case-studies/auspatious",
+ },
+ {
+ content:
+ "Source has allowed us to open up all of this data to really anybody in the world… we would have been hesitant to do this without Source. We get people from local communities, indigenous groups, and others from almost every continent, who have reached out to us about this data.",
+ byline: '— Tom "Hutch" Ingold, Earth Genome, CTO',
+ url: "https://docs.source.coop/case-studies/earth-genome",
+ },
+];
+
+// All slides share a fixed height so the track translation math stays simple.
+// Increase if the longest quote ever overflows.
+const SLIDE_H = 260;
+const PEEK = Math.round(SLIDE_H * 0.2); // 52px visible above and below
+
+export function CaseStudyCarousel() {
+ const [index, setIndex] = useState(0);
+
+ const canPrev = index > 0;
+ const canNext = index < CASE_STUDIES.length - 1;
+
+ const goPrev = () => canPrev && setIndex((i) => i - 1);
+ const goNext = () => canNext && setIndex((i) => i + 1);
+
+ // Shift the track so the active slide sits below the top peek slot
+ const trackY = PEEK - index * SLIDE_H;
+
+ return (
+
+ {/* Clipping viewport */}
+
+ {/* Sliding track */}
+
+ {CASE_STUDIES.map((study, i) => (
+
+
+ "{study.content}"
+
+
+ {study.byline}
+
+
+ Read case study →
+
+
+ ))}
+
+
+
+ {/* Arrows — outside the viewport, vertically centered by the parent Flex */}
+
+
+ ↑
+
+
+ ↓
+
+
+
+ );
+}
diff --git a/src/app/(marketing)/Landing.module.css b/src/app/(marketing)/Landing.module.css
new file mode 100644
index 00000000..1eb0ccc8
--- /dev/null
+++ b/src/app/(marketing)/Landing.module.css
@@ -0,0 +1,233 @@
+.landing, :global(.light) .landing, :global(.light-theme) .landing, :global(.radix-themes) :global(.light) .landing {
+ --gray-1: #F8F8F8;
+ --gray-2: #EDECEA;
+ --gray-3: #E5E3E4;
+ --gray-4: #D3CED1;
+ --gray-5: #B8B1B5;
+ --gray-6: #9E959A;
+ --gray-7: #867C81;
+ --gray-8: #6F666B;
+ --gray-9: #5E565A;
+ --gray-10: #514B4E;
+ --gray-11: #292628;
+ --gray-12: #1c2124;
+
+ --gray-a1: #2d606005;
+ --gray-a2: #164e4e09;
+ --gray-a3: #062c4614;
+ --gray-a4: #0225371d;
+ --gray-a5: #07273b27;
+ --gray-a6: #041f352f;
+ --gray-a7: #0220313b;
+ --gray-a8: #031f2f51;
+ --gray-a9: #00121c80;
+ --gray-a10: #000f188a;
+ --gray-a11: #000910a7;
+ --gray-a12: #01070ae3;
+
+ --gray-contrast: #FFFFFF;
+ --gray-surface: #ffffffcc;
+ --gray-indicator: #7c858a;
+ --gray-track: #7c858a;
+ --color-background: #edecea;
+}
+
+@supports (color: color(display-p3 1 1 1)) {
+ @media (color-gamut: p3) {
+ .landing, :global(.light) .landing, :global(.light-theme) .landing, :global(.radix-themes) :global(.light) .landing {
+ --gray-1: oklch(96.9% 0.0012 234);
+ --gray-2: oklch(95.9% 0.0022 234);
+ --gray-3: oklch(92.9% 0.0039 234);
+ --gray-4: oklch(90.4% 0.0051 234);
+ --gray-5: oklch(88% 0.0066 234);
+ --gray-6: oklch(85.5% 0.0076 234);
+ --gray-7: oklch(82.1% 0.0094 234);
+ --gray-8: oklch(76% 0.0127 234);
+ --gray-9: oklch(61.1% 0.0128 234);
+ --gray-10: oklch(57.6% 0.0122 234);
+ --gray-11: oklch(47.2% 0.0105 234);
+ --gray-12: oklch(24.4% 0.0088 234);
+
+ --gray-a1: color(display-p3 0.051 0.2824 0.2824 / 0.017);
+ --gray-a2: color(display-p3 0.0235 0.2627 0.2627 / 0.033);
+ --gray-a3: color(display-p3 0.0078 0.1137 0.2235 / 0.073);
+ --gray-a4: color(display-p3 0.0039 0.1098 0.1843 / 0.109);
+ --gray-a5: color(display-p3 0.0078 0.1137 0.1961 / 0.146);
+ --gray-a6: color(display-p3 0.0039 0.0941 0.1804 / 0.178);
+ --gray-a7: color(display-p3 0.0039 0.1059 0.1765 / 0.226);
+ --gray-a8: color(display-p3 0.0039 0.0941 0.1451 / 0.307);
+ --gray-a9: color(display-p3 0.0039 0.0588 0.0902 / 0.492);
+ --gray-a10: color(display-p3 0 0.051 0.0824 / 0.537);
+ --gray-a11: color(display-p3 0 0.0314 0.0549 / 0.65);
+ --gray-a12: color(display-p3 0 0.0196 0.0314 / 0.884);
+
+ --gray-contrast: #FFFFFF;
+ --gray-surface: color(display-p3 1 1 1 / 80%);
+ --gray-indicator: oklch(61.1% 0.0128 234);
+ --gray-track: oklch(61.1% 0.0128 234);
+ --color-background: #edecea;
+ }
+ }
+}
+
+:global(.dark) .landing, :global(.dark-theme) .landing, :global(.radix-themes) :global(.dark) .landing, :global(:is(.dark, .dark-theme)) .landing {
+ --gray-1: #31302e;
+ --gray-2: #363533;
+ --gray-3: #3e3c3a;
+ --gray-4: #42413f;
+ --gray-5: #474643;
+ --gray-6: #4e4c4a;
+ --gray-7: #595755;
+ --gray-8: #6e6d6b;
+ --gray-9: #797775;
+ --gray-10: #83817f;
+ --gray-11: #b8b6b4;
+ --gray-12: #eeedeb;
+
+ --gray-a1: #e30d0007;
+ --gray-a2: #f17f210d;
+ --gray-a3: #fdb17916;
+ --gray-a4: #fcc99c1b;
+ --gray-a5: #fdd4a821;
+ --gray-a6: #fbd5ba2a;
+ --gray-a7: #fce2cd37;
+ --gray-a8: #fff0e350;
+ --gray-a9: #fdefe55e;
+ --gray-a10: #fdf1e96a;
+ --gray-a11: #fef9f4aa;
+ --gray-a12: #fffdfbeb;
+
+ --gray-contrast: #FFFFFF;
+ --gray-surface: rgba(0, 0, 0, 0.05);
+ --gray-indicator: #797775;
+ --gray-track: #797775;
+ --color-background: #2c3134;
+}
+
+@supports (color: color(display-p3 1 1 1)) {
+ @media (color-gamut: p3) {
+ :global(.dark) .landing, :global(.dark-theme) .landing, :global(.radix-themes) :global(.dark) .landing {
+ --gray-1: oklch(30.9% 0.0036 84.56);
+ --gray-2: oklch(33% 0.0034 84.56);
+ --gray-3: oklch(35.8% 0.0043 84.56);
+ --gray-4: oklch(37.6% 0.0043 84.56);
+ --gray-5: oklch(39.3% 0.0043 84.56);
+ --gray-6: oklch(41.8% 0.0043 84.56);
+ --gray-7: oklch(45.8% 0.0043 84.56);
+ --gray-8: oklch(53.6% 0.0043 84.56);
+ --gray-9: oklch(57.1% 0.0043 84.56);
+ --gray-10: oklch(60.5% 0.0043 84.56);
+ --gray-11: oklch(77.8% 0.0043 84.56);
+ --gray-12: oklch(94.7% 0.0029 84.56);
+
+ --gray-a1: color(display-p3 0.9608 0 0 / 0.02);
+ --gray-a2: color(display-p3 1 0.5608 0.1137 / 0.043);
+ --gray-a3: color(display-p3 1 0.7255 0.498 / 0.081);
+ --gray-a4: color(display-p3 0.9961 0.8196 0.6353 / 0.1);
+ --gray-a5: color(display-p3 1 0.8588 0.6784 / 0.124);
+ --gray-a6: color(display-p3 0.9961 0.8627 0.7529 / 0.158);
+ --gray-a7: color(display-p3 0.9961 0.902 0.8235 / 0.21);
+ --gray-a8: color(display-p3 1 0.9529 0.902 / 0.31);
+ --gray-a9: color(display-p3 1 0.9529 0.9098 / 0.362);
+ --gray-a10: color(display-p3 0.9961 0.9608 0.9216 / 0.41);
+ --gray-a11: color(display-p3 1 0.9765 0.9608 / 0.662);
+ --gray-a12: color(display-p3 0.9961 0.9922 0.9843 / 0.92);
+
+ --gray-contrast: #FFFFFF;
+ --gray-surface: color(display-p3 0 0 0 / 5%);
+ --gray-indicator: oklch(57.1% 0.0043 84.56);
+ --gray-track: oklch(57.1% 0.0043 84.56);
+ --color-background: #2c3134;
+ }
+ }
+}
+
+.landing {
+ --heading-font-family: "Berkeley Mono", Menlo, Consolas, monospace;
+ background: var(--color-background);
+ overflow: hidden;
+}
+.landingInner {
+ border: 1px solid var(--gray-7);
+ border-top: 0;
+ border-bottom: 0;
+ overflow: hidden;
+ & > nav {
+ background: var(--gray-2);
+ }
+}
+.landing a {
+ font-family: var(--heading-font-family);
+ text-decoration: underline;
+ text-transform: uppercase;
+}
+
+.subheading {
+ text-transform: uppercase;
+ font-family: var(--heading-font-family);
+ font-weight: bold;
+ letter-spacing: 0.5px;
+}
+.heroImage {
+ mix-blend-mode: difference;
+}
+.productsSection {
+ border-bottom: 1px dashed var(--gray-9);
+ border-top: 1px dashed var(--gray-9);
+}
+.sectionDark {
+ background: var(--gray-12);
+ color: var(--gray-1);
+}
+.tout {
+ border-top: 1px solid var(--gray-7);
+}
+.toutPrice p:first-of-type {
+ font-family: "Berkeley Mono";
+ font-size: 0.75rem;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 1;
+ letter-spacing: 0.03rem;
+ text-transform: uppercase;
+}
+.toutHost p:first-of-type {
+ font-size: 8rem;
+ line-height: 100%;
+ margin: 0;
+}
+
+.priceAsterisk {
+ font-family: var(--heading-font-family);
+ line-height: 1;
+}
+.caseStudy {
+ border: 1px dashed var(--gray-7);
+}
+
+.carouselArrows {
+ cursor: pointer;
+ user-select: none;
+ font-family: var(--heading-font-family);
+ font-size: var(--font-size-4);
+}
+
+.carouselArrows span {
+ color: var(--gray-11);
+}
+
+.carouselArrows span:hover {
+ color: var(--gray-12);
+}
+
+.carouselViewport {
+ overflow: hidden;
+ position: relative;
+ flex: 1;
+}
+
+.carouselTrack {
+ position: absolute;
+ width: 100%;
+ transition: transform 0.4s ease;
+}
\ No newline at end of file
diff --git a/src/app/(marketing)/page.tsx b/src/app/(marketing)/page.tsx
new file mode 100644
index 00000000..7a6fa9dd
--- /dev/null
+++ b/src/app/(marketing)/page.tsx
@@ -0,0 +1,291 @@
+import {
+ Footer,
+ Navigation,
+ ProductsList,
+ ThemeAwareImage,
+} from "@/components";
+import { getProducts } from "@/lib/actions/products";
+import {
+ Badge,
+ Box,
+ Button,
+ Container,
+ Flex,
+ Heading,
+ Link,
+ Section,
+ Text,
+} from "@radix-ui/themes";
+import { CaseStudyCarousel } from "./CaseStudyCarousel";
+import { ThemeInverseComponent } from "@/components/layout/ThemeInverseComponent";
+import styles from "./Landing.module.css";
+import { productListUrl } from "@/lib/urls";
+
+function SectionSubheading({ children }: { children: React.ReactNode }) {
+ return (
+
+ {children}
+
+ );
+}
+
+
+export default async function Landing() {
+ const result = await getProducts({
+ featuredOnly: true,
+ limit: 10,
+ });
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+ The Cooperative Data Publishing Utility
+
+
+ Data publishing at any scale for everyone.
+
+
+ Upload, share, and access data without needing to build or maintain your own infrastructure.
+
+
+
+
+
+
+
+ Read the docs →
+
+
+
+
+ Explore Data Products →
+
+
+
+
+
+
+
+
+
+
+
+
+ Explore Source Datasets
+
+ Featured Products
+
+
+
+
+
+
+ What is Source Cooperative?
+
+
+
+ The Challenge
+
+
+ Scientific data infrastructure wasn't built for cross-border, cross-sector cooperation.
+
+ Addressing global challenges means combining data from governments, research institutions, commercial providers, and civil society—each with its own formats, access patterns, and APIs.
+
+ Data engineers, scientists, and researchers spend more time wrangling infrastructure than doing their actual work, hampering collaboration and limiting informed decision making.
+
+
+
+
+ Our Solution
+
+
+ Source is a nonprofit data publishing utility built on commodity cloud object storage. Researchers publish data at any scale without running servers, building portals, or writing APIs.
+
+ Source handles cloud infrastructure so researchers can focus on their data, not their hosting. Users access everything through standard URLs that work with existing tools—no custom portals, no proprietary APIs.
+ The service is intentionally commoditized: built to resist lock-in and designed so that no single provider, funder, or political decision can make research data disappear.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Why Source is different
+
+ Data publishing for everyone
+
+
+
+
+
+
+
+ Integrate into any workflow
+
+
+ Source is a vendor-neutral data publishing utility that works with any S3-compatible cloud provider.
+
+
+
+
+
+
+ *
+
+
+
+
+ Neutral hosting, mission backed
+
+
+ Retain full ownership and control of your data. Source
+ supports open formats and is a non-commercial
+ repository, so you're never trapped by
+ proprietary APIs or workflows.
+
+
+
+
+
+
+ S$S$S$S$S$S $S$S$S$S$S$ S$S$S$S$S$S $S$S$S$S$S$
+ S$S$S$S$S$S
+
+
+
+
+ Flat pricing
+
+
+ Instead of building and maintaining data portals or trying to wrangle variable cloud costs, Source lets you focus on the fundamentals that make data easy to publish and easy to use.
+
+ Pricing plans based on data volume and usage will be announced soon.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Case Studies
+
+ Open Source, Governed, and Trusted By These Teams
+
+
+
+
+
+
+
+
+
+
+
+ Built for Data Engineers, Scientists, and Developers
+
+
+
+
+ Source.Coop supports your data lifecycle, from prototyping
+ to public release, without navigating corporate cloud
+ policies.
+
+
+ Explore the data →
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index e6bc902f..f1da4c40 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -4,11 +4,10 @@ import { ThemeProvider } from "@/styles/theme";
import { SessionProvider } from "@ory/elements-react/client";
import NextTopLoader from "nextjs-toploader";
import { IBM_Plex_Sans } from "next/font/google";
-import { Container } from "@radix-ui/themes";
-import { S3CredentialsProvider } from "@/components/features/uploader/CredentialsProvider";
-import { UploadProvider } from "@/components/features/uploader/UploadProvider";
-import { Navigation } from "@/components/layout/Navigation";
-import { Footer } from "@/components/layout/Footer";
+import {
+ S3CredentialsProvider,
+ UploadProvider,
+} from "@/components";
import { metadata } from "./metadata";
const ibmPlexSans = IBM_Plex_Sans({
subsets: ["latin"],
@@ -36,13 +35,9 @@ export default async function RootLayout({ children }: RootLayoutProps) {
-
-
- {children}
-
+ {children}
-