forked from sashaastiadi/www_mycelium_net
Compare commits
33 Commits
1e55b58298
...
developmen
| Author | SHA1 | Date | |
|---|---|---|---|
| 4eb8a8aba7 | |||
| 90499e2b77 | |||
| 812eb5f455 | |||
| 471f53162f | |||
| e7b053bd76 | |||
| d197ca74ad | |||
| 0ca6a563b1 | |||
| f6841df98f | |||
| 8aa5309e36 | |||
| 076207c192 | |||
| fad531667e | |||
| d03b67df7d | |||
| bca730681e | |||
| 02da6bb5ed | |||
| 08a309abea | |||
| d344652a2f | |||
| bdbec5fd49 | |||
| 4d89745a57 | |||
| df60aaa7a1 | |||
| 10ca28b2ec | |||
| 2988ce5335 | |||
| 4934dc7f35 | |||
| acd46171c8 | |||
| 1494a83812 | |||
| ae277d33b5 | |||
| 794605117a | |||
| 39e19a95d0 | |||
| e598e2ffb1 | |||
| 5d37cb4b3b | |||
| 607a31e96d | |||
| 50f8ae3d69 | |||
| 4056d31743 | |||
| 4b5d1c7f00 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -53,7 +53,7 @@ node_modules/
|
|||||||
public
|
public
|
||||||
|
|
||||||
# Storybook build outputs
|
# Storybook build outputs
|
||||||
.out
|
out/
|
||||||
.storybook-out
|
.storybook-out
|
||||||
|
|
||||||
# Temporary folders
|
# Temporary folders
|
||||||
|
|||||||
81
README.md
81
README.md
@@ -148,3 +148,84 @@ To create a new page, follow these steps:
|
|||||||
```
|
```
|
||||||
|
|
||||||
The new page will be accessible at `http://localhost:3000/new-page`.
|
The new page will be accessible at `http://localhost:3000/new-page`.
|
||||||
|
|
||||||
|
### Download Page
|
||||||
|
|
||||||
|
The download page, located at `src/app/(main)/download/page.tsx`, provides users with download links for the Mycelium application across various operating systems. The page is composed of the following components:
|
||||||
|
|
||||||
|
- **DownloadHero**: Displays the main header and a grid of download cards for each supported platform (iOS, macOS, Windows, Android, and Linux).
|
||||||
|
- **DevHub**: Provides links to developer resources, including documentation, support channels, forums, and community groups.
|
||||||
|
- **Faqs**: A frequently asked questions section to address common user queries.
|
||||||
|
|
||||||
|
### Not Found Page
|
||||||
|
|
||||||
|
The `not-found.tsx` file at `src/app/not-found.tsx` defines a custom 404 error page. This page is displayed whenever a user navigates to a non-existent route. It features a clean and simple layout with a 404 message and a button that directs the user back to the homepage.
|
||||||
|
|
||||||
|
### Typography with `Texts.tsx`
|
||||||
|
|
||||||
|
The `src/components/Texts.tsx` file implements a flexible and consistent typography system using a factory pattern. It exports a set of reusable text components, such as `H1`, `P`, and `SectionHeader`, each with predefined styles and color variants.
|
||||||
|
|
||||||
|
This approach ensures that the visual hierarchy and design language remain consistent throughout the application. To use a text component, simply import it and use it like any other React component:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { H1, P } from '@/components/Texts';
|
||||||
|
|
||||||
|
function MyComponent() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<H1 color="accent">This is a heading</H1>
|
||||||
|
<P color="secondary">This is a paragraph.</P>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Button Components
|
||||||
|
|
||||||
|
The `src/components/Button.tsx` file provides a polymorphic button component that can be rendered as either a `<button>` or a Next.js `<Link>`. It supports two main variants (`solid` and `outline`) and multiple color schemes.
|
||||||
|
|
||||||
|
This component is used throughout the application to ensure that all buttons and links have a consistent look and feel. Example usage:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { Button } from '@/components/Button';
|
||||||
|
|
||||||
|
function MyComponent() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Button variant="solid" color="cyan">Submit</Button>
|
||||||
|
<Button href="/about" variant="outline">Learn More</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding Images
|
||||||
|
|
||||||
|
To add images to the project while ensuring they are optimized, use the Next.js `Image` component. Follow these steps:
|
||||||
|
|
||||||
|
1. **Place Your Image**: Add your image file to the `src/images/` directory.
|
||||||
|
|
||||||
|
2. **Import the Image**: In the component where you want to display the image, import it at the top of the file:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import myImage from '@/images/my-image.png';
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Use the `Image` Component**: Use the `Image` component from `next/image` to render your image. Provide the `src`, `alt`, `width`, and `height` props for proper rendering and accessibility.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import Image from 'next/image';
|
||||||
|
import myImage from '@/images/my-image.png';
|
||||||
|
|
||||||
|
export function MyComponent() {
|
||||||
|
return (
|
||||||
|
<Image
|
||||||
|
src={myImage}
|
||||||
|
alt="A descriptive alt text for accessibility"
|
||||||
|
width={500}
|
||||||
|
height={300}
|
||||||
|
priority // Optional: Add this if the image is critical for the initial page load
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
output: 'export',
|
output: 'export',
|
||||||
|
trailingSlash: true,
|
||||||
images: {
|
images: {
|
||||||
unoptimized: true,
|
unoptimized: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = nextConfig
|
module.exports = nextConfig
|
||||||
|
|
||||||
|
|||||||
20
package-lock.json
generated
20
package-lock.json
generated
@@ -14,11 +14,12 @@
|
|||||||
"@types/node": "^20.10.8",
|
"@types/node": "^20.10.8",
|
||||||
"@types/react": "^18.2.47",
|
"@types/react": "^18.2.47",
|
||||||
"@types/react-dom": "^18.2.18",
|
"@types/react-dom": "^18.2.18",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.1",
|
||||||
"framer-motion": "^10.15.0",
|
"framer-motion": "^10.15.0",
|
||||||
"next": "^14.0.4",
|
"next": "^14.0.4",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
"tailwind-merge": "^3.3.1",
|
||||||
"tailwindcss": "^4.1.7",
|
"tailwindcss": "^4.1.7",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"use-debounce": "^10.0.0"
|
"use-debounce": "^10.0.0"
|
||||||
@@ -1881,9 +1882,10 @@
|
|||||||
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
|
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
|
||||||
},
|
},
|
||||||
"node_modules/clsx": {
|
"node_modules/clsx": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||||
"integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==",
|
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
@@ -4942,6 +4944,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
|
||||||
"integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="
|
"integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="
|
||||||
},
|
},
|
||||||
|
"node_modules/tailwind-merge": {
|
||||||
|
"version": "3.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz",
|
||||||
|
"integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/dcastil"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "4.1.7",
|
"version": "4.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.7.tgz",
|
||||||
|
|||||||
@@ -16,11 +16,12 @@
|
|||||||
"@types/node": "^20.10.8",
|
"@types/node": "^20.10.8",
|
||||||
"@types/react": "^18.2.47",
|
"@types/react": "^18.2.47",
|
||||||
"@types/react-dom": "^18.2.18",
|
"@types/react-dom": "^18.2.18",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.1",
|
||||||
"framer-motion": "^10.15.0",
|
"framer-motion": "^10.15.0",
|
||||||
"next": "^14.0.4",
|
"next": "^14.0.4",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
"tailwind-merge": "^3.3.1",
|
||||||
"tailwindcss": "^4.1.7",
|
"tailwindcss": "^4.1.7",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"use-debounce": "^10.0.0"
|
"use-debounce": "^10.0.0"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { PrimaryFeatures } from '@/components/PrimaryFeatures'
|
|||||||
import { UseCases } from '@/components/UseCases'
|
import { UseCases } from '@/components/UseCases'
|
||||||
import { SecondaryFeatures } from '@/components/SecondaryFeatures'
|
import { SecondaryFeatures } from '@/components/SecondaryFeatures'
|
||||||
import { Benefits } from '@/components/Benefits'
|
import { Benefits } from '@/components/Benefits'
|
||||||
import { About } from '@/components/About'
|
import { AboutNew } from '@/components/AboutNew'
|
||||||
import { Features } from '@/components/Features'
|
import { Features } from '@/components/Features'
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
@@ -16,7 +16,7 @@ export default function Home() {
|
|||||||
<Hero />
|
<Hero />
|
||||||
</AnimatedSection>
|
</AnimatedSection>
|
||||||
<AnimatedSection>
|
<AnimatedSection>
|
||||||
<About />
|
<AboutNew />
|
||||||
</AnimatedSection>
|
</AnimatedSection>
|
||||||
<AnimatedSection>
|
<AnimatedSection>
|
||||||
<Features />
|
<Features />
|
||||||
|
|||||||
48
src/app/api/subscribe/route.ts
Normal file
48
src/app/api/subscribe/route.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
|
|
||||||
|
export async function POST(req: NextRequest) {
|
||||||
|
const { email } = await req.json();
|
||||||
|
|
||||||
|
if (!email) {
|
||||||
|
return NextResponse.json({ error: 'Email is required' }, { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAILERLITE_API_KEY = process.env.MAILERLITE_API_KEY;
|
||||||
|
const MAILERLITE_GROUP_ID = process.env.MAILERLITE_GROUP_ID;
|
||||||
|
|
||||||
|
if (!MAILERLITE_API_KEY || !MAILERLITE_GROUP_ID) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'MailerLite API key or Group ID are not configured' },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`https://api.mailerlite.com/api/v2/groups/${MAILERLITE_GROUP_ID}/subscribers`,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-MailerLite-ApiKey': MAILERLITE_API_KEY,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ email }),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorData = await response.json();
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: errorData.error.message || 'Something went wrong' },
|
||||||
|
{ status: response.status },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json({ success: true }, { status: 200 });
|
||||||
|
} catch (error) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'An unexpected error occurred' },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -1,5 +1,6 @@
|
|||||||
import { type Metadata } from 'next'
|
import { type Metadata } from 'next'
|
||||||
import { Inter } from 'next/font/google'
|
import { Inter } from 'next/font/google'
|
||||||
|
import Script from 'next/script'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
|
|
||||||
import '@/styles/tailwind.css'
|
import '@/styles/tailwind.css'
|
||||||
@@ -17,6 +18,9 @@ export const metadata: Metadata = {
|
|||||||
},
|
},
|
||||||
description:
|
description:
|
||||||
'Discover Mycelium, an end-to-end encrypted IPv6 overlay network. The future of secure, efficient, and scalable networking.',
|
'Discover Mycelium, an end-to-end encrypted IPv6 overlay network. The future of secure, efficient, and scalable networking.',
|
||||||
|
icons: {
|
||||||
|
icon: '/favicon.ico',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
@@ -26,7 +30,28 @@ export default function RootLayout({
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<html lang="en" className={clsx('bg-gray-50 antialiased', inter.variable)}>
|
<html lang="en" className={clsx('bg-gray-50 antialiased', inter.variable)}>
|
||||||
<body>{children}</body>
|
<body>
|
||||||
|
{children}
|
||||||
|
|
||||||
|
{/* Crisp Chat */}
|
||||||
|
<Script
|
||||||
|
id="crisp-init"
|
||||||
|
strategy="afterInteractive"
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: `
|
||||||
|
window.$crisp = [];
|
||||||
|
window.CRISP_WEBSITE_ID = "1a5a5241-91cb-4a41-8323-5ba5ec574da0";
|
||||||
|
(function () {
|
||||||
|
d = document;
|
||||||
|
s = d.createElement("script");
|
||||||
|
s.src = "https://client.crisp.chat/l.js";
|
||||||
|
s.async = 1;
|
||||||
|
d.getElementsByTagName("head")[0].appendChild(s);
|
||||||
|
})();
|
||||||
|
`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Button } from '@/components/Button'
|
import { Button } from '@/components/Button'
|
||||||
|
import { P, SectionHeader, Small } from '@/components/Texts'
|
||||||
import { CirclesBackground } from '@/components/CirclesBackground'
|
import { CirclesBackground } from '@/components/CirclesBackground'
|
||||||
import { Container } from '@/components/Container'
|
import { Container } from '@/components/Container'
|
||||||
import { Layout } from '@/components/Layout'
|
import { Layout } from '@/components/Layout'
|
||||||
@@ -8,13 +9,13 @@ export default function NotFound() {
|
|||||||
<Layout>
|
<Layout>
|
||||||
<Container className="relative isolate flex h-full flex-col items-center justify-center py-20 text-center sm:py-32">
|
<Container className="relative isolate flex h-full flex-col items-center justify-center py-20 text-center sm:py-32">
|
||||||
<CirclesBackground className="absolute top-1/2 left-1/2 -z-10 mt-44 w-272.5 -translate-x-1/2 -translate-y-1/2 mask-[linear-gradient(to_bottom,white_20%,transparent_75%)] stroke-gray-300/30" />
|
<CirclesBackground className="absolute top-1/2 left-1/2 -z-10 mt-44 w-272.5 -translate-x-1/2 -translate-y-1/2 mask-[linear-gradient(to_bottom,white_20%,transparent_75%)] stroke-gray-300/30" />
|
||||||
<p className="text-sm font-semibold text-gray-900">404</p>
|
<Small as="p" color="primary">404</Small>
|
||||||
<h1 className="mt-2 text-3xl lg:text-4xl font-medium tracking-tight text-gray-900">
|
<SectionHeader as="h1" className="mt-2">
|
||||||
Page not found
|
Page not found
|
||||||
</h1>
|
</SectionHeader>
|
||||||
<p className="mt-2 text-lg text-gray-600">
|
<P color="secondary" className="mt-2">
|
||||||
Sorry, we couldn’t find the page you’re looking for.
|
Sorry, we couldn’t find the page you’re looking for.
|
||||||
</p>
|
</P>
|
||||||
<Button href="/" variant="outline" className="mt-8">
|
<Button href="/" variant="outline" className="mt-8">
|
||||||
Go back home
|
Go back home
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { AppStoreLink } from '@/components/AppStoreLink'
|
import { AppStoreLink } from '@/components/AppStoreLink'
|
||||||
|
import { Eyebrow, P, SectionHeader } from '@/components/Texts'
|
||||||
import { Button } from '@/components/Button'
|
import { Button } from '@/components/Button'
|
||||||
import { CircleBackground } from '@/components/CircleBackground'
|
import { CircleBackground } from '@/components/CircleBackground'
|
||||||
import { Container } from '@/components/Container'
|
import { Container } from '@/components/Container'
|
||||||
@@ -7,35 +8,41 @@ export function About() {
|
|||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
id="about"
|
id="about"
|
||||||
className="relative overflow-hidden bg-gray-900 py-20 lg:py-32 lg:top-0 top-0"
|
className="relative bg-gray-900 py-20 lg:py-32"
|
||||||
>
|
>
|
||||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
<div className="relative -mt-[100vh]">
|
||||||
<CircleBackground color="#fff" className="animate-spin-slower" />
|
<Container>
|
||||||
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||||
|
<CircleBackground id="aboutcircle" color="#06b6d4" className="animate-spin-slower" />
|
||||||
</div>
|
</div>
|
||||||
<Container className="relative">
|
<div className="mx-auto max-w-3xl text-center">
|
||||||
<div className="mx-auto max-w-3xl text-center">
|
<Eyebrow color="accent">Our Mission</Eyebrow>
|
||||||
<h2 className="text-base/7 font-semibold text-cyan-500">Our Mission</h2>
|
<SectionHeader color="white" className="mt-2">
|
||||||
<p className="text-3xl lg:text-4xl font-medium tracking-tight text-white sm:text-4xl">
|
Discover Mycelium
|
||||||
Discover Mycelium
|
</SectionHeader>
|
||||||
</p>
|
<P color="light" className="mt-6">
|
||||||
<p className="mt-6 text-lg text-gray-300">
|
Mycelium is an unbreakable network, always finding the shortest path and
|
||||||
Mycelium is an unbreakable network, always finding the shortest path and providing 100% secure, peer-to-peer communication. But this is just the beginning.
|
providing 100% secure, peer-to-peer communication. But this is just
|
||||||
</p>
|
the beginning.
|
||||||
<p className="mt-6 text-lg text-gray-300">
|
</P>
|
||||||
Our mission is to create a sustainable digital ecosystem where communication is seamless, data is secure, and scalability knows no bounds.
|
<P color="light" className="mt-6">
|
||||||
</p>
|
Our mission is to create a sustainable digital ecosystem where
|
||||||
<div className="mt-8 flex justify-center">
|
communication is seamless, data is secure, and scalability knows no
|
||||||
<Button
|
bounds.
|
||||||
href="https://threefold.info/mycelium_network/docs/"
|
</P>
|
||||||
target="_blank"
|
<div className="mt-8 flex justify-center">
|
||||||
variant="outline"
|
<Button
|
||||||
color="white"
|
href="https://threefold.info/mycelium_network/docs/"
|
||||||
>
|
target="_blank"
|
||||||
Learn More
|
variant="outline"
|
||||||
</Button>
|
color="white"
|
||||||
|
>
|
||||||
|
Learn More
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Container>
|
||||||
</Container>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
37
src/components/AboutNew.tsx
Normal file
37
src/components/AboutNew.tsx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { AppStoreLink } from '@/components/AppStoreLink'
|
||||||
|
import { P, SectionHeader } from '@/components/Texts'
|
||||||
|
import { WindowsLink } from '@/components/WindowsLink'
|
||||||
|
import { AndroidLink } from './AndroidLink'
|
||||||
|
import { LinuxLink } from '@/components/LinuxLink'
|
||||||
|
import { CircleBackground } from '@/components/CircleBackground'
|
||||||
|
import { Container } from '@/components/Container'
|
||||||
|
|
||||||
|
export function AboutNew() {
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
id="get-free-shares-today"
|
||||||
|
className="relative overflow-hidden bg-gray-900 py-20 sm:py-28"
|
||||||
|
>
|
||||||
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||||
|
<CircleBackground id="aboutcircle" color="#06b6d4" className="animate-spin-slower" />
|
||||||
|
</div>
|
||||||
|
<Container>
|
||||||
|
<div className="mx-auto max-w-2xl text-center">
|
||||||
|
<SectionHeader as="h2" color="white">
|
||||||
|
Discover Mycelium
|
||||||
|
</SectionHeader>
|
||||||
|
<P color="light" className="mt-6">
|
||||||
|
Mycelium is an unbreakable network, always finding the shortest path and
|
||||||
|
providing 100% secure, peer-to-peer communication. But this is just
|
||||||
|
the beginning.
|
||||||
|
</P>
|
||||||
|
<P color="light" className="mt-6">
|
||||||
|
Our mission is to create a sustainable digital ecosystem where
|
||||||
|
communication is seamless, data is secure, and scalability knows no
|
||||||
|
bounds.
|
||||||
|
</P>
|
||||||
|
</div>
|
||||||
|
</Container>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ export function AndroidLink({
|
|||||||
href="#"
|
href="#"
|
||||||
aria-label="Download for Android"
|
aria-label="Download for Android"
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'flex items-center rounded-lg transition-colors px-4 py-2',
|
'flex items-center rounded-lg px-4 py-2 transition-all hover:scale-105',
|
||||||
color === 'black'
|
color === 'black'
|
||||||
? 'bg-gray-800 text-white hover:bg-gray-900'
|
? 'bg-gray-800 text-white hover:bg-gray-900'
|
||||||
: 'bg-white text-gray-900 hover:bg-gray-50',
|
: 'bg-white text-gray-900 hover:bg-gray-50',
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export function AppStoreLink({
|
|||||||
href="https://apps.apple.com/us/app/mycelium-network/id6504277565"
|
href="https://apps.apple.com/us/app/mycelium-network/id6504277565"
|
||||||
aria-label="Download on the App Store"
|
aria-label="Download on the App Store"
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'rounded-lg transition-colors',
|
'rounded-lg transition-all hover:scale-105',
|
||||||
color === 'black'
|
color === 'black'
|
||||||
? 'bg-gray-800 text-white hover:bg-gray-900'
|
? 'bg-gray-800 text-white hover:bg-gray-900'
|
||||||
: 'bg-white text-gray-900 hover:bg-gray-50',
|
: 'bg-white text-gray-900 hover:bg-gray-50',
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const baseStyles = {
|
|||||||
solid:
|
solid:
|
||||||
'inline-flex justify-center rounded-lg py-2 px-3 text-sm font-semibold transition-colors',
|
'inline-flex justify-center rounded-lg py-2 px-3 text-sm font-semibold transition-colors',
|
||||||
outline:
|
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(0.5rem-1px)] px-[calc(0.75rem-1px)] text-sm font-semibold transition-colors',
|
||||||
}
|
}
|
||||||
|
|
||||||
const variantStyles = {
|
const variantStyles = {
|
||||||
@@ -14,10 +14,11 @@ const variantStyles = {
|
|||||||
white:
|
white:
|
||||||
'bg-white text-cyan-900 hover:bg-white/90 active:bg-white/90 active:text-cyan-900/70',
|
'bg-white text-cyan-900 hover:bg-white/90 active:bg-white/90 active:text-cyan-900/70',
|
||||||
gray: 'bg-gray-800 text-white hover:bg-gray-900 active:bg-gray-800 active:text-white/80',
|
gray: 'bg-gray-800 text-white hover:bg-gray-900 active:bg-gray-800 active:text-white/80',
|
||||||
|
green: 'bg-green-500 text-white hover:bg-green-600',
|
||||||
},
|
},
|
||||||
outline: {
|
outline: {
|
||||||
gray: 'border-gray-300 text-gray-700 hover:text-gray-500 hover:border-gray-400 active:bg-gray-100 active:text-gray-700/80',
|
gray: 'border-gray-300 text-gray-600 hover:border-cyan-500 active:border-cyan-500',
|
||||||
white: 'border-gray-300 text-white hover:text-gray-200 hover:border-gray-400 active:bg-gray-100 active:text-gray-700/80',
|
white: 'border-gray-300 text-white hover:border-cyan-500 active:border-cyan-500',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { AppStoreLink } from '@/components/AppStoreLink'
|
import { AppStoreLink } from '@/components/AppStoreLink'
|
||||||
|
import { P, SectionHeader } from '@/components/Texts'
|
||||||
import { WindowsLink } from '@/components/WindowsLink'
|
import { WindowsLink } from '@/components/WindowsLink'
|
||||||
import { AndroidLink } from './AndroidLink'
|
import { AndroidLink } from './AndroidLink'
|
||||||
import { LinuxLink } from '@/components/LinuxLink'
|
import { LinuxLink } from '@/components/LinuxLink'
|
||||||
@@ -12,17 +13,18 @@ export function CallToAction() {
|
|||||||
className="relative overflow-hidden bg-gray-900 py-20 sm:py-28"
|
className="relative overflow-hidden bg-gray-900 py-20 sm:py-28"
|
||||||
>
|
>
|
||||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||||
<CircleBackground color="#fff" className="animate-spin-slower" />
|
<CircleBackground id="cta_circle" color="#06b6d4" className="animate-spin-slower" />
|
||||||
</div>
|
</div>
|
||||||
<Container className="relative">
|
<Container>
|
||||||
<div className="mx-auto max-w-2xl sm:text-center">
|
<div className="mx-auto max-w-2xl text-center">
|
||||||
<h2 className="text-3xl lg:text-4xl font-medium tracking-tight text-white sm:text-4xl">
|
<SectionHeader as="h2" color="white">
|
||||||
Get Started Today
|
Get Started Today
|
||||||
</h2>
|
</SectionHeader>
|
||||||
<p className="mt-6 text-lg text-gray-300">
|
<P color="lightSecondary" className="mt-6">
|
||||||
Download the Mycelium app and step into the future of secure, peer-to-peer networking; fast, private, and decentralized.
|
Download the Mycelium app and step into the future of secure,
|
||||||
</p>
|
peer-to-peer networking; fast, private, and decentralized.
|
||||||
<div className="mt-8 grid grid-cols-2 justify-items-center gap-4 sm:flex sm:justify-center">
|
</P>
|
||||||
|
<div className="mt-10 flex flex-wrap justify-center gap-x-6 gap-y-4">
|
||||||
<AppStoreLink color="white" />
|
<AppStoreLink color="white" />
|
||||||
<WindowsLink color="white" />
|
<WindowsLink color="white" />
|
||||||
<AndroidLink color="white" />
|
<AndroidLink color="white" />
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { motion, useReducedMotion } from 'framer-motion';
|
import { motion, useReducedMotion } from 'framer-motion';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
className?: string; // e.g. "w-full h-80"
|
className?: string; // e.g. "w-full h-80"
|
||||||
@@ -135,7 +136,12 @@ export default function ContentDistribution({ className, bg = '#ffffff' }: Props
|
|||||||
const prefersReduced = useReducedMotion();
|
const prefersReduced = useReducedMotion();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className} aria-hidden="true" role="img" style={{ background: bg }}>
|
<div
|
||||||
|
className={clsx('relative overflow-hidden', className)}
|
||||||
|
aria-hidden="true"
|
||||||
|
role="img"
|
||||||
|
style={{ background: bg }}
|
||||||
|
>
|
||||||
<svg viewBox={`0 0 ${W} ${H}`} width="100%" height="100%">
|
<svg viewBox={`0 0 ${W} ${H}`} width="100%" height="100%">
|
||||||
{/* subtle radial background + rings */}
|
{/* subtle radial background + rings */}
|
||||||
<defs>
|
<defs>
|
||||||
|
|||||||
@@ -1,18 +1,43 @@
|
|||||||
import { CheckIcon } from '@heroicons/react/20/solid'
|
import {
|
||||||
|
Eyebrow,
|
||||||
|
FeatureDescription,
|
||||||
|
P,
|
||||||
|
SectionHeader,
|
||||||
|
SecondaryFeatureTitle,
|
||||||
|
} from './Texts'
|
||||||
|
import {
|
||||||
|
BookOpenIcon,
|
||||||
|
LifebuoyIcon,
|
||||||
|
ChatBubbleOvalLeftEllipsisIcon,
|
||||||
|
UserGroupIcon,
|
||||||
|
} from '@heroicons/react/24/outline';
|
||||||
|
|
||||||
const features = [
|
const features = [
|
||||||
{
|
{
|
||||||
name: 'Documentation',
|
name: 'Documentation',
|
||||||
description: 'Documentation for Mycelium.',
|
description: 'Documentation for Mycelium.',
|
||||||
|
href: 'https://threefold.info/mycelium_network/docs/',
|
||||||
|
icon: BookOpenIcon,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Support',
|
||||||
|
description: 'Talk to an expert.',
|
||||||
|
href: 'https://threefoldfaq.crisp.help/en/',
|
||||||
|
icon: LifebuoyIcon,
|
||||||
},
|
},
|
||||||
{ name: 'Support', description: 'Talk to an expert.' },
|
|
||||||
{
|
{
|
||||||
name: 'Forum',
|
name: 'Forum',
|
||||||
description: 'Forum for all your questions.',
|
description: 'Forum for all your questions.',
|
||||||
|
href: 'https://forum.threefold.io/',
|
||||||
|
icon: ChatBubbleOvalLeftEllipsisIcon,
|
||||||
},
|
},
|
||||||
{ name: 'Community', description: 'Join our Developers community on telegram.' },
|
{
|
||||||
|
name: 'Community',
|
||||||
]
|
description: 'Join our Developers community on telegram.',
|
||||||
|
href: 'https://t.me/threefoldtesting',
|
||||||
|
icon: UserGroupIcon,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export function DevHub() {
|
export function DevHub() {
|
||||||
return (
|
return (
|
||||||
@@ -20,27 +45,40 @@ export function DevHub() {
|
|||||||
<div className="mx-auto max-w-7xl px-6 lg:px-8">
|
<div className="mx-auto max-w-7xl px-6 lg:px-8">
|
||||||
<div className="mx-auto grid max-w-2xl grid-cols-1 gap-x-8 gap-y-16 sm:gap-y-20 lg:mx-0 lg:max-w-none lg:grid-cols-5">
|
<div className="mx-auto grid max-w-2xl grid-cols-1 gap-x-8 gap-y-16 sm:gap-y-20 lg:mx-0 lg:max-w-none lg:grid-cols-5">
|
||||||
<div className="col-span-2">
|
<div className="col-span-2">
|
||||||
<h2 className="text-base/7 font-semibold text-cyan-500 mb-2">Get Started</h2>
|
<Eyebrow color="accent" className="mb-2">Get Started</Eyebrow>
|
||||||
<p className="text-4xl font-semibold tracking-tight text-pretty text-white sm:text-5xl">
|
<SectionHeader as="h2" color="white">
|
||||||
Developer Hub
|
Developer Hub
|
||||||
</p>
|
</SectionHeader>
|
||||||
<p className="mt-6 text-base/7 text-gray-300">
|
<P color="lightSecondary" className="mt-6">
|
||||||
Our Developer Hub is a resource center for developers looking to build on top of Mycelium. Join our Developers community on telegram to get started.
|
Our Developer Hub is a resource center for developers looking to build
|
||||||
</p>
|
on top of Mycelium. Join our Developers community on telegram to get
|
||||||
|
started.
|
||||||
|
</P>
|
||||||
</div>
|
</div>
|
||||||
<dl className="col-span-3 grid grid-cols-1 gap-x-8 gap-y-10 text-base/7 text-gray-400 sm:grid-cols-2 lg:gap-y-16">
|
<dl className="col-span-3 grid grid-cols-1 gap-8 sm:grid-cols-2">
|
||||||
{features.map((feature) => (
|
{features.map((feature) => (
|
||||||
<div key={feature.name} className="relative pl-9">
|
<a
|
||||||
<dt className="font-semibold text-white">
|
key={feature.name}
|
||||||
<CheckIcon aria-hidden="true" className="absolute top-1 left-0 size-5 text-indigo-400" />
|
href={feature.href}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="block rounded-2xl border border-gray-700 p-6 shadow-sm transition-all duration-300 ease-in-out hover:scale-105 hover:border-cyan-500 hover:shadow-lg hover:shadow-cyan-500/20 hover:bg-gray-800"
|
||||||
|
>
|
||||||
|
<feature.icon
|
||||||
|
aria-hidden="true"
|
||||||
|
className="h-6 w-6 flex-none text-cyan-500 mb-4"
|
||||||
|
/>
|
||||||
|
<SecondaryFeatureTitle as="dt" color="white">
|
||||||
{feature.name}
|
{feature.name}
|
||||||
</dt>
|
</SecondaryFeatureTitle>
|
||||||
<dd className="mt-2">{feature.description}</dd>
|
<FeatureDescription as="dd" color="secondary" className="mt-2">
|
||||||
</div>
|
{feature.description}
|
||||||
|
</FeatureDescription>
|
||||||
|
</a>
|
||||||
))}
|
))}
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,13 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
|
import {
|
||||||
|
DownloadCardDescription,
|
||||||
|
DownloadCardTitle,
|
||||||
|
P,
|
||||||
|
PageHeader,
|
||||||
|
} from './Texts'
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
import appleIcon from '@/images/apple.svg';
|
import appleIcon from '@/images/apple.svg';
|
||||||
import windowsIcon from '@/images/windows.svg';
|
import windowsIcon from '@/images/windows.svg';
|
||||||
import androidIcon from '@/images/android.svg';
|
import androidIcon from '@/images/android.svg';
|
||||||
@@ -36,37 +45,59 @@ export default function DownloadHero() {
|
|||||||
<div className=" py-16 sm:py-32">
|
<div className=" py-16 sm:py-32">
|
||||||
<div className="mx-auto max-w-7xl px-6 lg:px-8">
|
<div className="mx-auto max-w-7xl px-6 lg:px-8">
|
||||||
<div className="mx-auto max-w-2xl lg:mx-0">
|
<div className="mx-auto max-w-2xl lg:mx-0">
|
||||||
<h2 className="text-5xl lg:text-6xl font-medium tracking-tight text-gray-900">
|
<motion.div
|
||||||
Download Mycelium
|
initial={{ opacity: 0, y: 20 }}
|
||||||
</h2>
|
animate={{ opacity: 1, y: 0 }}
|
||||||
<p className="mt-6 text-lg/8 text-gray-600">
|
transition={{ duration: 0.5 }}
|
||||||
Get Mycelium for Android, Windows, macOS, and iOS to securely connect, store, and interact with the decentralized network—seamlessly and efficiently. Not sure how it works?{' '}
|
>
|
||||||
<a href="https://threefold.info/mycelium_network/docs/" className="text-cyan-500 hover:text-cyan-600 font-semibold underline">
|
<PageHeader>Download Mycelium</PageHeader>
|
||||||
Read the manual.
|
</motion.div>
|
||||||
</a>
|
<motion.div
|
||||||
</p>
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.5, delay: 0.2 }}
|
||||||
|
>
|
||||||
|
<P color="secondary" className="mt-6 text-lg/8">
|
||||||
|
Get Mycelium for Android, Windows, macOS, and iOS to securely
|
||||||
|
connect, store, and interact with the decentralized
|
||||||
|
network—seamlessly and efficiently. Not sure how it works?{' '}
|
||||||
|
<a
|
||||||
|
href="https://threefold.info/mycelium_network/docs/"
|
||||||
|
className="text-gray-900 hover:text-cyan-500 transition-colors font-semibold underline"
|
||||||
|
>
|
||||||
|
Read the manual.
|
||||||
|
</a>
|
||||||
|
</P>
|
||||||
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx-auto mt-16 max-w-2xl sm:mt-20 lg:mt-24 lg:max-w-none">
|
<div className="mx-auto mt-16 max-w-2xl sm:mt-20 lg:mt-24 lg:max-w-none">
|
||||||
<dl className="grid max-w-xl grid-cols-1 gap-x-8 gap-y-16 lg:max-w-none md:grid-cols-2 lg:grid-cols-4">
|
<dl className="grid max-w-xl grid-cols-1 gap-x-8 gap-y-16 lg:max-w-none md:grid-cols-2 lg:grid-cols-4">
|
||||||
{features.map((feature) => (
|
{features.map((feature) => (
|
||||||
<div
|
<div
|
||||||
key={feature.name}
|
key={feature.name}
|
||||||
className="flex flex-col rounded-lg border border-gray-200 p-8 shadow-sm transition-all duration-300 ease-in-out hover:bg-gray-50 hover:shadow-md hover:scale-105"
|
className="flex flex-col rounded-lg border border-gray-200 p-8 shadow-sm transition-all duration-300 ease-in-out hover:scale-105 hover:border-cyan-500 hover:shadow-lg hover:shadow-cyan-500/20"
|
||||||
>
|
>
|
||||||
<dt className="text-base/7 font-semibold text-gray-900">
|
<DownloadCardTitle color="primary">
|
||||||
<div className="mb-6 flex h-10 w-10 items-center justify-center">
|
<div className="mb-6 flex h-10 w-10 items-center justify-center">
|
||||||
<Image src={feature.icon} alt="" className="h-10 w-10" />
|
<Image src={feature.icon} alt="" className="h-10 w-10" />
|
||||||
</div>
|
</div>
|
||||||
{feature.name}
|
{feature.name}
|
||||||
</dt>
|
</DownloadCardTitle>
|
||||||
<dd className="mt-1 flex flex-auto flex-col text-base/7 text-gray-600">
|
<DownloadCardDescription
|
||||||
|
as="dd"
|
||||||
|
color="secondary"
|
||||||
|
className="mt-1 flex flex-auto flex-col"
|
||||||
|
>
|
||||||
<p className="flex-auto">{feature.description}</p>
|
<p className="flex-auto">{feature.description}</p>
|
||||||
<p className="mt-6">
|
<p className="mt-6">
|
||||||
<a href={feature.href} className="text-sm/6 font-semibold text-cyan-500 hover:text-cyan-500">
|
<a
|
||||||
|
href={feature.href}
|
||||||
|
className="text-sm/6 font-semibold text-cyan-500 hover:text-cyan-500"
|
||||||
|
>
|
||||||
Download Now <span aria-hidden="true">→</span>
|
Download Now <span aria-hidden="true">→</span>
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</dd>
|
</DownloadCardDescription>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</dl>
|
</dl>
|
||||||
|
|||||||
@@ -4,10 +4,8 @@ import { ArrowDownTrayIcon } from '@heroicons/react/24/solid'
|
|||||||
export function DownloadLink() {
|
export function DownloadLink() {
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
href="https://github.com/threefoldtech/mycelium/releases"
|
href="/download"
|
||||||
aria-label="Download Mycelium"
|
aria-label="Download Mycelium"
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="inline-flex items-center rounded-lg bg-cyan-500 px-4 py-2 text-sm font-semibold text-white hover:bg-cyan-600 transition-colors"
|
className="inline-flex items-center rounded-lg bg-cyan-500 px-4 py-2 text-sm font-semibold text-white hover:bg-cyan-600 transition-colors"
|
||||||
>
|
>
|
||||||
<ArrowDownTrayIcon className="h-5 w-5 mr-2" />
|
<ArrowDownTrayIcon className="h-5 w-5 mr-2" />
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Container } from '@/components/Container'
|
import { Container } from '@/components/Container'
|
||||||
|
import { Answer, P, Question, SectionHeader } from './Texts'
|
||||||
|
|
||||||
const faqs = [
|
const faqs = [
|
||||||
[
|
[
|
||||||
@@ -58,22 +59,19 @@ export function Faqs() {
|
|||||||
>
|
>
|
||||||
<Container>
|
<Container>
|
||||||
<div className="mx-auto max-w-2xl lg:mx-0">
|
<div className="mx-auto max-w-2xl lg:mx-0">
|
||||||
<h2
|
<SectionHeader id="faqs-title" as="h2">
|
||||||
id="faqs-title"
|
|
||||||
className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900"
|
|
||||||
>
|
|
||||||
Frequently asked questions
|
Frequently asked questions
|
||||||
</h2>
|
</SectionHeader>
|
||||||
<p className="mt-2 text-lg text-gray-600">
|
<P color="secondary" className="mt-2">
|
||||||
If you have anything else you want to ask,{' '}
|
If you have anything else you want to ask,{' '}
|
||||||
<a
|
<a
|
||||||
href="https://t.me/threefold"
|
href="https://threefoldfaq.crisp.help/en/"
|
||||||
className="text-gray-900 underline"
|
className="text-gray-900 hover:text-cyan-500 transition-colors font-semibold underline"
|
||||||
>
|
>
|
||||||
reach out to us
|
reach out to us
|
||||||
</a>
|
</a>
|
||||||
.
|
.
|
||||||
</p>
|
</P>
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
role="list"
|
role="list"
|
||||||
@@ -84,10 +82,8 @@ export function Faqs() {
|
|||||||
<ul role="list" className="space-y-10">
|
<ul role="list" className="space-y-10">
|
||||||
{column.map((faq, faqIndex) => (
|
{column.map((faq, faqIndex) => (
|
||||||
<li key={faqIndex}>
|
<li key={faqIndex}>
|
||||||
<h3 className="text-lg/6 font-semibold text-gray-900">
|
<Question color="primary">{faq.question}</Question>
|
||||||
{faq.question}
|
<Answer color="tertiary">{faq.answer}</Answer>
|
||||||
</h3>
|
|
||||||
<p className="mt-4 text-sm text-gray-700">{faq.answer}</p>
|
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,109 +1,96 @@
|
|||||||
|
import { CardDescription, CardEyebrow, CardTitle, Eyebrow, P, SectionHeader } from '@/components/Texts'
|
||||||
import Pathfinding from '@/components/Pathfinding'
|
import Pathfinding from '@/components/Pathfinding'
|
||||||
import MessageBus from '@/components/MessageBus'
|
import MessageBus from '@/components/MessageBus'
|
||||||
import ProxyDetection from '@/components/ProxyDetection'
|
import ProxyDetection from '@/components/ProxyDetection'
|
||||||
import ProxyForwarding from '@/components/ProxyForwarding'
|
import ProxyForwarding from '@/components/ProxyForwarding'
|
||||||
import ContentDistribution from '@/components/ContentDistribution'
|
import ContentDistribution from '@/components/ContentDistribution'
|
||||||
|
|
||||||
|
const eyebrow = 'Core Components'
|
||||||
|
const sectionHeader = 'Network Capabilities'
|
||||||
|
const description1 = 'Built for resilience and autonomy, the Mycelium Network dynamically connects nodes through intelligent routing, proxy discovery, and decentralized delivery.'
|
||||||
|
const description2 = 'Each component — from message passing to content distribution — works in harmony to create a fully self-healing, self-optimizing data mesh.'
|
||||||
|
|
||||||
|
const cards = [
|
||||||
|
{
|
||||||
|
eyebrow: 'Routing',
|
||||||
|
title: 'Automatic pathfinding',
|
||||||
|
description: 'The Mycelium Network automatically discovers the shortest and fastest routes between nodes, ensuring optimal data flow and network efficiency without manual configuration.',
|
||||||
|
component: <Pathfinding />,
|
||||||
|
className: 'lg:col-span-3',
|
||||||
|
roundedClassName: 'max-lg:rounded-t-4xl lg:rounded-tl-4xl',
|
||||||
|
roundedInnerClassName: 'max-lg:rounded-t-[calc(2rem+1px)] lg:rounded-tl-[calc(2rem+1px)]'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
eyebrow: 'Communication',
|
||||||
|
title: 'Distributed message bus',
|
||||||
|
description: 'Acts as a global message layer that lets nodes exchange information seamlessly. Enables resilient, asynchronous communication across the entire decentralized mesh.',
|
||||||
|
component: <MessageBus />,
|
||||||
|
className: 'lg:col-span-3',
|
||||||
|
roundedClassName: 'lg:rounded-tr-4xl',
|
||||||
|
roundedInnerClassName: 'lg:rounded-tr-[calc(2rem+1px)]'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
eyebrow: 'Discovery',
|
||||||
|
title: 'Automatic proxy detection',
|
||||||
|
description: 'The system continuously scans for open SOCKS5 proxies within the network, making it effortless to find available connection points without manual setup.',
|
||||||
|
component: <ProxyDetection className="h-80" />,
|
||||||
|
className: 'lg:col-span-2',
|
||||||
|
roundedClassName: 'lg:rounded-bl-4xl',
|
||||||
|
roundedInnerClassName: 'lg:rounded-bl-[calc(2rem+1px)]'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
eyebrow: 'Connectivity',
|
||||||
|
title: 'Seamless proxy forwarding',
|
||||||
|
description: 'Local SOCKS5 connections can be forwarded through nearby nodes or remote proxies. When browsers use the local proxy, traffic moves securely through the mesh—like a built-in VPN.',
|
||||||
|
component: <ProxyForwarding className="h-80" />,
|
||||||
|
className: 'lg:col-span-2',
|
||||||
|
roundedClassName: '',
|
||||||
|
roundedInnerClassName: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
eyebrow: 'Delivery',
|
||||||
|
title: 'Decentralized content distribution',
|
||||||
|
description: 'Mycelium can serve data from distributed 0-DBs, creating a CDN-like layer that delivers content faster and more reliably—without relying on centralized servers.',
|
||||||
|
component: <ContentDistribution className="h-80" />,
|
||||||
|
className: 'lg:col-span-2',
|
||||||
|
roundedClassName: 'max-lg:rounded-b-4xl lg:rounded-br-4xl',
|
||||||
|
roundedInnerClassName: 'max-lg:rounded-b-[calc(2rem+1px)] lg:rounded-br-[calc(2rem+1px)]'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
export function Features() {
|
export function Features() {
|
||||||
return (
|
return (
|
||||||
<section id="features" className=" py-24">
|
<section id="features" className="py-24">
|
||||||
<div className="mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-8">
|
<div className="mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-8">
|
||||||
<h2 className="text-base/7 font-semibold text-cyan-500">Core Components</h2>
|
<Eyebrow color="accent">{eyebrow}</Eyebrow>
|
||||||
<p className="mt-2 max-w-4xl text-3xl lg:text-4xl font-medium tracking-tight text-pretty text-gray-950">
|
<SectionHeader color="dark" className="mt-2 max-w-2xl text-pretty">
|
||||||
Network Capabilities
|
{sectionHeader}
|
||||||
</p>
|
</SectionHeader>
|
||||||
<p className="mt-4 max-w-xl text-lg text-gray-600">
|
<P color="secondary" className="mt-4 max-w-4xl text-black">
|
||||||
Built for resilience and autonomy, the Mycelium Network dynamically connects nodes through intelligent routing, proxy discovery, and decentralized delivery.
|
{description1}
|
||||||
</p>
|
</P>
|
||||||
<p className="mt-2 max-w-xl text-lg text-gray-600">
|
<P color="secondary" className="mt-2 max-w-4xl">
|
||||||
Each component — from message passing to content distribution — works in harmony to create a fully self-healing, self-optimizing data mesh.
|
{description2}
|
||||||
</p>
|
</P>
|
||||||
<div className="mt-10 grid grid-cols-1 gap-x-4 gap-y-8 sm:mt-16 lg:grid-cols-6 lg:grid-rows-2">
|
<div className="mt-10 grid grid-cols-1 gap-x-4 gap-y-8 sm:mt-16 lg:grid-cols-6 lg:grid-rows-2">
|
||||||
<div className="relative lg:col-span-3 transition-all duration-300 ease-in-out hover:scale-105">
|
{cards.map((card, index) => (
|
||||||
<div className="absolute inset-0 rounded-lg bg-white max-lg:rounded-t-4xl lg:rounded-tl-4xl" />
|
<div key={index} className={`group relative ${card.className} transition-all duration-300 ease-in-out hover:scale-105`}>
|
||||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] max-lg:rounded-t-[calc(2rem+1px)] lg:rounded-tl-[calc(2rem+1px)]">
|
<div className={`absolute inset-0 rounded-lg bg-transparent ${card.roundedClassName}`} />
|
||||||
<Pathfinding />
|
<div className={`flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] ${card.roundedInnerClassName}`}>
|
||||||
<div className="p-10 pt-4">
|
{card.component}
|
||||||
<h3 className="text-sm/4 font-semibold text-cyan-500">Routing</h3>
|
<div className="p-10 pt-4">
|
||||||
<p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
|
<CardEyebrow color="accent">{card.eyebrow}</CardEyebrow>
|
||||||
Automatic pathfinding
|
<CardTitle color="dark" className="mt-2">
|
||||||
</p>
|
{card.title}
|
||||||
<p className="mt-2 max-w-lg text-sm/6 text-gray-600">
|
</CardTitle>
|
||||||
The Mycelium Network automatically discovers the shortest and fastest routes between nodes,
|
<CardDescription color="secondary" className="mt-2 max-w-lg">
|
||||||
ensuring optimal data flow and network efficiency without manual configuration.
|
{card.description}
|
||||||
</p>
|
</CardDescription>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={`pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5 group-hover:outline-cyan-500 group-hover:shadow-lg group-hover:shadow-cyan-500/20 ${card.roundedClassName}`} />
|
||||||
</div>
|
</div>
|
||||||
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5 max-lg:rounded-t-4xl lg:rounded-tl-4xl" />
|
))}
|
||||||
</div>
|
|
||||||
<div className="relative lg:col-span-3 transition-all duration-300 ease-in-out hover:scale-105">
|
|
||||||
<div className="absolute inset-0 rounded-lg bg-white lg:rounded-tr-4xl" />
|
|
||||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] lg:rounded-tr-[calc(2rem+1px)]">
|
|
||||||
<MessageBus />
|
|
||||||
<div className="p-10 pt-4">
|
|
||||||
<h3 className="text-sm/4 font-semibold text-cyan-500">Communication</h3>
|
|
||||||
<p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
|
|
||||||
Distributed message bus
|
|
||||||
</p>
|
|
||||||
<p className="mt-2 max-w-lg text-sm/6 text-gray-600">
|
|
||||||
Acts as a global message layer that lets nodes exchange information seamlessly.
|
|
||||||
Enables resilient, asynchronous communication across the entire decentralized mesh.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5 lg:rounded-tr-4xl" />
|
|
||||||
</div>
|
|
||||||
<div className="relative lg:col-span-2 transition-all duration-300 ease-in-out hover:scale-105">
|
|
||||||
<div className="absolute inset-0 rounded-lg bg-white lg:rounded-bl-4xl" />
|
|
||||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] lg:rounded-bl-[calc(2rem+1px)]">
|
|
||||||
<ProxyDetection className="h-80" />
|
|
||||||
<div className="p-10 pt-4">
|
|
||||||
<h3 className="text-sm/4 font-semibold text-cyan-500">Discovery</h3>
|
|
||||||
<p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
|
|
||||||
Automatic proxy detection
|
|
||||||
</p>
|
|
||||||
<p className="mt-2 max-w-lg text-sm/6 text-gray-600">
|
|
||||||
The system continuously scans for open SOCKS5 proxies within the network,
|
|
||||||
making it effortless to find available connection points without manual setup.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5 lg:rounded-bl-4xl" />
|
|
||||||
</div>
|
|
||||||
<div className="relative lg:col-span-2 transition-all duration-300 ease-in-out hover:scale-105">
|
|
||||||
<div className="absolute inset-0 rounded-lg bg-white" />
|
|
||||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)]">
|
|
||||||
<ProxyForwarding className="h-80" />
|
|
||||||
<div className="p-10 pt-4">
|
|
||||||
<h3 className="text-sm/4 font-semibold text-cyan-500">Connectivity</h3>
|
|
||||||
<p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
|
|
||||||
Seamless proxy forwarding
|
|
||||||
</p>
|
|
||||||
<p className="mt-2 max-w-lg text-sm/6 text-gray-600">
|
|
||||||
Local SOCKS5 connections can be forwarded through nearby nodes or remote proxies.
|
|
||||||
When browsers use the local proxy, traffic moves securely through the mesh—like a built-in VPN.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5" />
|
|
||||||
</div>
|
|
||||||
<div className="relative lg:col-span-2 transition-all duration-300 ease-in-out hover:scale-105">
|
|
||||||
<div className="absolute inset-0 rounded-lg bg-white max-lg:rounded-b-4xl lg:rounded-br-4xl" />
|
|
||||||
<div className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] max-lg:rounded-b-[calc(2rem+1px)] lg:rounded-br-[calc(2rem+1px)]">
|
|
||||||
<ContentDistribution className="h-80" />
|
|
||||||
<div className="p-10 pt-4">
|
|
||||||
<h3 className="text-sm/4 font-semibold text-cyan-500">Delivery</h3>
|
|
||||||
<p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
|
|
||||||
Decentralized content distribution
|
|
||||||
</p>
|
|
||||||
<p className="mt-2 max-w-lg text-sm/6 text-gray-600">
|
|
||||||
Mycelium can serve data from distributed 0-DBs, creating a CDN-like layer that delivers
|
|
||||||
content faster and more reliably—without relying on centralized servers.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="pointer-events-none absolute inset-0 rounded-lg shadow-sm outline outline-black/5 max-lg:rounded-b-4xl lg:rounded-br-4xl" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,26 +1,66 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
import { Button } from '@/components/Button'
|
import { Button } from '@/components/Button'
|
||||||
import { Container } from '@/components/Container'
|
import { Container } from '@/components/Container'
|
||||||
import { TextField } from '@/components/Fields'
|
import { TextField } from '@/components/Fields'
|
||||||
import { NavLinks } from '@/components/NavLinks'
|
import { NavLinks } from '@/components/NavLinks'
|
||||||
import github from '@/images/github.svg'
|
import github from '@/images/github.svg'
|
||||||
|
import logomark from '@/images/logomark.svg'
|
||||||
|
|
||||||
export function Footer() {
|
export function Footer() {
|
||||||
|
const [email, setEmail] = useState('');
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [success, setSuccess] = useState(false);
|
||||||
|
const [message, setMessage] = useState('');
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setLoading(true);
|
||||||
|
setSuccess(false);
|
||||||
|
setMessage('');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/subscribe', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ email }),
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(data.error || 'Something went wrong');
|
||||||
|
}
|
||||||
|
|
||||||
|
setSuccess(true);
|
||||||
|
setMessage('Thanks for subscribing!');
|
||||||
|
setEmail('');
|
||||||
|
} catch (error: any) {
|
||||||
|
setMessage(error.message);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className="border-t border-gray-200">
|
<footer className="border-t border-gray-200">
|
||||||
<Container>
|
<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-8">
|
<div className="flex flex-col items-start justify-between gap-y-12 pt-16 pb-6 lg:flex-row lg:items-center lg:py-8">
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center text-gray-900">
|
<div className="flex items-center text-gray-900">
|
||||||
<Image src="/images/logo.svg" alt="Mycelium Logomark" width={60} height={60} className="h-20 w-20 flex-none" />
|
<Image src={logomark} alt="Mycelium Logomark" width={60} height={60} className="h-20 w-20 flex-none" />
|
||||||
<div className="ml-4">
|
<div className="ml-4">
|
||||||
<p className="text-base font-semibold">Mycelium</p>
|
<p className="text-base font-semibold">Mycelium</p>
|
||||||
<p className="mt-1 text-sm">Unleash the Power of Decentralized Networks</p>
|
<p className="mt-1 text-sm">Unleash the Power of Decentralized Networks</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<nav className="mt-11 flex gap-8">
|
<nav className="mt-10 flex gap-8">
|
||||||
<NavLinks />
|
<NavLinks />
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
@@ -42,22 +82,35 @@ export function Footer() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col items-center border-t border-gray-200 pt-8 pb-12 md:flex-row-reverse md:justify-between md:pt-6">
|
<div className="flex flex-col items-center border-t border-gray-200 pt-8 pb-12 md:flex-row-reverse md:justify-between md:pt-6">
|
||||||
<form className="flex w-full justify-center md:w-auto">
|
<div>
|
||||||
<TextField
|
<form className="flex w-full justify-center md:w-auto" onSubmit={handleSubmit}>
|
||||||
type="email"
|
<TextField
|
||||||
aria-label="Email address"
|
type="email"
|
||||||
placeholder="Email address"
|
aria-label="Email address"
|
||||||
autoComplete="email"
|
placeholder="Email address"
|
||||||
required
|
autoComplete="email"
|
||||||
className="w-60 min-w-0 shrink"
|
required
|
||||||
/>
|
className="w-60 min-w-0 shrink"
|
||||||
<Button type="submit" color="cyan" className="ml-4 flex-none">
|
value={email}
|
||||||
<span className="hidden lg:inline">Join our newsletter</span>
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
<span className="lg:hidden">Join newsletter</span>
|
/>
|
||||||
</Button>
|
<Button
|
||||||
</form>
|
type="submit"
|
||||||
|
color={success ? 'green' : 'cyan'}
|
||||||
|
className="ml-4 flex-none"
|
||||||
|
disabled={loading || success}
|
||||||
|
>
|
||||||
|
{loading ? 'Joining...' : success ? 'Sent!' : <><span className="hidden lg:inline">Join our newsletter</span><span className="lg:hidden">Join newsletter</span></>}
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
{message && <p className="mt-2 text-sm text-gray-600">{message}</p>}
|
||||||
|
</div>
|
||||||
<p className="mt-6 text-sm text-gray-500 md:mt-0">
|
<p className="mt-6 text-sm text-gray-500 md:mt-0">
|
||||||
© Copyright ThreeFold {new Date().getFullYear()}. All rights reserved.
|
© Copyright{' '}
|
||||||
|
<a href="https://www.threefold.io" target="_blank" rel="noopener noreferrer" className="hover:text-cyan-500 transition-colors">
|
||||||
|
ThreeFold
|
||||||
|
</a>{' '}
|
||||||
|
{new Date().getFullYear()}. All rights reserved.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import Image from 'next/image'
|
|||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
|
|
||||||
import { DownloadLink } from '@/components/DownloadLink'
|
import { DownloadLink } from '@/components/DownloadLink'
|
||||||
|
import { H1, H2, H3, H4, H5, P } from '@/components/Texts'
|
||||||
import { Button } from '@/components/Button'
|
import { Button } from '@/components/Button'
|
||||||
import phoneFrame from '@/images/phoneframe.png'
|
import phoneFrame from '@/images/phoneframe.png'
|
||||||
import { Container } from '@/components/Container'
|
import { Container } from '@/components/Container'
|
||||||
@@ -103,27 +104,26 @@ export function Hero() {
|
|||||||
<Container>
|
<Container>
|
||||||
<div className="flex flex-col-reverse gap-y-16 lg:grid lg:grid-cols-12 lg:gap-x-8 lg:gap-y-20">
|
<div className="flex flex-col-reverse gap-y-16 lg:grid lg:grid-cols-12 lg:gap-x-8 lg:gap-y-20">
|
||||||
<div className="relative z-10 mx-auto max-w-2xl lg:col-span-7 lg:max-w-none lg:pt-6 xl:col-span-6">
|
<div className="relative z-10 mx-auto max-w-2xl lg:col-span-7 lg:max-w-none lg:pt-6 xl:col-span-6">
|
||||||
<h1 className="text-4xl lg:text-6xl font-medium tracking-tight text-gray-900">
|
<H1>Mycelium</H1>
|
||||||
Mycelium
|
<H5 color="secondary" className="mt-6">
|
||||||
</h1>
|
Unleashing the Power of Decentralized Networks
|
||||||
<h2 className="mt-6 lg:text-2xl text-xl tracking-tight leading-normal text-gray-600">
|
</H5>
|
||||||
Unleashing the Power of Decentralized Networks
|
<P color="secondary" className="mt-6">
|
||||||
</h2>
|
Discover Mycelium, an end-to-end encrypted IPv6 overlay network. The
|
||||||
<p className="mt-6 lg:text-xl text-lg text-gray-600 lg:leading-normal leading-tight">
|
future of secure, efficient, and scalable networking.
|
||||||
Discover Mycelium, an end-to-end encrypted IPv6 overlay network. The future of secure, efficient, and scalable networking.
|
</P>
|
||||||
</p>
|
<P color="secondary" className="mt-6">
|
||||||
<p className="mt-6 text-lg text-gray-600 ">
|
|
||||||
Coming Soon: New Decentralized Features
|
Coming Soon: New Decentralized Features
|
||||||
</p>
|
</P>
|
||||||
<div className="mt-8 flex flex-wrap gap-x-6 gap-y-4">
|
<div className="mt-8 flex flex-wrap gap-x-6 gap-y-4">
|
||||||
<DownloadLink />
|
<DownloadLink />
|
||||||
<Button
|
{/* <Button
|
||||||
href="https://youtu.be/4oq15lxvkts?si=Heh_8DHqHaNpy3_F"
|
href="https://youtu.be/4oq15lxvkts?si=Heh_8DHqHaNpy3_F"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
>
|
>
|
||||||
<PlayIcon className="h-6 w-6 flex-none" />
|
<PlayIcon className="h-6 w-6 flex-none" />
|
||||||
<span className="ml-2.5">Watch the Demo</span>
|
<span className="ml-2.5">Watch the Demo</span>
|
||||||
</Button>
|
</Button> */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative lg:mt-10 mt-0 lg:col-span-5 lg:row-span-2 xl:col-span-6">
|
<div className="relative lg:mt-10 mt-0 lg:col-span-5 lg:row-span-2 xl:col-span-6">
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export function LinuxLink({
|
|||||||
href="https://github.com/threefoldtech/mycelium/releases"
|
href="https://github.com/threefoldtech/mycelium/releases"
|
||||||
aria-label="Download for Linux"
|
aria-label="Download for Linux"
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'flex items-center rounded-lg transition-colors px-4 py-2',
|
'flex items-center rounded-lg px-4 py-2 transition-all hover:scale-105',
|
||||||
color === 'black'
|
color === 'black'
|
||||||
? 'bg-gray-800 text-white hover:bg-gray-900'
|
? 'bg-gray-800 text-white hover:bg-gray-900'
|
||||||
: 'bg-white text-gray-900 hover:bg-gray-50',
|
: 'bg-white text-gray-900 hover:bg-gray-50',
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { motion, useReducedMotion } from 'framer-motion';
|
import { motion, useReducedMotion } from 'framer-motion';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
className?: string; // e.g. "w-full h-72"
|
className?: string; // e.g. "w-full h-72"
|
||||||
@@ -72,7 +73,12 @@ export default function MessageBus({ className, bg = '#ffffff' }: Props) {
|
|||||||
const H = 460;
|
const H = 460;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className} aria-hidden="true" role="img" style={{ background: bg }}>
|
<div
|
||||||
|
className={clsx('relative overflow-hidden', className)}
|
||||||
|
aria-hidden="true"
|
||||||
|
role="img"
|
||||||
|
style={{ background: bg }}
|
||||||
|
>
|
||||||
<svg viewBox={`0 0 ${W} ${H}`} width="100%" height="100%">
|
<svg viewBox={`0 0 ${W} ${H}`} width="100%" height="100%">
|
||||||
|
|
||||||
{/* subtle grid */}
|
{/* subtle grid */}
|
||||||
|
|||||||
@@ -14,11 +14,12 @@ export function NavLinks() {
|
|||||||
['How it Works', '/#howitworks'],
|
['How it Works', '/#howitworks'],
|
||||||
['Coming Soon', '/#comingsoon'],
|
['Coming Soon', '/#comingsoon'],
|
||||||
['FAQs', '/#faqs'],
|
['FAQs', '/#faqs'],
|
||||||
|
['Docs', 'https://threefold.info/mycelium_network/docs/'],
|
||||||
].map(([label, href], index) => (
|
].map(([label, href], index) => (
|
||||||
<Link
|
<Link
|
||||||
key={label}
|
key={label}
|
||||||
href={href}
|
href={href}
|
||||||
className="relative -mx-3 -my-2 rounded-lg px-3 py-2 text-sm text-gray-700 transition-colors delay-150 hover:text-gray-900 hover:delay-0"
|
className="relative -mx-3 -my-2 rounded-lg px-3 py-2 text-sm leading-tight text-gray-700 transition-colors delay-150 hover:text-gray-900 hover:delay-0"
|
||||||
onMouseEnter={() => {
|
onMouseEnter={() => {
|
||||||
if (timeoutRef.current) {
|
if (timeoutRef.current) {
|
||||||
window.clearTimeout(timeoutRef.current)
|
window.clearTimeout(timeoutRef.current)
|
||||||
@@ -31,13 +32,17 @@ export function NavLinks() {
|
|||||||
}, 50)
|
}, 50)
|
||||||
}}
|
}}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault()
|
if (href.startsWith('/#')) {
|
||||||
const targetId = href.substring(2)
|
e.preventDefault();
|
||||||
const targetElement = document.getElementById(targetId)
|
const targetId = href.substring(2);
|
||||||
if (targetElement) {
|
const targetElement = document.getElementById(targetId);
|
||||||
targetElement.scrollIntoView({ behavior: 'smooth' })
|
if (targetElement) {
|
||||||
|
targetElement.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
target={href.startsWith('http') ? '_blank' : undefined}
|
||||||
|
rel={href.startsWith('http') ? 'noopener noreferrer' : undefined}
|
||||||
>
|
>
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{hoveredIndex === index && (
|
{hoveredIndex === index && (
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
|
|
||||||
|
import phoneFrame from '@/images/phone-frame.svg'
|
||||||
|
|
||||||
export function PhoneFrame({
|
export function PhoneFrame({
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
@@ -10,7 +12,7 @@ export function PhoneFrame({
|
|||||||
return (
|
return (
|
||||||
<div className={clsx('relative aspect-[366/729]', className)} {...props}>
|
<div className={clsx('relative aspect-[366/729]', className)} {...props}>
|
||||||
<Image
|
<Image
|
||||||
src="/images/phone-frame.svg"
|
src={phoneFrame}
|
||||||
alt=""
|
alt=""
|
||||||
className="pointer-events-none absolute inset-0"
|
className="pointer-events-none absolute inset-0"
|
||||||
fill
|
fill
|
||||||
|
|||||||
@@ -13,6 +13,14 @@ import {
|
|||||||
import { useDebouncedCallback } from 'use-debounce'
|
import { useDebouncedCallback } from 'use-debounce'
|
||||||
|
|
||||||
import { AppScreen } from '@/components/AppScreen'
|
import { AppScreen } from '@/components/AppScreen'
|
||||||
|
import {
|
||||||
|
Eyebrow,
|
||||||
|
FeatureDescription,
|
||||||
|
FeatureTitle,
|
||||||
|
MobileFeatureTitle,
|
||||||
|
P,
|
||||||
|
SectionHeader,
|
||||||
|
} from '@/components/Texts'
|
||||||
import { CircleBackground } from '@/components/CircleBackground'
|
import { CircleBackground } from '@/components/CircleBackground'
|
||||||
import { Container } from '@/components/Container'
|
import { Container } from '@/components/Container'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
@@ -251,11 +259,16 @@ function FeaturesDesktop() {
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
vertical
|
vertical
|
||||||
>
|
>
|
||||||
<TabList className="relative z-10 order-last col-span-6 space-y-6">
|
<TabList className="z-10 order-last col-span-6 space-y-6">
|
||||||
{features.map((feature, featureIndex) => (
|
{features.map((feature, featureIndex) => (
|
||||||
<div
|
<div
|
||||||
key={feature.name}
|
key={feature.name}
|
||||||
className="relative rounded-2xl transition-all duration-300 ease-in-out hover:scale-105 hover:bg-gray-800/30"
|
className={clsx(
|
||||||
|
'relative rounded-2xl outline-2 transition-all duration-300 ease-in-out hover:scale-105 hover:bg-gray-800/30',
|
||||||
|
selectedIndex === featureIndex
|
||||||
|
? 'outline-cyan-500'
|
||||||
|
: 'outline-transparent hover:outline-cyan-500',
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{featureIndex === selectedIndex && (
|
{featureIndex === selectedIndex && (
|
||||||
<motion.div
|
<motion.div
|
||||||
@@ -266,22 +279,22 @@ function FeaturesDesktop() {
|
|||||||
)}
|
)}
|
||||||
<div className="relative z-10 p-8">
|
<div className="relative z-10 p-8">
|
||||||
<feature.icon className="h-8 w-8" />
|
<feature.icon className="h-8 w-8" />
|
||||||
<h3 className="mt-6 text-lg font-semibold text-white">
|
<FeatureTitle as="h3" color="white" className="mt-6">
|
||||||
<Tab className="text-left data-selected:not-data-focus:outline-hidden">
|
<Tab className="text-left data-selected:not-data-focus:outline-hidden">
|
||||||
<span className="absolute inset-0 rounded-2xl" />
|
<span className="absolute inset-0 rounded-2xl" />
|
||||||
{feature.name}
|
{feature.name}
|
||||||
</Tab>
|
</Tab>
|
||||||
</h3>
|
</FeatureTitle>
|
||||||
<p className="mt-2 text-sm text-gray-400">
|
<FeatureDescription color="secondary" className="mt-2">
|
||||||
{feature.description}
|
{feature.description}
|
||||||
</p>
|
</FeatureDescription>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</TabList>
|
</TabList>
|
||||||
<div className="relative col-span-6">
|
<div className="relative col-span-6">
|
||||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||||
<CircleBackground color="#13B5C8" className="animate-spin-slower" />
|
<CircleBackground id="primaryfeatures_desktop_circle" color="#13B5C8" className="animate-spin-slower" />
|
||||||
</div>
|
</div>
|
||||||
<PhoneFrame className="z-10 mx-auto w-full max-w-[366px]">
|
<PhoneFrame className="z-10 mx-auto w-full max-w-[366px]">
|
||||||
<TabPanels as={Fragment}>
|
<TabPanels as={Fragment}>
|
||||||
@@ -355,9 +368,17 @@ function FeaturesMobile() {
|
|||||||
ref={(ref) => ref && (slideRefs.current[featureIndex] = ref)}
|
ref={(ref) => ref && (slideRefs.current[featureIndex] = ref)}
|
||||||
className="w-full flex-none snap-center px-4 sm:px-6 transition-all duration-300 ease-in-out hover:scale-105"
|
className="w-full flex-none snap-center px-4 sm:px-6 transition-all duration-300 ease-in-out hover:scale-105"
|
||||||
>
|
>
|
||||||
<div className="relative transform overflow-hidden rounded-2xl bg-gray-800 px-5 py-6">
|
<div
|
||||||
|
className={clsx(
|
||||||
|
'relative transform overflow-hidden rounded-2xl bg-gray-800 px-5 py-6 outline-2 transition-colors',
|
||||||
|
activeIndex === featureIndex
|
||||||
|
? 'outline-transparent' // Remove outline for active mobile slide
|
||||||
|
: 'outline-transparent hover:outline-cyan-500',
|
||||||
|
)}
|
||||||
|
>
|
||||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||||
<CircleBackground
|
<CircleBackground
|
||||||
|
id={`primaryfeatures_mobile_circle_${featureIndex}`}
|
||||||
color="#13B5C8"
|
color="#13B5C8"
|
||||||
className={featureIndex % 2 === 1 ? 'rotate-180' : undefined}
|
className={featureIndex % 2 === 1 ? 'rotate-180' : undefined}
|
||||||
/>
|
/>
|
||||||
@@ -367,12 +388,12 @@ function FeaturesMobile() {
|
|||||||
</PhoneFrame>
|
</PhoneFrame>
|
||||||
<div className="absolute inset-x-0 bottom-0 bg-gray-800/95 p-6 backdrop-blur-sm sm:p-10">
|
<div className="absolute inset-x-0 bottom-0 bg-gray-800/95 p-6 backdrop-blur-sm sm:p-10">
|
||||||
<feature.icon className="h-8 w-8" />
|
<feature.icon className="h-8 w-8" />
|
||||||
<h3 className="mt-6 text-sm font-semibold text-white sm:text-lg">
|
<MobileFeatureTitle color="white" className="mt-6">
|
||||||
{feature.name}
|
{feature.name}
|
||||||
</h3>
|
</MobileFeatureTitle>
|
||||||
<p className="mt-2 text-sm text-gray-400">
|
<FeatureDescription color="secondary" className="mt-2">
|
||||||
{feature.description}
|
{feature.description}
|
||||||
</p>
|
</FeatureDescription>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -412,13 +433,15 @@ export function PrimaryFeatures() {
|
|||||||
>
|
>
|
||||||
<Container>
|
<Container>
|
||||||
<div className="mx-auto max-w-2xl lg:mx-0 lg:max-w-3xl">
|
<div className="mx-auto max-w-2xl lg:mx-0 lg:max-w-3xl">
|
||||||
<h2 className="text-base/7 font-semibold text-cyan-500">How It Works</h2>
|
<Eyebrow color="accent">How It Works</Eyebrow>
|
||||||
<p className="text-3xl lg:text-4xl font-medium tracking-tight text-white">
|
<SectionHeader color="white" className="mt-2">
|
||||||
How Mycelium Operates
|
How Mycelium Operates
|
||||||
</p>
|
</SectionHeader>
|
||||||
<p className="mt-6 text-lg text-gray-300">
|
<P color="light" className="mt-6">
|
||||||
Mycelium, like its natural namesake, thrives on decentralization, efficiency, and security, making it a truly powerful force in the world of decentralized networks.
|
Mycelium, like its natural namesake, thrives on decentralization,
|
||||||
</p>
|
efficiency, and security, making it a truly powerful force in the world
|
||||||
|
of decentralized networks.
|
||||||
|
</P>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
<div className="mt-16 md:hidden">
|
<div className="mt-16 md:hidden">
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { motion, useReducedMotion } from 'framer-motion';
|
import { motion, useReducedMotion } from 'framer-motion';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
className?: string; // e.g. "w-full h-64"
|
className?: string; // e.g. "w-full h-64"
|
||||||
@@ -160,8 +161,8 @@ export default function ProxyDetection({ className, bg = '#ffffff' }: Props) {
|
|||||||
const delays = [0.8, 0.6, 0.4, 0.2, 0.0];
|
const delays = [0.8, 0.6, 0.4, 0.2, 0.0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={className}
|
className={clsx('relative overflow-hidden', className)}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
role="img"
|
role="img"
|
||||||
style={{ background: bg }}
|
style={{ background: bg }}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { motion, useReducedMotion } from 'framer-motion';
|
import { motion, useReducedMotion } from 'framer-motion';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
className?: string; // e.g. "w-full h-72"
|
className?: string; // e.g. "w-full h-72"
|
||||||
@@ -124,7 +125,12 @@ export default function ProxyForwarding({ className, bg = '#ffffff' }: Props) {
|
|||||||
const DEST = { x: 860, y: 210 };
|
const DEST = { x: 860, y: 210 };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className} aria-hidden="true" role="img" style={{ background: bg }}>
|
<div
|
||||||
|
className={clsx('relative overflow-hidden', className)}
|
||||||
|
aria-hidden="true"
|
||||||
|
role="img"
|
||||||
|
style={{ background: bg }}
|
||||||
|
>
|
||||||
<svg viewBox={`0 0 ${W} ${H}`} width="100%" height="100%">
|
<svg viewBox={`0 0 ${W} ${H}`} width="100%" height="100%">
|
||||||
{/* subtle grid bg */}
|
{/* subtle grid bg */}
|
||||||
<defs>
|
<defs>
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
import { useId } from 'react'
|
import { useId } from 'react'
|
||||||
|
import {
|
||||||
|
Eyebrow,
|
||||||
|
FeatureDescription,
|
||||||
|
P,
|
||||||
|
SectionHeader,
|
||||||
|
SecondaryFeatureTitle,
|
||||||
|
} from './Texts'
|
||||||
|
|
||||||
import { Container } from '@/components/Container'
|
import { Container } from '@/components/Container'
|
||||||
|
|
||||||
@@ -195,13 +202,16 @@ export function SecondaryFeatures() {
|
|||||||
>
|
>
|
||||||
<Container>
|
<Container>
|
||||||
<div className="mx-auto max-w-4xl sm:text-center">
|
<div className="mx-auto max-w-4xl sm:text-center">
|
||||||
<h2 className="text-base/7 font-semibold text-cyan-500">Roadmap</h2>
|
<Eyebrow color="accent">Roadmap</Eyebrow>
|
||||||
<p className="text-3xl lg:text-4xl font-medium tracking-tight text-gray-900">
|
<SectionHeader as="h2" className="mt-2">
|
||||||
Coming Soon: The Future of Mycelium
|
Coming Soon: The Future of Mycelium
|
||||||
</p>
|
</SectionHeader>
|
||||||
<p className="mt-6 text-lg text-gray-600">
|
<P color="secondary" className="mt-6">
|
||||||
Mycelium 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.
|
Mycelium is evolving to bring even more powerful decentralized
|
||||||
</p>
|
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>
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
role="list"
|
role="list"
|
||||||
@@ -210,13 +220,15 @@ export function SecondaryFeatures() {
|
|||||||
{features.map((feature) => (
|
{features.map((feature) => (
|
||||||
<li
|
<li
|
||||||
key={feature.name}
|
key={feature.name}
|
||||||
className="rounded-2xl border border-gray-200 p-8 transition-all duration-300 ease-in-out hover:scale-105"
|
className="rounded-2xl border border-gray-200 p-8 transition-all duration-300 ease-in-out hover:scale-105 hover:border-cyan-500 hover:shadow-lg hover:shadow-cyan-500/20"
|
||||||
>
|
>
|
||||||
<feature.icon className="h-8 w-8" />
|
<feature.icon className="h-8 w-8" />
|
||||||
<h3 className="mt-6 font-semibold text-gray-900">
|
<SecondaryFeatureTitle color="primary" className="mt-6">
|
||||||
{feature.name}
|
{feature.name}
|
||||||
</h3>
|
</SecondaryFeatureTitle>
|
||||||
<p className="mt-2 text-gray-700">{feature.description}</p>
|
<FeatureDescription color="tertiary" className="mt-2">
|
||||||
|
{feature.description}
|
||||||
|
</FeatureDescription>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
147
src/components/Texts.tsx
Normal file
147
src/components/Texts.tsx
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import React from 'react'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
const colorVariants = {
|
||||||
|
primary: 'text-gray-900',
|
||||||
|
secondary: 'text-gray-600',
|
||||||
|
light: 'text-gray-50',
|
||||||
|
accent: 'text-cyan-500',
|
||||||
|
white: 'text-white',
|
||||||
|
dark: 'text-gray-950',
|
||||||
|
tertiary: 'text-gray-700',
|
||||||
|
lightSecondary: 'text-gray-300',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
type TextOwnProps = {
|
||||||
|
color?: keyof typeof colorVariants
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Polymorphic helpers
|
||||||
|
type PolymorphicProps<E extends React.ElementType, P> = P & {
|
||||||
|
as?: E
|
||||||
|
} & Omit<React.ComponentPropsWithoutRef<E>, keyof P | 'as'>
|
||||||
|
|
||||||
|
const createTextComponent = <DefaultElement extends React.ElementType>(
|
||||||
|
defaultElement: DefaultElement,
|
||||||
|
defaultClassName: string
|
||||||
|
) => {
|
||||||
|
type Props<E extends React.ElementType = DefaultElement> = PolymorphicProps<
|
||||||
|
E,
|
||||||
|
TextOwnProps
|
||||||
|
>
|
||||||
|
|
||||||
|
function Text<E extends React.ElementType = DefaultElement>({
|
||||||
|
as,
|
||||||
|
color = 'primary',
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: Props<E>) {
|
||||||
|
const Tag = (as || defaultElement) as React.ElementType
|
||||||
|
return (
|
||||||
|
<Tag
|
||||||
|
className={cn(defaultClassName, colorVariants[color], className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Tag>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
;(Text as any).displayName = `Text(${typeof defaultElement === 'string' ? defaultElement : 'Component'
|
||||||
|
})`
|
||||||
|
return Text
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exports based on your tailwind.css and the example
|
||||||
|
export const H1 = createTextComponent(
|
||||||
|
'h1',
|
||||||
|
'text-5xl lg:text-8xl font-medium leading-tight tracking-tight'
|
||||||
|
)
|
||||||
|
export const H2 = createTextComponent(
|
||||||
|
'h2',
|
||||||
|
'text-4xl lg:text-6xl font-medium leading-tight tracking-tight'
|
||||||
|
)
|
||||||
|
export const H3 = createTextComponent(
|
||||||
|
'h3',
|
||||||
|
'text-3xl lg:text-5xl font-medium leading-tight tracking-tight'
|
||||||
|
)
|
||||||
|
export const H4 = createTextComponent(
|
||||||
|
'h4',
|
||||||
|
'text-2xl lg:text-4xl font-medium leading-snug tracking-tight'
|
||||||
|
)
|
||||||
|
export const P = createTextComponent(
|
||||||
|
'p',
|
||||||
|
'text-base lg:text-lg leading-relaxed'
|
||||||
|
)
|
||||||
|
export const Small = createTextComponent(
|
||||||
|
'small',
|
||||||
|
'text-sm font-medium leading-normal tracking-normal'
|
||||||
|
)
|
||||||
|
export const Subtle = createTextComponent(
|
||||||
|
'p',
|
||||||
|
'text-sm leading-normal tracking-normal text-gray-500'
|
||||||
|
)
|
||||||
|
export const H5 = createTextComponent(
|
||||||
|
'h5',
|
||||||
|
'text-xl lg:text-2xl font-semibold leading-snug tracking-tight'
|
||||||
|
)
|
||||||
|
export const Eyebrow = createTextComponent(
|
||||||
|
'h2',
|
||||||
|
'text-base/7 font-semibold tracking-wide'
|
||||||
|
)
|
||||||
|
export const SectionHeader = createTextComponent(
|
||||||
|
'p',
|
||||||
|
'text-3xl lg:text-4xl font-medium leading-tight tracking-tight'
|
||||||
|
)
|
||||||
|
export const CardEyebrow = createTextComponent(
|
||||||
|
'h3',
|
||||||
|
'text-sm/4 font-semibold tracking-wide'
|
||||||
|
)
|
||||||
|
export const CardTitle = createTextComponent(
|
||||||
|
'p',
|
||||||
|
'text-lg font-medium leading-snug tracking-tight'
|
||||||
|
)
|
||||||
|
export const CardDescription = createTextComponent(
|
||||||
|
'p',
|
||||||
|
'text-sm/6 leading-normal tracking-normal'
|
||||||
|
)
|
||||||
|
export const FeatureTitle = createTextComponent(
|
||||||
|
'h3',
|
||||||
|
'text-lg font-semibold leading-snug tracking-tight'
|
||||||
|
)
|
||||||
|
export const FeatureDescription = createTextComponent(
|
||||||
|
'p',
|
||||||
|
'text-sm leading-normal tracking-normal'
|
||||||
|
)
|
||||||
|
export const MobileFeatureTitle = createTextComponent(
|
||||||
|
'h3',
|
||||||
|
'text-sm font-semibold sm:text-lg leading-snug tracking-tight'
|
||||||
|
)
|
||||||
|
export const SecondaryFeatureTitle = createTextComponent(
|
||||||
|
'h3',
|
||||||
|
'text-base font-semibold leading-snug tracking-tight'
|
||||||
|
)
|
||||||
|
export const Question = createTextComponent(
|
||||||
|
'h3',
|
||||||
|
'text-lg/6 font-semibold tracking-tight'
|
||||||
|
)
|
||||||
|
export const Answer = createTextComponent(
|
||||||
|
'p',
|
||||||
|
'mt-4 text-sm leading-normal tracking-normal'
|
||||||
|
)
|
||||||
|
export const PageHeader = createTextComponent(
|
||||||
|
'h2',
|
||||||
|
'text-5xl lg:text-6xl font-medium leading-tight tracking-tight'
|
||||||
|
)
|
||||||
|
export const DownloadCardTitle = createTextComponent(
|
||||||
|
'dt',
|
||||||
|
'text-base/7 font-semibold tracking-wide'
|
||||||
|
)
|
||||||
|
export const DownloadCardDescription = createTextComponent(
|
||||||
|
'dd',
|
||||||
|
'text-base/7 leading-normal tracking-normal'
|
||||||
|
)
|
||||||
@@ -8,10 +8,10 @@ export function WindowsLink({
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
href="#"
|
href="https://github.com/threefoldtech/myceliumflut/releases"
|
||||||
aria-label="Download for Windows"
|
aria-label="Download for Windows"
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'flex items-center rounded-lg transition-colors px-4 py-2',
|
'flex items-center rounded-lg px-4 py-2 transition-all hover:scale-105',
|
||||||
color === 'black'
|
color === 'black'
|
||||||
? 'bg-gray-800 text-white hover:bg-gray-900'
|
? 'bg-gray-800 text-white hover:bg-gray-900'
|
||||||
: 'bg-white text-gray-900 hover:bg-gray-50',
|
: 'bg-white text-gray-900 hover:bg-gray-50',
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 83 KiB |
1
src/images/logomark.svg
Normal file
1
src/images/logomark.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 110 KiB |
6
src/lib/utils.ts
Normal file
6
src/lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { type ClassValue, clsx } from 'clsx'
|
||||||
|
import { twMerge } from 'tailwind-merge'
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user