Compare commits
54 Commits
developmen
...
main
Author | SHA1 | Date | |
---|---|---|---|
41d4c3a054 | |||
a362985d4c | |||
1d66fd60a4 | |||
43d995bbc2 | |||
0dedde3592 | |||
d5b9303d94 | |||
3a240177c4 | |||
0479b7330a | |||
a78bc67ed3 | |||
a035500c34 | |||
2b5c502724 | |||
a462afc8b2 | |||
bf78cde2d8 | |||
cde6c90033 | |||
f5ab743987 | |||
45364a7452 | |||
b7f25d712f | |||
2fdcb3697d | |||
204625b9a8 | |||
02557fcb82 | |||
9277bc7105 | |||
3f6ffbe4ea | |||
343b7ae22e | |||
5f6ad1c98d | |||
9e26dce717 | |||
8f997b2f86 | |||
f712a6c894 | |||
1708aadf1e | |||
dadf92559c | |||
c3481f3221 | |||
8d83f44a07 | |||
9faaf7dee9 | |||
fa7b8dbbb8 | |||
4b5c30c11e | |||
bde7d37305 | |||
b65f2aa538 | |||
be949d65bd | |||
9ee0d678c9 | |||
eb2ad2be3f | |||
34bd6522e3 | |||
273cb24a47 | |||
13ecc4d2ec | |||
979a6523fa | |||
de6a83a87c | |||
4aff3a5c6b | |||
78e1e51877 | |||
3df200c7d2 | |||
f4c247baa2 | |||
cbc89b192b | |||
c9af96e669 | |||
e3ede705c7 | |||
|
c49a51783a | ||
4618fc3525 | |||
6e06d215fa |
1
next-env.d.ts
vendored
@@ -1,5 +1,6 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
/// <reference types="next/navigation-types/compat/navigation" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
|
||||
|
@@ -1,4 +1,9 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {}
|
||||
const nextConfig = {
|
||||
output: 'export',
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = nextConfig
|
||||
|
85
package-lock.json
generated
@@ -9,9 +9,10 @@
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^2.1.0",
|
||||
"@heroicons/react": "^2.2.0",
|
||||
"@lobehub/icons": "^1.97.2",
|
||||
"@tabler/icons-react": "^3.35.0",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tailwindcss/postcss": "^4.1.7",
|
||||
"@types/node": "^20.10.8",
|
||||
"@types/react": "^18.2.55",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
@@ -34,6 +35,7 @@
|
||||
"use-debounce": "^10.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.13",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-next": "^14.0.4",
|
||||
"prettier": "^3.3.2",
|
||||
@@ -46,6 +48,7 @@
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
||||
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
@@ -639,6 +642,7 @@
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz",
|
||||
"integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
@@ -650,6 +654,7 @@
|
||||
"version": "0.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-0.44.0.tgz",
|
||||
"integrity": "sha512-ZX/etZEZw8DR7zAB1eVQT40lNo0jeqpb6dCgOvctB6FIQ5PoXfMuNY8+ayQfu8tNQbAB8gQWSSJupR8NxeiZXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
@@ -660,6 +665,7 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz",
|
||||
"integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
@@ -1025,6 +1031,15 @@
|
||||
"react-dom": "^18 || ^19 || ^19.0.0-rc"
|
||||
}
|
||||
},
|
||||
"node_modules/@heroicons/react": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.2.0.tgz",
|
||||
"integrity": "sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": ">= 16 || ^19.0.0-rc"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
|
||||
@@ -1617,6 +1632,7 @@
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
|
||||
"integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"minipass": "^7.0.4"
|
||||
@@ -1939,6 +1955,7 @@
|
||||
"version": "0.2.12",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
|
||||
"integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
@@ -1951,6 +1968,7 @@
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz",
|
||||
"integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
@@ -2959,6 +2977,32 @@
|
||||
"tslib": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tabler/icons": {
|
||||
"version": "3.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.35.0.tgz",
|
||||
"integrity": "sha512-yYXe+gJ56xlZFiXwV9zVoe3FWCGuZ/D7/G4ZIlDtGxSx5CGQK110wrnT29gUj52kEZoxqF7oURTk97GQxELOFQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/codecalm"
|
||||
}
|
||||
},
|
||||
"node_modules/@tabler/icons-react": {
|
||||
"version": "3.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.35.0.tgz",
|
||||
"integrity": "sha512-XG7t2DYf3DyHT5jxFNp5xyLVbL4hMJYJhiSdHADzAjLRYfL7AnjlRfiHDHeXxkb2N103rEIvTsBRazxXtAUz2g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tabler/icons": "3.35.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/codecalm"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/forms": {
|
||||
"version": "0.5.10",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.10.tgz",
|
||||
@@ -2975,6 +3019,7 @@
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.13.tgz",
|
||||
"integrity": "sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/remapping": "^2.3.4",
|
||||
@@ -2990,6 +3035,7 @@
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.13.tgz",
|
||||
"integrity": "sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3021,6 +3067,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3037,6 +3084,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3053,6 +3101,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3069,6 +3118,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3085,6 +3135,7 @@
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3101,6 +3152,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3117,6 +3169,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3133,6 +3186,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3149,6 +3203,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3173,6 +3228,7 @@
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
@@ -3194,6 +3250,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3210,6 +3267,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -3223,6 +3281,7 @@
|
||||
"version": "4.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.13.tgz",
|
||||
"integrity": "sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
@@ -3263,6 +3322,7 @@
|
||||
"version": "0.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
|
||||
"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
@@ -4982,6 +5042,7 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
|
||||
"integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
@@ -5886,6 +5947,7 @@
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
|
||||
"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
@@ -5971,6 +6033,7 @@
|
||||
"version": "5.18.3",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
|
||||
"integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
@@ -8402,6 +8465,7 @@
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz",
|
||||
"integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
@@ -8642,6 +8706,7 @@
|
||||
"version": "1.30.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
|
||||
"integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==",
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.3"
|
||||
@@ -8673,6 +8738,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -8693,6 +8759,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -8713,6 +8780,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -8733,6 +8801,7 @@
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -8753,6 +8822,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -8773,6 +8843,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -8793,6 +8864,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -8813,6 +8885,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -8833,6 +8906,7 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -8853,6 +8927,7 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -9003,6 +9078,7 @@
|
||||
"version": "0.30.19",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
|
||||
"integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
@@ -10223,6 +10299,7 @@
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
@@ -10232,6 +10309,7 @@
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz",
|
||||
"integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minipass": "^7.1.2"
|
||||
@@ -10257,6 +10335,7 @@
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
|
||||
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mkdirp": "dist/cjs/src/bin.js"
|
||||
@@ -11002,6 +11081,7 @@
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -13410,6 +13490,7 @@
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.3.tgz",
|
||||
"integrity": "sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
@@ -13423,6 +13504,7 @@
|
||||
"version": "7.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
|
||||
"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@isaacs/fs-minipass": "^4.0.0",
|
||||
@@ -14358,6 +14440,7 @@
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
|
||||
"integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
@@ -11,9 +11,10 @@
|
||||
"browserslist": "defaults, not ie <= 11",
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^2.1.0",
|
||||
"@heroicons/react": "^2.2.0",
|
||||
"@lobehub/icons": "^1.97.2",
|
||||
"@tabler/icons-react": "^3.35.0",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tailwindcss/postcss": "^4.1.7",
|
||||
"@types/node": "^20.10.8",
|
||||
"@types/react": "^18.2.55",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
@@ -36,6 +37,7 @@
|
||||
"use-debounce": "^10.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.13",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-next": "^14.0.4",
|
||||
"prettier": "^3.3.2",
|
||||
|
BIN
public/images/gallery/branding.jpg
Normal file
After Width: | Height: | Size: 101 KiB |
BIN
public/images/gallery/calendar.jpg
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
public/images/gallery/code.jpg
Normal file
After Width: | Height: | Size: 114 KiB |
BIN
public/images/gallery/data.jpg
Normal file
After Width: | Height: | Size: 177 KiB |
BIN
public/images/gallery/datasets.jpg
Normal file
After Width: | Height: | Size: 128 KiB |
BIN
public/images/gallery/docs.jpg
Normal file
After Width: | Height: | Size: 84 KiB |
BIN
public/images/gallery/flow.jpg
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
public/images/gallery/interface.jpg
Normal file
After Width: | Height: | Size: 110 KiB |
BIN
public/images/gallery/market.jpg
Normal file
After Width: | Height: | Size: 120 KiB |
BIN
public/images/gallery/structure.jpg
Normal file
After Width: | Height: | Size: 109 KiB |
BIN
public/images/gallery/translate.jpg
Normal file
After Width: | Height: | Size: 78 KiB |
BIN
public/images/getstarted.webp
Normal file
After Width: | Height: | Size: 281 KiB |
BIN
public/images/logomark.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
14
public/images/logomark.svg
Normal file
After Width: | Height: | Size: 112 KiB |
BIN
public/images/placeholder.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
public/images/stars.webp
Normal file
After Width: | Height: | Size: 329 KiB |
BIN
public/videos/agent.mp4
Normal file
BIN
public/videos/benefits.jpg
Normal file
After Width: | Height: | Size: 156 KiB |
BIN
public/videos/benefits.mp4
Normal file
BIN
public/videos/cta.mp4
Normal file
BIN
public/videos/deterministic.mp4
Normal file
BIN
public/videos/fungistor.mp4
Normal file
BIN
public/videos/herodb.mp4
Normal file
BIN
public/videos/mesh.mp4
Normal file
BIN
public/videos/sandbox.mp4
Normal file
BIN
public/videos/universal.mp4
Normal file
@@ -7,11 +7,13 @@ import { HomeAbout } from '@/components/HomeAbout'
|
||||
import { ClickableGallery } from '@/components/ClickableGallery'
|
||||
import { StackSectionPreview } from '@/components/StackSection'
|
||||
import { Companies } from '@/components/Companies'
|
||||
import { CallTo } from '@/components/CallTo'
|
||||
import { CallToAction } from '@/components/CallToAction'
|
||||
import { ScrollDown } from '@/components/ui/ScrollDown'
|
||||
import { ScrollUp } from '@/components/ui/ScrollUp'
|
||||
import { GridStats } from '@/components/GridStats'
|
||||
import { WorldMap } from '@/components/WorldMap'
|
||||
import { GetStarted } from '@/components/GetStarted'
|
||||
import { BentoReviews } from '@/components/BentoReviews'
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
@@ -19,26 +21,27 @@ export default function Home() {
|
||||
<section id="home-hero">
|
||||
<HomeHero />
|
||||
</section>
|
||||
<section id="companies">
|
||||
<Companies />
|
||||
<section id="about">
|
||||
<StackSectionPreview />
|
||||
</section>
|
||||
<section id="steps">
|
||||
<Steps />
|
||||
<section id="bento-reviews">
|
||||
<BentoReviews />
|
||||
</section>
|
||||
<section id="world-map">
|
||||
<section id="network">
|
||||
<WorldMap />
|
||||
</section>
|
||||
<section id="grid-stats">
|
||||
<GridStats />
|
||||
<section id="deploy">
|
||||
<Steps />
|
||||
</section>
|
||||
<section id="use-cases">
|
||||
<UseCases />
|
||||
<section id="llms">
|
||||
<Companies />
|
||||
</section>
|
||||
<section id="clickable-gallery">
|
||||
<ClickableGallery />
|
||||
</section>
|
||||
<section id="call-to-action">
|
||||
<CallTo />
|
||||
<CallToAction />
|
||||
</section>
|
||||
<ScrollDown />
|
||||
<ScrollUp />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
BIN
src/app/.DS_Store
vendored
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
263
src/components/Archives/1UseCases.tsx
Normal file
@@ -0,0 +1,263 @@
|
||||
'use client'
|
||||
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import clsx from 'clsx'
|
||||
import {
|
||||
ArchiveBoxIcon,
|
||||
CodeBracketIcon,
|
||||
CpuChipIcon,
|
||||
GlobeAltIcon,
|
||||
MagnifyingGlassIcon,
|
||||
ShareIcon,
|
||||
UserGroupIcon,
|
||||
CheckBadgeIcon,
|
||||
} from '@heroicons/react/24/solid'
|
||||
|
||||
import { Container } from '@/components/Container'
|
||||
import { H2, P, CT, CP } from '@/components/Texts'
|
||||
import { motion, useInView } from 'framer-motion'
|
||||
|
||||
interface Review {
|
||||
title: string
|
||||
body: string
|
||||
}
|
||||
|
||||
const reviews: Array<Review> = [
|
||||
{
|
||||
title: 'FungiStor: Long-Term AI Memory',
|
||||
body: 'Quantum-safe permanent storage preserving AI knowledge forever. Zero-knowledge architecture with mathematical dispersal ensures immortality.',
|
||||
},
|
||||
{
|
||||
title: 'HeroDB: Active AI Memory',
|
||||
body: 'High-performance datastore for AI working memory. Multi-modal indexing enables vector search with global accessibility.',
|
||||
},
|
||||
{
|
||||
title: 'MOS Sandboxes: Secure Agent Workspaces',
|
||||
body: 'Lightweight isolated environments deploying globally in five seconds. Hardware-level isolation ensures maximum security for agents.',
|
||||
},
|
||||
{
|
||||
title: 'Mycelium Mesh: Secure Communication Network',
|
||||
body: 'Peer-to-peer overlay network with end-to-end encryption. Self-healing shortest-path routing creates resilient agentic communication.',
|
||||
},
|
||||
{
|
||||
title: 'Deterministic Deployment: Verifiable Code Execution',
|
||||
body: 'Cryptographic guarantee system ensuring deployed code matches specifications. Prevents supply-chain attacks with immutable trails.',
|
||||
},
|
||||
{
|
||||
title: 'Agent Coordination: Sovereign Workflow Management',
|
||||
body: 'User-centric orchestration where HERO agents coordinate worker fleets. Planetary-scale coordination with instant spawning.',
|
||||
},
|
||||
{
|
||||
title: 'Universal Interface Layer: AI Service Gateway',
|
||||
body: 'Unified broker connecting agents to LLMs, APIs, and services. Integrated micropayments simplify development.',
|
||||
},
|
||||
{
|
||||
title: 'Semantic Index & Search: Navigable Knowledge Fabric',
|
||||
body: 'Transforms data chaos into unified knowledge graphs. Goes beyond keywords to understand meaning and context.',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
function getReviewIcon(title: string) {
|
||||
if (title.startsWith('FungiStor')) return ArchiveBoxIcon;
|
||||
if (title.startsWith('HeroDB')) return CpuChipIcon;
|
||||
if (title.startsWith('MOS Sandboxes')) return CodeBracketIcon;
|
||||
if (title.startsWith('Mycelium Mesh')) return ShareIcon;
|
||||
if (title.startsWith('Deterministic Deployment')) return CheckBadgeIcon;
|
||||
if (title.startsWith('Agent Coordination')) return UserGroupIcon;
|
||||
if (title.startsWith('Universal Interface Layer')) return GlobeAltIcon;
|
||||
if (title.startsWith('Semantic Index & Search')) return MagnifyingGlassIcon;
|
||||
return GlobeAltIcon; // default
|
||||
}
|
||||
|
||||
function Review({
|
||||
title,
|
||||
body,
|
||||
className,
|
||||
...props
|
||||
}: Omit<React.ComponentPropsWithoutRef<'figure'>, keyof Review> & Review) {
|
||||
let animationDelay = useMemo(() => {
|
||||
let possibleAnimationDelays = ['0s', '0.1s', '0.2s', '0.3s', '0.4s', '0.5s']
|
||||
return possibleAnimationDelays[
|
||||
Math.floor(Math.random() * possibleAnimationDelays.length)
|
||||
]
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<figure
|
||||
className={clsx(
|
||||
'animate-fade-in rounded-3xl bg-gray-900/50 p-6 opacity-0 shadow-md shadow-gray-900/5',
|
||||
className,
|
||||
)}
|
||||
style={{ animationDelay }}
|
||||
{...props}
|
||||
>
|
||||
<blockquote className="text-white">
|
||||
{React.createElement(getReviewIcon(title), { className: "h-6 w-6 text-white mb-2" })}
|
||||
<CT color="light" className="mt-4 text-lg/6 font-semibold">
|
||||
{title}
|
||||
</CT>
|
||||
<CP color="light" className="mt-3 text-sm">{body}</CP>
|
||||
</blockquote>
|
||||
|
||||
</figure>
|
||||
)
|
||||
}
|
||||
|
||||
function splitArray<T>(array: Array<T>, numParts: number) {
|
||||
let result: Array<Array<T>> = []
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
let index = i % numParts
|
||||
if (!result[index]) {
|
||||
result[index] = []
|
||||
}
|
||||
result[index].push(array[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function ReviewColumn({
|
||||
reviews,
|
||||
className,
|
||||
reviewClassName,
|
||||
msPerPixel = 0,
|
||||
}: {
|
||||
reviews: Array<Review>
|
||||
className?: string
|
||||
reviewClassName?: (reviewIndex: number) => string
|
||||
msPerPixel?: number
|
||||
}) {
|
||||
let columnRef = useRef<React.ElementRef<'div'>>(null)
|
||||
let [columnHeight, setColumnHeight] = useState(0)
|
||||
let duration = `${columnHeight * msPerPixel}ms`
|
||||
|
||||
useEffect(() => {
|
||||
if (!columnRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
let resizeObserver = new window.ResizeObserver(() => {
|
||||
setColumnHeight(columnRef.current?.offsetHeight ?? 0)
|
||||
})
|
||||
|
||||
resizeObserver.observe(columnRef.current)
|
||||
|
||||
return () => {
|
||||
resizeObserver.disconnect()
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={columnRef}
|
||||
className={clsx('animate-marquee space-y-8 py-4', className)}
|
||||
style={{ '--marquee-duration': duration } as React.CSSProperties}
|
||||
>
|
||||
{reviews.concat(reviews).map((review, reviewIndex) => (
|
||||
<Review
|
||||
key={reviewIndex}
|
||||
aria-hidden={reviewIndex >= reviews.length}
|
||||
className={reviewClassName?.(reviewIndex % reviews.length)}
|
||||
{...review}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function ReviewGrid() {
|
||||
let containerRef = useRef<React.ElementRef<'div'>>(null)
|
||||
let isInView = useInView(containerRef, { once: true, amount: 0.4 })
|
||||
let columns = splitArray(reviews, 3)
|
||||
let column1 = columns[0]
|
||||
let column2 = columns[1]
|
||||
let column3 = splitArray(columns[2], 2)
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="relative -mx-4 mt-0 grid h-196 max-h-[150vh] grid-cols-1 items-start gap-8 overflow-hidden px-4 md:grid-cols-2 lg:grid-cols-3"
|
||||
>
|
||||
{isInView && (
|
||||
<>
|
||||
<ReviewColumn
|
||||
reviews={[...column1, ...column3.flat(), ...column2]}
|
||||
reviewClassName={(reviewIndex) =>
|
||||
clsx(
|
||||
reviewIndex >= column1.length + column3[0].length &&
|
||||
'md:hidden',
|
||||
reviewIndex >= column1.length && 'lg:hidden',
|
||||
)
|
||||
}
|
||||
msPerPixel={10}
|
||||
/>
|
||||
<ReviewColumn
|
||||
reviews={[...column2, ...column3[1]]}
|
||||
className="hidden md:block"
|
||||
reviewClassName={(reviewIndex) =>
|
||||
reviewIndex >= column2.length ? 'lg:hidden' : ''
|
||||
}
|
||||
msPerPixel={15}
|
||||
/>
|
||||
<ReviewColumn
|
||||
reviews={column3.flat()}
|
||||
className="hidden lg:block"
|
||||
msPerPixel={10}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div className="pointer-events-none absolute inset-x-0 top-0 h-32 bg-linear-to-b from-black" />
|
||||
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-32 bg-linear-to-t from-black" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function UseCases() {
|
||||
const ref = useRef(null);
|
||||
const isInView = useInView(ref, { once: true });
|
||||
|
||||
return (
|
||||
<section
|
||||
id="usecases"
|
||||
ref={ref}
|
||||
aria-labelledby="usecases-title"
|
||||
className="bg-black py-24"
|
||||
>
|
||||
<Container className=''>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
||||
transition={{ duration: 0.8, delay: 0.1 }}
|
||||
className="mx-auto max-w-2xl lg:max-w-5xl"
|
||||
>
|
||||
<H2
|
||||
id="usecases-title"
|
||||
color="light"
|
||||
className="text-center"
|
||||
>
|
||||
Coming Soon: The Future of Mycelium
|
||||
</H2>
|
||||
<P className="mt-6 text-center" color="light">
|
||||
Mycelium Cloud is evolving to bring even more powerful decentralized features, designed to enhance your experience and expand possibilities. Be the first to explore what's coming next by staying connected with our latest updates.
|
||||
</P>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
|
||||
transition={{ duration: 1, delay: 0.2 }}
|
||||
aria-hidden="true"
|
||||
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
clipPath:
|
||||
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
|
||||
}}
|
||||
className="relative left-[calc(50%-30rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#93c5fd] to-[#9089fc] opacity-30 sm:left-[calc(50%-36rem)] sm:w-[72.1875rem]"
|
||||
/>
|
||||
</motion.div>
|
||||
<ReviewGrid />
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
116
src/components/Archives/Cubec.tsx
Normal file
@@ -0,0 +1,116 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import { motion } from "framer-motion";
|
||||
import { CT, CP } from '@/components/Texts';
|
||||
|
||||
interface CubeProps {
|
||||
title: string;
|
||||
descriptionTitle: string;
|
||||
description: string;
|
||||
isActive: boolean;
|
||||
index: number;
|
||||
onHover: () => void;
|
||||
onLeave: () => void;
|
||||
}
|
||||
|
||||
|
||||
export function Cube({ title, descriptionTitle, description, isActive, index, onHover, onLeave }: CubeProps) {
|
||||
return (
|
||||
<div className="relative flex flex-col items-center">
|
||||
<motion.div
|
||||
className="relative cursor-pointer pointer-events-none"
|
||||
onMouseEnter={onHover}
|
||||
onMouseLeave={onLeave}
|
||||
style={{
|
||||
zIndex: 10 - index,
|
||||
}}
|
||||
animate={{
|
||||
scale: isActive ? 1.05 : 1,
|
||||
}}
|
||||
transition={{
|
||||
duration: 0.3,
|
||||
ease: "easeOut",
|
||||
}}
|
||||
>
|
||||
{/* Image Cube */}
|
||||
<Image
|
||||
src="/images/cube.png"
|
||||
alt="Cube"
|
||||
width={507}
|
||||
height={234}
|
||||
className="w-60 sm:w-80 lg:w-96 h-auto drop-shadow-lg pointer-events-auto"
|
||||
style={{
|
||||
filter: isActive
|
||||
? 'brightness(1.1) drop-shadow(0 25px 25px rgba(144, 137, 252, 0.4))'
|
||||
: 'brightness(0.9) drop-shadow(0 10px 15px rgba(144, 137, 252, 0.2))',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Title overlay */}
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<CT as="h3" className="px-4 drop-shadow-lg" style={{ transform: 'rotate(0deg) skewX(0deg)', transformOrigin: 'center' }}>
|
||||
{title}
|
||||
</CT>
|
||||
</div>
|
||||
|
||||
{/* Description with arrow line - Desktop */}
|
||||
{isActive && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="hidden lg:block absolute left-full top-1/2 -translate-y-1/2 z-50"
|
||||
>
|
||||
{/* Arrow line */}
|
||||
<svg
|
||||
className="absolute left-0 top-1/2 -translate-y-1/2"
|
||||
width="120"
|
||||
height="2"
|
||||
viewBox="0 0 120 2"
|
||||
fill="none"
|
||||
>
|
||||
<line
|
||||
x1="0"
|
||||
y1="1"
|
||||
x2="120"
|
||||
y2="1"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1"
|
||||
opacity="0.6"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
{/* Description text */}
|
||||
<div className="ml-32 w-80 text-[#2F3178]">
|
||||
<h4 className="text-base font-semibold mb-2">
|
||||
{descriptionTitle}
|
||||
</h4>
|
||||
<CP color="custom">{description}</CP>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{/* Description for Mobile - Below cube */}
|
||||
{isActive && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: 10 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="lg:hidden absolute top-full left-1/2 -translate-x-1/2 mt-8 z-50"
|
||||
>
|
||||
<div className="w-64 sm:w-80 px-4 text-[#2F3178]">
|
||||
<h4 className="text-base font-semibold mb-2 text-center">
|
||||
{descriptionTitle}
|
||||
</h4>
|
||||
<CP className="text-center" color="custom">{description}</CP>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
111
src/components/Archives/WorldMap.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
import { Globe } from "@/components/ui/globe"
|
||||
import { motion } from "framer-motion"
|
||||
import { H2, H4, CP, CT } from "@/components/Texts"
|
||||
|
||||
export function WorldMap() {
|
||||
return (
|
||||
<div className="relative h-screen max-w-full overflow-hidden -top-20">
|
||||
{/* Background video */}
|
||||
<video
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
playsInline
|
||||
className="absolute inset-0 w-full h-full object-cover"
|
||||
>
|
||||
<source src="/videos/benefits.mp4" type="video/mp4" />
|
||||
</video>
|
||||
|
||||
{/* Dark overlay */}
|
||||
<div className="absolute inset-0 bg-black/60" />
|
||||
|
||||
{/* Top Left Intro Text */}
|
||||
<div className="absolute top-0 left-0 px-6 py-24 z-10 max-w-lg">
|
||||
<H4 color="light">Mycelium Network is Live.</H4>
|
||||
<CP className="mt-6 text-base leading-relaxed font-light" color="light">
|
||||
Mycelium Cloud's advancement technology enables anyone to deploy
|
||||
their own Internet infrastructure, anywhere.
|
||||
</CP>
|
||||
</div>
|
||||
|
||||
{/* Globe Centered */}
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<Globe className="top-28" />
|
||||
</div>
|
||||
|
||||
{/* Right Side Stats Column */}
|
||||
<div className="absolute right-0 top-0 bottom-0 flex flex-col justify-center gap-6 px-6 py-12 max-w-xs z-10">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 50 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.1 }}
|
||||
className="rounded-2xl bg-white/5 backdrop-blur-md border border-white/10 p-4 shadow-md"
|
||||
>
|
||||
<CT color="light" className="uppercase tracking-wide">
|
||||
CORES
|
||||
</CT>
|
||||
<H2 color="light" className="mt-2 text-3xl font-bold">
|
||||
54,958
|
||||
</H2>
|
||||
<CP color="light" className="mt-2 text-sm">
|
||||
Total Central Processing Unit Cores available on the grid.
|
||||
</CP>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 50 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.2 }}
|
||||
className="rounded-2xl bg-white/5 backdrop-blur-md border border-white/10 p-4 shadow-md"
|
||||
>
|
||||
<CT color="light" className="uppercase tracking-wide">
|
||||
NODES
|
||||
</CT>
|
||||
<H2 color="light" className="mt-2 text-3xl font-bold">
|
||||
54,958
|
||||
</H2>
|
||||
<CP color="light" className="mt-2 text-sm">
|
||||
Total number of nodes on the grid.
|
||||
</CP>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 50 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.3 }}
|
||||
className="rounded-2xl bg-white/5 backdrop-blur-md border border-white/10 p-4 shadow-md"
|
||||
>
|
||||
<CT color="light" className="uppercase tracking-wide">
|
||||
SSD CAPACITY
|
||||
</CT>
|
||||
<H2 color="light" className="mt-2 text-3xl font-bold">
|
||||
54,958
|
||||
</H2>
|
||||
<CP color="light" className="mt-2 text-sm">
|
||||
Total amount of storage (SSD, HDD, & RAM) on the grid.
|
||||
</CP>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 50 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.4 }}
|
||||
className="rounded-2xl bg-white/5 backdrop-blur-md border border-white/10 p-4 shadow-md"
|
||||
>
|
||||
<CT color="light" className="uppercase tracking-wide">
|
||||
COUNTRIES
|
||||
</CT>
|
||||
<H2 color="light" className="mt-2 text-3xl font-bold">
|
||||
51
|
||||
</H2>
|
||||
<CP color="light" className="mt-2 text-sm">
|
||||
Total number of countries with active nodes.
|
||||
</CP>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Radial fade overlay */}
|
||||
<div className="pointer-events-none absolute inset-0 h-full bg-[radial-gradient(circle_at_50%_200%,rgba(0,0,0,0.2),rgba(255,255,255,0))]" />
|
||||
</div>
|
||||
)
|
||||
}
|
172
src/components/BentoReviews.tsx
Normal file
@@ -0,0 +1,172 @@
|
||||
"use client";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { H2, P } from "@/components/Texts";
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { BentoGrid, MotionBentoGridItem } from "@/components/ui/bento-grid";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import { FadeIn } from "./FadeIn";
|
||||
|
||||
const items = [
|
||||
{
|
||||
title: 'FungiStor',
|
||||
subtitle: 'Long-Term AI Memory',
|
||||
description: 'Quantum-safe permanent storage preserving AI knowledge forever. Zero-knowledge architecture with mathematical dispersal ensures immortality.',
|
||||
video: "/videos/fungistor.mp4",
|
||||
},
|
||||
{
|
||||
title: 'HeroDB',
|
||||
subtitle: 'Active AI Memory',
|
||||
description: 'High-performance datastore for AI working memory. Multi-modal indexing enables vector search with global accessibility.',
|
||||
video: "/videos/herodb.mp4",
|
||||
},
|
||||
{
|
||||
title: 'MOS Sandboxes',
|
||||
subtitle: 'Secure Agent Workspaces',
|
||||
description: 'Lightweight isolated environments deploying globally in five seconds. Hardware-level isolation ensures maximum security for agents.',
|
||||
video: "/videos/sandbox.mp4",
|
||||
},
|
||||
{
|
||||
title: 'Mycelium Mesh',
|
||||
subtitle: 'Secure Communication Network',
|
||||
description: 'Peer-to-peer overlay network with end-to-end encryption. Self-healing shortest-path routing creates resilient agentic communication.',
|
||||
video: "/videos/mesh.mp4",
|
||||
},
|
||||
{
|
||||
title: 'Deterministic Deployment',
|
||||
subtitle: 'Verifiable Code Execution',
|
||||
description: 'Cryptographic guarantee system ensuring deployed code matches specifications. Prevents supply-chain attacks with immutable trails.',
|
||||
video: "/videos/deterministic.mp4",
|
||||
},
|
||||
{
|
||||
title: 'Agent Coordination',
|
||||
subtitle: 'Sovereign Workflow Management',
|
||||
description: 'User-centric orchestration where HERO agents coordinate worker fleets. Planetary-scale coordination with instant spawning.',
|
||||
video: "/videos/agent.mp4",
|
||||
},
|
||||
{
|
||||
title: 'Universal Interface Layer',
|
||||
subtitle: 'AI Service Gateway',
|
||||
description: 'Unified broker connecting agents to LLMs, APIs, and services. Integrated micropayments simplify development.',
|
||||
video: "/videos/universal.mp4",
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
export function BentoReviews() {
|
||||
const [activeIndex, setActiveIndex] = useState(0);
|
||||
const [isPaused, setIsPaused] = useState(false);
|
||||
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPaused) {
|
||||
intervalRef.current = setInterval(() => {
|
||||
setActiveIndex((prevIndex) => (prevIndex + 1) % items.length);
|
||||
}, 3000);
|
||||
} else {
|
||||
if (intervalRef.current) {
|
||||
clearInterval(intervalRef.current);
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (intervalRef.current) {
|
||||
clearInterval(intervalRef.current);
|
||||
}
|
||||
};
|
||||
}, [isPaused]);
|
||||
|
||||
const handleCardTap = () => {
|
||||
setIsPaused(true);
|
||||
};
|
||||
|
||||
const handlePrev = () => {
|
||||
setActiveIndex((prevIndex) => (prevIndex - 1 + items.length) % items.length);
|
||||
setIsPaused(true);
|
||||
};
|
||||
|
||||
const handleNext = () => {
|
||||
setActiveIndex((prevIndex) => (prevIndex + 1) % items.length);
|
||||
setIsPaused(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="relative isolate pt-24 pb-12 bg-black text-center w-full lg:px-0 px-4">
|
||||
<FadeIn transition={{ duration: 0.8, delay: 0.1 }}>
|
||||
<div className="mx-auto max-w-5xl ">
|
||||
<H2 className="text-center">Mycelium Technologies</H2>
|
||||
</div>
|
||||
</FadeIn>
|
||||
<FadeIn transition={{ duration: 0.8, delay: 0.2 }}>
|
||||
<div className="mx-auto max-w-4xl mt-6 mb-8">
|
||||
<P className="text-center" color="primary">
|
||||
A robust infrastructure layer for autonomous AI agents, our technology stack
|
||||
delivers a secure, efficient, and intuitive platform for deploying and managing AI agents at scale.
|
||||
</P>
|
||||
</div>
|
||||
</FadeIn>
|
||||
</div>
|
||||
|
||||
{/* Desktop Grid */}
|
||||
<div className="hidden lg:block">
|
||||
<BentoGrid className="max-w-8xl lg:px-12 px-4 pb-12 lg:grid-cols-3">
|
||||
{items.map((item, i) => (
|
||||
<MotionBentoGridItem
|
||||
key={i}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: false, margin: '0px 0px -100px 0px' }}
|
||||
transition={{ duration: 0.8, delay: 0.3 + i * 0.1 }}
|
||||
className={cn(i === 3 || i === 6 ? "md:col-span-2" : "")}
|
||||
rowHeight={i >= 3 ? "h-[22rem]" : ""}
|
||||
title={item.title}
|
||||
subtitle={item.subtitle}
|
||||
description={item.description}
|
||||
video={item.video}
|
||||
/>
|
||||
))}
|
||||
</BentoGrid>
|
||||
</div>
|
||||
|
||||
{/* Mobile Carousel */}
|
||||
<div className="lg:hidden block px-4 pb-12">
|
||||
<div className="relative h-[24rem] w-full overflow-hidden">
|
||||
<div className="absolute inset-0" onTouchStart={handleCardTap} />
|
||||
<AnimatePresence initial={false}>
|
||||
<motion.div
|
||||
key={activeIndex}
|
||||
className="absolute h-full w-full"
|
||||
initial={{ x: "100%", opacity: 0 }}
|
||||
animate={{ x: 0, opacity: 1 }}
|
||||
exit={{ x: "-100%", opacity: 0 }}
|
||||
transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
||||
>
|
||||
<MotionBentoGridItem
|
||||
className="h-full"
|
||||
title={items[activeIndex].title}
|
||||
subtitle={items[activeIndex].subtitle}
|
||||
description={items[activeIndex].description}
|
||||
video={items[activeIndex].video}
|
||||
/>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
<button
|
||||
onClick={handlePrev}
|
||||
className="absolute left-2 top-[58%] -translate-y-1/2 rounded-full bg-black/50 p-2 text-white z-10"
|
||||
>
|
||||
<ChevronLeft className="h-6 w-6" />
|
||||
</button>
|
||||
<button
|
||||
onClick={handleNext}
|
||||
className="absolute right-2 top-[58%] -translate-y-1/2 rounded-full bg-black/50 p-2 text-white z-10"
|
||||
>
|
||||
<ChevronRight className="h-6 w-6" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ const baseStyles = {
|
||||
solid:
|
||||
'inline-flex justify-center rounded-lg py-2 px-3 text-sm font-semibold transition-colors',
|
||||
outline:
|
||||
'inline-flex justify-center rounded-lg border py-[calc(--spacing(2)-1px)] px-[calc(--spacing(3)-1px)] text-sm transition-colors',
|
||||
'inline-flex justify-center rounded-lg border py-[calc(theme(spacing.2)-1px)] px-[calc(theme(spacing.3)-1px)] text-sm transition-colors',
|
||||
}
|
||||
|
||||
const variantStyles = {
|
||||
@@ -16,7 +16,8 @@ const variantStyles = {
|
||||
gray: 'bg-gray-800 text-white hover:bg-gray-900 active:bg-gray-800 active:text-white/80',
|
||||
},
|
||||
outline: {
|
||||
gray: 'border-gray-300 text-gray-200 hover:border-gray-400 active:bg-gray-100 active:text-gray-700/80',
|
||||
gray: 'border-gray-300 text-gray-700 hover:border-gray-400 active:bg-gray-100 active:text-gray-700/80',
|
||||
white: 'border-gray-300 text-white hover:border-gray-400 hover:text-gray-300 active:bg-gray-100 active:text-gray-800',
|
||||
},
|
||||
}
|
||||
|
||||
|
48
src/components/CallToAction.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import { CircleBackground } from '@/components/CircleBackground'
|
||||
import { Container } from '@/components/Container'
|
||||
import { Button } from '@/components/Button'
|
||||
import { FadeIn } from '@/components/FadeIn'
|
||||
|
||||
export function CallToAction() {
|
||||
return (
|
||||
<section
|
||||
id="get-free-shares-today"
|
||||
className="relative overflow-hidden py-20 sm:py-28 border-t border-gray-800"
|
||||
>
|
||||
<video
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
playsInline
|
||||
className="absolute top-0 left-0 w-full h-full object-cover z-0"
|
||||
>
|
||||
<source src="/videos/cta.mp4" type="video/mp4" />
|
||||
</video>
|
||||
<div className="absolute top-0 left-0 w-full h-full bg-black opacity-40 z-10"></div>
|
||||
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 sm:left-1/2 sm:-translate-x-1/2 z-20">
|
||||
<CircleBackground color="#fff" className="animate-spin-slower" />
|
||||
</div>
|
||||
<Container className="relative z-20">
|
||||
<FadeIn>
|
||||
<div className="mx-auto max-w-md text-center">
|
||||
<h2 className="text-3xl font-medium tracking-tight text-white sm:text-4xl">
|
||||
Decentralized AI Agents that are Truly Yours
|
||||
</h2>
|
||||
<p className="mt-4 text-lg text-gray-300">
|
||||
Why hand out your intelligence to centralized giants when you can
|
||||
build your own. Ready to own your intelligence?
|
||||
</p>
|
||||
<div className="mt-8 flex justify-center gap-x-6">
|
||||
<Button variant="solid" color="cyan" href="#">
|
||||
Book a Meeting
|
||||
</Button>
|
||||
<Button href="#" variant="outline" color="white">
|
||||
Join the Waitlist
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</FadeIn>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
}
|
@@ -1,41 +1,37 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect, useMemo, useState, useRef } from 'react'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { useResponsiveCarousel } from '@/hooks/useResponsiveCarousel';
|
||||
import Image from 'next/image'
|
||||
import { motion, AnimatePresence, useInView } from 'framer-motion'
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
import { wrap } from 'popmotion'
|
||||
import { Button } from '@/components/Button';
|
||||
import { H2, P, H4 } from '@/components/Texts';
|
||||
import { H2, P, CT } from '@/components/Texts';
|
||||
import { TypeAnimation } from 'react-type-animation'
|
||||
import { FadeIn } from './FadeIn';
|
||||
|
||||
const galleryItems = [
|
||||
{ text: 'Navigate and interact with any web interface', image: '/images/interface.png' },
|
||||
{ text: 'Process documents across all formats', image: '/images/docs.png' },
|
||||
{ text: 'Execute multi-step workflows autonomously', image: '/images/flow.png' },
|
||||
{ text: 'Manage calendars, emails, and tasks', image: '/images/calendar.png' },
|
||||
{ text: 'Perform deep semantic search across all data sources', image: '/images/data.png' },
|
||||
{ text: 'Identify patterns in complex datasets', image: '/images/datasets.png' },
|
||||
{ text: 'Provide real-time market intelligence', image: '/images/market.png' },
|
||||
{ text: 'Generate and debug code in multiple languages', image: '/images/code.png' },
|
||||
{ text: 'Create consistent branded content', image: '/images/branding.png' },
|
||||
{ text: 'Translate and localize materials', image: '/images/translate.png' },
|
||||
{ text: 'Transform and migrate data structures', image: '/images/structure.png' },
|
||||
{ text: 'Navigate and interact with any web interface', image: '/images/gallery/interface.jpg', width: 448, height: 277 },
|
||||
{ text: 'Process documents across all formats', image: '/images/gallery/docs.jpg', width: 448, height: 277 },
|
||||
{ text: 'Execute multi-step workflows autonomously', image: '/images/gallery/flow.jpg', width: 448, height: 277 },
|
||||
{ text: 'Manage calendars, emails, and tasks', image: '/images/gallery/calendar.jpg', width: 448, height: 277 },
|
||||
{ text: 'Perform deep semantic search across all data sources', image: '/images/gallery/data.jpg', width: 448, height: 277 },
|
||||
{ text: 'Identify patterns in complex datasets', image: '/images/gallery/datasets.jpg', width: 448, height: 277 },
|
||||
{ text: 'Provide real-time market intelligence', image: '/images/gallery/market.jpg', width: 448, height: 277 },
|
||||
{ text: 'Generate and debug code in multiple languages', image: '/images/gallery/code.jpg', width: 448, height: 277 },
|
||||
{ text: 'Create consistent branded content', image: '/images/gallery/branding.jpg', width: 448, height: 277 },
|
||||
{ text: 'Translate and localize materials', image: '/images/gallery/translate.jpg', width: 448, height: 277 },
|
||||
{ text: 'Transform and migrate data structures', image: '/images/gallery/structure.jpg', width: 448, height: 277 },
|
||||
]
|
||||
|
||||
// 🔧 Carousel Config
|
||||
const VISIBLE = 4
|
||||
const CARD_SIZE = 360 // square size on desktop
|
||||
const GAP = 300 // spacing for larger cards
|
||||
const ROT_Y = 18
|
||||
const DEPTH = 210
|
||||
const SCALE_DROP = 0.12
|
||||
const AUTOPLAY_MS = 3200
|
||||
const VISIBLE = 4;
|
||||
const AUTOPLAY_MS = 3200;
|
||||
|
||||
export function ClickableGallery() {
|
||||
const [active, setActive] = useState(0)
|
||||
const [hovering, setHovering] = useState(false)
|
||||
const ref = useRef(null);
|
||||
const isInView = useInView(ref, { once: true });
|
||||
const [active, setActive] = useState(0);
|
||||
const [hovering, setHovering] = useState(false);
|
||||
const { GAP, ROT_Y, DEPTH, SCALE_DROP } = useResponsiveCarousel();
|
||||
|
||||
// autoplay
|
||||
useEffect(() => {
|
||||
@@ -53,142 +49,131 @@ export function ClickableGallery() {
|
||||
const prev = () => setActive((i) => wrap(0, galleryItems.length, i - 1))
|
||||
|
||||
return (
|
||||
<div ref={ref}>
|
||||
<div className="relative isolate pt-24 pb-0 text-center w-full">
|
||||
<motion.div initial={{ opacity: 0, y: 20 }} animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }} transition={{ duration: 0.8, delay: 0.1 }} className="mx-auto max-w-5xl">
|
||||
<H2 className="text-center">One Agent, Endless Possibilities.</H2>
|
||||
</motion.div>
|
||||
<motion.div initial={{ opacity: 0, y: 20 }} animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }} transition={{ duration: 0.8, delay: 0.2 }} className="mx-auto max-w-4xl mt-6">
|
||||
<P className="text-center" color="custom">
|
||||
The future isn’t about more tools. It’s about one intelligent partner that can do it all. This is your gateway to creativity, automation, and discovery.
|
||||
</P>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
|
||||
transition={{ duration: 1, delay: 0.3 }}
|
||||
aria-hidden="true"
|
||||
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
|
||||
<div>
|
||||
<div className="relative isolate pt-8 pb-0 bg-transparent text-center w-full">
|
||||
<FadeIn transition={{ duration: 0.8, delay: 0.1 }}>
|
||||
<div className="mx-auto max-w-5xl">
|
||||
<H2 className="text-center">One Agent, Endless Possibilities.</H2>
|
||||
</div>
|
||||
</FadeIn>
|
||||
<FadeIn transition={{ duration: 0.8, delay: 0.2 }}>
|
||||
<div className="mx-auto max-w-4xl mt-6 lg:px-0 px-4">
|
||||
<P className="text-center" color="primary">
|
||||
The future isn’t about more tools. It’s about one intelligent partner that can do it all. This is your gateway to creativity, automation, and discovery.
|
||||
</P>
|
||||
</div>
|
||||
</FadeIn>
|
||||
</div>
|
||||
<FadeIn transition={{ duration: 1, delay: 0.4 }}>
|
||||
<section
|
||||
className="relative w-full flex items-center justify-center overflow-hidden bg-transparent -mt-8 pt-0 pb-0"
|
||||
onMouseEnter={() => setHovering(true)}
|
||||
onMouseLeave={() => setHovering(false)}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
clipPath:
|
||||
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
|
||||
}}
|
||||
className="relative left-[calc(50%-30rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#93c5fd] to-[#9089fc] opacity-30 sm:left-[calc(50%-36rem)] sm:w-[72.1875rem]"
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
<motion.section
|
||||
initial={{ opacity: 0 }}
|
||||
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
|
||||
transition={{ duration: 1, delay: 0.4 }}
|
||||
className="relative w-full flex items-center justify-center overflow-hidden bg-background -mt-16 pt-0 pb-32"
|
||||
onMouseEnter={() => setHovering(true)}
|
||||
onMouseLeave={() => setHovering(false)}
|
||||
>
|
||||
{/* Soft edge fades */}
|
||||
<div className="pointer-events-none absolute inset-y-0 left-0 w-32 bg-gradient-to-r from-background to-transparent" />
|
||||
<div className="pointer-events-none absolute inset-y-0 right-0 w-32 bg-gradient-to-l from-background to-transparent" />
|
||||
<div className="relative w-full max-w-[1800px] h-[300px] md:h-[500px]" style={{ perspective: '1600px' }}>
|
||||
<div className="absolute inset-0" style={{ transformStyle: 'preserve-3d' }}>
|
||||
<AnimatePresence initial={false}>
|
||||
{indices.map((idx, i) => {
|
||||
const distance = i - VISIBLE;
|
||||
const item = galleryItems[idx];
|
||||
|
||||
<div className="relative w-full max-w-[1800px] h-[500px]" style={{ perspective: '1600px' }}>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
clipPath:
|
||||
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
|
||||
}}
|
||||
className="relative left-[calc(50%+4rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#93c5fd] to-[#9089fc] opacity-30 sm:left-[calc(50%+60rem)] sm:w-[72.1875rem]"
|
||||
/>
|
||||
const x = distance * GAP;
|
||||
const z = -Math.abs(distance) * DEPTH;
|
||||
const r = distance * ROT_Y;
|
||||
const s = 1 - Math.abs(distance) * SCALE_DROP;
|
||||
const o = distance === 0 ? 1 : 0.80;
|
||||
const zIndex = 100 - Math.abs(distance);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
key={`${idx}-${i}`}
|
||||
className={`absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 will-change-transform overflow-hidden ${distance === 0 ? 'rounded-xl' : ''}`}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{
|
||||
transform: `translateX(${x}px) translateZ(${z}px) rotateY(${r}deg) scale(${s})`,
|
||||
zIndex,
|
||||
opacity: o,
|
||||
boxShadow: distance === 0 ? '0 0 20px 5px rgba(255, 255, 255, 0.2)' : 'none',
|
||||
}}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ type: 'spring', stiffness: 220, damping: 26 }}
|
||||
onClick={() => setActive(idx)}
|
||||
>
|
||||
<div className="relative bg-black flex items-center justify-center">
|
||||
<Image
|
||||
src={item.image}
|
||||
alt={item.text}
|
||||
width={item.width}
|
||||
height={item.height}
|
||||
className="object-contain text-white"
|
||||
priority={i === VISIBLE}
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute inset-0" style={{ transformStyle: 'preserve-3d' }}>
|
||||
<AnimatePresence initial={false}>
|
||||
{indices.map((idx, i) => {
|
||||
const distance = i - VISIBLE
|
||||
const item = galleryItems[idx]
|
||||
|
||||
const x = distance * GAP
|
||||
const z = -Math.abs(distance) * DEPTH
|
||||
const r = distance * ROT_Y
|
||||
const s = 1 - Math.abs(distance) * SCALE_DROP
|
||||
const o = distance === 0 ? 1 : 0.90
|
||||
const zIndex = 100 - Math.abs(distance)
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
key={`${idx}-${i}`}
|
||||
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 will-change-transform"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{
|
||||
transform: `translateX(${x}px) translateZ(${z}px) rotateY(${r}deg) scale(${s})`,
|
||||
zIndex,
|
||||
opacity: o,
|
||||
}}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ type: 'spring', stiffness: 220, damping: 26 }}
|
||||
onClick={() => setActive(idx)}
|
||||
>
|
||||
{/* Square container, keeps image ratio inside */}
|
||||
<div
|
||||
className="relative rounded-2xl overflow-hidden bg-white flex items-center justify-center"
|
||||
style={{ width: CARD_SIZE, height: CARD_SIZE }}
|
||||
>
|
||||
<Image
|
||||
src={item.image}
|
||||
alt={item.text}
|
||||
fill
|
||||
className="object-contain rounded-2xl"
|
||||
priority={i === VISIBLE}
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
)
|
||||
})}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
{/* Arrows */}
|
||||
<div className="absolute inset-y-0 left-8 flex items-center z-50">
|
||||
<button
|
||||
onClick={prev}
|
||||
className="bg-white/70 hover:bg-white rounded-full p-3 shadow-lg backdrop-blur-md"
|
||||
aria-label="Previous"
|
||||
>
|
||||
<svg className="size-8" viewBox="0 0 24 24" fill="none" dangerouslySetInnerHTML={{ __html: '<path d="M15 19L8 12l7-7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>' }} />
|
||||
</button>
|
||||
</div>
|
||||
<div className="absolute inset-y-0 right-8 flex items-center z-50">
|
||||
<button
|
||||
onClick={next}
|
||||
className="bg-white/70 hover:bg-white rounded-full p-3 shadow-lg backdrop-blur-md"
|
||||
aria-label="Next"
|
||||
>
|
||||
<svg className="size-8" viewBox="0 0 24 24" fill="none" dangerouslySetInnerHTML={{ __html: '<path d="M9 5l7 7-7 7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>' }} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Foreground pill */}
|
||||
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-[60]">
|
||||
<div className="flex items-center justify-between w-[1040px] gap-6 rounded-3xl bg-white/95 shadow-[0_8px_40px_rgba(0,0,0,0.15)] px-12 py-6 backdrop-blur">
|
||||
<H4 as="h4" className="max-w-[820px] h-[72px]">
|
||||
<TypeAnimation
|
||||
key={active}
|
||||
sequence={[galleryItems[active].text]}
|
||||
wrapper="span"
|
||||
speed={50}
|
||||
repeat={0}
|
||||
/>
|
||||
</H4>
|
||||
<Button href="#" color="cyan" className="text-sm px-4 py-2 lg:text-base">
|
||||
Start
|
||||
</Button>
|
||||
{/* Arrows */}
|
||||
{/* Arrows */}
|
||||
<div className="absolute inset-y-0 left-8 hidden md:flex items-center z-50">
|
||||
<button
|
||||
onClick={prev}
|
||||
className="bg-transparent rounded-full p-2 shadow-lg backdrop-blur-md"
|
||||
aria-label="Previous"
|
||||
>
|
||||
<svg className="size-8" viewBox="0 0 24 24" fill="none" dangerouslySetInnerHTML={{ __html: '<path d="M15 19L8 12l7-7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>' }} />
|
||||
</button>
|
||||
</div>
|
||||
<div className="absolute inset-y-0 right-8 hidden md:flex items-center z-50">
|
||||
<button
|
||||
onClick={next}
|
||||
className="bg-transparent rounded-full p-2 shadow-lg backdrop-blur-md"
|
||||
aria-label="Next"
|
||||
>
|
||||
<svg className="size-8" viewBox="0 0 24 24" fill="none" dangerouslySetInnerHTML={{ __html: '<path d="M9 5l7 7-7 7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>' }} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Foreground pill (Desktop) */}
|
||||
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-[60] hidden md:block">
|
||||
<div className="flex items-center justify-between w-[1040px] gap-6 rounded-2xl bg-black/30 shadow-[0_8px_40px_rgba(0,0,0,0.15)] px-12 backdrop-blur">
|
||||
<CT as="h4" className="max-w-[820px] h-[72px] text-white flex items-center">
|
||||
<TypeAnimation
|
||||
key={active}
|
||||
sequence={[galleryItems[active].text]}
|
||||
wrapper="span"
|
||||
speed={50}
|
||||
repeat={0}
|
||||
/>
|
||||
</CT>
|
||||
<Button href="#" color="cyan" className="text-sm px-4 py-2 lg:text-base whitespace-nowrap">
|
||||
Start
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Text box (Mobile) */}
|
||||
<div className="md:hidden w-full px-4 -mt-12 mb-16">
|
||||
<div className="flex flex-row items-center justify-between w-full gap-x-4 rounded-2xl bg-white/10 bg-opacity-80 p-4 backdrop-blur-md">
|
||||
<CT as="h4" className="w-full text-left h-[72px] text-white leading-tight flex items-center">
|
||||
<TypeAnimation
|
||||
key={active}
|
||||
sequence={[galleryItems[active].text]}
|
||||
wrapper="span"
|
||||
speed={50}
|
||||
repeat={0}
|
||||
/>
|
||||
</CT>
|
||||
<Button href="#" color="cyan" className="text-xs px-3 py-1.5 whitespace-nowrap">
|
||||
Start
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.section>
|
||||
</FadeIn>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@ const row2 = logos.slice(6);
|
||||
|
||||
export function Companies() {
|
||||
return (
|
||||
<div id="companies" className="relative bg-black flex flex-col items-center justify-center w-full overflow-hidden antialiased py-12 -top-20">
|
||||
<div id="companies" className="relative bg-black flex flex-col items-center justify-center w-full overflow-hidden antialiased lg:py-12 py-4 -top-20">
|
||||
<div className="relative z-10 mx-auto w-full max-w-6xl p-4">
|
||||
|
||||
{/* Heading */}
|
||||
@@ -50,7 +50,7 @@ export function Companies() {
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 1 }}
|
||||
>
|
||||
<P className="text-gray-100 text-center">
|
||||
<P className="text-gray-100 text-center mb-6">
|
||||
Mycelium Cloud allows you to deploy and scale AI agents from top global providers on a decentralized, privacy-first infrastructure.
|
||||
</P>
|
||||
</motion.div>
|
||||
|
18
src/components/CountUpNumber.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
'use client'
|
||||
|
||||
import CountUp from 'react-countup'
|
||||
import { H2 } from './Texts'
|
||||
|
||||
interface CountUpNumberProps {
|
||||
end: number
|
||||
className?: string
|
||||
color?: 'light' | 'primary' | 'secondary' | 'custom'
|
||||
}
|
||||
|
||||
export function CountUpNumber({ end, className, color }: CountUpNumberProps) {
|
||||
return (
|
||||
<H2 color={color} className={className}>
|
||||
<CountUp end={end} duration={2.75} separator="," />
|
||||
</H2>
|
||||
)
|
||||
}
|
28
src/components/FadeIn.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
'use client'
|
||||
|
||||
import { motion, Transition } from 'framer-motion'
|
||||
import React from 'react'
|
||||
import { useMediaQuery } from '@/hooks/useMediaQuery'
|
||||
|
||||
type FadeInProps = {
|
||||
children: React.ReactNode
|
||||
transition?: Transition
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function FadeIn({ children, transition, className }: FadeInProps) {
|
||||
const isMobile = useMediaQuery('(max-width: 768px)')
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
className={className}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: false, margin: isMobile ? '0px 0px -50px 0px' : '0px 0px -100px 0px' }}
|
||||
transition={transition || { duration: 0.5 }}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
)
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ import { Container } from '@/components/Container'
|
||||
import { TextField } from '@/components/Fields'
|
||||
import { Logomark } from '@/components/Logo'
|
||||
import { NavLinks } from '@/components/NavLinks'
|
||||
import { FadeIn } from '@/components/FadeIn'
|
||||
import qrCode from '@/images/qr-code.svg'
|
||||
|
||||
function QrCodeBorder(props: React.ComponentPropsWithoutRef<'svg'>) {
|
||||
@@ -23,8 +24,9 @@ function QrCodeBorder(props: React.ComponentPropsWithoutRef<'svg'>) {
|
||||
export function Footer() {
|
||||
return (
|
||||
<footer id="footer" className="border-t border-gray-800">
|
||||
<FadeIn>
|
||||
<Container>
|
||||
<div className="flex flex-col items-start justify-between gap-y-12 pt-16 pb-6 lg:flex-row lg:items-center lg:py-16">
|
||||
<div className="flex flex-col items-start justify-between gap-y-12 pt-12 pb-6 lg:flex-row lg:items-center lg:py-12">
|
||||
<div>
|
||||
<div className="flex items-center text-white">
|
||||
<Logomark className="h-10 w-10 flex-none fill-cyan-500" />
|
||||
@@ -39,24 +41,24 @@ export function Footer() {
|
||||
</div>
|
||||
<div className="group relative -mx-4 flex items-center self-stretch p-4 transition-colors hover:bg-gray-800/50 sm:self-auto sm:rounded-2xl lg:mx-0 lg:self-auto lg:p-6">
|
||||
<div className="relative flex h-24 w-24 flex-none items-center justify-center">
|
||||
<QrCodeBorder className="absolute inset-0 h-full w-full stroke-gray-700 transition-colors group-hover:stroke-cyan-500" />
|
||||
<QrCodeBorder className="absolute inset-0 h-full w-full stroke-gray-700 transition-colors group-hover:stroke-[#015eff]" />
|
||||
<Image src={qrCode} alt="" unoptimized />
|
||||
</div>
|
||||
<div className="ml-8 lg:w-64">
|
||||
<p className="text-base font-semibold text-white">
|
||||
<Link href="#">
|
||||
<Link href="https://threefoldfaq.crisp.help/en/">
|
||||
<span className="absolute inset-0 sm:rounded-2xl" />
|
||||
Download the app
|
||||
Talk to a human
|
||||
</Link>
|
||||
</p>
|
||||
<p className="mt-1 text-sm text-gray-400">
|
||||
Scan the QR code to download the app from the App Store.
|
||||
Get in touch with us for any inquiries or questions.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-center border-t border-gray-800 pt-8 pb-12 md:flex-row-reverse md:justify-between md:pt-6">
|
||||
<form className="flex w-full justify-center md:w-auto">
|
||||
{/* <form className="flex w-full justify-center md:w-auto">
|
||||
<TextField
|
||||
type="email"
|
||||
aria-label="Email address"
|
||||
@@ -70,12 +72,13 @@ export function Footer() {
|
||||
<span className="hidden lg:inline">Join our newsletter</span>
|
||||
<span className="lg:hidden">Join newsletter</span>
|
||||
</Button>
|
||||
</form>
|
||||
<p className="mt-6 text-sm text-gray-400 md:mt-0">
|
||||
© Copyright ThreeFold {new Date().getFullYear()}. All rights reserved.
|
||||
</form> */}
|
||||
<p className="mt-6 text-sm text-gray-400 md:mt-0 ">
|
||||
© Copyright OurWorld Holdings, {new Date().getFullYear()}. All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
</Container>
|
||||
</FadeIn>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
|
75
src/components/GetStarted.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
"use client";
|
||||
|
||||
import { H2, P, CP } from "@/components/Texts";
|
||||
import { Button } from "@/components/Button";
|
||||
|
||||
export function GetStarted() {
|
||||
const items = [
|
||||
{
|
||||
title: "Mycelium Docs",
|
||||
description:
|
||||
"Learn how Mycelium works and get a high-level understanding of its architecture, deployment, and API references.",
|
||||
href: "/docs",
|
||||
buttonText: "Docs",
|
||||
},
|
||||
{
|
||||
title: "Mycelium Repository",
|
||||
description:
|
||||
"Explore the official code repositories, contribute, and stay up-to-date with the latest changes.",
|
||||
href: "https://github.com/your-repo", // replace with actual repo
|
||||
buttonText: "Explore",
|
||||
},
|
||||
{
|
||||
title: "Mycelium Support",
|
||||
description:
|
||||
"Need help? Reach out to our support team or join the community to get your questions answered quickly.",
|
||||
href: "/support",
|
||||
buttonText: "Support",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<section
|
||||
className="bg-cover bg-center text-white py-32 px-6 relative"
|
||||
style={{
|
||||
backgroundImage: `url('/images/getstarted.webp')`,
|
||||
}}
|
||||
>
|
||||
<div className="max-w-8xl mx-auto px-4 text-left mb-12">
|
||||
<H2>Get Started</H2>
|
||||
<P>Explore the documentation, code, and support channels to start building with Mycelium Cloud.</P>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 md:grid-cols-3 max-w-8xl mx-auto px-4">
|
||||
{items.map((item, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className="relative flex flex-col justify-between overflow-hidden rounded-2xl border border-white/10 bg-black/40 p-6 shadow-md shadow-gray-900/5 transition-all duration-300 ease-out hover:scale-105 hover:border-white/40 hover:bg-black/60"
|
||||
style={{
|
||||
filter: 'brightness(1)',
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.filter = 'brightness(0.8)';
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.filter = 'brightness(1)';
|
||||
}}
|
||||
>
|
||||
{/* Title + Button Row */}
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-xl font-semibold">{item.title}</h3>
|
||||
<Button variant="outline" href={item.href} color="white">
|
||||
{item.buttonText}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Divider + Description */}
|
||||
<div className="mt-4 border-t border-white/10"></div>
|
||||
|
||||
<CP className="mt-4">{item.description}</CP>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
@@ -3,6 +3,7 @@
|
||||
import CountUp from "react-countup";
|
||||
import React from "react";
|
||||
import { Button } from "@/components/Button";
|
||||
import { H2, P } from "@/components/Texts";
|
||||
|
||||
export function GridStats() {
|
||||
return (
|
||||
@@ -15,18 +16,18 @@ export function GridStats() {
|
||||
backgroundPosition: "center",
|
||||
}}
|
||||
>
|
||||
<div className="mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-4">
|
||||
<div className="grid grid-cols-1 gap-12 lg:grid-cols-3">
|
||||
<div className="max-w-2xl px-6 lg:max-w-7xl lg:px-6">
|
||||
<div className="grid grid-cols-1 gap-16 lg:grid-cols-3">
|
||||
{/* Column 1: Title & Description */}
|
||||
<div className="flex flex-col space-y-10">
|
||||
<div>
|
||||
<h2 className="text-2xl font-semibold tracking-tight leading-tight text-white lg:text-4xl">
|
||||
<H2 color="light">
|
||||
Robust Infrastructure for your Intellegence Needs
|
||||
</h2>
|
||||
<p className="mt-4 sm:mt-6 text-sm font-light text-pretty text-white lg:text-base">
|
||||
</H2>
|
||||
<P color="light" className="mt-6">
|
||||
Mycelium's groundbreaking technology provides dedicated, performance-validated GPUs for your AI workloads.
|
||||
</p>
|
||||
<Button className="mt-8" variant="outline" href="https://threefold.io/build" >Explore TFGrid →</Button>
|
||||
</P>
|
||||
<Button className="mt-8" variant="outline" href="https://threefold.io/build" color="white">Explore TFGrid →</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -34,23 +35,23 @@ export function GridStats() {
|
||||
<div className="flex flex-col space-y-10">
|
||||
<StatCard
|
||||
label="Dedicated Hosting"
|
||||
description="Run LLMs, VLMs, and diffusion models on single-tenant GPUs with private endpoints. Bring your own weights or deploy from a curated library of open models. Enjoy full control with flexible hourly pricing. Perfect for always-on inference or workloads exceeding 100K tokens per minute."
|
||||
description="Run LLMs, VLMs, and diffusion models on single-tenant GPUs with private endpoints. Bring your own weights or deploy from a curated library of open models."
|
||||
/>
|
||||
<StatCard
|
||||
label="Data Sovereignty"
|
||||
description="Keep your sensitive data fully under your control. Mycelium nodes run on trusted infrastructure you own or choose, ensuring that no third party can access, train on, or monetize your data. This makes Mycelium ideal for enterprises in regulated industries that demand compliance and privacy."
|
||||
description="Mycelium nodes run on trusted infrastructure you own or choose, ensuring that no third party can access, train on, or monetize your data."
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Column 3: StatCards */}
|
||||
<div className="flex flex-col space-y-10 justify-start">
|
||||
<div className="flex flex-col space-y-10 justify-start mt-20">
|
||||
<StatCard
|
||||
label="Seamless Scalability"
|
||||
description="Scale from a single agent to hundreds without re-architecting. Mycelium’s decentralized infrastructure dynamically allocates compute, storage, and bandwidth across the network, so your AI workloads remain fast and resilient even under heavy demand."
|
||||
description="Mycelium’s decentralized infrastructure dynamically allocates compute, storage, and bandwidth across the network, so your AI workloads remain fast and resilient even under heavy demand."
|
||||
/>
|
||||
<StatCard
|
||||
label="Composable Agent Ecosystem"
|
||||
description="Mix and match agents for every part of your workflow: data ingestion, cleaning, orchestration, analysis, and reporting. Build an intelligent automation stack that evolves with your business needs, integrating easily with existing tools and APIs."
|
||||
description="Mix and match agents for every part of your workflow: data ingestion, cleaning, orchestration, analysis, and reporting."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,7 +64,7 @@ export function GridStats() {
|
||||
function StatCard({
|
||||
label,
|
||||
description,
|
||||
className = "",
|
||||
className = "border border-white/10 hover:border-white/40 hover:bg-black/40",
|
||||
}: {
|
||||
label: string;
|
||||
description: string;
|
||||
|
@@ -48,7 +48,7 @@ function MobileNavLink(
|
||||
return (
|
||||
<PopoverButton
|
||||
as={Link}
|
||||
className="block text-base/7 tracking-tight text-[#2F3178]"
|
||||
className="block text-base/7 tracking-tight text-white"
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
@@ -72,7 +72,7 @@ export function Header() {
|
||||
{({ open }) => (
|
||||
<>
|
||||
<PopoverButton
|
||||
className="relative z-10 -m-2 inline-flex items-center rounded-lg stroke-gray-900 p-2 hover:bg-gray-200/50 hover:stroke-gray-600 focus:not-data-focus:outline-hidden active:stroke-gray-900"
|
||||
className="relative z-10 -m-2 inline-flex items-center rounded-lg stroke-white p-2 hover:bg-gray-200/50 hover:stroke-gray-400 focus:not-data-focus:outline-hidden active:stroke-white"
|
||||
aria-label="Toggle site navigation"
|
||||
>
|
||||
{({ open }) =>
|
||||
@@ -104,7 +104,7 @@ export function Header() {
|
||||
y: -32,
|
||||
transition: { duration: 0.2 },
|
||||
}}
|
||||
className="absolute inset-x-0 top-0 z-0 origin-top rounded-b-2xl bg-white px-6 pt-32 pb-6 shadow-2xl shadow-gray-900/20"
|
||||
className="absolute inset-x-0 top-0 z-0 origin-top rounded-b-2xl bg-gray-900 px-6 pt-32 pb-6 shadow-2xl shadow-gray-900/20"
|
||||
>
|
||||
<div className="space-y-4">
|
||||
<MobileNavLink href="/#about">
|
||||
@@ -122,7 +122,7 @@ export function Header() {
|
||||
<MobileNavLink href="/#faqs">FAQs</MobileNavLink>
|
||||
</div>
|
||||
<div className="mt-8 flex flex-col gap-4">
|
||||
<Button href="https://docs.ourworld.tf/mycelium_cloud/docs/" variant="outline">
|
||||
<Button href="https://docs.ourworld.tf/mycelium_cloud/docs/" variant="outline" color="white" target="_blank" rel="noopener noreferrer">
|
||||
Docs
|
||||
</Button>
|
||||
<Button href="https://www.mycelium.threefold.io/download/" color="cyan">Get Started</Button>
|
||||
@@ -135,7 +135,7 @@ export function Header() {
|
||||
)}
|
||||
</Popover>
|
||||
<div className="flex items-center gap-6 max-lg:hidden">
|
||||
<Button href="https://docs.ourworld.tf/mycelium_cloud/docs/" variant="outline">
|
||||
<Button href="https://docs.ourworld.tf/mycelium_cloud/docs/" variant="outline" color="white" target="_blank" rel="noopener noreferrer">
|
||||
Docs
|
||||
</Button>
|
||||
<Button href="https://www.mycelium.threefold.io/download/" color="cyan">Get Started</Button>
|
||||
|
@@ -27,31 +27,48 @@ export function HomeHero() {
|
||||
playsInline
|
||||
className="absolute inset-0 w-full h-full object-cover"
|
||||
>
|
||||
<source src="/videos/mycelium.mp4" type="video/mp4" />
|
||||
<source src="/videos/mycelium2.mp4" type="video/mp4" />
|
||||
</video>
|
||||
<div className="absolute inset-0 bg-black/60" />
|
||||
</div>
|
||||
<div className="relative px-6 lg:px-8">
|
||||
<div className="relative -top-15 mx-auto max-w-8xl h-screen flex items-center justify-center">
|
||||
<div className="text-center max-w-5xl">
|
||||
<H1 color="light">
|
||||
<TypeAnimation
|
||||
sequence={[
|
||||
'Decentralized Autonomous Agentic Cloud.',
|
||||
1000,
|
||||
]}
|
||||
wrapper="span"
|
||||
speed={50}
|
||||
repeat={0}
|
||||
/>
|
||||
</H1>
|
||||
<div className="relative -top-15 mx-auto flex h-screen max-w-8xl items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="max-w-5xl">
|
||||
<H1 color="light">
|
||||
<TypeAnimation
|
||||
sequence={[
|
||||
'Decentralized Autonomous Agentic Cloud.',
|
||||
1000,
|
||||
]}
|
||||
wrapper="span"
|
||||
speed={50}
|
||||
repeat={0}
|
||||
/>
|
||||
</H1>
|
||||
</div>
|
||||
|
||||
{/* Mobile-only PL */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 1, delay: 1 }}
|
||||
className="lg:hidden"
|
||||
>
|
||||
<PL className="mt-8 max-w-xl text-center text-gray-100" color="light">
|
||||
Mycelium's advancements in Agentic infrastructure supports private, secure and autonomous Agents that connect, learn and grow with you.
|
||||
</PL>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Desktop-only PL */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 1, delay: 1 }}
|
||||
className="hidden lg:block"
|
||||
>
|
||||
<PL className="absolute bottom-0 left-0 max-w-xl text-left text-gray-100" color="light">
|
||||
<PL className="absolute -bottom-8 left-0 max-w-xl text-left text-gray-100" color="light">
|
||||
Mycelium's advancements in Agentic infrastructure supports private, secure and autonomous Agents that connect, learn and grow with you.
|
||||
</PL>
|
||||
</motion.div>
|
||||
|
@@ -8,20 +8,33 @@ export function NavLinks() {
|
||||
let [hoveredIndex, setHoveredIndex] = useState<number | null>(null)
|
||||
let timeoutRef = useRef<number | null>(null)
|
||||
|
||||
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>, href: string) => {
|
||||
if (href.startsWith('/#')) {
|
||||
e.preventDefault();
|
||||
const targetId = href.substring(2);
|
||||
const targetElement = document.getElementById(targetId);
|
||||
|
||||
if (targetElement) {
|
||||
targetElement.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return [
|
||||
['About', '/#home-about'],
|
||||
['Marketplace', '/#companies'],
|
||||
['Technology', '/#stack-section'],
|
||||
['How it works', '/#steps'],
|
||||
['Use Cases', '/#clickable-gallery'],
|
||||
['Coming Soon', '/#use-cases'],
|
||||
['Get Started', '/#call-to-action'],
|
||||
['FAQs', '/#faqs'],
|
||||
['About', '/#about'],
|
||||
['Network', '/#network'],
|
||||
['Deploy', '/#deploy'],
|
||||
['LLMs', '/#llms'],
|
||||
['Features', '/#features'],
|
||||
['Get Started', '/#get-started'],
|
||||
].map(([label, href], index) => (
|
||||
<Link
|
||||
key={label}
|
||||
href={href}
|
||||
className="relative -mx-3 -my-2 rounded-lg px-3 py-2 text-sm text-white transition-colors delay-150 hover:text-gray-300 hover:delay-0"
|
||||
onClick={(e) => handleClick(e, href)}
|
||||
onMouseEnter={() => {
|
||||
if (timeoutRef.current) {
|
||||
window.clearTimeout(timeoutRef.current)
|
||||
|
@@ -1,63 +1,34 @@
|
||||
"use client";
|
||||
|
||||
import { StackedCubes } from "@/components/ui/StackedCubes";
|
||||
import { Button } from "@/components/Button";
|
||||
import { motion, useInView } from 'framer-motion';
|
||||
import { H2, P } from '@/components/Texts';
|
||||
import { useRef } from "react";
|
||||
import { FadeIn } from "./FadeIn";
|
||||
|
||||
export function StackSectionPreview() {
|
||||
const ref = useRef(null);
|
||||
const isInView = useInView(ref);
|
||||
|
||||
return (
|
||||
<section ref={ref} className="w-full h-screen bg-transparent lg:px-0 pt-24 pb-12 px-6 relative">
|
||||
{/* Gradient Blob Component */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={isInView ? { opacity: 0.4 } : { opacity: 0 }}
|
||||
transition={{ duration: 1, delay: 0.1 }}
|
||||
className="absolute w-[400px] h-[200px] bg-gradient-to-br from-[#505050] to-[#7e7e7e] rounded-full blur-[150px] bottom-[200px] left-[-150px] z-0"
|
||||
/>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={isInView ? { opacity: 0.5 } : { opacity: 0 }}
|
||||
transition={{ duration: 1, delay: 0.15 }}
|
||||
className="absolute w-[200px] h-[100px] bg-gradient-to-br from-[#505050] to-[#7e7e7e] rounded-full blur-[150px] top-[200px] right-[-150px] z-0"
|
||||
/>
|
||||
<section className="w-full bg-transparent lg:px-0 py-12 lg:py-24 px-6 relative">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4 lg:gap-16 items-center lg:items-start">
|
||||
{/* Left Column - Text (1/3 width) */}
|
||||
<div className="text-left lg:text-left lg:col-span-1 order-1 lg:order-1">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }}
|
||||
transition={{ duration: 0.8, delay: 0.2 }}
|
||||
>
|
||||
<FadeIn>
|
||||
<H2 className="">
|
||||
The Mycelium Stack
|
||||
</H2>
|
||||
</motion.div>
|
||||
</FadeIn>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }}
|
||||
transition={{ duration: 0.8, delay: 0.6 }}
|
||||
>
|
||||
<P className="mx-auto mt-8 max-w-3xl" color="custom">
|
||||
<FadeIn>
|
||||
<P className="mx-auto mt-8 max-w-3xl" color="light">
|
||||
Built with Mycelium technology, our AI infrastructure ensures unbreakable networks, complete data sovereignty, ultra-secure agent-human communication, and unhackable data storage systems.
|
||||
</P>
|
||||
</motion.div>
|
||||
</FadeIn>
|
||||
</div>
|
||||
{/* Right Column - Stacked Cubes (2/3 width) */}
|
||||
<div className="lg:col-span-2 flex items-center justify-center lg:justify-start order-2 lg:order-2">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }}
|
||||
transition={{ duration: 0.8, delay: 0.3 }}
|
||||
>
|
||||
<div className="lg:col-span-2 flex items-center justify-center lg:justify-start order-2 lg:order-2 mt-8 lg:mt-0">
|
||||
<FadeIn>
|
||||
<StackedCubes />
|
||||
</motion.div>
|
||||
</FadeIn>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -31,7 +31,7 @@ export function Steps() {
|
||||
|
||||
return (
|
||||
<section id="benefits" ref={ref} className="relative bg-cover bg-center py-32 -top-20 text-white" style={{ backgroundImage: "url('/images/deployment.webp')" }}>
|
||||
<div className="absolute inset-0 bg-black/70" />
|
||||
<div className="absolute inset-0 bg-black/60" />
|
||||
<div className="relative px-6 lg:px-6">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
@@ -50,7 +50,7 @@ export function Steps() {
|
||||
initial={{ opacity: 0 }}
|
||||
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
|
||||
transition={{ duration: 0.5, delay: 0.2, staggerChildren: 0.2 }}
|
||||
className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-x-8 gap-y-16 text-base/7 sm:grid-cols-2 lg:mx-0 lg:max-w-none lg:grid-cols-3"
|
||||
className="mx-auto lg:mt-12 mt-8 grid max-w-2xl grid-cols-1 gap-x-8 gap-y-8 text-base/7 sm:grid-cols-2 sm:gap-y-16 lg:mx-0 lg:max-w-none lg:grid-cols-3"
|
||||
>
|
||||
{features.map((feature, index) => (
|
||||
<motion.li
|
||||
@@ -58,7 +58,7 @@ export function Steps() {
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
||||
transition={{ duration: 0.5, delay: 0.3 + index * 0.2 }}
|
||||
className="rounded-2xl border border-white/20 bg-black/20 p-8 backdrop-blur-sm transition-all duration-300 ease-in-out hover:scale-105 hover:border-white/40 hover:bg-black/40"
|
||||
className="rounded-2xl border border-white/20 bg-black/20 lg:py-8 lg:px-8 py-6 px-6 backdrop-blur-sm transition-all duration-300 ease-in-out hover:scale-105 hover:border-white/40 hover:bg-black/40"
|
||||
>
|
||||
<feature.icon className="h-8 w-8 mb-4 text-white" />
|
||||
<CT as="span" className="font-semibold" color="light">{feature.name}</CT>
|
||||
|
@@ -4,10 +4,10 @@ import React from 'react'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const colorVariants = {
|
||||
primary: 'text-[#2F3178]',
|
||||
secondary: 'text-gray-600',
|
||||
custom: 'text-[#1c1c49]',
|
||||
light: 'text-white',
|
||||
primary: 'text-[#fffff]',
|
||||
secondary: 'text-gray-200',
|
||||
custom: 'text-[#015eff]',
|
||||
light: '[#fcfcfc]',
|
||||
} as const
|
||||
|
||||
type TextOwnProps = {
|
||||
@@ -53,9 +53,9 @@ const createTextComponent = <DefaultElement extends React.ElementType>(
|
||||
export const H1 = createTextComponent('h1', 'text-5xl font-medium tracking-tight text-balance lg:text-8xl')
|
||||
export const PL = createTextComponent('p', 'text-2xl font-medium text-pretty leading-[1.2] lg:text-3xl')
|
||||
export const H2 = createTextComponent('h2', 'text-3xl font-medium text-pretty lg:text-4xl')
|
||||
export const P = createTextComponent('p', 'text-lg font-normal text-pretty lg:text-xl')
|
||||
export const P = createTextComponent('p', 'text-lg font-normal text-pretty leading-snug lg:text-xl lg:leading-normal')
|
||||
export const H3 = createTextComponent('h3', 'text-2xl lg:text-3xl font-medium')
|
||||
export const H4 = createTextComponent('h4', 'text-xl lg:text-2xl font-semibold leading-tight')
|
||||
export const H4 = createTextComponent('h4', 'text-xl lg:text-2xl font-semibold leading-[1.15]')
|
||||
export const CT = createTextComponent('span', 'text-lg lg:text-xl font-semibold text-center')
|
||||
export const CP = createTextComponent('p', 'text-sm lg:text-base leading-relaxed font-light')
|
||||
export const NL = createTextComponent('span', 'text-lg font-semibold leading-6')
|
||||
export const CP = createTextComponent('p', 'text-sm lg:text-base leading-[1.525] font-light')
|
||||
export const NL = createTextComponent('span', 'text-lg font-semibold leading-[1.23]')
|
||||
|
@@ -22,129 +22,75 @@ interface Review {
|
||||
body: string
|
||||
}
|
||||
|
||||
const reviews: Array<Review> = [
|
||||
{
|
||||
title: 'FungiStor: Long-Term AI Memory',
|
||||
body: 'Quantum-safe permanent storage preserving AI knowledge forever. Zero-knowledge architecture with mathematical dispersal ensures immortality.',
|
||||
},
|
||||
{
|
||||
title: 'HeroDB: Active AI Memory',
|
||||
body: 'High-performance datastore for AI working memory. Multi-modal indexing enables vector search with global accessibility.',
|
||||
},
|
||||
{
|
||||
title: 'MOS Sandboxes: Secure Agent Workspaces',
|
||||
body: 'Lightweight isolated environments deploying globally in five seconds. Hardware-level isolation ensures maximum security for agents.',
|
||||
},
|
||||
{
|
||||
title: 'Mycelium Mesh: Secure Communication Network',
|
||||
body: 'Peer-to-peer overlay network with end-to-end encryption. Self-healing shortest-path routing creates resilient agentic communication.',
|
||||
},
|
||||
{
|
||||
title: 'Deterministic Deployment: Verifiable Code Execution',
|
||||
body: 'Cryptographic guarantee system ensuring deployed code matches specifications. Prevents supply-chain attacks with immutable trails.',
|
||||
},
|
||||
{
|
||||
title: 'Agent Coordination: Sovereign Workflow Management',
|
||||
body: 'User-centric orchestration where HERO agents coordinate worker fleets. Planetary-scale coordination with instant spawning.',
|
||||
},
|
||||
{
|
||||
title: 'Universal Interface Layer: AI Service Gateway',
|
||||
body: 'Unified broker connecting agents to LLMs, APIs, and services. Integrated micropayments simplify development.',
|
||||
},
|
||||
{
|
||||
title: 'Semantic Index & Search: Navigable Knowledge Fabric',
|
||||
body: 'Transforms data chaos into unified knowledge graphs. Goes beyond keywords to understand meaning and context.',
|
||||
},
|
||||
const reviews: Review[] = [
|
||||
{ title: 'FungiStor: Long-Term AI Memory', body: 'Quantum-safe permanent storage preserving AI knowledge forever. Zero-knowledge architecture with mathematical dispersal ensures immortality.' },
|
||||
{ title: 'HeroDB: Active AI Memory', body: 'High-performance datastore for AI working memory. Multi-modal indexing enables vector search with global accessibility.' },
|
||||
{ title: 'MOS Sandboxes: Secure Agent Workspaces', body: 'Lightweight isolated environments deploying globally in five seconds. Hardware-level isolation ensures maximum security for agents.' },
|
||||
{ title: 'Mycelium Mesh: Secure Communication Network', body: 'Peer-to-peer overlay network with end-to-end encryption. Self-healing shortest-path routing creates resilient agentic communication.' },
|
||||
{ title: 'Deterministic Deployment: Verifiable Code Execution', body: 'Cryptographic guarantee system ensuring deployed code matches specifications. Prevents supply-chain attacks with immutable trails.' },
|
||||
{ title: 'Agent Coordination: Sovereign Workflow Management', body: 'User-centric orchestration where HERO agents coordinate worker fleets. Planetary-scale coordination with instant spawning.' },
|
||||
{ title: 'Universal Interface Layer: AI Service Gateway', body: 'Unified broker connecting agents to LLMs, APIs, and services. Integrated micropayments simplify development.' },
|
||||
{ title: 'Semantic Index & Search: Navigable Knowledge Fabric', body: 'Transforms data chaos into unified knowledge graphs. Goes beyond keywords to understand meaning and context.' },
|
||||
]
|
||||
|
||||
|
||||
function getReviewIcon(title: string) {
|
||||
if (title.startsWith('FungiStor')) return ArchiveBoxIcon;
|
||||
if (title.startsWith('HeroDB')) return CpuChipIcon;
|
||||
if (title.startsWith('MOS Sandboxes')) return CodeBracketIcon;
|
||||
if (title.startsWith('Mycelium Mesh')) return ShareIcon;
|
||||
if (title.startsWith('Deterministic Deployment')) return CheckBadgeIcon;
|
||||
if (title.startsWith('Agent Coordination')) return UserGroupIcon;
|
||||
if (title.startsWith('Universal Interface Layer')) return GlobeAltIcon;
|
||||
if (title.startsWith('Semantic Index & Search')) return MagnifyingGlassIcon;
|
||||
return GlobeAltIcon; // default
|
||||
if (title.startsWith('FungiStor')) return ArchiveBoxIcon
|
||||
if (title.startsWith('HeroDB')) return CpuChipIcon
|
||||
if (title.startsWith('MOS Sandboxes')) return CodeBracketIcon
|
||||
if (title.startsWith('Mycelium Mesh')) return ShareIcon
|
||||
if (title.startsWith('Deterministic Deployment')) return CheckBadgeIcon
|
||||
if (title.startsWith('Agent Coordination')) return UserGroupIcon
|
||||
if (title.startsWith('Universal Interface Layer')) return GlobeAltIcon
|
||||
if (title.startsWith('Semantic Index & Search')) return MagnifyingGlassIcon
|
||||
return GlobeAltIcon
|
||||
}
|
||||
|
||||
function Review({
|
||||
title,
|
||||
body,
|
||||
className,
|
||||
...props
|
||||
}: Omit<React.ComponentPropsWithoutRef<'figure'>, keyof Review> & Review) {
|
||||
let animationDelay = useMemo(() => {
|
||||
let possibleAnimationDelays = ['0s', '0.1s', '0.2s', '0.3s', '0.4s', '0.5s']
|
||||
return possibleAnimationDelays[
|
||||
Math.floor(Math.random() * possibleAnimationDelays.length)
|
||||
]
|
||||
function Review({ title, body, className, ...props }: Omit<React.ComponentPropsWithoutRef<'figure'>, keyof Review> & Review) {
|
||||
const animationDelay = useMemo(() => {
|
||||
const delays = ['0s', '0.1s', '0.2s', '0.3s', '0.4s', '0.5s']
|
||||
return delays[Math.floor(Math.random() * delays.length)]
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<figure
|
||||
className={clsx(
|
||||
'animate-fade-in rounded-3xl bg-gray-900/50 p-6 opacity-0 shadow-md shadow-gray-900/5',
|
||||
className,
|
||||
className
|
||||
)}
|
||||
style={{ animationDelay }}
|
||||
{...props}
|
||||
>
|
||||
<blockquote className="text-white">
|
||||
{React.createElement(getReviewIcon(title), { className: "h-6 w-6 text-[#2F3178] mb-2" })}
|
||||
<CT color="light" className="mt-4 text-lg/6 font-semibold">
|
||||
{title}
|
||||
</CT>
|
||||
{React.createElement(getReviewIcon(title), { className: 'h-6 w-6 text-white mb-2' })}
|
||||
<CT color="light" className="mt-4 text-lg font-semibold">{title}</CT>
|
||||
<CP color="light" className="mt-3 text-sm">{body}</CP>
|
||||
</blockquote>
|
||||
|
||||
</figure>
|
||||
)
|
||||
}
|
||||
|
||||
function splitArray<T>(array: Array<T>, numParts: number) {
|
||||
let result: Array<Array<T>> = []
|
||||
function splitArray<T>(array: T[], numParts: number) {
|
||||
const result: T[][] = []
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
let index = i % numParts
|
||||
if (!result[index]) {
|
||||
result[index] = []
|
||||
}
|
||||
const index = i % numParts
|
||||
if (!result[index]) result[index] = []
|
||||
result[index].push(array[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function ReviewColumn({
|
||||
reviews,
|
||||
className,
|
||||
reviewClassName,
|
||||
msPerPixel = 0,
|
||||
}: {
|
||||
reviews: Array<Review>
|
||||
className?: string
|
||||
reviewClassName?: (reviewIndex: number) => string
|
||||
msPerPixel?: number
|
||||
}) {
|
||||
let columnRef = useRef<React.ElementRef<'div'>>(null)
|
||||
let [columnHeight, setColumnHeight] = useState(0)
|
||||
let duration = `${columnHeight * msPerPixel}ms`
|
||||
function ReviewColumn({ reviews, className, msPerPixel = 0 }: { reviews: Review[], className?: string, msPerPixel?: number }) {
|
||||
const columnRef = useRef<HTMLDivElement>(null)
|
||||
const [columnHeight, setColumnHeight] = useState(0)
|
||||
const duration = `${columnHeight * msPerPixel}ms`
|
||||
|
||||
useEffect(() => {
|
||||
if (!columnRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
let resizeObserver = new window.ResizeObserver(() => {
|
||||
if (!columnRef.current) return
|
||||
const resizeObserver = new ResizeObserver(() =>
|
||||
setColumnHeight(columnRef.current?.offsetHeight ?? 0)
|
||||
})
|
||||
|
||||
)
|
||||
resizeObserver.observe(columnRef.current)
|
||||
|
||||
return () => {
|
||||
resizeObserver.disconnect()
|
||||
}
|
||||
return () => resizeObserver.disconnect()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
@@ -153,110 +99,73 @@ function ReviewColumn({
|
||||
className={clsx('animate-marquee space-y-8 py-4', className)}
|
||||
style={{ '--marquee-duration': duration } as React.CSSProperties}
|
||||
>
|
||||
{reviews.concat(reviews).map((review, reviewIndex) => (
|
||||
<Review
|
||||
key={reviewIndex}
|
||||
aria-hidden={reviewIndex >= reviews.length}
|
||||
className={reviewClassName?.(reviewIndex % reviews.length)}
|
||||
{...review}
|
||||
/>
|
||||
{reviews.concat(reviews).map((review, i) => (
|
||||
<Review key={i} aria-hidden={i >= reviews.length} {...review} />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function ReviewGrid() {
|
||||
let containerRef = useRef<React.ElementRef<'div'>>(null)
|
||||
let isInView = useInView(containerRef, { once: true, amount: 0.4 })
|
||||
let columns = splitArray(reviews, 3)
|
||||
let column1 = columns[0]
|
||||
let column2 = columns[1]
|
||||
let column3 = splitArray(columns[2], 2)
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const isInView = useInView(containerRef, { once: true, amount: 0.4 })
|
||||
const columns = splitArray(reviews, 2)
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="relative -mx-4 mt-0 grid h-196 max-h-[150vh] grid-cols-1 items-start gap-8 overflow-hidden px-4 md:grid-cols-2 lg:grid-cols-3"
|
||||
>
|
||||
<div ref={containerRef} className="relative grid grid-cols-1 md:grid-cols-2 gap-8 overflow-hidden h-full">
|
||||
{isInView && (
|
||||
<>
|
||||
<ReviewColumn
|
||||
reviews={[...column1, ...column3.flat(), ...column2]}
|
||||
reviewClassName={(reviewIndex) =>
|
||||
clsx(
|
||||
reviewIndex >= column1.length + column3[0].length &&
|
||||
'md:hidden',
|
||||
reviewIndex >= column1.length && 'lg:hidden',
|
||||
)
|
||||
}
|
||||
msPerPixel={10}
|
||||
/>
|
||||
<ReviewColumn
|
||||
reviews={[...column2, ...column3[1]]}
|
||||
className="hidden md:block"
|
||||
reviewClassName={(reviewIndex) =>
|
||||
reviewIndex >= column2.length ? 'lg:hidden' : ''
|
||||
}
|
||||
msPerPixel={15}
|
||||
/>
|
||||
<ReviewColumn
|
||||
reviews={column3.flat()}
|
||||
className="hidden lg:block"
|
||||
msPerPixel={10}
|
||||
/>
|
||||
<ReviewColumn reviews={columns[0]} msPerPixel={10} />
|
||||
<ReviewColumn reviews={columns[1]} msPerPixel={15} />
|
||||
</>
|
||||
)}
|
||||
<div className="pointer-events-none absolute inset-x-0 top-0 h-32 bg-linear-to-b from-black" />
|
||||
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-32 bg-linear-to-t from-black" />
|
||||
{/* Top Gradient */}
|
||||
<div className="pointer-events-none absolute inset-x-0 top-0 h-32 bg-gradient-to-b from-black/90 to-transparent z-10" />
|
||||
{/* Bottom Gradient */}
|
||||
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-32 bg-gradient-to-t from-black/90 to-transparent z-10" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function UseCases() {
|
||||
const ref = useRef(null);
|
||||
const isInView = useInView(ref, { once: true });
|
||||
const ref = useRef(null)
|
||||
const isInView = useInView(ref, { once: true })
|
||||
|
||||
return (
|
||||
<section
|
||||
id="usecases"
|
||||
ref={ref}
|
||||
aria-labelledby="usecases-title"
|
||||
className="bg-black py-12"
|
||||
className="bg-black h-screen relative flex items-start py-12 -top-20"
|
||||
>
|
||||
<Container className=''>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
|
||||
transition={{ duration: 0.8, delay: 0.1 }}
|
||||
className="mx-auto max-w-2xl lg:max-w-5xl"
|
||||
>
|
||||
<H2
|
||||
id="usecases-title"
|
||||
color="light"
|
||||
className="text-center"
|
||||
<Container className="h-full">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-10 h-full">
|
||||
{/* Left Column */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 10 }}
|
||||
transition={{ duration: 0.8, delay: 0.1 }}
|
||||
className="flex flex-col items-start justify-start pt-10 lg:pr-12"
|
||||
>
|
||||
Coming Soon: The Future of Mycelium
|
||||
</H2>
|
||||
<P className="mt-6 text-center" color="light">
|
||||
Mycelium Cloud is evolving to bring even more powerful decentralized features, designed to enhance your experience and expand possibilities. Be the first to explore what's coming next by staying connected with our latest updates.
|
||||
</P>
|
||||
</motion.div>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
|
||||
transition={{ duration: 1, delay: 0.2 }}
|
||||
aria-hidden="true"
|
||||
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
clipPath:
|
||||
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
|
||||
}}
|
||||
className="relative left-[calc(50%-30rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#93c5fd] to-[#9089fc] opacity-30 sm:left-[calc(50%-36rem)] sm:w-[72.1875rem]"
|
||||
/>
|
||||
</motion.div>
|
||||
<ReviewGrid />
|
||||
<H2 id="usecases-title" color="light" className="text-left">
|
||||
Mycelium Technologies
|
||||
</H2>
|
||||
<P className="mt-4 text-left" color="light">
|
||||
A robust infrastructure layer for autonomous AI agents, our technology stack
|
||||
delivers a secure, efficient, and intuitive platform for deploying and managing AI agents at scale.
|
||||
</P>
|
||||
</motion.div>
|
||||
|
||||
{/* Right Columns */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={isInView ? { opacity: 1 } : { opacity: 0 }}
|
||||
transition={{ duration: 1, delay: 0.2 }}
|
||||
className="lg:col-span-2 h-full"
|
||||
>
|
||||
<ReviewGrid />
|
||||
</motion.div>
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
)
|
||||
|
@@ -1,23 +1,120 @@
|
||||
'use client'
|
||||
|
||||
import { Globe } from "@/components/ui/globe"
|
||||
import { motion } from "framer-motion"
|
||||
import { H2, H3, H4, P } from "./Texts"
|
||||
import { H2, P, CT, CP } from "@/components/Texts"
|
||||
import { CountUpNumber } from './CountUpNumber'
|
||||
|
||||
export function WorldMap() {
|
||||
|
||||
return (
|
||||
<div className="relative h-screen max-w-full overflow-hidden bg-black -top-20">
|
||||
<div className="absolute top-0 left-0 px-6 py-24 z-10 max-w-lg">
|
||||
<H4 className="" color="light">
|
||||
Mycelium Network is Live.
|
||||
</H4>
|
||||
<P className="mt-6 text-base text-pretty leading-relaxed font-light" color="light">
|
||||
Mycelium Cloud's advancement technology enables anyone to deploy their own Internet infrastructure, anywhere.
|
||||
</P>
|
||||
</div>
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<Globe className="top-28" />
|
||||
<div className="relative min-h-screen w-full overflow-hidden top-0 flex py-12 flex-col">
|
||||
{/* Background video */}
|
||||
<video
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
playsInline
|
||||
className="absolute inset-0 w-full h-full object-cover"
|
||||
>
|
||||
<source src="/videos/benefits.mp4" type="video/mp4" />
|
||||
</video>
|
||||
|
||||
{/* Dark overlay */}
|
||||
<div className="absolute inset-0 bg-black/10" />
|
||||
|
||||
{/* Content */}
|
||||
<div className="relative z-10 flex flex-col h-full px-8 md:px-16 py-12">
|
||||
{/* Title + Subtitle */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
className="max-w-xl"
|
||||
>
|
||||
<H2 color="light">Mycelium Network is Live.</H2>
|
||||
<P className="mt-4 text-base leading-relaxed font-light" color="light">
|
||||
Mycelium Cloud's advancement technology enables anyone to deploy
|
||||
their own Internet infrastructure, anywhere.
|
||||
</P>
|
||||
</motion.div>
|
||||
|
||||
{/* Bottom Layout: Globe + Cards */}
|
||||
<div className="mt-8 flex flex-1 flex-col lg:flex-row items-center lg:items-stretch gap-x-10">
|
||||
{/* Globe Left Column */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.5, delay: 0.2 }}
|
||||
className="flex-1 flex items-center justify-center"
|
||||
>
|
||||
<div className="relative w-[450px] h-[450px] md:w-[600px] md:h-[600px]">
|
||||
<Globe className="absolute inset-0 w-full h-full left-0 lg:-left-24" />
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Cards Right Column */}
|
||||
<div className="relative flex-1 lg:h-auto h-[700px] flex flex-col lg:block items-center gap-y-4 mt-8 lg:mt-0">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ duration: 0.5, delay: 0.4 }}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
className="lg:absolute lg:top-12 lg:-left-12 rounded-xl bg-white/5 backdrop-blur-md border border-white/10 px-4 lg:py-8 py-6 shadow-md w-80"
|
||||
>
|
||||
<CT color="light" className="uppercase tracking-wide">CORES</CT>
|
||||
<CountUpNumber end={54958} color="light" className="mt-2 text-3xl font-bold" />
|
||||
<CP color="light" className="mt-2 text-sm">
|
||||
Total Central Processing Unit Cores available on the grid.
|
||||
</CP>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ duration: 0.5, delay: 0.5 }}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
className="lg:absolute lg:-top-10 lg:right-0 rounded-xl bg-white/5 backdrop-blur-md border border-white/10 px-4 lg:py-8 py-6 shadow-md w-80"
|
||||
>
|
||||
<CT color="light" className="uppercase tracking-wide">NODES</CT>
|
||||
<CountUpNumber end={1493} color="light" className="mt-2 text-3xl font-bold" />
|
||||
<CP color="light" className="mt-2 text-sm">
|
||||
Total number of nodes on the grid.
|
||||
</CP>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ duration: 0.5, delay: 0.6 }}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
className="lg:absolute lg:bottom-28 lg:-left-12 rounded-xl bg-white/5 backdrop-blur-md border border-white/10 px-4 lg:py-8 py-6 shadow-md w-80"
|
||||
>
|
||||
<CT color="light" className="uppercase tracking-wide">SSD CAPACITY</CT>
|
||||
<CountUpNumber end={5388956} color="light" className="mt-2 text-3xl font-bold" />
|
||||
<CP color="light" className="mt-2 text-sm">
|
||||
Total GB amount of storage (SSD, HDD, & RAM) on the grid.
|
||||
</CP>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ duration: 0.5, delay: 0.7 }}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
className="lg:absolute lg:top-44 lg:right-0 rounded-xl bg-white/5 backdrop-blur-md border border-white/10 px-4 lg:py-8 py-6 shadow-md w-80"
|
||||
>
|
||||
<CT color="light" className="uppercase tracking-wide">COUNTRIES</CT>
|
||||
<CountUpNumber end={44} color="light" className="mt-2 text-3xl font-bold" />
|
||||
<CP color="light" className="mt-2 text-sm">
|
||||
Total number of countries with active nodes.
|
||||
</CP>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Radial fade overlay */}
|
||||
<div className="pointer-events-none absolute inset-0 h-full bg-[radial-gradient(circle_at_50%_200%,rgba(0,0,0,0.2),rgba(255,255,255,0))]" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@@ -1,59 +0,0 @@
|
||||
import Link from 'next/link'
|
||||
import clsx from 'clsx'
|
||||
|
||||
const baseStyles = {
|
||||
solid:
|
||||
'inline-flex justify-center rounded-lg py-2 px-3 text-sm font-semibold transition-colors',
|
||||
outline:
|
||||
'inline-flex justify-center rounded-lg border py-[calc(theme(spacing.2)-1px)] px-[calc(theme(spacing.3)-1px)] text-sm transition-colors',
|
||||
}
|
||||
|
||||
const variantStyles = {
|
||||
solid: {
|
||||
primary: 'bg-[#005eff] text-white hover:bg-[#005eff]/90 active:bg-[#005eff]/80',
|
||||
white: 'bg-white text-black hover:bg-white/90 active:bg-white/90 active:text-gray-400',
|
||||
gray: 'bg-gray-800 text-white hover:bg-gray-900 active:bg-gray-800 active:text-white/80',
|
||||
},
|
||||
outline: {
|
||||
primary: 'border-[#005eff] text-[#005eff] hover:border-[#005eff]/80 hover:text-[#005eff]/80 active:bg-gray-100 active:text-[#005eff]/70',
|
||||
gray: 'border-gray-300 text-gray-700 hover:border-gray-400 active:bg-gray-100 active:text-gray-700/80',
|
||||
},
|
||||
}
|
||||
|
||||
type ButtonProps = (
|
||||
| { variant?: 'solid'; color?: keyof typeof variantStyles.solid }
|
||||
| { variant: 'outline'; color?: keyof typeof variantStyles.outline }
|
||||
) & (
|
||||
| Omit<React.ComponentPropsWithoutRef<typeof Link>, 'color'>
|
||||
| (Omit<React.ComponentPropsWithoutRef<'button'>, 'color'> & {
|
||||
href?: undefined
|
||||
})
|
||||
)
|
||||
|
||||
export function Button({ className, ...props }: ButtonProps) {
|
||||
props.variant ??= 'solid'
|
||||
if (props.variant === 'solid') {
|
||||
props.color ??= 'primary'
|
||||
} else {
|
||||
props.color ??= 'gray'
|
||||
}
|
||||
|
||||
let variantClass: string | undefined;
|
||||
if (props.variant === 'outline') {
|
||||
variantClass = variantStyles.outline[props.color as keyof typeof variantStyles.outline];
|
||||
} else if (props.variant === 'solid') {
|
||||
variantClass = variantStyles.solid[props.color as keyof typeof variantStyles.solid];
|
||||
}
|
||||
|
||||
className = clsx(
|
||||
baseStyles[props.variant],
|
||||
variantClass,
|
||||
className,
|
||||
)
|
||||
|
||||
return typeof props.href === 'undefined' ? (
|
||||
<button className={className} {...props} />
|
||||
) : (
|
||||
<Link className={className} {...props} />
|
||||
)
|
||||
}
|
@@ -1,9 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import { motion } from "framer-motion";
|
||||
import { CT, CP } from '@/components/Texts';
|
||||
|
||||
interface CubeProps {
|
||||
title: string;
|
||||
@@ -13,16 +11,46 @@ interface CubeProps {
|
||||
index: number;
|
||||
onHover: () => void;
|
||||
onLeave: () => void;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
const CubeSvg: React.FC<React.SVGProps<SVGSVGElement> & { index: number }> = ({ index, ...props }) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="507"
|
||||
height="234"
|
||||
fill="none"
|
||||
viewBox="0 0 507 234"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill={`url(#cube-gradient-${index})`}
|
||||
d="M491.651 144.747L287.198 227.339C265.219 236.22 241.783 236.22 219.802 227.339L15.3486 144.747C-5.11621 136.479 -5.11621 97.5191 15.3486 89.2539L219.802 6.65884C241.783 -2.21961 265.219 -2.21961 287.198 6.65884L491.651 89.2539C512.116 97.5191 512.116 136.479 491.651 144.747Z"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id={`cube-gradient-${index}`}
|
||||
x1="185.298"
|
||||
x2="185.298"
|
||||
y1="-27.5515"
|
||||
y2="206.448"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop />
|
||||
<stop offset="1" stopColor="#3F3B3E" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export function Cube({ title, descriptionTitle, description, isActive, index, onHover, onLeave }: CubeProps) {
|
||||
export function Cube({ title, descriptionTitle, description, isActive, index, onHover, onLeave, onClick }: CubeProps) {
|
||||
return (
|
||||
<div className="relative flex flex-col items-center">
|
||||
<motion.div
|
||||
className="relative cursor-pointer pointer-events-none"
|
||||
className="relative cursor-pointer"
|
||||
onMouseEnter={onHover}
|
||||
onMouseLeave={onLeave}
|
||||
onClick={onClick}
|
||||
style={{
|
||||
zIndex: 10 - index,
|
||||
}}
|
||||
@@ -34,25 +62,26 @@ export function Cube({ title, descriptionTitle, description, isActive, index, on
|
||||
ease: "easeOut",
|
||||
}}
|
||||
>
|
||||
{/* Image Cube */}
|
||||
<Image
|
||||
src="/images/cube.png"
|
||||
alt="Cube"
|
||||
width={507}
|
||||
height={234}
|
||||
className="w-60 sm:w-80 lg:w-96 h-auto drop-shadow-lg pointer-events-auto"
|
||||
{/* SVG Cube */}
|
||||
<CubeSvg
|
||||
index={index}
|
||||
className="w-48 sm:w-64 lg:w-80 h-auto drop-shadow-lg opacity-50"
|
||||
style={{
|
||||
filter: isActive
|
||||
? 'brightness(1.1) drop-shadow(0 25px 25px rgba(144, 137, 252, 0.4))'
|
||||
: 'brightness(0.9) drop-shadow(0 10px 15px rgba(144, 137, 252, 0.2))',
|
||||
filter: isActive ? 'brightness(1.2) drop-shadow(0 0 20px rgba(156, 163, 175, 0.5))' : 'brightness(0.9)',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Title overlay */}
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<CT as="h3" className="px-4 drop-shadow-lg" style={{ transform: 'rotate(0deg) skewX(0deg)', transformOrigin: 'center' }}>
|
||||
<h3
|
||||
className="text-white text-sm lg:text-base font-medium text-center px-4 drop-shadow-lg"
|
||||
style={{
|
||||
transform: 'rotate(0deg) skewX(0deg)',
|
||||
transformOrigin: 'center'
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</CT>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
{/* Description with arrow line - Desktop */}
|
||||
@@ -77,40 +106,26 @@ export function Cube({ title, descriptionTitle, description, isActive, index, on
|
||||
y1="1"
|
||||
x2="120"
|
||||
y2="1"
|
||||
stroke="currentColor"
|
||||
stroke="white"
|
||||
strokeWidth="1"
|
||||
opacity="0.6"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
{/* Description text */}
|
||||
<div className="ml-32 w-80 text-[#2F3178]">
|
||||
<h4 className="text-base font-semibold mb-2">
|
||||
<div className="ml-32 w-80">
|
||||
<h4 className="text-white text-base font-semibold mb-2">
|
||||
{descriptionTitle}
|
||||
</h4>
|
||||
<CP color="custom">{description}</CP>
|
||||
<p className="text-white text-sm leading-relaxed font-light">
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{/* Description for Mobile - Below cube */}
|
||||
{isActive && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: 10 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="lg:hidden absolute top-full left-1/2 -translate-x-1/2 mt-8 z-50"
|
||||
>
|
||||
<div className="w-64 sm:w-80 px-4 text-[#2F3178]">
|
||||
<h4 className="text-base font-semibold mb-2 text-center">
|
||||
{descriptionTitle}
|
||||
</h4>
|
||||
<CP className="text-center" color="custom">{description}</CP>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { Cube } from "@/components/ui/Cube";
|
||||
import { Cube } from "@/components/ui/Cube"
|
||||
|
||||
const stackData = [
|
||||
{
|
||||
@@ -33,14 +33,22 @@ const stackData = [
|
||||
|
||||
export function StackedCubes() {
|
||||
const [active, setActive] = useState<string | null>("agent");
|
||||
const [selectedForMobile, setSelectedForMobile] = useState<string | null>("agent");
|
||||
|
||||
const handleCubeClick = (id: string) => {
|
||||
setSelectedForMobile(prev => (prev === id ? null : id));
|
||||
};
|
||||
|
||||
const selectedMobileLayer = stackData.find(layer => layer.id === selectedForMobile);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center">
|
||||
<div
|
||||
className="relative w-full flex items-center justify-center lg:justify-start min-h-[600px] sm:min-h-[700px] lg:min-h-[600px]"
|
||||
className="relative w-full flex items-center justify-center lg:justify-center min-h-[450px] lg:min-h-[400px]"
|
||||
onMouseLeave={() => setActive("agent")}
|
||||
>
|
||||
<motion.div
|
||||
className="relative ml-0 sm:ml-4 lg:ml-8 h-[600px] w-96"
|
||||
className="relative lg:pl-0 pl-6 h-[300px] lg:h-[400px] w-64 sm:w-80 lg:w-96 scale-120 lg:scale-100"
|
||||
animate={{ y: ["-8px", "8px"] }}
|
||||
transition={{
|
||||
duration: 4,
|
||||
@@ -54,7 +62,7 @@ export function StackedCubes() {
|
||||
key={layer.id}
|
||||
className="absolute"
|
||||
style={{
|
||||
top: `${index * 140}px`,
|
||||
top: `calc(${index * 30}% - ${index * 10}px)`,
|
||||
zIndex: active === layer.id ? 20 : 10 - index,
|
||||
}}
|
||||
>
|
||||
@@ -66,10 +74,22 @@ export function StackedCubes() {
|
||||
index={index}
|
||||
onHover={() => setActive(layer.id)}
|
||||
onLeave={() => {}}
|
||||
onClick={() => handleCubeClick(layer.id)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</motion.div>
|
||||
</div>
|
||||
{selectedMobileLayer && (
|
||||
<div className="lg:hidden w-full max-w-md p-6 -mt-8 bg-gray-800/50 rounded-lg">
|
||||
<h4 className="text-white text-lg font-semibold mb-2 text-center">
|
||||
{selectedMobileLayer.descriptionTitle}
|
||||
</h4>
|
||||
<p className="text-gray-300 text-sm leading-relaxed text-center">
|
||||
{selectedMobileLayer.description}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
79
src/components/ui/bento-grid.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import { CT, CP } from "@/components/Texts";
|
||||
import Image from 'next/image';
|
||||
import React from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
export const BentoGrid = ({
|
||||
className,
|
||||
children,
|
||||
}: {
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"mx-4 grid max-w-6xl grid-cols-1 gap-4 lg:grid-cols-3",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface BentoGridItemProps {
|
||||
className?: string;
|
||||
title?: string | React.ReactNode;
|
||||
subtitle?: string | React.ReactNode;
|
||||
description?: string | React.ReactNode;
|
||||
img?: string;
|
||||
video?: string;
|
||||
rowHeight?: string;
|
||||
}
|
||||
|
||||
export const BentoGridItem = React.forwardRef<HTMLDivElement, BentoGridItemProps>(
|
||||
({ className, title, subtitle, description, img, video, rowHeight }, ref) => {
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"group/bento shadow-input row-span-1 flex flex-col justify-between rounded-xl border border-black bg-black/10 backdrop-blur-md transition-all duration-300 ease-in-out hover:scale-105 hover:border-black hover:bg-black/40",
|
||||
rowHeight ? rowHeight : "h-full",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="relative w-full h-[65%] min-h-[6rem] bg-transparent overflow-hidden">
|
||||
{video ? (
|
||||
<video
|
||||
src={video}
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
playsInline
|
||||
className="w-full h-full object-cover opacity-90 group-hover/bento:opacity-100 transition-opacity duration-300"
|
||||
/>
|
||||
) : img ? (
|
||||
<Image
|
||||
src={img}
|
||||
alt={title as string}
|
||||
width={300}
|
||||
height={300}
|
||||
className="w-full h-full object-cover opacity-90 group-hover/bento:opacity-100 transition-opacity duration-300"
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="p-4 transition bg-white/5 hover:bg-white/7 backdrop-blur-md duration-200 group-hover/bento:translate-x-2 ">
|
||||
<CT>{title}</CT>
|
||||
<CP className="font-medium">{subtitle}</CP>
|
||||
<CP className="mt-2">{description}</CP>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
BentoGridItem.displayName = "BentoGridItem";
|
||||
|
||||
export const MotionBentoGridItem = motion(BentoGridItem);
|
@@ -16,23 +16,56 @@ const GLOBE_CONFIG: COBEOptions = {
|
||||
phi: 0,
|
||||
theta: 0.3,
|
||||
dark: 0,
|
||||
diffuse: 0.4,
|
||||
diffuse: 0.25, // softer shading for premium look
|
||||
mapSamples: 16000,
|
||||
mapBrightness: 1.2,
|
||||
baseColor: [1, 1, 1],
|
||||
markerColor: [1 / 255, 94 / 255, 255 / 255],
|
||||
glowColor: [1, 1, 1],
|
||||
mapBrightness: 1.1,
|
||||
baseColor: [0.8, 0.8, 0.8], // sleek dark gray globe
|
||||
markerColor: [0.3, 0.6, 1], // soft, elegant blue
|
||||
glowColor: [0.8, 0.8, 0.85], // subtle glow
|
||||
markers: [
|
||||
{ location: [14.5995, 120.9842], size: 0.03 },
|
||||
{ location: [19.076, 72.8777], size: 0.1 },
|
||||
{ location: [23.8103, 90.4125], size: 0.05 },
|
||||
{ location: [30.0444, 31.2357], size: 0.07 },
|
||||
{ location: [39.9042, 116.4074], size: 0.08 },
|
||||
{ location: [-23.5505, -46.6333], size: 0.1 },
|
||||
{ location: [19.4326, -99.1332], size: 0.1 },
|
||||
{ location: [40.7128, -74.006], size: 0.1 },
|
||||
{ location: [34.6937, 135.5022], size: 0.05 },
|
||||
{ location: [41.0082, 28.9784], size: 0.06 },
|
||||
// --- Core Global Markers ---
|
||||
{ location: [14.5995, 120.9842], size: 0.03 }, // Manila
|
||||
{ location: [19.076, 72.8777], size: 0.1 }, // Mumbai
|
||||
{ location: [23.8103, 90.4125], size: 0.05 }, // Dhaka
|
||||
{ location: [30.0444, 31.2357], size: 0.07 }, // Cairo
|
||||
{ location: [39.9042, 116.4074], size: 0.08 }, // Beijing
|
||||
{ location: [-23.5505, -46.6333], size: 0.1 }, // São Paulo
|
||||
{ location: [19.4326, -99.1332], size: 0.1 }, // Mexico City
|
||||
{ location: [40.7128, -74.006], size: 0.1 }, // New York
|
||||
{ location: [34.6937, 135.5022], size: 0.05 }, // Osaka
|
||||
{ location: [41.0082, 28.9784], size: 0.06 }, // Istanbul
|
||||
{ location: [48.8566, 2.3522], size: 0.08 }, // Paris
|
||||
{ location: [51.5072, -0.1276], size: 0.08 }, // London
|
||||
{ location: [52.52, 13.405], size: 0.07 }, // Berlin
|
||||
{ location: [35.6895, 139.6917], size: 0.06 }, // Tokyo
|
||||
{ location: [-33.8688, 151.2093], size: 0.06 }, // Sydney
|
||||
{ location: [-1.2921, 36.8219], size: 0.05 }, // Nairobi
|
||||
{ location: [-34.6037, -58.3816], size: 0.07 }, // Buenos Aires
|
||||
{ location: [37.7749, -122.4194], size: 0.08 }, // San Francisco
|
||||
{ location: [1.3521, 103.8198], size: 0.06 }, // Singapore
|
||||
{ location: [28.6139, 77.2090], size: 0.08 }, // New Delhi
|
||||
{ location: [13.7563, 100.5018], size: 0.06 }, // Bangkok
|
||||
{ location: [59.9343, 30.3351], size: 0.05 }, // St. Petersburg
|
||||
{ location: [33.6844, 73.0479], size: 0.05 }, // Islamabad
|
||||
{ location: [25.276987, 55.296249], size: 0.07 }, // Dubai
|
||||
{ location: [60.1699, 24.9384], size: 0.05 }, // Helsinki
|
||||
{ location: [43.6532, -79.3832], size: 0.07 }, // Toronto
|
||||
{ location: [6.5244, 3.3792], size: 0.08 }, // Lagos
|
||||
{ location: [50.1109, 8.6821], size: 0.06 }, // Frankfurt
|
||||
|
||||
// --- 12 New US + European Cities ---
|
||||
{ location: [34.0522, -118.2437], size: 0.08 }, // Los Angeles
|
||||
{ location: [41.8781, -87.6298], size: 0.07 }, // Chicago
|
||||
{ location: [29.7604, -95.3698], size: 0.07 }, // Houston
|
||||
{ location: [25.7617, -80.1918], size: 0.07 }, // Miami
|
||||
{ location: [45.5017, -73.5673], size: 0.06 }, // Montreal
|
||||
{ location: [47.6062, -122.3321], size: 0.06 }, // Seattle
|
||||
{ location: [40.4406, -79.9959], size: 0.05 }, // Pittsburgh
|
||||
{ location: [41.3851, 2.1734], size: 0.06 }, // Barcelona
|
||||
{ location: [45.4642, 9.19], size: 0.06 }, // Milan
|
||||
{ location: [52.3676, 4.9041], size: 0.06 }, // Amsterdam
|
||||
{ location: [38.7169, -9.139], size: 0.05 }, // Lisbon
|
||||
{ location: [59.3293, 18.0686], size: 0.05 }, // Stockholmx
|
||||
],
|
||||
};
|
||||
|
||||
@@ -47,12 +80,11 @@ export function Globe({
|
||||
let width = 0;
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const pointerInteracting = useRef<number | null>(null);
|
||||
const pointerInteractionMovement = useRef(0);
|
||||
|
||||
const r = useMotionValue(0);
|
||||
const rs = useSpring(r, {
|
||||
mass: 1,
|
||||
damping: 30,
|
||||
damping: 35, // slightly smoother motion
|
||||
stiffness: 100,
|
||||
});
|
||||
|
||||
@@ -66,16 +98,13 @@ export function Globe({
|
||||
const updateMovement = (clientX: number) => {
|
||||
if (pointerInteracting.current !== null) {
|
||||
const delta = clientX - pointerInteracting.current;
|
||||
pointerInteractionMovement.current = delta;
|
||||
r.set(r.get() + delta / MOVEMENT_DAMPING);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const onResize = () => {
|
||||
if (canvasRef.current) {
|
||||
width = canvasRef.current.offsetWidth;
|
||||
}
|
||||
if (canvasRef.current) width = canvasRef.current.offsetWidth;
|
||||
};
|
||||
|
||||
window.addEventListener("resize", onResize);
|
||||
@@ -86,7 +115,7 @@ export function Globe({
|
||||
width: width * 2,
|
||||
height: width * 2,
|
||||
onRender: (state) => {
|
||||
if (!pointerInteracting.current) phi += 0.005;
|
||||
if (!pointerInteracting.current) phi += 0.004; // slightly slower rotation for elegance
|
||||
state.phi = phi + rs.get();
|
||||
state.width = width * 2;
|
||||
state.height = width * 2;
|
||||
@@ -103,7 +132,8 @@ export function Globe({
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"absolute inset-0 mx-auto aspect-[1/1] w-full max-w-[600px]",
|
||||
// Radial gradient background that fades to pure black at edges
|
||||
"absolute inset-0 mx-auto aspect-[1/1] w-full max-w-[600px] rounded-full",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
21
src/hooks/useMediaQuery.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
export function useMediaQuery(query: string) {
|
||||
const [matches, setMatches] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const media = window.matchMedia(query)
|
||||
if (media.matches !== matches) {
|
||||
setMatches(media.matches)
|
||||
}
|
||||
const listener = () => {
|
||||
setMatches(media.matches)
|
||||
}
|
||||
media.addEventListener('change', listener)
|
||||
return () => media.removeEventListener('change', listener)
|
||||
}, [matches, query])
|
||||
|
||||
return matches
|
||||
}
|
39
src/hooks/useResponsiveCarousel.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
// 🔧 Carousel Config
|
||||
const desktopConfig = {
|
||||
GAP: 300,
|
||||
ROT_Y: 18,
|
||||
DEPTH: 210,
|
||||
SCALE_DROP: 0.12,
|
||||
};
|
||||
|
||||
const mobileConfig = {
|
||||
GAP: 110, // Smaller gap for mobile
|
||||
ROT_Y: 0, // Flatter view on mobile
|
||||
DEPTH: 150, // Less depth
|
||||
SCALE_DROP: 0.1, // Less aggressive scaling
|
||||
};
|
||||
|
||||
export const useResponsiveCarousel = () => {
|
||||
const [config, setConfig] = useState(desktopConfig);
|
||||
|
||||
useEffect(() => {
|
||||
const checkScreenSize = () => {
|
||||
if (window.innerWidth < 768) {
|
||||
setConfig(mobileConfig);
|
||||
} else {
|
||||
setConfig(desktopConfig);
|
||||
}
|
||||
};
|
||||
|
||||
checkScreenSize();
|
||||
window.addEventListener('resize', checkScreenSize);
|
||||
|
||||
return () => window.removeEventListener('resize', checkScreenSize);
|
||||
}, []);
|
||||
|
||||
return config;
|
||||
};
|
@@ -1,118 +1 @@
|
||||
<svg width="80" height="80" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.2 0H0v3.2h3.2V0ZM3.2 3.2H0v3.2h3.2V3.2ZM3.2 6.4H0v3.2h3.2V6.4Z" fill="#171717" />
|
||||
<path
|
||||
d="M3.2 9.6H0v3.2h3.2V9.6ZM3.2 12.8H0V16h3.2v-3.2ZM3.2 16H0v3.2h3.2V16ZM3.2 19.2H0v3.2h3.2v-3.2ZM3.2 25.6H0v3.2h3.2v-3.2ZM3.2 35.2H0v3.2h3.2v-3.2ZM3.2 57.6H0v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path d="M3.2 60.8H0V64h3.2v-3.2ZM3.2 64H0v3.2h3.2V64ZM3.2 67.2H0v3.2h3.2v-3.2ZM3.2 70.4H0v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M3.2 73.6H0v3.2h3.2v-3.2ZM3.2 76.8H0V80h3.2v-3.2ZM6.4 0H3.2v3.2h3.2V0ZM6.4 19.2H3.2v3.2h3.2v-3.2ZM6.4 25.6H3.2v3.2h3.2v-3.2ZM6.4 28.8H3.2V32h3.2v-3.2ZM6.4 32H3.2v3.2h3.2V32ZM6.4 35.2H3.2v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M6.4 38.4H3.2v3.2h3.2v-3.2ZM6.4 48H3.2v3.2h3.2V48ZM6.4 51.2H3.2v3.2h3.2v-3.2ZM6.4 57.6H3.2v3.2h3.2v-3.2ZM6.4 76.8H3.2V80h3.2v-3.2ZM9.6 0H6.4v3.2h3.2V0ZM9.6 6.4H6.4v3.2h3.2V6.4Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M9.6 9.6H6.4v3.2h3.2V9.6ZM9.6 12.8H6.4V16h3.2v-3.2ZM9.6 19.2H6.4v3.2h3.2v-3.2ZM9.6 28.8H6.4V32h3.2v-3.2ZM9.6 32H6.4v3.2h3.2V32ZM9.6 41.6H6.4v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M9.6 44.8H6.4V48h3.2v-3.2ZM9.6 57.6H6.4v3.2h3.2v-3.2ZM9.6 64H6.4v3.2h3.2V64ZM9.6 67.2H6.4v3.2h3.2v-3.2ZM9.6 70.4H6.4v3.2h3.2v-3.2ZM9.6 76.8H6.4V80h3.2v-3.2ZM12.8 0H9.6v3.2h3.2V0ZM12.8 6.4H9.6v3.2h3.2V6.4Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M12.8 9.6H9.6v3.2h3.2V9.6ZM12.8 12.8H9.6V16h3.2v-3.2ZM12.8 19.2H9.6v3.2h3.2v-3.2ZM12.8 25.6H9.6v3.2h3.2v-3.2ZM12.8 38.4H9.6v3.2h3.2v-3.2ZM12.8 48H9.6v3.2h3.2V48ZM12.8 51.2H9.6v3.2h3.2v-3.2ZM12.8 57.6H9.6v3.2h3.2v-3.2ZM12.8 64H9.6v3.2h3.2V64ZM12.8 67.2H9.6v3.2h3.2v-3.2ZM12.8 70.4H9.6v3.2h3.2v-3.2ZM12.8 76.8H9.6V80h3.2v-3.2ZM16 0h-3.2v3.2H16V0ZM16 6.4h-3.2v3.2H16V6.4Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M16 9.6h-3.2v3.2H16V9.6ZM16 12.8h-3.2V16H16v-3.2ZM16 19.2h-3.2v3.2H16v-3.2ZM16 25.6h-3.2v3.2H16v-3.2ZM16 41.6h-3.2v3.2H16v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M16 44.8h-3.2V48H16v-3.2ZM16 57.6h-3.2v3.2H16v-3.2ZM16 64h-3.2v3.2H16V64ZM16 67.2h-3.2v3.2H16v-3.2ZM16 70.4h-3.2v3.2H16v-3.2ZM16 76.8h-3.2V80H16v-3.2ZM19.2 0H16v3.2h3.2V0ZM19.2 19.2H16v3.2h3.2v-3.2ZM19.2 28.8H16V32h3.2v-3.2ZM19.2 44.8H16V48h3.2v-3.2ZM19.2 57.6H16v3.2h3.2v-3.2ZM19.2 76.8H16V80h3.2v-3.2ZM22.4 0h-3.2v3.2h3.2V0ZM22.4 3.2h-3.2v3.2h3.2V3.2ZM22.4 6.4h-3.2v3.2h3.2V6.4Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M22.4 9.6h-3.2v3.2h3.2V9.6ZM22.4 12.8h-3.2V16h3.2v-3.2ZM22.4 16h-3.2v3.2h3.2V16ZM22.4 19.2h-3.2v3.2h3.2v-3.2ZM22.4 25.6h-3.2v3.2h3.2v-3.2ZM22.4 32h-3.2v3.2h3.2V32ZM22.4 38.4h-3.2v3.2h3.2v-3.2ZM22.4 44.8h-3.2V48h3.2v-3.2ZM22.4 51.2h-3.2v3.2h3.2v-3.2ZM22.4 57.6h-3.2v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M22.4 60.8h-3.2V64h3.2v-3.2ZM22.4 64h-3.2v3.2h3.2V64ZM22.4 67.2h-3.2v3.2h3.2v-3.2ZM22.4 70.4h-3.2v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M22.4 73.6h-3.2v3.2h3.2v-3.2ZM22.4 76.8h-3.2V80h3.2v-3.2ZM25.6 28.8h-3.2V32h3.2v-3.2ZM25.6 32h-3.2v3.2h3.2V32ZM25.6 35.2h-3.2v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M25.6 38.4h-3.2v3.2h3.2v-3.2ZM25.6 44.8h-3.2V48h3.2v-3.2ZM25.6 48h-3.2v3.2h3.2V48ZM25.6 51.2h-3.2v3.2h3.2v-3.2ZM28.8 0h-3.2v3.2h3.2V0ZM28.8 19.2h-3.2v3.2h3.2v-3.2ZM28.8 22.4h-3.2v3.2h3.2v-3.2ZM28.8 28.8h-3.2V32h3.2v-3.2ZM28.8 32h-3.2v3.2h3.2V32ZM28.8 35.2h-3.2v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path d="M28.8 38.4h-3.2v3.2h3.2v-3.2ZM28.8 44.8h-3.2V48h3.2v-3.2ZM28.8 51.2h-3.2v3.2h3.2v-3.2Z" fill="#171717" />
|
||||
<path
|
||||
d="M28.8 54.4h-3.2v3.2h3.2v-3.2ZM28.8 64h-3.2v3.2h3.2V64ZM28.8 67.2h-3.2v3.2h3.2v-3.2ZM28.8 73.6h-3.2v3.2h3.2v-3.2ZM28.8 76.8h-3.2V80h3.2v-3.2ZM32 0h-3.2v3.2H32V0ZM32 6.4h-3.2v3.2H32V6.4ZM32 16h-3.2v3.2H32V16ZM32 22.4h-3.2v3.2H32v-3.2ZM32 25.6h-3.2v3.2H32v-3.2ZM32 32h-3.2v3.2H32V32ZM32 38.4h-3.2v3.2H32v-3.2ZM32 54.4h-3.2v3.2H32v-3.2ZM32 57.6h-3.2v3.2H32v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M32 60.8h-3.2V64H32v-3.2ZM32 76.8h-3.2V80H32v-3.2ZM35.2 0H32v3.2h3.2V0ZM35.2 9.6H32v3.2h3.2V9.6ZM35.2 12.8H32V16h3.2v-3.2ZM35.2 19.2H32v3.2h3.2v-3.2ZM35.2 28.8H32V32h3.2v-3.2ZM35.2 38.4H32v3.2h3.2v-3.2ZM35.2 41.6H32v3.2h3.2v-3.2ZM35.2 48H32v3.2h3.2V48ZM35.2 57.6H32v3.2h3.2v-3.2ZM35.2 64H32v3.2h3.2V64ZM35.2 76.8H32V80h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path d="M38.4 0h-3.2v3.2h3.2V0ZM38.4 3.2h-3.2v3.2h3.2V3.2ZM38.4 6.4h-3.2v3.2h3.2V6.4Z" fill="#171717" />
|
||||
<path
|
||||
d="M38.4 9.6h-3.2v3.2h3.2V9.6ZM38.4 12.8h-3.2V16h3.2v-3.2ZM38.4 16h-3.2v3.2h3.2V16ZM38.4 51.2h-3.2v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M38.4 54.4h-3.2v3.2h3.2v-3.2ZM38.4 60.8h-3.2V64h3.2v-3.2ZM38.4 64h-3.2v3.2h3.2V64ZM38.4 70.4h-3.2v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M38.4 73.6h-3.2v3.2h3.2v-3.2ZM38.4 76.8h-3.2V80h3.2v-3.2ZM41.6 3.2h-3.2v3.2h3.2V3.2ZM41.6 12.8h-3.2V16h3.2v-3.2ZM41.6 19.2h-3.2v3.2h3.2v-3.2ZM41.6 22.4h-3.2v3.2h3.2v-3.2ZM41.6 25.6h-3.2v3.2h3.2v-3.2ZM41.6 32h-3.2v3.2h3.2V32ZM41.6 41.6h-3.2v3.2h3.2v-3.2ZM41.6 48h-3.2v3.2h3.2V48ZM41.6 51.2h-3.2v3.2h3.2v-3.2ZM41.6 57.6h-3.2v3.2h3.2v-3.2ZM41.6 67.2h-3.2v3.2h3.2v-3.2ZM41.6 73.6h-3.2v3.2h3.2v-3.2ZM41.6 76.8h-3.2V80h3.2v-3.2ZM44.8 0h-3.2v3.2h3.2V0ZM44.8 6.4h-3.2v3.2h3.2V6.4Z"
|
||||
fill="#171717" />
|
||||
<path d="M44.8 22.4h-3.2v3.2h3.2v-3.2ZM44.8 32h-3.2v3.2h3.2V32ZM44.8 41.6h-3.2v3.2h3.2v-3.2Z" fill="#171717" />
|
||||
<path d="M44.8 44.8h-3.2V48h3.2v-3.2ZM44.8 51.2h-3.2v3.2h3.2v-3.2Z" fill="#171717" />
|
||||
<path d="M44.8 54.4h-3.2v3.2h3.2v-3.2ZM44.8 57.6h-3.2v3.2h3.2v-3.2Z" fill="#171717" />
|
||||
<path
|
||||
d="M44.8 60.8h-3.2V64h3.2v-3.2ZM44.8 64h-3.2v3.2h3.2V64ZM44.8 67.2h-3.2v3.2h3.2v-3.2ZM44.8 70.4h-3.2v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M44.8 73.6h-3.2v3.2h3.2v-3.2ZM44.8 76.8h-3.2V80h3.2v-3.2ZM48 0h-3.2v3.2H48V0ZM48 16h-3.2v3.2H48V16ZM48 19.2h-3.2v3.2H48v-3.2ZM48 25.6h-3.2v3.2H48v-3.2ZM48 44.8h-3.2V48H48v-3.2ZM48 54.4h-3.2v3.2H48v-3.2ZM48 57.6h-3.2v3.2H48v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M48 60.8h-3.2V64H48v-3.2ZM48 67.2h-3.2v3.2H48v-3.2ZM51.2 6.4H48v3.2h3.2V6.4ZM51.2 12.8H48V16h3.2v-3.2ZM51.2 22.4H48v3.2h3.2v-3.2ZM51.2 25.6H48v3.2h3.2v-3.2ZM51.2 28.8H48V32h3.2v-3.2ZM51.2 32H48v3.2h3.2V32ZM51.2 35.2H48v3.2h3.2v-3.2ZM51.2 41.6H48v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M51.2 44.8H48V48h3.2v-3.2ZM51.2 54.4H48v3.2h3.2v-3.2ZM51.2 60.8H48V64h3.2v-3.2ZM51.2 64H48v3.2h3.2V64ZM54.4 6.4h-3.2v3.2h3.2V6.4ZM54.4 12.8h-3.2V16h3.2v-3.2ZM54.4 19.2h-3.2v3.2h3.2v-3.2ZM54.4 28.8h-3.2V32h3.2v-3.2ZM54.4 32h-3.2v3.2h3.2V32ZM54.4 38.4h-3.2v3.2h3.2v-3.2ZM54.4 48h-3.2v3.2h3.2V48Z"
|
||||
fill="#171717" />
|
||||
<path d="M54.4 51.2h-3.2v3.2h3.2v-3.2Z" fill="#171717" />
|
||||
<path d="M54.4 54.4h-3.2v3.2h3.2v-3.2ZM54.4 57.6h-3.2v3.2h3.2v-3.2Z" fill="#171717" />
|
||||
<path
|
||||
d="M54.4 60.8h-3.2V64h3.2v-3.2ZM54.4 64h-3.2v3.2h3.2V64ZM54.4 67.2h-3.2v3.2h3.2v-3.2ZM54.4 70.4h-3.2v3.2h3.2v-3.2ZM54.4 76.8h-3.2V80h3.2v-3.2ZM57.6 32h-3.2v3.2h3.2V32ZM57.6 41.6h-3.2v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M57.6 44.8h-3.2V48h3.2v-3.2ZM57.6 51.2h-3.2v3.2h3.2v-3.2ZM57.6 64h-3.2v3.2h3.2V64ZM57.6 70.4h-3.2v3.2h3.2v-3.2ZM57.6 76.8h-3.2V80h3.2v-3.2ZM60.8 0h-3.2v3.2h3.2V0ZM60.8 3.2h-3.2v3.2h3.2V3.2ZM60.8 6.4h-3.2v3.2h3.2V6.4Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M60.8 9.6h-3.2v3.2h3.2V9.6ZM60.8 12.8h-3.2V16h3.2v-3.2ZM60.8 16h-3.2v3.2h3.2V16ZM60.8 19.2h-3.2v3.2h3.2v-3.2ZM60.8 25.6h-3.2v3.2h3.2v-3.2ZM60.8 35.2h-3.2v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M60.8 38.4h-3.2v3.2h3.2v-3.2ZM60.8 44.8h-3.2V48h3.2v-3.2ZM60.8 48h-3.2v3.2h3.2V48ZM60.8 51.2h-3.2v3.2h3.2v-3.2ZM60.8 57.6h-3.2v3.2h3.2v-3.2ZM60.8 64h-3.2v3.2h3.2V64ZM60.8 67.2h-3.2v3.2h3.2v-3.2ZM64 0h-3.2v3.2H64V0ZM64 19.2h-3.2v3.2H64v-3.2ZM64 28.8h-3.2V32H64v-3.2ZM64 38.4h-3.2v3.2H64v-3.2ZM64 48h-3.2v3.2H64V48ZM64 51.2h-3.2v3.2H64v-3.2ZM64 64h-3.2v3.2H64V64ZM64 73.6h-3.2v3.2H64v-3.2ZM67.2 0H64v3.2h3.2V0ZM67.2 6.4H64v3.2h3.2V6.4Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M67.2 9.6H64v3.2h3.2V9.6ZM67.2 12.8H64V16h3.2v-3.2ZM67.2 19.2H64v3.2h3.2v-3.2ZM67.2 28.8H64V32h3.2v-3.2ZM67.2 41.6H64v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path d="M67.2 44.8H64V48h3.2v-3.2ZM67.2 51.2H64v3.2h3.2v-3.2Z" fill="#171717" />
|
||||
<path d="M67.2 54.4H64v3.2h3.2v-3.2ZM67.2 57.6H64v3.2h3.2v-3.2Z" fill="#171717" />
|
||||
<path d="M67.2 60.8H64V64h3.2v-3.2ZM67.2 64H64v3.2h3.2V64ZM67.2 70.4H64v3.2h3.2v-3.2Z" fill="#171717" />
|
||||
<path d="M67.2 73.6H64v3.2h3.2v-3.2ZM70.4 0h-3.2v3.2h3.2V0ZM70.4 6.4h-3.2v3.2h3.2V6.4Z" fill="#171717" />
|
||||
<path
|
||||
d="M70.4 9.6h-3.2v3.2h3.2V9.6ZM70.4 12.8h-3.2V16h3.2v-3.2ZM70.4 19.2h-3.2v3.2h3.2v-3.2ZM70.4 28.8h-3.2V32h3.2v-3.2ZM70.4 32h-3.2v3.2h3.2V32ZM70.4 35.2h-3.2v3.2h3.2v-3.2ZM70.4 44.8h-3.2V48h3.2v-3.2ZM70.4 48h-3.2v3.2h3.2V48ZM70.4 70.4h-3.2v3.2h3.2v-3.2ZM70.4 76.8h-3.2V80h3.2v-3.2ZM73.6 0h-3.2v3.2h3.2V0Z"
|
||||
fill="#171717" />
|
||||
<path d="M73.6 6.4h-3.2v3.2h3.2V6.4Z" fill="#171717" />
|
||||
<path
|
||||
d="M73.6 9.6h-3.2v3.2h3.2V9.6ZM73.6 12.8h-3.2V16h3.2v-3.2ZM73.6 19.2h-3.2v3.2h3.2v-3.2ZM73.6 28.8h-3.2V32h3.2v-3.2ZM73.6 35.2h-3.2v3.2h3.2v-3.2ZM73.6 44.8h-3.2V48h3.2v-3.2ZM73.6 48h-3.2v3.2h3.2V48ZM73.6 51.2h-3.2v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path d="M73.6 54.4h-3.2v3.2h3.2v-3.2ZM73.6 70.4h-3.2v3.2h3.2v-3.2Z" fill="#171717" />
|
||||
<path
|
||||
d="M73.6 73.6h-3.2v3.2h3.2v-3.2ZM76.8 0h-3.2v3.2h3.2V0ZM76.8 19.2h-3.2v3.2h3.2v-3.2ZM76.8 28.8h-3.2V32h3.2v-3.2ZM76.8 35.2h-3.2v3.2h3.2v-3.2ZM76.8 41.6h-3.2v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path d="M76.8 44.8h-3.2V48h3.2v-3.2ZM76.8 51.2h-3.2v3.2h3.2v-3.2Z" fill="#171717" />
|
||||
<path
|
||||
d="M76.8 54.4h-3.2v3.2h3.2v-3.2ZM76.8 64h-3.2v3.2h3.2V64ZM76.8 67.2h-3.2v3.2h3.2v-3.2ZM76.8 70.4h-3.2v3.2h3.2v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path d="M76.8 73.6h-3.2v3.2h3.2v-3.2ZM80 0h-3.2v3.2H80V0ZM80 3.2h-3.2v3.2H80V3.2ZM80 6.4h-3.2v3.2H80V6.4Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M80 9.6h-3.2v3.2H80V9.6ZM80 12.8h-3.2V16H80v-3.2ZM80 16h-3.2v3.2H80V16ZM80 19.2h-3.2v3.2H80v-3.2ZM80 25.6h-3.2v3.2H80v-3.2ZM80 32h-3.2v3.2H80V32ZM80 35.2h-3.2v3.2H80v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path
|
||||
d="M80 38.4h-3.2v3.2H80v-3.2ZM80 44.8h-3.2V48H80v-3.2ZM80 48h-3.2v3.2H80V48ZM80 57.6h-3.2v3.2H80v-3.2ZM80 64h-3.2v3.2H80V64ZM80 67.2h-3.2v3.2H80v-3.2ZM80 70.4h-3.2v3.2H80v-3.2Z"
|
||||
fill="#171717" />
|
||||
<path d="M80 73.6h-3.2v3.2H80v-3.2ZM80 76.8h-3.2V80H80v-3.2Z" fill="#171717" />
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="80" zoomAndPan="magnify" viewBox="0 0 60 60" height="80" preserveAspectRatio="xMidYMid meet" version="1.0"><defs><clipPath id="38e6314a1e"><path d="M 6 12.121094 L 31 12.121094 L 31 34 L 6 34 Z M 6 12.121094 " clip-rule="nonzero"/></clipPath><clipPath id="e1a7034db0"><path d="M 6 12.121094 L 31 12.121094 L 31 34 L 6 34 Z M 6 12.121094 " clip-rule="nonzero"/></clipPath></defs><g clip-path="url(#38e6314a1e)"><path fill="#5999f6" d="M 29.101562 28.996094 L 18.433594 28.996094 L 10.6875 33.613281 C 10.378906 33.820312 10.019531 33.511719 10.070312 33.152344 L 11.199219 28.945312 L 7.761719 28.945312 C 6.839844 28.945312 6.019531 28.125 6.019531 27.203125 L 6.019531 13.863281 C 6.019531 12.941406 6.839844 12.121094 7.761719 12.121094 L 29.101562 12.121094 C 30.027344 12.121094 30.847656 12.941406 30.847656 13.863281 L 30.847656 27.304688 C 30.847656 28.277344 30.078125 28.996094 29.101562 28.996094 Z M 29.101562 28.996094 " fill-opacity="1" fill-rule="nonzero"/></g><path fill="#015eff" d="M 23.921875 41.617188 L 37.824219 41.617188 L 47.929688 47.617188 C 48.339844 47.875 48.800781 47.464844 48.75 47.054688 L 47.261719 41.617188 L 51.722656 41.617188 C 52.957031 41.617188 53.980469 40.539062 53.980469 39.359375 L 53.980469 21.96875 C 53.980469 20.738281 52.902344 19.710938 51.722656 19.710938 L 24.023438 19.710938 C 22.792969 19.710938 21.765625 20.789062 21.765625 21.96875 L 21.765625 39.460938 C 21.613281 40.640625 22.691406 41.617188 23.921875 41.617188 Z M 23.921875 41.617188 " fill-opacity="1" fill-rule="nonzero"/><path fill="#ffffff" d="M 37.824219 28.945312 C 38.796875 28.945312 39.515625 29.765625 39.515625 30.636719 C 39.515625 31.511719 38.695312 32.332031 37.824219 32.332031 C 36.847656 32.332031 36.128906 31.511719 36.128906 30.636719 C 36.128906 29.765625 36.847656 28.945312 37.824219 28.945312 Z M 37.824219 28.945312 " fill-opacity="1" fill-rule="nonzero"/><path fill="#ffffff" d="M 44.800781 28.945312 C 45.773438 28.945312 46.492188 29.765625 46.492188 30.636719 C 46.492188 31.511719 45.671875 32.332031 44.800781 32.332031 C 43.824219 32.332031 43.105469 31.511719 43.105469 30.636719 C 43.105469 29.765625 43.824219 28.945312 44.800781 28.945312 Z M 44.800781 28.945312 " fill-opacity="1" fill-rule="nonzero"/><path fill="#ffffff" d="M 30.796875 28.945312 C 31.769531 28.945312 32.488281 29.765625 32.488281 30.636719 C 32.488281 31.511719 31.667969 32.332031 30.796875 32.332031 C 29.820312 32.332031 29.101562 31.511719 29.101562 30.636719 C 29.101562 29.765625 29.820312 28.945312 30.796875 28.945312 Z M 30.796875 28.945312 " fill-opacity="1" fill-rule="nonzero"/><g clip-path="url(#e1a7034db0)"><path fill="#5999f6" d="M 29.101562 28.996094 L 18.433594 28.996094 L 10.6875 33.613281 C 10.378906 33.820312 10.019531 33.511719 10.070312 33.152344 L 11.199219 28.945312 L 7.761719 28.945312 C 6.839844 28.945312 6.019531 28.125 6.019531 27.203125 L 6.019531 13.863281 C 6.019531 12.941406 6.839844 12.121094 7.761719 12.121094 L 29.101562 12.121094 C 30.027344 12.121094 30.847656 12.941406 30.847656 13.863281 L 30.847656 27.304688 C 30.847656 28.277344 30.078125 28.996094 29.101562 28.996094 Z M 29.101562 28.996094 " fill-opacity="1" fill-rule="nonzero"/></g><path fill="#015eff" d="M 23.921875 41.617188 L 37.824219 41.617188 L 47.929688 47.617188 C 48.339844 47.875 48.800781 47.464844 48.75 47.054688 L 47.261719 41.617188 L 51.722656 41.617188 C 52.957031 41.617188 53.980469 40.539062 53.980469 39.359375 L 53.980469 21.96875 C 53.980469 20.738281 52.902344 19.710938 51.722656 19.710938 L 24.023438 19.710938 C 22.792969 19.710938 21.765625 20.789062 21.765625 21.96875 L 21.765625 39.460938 C 21.613281 40.640625 22.691406 41.617188 23.921875 41.617188 Z M 23.921875 41.617188 " fill-opacity="1" fill-rule="nonzero"/><path fill="#ffffff" d="M 37.824219 28.945312 C 38.796875 28.945312 39.515625 29.765625 39.515625 30.636719 C 39.515625 31.511719 38.695312 32.332031 37.824219 32.332031 C 36.847656 32.332031 36.128906 31.511719 36.128906 30.636719 C 36.128906 29.765625 36.847656 28.945312 37.824219 28.945312 Z M 37.824219 28.945312 " fill-opacity="1" fill-rule="nonzero"/><path fill="#ffffff" d="M 44.800781 28.945312 C 45.773438 28.945312 46.492188 29.765625 46.492188 30.636719 C 46.492188 31.511719 45.671875 32.332031 44.800781 32.332031 C 43.824219 32.332031 43.105469 31.511719 43.105469 30.636719 C 43.105469 29.765625 43.824219 28.945312 44.800781 28.945312 Z M 44.800781 28.945312 " fill-opacity="1" fill-rule="nonzero"/><path fill="#ffffff" d="M 30.796875 28.945312 C 31.769531 28.945312 32.488281 29.765625 32.488281 30.636719 C 32.488281 31.511719 31.667969 32.332031 30.796875 32.332031 C 29.820312 32.332031 29.101562 31.511719 29.101562 30.636719 C 29.101562 29.765625 29.820312 28.945312 30.796875 28.945312 Z M 30.796875 28.945312 " fill-opacity="1" fill-rule="nonzero"/></svg>
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 4.8 KiB |
13
src/pages/_document.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Html, Head, Main, NextScript } from 'next/document'
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|