This commit is contained in:
2025-09-12 14:44:50 +02:00
commit 036bec164c
68 changed files with 9681 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
node_modules

126
CHANGELOG.md Normal file
View File

@@ -0,0 +1,126 @@
# Changelog
## 2025-05-22
- Fix bug with focus styles
## 2025-04-28
- Update template to Tailwind CSS v4.1.4
## 2025-04-10
- Update template to Tailwind CSS v4.1.3
## 2025-03-22
- Update template to Tailwind CSS v4.0.15
## 2025-02-10
- Update template to Tailwind CSS v4.0.6
## 2025-01-23
- Update template to Tailwind CSS v4.0
## 2024-06-21
- Bump Headless UI dependency to v2.1
- Replaced `PopoverOverlay` with `PopoverBackdrop`
## 2024-06-18
- Update `prettier` and `prettier-plugin-tailwindcss` dependencies
- Fix formatting in `PrimaryFeatures` component
## 2024-05-31
- Fix `npm audit` warnings
## 2024-05-07
- Bump Headless UI dependency to v2.0
## 2024-03-27
- Fix page scrolling issues ([#1563](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1563))
## 2024-01-17
- Fix `sharp` dependency issues ([#1549](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1549))
## 2024-01-10
- Update Tailwind CSS, Next.js, Prettier, TypeScript, ESLint, and other dependencies
- Fix types in `Button` component
## 2023-09-07
- Added TypeScript version of template
## 2023-08-15
- Bump Next.js dependency
## 2023-08-12
- Use plain anchor for mailto link ([#1490](https://github.com/tailwindlabs/tailwind-plus-issues/issues/1490))
## 2023-07-31
- Port template to Next.js app router
## 2023-07-18
- Add 404 page
- Sort imports
## 2023-05-16
- Bump Next.js dependency
## 2023-04-11
- Bump Next.js dependency
## 2023-03-29
- Bump Tailwind CSS and Prettier dependencies
- Sort classes
## 2023-03-22
- Bump Headless UI dependency
## 2023-02-02
- Bump Headless UI dependency
## 2022-11-04
- Bump Tailwind CSS and Next.js dependencies
## 2022-09-27
- Update Headless UI, Next.js, and Autoprefixer dependencies
## 2022-09-09
- Update Next.js dependency
## 2022-09-07
- Update Headless UI dependency
## 2022-09-01
- Update Tailwind CSS, Next.js, Headless UI, ESLint, and other dependencies
## 2022-08-16
- Enable experimental Next.js `scrollRestoration` flag
## 2022-08-12
- Initial release

129
LICENSE.md Normal file
View File

@@ -0,0 +1,129 @@
# Tailwind Plus License
## Personal License
Tailwind Labs Inc. grants you an on-going, non-exclusive license to use the Components and Templates.
The license grants permission to **one individual** (the Licensee) to access and use the Components and Templates.
You **can**:
- Use the Components and Templates to create unlimited End Products.
- Modify the Components and Templates to create derivative components and templates. Those components and templates are subject to this license.
- Use the Components and Templates to create unlimited End Products for unlimited Clients.
- Use the Components and Templates to create End Products where the End Product is sold to End Users.
- Use the Components and Templates to create End Products that are open source and freely available to End Users.
You **cannot**:
- Use the Components and Templates to create End Products that are designed to allow an End User to build their own End Products using the Components and Templates or derivatives of the Components and Templates.
- Re-distribute the Components and Templates or derivatives of the Components and Templates separately from an End Product, neither in code or as design assets.
- Share your access to the Components and Templates with any other individuals.
- Use the Components and Templates to produce anything that may be deemed by Tailwind Labs Inc, in their sole and absolute discretion, to be competitive or in conflict with the business of Tailwind Labs Inc.
### Example usage
Examples of usage **allowed** by the license:
- Creating a personal website by yourself.
- Creating a website or web application for a client that will be owned by that client.
- Creating a commercial SaaS application (like an invoicing app for example) where end users have to pay a fee to use the application.
- Creating a commercial self-hosted web application that is sold to end users for a one-time fee.
- Creating a web application where the primary purpose is clearly not to simply re-distribute the components (like a conference organization app that uses the components for its UI for example) that is free and open source, where the source code is publicly available.
Examples of usage **not allowed** by the license:
- Creating a repository of your favorite Tailwind Plus components or templates (or derivatives based on Tailwind Plus components or templates) and publishing it publicly.
- Creating a React or Vue version of Tailwind Plus and making it available either for sale or for free.
- Create a Figma or Sketch UI kit based on the Tailwind Plus component designs.
- Creating a "website builder" project where end users can build their own websites using components or templates included with or derived from Tailwind Plus.
- Creating a theme, template, or project starter kit using the components or templates and making it available either for sale or for free.
- Creating an admin panel tool (like [Laravel Nova](https://nova.laravel.com/) or [ActiveAdmin](https://activeadmin.info/)) that is made available either for sale or for free.
In simple terms, use Tailwind Plus for anything you like as long as it doesn't compete with Tailwind Plus.
### Personal License Definitions
Licensee is the individual who has purchased a Personal License.
Components and Templates are the source code and design assets made available to the Licensee after purchasing a Tailwind Plus license.
End Product is any artifact produced that incorporates the Components or Templates or derivatives of the Components or Templates.
End User is a user of an End Product.
Client is an individual or entity receiving custom professional services directly from the Licensee, produced specifically for that individual or entity. Customers of software-as-a-service products are not considered clients for the purpose of this document.
## Team License
Tailwind Labs Inc. grants you an on-going, non-exclusive license to use the Components and Templates.
The license grants permission for **up to 25 Employees and Contractors of the Licensee** to access and use the Components and Templates.
You **can**:
- Use the Components and Templates to create unlimited End Products.
- Modify the Components and Templates to create derivative components and templates. Those components and templates are subject to this license.
- Use the Components and Templates to create unlimited End Products for unlimited Clients.
- Use the Components and Templates to create End Products where the End Product is sold to End Users.
- Use the Components and Templates to create End Products that are open source and freely available to End Users.
You **cannot**:
- Use the Components or Templates to create End Products that are designed to allow an End User to build their own End Products using the Components or Templates or derivatives of the Components or Templates.
- Re-distribute the Components or Templates or derivatives of the Components or Templates separately from an End Product.
- Use the Components or Templates to create End Products that are the property of any individual or entity other than the Licensee or Clients of the Licensee.
- Use the Components or Templates to produce anything that may be deemed by Tailwind Labs Inc, in their sole and absolute discretion, to be competitive or in conflict with the business of Tailwind Labs Inc.
### Example usage
Examples of usage **allowed** by the license:
- Creating a website for your company.
- Creating a website or web application for a client that will be owned by that client.
- Creating a commercial SaaS application (like an invoicing app for example) where end users have to pay a fee to use the application.
- Creating a commercial self-hosted web application that is sold to end users for a one-time fee.
- Creating a web application where the primary purpose is clearly not to simply re-distribute the components or templates (like a conference organization app that uses the components or a template for its UI for example) that is free and open source, where the source code is publicly available.
Examples of use **not allowed** by the license:
- Creating a repository of your favorite Tailwind Plus components or template (or derivatives based on Tailwind Plus components or templates) and publishing it publicly.
- Creating a React or Vue version of Tailwind Plus and making it available either for sale or for free.
- Creating a "website builder" project where end users can build their own websites using components or templates included with or derived from Tailwind Plus.
- Creating a theme or template using the components or templates and making it available either for sale or for free.
- Creating an admin panel tool (like [Laravel Nova](https://nova.laravel.com/) or [ActiveAdmin](https://activeadmin.info/)) that is made available either for sale or for free.
- Creating any End Product that is not the sole property of either your company or a client of your company. For example your employees/contractors can't use your company Tailwind Plus license to build their own websites or side projects.
### Team License Definitions
Licensee is the business entity who has purchased a Team License.
Components and Templates are the source code and design assets made available to the Licensee after purchasing a Tailwind Plus license.
End Product is any artifact produced that incorporates the Components or Templates or derivatives of the Components or Templates.
End User is a user of an End Product.
Employee is a full-time or part-time employee of the Licensee.
Contractor is an individual or business entity contracted to perform services for the Licensee.
Client is an individual or entity receiving custom professional services directly from the Licensee, produced specifically for that individual or entity. Customers of software-as-a-service products are not considered clients for the purpose of this document.
## Enforcement
If you are found to be in violation of the license, access to your Tailwind Plus account will be terminated, and a refund may be issued at our discretion. When license violation is blatant and malicious (such as intentionally redistributing the Components or Templates through private warez channels), no refund will be issued.
The copyright of the Components and Templates is owned by Tailwind Labs Inc. You are granted only the permissions described in this license; all other rights are reserved. Tailwind Labs Inc. reserves the right to pursue legal remedies for any unauthorized use of the Components or Templates outside the scope of this license.
## Liability
Tailwind Labs Inc.s liability to you for costs, damages, or other losses arising from your use of the Components or Templates — including third-party claims against you — is limited to a refund of your license fee. Tailwind Labs Inc. may not be held liable for any consequential damages related to your use of the Components or Templates.
This Agreement is governed by the laws of the Province of Ontario and the applicable laws of Canada. Legal proceedings related to this Agreement may only be brought in the courts of Ontario. You agree to service of process at the e-mail address on your original order.
## Questions?
Unsure which license you need, or unsure if your use case is covered by our licenses?
Email us at [support@tailwindcss.com](mailto:support@tailwindcss.com) with your questions.

35
README.md Normal file
View File

@@ -0,0 +1,35 @@
# Mycelium
Mycelium is a [Tailwind Plus](https://tailwindcss.com/plus) site template built using [Tailwind CSS](https://tailwindcss.com) and [Next.js](https://nextjs.org).
## Getting started
To get started with this template, first install the npm dependencies:
```bash
npm install
```
Next, run the development server:
```bash
npm run dev
```
Finally, open [http://localhost:3000](http://localhost:3000) in your browser to view the website.
## Customizing
You can start editing this template by modifying the files in the `/src` folder. The site will auto-update as you edit these files.
## License
This site template is a commercial product and is licensed under the [Tailwind Plus license](https://tailwindcss.com/plus/license).
## Learn more
To learn more about the technologies used in this site template, see the following resources:
- [Tailwind CSS](https://tailwindcss.com/docs) - the official Tailwind CSS documentation
- [Next.js](https://nextjs.org/docs) - the official Next.js documentation
- [Headless UI](https://headlessui.dev) - the official Headless UI documentation

5
next-env.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

4
next.config.js Normal file
View File

@@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {}
module.exports = nextConfig

5289
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

35
package.json Normal file
View File

@@ -0,0 +1,35 @@
{
"name": "tailwind-plus-pocket",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"browserslist": "defaults, not ie <= 11",
"dependencies": {
"@headlessui/react": "^2.1.0",
"@tailwindcss/forms": "^0.5.3",
"@tailwindcss/postcss": "^4.1.7",
"@types/node": "^20.10.8",
"@types/react": "^18.2.47",
"@types/react-dom": "^18.2.18",
"clsx": "^2.1.0",
"framer-motion": "^10.15.0",
"next": "^14.0.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tailwindcss": "^4.1.7",
"typescript": "^5.3.3",
"use-debounce": "^10.0.0"
},
"devDependencies": {
"eslint": "^8.56.0",
"eslint-config-next": "^14.0.4",
"prettier": "^3.3.2",
"prettier-plugin-tailwindcss": "^0.6.11",
"sharp": "0.33.1"
}
}

5
postcss.config.js Normal file
View File

@@ -0,0 +1,5 @@
module.exports = {
plugins: {
'@tailwindcss/postcss': {},
},
}

7
prettier.config.js Normal file
View File

@@ -0,0 +1,7 @@
/** @type {import('prettier').Options} */
module.exports = {
singleQuote: true,
semi: false,
plugins: ['prettier-plugin-tailwindcss'],
tailwindStylesheet: './src/styles/tailwind.css',
}

View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 50 50">
<defs>
<style>
.cls-1 {
fill: #000;
}
.cls-1, .cls-2, .cls-3 {
stroke-width: 0px;
}
.cls-4 {
clip-path: url(#clippath-2);
}
.cls-2 {
fill: #a6a6a6;
}
.cls-3 {
fill: none;
}
.cls-5 {
clip-path: url(#clippath-1);
}
.cls-6 {
clip-path: url(#clippath-4);
}
.cls-7 {
clip-path: url(#clippath);
}
.cls-8 {
clip-path: url(#clippath-3);
}
</style>
<clipPath id="clippath">
<rect class="cls-3" x="9.6" y="9.5" width="31.3" height="31.3"/>
</clipPath>
<clipPath id="clippath-1">
<rect class="cls-3" x="21.1" y="4.7" width="8.3" height="8.6"/>
</clipPath>
<clipPath id="clippath-2">
<rect class="cls-3" x="21.1" y="36.6" width="8.3" height="8.7"/>
</clipPath>
<clipPath id="clippath-3">
<rect class="cls-3" x="37" y="27.4" width="7.7" height="9.2"/>
</clipPath>
<clipPath id="clippath-4">
<rect class="cls-3" x="37" y="12.4" width="7.7" height="10"/>
</clipPath>
</defs>
<g class="cls-7">
<path class="cls-2" d="M40.5,24.9c0,1-.1,2-.3,3,0,.5-.2,1-.4,1.5-.1.5-.3,1-.5,1.4-.4.9-.9,1.8-1.4,2.7-.6.8-1.2,1.6-1.9,2.3-.4.4-.7.7-1.1,1-.4.3-.8.6-1.2.9-3,2-6.5,2.9-10.1,2.5-.5,0-1-.1-1.5-.2-.5-.1-1-.2-1.5-.4-.5-.1-1-.3-1.4-.5-.9-.4-1.8-.9-2.7-1.4-.4-.3-.8-.6-1.2-.9-.8-.6-1.5-1.4-2.1-2.1-.3-.4-.6-.8-.9-1.2-.6-.8-1-1.7-1.4-2.7-.2-.5-.4-.9-.5-1.4-.1-.5-.3-1-.4-1.5-.1-.5-.2-1-.2-1.5,0-.5,0-1,0-1.5s0-1,0-1.5c0-.5.1-1,.2-1.5,0-.5.2-1,.4-1.5.6-1.9,1.6-3.8,2.8-5.3.3-.4.7-.8,1-1.1.4-.4.7-.7,1.1-1,1.2-1,2.5-1.8,3.9-2.3.5-.2.9-.4,1.4-.5,1.5-.4,3-.7,4.5-.7,1,0,2,.1,3,.3.5.1,1,.2,1.5.4,1,.3,1.9.7,2.8,1.2.4.2.9.5,1.3.8.4.3.8.6,1.2.9.4.3.8.7,1.1,1,.4.4.7.7,1,1.1.3.4.6.8.9,1.2,1.7,2.5,2.6,5.5,2.6,8.6Z"/>
</g>
<path class="cls-1" d="M28.5,22.5l-3.2-1.8c-.2-.1-.4-.1-.6,0l-3.2,1.8c-.2.1-.3.3-.3.5v3.6c0,.2.1.4.3.5l3.2,1.8c0,0,.2,0,.3,0,.1,0,.2,0,.3,0l3.2-1.8c.2-.1.3-.3.3-.5v-3.6c0-.2-.1-.4-.3-.5ZM27.6,26.4l-2.5,1.5-2.5-1.5v-2.9l2.5-1.5,2.5,1.5v2.9Z"/>
<g class="cls-5">
<path class="cls-1" d="M28.5,6.6l-3.2-1.8c-.2-.1-.4-.1-.6,0l-3.1,1.8c-.2.1-.3.3-.3.5v3.6c0,.2.1.4.3.5l3.2,1.8c0,0,.2,0,.3,0,.1,0,.2,0,.3,0l3.2-1.8c.2-.1.3-.3.3-.5v-3.6c0-.2-.1-.4-.3-.5ZM27.6,10.5l-2.5,1.5-2.5-1.5v-2.9l2.5-1.5,2.5,1.5v2.9Z"/>
</g>
<g class="cls-4">
<path class="cls-1" d="M28.5,38.6l-3.2-1.8c-.2-.1-.4-.1-.6,0l-3.2,1.8c-.2.1-.3.3-.3.5v3.6c0,.2.1.4.3.5l3.2,1.8c0,0,.2,0,.3,0,.1,0,.2,0,.3,0l3.2-1.8c.2-.1.3-.3.3-.5v-3.6c0-.2-.1-.4-.3-.5ZM27.6,42.4l-2.5,1.5-2.5-1.5v-2.9l2.5-1.5,2.5,1.5v2.9Z"/>
</g>
<path class="cls-1" d="M12.5,29.9l-3.2-1.8c-.2-.1-.4-.1-.6,0l-3.2,1.8c-.2.1-.3.3-.3.5v3.6c0,.2.1.4.3.5l3.2,1.8c.2.1.4.1.6,0l3.2-1.8c.2-.1.3-.3.3-.5v-3.6c0-.2-.1-.4-.3-.5ZM11.6,33.7l-2.5,1.5-2.5-1.5v-2.9l2.5-1.5,2.5,1.5v2.9Z"/>
<g class="cls-8">
<path class="cls-1" d="M44.5,29.9l-3.2-1.8c-.2-.1-.4-.1-.6,0l-3.2,1.8c-.2.1-.3.3-.3.5v3.6c0,.2.1.4.3.5l3.2,1.8c.2.1.4.1.6,0l3.2-1.8c.2-.1.3-.3.3-.5v-3.6c0-.2-.1-.4-.3-.5ZM43.6,33.7l-2.5,1.5-2.5-1.5v-2.9l2.5-1.5,2.5,1.5v2.9Z"/>
</g>
<path class="cls-1" d="M12.5,15.1l-3.2-1.8c-.2-.1-.4-.1-.6,0l-3.2,1.8c-.2.1-.3.3-.3.5v3.6c0,.2.1.4.3.5l3.2,1.8c.2.1.4.1.6,0l3.2-1.8c.2-.1.3-.3.3-.5v-3.6c0-.2-.1-.4-.3-.5h0ZM11.6,19l-2.5,1.5-2.5-1.5v-2.9l2.5-1.5,2.5,1.5v2.9Z"/>
<g class="cls-6">
<path class="cls-1" d="M44.5,15.1l-3.2-1.8c-.2-.1-.4-.1-.6,0l-3.2,1.8c-.2.1-.3.3-.3.5v3.6c0,.2.1.4.3.5l3.2,1.8c.2.1.4.1.6,0l3.2-1.8c.2-.1.3-.3.3-.5v-3.6c0-.2-.1-.4-.3-.5h0ZM43.6,19l-2.5,1.5-2.5-1.5v-2.9l2.5-1.5,2.5,1.5v2.9Z"/>
</g>
<path class="cls-1" d="M9.7,26.5v-3.1c0-.3-.3-.6-.6-.6s-.6.3-.6.6v3.1c0,.3.3.6.6.6s.6-.3.6-.6h0ZM25.7,34.4v-3.1c0-.3-.3-.6-.6-.6-.3,0-.6.3-.6.6h0v3.1c0,.3.3.6.6.6.3,0,.6-.3.6-.6,0,0,0,0,0,0ZM18.9,37.4l-3.7-2.3c-.3-.2-.7,0-.9.2s0,.7.2.9h0l3.7,2.3c.3.2.7,0,.9-.2.2-.3,0-.7-.2-.9ZM34.7,35.1l-3.7,2.3c-.3.2-.4.6-.2.9.1.2.3.3.5.3.1,0,.2,0,.3,0l3.7-2.3c.3-.2.4-.6.2-.9-.2-.3-.6-.4-.8-.2ZM31,12.5l3.7,2.3c0,0,.2,0,.3,0,.2,0,.4-.1.5-.3.2-.3,0-.7-.2-.9l-3.7-2.3c-.3-.2-.7,0-.9.2,0,0,0,0,0,0-.2.3,0,.7.2.9ZM15.1,14.8c.1,0,.2,0,.3,0l3.7-2.3c.3-.2.4-.6.2-.9-.2-.3-.6-.4-.9-.2l-3.7,2.3c-.3.2-.4.6-.2.9.1.2.3.3.5.3ZM25.7,18.5v-3.1c0-.3-.3-.6-.6-.6s-.6.3-.6.6v3.1c0,.3.3.6.6.6.3,0,.6-.3.6-.6,0,0,0,0,0,0ZM41.7,26.5v-3.1c0-.3-.3-.6-.6-.6s-.6.3-.6.6v3.1c0,.3.3.6.6.6s.6-.3.6-.6h0ZM19.2,21.6l-3.7-1.8c-.3-.1-.7,0-.8.3,0,0,0,0,0,0-.1.3,0,.7.3.8l3.7,1.8c0,0,.2,0,.3,0,.2,0,.5-.1.6-.4.1-.3,0-.7-.3-.8ZM31.3,22.8c0,0,.2,0,.3,0l3.7-1.8c.3-.1.5-.5.3-.8-.1-.3-.5-.5-.8-.3,0,0,0,0,0,0l-3.7,1.8c-.3.1-.4.5-.3.8.1.2.3.4.6.4ZM35.3,29.2l-3.7-1.8c-.3-.1-.7,0-.8.3,0,0,0,0,0,0-.1.3,0,.7.3.8h0s3.7,1.8,3.7,1.8c0,0,.2,0,.3,0,.3,0,.6-.3.6-.6,0-.2-.1-.5-.4-.6ZM18.6,27.4l-3.7,1.8c-.3.1-.4.5-.3.8.1.2.3.4.6.4,0,0,.2,0,.3,0l3.7-1.8c.3-.1.4-.5.3-.8-.1-.3-.5-.4-.8-.3,0,0,0,0,0,0Z"/>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 50 50">
<defs>
<style>
.cls-1 {
fill: #000;
}
.cls-1, .cls-2, .cls-3 {
stroke-width: 0px;
}
.cls-2 {
fill: #a6a6a6;
}
.cls-3 {
fill: none;
}
.cls-4 {
clip-path: url(#clippath);
}
</style>
<clipPath id="clippath">
<rect class="cls-3" x="9.6" y="9.5" width="31.2" height="31.2"/>
</clipPath>
</defs>
<g class="cls-4">
<path class="cls-2" d="M40.5,25c0,1-.1,2-.3,3-.1.5-.2,1-.4,1.5-.1.5-.3,1-.5,1.4-.4.9-.9,1.8-1.4,2.7-.6.8-1.2,1.6-1.9,2.3-1.1,1.1-2.3,2-3.6,2.7-.4.2-.9.5-1.4.6-.5.2-.9.4-1.4.5-.5.1-1,.3-1.5.4-2,.4-4,.4-6,0-1-.2-2-.5-2.9-.9-1.4-.6-2.7-1.4-3.9-2.3-.4-.3-.8-.7-1.1-1-1.1-1.1-2-2.3-2.7-3.6-.2-.4-.5-.9-.6-1.4-.2-.5-.4-.9-.5-1.4-.4-1.5-.7-3-.7-4.5,0-1,.1-2,.3-3,.1-.5.2-1,.4-1.5.6-1.9,1.6-3.8,2.8-5.3.3-.4.7-.8,1-1.1.4-.4.7-.7,1.1-1,.4-.3.8-.6,1.2-.9,2.5-1.7,5.5-2.6,8.6-2.6,1,0,2,.1,3,.3.5.1,1,.2,1.5.4.5.1,1,.3,1.4.5.9.4,1.8.9,2.7,1.4.8.6,1.6,1.2,2.3,1.9.4.4.7.7,1,1.1.3.4.6.8.9,1.2,1.7,2.5,2.6,5.5,2.6,8.6Z"/>
</g>
<path class="cls-1" d="M24.4,22.7c.2-.5,0-1.1-.5-1.3,0,0,0,0,0,0-1.3-.6-2.8-1-4.3-1-1.3,0-2.6.3-3.9.8-1.2.5-2.3,1.2-3.2,2.1-.9.9-1.6,2-2.1,3.2-.5,1.2-.8,2.5-.8,3.9,0,1.3.3,2.6.8,3.9,1,2.4,2.9,4.3,5.3,5.3,1.2.5,2.5.8,3.9.8s2.6-.3,3.9-.8c2.4-1,4.3-2.9,5.3-5.3.5-1.2.8-2.5.8-3.9s-.3-2.9-.9-4.2c-.2-.5-.8-.7-1.3-.5-.5.2-.7.8-.5,1.3.5,1.1.8,2.2.8,3.4,0,2.1-.8,4.1-2.3,5.6-1.5,1.5-3.5,2.3-5.6,2.3-2.1,0-4.1-.8-5.6-2.3-1.5-1.5-2.3-3.5-2.3-5.6,0-2.1.8-4.1,2.3-5.6,1.5-1.5,3.5-2.3,5.6-2.3,1.2,0,2.4.3,3.4.8.5.2,1.1,0,1.3-.5h0Z"/>
<path class="cls-1" d="M30.7,22.2c-.5.3-.6.9-.3,1.4,1.3,2,1.9,4.3,1.9,6.7,0,1.7-.3,3.4-1,4.9-.6,1.5-1.6,2.9-2.7,4-1.2,1.2-2.5,2.1-4,2.7-1.6.7-3.2,1-4.9,1-1.7,0-3.4-.3-4.9-1-1.5-.6-2.9-1.6-4-2.7-1.2-1.2-2.1-2.5-2.7-4-.7-1.6-1-3.2-1-4.9,0-5.3,3.2-10,8.2-11.8,1.4-.5,3-.8,4.5-.8,2.4,0,4.7.7,6.7,1.9.5.3,1.1.1,1.4-.4.3-.5.1-1-.3-1.3-2.3-1.4-5-2.2-7.7-2.2-1.8,0-3.5.3-5.2.9-5.7,2.2-9.5,7.6-9.5,13.7,0,3.9,1.5,7.6,4.3,10.4,1.3,1.3,2.9,2.4,4.7,3.1,1.8.8,3.7,1.2,5.7,1.2,3.9,0,7.6-1.5,10.4-4.3,2.8-2.7,4.3-6.5,4.3-10.4,0-2.8-.8-5.5-2.2-7.8-.3-.5-.9-.6-1.4-.3Z"/>
<path class="cls-1" d="M44.9,12.9c-.1-.4-.4-.6-.8-.7l-5-.8c-.1-.2-.3-.4-.5-.5l-.8-5c0-.4-.3-.7-.7-.8-.4-.1-.8,0-1,.2l-6.4,6.4c-.2.2-.3.5-.3.9l.9,5.7-11,11c-.4.4-.4,1,0,1.4.2.2.4.3.7.3.3,0,.5,0,.7-.3l11-11,5.7.9c.3,0,.6,0,.9-.3l6.4-6.4c.3-.3.4-.7.2-1h0ZM36.1,8.1l.6,3.8-4.6,4.6-.6-3.8,4.6-4.6ZM37.2,18.5l-3.8-.6,4.6-4.6,3.8.6-4.6,4.6Z"/>
<path class="cls-1" d="M19.7,27.7c.1,0,.2,0,.4,0,.5,0,1.1-.3,1.1-.9,0-.5-.3-1.1-.9-1.1h0c-.2,0-.4,0-.6,0-2.6,0-4.7,2.1-4.7,4.7,0,2.6,2.1,4.7,4.7,4.7,2.6,0,4.7-2.1,4.7-4.7,0-.2,0-.4,0-.6,0-.5-.6-.9-1.2-.8-.5,0-.9.6-.8,1.1,0,.1,0,.2,0,.4,0,1.5-1.2,2.7-2.7,2.7-1.5,0-2.7-1.2-2.7-2.7,0-1.5,1.2-2.7,2.7-2.7Z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 50 50">
<defs>
<style>
.cls-1 {
fill: #000;
}
.cls-1, .cls-2, .cls-3 {
stroke-width: 0px;
}
.cls-2 {
fill: #a6a6a6;
}
.cls-3 {
fill: none;
}
.cls-4 {
clip-path: url(#clippath-1);
}
.cls-5 {
clip-path: url(#clippath);
}
</style>
<clipPath id="clippath">
<rect class="cls-3" x="9.4" y="9.5" width="31.2" height="31.3"/>
</clipPath>
<clipPath id="clippath-1">
<rect class="cls-3" x="8.4" y="5" width="33.1" height="40"/>
</clipPath>
</defs>
<g class="cls-5">
<path class="cls-2" d="M40.3,25c0,.5,0,1,0,1.5-.2,2-.8,4-1.8,5.8-.2.4-.5.9-.8,1.3-.3.4-.6.8-.9,1.2-.6.8-1.4,1.5-2.1,2.1-.4.3-.8.6-1.2.9-.4.3-.9.5-1.3.8-.9.5-1.8.9-2.8,1.2-.5.1-1,.3-1.5.4-1.5.3-3,.4-4.5.2-.5,0-1-.1-1.5-.2-.5-.1-1-.2-1.5-.4-.5-.1-1-.3-1.4-.5-.5-.2-.9-.4-1.4-.6-.4-.2-.9-.5-1.3-.8-.4-.3-.8-.6-1.2-.9-.8-.6-1.5-1.4-2.1-2.1-.3-.4-.6-.8-.9-1.2-.3-.4-.5-.9-.8-1.3-.5-.9-.9-1.8-1.2-2.8-.7-2.4-.9-5-.4-7.5,0-.5.2-1,.4-1.5.2-.5.3-1,.5-1.4.2-.5.4-.9.6-1.4.5-.9,1-1.7,1.7-2.5.6-.8,1.4-1.5,2.1-2.1.4-.3.8-.6,1.2-.9.4-.3.9-.5,1.3-.8.4-.2.9-.5,1.4-.6.5-.2.9-.4,1.4-.5,1.5-.4,3-.7,4.5-.7,1,0,2,0,3,.3.5,0,1,.2,1.5.4,1,.3,1.9.7,2.8,1.2.4.2.9.5,1.3.8.4.3.8.6,1.2.9.4.3.8.7,1.1,1s.7.7,1,1.1c.6.8,1.2,1.6,1.7,2.5.2.4.5.9.6,1.4.2.5.4.9.5,1.4.3,1,.5,2,.6,3,0,.5,0,1,0,1.5Z"/>
</g>
<g class="cls-4">
<path class="cls-1" d="M40.8,10.4c-.3-.3-.7-.4-1-.3-.8,0-1.6.1-2.4.1-5.8,0-9.9-2.2-10.9-4.4-.2-.5-.7-.8-1.2-.8h-.8c-.5,0-1,.3-1.2.8-1,2.2-5.1,4.4-10.9,4.4s-1.6,0-2.4-.1c-.4,0-.8,0-1,.3-.3.3-.4.6-.4,1v8c0,10.9,6.1,20.6,15.8,25.4.4.2.8.2,1.2,0,9.8-4.8,15.8-14.6,15.8-25.4v-8c0-.4-.2-.7-.4-1h0ZM38.6,19.4c0,9.6-5.3,18.3-13.8,22.7-8.5-4.5-13.8-13.1-13.8-22.7v-6.6c.4,0,.8,0,1.2,0,5.5,0,10.3-1.8,12.5-4.7,2.2,2.8,7,4.7,12.5,4.7s.8,0,1.2,0v6.6ZM35.1,17.5c.5.5.5,1.4,0,1.9,0,0,0,0,0,0l-11.6,11.2c-.2.2-.6.4-.9.4h0c-.4,0-.7-.2-.9-.4l-4.2-4.7c-.5-.6-.4-1.4.1-1.9.5-.5,1.3-.4,1.8,0l3.3,3.7,10.6-10.2c.5-.5,1.4-.5,1.9,0,0,0,0,0,0,0h0Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
src/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,49 @@
import { type Metadata } from 'next'
import Link from 'next/link'
import { AuthLayout } from '@/components/AuthLayout'
import { Button } from '@/components/Button'
import { TextField } from '@/components/Fields'
export const metadata: Metadata = {
title: 'Sign In',
}
export default function Login() {
return (
<AuthLayout
title="Sign in to account"
subtitle={
<>
Dont have an account?{' '}
<Link href="/register" className="text-cyan-600">
Sign up
</Link>{' '}
for a free trial.
</>
}
>
<form>
<div className="space-y-6">
<TextField
label="Email address"
name="email"
type="email"
autoComplete="email"
required
/>
<TextField
label="Password"
name="password"
type="password"
autoComplete="current-password"
required
/>
</div>
<Button type="submit" color="cyan" className="mt-8 w-full">
Sign in to account
</Button>
</form>
</AuthLayout>
)
}

View File

@@ -0,0 +1,75 @@
import { type Metadata } from 'next'
import Link from 'next/link'
import { AuthLayout } from '@/components/AuthLayout'
import { Button } from '@/components/Button'
import { SelectField, TextField } from '@/components/Fields'
export const metadata: Metadata = {
title: 'Sign Up',
}
export default function Register() {
return (
<AuthLayout
title="Sign up for an account"
subtitle={
<>
Already registered?{' '}
<Link href="/login" className="text-cyan-600">
Sign in
</Link>{' '}
to your account.
</>
}
>
<form>
<div className="grid grid-cols-2 gap-6">
<TextField
label="First name"
name="first_name"
type="text"
autoComplete="given-name"
required
/>
<TextField
label="Last name"
name="last_name"
type="text"
autoComplete="family-name"
required
/>
<TextField
className="col-span-full"
label="Email address"
name="email"
type="email"
autoComplete="email"
required
/>
<TextField
className="col-span-full"
label="Password"
name="password"
type="password"
autoComplete="new-password"
required
/>
<SelectField
className="col-span-full"
label="How did you hear about us?"
name="referral_source"
>
<option>AltaVista search</option>
<option>Super Bowl commercial</option>
<option>Our route 34 city bus ad</option>
<option>The Never Use This podcast</option>
</SelectField>
</div>
<Button type="submit" color="cyan" className="mt-8 w-full">
Get started today
</Button>
</form>
</AuthLayout>
)
}

View File

@@ -0,0 +1 @@
export { Layout as default } from '@/components/Layout'

24
src/app/(main)/page.tsx Normal file
View File

@@ -0,0 +1,24 @@
import { CallToAction } from '@/components/CallToAction'
import { Faqs } from '@/components/Faqs'
import { Hero } from '@/components/Hero'
import { Pricing } from '@/components/Pricing'
import { PrimaryFeatures } from '@/components/PrimaryFeatures'
import { UseCases } from '@/components/UseCases'
import { SecondaryFeatures } from '@/components/SecondaryFeatures'
import { Benefits } from '@/components/Benefits'
import { About } from '@/components/About'
export default function Home() {
return (
<>
<Hero />
<About />
<Benefits />
<PrimaryFeatures />
<UseCases />
<CallToAction />
<SecondaryFeatures />
<Faqs />
</>
)
}

BIN
src/app/.DS_Store vendored Normal file

Binary file not shown.

BIN
src/app/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

32
src/app/layout.tsx Normal file
View File

@@ -0,0 +1,32 @@
import { type Metadata } from 'next'
import { Inter } from 'next/font/google'
import clsx from 'clsx'
import '@/styles/tailwind.css'
const inter = Inter({
subsets: ['latin'],
display: 'swap',
variable: '--font-inter',
})
export const metadata: Metadata = {
title: {
template: '%s - Mycelium',
default: 'Mycelium - Unleash the Power of Decentralized Networks',
},
description:
'Discover Mycelium, an end-to-end encrypted IPv6 overlay network. The future of secure, efficient, and scalable networking.',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" className={clsx('bg-gray-50 antialiased', inter.variable)}>
<body>{children}</body>
</html>
)
}

24
src/app/not-found.tsx Normal file
View File

@@ -0,0 +1,24 @@
import { Button } from '@/components/Button'
import { CirclesBackground } from '@/components/CirclesBackground'
import { Container } from '@/components/Container'
import { Layout } from '@/components/Layout'
export default function NotFound() {
return (
<Layout>
<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" />
<p className="text-sm font-semibold text-gray-900">404</p>
<h1 className="mt-2 text-3xl font-medium tracking-tight text-gray-900">
Page not found
</h1>
<p className="mt-2 text-lg text-gray-600">
Sorry, we couldnt find the page youre looking for.
</p>
<Button href="/" variant="outline" className="mt-8">
Go back home
</Button>
</Container>
</Layout>
)
}

32
src/components/About.tsx Normal file
View File

@@ -0,0 +1,32 @@
import { AppStoreLink } from '@/components/AppStoreLink'
import { CircleBackground } from '@/components/CircleBackground'
import { Container } from '@/components/Container'
export function About() {
return (
<section
id="about"
className="relative overflow-hidden bg-gray-900 py-20 sm:py-28"
>
<div className="absolute top-1/2 left-20 -translate-y-1/2 sm:left-1/2 sm:-translate-x-1/2">
<CircleBackground color="#fff" className="animate-spin-slower" />
</div>
<Container className="relative">
<div className="mx-auto max-w-3xl sm:text-center">
<h2 className="text-3xl font-medium tracking-tight text-white sm:text-4xl">
Discover Mycelium
</h2>
<p className="mt-6 text-lg text-gray-300">
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 className="mt-6 text-lg text-gray-300">
Our mission is to create a sustainable digital ecosystem where communication is seamless, data is secure, and scalability knows no bounds.
</p>
<div className="mt-8 flex justify-center">
<AppStoreLink color="white" />
</div>
</div>
</Container>
</section>
)
}

View File

@@ -0,0 +1,71 @@
import Link from 'next/link'
import clsx from 'clsx'
export function AndroidLink({
color = 'black',
}: {
color?: 'black' | 'white'
}) {
return (
<Link
href="#"
aria-label="Download for Android"
className={clsx(
'flex items-center rounded-lg transition-colors px-4 py-2',
color === 'black'
? 'bg-gray-800 text-white hover:bg-gray-900'
: 'bg-white text-gray-900 hover:bg-gray-50',
)}
>
{/* Android SVG (converted for JSX) */}
<svg
viewBox="0 0 60 60"
aria-hidden="true"
className="h-5 w-5 mr-3"
>
<defs>
<clipPath id="android_clip_a">
<path d="M 1.566406 25 L 8 25 L 8 43 L 1.566406 43 Z M 1.566406 25 " clipRule="nonzero" />
</clipPath>
<clipPath id="android_clip_b">
<path d="M 10 25 L 34 25 L 34 53.640625 L 10 53.640625 Z M 10 25 " clipRule="nonzero" />
</clipPath>
</defs>
<g clipPath="url(#android_clip_a)">
<path
fill="currentColor"
d="M 4.445312 25.296875 C 2.855469 25.296875 1.5625 26.582031 1.5625 28.164062 L 1.5625 39.636719 C 1.5625 41.21875 2.855469 42.503906 4.445312 42.503906 C 6.035156 42.503906 7.324219 41.21875 7.324219 39.636719 L 7.324219 28.164062 C 7.324219 26.582031 6.035156 25.296875 4.445312 25.296875 Z M 4.445312 25.296875 "
fillOpacity="1"
fillRule="nonzero"
/>
</g>
<path
fill="currentColor"
d="M 39.015625 25.296875 C 37.425781 25.296875 36.132812 26.582031 36.132812 28.164062 L 36.132812 39.636719 C 36.132812 41.21875 37.425781 42.503906 39.015625 42.503906 C 40.605469 42.503906 41.894531 41.21875 41.894531 39.636719 L 41.894531 28.164062 C 41.894531 26.582031 40.605469 25.296875 39.015625 25.296875 Z M 39.015625 25.296875 "
fillOpacity="1"
fillRule="nonzero"
/>
<g clipPath="url(#android_clip_b)">
<path
fill="currentColor"
d="M 10.207031 42.667969 C 10.207031 44.253906 11.496094 45.535156 13.085938 45.535156 L 13.085938 51.105469 C 13.085938 52.6875 14.378906 53.972656 15.96875 53.972656 C 17.558594 53.972656 18.847656 52.6875 18.847656 51.105469 L 18.847656 45.535156 L 24.609375 45.535156 L 24.609375 51.105469 C 24.609375 52.6875 25.902344 53.972656 27.492188 53.972656 C 29.082031 53.972656 30.371094 52.6875 30.371094 51.105469 L 30.371094 45.535156 C 31.960938 45.535156 33.253906 44.253906 33.253906 42.667969 L 33.253906 25.464844 L 10.207031 25.464844 Z M 10.207031 42.667969 "
fillOpacity="1"
fillRule="nonzero"
/>
</g>
<path
fill="currentColor"
d="M 28.921875 13.53125 L 31.484375 10.4375 C 31.992188 9.824219 31.90625 8.921875 31.292969 8.417969 C 30.675781 7.914062 29.769531 8 29.261719 8.609375 L 26.460938 11.992188 C 25.015625 11.339844 23.421875 10.957031 21.730469 10.957031 C 20.015625 10.957031 18.402344 11.355469 16.941406 12.023438 L 14.214844 8.628906 C 13.714844 8.011719 12.808594 7.910156 12.1875 8.40625 C 11.570312 8.902344 11.46875 9.804688 11.964844 10.421875 L 14.492188 13.570312 C 11.898438 15.671875 10.207031 18.839844 10.207031 22.429688 L 33.253906 22.429688 C 33.253906 18.816406 31.542969 15.632812 28.921875 13.53125 Z M 18.847656 18.128906 C 18.054688 18.128906 17.410156 17.484375 17.410156 16.695312 C 17.410156 15.902344 18.054688 15.261719 18.847656 15.261719 C 19.644531 15.261719 20.289062 15.902344 20.289062 16.695312 C 20.289062 17.484375 19.644531 18.128906 18.847656 18.128906 Z M 24.609375 18.128906 C 23.816406 18.128906 23.171875 17.484375 23.171875 16.695312 C 23.171875 15.902344 23.816406 15.261719 24.609375 15.261719 C 25.40625 15.261719 26.050781 15.902344 26.050781 16.695312 C 26.050781 17.484375 25.40625 18.128906 24.609375 18.128906 Z M 24.609375 18.128906 "
fillOpacity="1"
fillRule="nonzero"
/>
</svg>
{/* Text */}
<div className="flex flex-col text-left leading-tight">
<span className="text-[9px] mt-0">Download for</span>
<span className="text-sm font-semibold -mt-1.5">Android</span>
</div>
</Link>
)
}

250
src/components/AppDemo.tsx Normal file
View File

@@ -0,0 +1,250 @@
'use client'
import { useId, useRef, useState } from 'react'
import clsx from 'clsx'
import { motion, useInView, useMotionValue } from 'framer-motion'
import { AppScreen } from '@/components/AppScreen'
const prices = [
997.56, 944.34, 972.25, 832.4, 888.76, 834.8, 805.56, 767.38, 861.21, 669.6,
694.39, 721.32, 694.03, 610.1, 502.2, 549.56, 611.03, 583.4, 610.14, 660.6,
752.11, 721.19, 638.89, 661.7, 694.51, 580.3, 638.0, 613.3, 651.64, 560.51,
611.45, 670.68, 752.56,
]
const maxPrice = Math.max(...prices)
const minPrice = Math.min(...prices)
function Chart({
className,
activePointIndex,
onChangeActivePointIndex,
width: totalWidth,
height: totalHeight,
paddingX = 0,
paddingY = 0,
gridLines = 6,
...props
}: React.ComponentPropsWithoutRef<'svg'> & {
activePointIndex: number | null
onChangeActivePointIndex: (index: number | null) => void
width: number
height: number
paddingX?: number
paddingY?: number
gridLines?: number
}) {
let width = totalWidth - paddingX * 2
let height = totalHeight - paddingY * 2
let id = useId()
let svgRef = useRef<React.ElementRef<'svg'>>(null)
let pathRef = useRef<React.ElementRef<'path'>>(null)
let isInView = useInView(svgRef, { amount: 0.5, once: true })
let pathWidth = useMotionValue(0)
let [interactionEnabled, setInteractionEnabled] = useState(false)
let path = ''
let points: Array<{ x: number; y: number }> = []
for (let index = 0; index < prices.length; index++) {
let x = paddingX + (index / (prices.length - 1)) * width
let y =
paddingY +
(1 - (prices[index] - minPrice) / (maxPrice - minPrice)) * height
points.push({ x, y })
path += `${index === 0 ? 'M' : 'L'} ${x.toFixed(4)} ${y.toFixed(4)}`
}
return (
<svg
ref={svgRef}
viewBox={`0 0 ${totalWidth} ${totalHeight}`}
className={clsx(className, 'overflow-visible')}
{...(interactionEnabled
? {
onPointerLeave: () => onChangeActivePointIndex(null),
onPointerMove: (event) => {
let x = event.nativeEvent.offsetX
let closestPointIndex: number | null = null
let closestDistance = Infinity
for (
let pointIndex = 0;
pointIndex < points.length;
pointIndex++
) {
let point = points[pointIndex]
let distance = Math.abs(point.x - x)
if (distance < closestDistance) {
closestDistance = distance
closestPointIndex = pointIndex
} else {
break
}
}
onChangeActivePointIndex(closestPointIndex)
},
}
: {})}
{...props}
>
<defs>
<clipPath id={`${id}-clip`}>
<path d={`${path} V ${height + paddingY} H ${paddingX} Z`} />
</clipPath>
<linearGradient id={`${id}-gradient`} x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stopColor="#13B5C8" />
<stop offset="100%" stopColor="#13B5C8" stopOpacity="0" />
</linearGradient>
</defs>
{[...Array(gridLines - 1).keys()].map((index) => (
<line
key={index}
stroke="#a3a3a3"
opacity="0.1"
x1="0"
y1={(totalHeight / gridLines) * (index + 1)}
x2={totalWidth}
y2={(totalHeight / gridLines) * (index + 1)}
/>
))}
<motion.rect
y={paddingY}
width={pathWidth}
height={height}
fill={`url(#${id}-gradient)`}
clipPath={`url(#${id}-clip)`}
opacity="0.5"
/>
<motion.path
ref={pathRef}
d={path}
fill="none"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
initial={{ pathLength: 0 }}
transition={{ duration: 1 }}
{...(isInView ? { stroke: '#06b6d4', animate: { pathLength: 1 } } : {})}
onUpdate={({ pathLength }) => {
if (pathRef.current && typeof pathLength === 'number') {
pathWidth.set(
pathRef.current.getPointAtLength(
pathLength * pathRef.current.getTotalLength(),
).x,
)
}
}}
onAnimationComplete={() => setInteractionEnabled(true)}
/>
{activePointIndex !== null && (
<>
<line
x1="0"
y1={points[activePointIndex].y}
x2={totalWidth}
y2={points[activePointIndex].y}
stroke="#06b6d4"
strokeDasharray="1 3"
/>
<circle
r="4"
cx={points[activePointIndex].x}
cy={points[activePointIndex].y}
fill="#fff"
strokeWidth="2"
stroke="#06b6d4"
/>
</>
)}
</svg>
)
}
export function AppDemo() {
let [activePointIndex, setActivePointIndex] = useState<number | null>(null)
let activePriceIndex = activePointIndex ?? prices.length - 1
let activeValue = prices[activePriceIndex]
let previousValue = prices[activePriceIndex - 1]
let percentageChange =
activePriceIndex === 0
? null
: ((activeValue - previousValue) / previousValue) * 100
return (
<AppScreen>
<AppScreen.Body>
<div className="p-4">
<div className="flex gap-2">
<div className="text-xs/6 text-gray-500">Tailwind Labs, Inc.</div>
<div className="text-sm text-gray-900">$CSS</div>
<svg viewBox="0 0 24 24" className="ml-auto h-6 w-6" fill="none">
<path
d="M5 12a7 7 0 1 1 14 0 7 7 0 0 1-14 0ZM12 9v6M15 12H9"
stroke="#171717"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</div>
<div className="mt-3 border-t border-gray-200 pt-5">
<div className="flex items-baseline gap-2">
<div className="text-2xl tracking-tight text-gray-900 tabular-nums">
{activeValue.toFixed(2)}
</div>
<div className="text-sm text-gray-900">USD</div>
{percentageChange && (
<div
className={clsx(
'ml-auto text-sm tracking-tight tabular-nums',
percentageChange >= 0 ? 'text-cyan-500' : 'text-gray-500',
)}
>
{`${
percentageChange >= 0 ? '+' : ''
}${percentageChange.toFixed(2)}%`}
</div>
)}
</div>
<div className="mt-6 flex gap-4 text-xs text-gray-500">
<div>1D</div>
<div>5D</div>
<div className="font-semibold text-cyan-600">1M</div>
<div>6M</div>
<div>1Y</div>
<div>5Y</div>
</div>
<div className="mt-3 rounded-lg bg-gray-50 ring-1 ring-black/5 ring-inset">
<Chart
width={286}
height={208}
paddingX={16}
paddingY={32}
activePointIndex={activePointIndex}
onChangeActivePointIndex={setActivePointIndex}
/>
</div>
<div className="mt-4 rounded-lg bg-cyan-500 px-4 py-2 text-center text-sm font-semibold text-white">
Trade
</div>
<div className="mt-3 divide-y divide-gray-100 text-sm">
<div className="flex justify-between py-1">
<div className="text-gray-500">Open</div>
<div className="font-medium text-gray-900">6,387.55</div>
</div>
<div className="flex justify-between py-1">
<div className="text-gray-500">Closed</div>
<div className="font-medium text-gray-900">6,487.09</div>
</div>
<div className="flex justify-between py-1">
<div className="text-gray-500">Low</div>
<div className="font-medium text-gray-900">6,322.01</div>
</div>
</div>
</div>
</div>
</AppScreen.Body>
</AppScreen>
)
}

View File

@@ -0,0 +1,109 @@
import { forwardRef } from 'react'
import clsx from 'clsx'
function Logo(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 79 24" fill="none" aria-hidden="true" {...props}>
<path
d="M12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12ZM2.4 12a9.004 9.004 0 0 0 6.055 8.507c1.565.542 2.945-.85 2.945-2.507V6c0-1.657-1.38-3.049-2.945-2.507A9.004 9.004 0 0 0 2.4 12Z"
fill="#06B6D4"
/>
<path
d="M33.004 17V6.818h3.818c.783 0 1.439.146 1.97.438.533.291.935.692 1.207 1.203.275.507.413 1.084.413 1.73 0 .653-.138 1.233-.413 1.74a2.948 2.948 0 0 1-1.218 1.198c-.537.288-1.198.433-1.983.433h-2.531v-1.517h2.282c.457 0 .832-.08 1.124-.238.291-.16.507-.378.646-.657.142-.278.214-.598.214-.96 0-.36-.072-.679-.214-.954a1.452 1.452 0 0 0-.651-.641c-.292-.156-.668-.234-1.129-.234h-1.69V17h-1.845Zm12.152.15c-.746 0-1.392-.165-1.939-.493a3.343 3.343 0 0 1-1.273-1.377c-.298-.59-.447-1.28-.447-2.068 0-.79.15-1.48.447-2.073a3.335 3.335 0 0 1 1.273-1.383c.547-.328 1.193-.492 1.94-.492.745 0 1.391.164 1.938.492.547.329.97.79 1.268 1.383.301.593.452 1.284.452 2.073 0 .789-.15 1.478-.452 2.068a3.309 3.309 0 0 1-1.268 1.377c-.547.328-1.193.492-1.939.492Zm.01-1.443c.404 0 .742-.11 1.014-.333.272-.225.474-.527.607-.905.136-.377.204-.798.204-1.262 0-.468-.068-.89-.204-1.268a2.007 2.007 0 0 0-.607-.91c-.272-.225-.61-.338-1.014-.338-.414 0-.759.113-1.034.338a2.041 2.041 0 0 0-.612.91 3.81 3.81 0 0 0-.198 1.268c0 .464.066.885.198 1.262.136.378.34.68.612.905.275.222.62.333 1.034.333Zm8.508 1.442c-.763 0-1.417-.167-1.964-.502a3.352 3.352 0 0 1-1.258-1.387c-.292-.593-.437-1.276-.437-2.048 0-.776.149-1.46.447-2.054a3.34 3.34 0 0 1 1.263-1.392c.547-.334 1.193-.502 1.939-.502.62 0 1.168.115 1.645.343.48.226.864.546 1.149.96.285.41.447.891.487 1.441h-1.72a1.644 1.644 0 0 0-.497-.92c-.259-.248-.605-.372-1.04-.372-.367 0-.69.1-.969.298-.278.196-.495.478-.651.845-.153.368-.229.81-.229 1.323 0 .52.076.968.229 1.342.152.371.366.658.641.86.279.2.605.298.98.298.265 0 .502-.05.71-.149.213-.102.39-.25.532-.442.143-.192.24-.426.294-.701h1.72a2.999 2.999 0 0 1-.477 1.437c-.275.414-.65.739-1.124.974-.474.232-1.03.348-1.67.348Zm6.39-2.545-.006-2.173h.289l2.744-3.067h2.103l-3.376 3.758h-.372l-1.383 1.482ZM58.422 17V6.818h1.8V17h-1.8Zm4.792 0-2.485-3.475 1.213-1.268L65.368 17h-2.153Zm6.245.15c-.766 0-1.427-.16-1.984-.478a3.233 3.233 0 0 1-1.278-1.362c-.298-.59-.447-1.285-.447-2.083 0-.786.149-1.475.447-2.069a3.384 3.384 0 0 1 1.263-1.392c.54-.334 1.175-.502 1.904-.502.47 0 .915.076 1.333.229.42.149.792.381 1.113.696.325.315.58.716.766 1.203.186.484.278 1.06.278 1.73v.552h-6.259v-1.213h4.534a1.935 1.935 0 0 0-.224-.92 1.625 1.625 0 0 0-.611-.641 1.719 1.719 0 0 0-.905-.234c-.368 0-.691.09-.97.269a1.848 1.848 0 0 0-.65.696c-.153.285-.231.598-.234.94v1.058c0 .444.08.825.243 1.144.163.315.39.556.681.726.292.165.634.248 1.025.248.261 0 .498-.036.71-.11.213-.075.397-.187.552-.332.156-.146.274-.327.353-.542l1.68.189a2.62 2.62 0 0 1-.606 1.163 2.958 2.958 0 0 1-1.133.766c-.461.179-.988.268-1.581.268Zm8.731-7.786v1.392h-4.39V9.364h4.39Zm-3.306-1.83h1.8v7.17c0 .241.036.427.109.556a.59.59 0 0 0 .298.258c.123.047.259.07.408.07.113 0 .215-.008.308-.025.096-.016.17-.031.219-.045l.303 1.407c-.096.034-.233.07-.412.11-.176.04-.392.063-.647.07a2.934 2.934 0 0 1-1.218-.204 1.895 1.895 0 0 1-.86-.706c-.209-.319-.311-.716-.308-1.194V7.534Z"
fill="#fff"
/>
</svg>
)
}
function MenuIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" {...props}>
<path
d="M5 6h14M5 18h14M5 12h14"
stroke="#fff"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
function UserIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" {...props}>
<path
d="M15 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0ZM6.696 19h10.608c1.175 0 2.08-.935 1.532-1.897C18.028 15.69 16.187 14 12 14s-6.028 1.689-6.836 3.103C4.616 18.065 5.521 19 6.696 19Z"
stroke="#fff"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export function AppScreen({
children,
className,
...props
}: React.ComponentPropsWithoutRef<'div'>) {
return (
<div className={clsx('flex flex-col', className)} {...props}>
<div className="flex justify-between px-4 pt-4">
<MenuIcon className="h-6 w-6 flex-none" />
<Logo className="h-6 flex-none" />
<UserIcon className="h-6 w-6 flex-none" />
</div>
{children}
</div>
)
}
AppScreen.Header = forwardRef<
React.ElementRef<'div'>,
{ children: React.ReactNode }
>(function AppScreenHeader({ children }, ref) {
return (
<div ref={ref} className="mt-6 px-4 text-white">
{children}
</div>
)
})
AppScreen.Title = forwardRef<
React.ElementRef<'div'>,
{ children: React.ReactNode }
>(function AppScreenTitle({ children }, ref) {
return (
<div ref={ref} className="text-2xl text-white">
{children}
</div>
)
})
AppScreen.Subtitle = forwardRef<
React.ElementRef<'div'>,
{ children: React.ReactNode }
>(function AppScreenSubtitle({ children }, ref) {
return (
<div ref={ref} className="text-sm text-gray-500">
{children}
</div>
)
})
AppScreen.Body = forwardRef<
React.ElementRef<'div'>,
{ className?: string; children: React.ReactNode }
>(function AppScreenBody({ children, className }, ref) {
return (
<div
ref={ref}
className={clsx('mt-6 flex-auto rounded-t-2xl bg-white', className)}
>
{children}
</div>
)
})

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,40 @@
import Link from 'next/link'
import { CirclesBackground } from '@/components/CirclesBackground'
import { Logo } from '@/components/Logo'
export function AuthLayout({
title,
subtitle,
children,
}: {
title: string
subtitle: React.ReactNode
children: React.ReactNode
}) {
return (
<main className="flex min-h-full overflow-hidden pt-16 sm:py-28">
<div className="mx-auto flex w-full max-w-2xl flex-col px-4 sm:px-6">
<Link href="/" aria-label="Home">
<Logo className="mx-auto h-10 w-auto" />
</Link>
<div className="relative mt-12 sm:mt-16">
<CirclesBackground
width="1090"
height="1090"
className="absolute -top-7 left-1/2 -z-10 h-[788px] -translate-x-1/2 mask-[linear-gradient(to_bottom,white_20%,transparent_75%)] stroke-gray-300/30 sm:-top-9 sm:h-auto"
/>
<h1 className="text-center text-2xl font-medium tracking-tight text-gray-900">
{title}
</h1>
{subtitle && (
<p className="mt-3 text-center text-lg text-gray-600">{subtitle}</p>
)}
</div>
<div className="-mx-4 mt-10 flex-auto bg-white px-4 py-10 shadow-2xl shadow-gray-900/10 sm:mx-0 sm:flex-none sm:rounded-5xl sm:p-24">
{children}
</div>
</div>
</main>
)
}

View File

@@ -0,0 +1,60 @@
'use client'
import React, { useEffect, useMemo, useRef, useState } from 'react'
import clsx from 'clsx'
import { useInView } from 'framer-motion'
import { Container } from '@/components/Container'
const features = [
{
name: 'Decentralization',
description: 'Designed to operate in a decentralized manner, it connects nodes and enables efficient data transfer and communication without relying on a single central authority.',
},
{
name: 'Efficiency',
description:
'Mycelium provides an efficient digital communication network where data travels along the most efficient paths, reducing latency and optimizing resource utilization.',
},
{
name: 'Resilience',
description:
'Inspired by nature\'s resilience, it creates a network that can adapt and continue to function even in the presence of challenges, ensuring uninterrupted communication.',
},
]
export function Benefits() {
return (
<section id="benefits" className="bg-white py-24 sm:py-32 dark:bg-gray-900">
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-5xl lg:mx-0">
<h2 className="text-3xl font-medium tracking-tight text-gray-900">
Nature's Blueprint for Digital Connectivity
</h2>
<p className="mt-6 text-lg text-gray-600">
Just as nature's mycelium network serves as a critical component in the ecosystems of forests, connecting trees and plants underground, the Mycelium technology offers reliable connectivity in an efficient and resilient way.
</p>
</div>
<ul 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">
{features.map((feature) => (
<li
key={feature.name}
className="rounded-2xl border border-gray-200 p-8 dark:border-gray-700"
>
<img
src={`/images/${feature.name.toLowerCase()}.svg`}
alt={feature.name}
className="h-8 w-8 mb-4"
/>
<h3 className="font-semibold text-gray-900 dark:text-white">{feature.name}</h3>
<p className="mt-2 text-gray-700 text-sm dark:text-gray-400">{feature.description}</p>
</li>
))}
</ul>
</div>
</section>
)
}

59
src/components/Button.tsx Normal file
View File

@@ -0,0 +1,59 @@
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(--spacing(2)-1px)] px-[calc(--spacing(3)-1px)] text-sm transition-colors',
}
const variantStyles = {
solid: {
cyan: 'relative overflow-hidden bg-cyan-500 text-white before:absolute before:inset-0 active:before:bg-transparent hover:before:bg-white/10 active:bg-cyan-600 active:text-white/80 before:transition-colors',
white:
'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',
},
outline: {
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'
props.color ??= 'gray'
className = clsx(
baseStyles[props.variant],
props.variant === 'outline'
? variantStyles.outline[props.color]
: props.variant === 'solid'
? variantStyles.solid[props.color]
: undefined,
className,
)
return typeof props.href === 'undefined' ? (
<button className={className} {...props} />
) : (
<Link className={className} {...props} />
)
}

View File

@@ -0,0 +1,35 @@
import { AppStoreLink } from '@/components/AppStoreLink'
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 CallToAction() {
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-20 -translate-y-1/2 sm:left-1/2 sm:-translate-x-1/2">
<CircleBackground color="#fff" className="animate-spin-slower" />
</div>
<Container className="relative">
<div className="mx-auto max-w-2xl sm:text-center">
<h2 className="text-3xl font-medium tracking-tight text-white sm:text-4xl">
Get Started Today
</h2>
<p className="mt-6 text-lg text-gray-300">
Download the Mycelium app and step into the future of secure, peer-to-peer networking; fast, private, and decentralized.
</p>
<div className="mt-8 flex justify-center gap-4">
<AppStoreLink color="white" />
<WindowsLink color="white" />
<AndroidLink color="white" />
<LinuxLink color="white" />
</div>
</div>
</Container>
</section>
)
}

View File

@@ -0,0 +1,45 @@
import { useId } from 'react'
export function CircleBackground({
color,
...props
}: React.ComponentPropsWithoutRef<'svg'> & {
color: string
}) {
let id = useId()
return (
<svg
viewBox="0 0 558 558"
width="558"
height="558"
fill="none"
aria-hidden="true"
{...props}
>
<defs>
<linearGradient
id={id}
x1="79"
y1="16"
x2="105"
y2="237"
gradientUnits="userSpaceOnUse"
>
<stop stopColor={color} />
<stop offset="1" stopColor={color} stopOpacity="0" />
</linearGradient>
</defs>
<path
opacity=".2"
d="M1 279C1 125.465 125.465 1 279 1s278 124.465 278 278-124.465 278-278 278S1 432.535 1 279Z"
stroke={color}
/>
<path
d="M1 279C1 125.465 125.465 1 279 1"
stroke={`url(#${id})`}
strokeLinecap="round"
/>
</svg>
)
}

View File

@@ -0,0 +1,18 @@
export function CirclesBackground(
props: React.ComponentPropsWithoutRef<'svg'>,
) {
return (
<svg
viewBox="0 0 1090 1090"
aria-hidden="true"
fill="none"
preserveAspectRatio="none"
{...props}
>
<circle cx={545} cy={545} r="544.5" />
<circle cx={545} cy={545} r="480.5" />
<circle cx={545} cy={545} r="416.5" />
<circle cx={545} cy={545} r="352.5" />
</svg>
)
}

View File

@@ -0,0 +1,13 @@
import clsx from 'clsx'
export function Container({
className,
...props
}: React.ComponentPropsWithoutRef<'div'>) {
return (
<div
className={clsx('mx-auto max-w-7xl px-4 sm:px-6 lg:px-8', className)}
{...props}
/>
)
}

View File

@@ -0,0 +1,15 @@
import Link from 'next/link'
import { ArrowDownTrayIcon } from '@heroicons/react/24/solid'
export function DownloadLink() {
return (
<Link
href="#"
aria-label="Download Mycelium"
className="inline-flex items-center rounded-lg bg-gray-800 px-4 py-2 text-sm font-semibold text-white hover:bg-gray-900 transition-colors"
>
<ArrowDownTrayIcon className="h-5 w-5 mr-2" />
Get Mycelium
</Link>
)
}

100
src/components/Faqs.tsx Normal file
View File

@@ -0,0 +1,100 @@
import { Container } from '@/components/Container'
const faqs = [
[
{
question: 'What is Mycelium?',
answer:
'Mycelium is an end-to-end encrypted IPv6 overlay network written in Rust. Each node joining the network receives an IP in the 400::/7 range, facilitating secure and private communications.',
},
{
question: 'Is mycelium ready to scale to the world?',
answer:
'No, Mycelium is not yet fully scalable to a global level. Currently, each network can support around 100,000 users, but multiple networks can be deployed to expand capacity. We anticipate resolving these scalability challenges by 2025.',
},
{
question: 'How do I install Mycelium?',
answer:
'The Mycelium app supports iOS, macOS, Android and Windows. For Linux, a binary is available. Installation guides are available for both local machines and virtual machines running on the TFGrid. Note that Windows users need to have wintun.dll in the same directory as the Mycelium executable.',
},
],
[
{
question: 'How can I find and use my Mycelium address?',
answer:
'Upon using the Mycelium app, you\'re assigned a unique Mycelium address. To copy this address, click the button located to the right of the displayed address in the app interface.',
},
{
question: 'Can I deploy workloads on the TFGrid using Mycelium?',
answer:
'Yes, after installing Mycelium, you can deploy workloads on the TFGrid and connect to them using the Mycelium network. Detailed deployment guides are available in the documentation.',
},
{
question: 'Is there an API available for Mycelium?',
answer:
'Yes, Mycelium offers an API for administrative operations, peer management, and message subsystem operations. Comprehensive API documentation can be found in the official Mycelium GitHub repository.',
},
],
[
{
question: 'What should I do if I encounter issues during installation or usage?',
answer:
'If you face any challenges, refer to the troubleshooting section in the Mycelium documentation. Additionally, ensure that all prerequisites are met, such as having wintun.dll in the correct directory for Windows installations.',
},
{
question: 'How does Mycelium handle routing within its network?',
answer:
'Mycelium incorporates core principles of the Babel routing protocol, enabling efficient and dynamic routing within its encrypted IPv6 overlay network.',
},
],
]
export function Faqs() {
return (
<section
id="faqs"
aria-labelledby="faqs-title"
className="border-t border-gray-200 py-20 sm:py-32"
>
<Container>
<div className="mx-auto max-w-2xl lg:mx-0">
<h2
id="faqs-title"
className="text-3xl font-medium tracking-tight text-gray-900"
>
Frequently asked questions
</h2>
<p className="mt-2 text-lg text-gray-600">
If you have anything else you want to ask,{' '}
<a
href="mailto:info@example.com"
className="text-gray-900 underline"
>
reach out to us
</a>
.
</p>
</div>
<ul
role="list"
className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-8 sm:mt-20 lg:max-w-none lg:grid-cols-3"
>
{faqs.map((column, columnIndex) => (
<li key={columnIndex}>
<ul role="list" className="space-y-10">
{column.map((faq, faqIndex) => (
<li key={faqIndex}>
<h3 className="text-lg/6 font-semibold text-gray-900">
{faq.question}
</h3>
<p className="mt-4 text-sm text-gray-700">{faq.answer}</p>
</li>
))}
</ul>
</li>
))}
</ul>
</Container>
</section>
)
}

47
src/components/Fields.tsx Normal file
View File

@@ -0,0 +1,47 @@
import { useId } from 'react'
import clsx from 'clsx'
const formClasses =
'block w-full appearance-none rounded-lg border border-gray-200 bg-white py-[calc(--spacing(2)-1px)] px-[calc(--spacing(3)-1px)] text-gray-900 placeholder:text-gray-400 focus:border-cyan-500 focus:outline-hidden focus:ring-cyan-500 sm:text-sm'
function Label({ id, children }: { id: string; children: React.ReactNode }) {
return (
<label
htmlFor={id}
className="mb-2 block text-sm font-semibold text-gray-900"
>
{children}
</label>
)
}
export function TextField({
label,
type = 'text',
className,
...props
}: Omit<React.ComponentPropsWithoutRef<'input'>, 'id'> & { label?: string }) {
let id = useId()
return (
<div className={className}>
{label && <Label id={id}>{label}</Label>}
<input id={id} type={type} {...props} className={formClasses} />
</div>
)
}
export function SelectField({
label,
className,
...props
}: Omit<React.ComponentPropsWithoutRef<'select'>, 'id'> & { label?: string }) {
let id = useId()
return (
<div className={className}>
{label && <Label id={id}>{label}</Label>}
<select id={id} {...props} className={clsx(formClasses, 'pr-8')} />
</div>
)
}

80
src/components/Footer.tsx Normal file
View File

@@ -0,0 +1,80 @@
import Image from 'next/image'
import Link from 'next/link'
import { Button } from '@/components/Button'
import { Container } from '@/components/Container'
import { TextField } from '@/components/Fields'
import { Logomark } from '@/components/Logo'
import { NavLinks } from '@/components/NavLinks'
import qrCode from '@/images/qr-code.svg'
function QrCodeBorder(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 96 96" fill="none" aria-hidden="true" {...props}>
<path
d="M1 17V9a8 8 0 0 1 8-8h8M95 17V9a8 8 0 0 0-8-8h-8M1 79v8a8 8 0 0 0 8 8h8M95 79v8a8 8 0 0 1-8 8h-8"
strokeWidth="2"
strokeLinecap="round"
/>
</svg>
)
}
export function Footer() {
return (
<footer className="border-t border-gray-200">
<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>
<div className="flex items-center text-gray-900">
<Logomark className="h-10 w-10 flex-none fill-cyan-500" />
<div className="ml-4">
<p className="text-base font-semibold">Mycelium</p>
<p className="mt-1 text-sm">Unleash the Power of Decentralized Networks</p>
</div>
</div>
<nav className="mt-11 flex gap-8">
<NavLinks />
</nav>
</div>
<div className="group relative -mx-4 flex items-center self-stretch p-4 transition-colors hover:bg-gray-100 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-300 transition-colors group-hover:stroke-cyan-500" />
<Image src={qrCode} alt="" unoptimized />
</div>
<div className="ml-8 lg:w-64">
<p className="text-base font-semibold text-gray-900">
<Link href="#">
<span className="absolute inset-0 sm:rounded-2xl" />
Download the app
</Link>
</p>
<p className="mt-1 text-sm text-gray-700">
Scan the QR code to download the app from the App Store.
</p>
</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">
<form className="flex w-full justify-center md:w-auto">
<TextField
type="email"
aria-label="Email address"
placeholder="Email address"
autoComplete="email"
required
className="w-60 min-w-0 shrink"
/>
<Button type="submit" color="cyan" className="ml-4 flex-none">
<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-500 md:mt-0">
&copy; Copyright ThreeFold {new Date().getFullYear()}. All rights reserved.
</p>
</div>
</Container>
</footer>
)
}

149
src/components/Header.tsx Normal file
View File

@@ -0,0 +1,149 @@
'use client'
import Link from 'next/link'
import {
Popover,
PopoverButton,
PopoverBackdrop,
PopoverPanel,
} from '@headlessui/react'
import { AnimatePresence, motion } from 'framer-motion'
import { Button } from '@/components/Button'
import { Container } from '@/components/Container'
import { Logo } from '@/components/Logo'
import { NavLinks } from '@/components/NavLinks'
function MenuIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" {...props}>
<path
d="M5 6h14M5 18h14M5 12h14"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
function ChevronUpIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" {...props}>
<path
d="M17 14l-5-5-5 5"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
function MobileNavLink(
props: Omit<
React.ComponentPropsWithoutRef<typeof PopoverButton<typeof Link>>,
'as' | 'className'
>,
) {
return (
<PopoverButton
as={Link}
className="block text-base/7 tracking-tight text-gray-700"
{...props}
/>
)
}
export function Header() {
return (
<header>
<nav>
<Container className="relative z-50 flex justify-between py-8">
<div className="relative z-10 flex items-center gap-16">
<Link href="/" aria-label="Home">
<Logo className="h-10 w-auto" />
</Link>
<div className="hidden lg:flex lg:gap-10">
<NavLinks />
</div>
</div>
<div className="flex items-center gap-6">
<Popover className="lg:hidden">
{({ 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"
aria-label="Toggle site navigation"
>
{({ open }) =>
open ? (
<ChevronUpIcon className="h-6 w-6" />
) : (
<MenuIcon className="h-6 w-6" />
)
}
</PopoverButton>
<AnimatePresence initial={false}>
{open && (
<>
<PopoverBackdrop
static
as={motion.div}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 z-0 bg-gray-300/60 backdrop-blur-sm"
/>
<PopoverPanel
static
as={motion.div}
initial={{ opacity: 0, y: -32 }}
animate={{ opacity: 1, y: 0 }}
exit={{
opacity: 0,
y: -32,
transition: { duration: 0.2 },
}}
className="absolute inset-x-0 top-0 z-0 origin-top rounded-b-2xl bg-gray-50 px-6 pt-32 pb-6 shadow-2xl shadow-gray-900/20"
>
<div className="space-y-4">
<MobileNavLink href="/#about">
About
</MobileNavLink>
<MobileNavLink href="/#benefits">
Benefits
</MobileNavLink>
<MobileNavLink href="/#features">
Features
</MobileNavLink>
<MobileNavLink href="/#usecases">
Use Cases
</MobileNavLink>
<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">
Docs
</Button>
<Button href="https://www.mycelium.threefold.io/download/">Get Mycelium</Button>
</div>
</PopoverPanel>
</>
)}
</AnimatePresence>
</>
)}
</Popover>
<div className="flex items-center gap-6 max-lg:hidden">
<Button href="https://docs.ourworld.tf/mycelium_cloud/docs/" variant="outline">
Docs
</Button>
<Button href="https://www.mycelium.threefold.io/download/">Get Mycelium</Button>
</div>
</div>
</Container>
</nav>
</header>
)
}

166
src/components/Hero.tsx Normal file
View File

@@ -0,0 +1,166 @@
import { useId } from 'react'
import Image from 'next/image'
import clsx from 'clsx'
import { AppDemo } from '@/components/AppDemo'
import { DownloadLink } from '@/components/DownloadLink'
import { Button } from '@/components/Button'
import { Container } from '@/components/Container'
import { PhoneFrame } from '@/components/PhoneFrame'
import logoBbc from '@/images/logos/bbc.svg'
import logoCbs from '@/images/logos/cbs.svg'
import logoCnn from '@/images/logos/cnn.svg'
import logoFastCompany from '@/images/logos/fast-company.svg'
import logoForbes from '@/images/logos/forbes.svg'
import logoHuffpost from '@/images/logos/huffpost.svg'
import logoTechcrunch from '@/images/logos/techcrunch.svg'
import logoWired from '@/images/logos/wired.svg'
function BackgroundIllustration(props: React.ComponentPropsWithoutRef<'div'>) {
let id = useId()
return (
<div {...props}>
<svg
viewBox="0 0 1026 1026"
fill="none"
aria-hidden="true"
className="absolute inset-0 h-full w-full animate-spin-slow"
>
<path
d="M1025 513c0 282.77-229.23 512-512 512S1 795.77 1 513 230.23 1 513 1s512 229.23 512 512Z"
stroke="#D4D4D4"
strokeOpacity="0.7"
/>
<path
d="M513 1025C230.23 1025 1 795.77 1 513"
stroke={`url(#${id}-gradient-1)`}
strokeLinecap="round"
/>
<defs>
<linearGradient
id={`${id}-gradient-1`}
x1="1"
y1="513"
x2="1"
y2="1025"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#06b6d4" />
<stop offset="1" stopColor="#06b6d4" stopOpacity="0" />
</linearGradient>
</defs>
</svg>
<svg
viewBox="0 0 1026 1026"
fill="none"
aria-hidden="true"
className="absolute inset-0 h-full w-full animate-spin-reverse-slower"
>
<path
d="M913 513c0 220.914-179.086 400-400 400S113 733.914 113 513s179.086-400 400-400 400 179.086 400 400Z"
stroke="#D4D4D4"
strokeOpacity="0.7"
/>
<path
d="M913 513c0 220.914-179.086 400-400 400"
stroke={`url(#${id}-gradient-2)`}
strokeLinecap="round"
/>
<defs>
<linearGradient
id={`${id}-gradient-2`}
x1="913"
y1="513"
x2="913"
y2="913"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#06b6d4" />
<stop offset="1" stopColor="#06b6d4" stopOpacity="0" />
</linearGradient>
</defs>
</svg>
</div>
)
}
function PlayIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" {...props}>
<circle cx="12" cy="12" r="11.5" stroke="#D4D4D4" />
<path
d="M9.5 14.382V9.618a.5.5 0 0 1 .724-.447l4.764 2.382a.5.5 0 0 1 0 .894l-4.764 2.382a.5.5 0 0 1-.724-.447Z"
fill="#A3A3A3"
stroke="#A3A3A3"
/>
</svg>
)
}
export function Hero() {
return (
<div className="overflow-hidden py-20 sm:py-32 lg:pb-32 xl:pb-36">
<Container>
<div className="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">
<h1 className="text-4xl font-medium tracking-tight text-gray-900">
Mycelium
</h1>
<h2 className="mt-6 text-2xl tracking-tight text-gray-600">
Unleashing the Power of Decentralized Networks
</h2>
<p className="mt-6 text-lg text-gray-600">
Discover Mycelium, an end-to-end encrypted IPv6 overlay network. The future of secure, efficient, and scalable networking.
</p>
<p className="mt-6 text-lg text-gray-600">
Coming Soon: New Decentralized Features
</p>
<div className="mt-8 flex flex-wrap gap-x-6 gap-y-4">
<DownloadLink />
<Button
href="https://youtu.be/4oq15lxvkts?si=Heh_8DHqHaNpy3_F"
variant="outline"
>
<PlayIcon className="h-6 w-6 flex-none" />
<span className="ml-2.5">Watch the Demo</span>
</Button>
</div>
</div>
<div className="relative mt-10 sm:mt-20 lg:col-span-5 lg:row-span-2 lg:mt-0 xl:col-span-6">
<BackgroundIllustration className="absolute top-4 left-1/2 h-[1026px] w-[1026px] -translate-x-1/3 mask-[linear-gradient(to_bottom,white_20%,transparent_75%)] stroke-gray-300/70 sm:top-16 sm:-translate-x-1/2 lg:-top-16 lg:ml-12 xl:-top-14 xl:ml-0" />
<div className="-mx-4 h-[448px] mask-[linear-gradient(to_bottom,white_60%,transparent)] px-9 sm:mx-0 lg:absolute lg:-inset-x-10 lg:-top-10 lg:-bottom-20 lg:h-auto lg:px-0 lg:pt-10 xl:-bottom-32">
<PhoneFrame className="mx-auto max-w-[366px]" priority>
<AppDemo />
</PhoneFrame>
</div>
</div>
<div className="relative -mt-4 lg:col-span-7 lg:mt-0 xl:col-span-6">
<p className="text-center text-sm font-semibold text-gray-900 lg:text-left">
As featured in
</p>
<ul
role="list"
className="mx-auto mt-8 flex max-w-xl flex-wrap justify-center gap-x-10 gap-y-8 lg:mx-0 lg:justify-start"
>
{[
['Forbes', logoForbes],
['TechCrunch', logoTechcrunch],
['Wired', logoWired],
['CNN', logoCnn, 'hidden xl:block'],
['BBC', logoBbc],
['CBS', logoCbs],
['Fast Company', logoFastCompany],
['HuffPost', logoHuffpost, 'hidden xl:block'],
].map(([name, logo, className]) => (
<li key={name} className={clsx('flex', className)}>
<Image src={logo} alt={name} className="h-8" unoptimized />
</li>
))}
</ul>
</div>
</div>
</Container>
</div>
)
}

12
src/components/Layout.tsx Normal file
View File

@@ -0,0 +1,12 @@
import { Footer } from '@/components/Footer'
import { Header } from '@/components/Header'
export function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<Header />
<main className="flex-auto">{children}</main>
<Footer />
</>
)
}

View File

@@ -0,0 +1,36 @@
import Link from 'next/link'
import clsx from 'clsx'
export function LinuxLink({
color = 'black',
}: {
color?: 'black' | 'white'
}) {
return (
<Link
href="#"
aria-label="Download for Linux"
className={clsx(
'flex items-center rounded-lg transition-colors px-4 py-2',
color === 'black'
? 'bg-gray-800 text-white hover:bg-gray-900'
: 'bg-white text-gray-900 hover:bg-gray-50',
)}
>
{/* Linux SVG */}
<svg
viewBox="0 0 266 312"
aria-hidden="true"
className="h-5 w-5 mr-3"
>
<path d="M128.6640625 79.2793c0 1-1 1-1 1h-1c-1 0-1-1-2-2 0 0-1-1-1-2s0-1 1-1l2 1c1 1 2 2 2 3m-18-10c0-5-2-8-5-8 0 0 0 1-1 1v2h3c0 2 1 3 1 5h2m35-5c2 0 3 2 4 5h2c-1-1-1-2-1-3s0-2-1-3-2-2-3-2c0 0-1 1-2 1 0 1 1 1 1 2m-30 16c-1 0-1 0-1-1s0-2 1-3c2 0 3-1 3-1 1 0 1 1 1 1 0 1-1 2-3 4h-1m-11-1c-4-2-5-5-5-10 0-3 0-5 2-7 1-2 3-3 5-3s3 1 5 3c1 3 2 6 2 9v2h1v-1c1 0 1-2 1-6 0-3 0-6-2-9s-4-5-8-5c-3 0-6 2-7 5-2 4-2.4 7-2.4 12 0 4 1.4 8 5.4 12 1-1 2-1 3-2m125 141c1 0 1-.4 1-1.3 0-2.2-1-4.8-4-7.7-3-3-8-4.9-14-5.7-1-.1-2-.1-2-.1-1-.2-1-.2-2-.2-1-.1-3-.3-4-.5 3-9.3 4-17.5 4-24.7 0-10-2-17-6-23s-8-9-13-10c-1 1-1 1-1 2 5 2 10 6 13 12 3 7 4 13 4 20 0 5.6-1 13.9-5 24.5-4 1.6-8 5.3-11 11.1 0 .9 0 1.4 1 1.4 0 0 1-.9 2-2.6 2-1.7 3-3.4 5-5.1 3-1.7 5-2.6 8-2.6 5 0 10 .7 13 2.1 4 1.3 6 2.7 7 4.3 1 1.5 2 2.9 3 4.2 0 1.3 1 1.9 1 1.9m-92-145c-1-1-1-3-1-5 0-4 0-6 2-9 2-2 4-3 6-3 3 0 5 2 7 4 1 3 2 5 2 8 0 5-2 8-6 9 0 0 1 1 2 1 2 0 3 1 5 2 1-6 2-10 2-15 0-6-1-10-3-13-3-3-6-4-10-4-3 0-6 1-9 3-2 3-3 5-3 8 0 5 1 9 3 13 1 0 2 1 3 1m12 16c-13 9-23 13-31 13-7 0-14-3-20-8 1 2 2 4 3 5l6 6c4 4 9 6 14 6 7 0 15-4 25-11l9-6c2-2 4-4 4-7 0-1 0-2-1-2-1-2-6-5-16-8-9-4-16-6-20-6-3 0-8 2-15 6-6 4-10 8-10 12 0 0 1 1 2 3 6 5 12 8 18 8 8 0 18-4 31-14v2c1 0 1 1 1 1m23 202c4 7.52 11 11.3 19 11.3 2 0 4-.3 6-.9 2-.4 4-1.1 5-1.9 1-.7 2-1.4 3-2.2 2-.7 2-1.2 3-1.7l17-14.7c4-3.19 8-5.98 13-8.4 4-2.4 8-4 10-4.9 3-.8 5-2 7-3.6 1-1.5 2-3.4 2-5.8 0-2.9-2-5.1-4-6.7s-4-2.7-6-3.4-4-2.3-7-5c-2-2.6-4-6.2-5-10.9l-1-5.8c-1-2.7-1-4.7-2-5.8 0-.3 0-.4-1-.4s-3 .9-4 2.6c-2 1.7-4 3.6-6 5.6-1 2-4 3.8-6 5.5-3 1.7-6 2.6-8 2.6-8 0-12-2.2-15-6.5-2-3.2-3-6.9-4-11.1-2-1.7-3-2.6-5-2.6-5 0-7 5.2-7 15.7v31.1c0 .9-1 2.9-1 6-1 3.1-1 6.62-1 10.6l-2 11.1v.17m-145-5.29c9.3 1.36 20 4.27 32.1 8.71 12.1 4.4 19.5 6.7 22.2 6.7 7 0 12.8-3.1 17.6-9.09 1-1.94 1-4.22 1-6.84 0-9.45-5.7-21.4-17.1-35.9l-6.8-9.1c-1.4-1.9-3.1-4.8-5.3-8.7-2.1-3.9-4-6.9-5.5-9-1.3-2.3-3.4-4.6-6.1-6.9-2.6-2.3-5.6-3.8-8.9-4.6-4.2.8-7.1 2.2-8.5 4.1s-2.2 4-2.4 6.2c-.3 2.1-.9 3.5-1.9 4.2-1 .6-2.7 1.1-5 1.6-.5 0-1.4 0-2.7.1h-2.7c-5.3 0-8.9.6-10.8 1.6-2.5 2.9-3.8 6.2-3.8 9.7 0 1.6.4 4.3 1.2 8.1.8 3.7 1.2 6.7 1.2 8.8 0 4.1-1.2 8.2-3.7 12.3-2.5 4.3-3.8 7.5-3.8 9.78 1 3.88 7.6 6.61 19.7 8.21m33.3-90.9c0-6.9 1.8-14.5 5.5-23.5 3.6-9 7.2-15 10.7-19-.2-1-.7-1-1.5-1l-1-1c-2.9 3-6.4 10-10.6 20-4.2 9-6.4 17.3-6.4 23.4 0 4.5 1.1 8.4 3.1 11.8 2.2 3.3 7.5 8.1 15.9 14.2l10.6 6.9c11.3 9.8 17.3 16.6 17.3 20.6 0 2.1-1 4.2-4 6.5-2 2.4-4.7 3.6-7 3.6-.2 0-.3.2-.3.7 0 .1 1 2.1 3.1 6 4.2 5.7 13.2 8.5 25.2 8.5 22 0 39-9 52-27 0-5 0-8.1-1-9.4v-3.7c0-6.5 1-11.4 3-14.6s4-4.7 7-4.7c2 0 4 .7 6 2.2 1-7.7 1-14.4 1-20.4 0-9.1 0-16.6-2-23.6-1-6-3-11-5-15l-6-9c-2-3-3-6-5-9-1-4-2-7-2-12-3-5-5-10-8-15-2-5-4-10-6-14l-9 7c-10 7-18 10-25 10-6 0-11-1-14-5l-6-5c0 3-1 7-3 11l-6.3 12c-2.8 7-4.3 11-4.6 14-.4 2-.7 4-.9 4l-7.5 15c-8.1 15-12.2 28.9-12.2 40.4 0 2.3.2 4.7.6 7.1-4.5-3.1-6.7-7.4-6.7-13m71.6 94.6c-13 0-23 1.76-30 5.25v-.3c-5 6-10.6 9.1-18.4 9.1-4.9 0-12.6-1.9-23-5.7-10.5-3.6-19.8-6.36-27.9-8.18-.8-.23-2.6-.57-5.5-1.03-2.8-.45-5.4-.91-7.7-1.37-2.1-.45-4.5-1.13-7.1-2.05-2.5-.79-4.5-1.82-6-3.07-1.38-1.26-2.06-2.68-2.06-4.27 0-1.6.34-3.31 1.02-5.13.64-1.1 1.34-2.2 2.04-3.2.7-1.1 1.3-2.1 1.7-3.1.6-.9 1-1.8 1.4-2.8.4-.9.8-1.8 1-2.9.2-1 .4-2 .4-3s-.4-4-1.2-9.3c-.8-5.2-1.2-8.5-1.2-9.9 0-4.4 1-7.9 3.2-10.4s4.3-3.8 6.5-3.8h11.5c.9 0 2.3-.5 4.4-1.7.7-1.6 1.3-2.9 1.7-4.1.5-1.2.7-2.1.9-2.5.2-.6.4-1.2.6-1.7.4-.7.9-1.5 1.6-2.3-.8-1-1.2-2.3-1.2-3.9 0-1.1 0-2.1.2-2.7 0-3.6 1.7-8.7 5.3-15.4l3.5-6.3c2.9-5.4 5.1-9.4 6.7-13.4 1.7-4 3.5-10 5.5-18 1.6-7 5.4-14 11.4-21l7.5-9c5.2-6 8.6-11 10.5-15s2.9-9 2.9-13c0-2-.5-8-1.6-18-1-10-1.5-20-1.5-29 0-7 .6-12 1.9-17s3.6-10 7-14c3-4 7-8 13-10s13-3 21-3c3 0 6 0 9 1 3 0 7 1 12 3 4 2 8 4 11 7 4 3 7 8 10 13 2 6 4 12 5 20 1 5 1 10 2 17 0 6 1 10 1 13 1 3 1 7 2 12 1 4 2 8 4 11 2 4 4 8 7 12 3 5 7 10 11 16 9 10 16 21 20 32 5 10 8 23 8 36.9 0 6.9-1 13.6-3 20.1 2 0 3 .8 4 2.2s2 4.4 3 9.1l1 7.4c1 2.2 2 4.3 5 6.1 2 1.8 4 3.3 7 4.5 2 1 5 2.4 7 4.2 2 2 3 4.1 3 6.3 0 3.4-1 5.9-3 7.7-2 2-4 3.4-7 4.3-2 1-6 3-12 5.82-5 2.96-10 6.55-15 10.8l-10 8.51c-4 3.9-8 6.7-11 8.4-3 1.8-7 2.7-11 2.7l-7-.8c-8-2.1-13-6.1-16-12.2-16-1.94-29-2.9-37-2.9" fill="currentColor" />
</svg>
{/* Text */}
<div className="flex flex-col text-left leading-tight">
<span className="text-[9px] mt-0">Download for</span>
<span className="text-sm font-semibold -mt-1.5">Linux</span>
</div>
</Link>
)
}

95
src/components/Logo.tsx Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,51 @@
'use client'
import { useRef, useState } from 'react'
import Link from 'next/link'
import { AnimatePresence, motion } from 'framer-motion'
export function NavLinks() {
let [hoveredIndex, setHoveredIndex] = useState<number | null>(null)
let timeoutRef = useRef<number | null>(null)
return [
['About', '/#about'],
['Benefits', '/#benefits'],
['Features', '/#features'],
['Use Cases', '/#usecases'],
['FAQs', '/#faqs'],
].map(([label, href], index) => (
<Link
key={label}
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"
onMouseEnter={() => {
if (timeoutRef.current) {
window.clearTimeout(timeoutRef.current)
}
setHoveredIndex(index)
}}
onMouseLeave={() => {
timeoutRef.current = window.setTimeout(() => {
setHoveredIndex(null)
}, 200)
}}
>
<AnimatePresence>
{hoveredIndex === index && (
<motion.span
className="absolute inset-0 rounded-lg bg-gray-100"
layoutId="hoverBackground"
initial={{ opacity: 0 }}
animate={{ opacity: 1, transition: { duration: 0.15 } }}
exit={{
opacity: 0,
transition: { duration: 0.15 },
}}
/>
)}
</AnimatePresence>
<span className="relative z-10">{label}</span>
</Link>
))
}

View File

@@ -0,0 +1,42 @@
import Image from 'next/image'
import clsx from 'clsx'
import frame from '@/images/phone-frame.svg'
function PlaceholderFrame(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 366 729" aria-hidden="true" {...props}>
<path
fill="#F2F2F2"
fillRule="evenodd"
clipRule="evenodd"
d="M300.092 1c41.22 0 63.223 21.99 63.223 63.213V184.94c-.173.184-.329.476-.458.851.188-.282.404-.547.647-.791.844-.073 2.496.257 2.496 2.157V268.719c-.406 2.023-2.605 2.023-2.605 2.023a7.119 7.119 0 0 1-.08-.102v394.462c0 41.213-22.001 63.212-63.223 63.212h-95.074c-.881-.468-2.474-.795-4.323-.838l-33.704-.005-.049.001h-.231l-.141-.001c-2.028 0-3.798.339-4.745.843H66.751c-41.223 0-63.223-21.995-63.223-63.208V287.739c-.402-.024-2.165-.23-2.524-2.02v-.973A2.039 2.039 0 0 1 1 284.62v-47.611c0-.042.001-.084.004-.126v-.726c0-1.9 1.652-2.23 2.496-2.157l.028.028v-16.289c-.402-.024-2.165-.23-2.524-2.02v-.973A2.039 2.039 0 0 1 1 214.62v-47.611c0-.042.001-.084.004-.126v-.726c0-1.9 1.652-2.23 2.496-2.157l.028.028v-26.041a2.26 2.26 0 0 0 .093-.236l-.064-.01a3.337 3.337 0 0 1-.72-.12l-.166-.028A2 2 0 0 1 1 135.62v-24.611a2 2 0 0 1 1.671-1.973l.857-.143v-44.68C3.528 22.99 25.53 1 66.75 1h233.341ZM3.952 234.516a5.481 5.481 0 0 0-.229-.278c.082.071.159.163.228.278Zm89.99-206.304A4.213 4.213 0 0 0 89.727 24H56.864C38.714 24 24 38.708 24 56.852v618.296C24 693.292 38.714 708 56.864 708h250.272c18.15 0 32.864-14.708 32.864-32.852V56.852C340 38.708 325.286 24 307.136 24h-32.864a4.212 4.212 0 0 0-4.213 4.212v2.527c0 10.235-8.3 18.532-18.539 18.532H112.48c-10.239 0-18.539-8.297-18.539-18.532v-2.527Z"
/>
<rect x="154" y="29" width="56" height="5" rx="2.5" fill="#D4D4D4" />
</svg>
)
}
export function PhoneFrame({
className,
children,
priority = false,
...props
}: React.ComponentPropsWithoutRef<'div'> & { priority?: boolean }) {
return (
<div className={clsx('relative aspect-366/729', className)} {...props}>
<div className="absolute inset-y-[calc(1/729*100%)] right-[calc(5/729*100%)] left-[calc(7/729*100%)] rounded-[calc(58/366*100%)/calc(58/729*100%)] shadow-2xl" />
<div className="absolute top-[calc(23/729*100%)] left-[calc(23/366*100%)] grid h-[calc(686/729*100%)] w-[calc(318/366*100%)] transform grid-cols-1 overflow-hidden bg-gray-900 pt-[calc(23/318*100%)]">
{children}
</div>
<PlaceholderFrame className="pointer-events-none absolute inset-0 h-full w-full fill-gray-100" />
<Image
src={frame}
alt=""
className="pointer-events-none absolute inset-0 h-full w-full"
unoptimized
priority={priority}
/>
</div>
)
}

288
src/components/Pricing.tsx Normal file
View File

@@ -0,0 +1,288 @@
'use client'
import { useState } from 'react'
import { Radio, RadioGroup } from '@headlessui/react'
import clsx from 'clsx'
import { Button } from '@/components/Button'
import { Container } from '@/components/Container'
import { Logomark } from '@/components/Logo'
const plans = [
{
name: 'Starter',
featured: false,
price: { Monthly: '$0', Annually: '$0' },
description:
'Youre new to investing but want to do it right. Get started for free.',
button: {
label: 'Get started for free',
href: '/register',
},
features: [
'Commission-free trading',
'Multi-layered encryption',
'One tip every day',
'Invest up to $1,500 each month',
],
logomarkClassName: 'fill-gray-300',
},
{
name: 'Investor',
featured: false,
price: { Monthly: '$7', Annually: '$70' },
description:
'Youve been investing for a while. Invest more and grow your wealth faster.',
button: {
label: 'Subscribe',
href: '/register',
},
features: [
'Commission-free trading',
'Multi-layered encryption',
'One tip every hour',
'Invest up to $15,000 each month',
'Basic transaction anonymization',
],
logomarkClassName: 'fill-gray-500',
},
{
name: 'VIP',
featured: true,
price: { Monthly: '$199', Annually: '$1,990' },
description:
'Youve got a huge amount of assets but its not enough. To the moon.',
button: {
label: 'Subscribe',
href: '/register',
},
features: [
'Commission-free trading',
'Multi-layered encryption',
'Real-time tip notifications',
'No investment limits',
'Advanced transaction anonymization',
'Automated tax-loss harvesting',
],
logomarkClassName: 'fill-cyan-500',
},
]
function CheckIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 24 24" aria-hidden="true" {...props}>
<path
d="M9.307 12.248a.75.75 0 1 0-1.114 1.004l1.114-1.004ZM11 15.25l-.557.502a.75.75 0 0 0 1.15-.043L11 15.25Zm4.844-5.041a.75.75 0 0 0-1.188-.918l1.188.918Zm-7.651 3.043 2.25 2.5 1.114-1.004-2.25-2.5-1.114 1.004Zm3.4 2.457 4.25-5.5-1.187-.918-4.25 5.5 1.188.918Z"
fill="currentColor"
/>
<circle
cx="12"
cy="12"
r="8.25"
fill="none"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
function Plan({
name,
price,
description,
button,
features,
activePeriod,
logomarkClassName,
featured = false,
}: {
name: string
price: {
Monthly: string
Annually: string
}
description: string
button: {
label: string
href: string
}
features: Array<string>
activePeriod: 'Monthly' | 'Annually'
logomarkClassName?: string
featured?: boolean
}) {
return (
<section
className={clsx(
'flex flex-col overflow-hidden rounded-3xl p-6 shadow-lg shadow-gray-900/5',
featured ? 'order-first bg-gray-900 lg:order-none' : 'bg-white',
)}
>
<h3
className={clsx(
'flex items-center text-sm font-semibold',
featured ? 'text-white' : 'text-gray-900',
)}
>
<Logomark className={clsx('h-6 w-6 flex-none', logomarkClassName)} />
<span className="ml-4">{name}</span>
</h3>
<p
className={clsx(
'relative mt-5 flex text-3xl tracking-tight',
featured ? 'text-white' : 'text-gray-900',
)}
>
{price.Monthly === price.Annually ? (
price.Monthly
) : (
<>
<span
aria-hidden={activePeriod === 'Annually'}
className={clsx(
'transition duration-300',
activePeriod === 'Annually' &&
'pointer-events-none translate-x-6 opacity-0 select-none',
)}
>
{price.Monthly}
</span>
<span
aria-hidden={activePeriod === 'Monthly'}
className={clsx(
'absolute top-0 left-0 transition duration-300',
activePeriod === 'Monthly' &&
'pointer-events-none -translate-x-6 opacity-0 select-none',
)}
>
{price.Annually}
</span>
</>
)}
</p>
<p
className={clsx(
'mt-3 text-sm',
featured ? 'text-gray-300' : 'text-gray-700',
)}
>
{description}
</p>
<div className="order-last mt-6">
<ul
role="list"
className={clsx(
'-my-2 divide-y text-sm',
featured
? 'divide-gray-800 text-gray-300'
: 'divide-gray-200 text-gray-700',
)}
>
{features.map((feature) => (
<li key={feature} className="flex py-2">
<CheckIcon
className={clsx(
'h-6 w-6 flex-none',
featured ? 'text-white' : 'text-cyan-500',
)}
/>
<span className="ml-4">{feature}</span>
</li>
))}
</ul>
</div>
<Button
href={button.href}
color={featured ? 'cyan' : 'gray'}
className="mt-6"
aria-label={`Get started with the ${name} plan for ${price}`}
>
{button.label}
</Button>
</section>
)
}
export function Pricing() {
let [activePeriod, setActivePeriod] = useState<'Monthly' | 'Annually'>(
'Monthly',
)
return (
<section
id="pricing"
aria-labelledby="pricing-title"
className="border-t border-gray-200 bg-gray-100 py-20 sm:py-32"
>
<Container>
<div className="mx-auto max-w-2xl text-center">
<h2
id="pricing-title"
className="text-3xl font-medium tracking-tight text-gray-900"
>
Flat pricing, no management fees.
</h2>
<p className="mt-2 text-lg text-gray-600">
Whether youre one person trying to get ahead or a big firm trying
to take over the world, weve got a plan for you.
</p>
</div>
<div className="mt-8 flex justify-center">
<div className="relative">
<RadioGroup
value={activePeriod}
onChange={setActivePeriod}
className="grid grid-cols-2"
>
{['Monthly', 'Annually'].map((period) => (
<Radio
key={period}
value={period}
className={clsx(
'cursor-pointer border border-gray-300 px-[calc(--spacing(3)-1px)] py-[calc(--spacing(2)-1px)] text-sm text-gray-700 transition-colors hover:border-gray-400 data-focus:outline-2 data-focus:outline-offset-2',
period === 'Monthly'
? 'rounded-l-lg'
: '-ml-px rounded-r-lg',
)}
>
{period}
</Radio>
))}
</RadioGroup>
<div
aria-hidden="true"
className={clsx(
'pointer-events-none absolute inset-0 z-10 grid grid-cols-2 overflow-hidden rounded-lg bg-cyan-500 transition-all duration-300',
activePeriod === 'Monthly'
? '[clip-path:inset(0_50%_0_0)]'
: '[clip-path:inset(0_0_0_calc(50%-1px))]',
)}
>
{['Monthly', 'Annually'].map((period) => (
<div
key={period}
className={clsx(
'py-2 text-center text-sm font-semibold text-white',
period === 'Annually' && '-ml-px',
)}
>
{period}
</div>
))}
</div>
</div>
</div>
<div className="mx-auto mt-16 grid max-w-2xl grid-cols-1 items-start gap-x-8 gap-y-10 sm:mt-20 lg:max-w-none lg:grid-cols-3">
{plans.map((plan) => (
<Plan key={plan.name} {...plan} activePeriod={activePeriod} />
))}
</div>
</Container>
</section>
)
}

View File

@@ -0,0 +1,595 @@
'use client'
import { Fragment, useEffect, useId, useRef, useState } from 'react'
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '@headlessui/react'
import clsx from 'clsx'
import {
type MotionProps,
type Variant,
type Variants,
AnimatePresence,
motion,
} from 'framer-motion'
import { useDebouncedCallback } from 'use-debounce'
import { AppScreen } from '@/components/AppScreen'
import { CircleBackground } from '@/components/CircleBackground'
import { Container } from '@/components/Container'
import { PhoneFrame } from '@/components/PhoneFrame'
import {
DiageoLogo,
LaravelLogo,
MirageLogo,
ReversableLogo,
StatamicLogo,
StaticKitLogo,
TransistorLogo,
TupleLogo,
} from '@/components/StockLogos'
const MotionAppScreenHeader = motion(AppScreen.Header)
const MotionAppScreenBody = motion(AppScreen.Body)
interface CustomAnimationProps {
isForwards: boolean
changeCount: number
}
const features = [
{
name: 'Decentralized Nodes',
description:
"Mycelium operates through a network of decentralized nodes, similar to how nature's mycelium forms a decentralized network of threads. Each node acts as a connection point in the overall digital ecosystem.",
icon: DeviceUserIcon,
screen: InviteScreen,
},
{
name: 'Efficient Data Routing',
description:
'Mycelium optimizes data routing by choosing the most efficient path for communication. Data travels along the shortest path in terms of latency, ensuring that information reaches its destination swiftly.',
icon: DeviceNotificationIcon,
screen: StocksScreen,
},
{
name: 'End-to-End Encryption',
description:
'Each node in the system is identified by a unique key pair. Data between nodes is encrypted using secret keys derived from these pairs. This ensures that data remains confidential, enhancing the privacy of the network.',
icon: DeviceTouchIcon,
screen: InvestScreen,
},
]
function DeviceUserIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 32 32" aria-hidden="true" {...props}>
<circle cx={16} cy={16} r={16} fill="#A3A3A3" fillOpacity={0.2} />
<path
fillRule="evenodd"
clipRule="evenodd"
d="M16 23a3 3 0 100-6 3 3 0 000 6zm-1 2a4 4 0 00-4 4v1a2 2 0 002 2h6a2 2 0 002-2v-1a4 4 0 00-4-4h-2z"
fill="#737373"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5 4a4 4 0 014-4h14a4 4 0 014 4v24a4.002 4.002 0 01-3.01 3.877c-.535.136-.99-.325-.99-.877s.474-.98.959-1.244A2 2 0 0025 28V4a2 2 0 00-2-2h-1.382a1 1 0 00-.894.553l-.448.894a1 1 0 01-.894.553h-6.764a1 1 0 01-.894-.553l-.448-.894A1 1 0 0010.382 2H9a2 2 0 00-2 2v24a2 2 0 001.041 1.756C8.525 30.02 9 30.448 9 31s-.455 1.013-.99.877A4.002 4.002 0 015 28V4z"
fill="#A3A3A3"
/>
</svg>
)
}
function DeviceNotificationIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 32 32" aria-hidden="true" {...props}>
<circle cx={16} cy={16} r={16} fill="#A3A3A3" fillOpacity={0.2} />
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9 0a4 4 0 00-4 4v24a4 4 0 004 4h14a4 4 0 004-4V4a4 4 0 00-4-4H9zm0 2a2 2 0 00-2 2v24a2 2 0 002 2h14a2 2 0 002-2V4a2 2 0 00-2-2h-1.382a1 1 0 00-.894.553l-.448.894a1 1 0 01-.894.553h-6.764a1 1 0 01-.894-.553l-.448-.894A1 1 0 0010.382 2H9z"
fill="#A3A3A3"
/>
<path
d="M9 8a2 2 0 012-2h10a2 2 0 012 2v2a2 2 0 01-2 2H11a2 2 0 01-2-2V8z"
fill="#737373"
/>
</svg>
)
}
function DeviceTouchIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
let id = useId()
return (
<svg viewBox="0 0 32 32" fill="none" aria-hidden="true" {...props}>
<defs>
<linearGradient
id={`${id}-gradient`}
x1={14}
y1={14.5}
x2={7}
y2={17}
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#737373" />
<stop offset={1} stopColor="#D4D4D4" stopOpacity={0} />
</linearGradient>
</defs>
<circle cx={16} cy={16} r={16} fill="#A3A3A3" fillOpacity={0.2} />
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5 4a4 4 0 014-4h14a4 4 0 014 4v13h-2V4a2 2 0 00-2-2h-1.382a1 1 0 00-.894.553l-.448.894a1 1 0 01-.894.553h-6.764a1 1 0 01-.894-.553l-.448-.894A1 1 0 0010.382 2H9a2 2 0 00-2 2v24a2 2 0 002 2h4v2H9a4 4 0 01-4-4V4z"
fill="#A3A3A3"
/>
<path
d="M7 22c0-4.694 3.5-8 8-8"
stroke={`url(#${id}-gradient)`}
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M21 20l.217-5.513a1.431 1.431 0 00-2.85-.226L17.5 21.5l-1.51-1.51a2.107 2.107 0 00-2.98 0 .024.024 0 00-.005.024l3.083 9.25A4 4 0 0019.883 32H25a4 4 0 004-4v-5a3 3 0 00-3-3h-5z"
fill="#A3A3A3"
/>
</svg>
)
}
const headerAnimation: Variants = {
initial: { opacity: 0, transition: { duration: 0.3 } },
animate: { opacity: 1, transition: { duration: 0.3, delay: 0.3 } },
exit: { opacity: 0, transition: { duration: 0.3 } },
}
const maxZIndex = 2147483647
const bodyVariantBackwards: Variant = {
opacity: 0.4,
scale: 0.8,
zIndex: 0,
filter: 'blur(4px)',
transition: { duration: 0.4 },
}
const bodyVariantForwards: Variant = (custom: CustomAnimationProps) => ({
y: '100%',
zIndex: maxZIndex - custom.changeCount,
transition: { duration: 0.4 },
})
const bodyAnimation: MotionProps = {
initial: 'initial',
animate: 'animate',
exit: 'exit',
variants: {
initial: (custom: CustomAnimationProps, ...props) =>
custom.isForwards
? bodyVariantForwards(custom, ...props)
: bodyVariantBackwards,
animate: (custom: CustomAnimationProps) => ({
y: '0%',
opacity: 1,
scale: 1,
zIndex: maxZIndex / 2 - custom.changeCount,
filter: 'blur(0px)',
transition: { duration: 0.4 },
}),
exit: (custom: CustomAnimationProps, ...props) =>
custom.isForwards
? bodyVariantBackwards
: bodyVariantForwards(custom, ...props),
},
}
type ScreenProps =
| {
animated: true
custom: CustomAnimationProps
}
| { animated?: false }
function InviteScreen(props: ScreenProps) {
return (
<AppScreen className="w-full">
<MotionAppScreenHeader {...(props.animated ? headerAnimation : {})}>
<AppScreen.Title>Invite people</AppScreen.Title>
<AppScreen.Subtitle>
Get tips <span className="text-white">5s sooner</span> for every
invite.
</AppScreen.Subtitle>
</MotionAppScreenHeader>
<MotionAppScreenBody
{...(props.animated ? { ...bodyAnimation, custom: props.custom } : {})}
>
<div className="px-4 py-6">
<div className="space-y-6">
{[
{ label: 'Full name', value: 'Albert H. Wiggin' },
{ label: 'Email address', value: 'awiggin@chase.com' },
].map((field) => (
<div key={field.label}>
<div className="text-sm text-gray-500">{field.label}</div>
<div className="mt-2 border-b border-gray-200 pb-2 text-sm text-gray-900">
{field.value}
</div>
</div>
))}
</div>
<div className="mt-6 rounded-lg bg-cyan-500 px-3 py-2 text-center text-sm font-semibold text-white">
Invite person
</div>
</div>
</MotionAppScreenBody>
</AppScreen>
)
}
function StocksScreen(props: ScreenProps) {
return (
<AppScreen className="w-full">
<MotionAppScreenHeader {...(props.animated ? headerAnimation : {})}>
<AppScreen.Title>Stocks</AppScreen.Title>
<AppScreen.Subtitle>March 9, 2022</AppScreen.Subtitle>
</MotionAppScreenHeader>
<MotionAppScreenBody
{...(props.animated ? { ...bodyAnimation, custom: props.custom } : {})}
>
<div className="divide-y divide-gray-100">
{[
{
name: 'Laravel',
price: '4,098.01',
change: '+4.98%',
color: '#F9322C',
logo: LaravelLogo,
},
{
name: 'Tuple',
price: '5,451.10',
change: '-3.38%',
color: '#5A67D8',
logo: TupleLogo,
},
{
name: 'Transistor',
price: '4,098.41',
change: '+6.25%',
color: '#2A5B94',
logo: TransistorLogo,
},
{
name: 'Diageo',
price: '250.65',
change: '+1.25%',
color: '#3320A7',
logo: DiageoLogo,
},
{
name: 'StaticKit',
price: '250.65',
change: '-3.38%',
color: '#2A3034',
logo: StaticKitLogo,
},
{
name: 'Statamic',
price: '5,040.85',
change: '-3.11%',
color: '#0EA5E9',
logo: StatamicLogo,
},
{
name: 'Mirage',
price: '140.44',
change: '+9.09%',
color: '#16A34A',
logo: MirageLogo,
},
{
name: 'Reversable',
price: '550.60',
change: '-1.25%',
color: '#8D8D8D',
logo: ReversableLogo,
},
].map((stock) => (
<div key={stock.name} className="flex items-center gap-4 px-4 py-3">
<div
className="flex-none rounded-full"
style={{ backgroundColor: stock.color }}
>
<stock.logo className="h-10 w-10" />
</div>
<div className="flex-auto text-sm text-gray-900">
{stock.name}
</div>
<div className="flex-none text-right">
<div className="text-sm font-medium text-gray-900">
{stock.price}
</div>
<div
className={clsx(
'text-xs/5',
stock.change.startsWith('+')
? 'text-cyan-500'
: 'text-gray-500',
)}
>
{stock.change}
</div>
</div>
</div>
))}
</div>
</MotionAppScreenBody>
</AppScreen>
)
}
function InvestScreen(props: ScreenProps) {
return (
<AppScreen className="w-full">
<MotionAppScreenHeader {...(props.animated ? headerAnimation : {})}>
<AppScreen.Title>Buy $LA</AppScreen.Title>
<AppScreen.Subtitle>
<span className="text-white">$34.28</span> per share
</AppScreen.Subtitle>
</MotionAppScreenHeader>
<MotionAppScreenBody
{...(props.animated ? { ...bodyAnimation, custom: props.custom } : {})}
>
<div className="px-4 py-6">
<div className="space-y-4">
{[
{ label: 'Number of shares', value: '100' },
{
label: 'Current market price',
value: (
<div className="flex">
$34.28
<svg viewBox="0 0 24 24" fill="none" className="h-6 w-6">
<path
d="M17 15V7H9M17 7 7 17"
stroke="#06B6D4"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</div>
),
},
{ label: 'Estimated cost', value: '$3,428.00' },
].map((item) => (
<div
key={item.label}
className="flex justify-between border-b border-gray-100 pb-4"
>
<div className="text-sm text-gray-500">{item.label}</div>
<div className="text-sm font-semibold text-gray-900">
{item.value}
</div>
</div>
))}
<div className="rounded-lg bg-cyan-500 px-3 py-2 text-center text-sm font-semibold text-white">
Buy shares
</div>
</div>
</div>
</MotionAppScreenBody>
</AppScreen>
)
}
function usePrevious<T>(value: T) {
let ref = useRef<T>()
useEffect(() => {
ref.current = value
}, [value])
return ref.current
}
function FeaturesDesktop() {
let [changeCount, setChangeCount] = useState(0)
let [selectedIndex, setSelectedIndex] = useState(0)
let prevIndex = usePrevious(selectedIndex)
let isForwards = prevIndex === undefined ? true : selectedIndex > prevIndex
let onChange = useDebouncedCallback(
(selectedIndex) => {
setSelectedIndex(selectedIndex)
setChangeCount((changeCount) => changeCount + 1)
},
100,
{ leading: true },
)
return (
<TabGroup
className="grid grid-cols-12 items-center gap-8 lg:gap-16 xl:gap-24"
selectedIndex={selectedIndex}
onChange={onChange}
vertical
>
<TabList className="relative z-10 order-last col-span-6 space-y-6">
{features.map((feature, featureIndex) => (
<div
key={feature.name}
className="relative rounded-2xl transition-colors hover:bg-gray-800/30"
>
{featureIndex === selectedIndex && (
<motion.div
layoutId="activeBackground"
className="absolute inset-0 bg-gray-800"
initial={{ borderRadius: 16 }}
/>
)}
<div className="relative z-10 p-8">
<feature.icon className="h-8 w-8" />
<h3 className="mt-6 text-lg font-semibold text-white">
<Tab className="text-left data-selected:not-data-focus:outline-hidden">
<span className="absolute inset-0 rounded-2xl" />
{feature.name}
</Tab>
</h3>
<p className="mt-2 text-sm text-gray-400">
{feature.description}
</p>
</div>
</div>
))}
</TabList>
<div className="relative col-span-6">
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
<CircleBackground color="#13B5C8" className="animate-spin-slower" />
</div>
<PhoneFrame className="z-10 mx-auto w-full max-w-[366px]">
<TabPanels as={Fragment}>
<AnimatePresence
initial={false}
custom={{ isForwards, changeCount }}
>
{features.map((feature, featureIndex) =>
selectedIndex === featureIndex ? (
<TabPanel
static
key={feature.name + changeCount}
className="col-start-1 row-start-1 flex focus:outline-offset-32 data-selected:not-data-focus:outline-hidden"
>
<feature.screen
animated
custom={{ isForwards, changeCount }}
/>
</TabPanel>
) : null,
)}
</AnimatePresence>
</TabPanels>
</PhoneFrame>
</div>
</TabGroup>
)
}
function FeaturesMobile() {
let [activeIndex, setActiveIndex] = useState(0)
let slideContainerRef = useRef<React.ElementRef<'div'>>(null)
let slideRefs = useRef<Array<React.ElementRef<'div'>>>([])
useEffect(() => {
let observer = new window.IntersectionObserver(
(entries) => {
for (let entry of entries) {
if (entry.isIntersecting && entry.target instanceof HTMLDivElement) {
setActiveIndex(slideRefs.current.indexOf(entry.target))
break
}
}
},
{
root: slideContainerRef.current,
threshold: 0.6,
},
)
for (let slide of slideRefs.current) {
if (slide) {
observer.observe(slide)
}
}
return () => {
observer.disconnect()
}
}, [slideContainerRef, slideRefs])
return (
<>
<div
ref={slideContainerRef}
className="-mb-4 flex snap-x snap-mandatory -space-x-4 overflow-x-auto overscroll-x-contain scroll-smooth pb-4 [scrollbar-width:none] sm:-space-x-6 [&::-webkit-scrollbar]:hidden"
>
{features.map((feature, featureIndex) => (
<div
key={featureIndex}
ref={(ref) => ref && (slideRefs.current[featureIndex] = ref)}
className="w-full flex-none snap-center px-4 sm:px-6"
>
<div className="relative transform overflow-hidden rounded-2xl bg-gray-800 px-5 py-6">
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
<CircleBackground
color="#13B5C8"
className={featureIndex % 2 === 1 ? 'rotate-180' : undefined}
/>
</div>
<PhoneFrame className="relative mx-auto w-full max-w-[366px]">
<feature.screen />
</PhoneFrame>
<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" />
<h3 className="mt-6 text-sm font-semibold text-white sm:text-lg">
{feature.name}
</h3>
<p className="mt-2 text-sm text-gray-400">
{feature.description}
</p>
</div>
</div>
</div>
))}
</div>
<div className="mt-6 flex justify-center gap-3">
{features.map((_, featureIndex) => (
<button
type="button"
key={featureIndex}
className={clsx(
'relative h-0.5 w-4 rounded-full',
featureIndex === activeIndex ? 'bg-gray-300' : 'bg-gray-500',
)}
aria-label={`Go to slide ${featureIndex + 1}`}
onClick={() => {
slideRefs.current[featureIndex].scrollIntoView({
block: 'nearest',
inline: 'nearest',
})
}}
>
<span className="absolute -inset-x-1.5 -inset-y-3" />
</button>
))}
</div>
</>
)
}
export function PrimaryFeatures() {
return (
<section
id="features"
aria-label="Features for investing all your money"
className="bg-gray-900 py-20 sm:py-32"
>
<Container>
<div className="mx-auto max-w-2xl lg:mx-0 lg:max-w-3xl">
<h2 className="text-3xl font-medium tracking-tight text-white">
How Mycelium Operates
</h2>
<p className="mt-6 text-lg text-gray-300">
Mycelium, like its natural namesake, thrives on decentralization, efficiency, and security, making it a truly powerful force in the world of decentralized networks.
</p>
</div>
</Container>
<div className="mt-16 md:hidden">
<FeaturesMobile />
</div>
<Container className="hidden md:mt-20 md:block">
<FeaturesDesktop />
</Container>
</section>
)
}

View File

@@ -0,0 +1,225 @@
import { useId } from 'react'
import { Container } from '@/components/Container'
const features = [
{
name: 'Quantum Safe Storage Functionality',
description:
"Mycelium's quantum safe storage enables flexible, scalable, and efficient data distribution across a decentralized network, ensuring redundancy and security.",
icon: DeviceArrowIcon,
},
{
name: 'Entry and Exit Points for AI Workloads',
description:
'Seamlessly connect AI applications to Mycelium, providing optimized and secured data pipelines for training, inference, and real-time processing.',
icon: DeviceCardsIcon,
},
{
name: 'Data Storage and Retrieval Mechanisms',
description:
'Users can choose between storing data locally for quick access or utilizing the distributed grid for enhanced scalability and resilience.',
icon: DeviceClockIcon,
},
{
name: 'Integrated Name Services (DNS)',
description:
'The Integrated DNS system efficiently finds the shortest path between users and websites, automatically balancing loads and identifying alternative routes in case of internet issues.',
icon: DeviceListIcon,
},
{
name: 'Frontend/Backend Integration',
description:
'Mycelium provides seamless integration with existing applications, enabling developers to leverage decentralized storage across both frontend and backend architectures.',
icon: DeviceLockIcon,
},
{
name: 'CDN (Content Delivery Network)',
description:
'Mycelium accelerates data distribution by acting as a decentralized CDN, ensuring fast, secure, and efficient content delivery across global nodes with minimal latency.',
icon: DeviceChartIcon,
},
]
function DeviceArrowIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 32 32" aria-hidden="true" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9 0a4 4 0 00-4 4v24a4 4 0 004 4h14a4 4 0 004-4V4a4 4 0 00-4-4H9zm0 2a2 2 0 00-2 2v24a2 2 0 002 2h14a2 2 0 002-2V4a2 2 0 00-2-2h-1.382a1 1 0 00-.894.553l-.448.894a1 1 0 01-.894.553h-6.764a1 1 0 01-.894-.553l-.448-.894A1 1 0 0010.382 2H9z"
fill="#737373"
/>
<path
d="M12 25l8-8m0 0h-6m6 0v6"
stroke="#171717"
strokeWidth={2}
strokeLinecap="round"
/>
<circle cx={16} cy={16} r={16} fill="#A3A3A3" fillOpacity={0.2} />
</svg>
)
}
function DeviceCardsIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
let id = useId()
return (
<svg viewBox="0 0 32 32" aria-hidden="true" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9 0a4 4 0 00-4 4v24a4 4 0 004 4h14a4 4 0 004-4V4a4 4 0 00-4-4H9zm0 2a2 2 0 00-2 2v24a2 2 0 002 2h14a2 2 0 002-2V4a2 2 0 00-2-2h-1.382a1 1 0 00-.894.553l-.448.894a1 1 0 01-.894.553h-6.764a1 1 0 01-.894-.553l-.448-.894A1 1 0 0010.382 2H9z"
fill="#737373"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9 13a1 1 0 011-1h12a1 1 0 011 1v2a1 1 0 01-1 1H10a1 1 0 01-1-1v-2zm0 6a1 1 0 011-1h12a1 1 0 011 1v2a1 1 0 01-1 1H10a1 1 0 01-1-1v-2zm1 5a1 1 0 00-1 1v2a1 1 0 001 1h12a1 1 0 001-1v-2a1 1 0 00-1-1H10z"
fill={`url(#${id}-gradient)`}
/>
<rect x={9} y={6} width={14} height={4} rx={1} fill="#171717" />
<circle cx={16} cy={16} r={16} fill="#A3A3A3" fillOpacity={0.2} />
<defs>
<linearGradient
id={`${id}-gradient`}
x1={16}
y1={12}
x2={16}
y2={28}
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#737373" />
<stop offset={1} stopColor="#737373" stopOpacity={0} />
</linearGradient>
</defs>
</svg>
)
}
function DeviceClockIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 32 32" aria-hidden="true" {...props}>
<circle cx={16} cy={16} r={16} fill="#A3A3A3" fillOpacity={0.2} />
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5 4a4 4 0 014-4h14a4 4 0 014 4v10h-2V4a2 2 0 00-2-2h-1.382a1 1 0 00-.894.553l-.448.894a1 1 0 01-.894.553h-6.764a1 1 0 01-.894-.553l-.448-.894A1 1 0 0010.382 2H9a2 2 0 00-2 2v24a2 2 0 002 2h5v2H9a4 4 0 01-4-4V4z"
fill="#737373"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M24 32a8 8 0 100-16 8 8 0 000 16zm1-8.414V19h-2v5.414l4 4L28.414 27 25 23.586z"
fill="#171717"
/>
</svg>
)
}
function DeviceListIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 32 32" fill="none" aria-hidden="true" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9 0a4 4 0 00-4 4v24a4 4 0 004 4h14a4 4 0 004-4V4a4 4 0 00-4-4H9zm0 2a2 2 0 00-2 2v24a2 2 0 002 2h14a2 2 0 002-2V4a2 2 0 00-2-2h-1.382a1 1 0 00-.894.553l-.448.894a1 1 0 01-.894.553h-6.764a1 1 0 01-.894-.553l-.448-.894A1 1 0 0010.382 2H9z"
fill="#737373"
/>
<circle cx={11} cy={14} r={2} fill="#171717" />
<circle cx={11} cy={20} r={2} fill="#171717" />
<circle cx={11} cy={26} r={2} fill="#171717" />
<path
d="M16 14h6M16 20h6M16 26h6"
stroke="#737373"
strokeWidth={2}
strokeLinecap="square"
/>
<circle cx={16} cy={16} r={16} fill="#A3A3A3" fillOpacity={0.2} />
</svg>
)
}
function DeviceLockIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 32 32" aria-hidden="true" {...props}>
<circle cx={16} cy={16} r={16} fill="#A3A3A3" fillOpacity={0.2} />
<path
fillRule="evenodd"
clipRule="evenodd"
d="M5 4a4 4 0 014-4h14a4 4 0 014 4v10h-2V4a2 2 0 00-2-2h-1.382a1 1 0 00-.894.553l-.448.894a1 1 0 01-.894.553h-6.764a1 1 0 01-.894-.553l-.448-.894A1 1 0 0010.382 2H9a2 2 0 00-2 2v24a2 2 0 002 2h5v2H9a4 4 0 01-4-4V4z"
fill="#737373"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M18 19.5a3.5 3.5 0 117 0V22a2 2 0 012 2v6a2 2 0 01-2 2h-7a2 2 0 01-2-2v-6a2 2 0 012-2v-2.5zm2 2.5h3v-2.5a1.5 1.5 0 00-3 0V22z"
fill="#171717"
/>
</svg>
)
}
function DeviceChartIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 32 32" fill="none" aria-hidden="true" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9 0a4 4 0 00-4 4v24a4 4 0 004 4h14a4 4 0 004-4V4a4 4 0 00-4-4H9zm0 2a2 2 0 00-2 2v24a2 2 0 002 2h14a2 2 0 002-2V4a2 2 0 00-2-2h-1.382a1 1 0 00-.894.553l-.448.894a1 1 0 01-.894.553h-6.764a1 1 0 01-.894-.553l-.448-.894A1 1 0 0010.382 2H9z"
fill="#737373"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M23 13.838V26a2 2 0 01-2 2H11a2 2 0 01-2-2V15.65l2.57 3.212a1 1 0 001.38.175L15.4 17.2a1 1 0 011.494.353l1.841 3.681c.399.797 1.562.714 1.843-.13L23 13.837z"
fill="#171717"
/>
<path
d="M10 12h12"
stroke="#737373"
strokeWidth={2}
strokeLinecap="square"
/>
<circle cx={16} cy={16} r={16} fill="#A3A3A3" fillOpacity={0.2} />
</svg>
)
}
export function SecondaryFeatures() {
return (
<section
id="secondary-features"
aria-label="Features for building a portfolio"
className="py-20 sm:py-32"
>
<Container>
<div className="mx-auto max-w-4xl sm:text-center">
<h2 className="text-3xl font-medium tracking-tight text-gray-900">
Coming Soon: The Future of Mycelium
</h2>
<p className="mt-6 text-lg text-gray-600">
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.
</p>
</div>
<ul
role="list"
className="mx-auto mt-16 grid max-w-2xl grid-cols-1 gap-6 text-sm sm:mt-20 sm:grid-cols-2 md:gap-y-10 lg:max-w-none lg:grid-cols-3"
>
{features.map((feature) => (
<li
key={feature.name}
className="rounded-2xl border border-gray-200 p-8"
>
<feature.icon className="h-8 w-8" />
<h3 className="mt-6 font-semibold text-gray-900">
{feature.name}
</h3>
<p className="mt-2 text-gray-700">{feature.description}</p>
</li>
))}
</ul>
</Container>
</section>
)
}

View File

@@ -0,0 +1,100 @@
export function LaravelLogo(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 40 40" fill="#fff" aria-hidden="true" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M29.982 14.509c.002.005.006.01.007.015a.316.316 0 0 1 .011.082v4.293a.304.304 0 0 1-.043.156.32.32 0 0 1-.119.115l-3.709 2.075v4.112a.305.305 0 0 1-.043.157.32.32 0 0 1-.119.114l-7.742 4.33a.286.286 0 0 1-.056.023l-.022.008a.33.33 0 0 1-.18-.005l-.01-.005c-.018-.006-.036-.011-.053-.021l-7.742-4.33a.32.32 0 0 1-.119-.115.304.304 0 0 1-.043-.156v-12.88a.33.33 0 0 1 .01-.08c.004-.01.01-.018.012-.027l.01-.027a.158.158 0 0 1 .011-.022c.006-.01.015-.018.023-.028.009-.012.017-.025.028-.036.01-.01.02-.016.031-.024.012-.009.023-.019.036-.026l3.871-2.165a.33.33 0 0 1 .322 0l3.872 2.165c.013.007.024.017.036.026l.01.008c.008.005.015.01.021.016a.175.175 0 0 1 .021.025l.008.011.022.028c.008.015.014.032.02.049l.006.01.006.016a.307.307 0 0 1 .01.082v8.044l3.227-1.804v-4.112c0-.028.004-.055.011-.082.003-.01.008-.017.011-.026l.004-.01a.228.228 0 0 1 .017-.039.132.132 0 0 1 .013-.018.203.203 0 0 0 .01-.01c.009-.012.017-.025.028-.036l.015-.013.016-.01.019-.016a.126.126 0 0 1 .017-.011l3.871-2.165a.33.33 0 0 1 .322 0l3.871 2.165c.014.007.024.018.036.026l.012.008.02.016a.162.162 0 0 1 .02.026l.009.01.008.01c.005.006.01.012.013.018a.254.254 0 0 1 .018.04l.003.009.005.01Zm-15.138 8.717 3.22 1.77 7.094-3.933-3.223-1.803-7.091 3.966Zm10.64-2.704v-3.57l-3.226-1.804v3.57l3.225 1.804Zm3.547-5.916-3.225-1.803-3.224 1.803 3.224 1.803 3.225-1.803Zm-14.515.218v7.863l3.226-1.805V13.02l-3.226 1.804Zm2.902-2.346-3.225-1.803-3.224 1.803 3.224 1.803 3.225-1.803Zm-3.547 2.347-3.226-1.805v12.155l7.098 3.97V25.54l-3.708-2.038h-.001l-.002-.002c-.013-.008-.024-.018-.035-.027a.28.28 0 0 0-.011-.007.133.133 0 0 1-.02-.015v-.001l-.019-.022a.452.452 0 0 0-.008-.011l-.016-.02a.086.086 0 0 1-.008-.01v-.002a.123.123 0 0 1-.013-.027l-.005-.012-.008-.016a.115.115 0 0 1-.007-.02.18.18 0 0 1-.005-.033l-.002-.013a.293.293 0 0 0-.002-.013l-.002-.022v-8.405Zm4.516 10.715v3.605l7.096-3.969v-3.572l-7.096 3.935Zm7.742-5.019 3.226-1.804v-3.57l-3.226 1.805v3.57Z"
/>
</svg>
)
}
export function TupleLogo(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 40 40" fill="#fff" aria-hidden="true" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M22.5 8 12 11.692v12l3.5 1.231v3.385L26 32V12.615l-3.5 1.231V8Zm-5.833 17.334 5.833 2.05v-12.24l2.333-.82v15.968l-8.166-2.87v-2.088Z"
/>
</svg>
)
}
export function TransistorLogo(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 40 40" fill="#fff" aria-hidden="true" {...props}>
<path d="M20 32c-6.617 0-12-5.383-12-12S13.383 8 20 8s12 5.383 12 12-5.383 12-12 12Zm0-22.4C14.267 9.6 9.6 14.266 9.6 20S14.267 30.4 20 30.4c5.734 0 10.4-4.666 10.4-10.4S25.734 9.6 20 9.6Z" />
<path d="M19.434 27.749c.15.15.354.234.566.235.433 0 .8-.368.8-.8V12.815a.8.8 0 0 0-1.6 0v14.368c0 .212.084.415.234.565ZM12.833 20.8h3.833a.802.802 0 0 0 .802-.8.8.8 0 0 0-.801-.8h-3.834c-.45 0-.8.35-.8.8a.8.8 0 0 0 .8.8ZM23.333 20.8h3.85c.433 0 .783-.35.783-.8a.799.799 0 0 0-.8-.8h-3.833c-.45 0-.8.35-.8.8a.8.8 0 0 0 .8.8Z" />
</svg>
)
}
export function DiageoLogo(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg
viewBox="0 0 40 40"
fill="#fff"
stroke="#fff"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
{...props}
>
<path d="M22.16 19 26 13H14l3.84 6" fill="none" />
<path d="M25 24a5 5 0 1 1-10 0 5 5 0 0 1 10 0Z" />
</svg>
)
}
export function StaticKitLogo(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 40 40" fill="#fff" aria-hidden="true" {...props}>
<path d="m26.068 10.555-11.49 13.089L12 21.089 23.489 8l2.58 2.555ZM28 18.91 16.512 32l-2.579-2.555 11.489-13.089L28 18.911Z" />
</svg>
)
}
export function StatamicLogo(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 40 40" fill="#fff" aria-hidden="true" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M30.177 27.293c0 1.921-.644 2.707-2.398 2.707H12.22c-1.754 0-2.397-.786-2.397-2.707v-3.741c0-1.805-.837-2.824-1.642-3.291a.385.385 0 0 1-.133-.143.403.403 0 0 1 .133-.526c.837-.551 1.642-1.704 1.642-3.241v-3.677c0-2.072.547-2.674 2.3-2.674h15.754c1.754 0 2.3.602 2.3 2.674v3.675c0 1.537.805 2.69 1.641 3.24.243.168.243.52 0 .67-.804.484-1.64 1.503-1.64 3.29v3.743h-.001Zm-14.739-2.455c1.271 1.152 2.64 1.737 4.522 1.737 2.96 0 4.891-1.537 4.891-4.026 0-2.637-2.3-3.31-4.17-3.856-1.282-.375-2.363-.691-2.363-1.54 0-.551.564-1.086 1.513-1.086.917 0 1.674.2 2.397.584.242.117.467.2.676.2.306 0 .547-.15.756-.45l.29-.451a.955.955 0 0 0 .161-.55c0-.336-.161-.67-.402-.837-.966-.635-2.27-1.17-4.039-1.17-2.51 0-4.44 1.37-4.44 3.826 0 2.746 2.349 3.443 4.23 4h.001c1.255.372 2.3.681 2.3 1.497 0 .785-.707 1.17-1.592 1.17a5.19 5.19 0 0 1-2.992-.92c-.274-.183-.532-.3-.805-.3-.242 0-.451.117-.644.368l-.387.517a.888.888 0 0 0-.192.585c0 .25.08.501.29.702Z"
/>
</svg>
)
}
export function MirageLogo(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 40 40" fill="#fff" aria-hidden="true" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M24.05 9c2.307 0 4.177 1.885 4.177 4.21a4.21 4.21 0 0 1-2.762 3.964l3.366 6.057h2.304c.355 0 .642.29.642.647a.645.645 0 0 1-.642.647H7.142a.645.645 0 0 1-.642-.647c0-.358.288-.647.643-.647h2.304l5.994-10.747a.641.641 0 0 1 1.097-.036l3.444 5.32 1.071-1.627a4.214 4.214 0 0 1-1.178-2.93c0-2.326 1.87-4.211 4.176-4.211Zm-3.304 9.948 2.772 4.283h3.84l-4.317-7.769-2.295 3.486Zm1.239 4.283-5.944-9.183-5.121 9.183h11.065Zm5.038-10.02a2.995 2.995 0 0 1-2.159 2.883l-1.216-2.19a.64.64 0 0 0-1.096-.04l-.811 1.232a3 3 0 0 1-.663-1.885c0-1.655 1.332-2.997 2.973-2.997 1.641 0 2.972 1.341 2.972 2.997Z"
/>
<path d="M12.069 26.469c-.354 0-.641.289-.641.646 0 .358.287.646.64.646h14.139c.354 0 .641-.29.641-.646a.644.644 0 0 0-.64-.646h-14.14Zm4.928 3.236a.645.645 0 0 0-.642.648c0 .357.288.647.642.647h4.282c.355 0 .643-.29.643-.647a.645.645 0 0 0-.643-.648h-4.282Z" />
</svg>
)
}
export function ReversableLogo(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg
viewBox="0 0 40 40"
fill="none"
stroke="#fff"
strokeWidth="2"
strokeLinecap="square"
strokeLinejoin="round"
aria-hidden="true"
{...props}
>
<path d="M15 26v-5.25m0 0V16a2 2 0 0 1 2-2h4.21c.968 0 1.37 1.24.587 1.809L15 20.75Zm0 0L25 26" />
</svg>
)
}

374
src/components/UseCases.tsx Normal file
View File

@@ -0,0 +1,374 @@
'use client'
import React, { useEffect, useMemo, useRef, useState } from 'react'
import clsx from 'clsx'
import { useInView } from 'framer-motion'
import {
ArchiveBoxIcon,
ChatBubbleBottomCenterIcon,
CloudIcon,
CodeBracketIcon,
ComputerDesktopIcon,
CpuChipIcon,
DocumentIcon,
EnvelopeIcon,
GlobeAltIcon,
GlobeAmericasIcon,
PlayCircleIcon,
ShareIcon,
EyeSlashIcon,
UserGroupIcon,
VideoCameraIcon,
} from '@heroicons/react/24/solid'
import { Container } from '@/components/Container'
interface Review {
title: string
body: string
author: string
rating: 1 | 2 | 3 | 4 | 5
}
const reviews: Array<Review> = [
{
title: 'Secure remote work collaboration.',
body: 'Mycelium provides a secure, encrypted network for a wide range of use cases, from private communication to decentralized infrastructure.',
author: 'CrazyInvestor',
rating: 5,
},
{
title: 'Private file sharing between trusted nodes.',
body: 'Mycelium enables private file sharing between trusted nodes, ensuring that sensitive information remains confidential and secure.',
author: 'CluelessButRich',
rating: 5,
},
{
title: 'Encrypted voice/video calls.',
body: 'Mycelium enables secure voice and video calls between users, ensuring that conversations remain private and protected from eavesdropping.',
author: 'LivingDaDream',
rating: 5,
},
{
title: 'Self-hosted messaging systems.',
body: 'Mycelium allows users to create their own self-hosted messaging systems, ensuring complete control over their communications.',
author: 'JordanBelfort1962',
rating: 5,
},
{
title: 'Secure document collaboration.',
body: 'Mycelium enables secure document collaboration between users, ensuring that sensitive information remains confidential and protected.',
author: 'MrBurns',
rating: 5,
},
{
title: 'Private cloud computing resources.',
body: 'Mycelium provides private cloud computing resources, allowing users to run their applications in a secure and isolated environment.',
author: 'LazyRich99',
rating: 5,
},
{
title: 'Secure IoT device networks.',
body: 'Mycelium provides secure IoT device networks, ensuring that all connected devices can communicate privately and securely.',
author: 'SarahLuvzCash',
rating: 5,
},
{
title: 'Remote system administration.',
body: 'Mycelium enables secure remote system administration, allowing users to manage their systems from anywhere without compromising security.',
author: 'ScroogeMcduck',
rating: 5,
},
{
title: 'Virtual private networks (VPNs).',
body: 'Mycelium enables the creation of virtual private networks (VPNs), allowing users to securely connect to remote networks and access resources without compromising their privacy.',
author: 'BruceWayne',
rating: 5,
},
{
title: 'Secure backup systems.',
body: 'Mycelium provides secure backup systems, ensuring that users can easily and safely back up their important data without the risk of unauthorized access.',
author: 'RichieRich',
rating: 5,
},
{
title: 'Self-hosted web services.',
body: 'Mycelium allows users to create their own self-hosted web services, ensuring complete control over their data and applications.',
author: 'TheCountOfMonteChristo',
rating: 5,
},
{
title: 'Private file sharing between trusted nodes.',
body: 'Mycelium enables private file sharing between trusted nodes, ensuring that sensitive information remains confidential and secure.',
author: 'ClarkKent',
rating: 5,
},
{
title: 'Private DNS systems.',
body: 'Mycelium enables the creation of private DNS systems, allowing users to maintain control over their domain name resolution and protect their privacy.',
author: 'GeorgeCostanza',
rating: 5,
},
{
title: 'Personal email servers.',
body: 'Mycelium allows users to create their own personal email servers, ensuring complete control over their communications and data.',
author: 'JeffBezos',
rating: 5,
},
{
title: 'Secure document collaboration.',
body: 'Mycelium enables secure document collaboration between users, ensuring that sensitive information remains confidential and protected.',
author: 'JeffBezos',
rating: 5,
},
{
title: 'Private media streaming.',
body: 'Mycelium enables private media streaming between users, ensuring that sensitive content remains confidential and protected.',
author: 'JeffBezos',
rating: 5,
},
{
title: 'Personal cloud storage.',
body: 'Mycelium allows users to create their own personal cloud storage solutions, ensuring complete control over their data and privacy.',
author: 'JeffBezos',
rating: 5,
},
{
title: 'Personal email servers.',
body: 'Mycelium allows users to create their own personal email servers, ensuring complete control over their communications and data.',
author: 'JeffBezos',
rating: 5,
},
{
title: 'Protected content distribution.',
body: 'Mycelium enables protected content distribution, allowing users to securely share and distribute sensitive information without compromising its confidentiality.',
author: 'JeffBezos',
rating: 5,
},
{
title: 'Secure game servers.',
body: 'Mycelium enables the creation of secure game servers, allowing users to host and manage their own gaming environments with complete control over their data and privacy.',
author: 'JeffBezos',
rating: 5,
}, {
title: 'Private git repositories.',
body: 'Mycelium enables the creation of private git repositories, allowing users to host and manage their own version control systems with complete control over their data and privacy.',
author: 'JeffBezos',
rating: 5,
},
]
function StarIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
</svg>
)
}
function StarRating({ rating }: { rating: Review['rating'] }) {
return (
<div className="flex">
{[...Array(5).keys()].map((index) => (
<StarIcon
key={index}
className={clsx(
'h-5 w-5',
rating > index ? 'fill-cyan-500' : 'fill-gray-300',
)}
/>
))}
</div>
)
}
function getReviewIcon(title: string) {
if (title.toLowerCase().includes('collaboration')) return UserGroupIcon;
if (title.toLowerCase().includes('file sharing')) return ShareIcon;
if (title.toLowerCase().includes('voice') || title.toLowerCase().includes('video')) return VideoCameraIcon;
if (title.toLowerCase().includes('messaging')) return ChatBubbleBottomCenterIcon;
if (title.toLowerCase().includes('document')) return DocumentIcon;
if (title.toLowerCase().includes('cloud')) return CloudIcon;
if (title.toLowerCase().includes('iot')) return CpuChipIcon;
if (title.toLowerCase().includes('administration')) return ComputerDesktopIcon;
if (title.toLowerCase().includes('vpn')) return GlobeAmericasIcon;
if (title.toLowerCase().includes('backup')) return ArchiveBoxIcon;
if (title.toLowerCase().includes('web services')) return GlobeAltIcon;
if (title.toLowerCase().includes('dns')) return GlobeAmericasIcon;
if (title.toLowerCase().includes('email')) return EnvelopeIcon;
if (title.toLowerCase().includes('media streaming') || title.toLowerCase().includes('streaming')) return PlayCircleIcon;
if (title.toLowerCase().includes('storage')) return CloudIcon;
if (title.toLowerCase().includes('distribution')) return EyeSlashIcon;
if (title.toLowerCase().includes('game')) return ComputerDesktopIcon;
if (title.toLowerCase().includes('git')) return CodeBracketIcon;
return ComputerDesktopIcon; // default
}
function Review({
title,
body,
author,
rating,
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-white p-6 opacity-0 shadow-md shadow-gray-900/5',
className,
)}
style={{ animationDelay }}
{...props}
>
<blockquote className="text-gray-900">
{React.createElement(getReviewIcon(title), { className: "h-6 w-6 text-gray-700 mb-2" })}
<p className="mt-4 text-lg/6 font-semibold">
{title}
</p>
<p className="mt-3 text-sm text-gray-600">{body}</p>
</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-16 grid h-196 max-h-[150vh] grid-cols-1 items-start gap-8 overflow-hidden px-4 sm:mt-20 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-gray-50" />
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-32 bg-linear-to-t from-gray-50" />
</div>
)
}
export function UseCases() {
return (
<section
id="usecases"
aria-labelledby="usecases-title"
className="pt-20 pb-16 sm:pt-32 sm:pb-24"
>
<Container className=''>
<div className="mx-auto max-w-2xl lg:max-w-5xl">
<h2
id="usecases-title"
className="text-3xl font-medium tracking-tight text-gray-900 sm:text-center"
>
Powering Secure & Decentralized Connectivity
</h2>
<p className="mt-6 text-lg text-gray-600 sm:text-center">
The ThreeFold Dashboard offers dozens of applications with built-in Mycelium support, making it easy to deploy and utilize. Once installed, Mycelium provides a secure, encrypted network for a wide range of use cases, from private communication to decentralized infrastructure.
</p>
</div>
<ReviewGrid />
</Container>
</section>
)
}

View File

@@ -0,0 +1,39 @@
import Link from 'next/link'
import clsx from 'clsx'
export function WindowsLink({
color = 'black',
}: {
color?: 'black' | 'white'
}) {
return (
<Link
href="#"
aria-label="Download for Windows"
className={clsx(
'flex items-center rounded-lg transition-colors px-4 py-2',
color === 'black'
? 'bg-gray-800 text-white hover:bg-gray-900'
: 'bg-white text-gray-900 hover:bg-gray-50',
)}
>
{/* Windows logo */}
<svg
viewBox="0 0 88 88"
aria-hidden="true"
className="h-5 w-5 mr-3"
>
<path
fill="currentColor"
d="M0 12.2L35.6 7v34.2H0V12.2Zm0 63.6L35.6 76V44.8H0v31ZM41.2 6l46.8-6v41.2H41.2V6Zm0 76l46.8 6V46.8H41.2V82Z"
/>
</svg>
{/* Text */}
<div className="flex flex-col text-left leading-tight">
<span className="text-[9px] mt-0">Download for</span>
<span className="text-sm font-semibold -mt-1.5">Windows</span>
</div>
</Link>
)
}

1
src/images/android.svg Normal file
View File

@@ -0,0 +1 @@
<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="3ce6073860"><path d="M 1.566406 25 L 8 25 L 8 43 L 1.566406 43 Z M 1.566406 25 " clip-rule="nonzero"/></clipPath><clipPath id="225ba38cc1"><path d="M 10 25 L 34 25 L 34 53.640625 L 10 53.640625 Z M 10 25 " clip-rule="nonzero"/></clipPath></defs><g clip-path="url(#3ce6073860)"><path fill="#000000" d="M 4.445312 25.296875 C 2.855469 25.296875 1.5625 26.582031 1.5625 28.164062 L 1.5625 39.636719 C 1.5625 41.21875 2.855469 42.503906 4.445312 42.503906 C 6.035156 42.503906 7.324219 41.21875 7.324219 39.636719 L 7.324219 28.164062 C 7.324219 26.582031 6.035156 25.296875 4.445312 25.296875 Z M 4.445312 25.296875 " fill-opacity="1" fill-rule="nonzero"/></g><path fill="#000000" d="M 39.015625 25.296875 C 37.425781 25.296875 36.132812 26.582031 36.132812 28.164062 L 36.132812 39.636719 C 36.132812 41.21875 37.425781 42.503906 39.015625 42.503906 C 40.605469 42.503906 41.894531 41.21875 41.894531 39.636719 L 41.894531 28.164062 C 41.894531 26.582031 40.605469 25.296875 39.015625 25.296875 Z M 39.015625 25.296875 " fill-opacity="1" fill-rule="nonzero"/><g clip-path="url(#225ba38cc1)"><path fill="#000000" d="M 10.207031 42.667969 C 10.207031 44.253906 11.496094 45.535156 13.085938 45.535156 L 13.085938 51.105469 C 13.085938 52.6875 14.378906 53.972656 15.96875 53.972656 C 17.558594 53.972656 18.847656 52.6875 18.847656 51.105469 L 18.847656 45.535156 L 24.609375 45.535156 L 24.609375 51.105469 C 24.609375 52.6875 25.902344 53.972656 27.492188 53.972656 C 29.082031 53.972656 30.371094 52.6875 30.371094 51.105469 L 30.371094 45.535156 C 31.960938 45.535156 33.253906 44.253906 33.253906 42.667969 L 33.253906 25.464844 L 10.207031 25.464844 Z M 10.207031 42.667969 " fill-opacity="1" fill-rule="nonzero"/></g><path fill="#000000" d="M 28.921875 13.53125 L 31.484375 10.4375 C 31.992188 9.824219 31.90625 8.921875 31.292969 8.417969 C 30.675781 7.914062 29.769531 8 29.261719 8.609375 L 26.460938 11.992188 C 25.015625 11.339844 23.421875 10.957031 21.730469 10.957031 C 20.015625 10.957031 18.402344 11.355469 16.941406 12.023438 L 14.214844 8.628906 C 13.714844 8.011719 12.808594 7.910156 12.1875 8.40625 C 11.570312 8.902344 11.46875 9.804688 11.964844 10.421875 L 14.492188 13.570312 C 11.898438 15.671875 10.207031 18.839844 10.207031 22.429688 L 33.253906 22.429688 C 33.253906 18.816406 31.542969 15.632812 28.921875 13.53125 Z M 18.847656 18.128906 C 18.054688 18.128906 17.410156 17.484375 17.410156 16.695312 C 17.410156 15.902344 18.054688 15.261719 18.847656 15.261719 C 19.644531 15.261719 20.289062 15.902344 20.289062 16.695312 C 20.289062 17.484375 19.644531 18.128906 18.847656 18.128906 Z M 24.609375 18.128906 C 23.816406 18.128906 23.171875 17.484375 23.171875 16.695312 C 23.171875 15.902344 23.816406 15.261719 24.609375 15.261719 C 25.40625 15.261719 26.050781 15.902344 26.050781 16.695312 C 26.050781 17.484375 25.40625 18.128906 24.609375 18.128906 Z M 24.609375 18.128906 " fill-opacity="1" fill-rule="nonzero"/></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

1
src/images/favicon.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 83 KiB

BIN
src/images/linux.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

3
src/images/linux.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.0" viewBox="0 0 266 312">
<path d="M128.6640625 79.2793c0 1-1 1-1 1h-1c-1 0-1-1-2-2 0 0-1-1-1-2s0-1 1-1l2 1c1 1 2 2 2 3m-18-10c0-5-2-8-5-8 0 0 0 1-1 1v2h3c0 2 1 3 1 5h2m35-5c2 0 3 2 4 5h2c-1-1-1-2-1-3s0-2-1-3-2-2-3-2c0 0-1 1-2 1 0 1 1 1 1 2m-30 16c-1 0-1 0-1-1s0-2 1-3c2 0 3-1 3-1 1 0 1 1 1 1 0 1-1 2-3 4h-1m-11-1c-4-2-5-5-5-10 0-3 0-5 2-7 1-2 3-3 5-3s3 1 5 3c1 3 2 6 2 9v2h1v-1c1 0 1-2 1-6 0-3 0-6-2-9s-4-5-8-5c-3 0-6 2-7 5-2 4-2.4 7-2.4 12 0 4 1.4 8 5.4 12 1-1 2-1 3-2m125 141c1 0 1-.4 1-1.3 0-2.2-1-4.8-4-7.7-3-3-8-4.9-14-5.7-1-.1-2-.1-2-.1-1-.2-1-.2-2-.2-1-.1-3-.3-4-.5 3-9.3 4-17.5 4-24.7 0-10-2-17-6-23s-8-9-13-10c-1 1-1 1-1 2 5 2 10 6 13 12 3 7 4 13 4 20 0 5.6-1 13.9-5 24.5-4 1.6-8 5.3-11 11.1 0 .9 0 1.4 1 1.4 0 0 1-.9 2-2.6 2-1.7 3-3.4 5-5.1 3-1.7 5-2.6 8-2.6 5 0 10 .7 13 2.1 4 1.3 6 2.7 7 4.3 1 1.5 2 2.9 3 4.2 0 1.3 1 1.9 1 1.9m-92-145c-1-1-1-3-1-5 0-4 0-6 2-9 2-2 4-3 6-3 3 0 5 2 7 4 1 3 2 5 2 8 0 5-2 8-6 9 0 0 1 1 2 1 2 0 3 1 5 2 1-6 2-10 2-15 0-6-1-10-3-13-3-3-6-4-10-4-3 0-6 1-9 3-2 3-3 5-3 8 0 5 1 9 3 13 1 0 2 1 3 1m12 16c-13 9-23 13-31 13-7 0-14-3-20-8 1 2 2 4 3 5l6 6c4 4 9 6 14 6 7 0 15-4 25-11l9-6c2-2 4-4 4-7 0-1 0-2-1-2-1-2-6-5-16-8-9-4-16-6-20-6-3 0-8 2-15 6-6 4-10 8-10 12 0 0 1 1 2 3 6 5 12 8 18 8 8 0 18-4 31-14v2c1 0 1 1 1 1m23 202c4 7.52 11 11.3 19 11.3 2 0 4-.3 6-.9 2-.4 4-1.1 5-1.9 1-.7 2-1.4 3-2.2 2-.7 2-1.2 3-1.7l17-14.7c4-3.19 8-5.98 13-8.4 4-2.4 8-4 10-4.9 3-.8 5-2 7-3.6 1-1.5 2-3.4 2-5.8 0-2.9-2-5.1-4-6.7s-4-2.7-6-3.4-4-2.3-7-5c-2-2.6-4-6.2-5-10.9l-1-5.8c-1-2.7-1-4.7-2-5.8 0-.3 0-.4-1-.4s-3 .9-4 2.6c-2 1.7-4 3.6-6 5.6-1 2-4 3.8-6 5.5-3 1.7-6 2.6-8 2.6-8 0-12-2.2-15-6.5-2-3.2-3-6.9-4-11.1-2-1.7-3-2.6-5-2.6-5 0-7 5.2-7 15.7v31.1c0 .9-1 2.9-1 6-1 3.1-1 6.62-1 10.6l-2 11.1v.17m-145-5.29c9.3 1.36 20 4.27 32.1 8.71 12.1 4.4 19.5 6.7 22.2 6.7 7 0 12.8-3.1 17.6-9.09 1-1.94 1-4.22 1-6.84 0-9.45-5.7-21.4-17.1-35.9l-6.8-9.1c-1.4-1.9-3.1-4.8-5.3-8.7-2.1-3.9-4-6.9-5.5-9-1.3-2.3-3.4-4.6-6.1-6.9-2.6-2.3-5.6-3.8-8.9-4.6-4.2.8-7.1 2.2-8.5 4.1s-2.2 4-2.4 6.2c-.3 2.1-.9 3.5-1.9 4.2-1 .6-2.7 1.1-5 1.6-.5 0-1.4 0-2.7.1h-2.7c-5.3 0-8.9.6-10.8 1.6-2.5 2.9-3.8 6.2-3.8 9.7 0 1.6.4 4.3 1.2 8.1.8 3.7 1.2 6.7 1.2 8.8 0 4.1-1.2 8.2-3.7 12.3-2.5 4.3-3.8 7.5-3.8 9.78 1 3.88 7.6 6.61 19.7 8.21m33.3-90.9c0-6.9 1.8-14.5 5.5-23.5 3.6-9 7.2-15 10.7-19-.2-1-.7-1-1.5-1l-1-1c-2.9 3-6.4 10-10.6 20-4.2 9-6.4 17.3-6.4 23.4 0 4.5 1.1 8.4 3.1 11.8 2.2 3.3 7.5 8.1 15.9 14.2l10.6 6.9c11.3 9.8 17.3 16.6 17.3 20.6 0 2.1-1 4.2-4 6.5-2 2.4-4.7 3.6-7 3.6-.2 0-.3.2-.3.7 0 .1 1 2.1 3.1 6 4.2 5.7 13.2 8.5 25.2 8.5 22 0 39-9 52-27 0-5 0-8.1-1-9.4v-3.7c0-6.5 1-11.4 3-14.6s4-4.7 7-4.7c2 0 4 .7 6 2.2 1-7.7 1-14.4 1-20.4 0-9.1 0-16.6-2-23.6-1-6-3-11-5-15l-6-9c-2-3-3-6-5-9-1-4-2-7-2-12-3-5-5-10-8-15-2-5-4-10-6-14l-9 7c-10 7-18 10-25 10-6 0-11-1-14-5l-6-5c0 3-1 7-3 11l-6.3 12c-2.8 7-4.3 11-4.6 14-.4 2-.7 4-.9 4l-7.5 15c-8.1 15-12.2 28.9-12.2 40.4 0 2.3.2 4.7.6 7.1-4.5-3.1-6.7-7.4-6.7-13m71.6 94.6c-13 0-23 1.76-30 5.25v-.3c-5 6-10.6 9.1-18.4 9.1-4.9 0-12.6-1.9-23-5.7-10.5-3.6-19.8-6.36-27.9-8.18-.8-.23-2.6-.57-5.5-1.03-2.8-.45-5.4-.91-7.7-1.37-2.1-.45-4.5-1.13-7.1-2.05-2.5-.79-4.5-1.82-6-3.07-1.38-1.26-2.06-2.68-2.06-4.27 0-1.6.34-3.31 1.02-5.13.64-1.1 1.34-2.2 2.04-3.2.7-1.1 1.3-2.1 1.7-3.1.6-.9 1-1.8 1.4-2.8.4-.9.8-1.8 1-2.9.2-1 .4-2 .4-3s-.4-4-1.2-9.3c-.8-5.2-1.2-8.5-1.2-9.9 0-4.4 1-7.9 3.2-10.4s4.3-3.8 6.5-3.8h11.5c.9 0 2.3-.5 4.4-1.7.7-1.6 1.3-2.9 1.7-4.1.5-1.2.7-2.1.9-2.5.2-.6.4-1.2.6-1.7.4-.7.9-1.5 1.6-2.3-.8-1-1.2-2.3-1.2-3.9 0-1.1 0-2.1.2-2.7 0-3.6 1.7-8.7 5.3-15.4l3.5-6.3c2.9-5.4 5.1-9.4 6.7-13.4 1.7-4 3.5-10 5.5-18 1.6-7 5.4-14 11.4-21l7.5-9c5.2-6 8.6-11 10.5-15s2.9-9 2.9-13c0-2-.5-8-1.6-18-1-10-1.5-20-1.5-29 0-7 .6-12 1.9-17s3.6-10 7-14c3-4 7-8 13-10s13-3 21-3c3 0 6 0 9 1 3 0 7 1 12 3 4 2 8 4 11 7 4 3 7 8 10 13 2 6 4 12 5 20 1 5 1 10 2 17 0 6 1 10 1 13 1 3 1 7 2 12 1 4 2 8 4 11 2 4 4 8 7 12 3 5 7 10 11 16 9 10 16 21 20 32 5 10 8 23 8 36.9 0 6.9-1 13.6-3 20.1 2 0 3 .8 4 2.2s2 4.4 3 9.1l1 7.4c1 2.2 2 4.3 5 6.1 2 1.8 4 3.3 7 4.5 2 1 5 2.4 7 4.2 2 2 3 4.1 3 6.3 0 3.4-1 5.9-3 7.7-2 2-4 3.4-7 4.3-2 1-6 3-12 5.82-5 2.96-10 6.55-15 10.8l-10 8.51c-4 3.9-8 6.7-11 8.4-3 1.8-7 2.7-11 2.7l-7-.8c-8-2.1-13-6.1-16-12.2-16-1.94-29-2.9-37-2.9"/>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

5
src/images/logos/bbc.svg Normal file
View File

@@ -0,0 +1,5 @@
<svg width="83" height="32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd"
d="M0 15.531v11.531h24.771V4H0v11.531Zm29.042 0v11.531h24.771V4H29.041v11.531Zm29.041 0v11.531h24.771V4H58.083v11.531ZM14.807 7.817c.979.444 1.988 1.197 2.242 1.67.254.475.461 1.43.461 2.125 0 .694-.364 1.713-.81 2.263l-.81 1 1.548 1.34c1.307 1.13 1.548 1.608 1.548 3.079 0 1.25-.29 2.049-1.026 2.834-.565.6-1.714 1.283-2.553 1.516-.84.233-3.208.425-5.264.426l-3.737.003V6.99l3.31.009c2.32.006 3.843.251 5.09.818Zm28.763-.134c1.045.418 1.982 1.173 2.358 1.9.343.665.624 1.677.624 2.25 0 .572-.365 1.492-.81 2.042-.81 1-.81 1 .68 2.29 1.18 1.02 1.5 1.621 1.535 2.888.028 1-.281 2.041-.827 2.776-.48.647-1.526 1.406-2.326 1.686s-3.233.52-5.406.534l-3.95.024V6.99h3.194c1.952 0 3.87.27 4.928.693Zm32.237-.116c1.566.47 1.72.65 1.844 2.148.1 1.222-.007 1.577-.427 1.402-.31-.128-1.59-.551-2.846-.94-1.556-.484-2.896-.618-4.206-.421-1.325.198-2.407.732-3.482 1.717-1.464 1.342-1.56 1.588-1.56 3.997 0 2.26.151 2.725 1.257 3.88.692.721 1.94 1.501 2.776 1.734.836.232 2.096.418 2.8.414.705-.004 2.387-.463 3.738-1.018l2.455-1.01v1.592c0 1.318-.202 1.688-1.174 2.148-.646.306-2.667.65-4.492.765-2.484.156-3.79.027-5.204-.512-1.038-.397-2.562-1.468-3.387-2.38-.824-.913-1.715-2.46-1.978-3.44-.264-.98-.36-2.496-.211-3.37.148-.874.624-2.175 1.06-2.892.436-.717 1.434-1.781 2.217-2.366.783-.584 2.001-1.264 2.706-1.51.704-.246 2.434-.448 3.844-.449 1.409 0 3.33.23 4.27.511ZM9.48 12.007l.13 2.03 1.685-.057c1.182-.039 1.915-.34 2.456-1.008.424-.523.77-1.11.77-1.301 0-.192-.301-.651-.67-1.02-.411-.411-1.415-.672-2.586-.672H9.349l.13 2.029Zm29.042 0 .13 2.03 1.594-.048c.876-.027 1.886-.29 2.242-.587.357-.296.648-.956.648-1.468 0-.511-.23-1.16-.512-1.442-.282-.282-1.35-.513-2.372-.513h-1.86l.13 2.029ZM9.48 19.056l.128 2.242 2.45-.05c1.347-.026 2.74-.29 3.096-.585.356-.296.647-.983.647-1.529 0-.545-.427-1.29-.95-1.655-.57-.4-1.855-.666-3.225-.666H9.351l.13 2.243Zm29.041 0c.123 2.136.189 2.249 1.403 2.387.7.08 1.995-.072 2.878-.337 1.184-.354 1.68-.776 1.887-1.604.217-.864.06-1.305-.683-1.907-.672-.543-1.674-.782-3.29-.782h-2.324l.13 2.243Z"
fill="#737373" />
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

5
src/images/logos/cbs.svg Normal file
View File

@@ -0,0 +1,5 @@
<svg width="101" height="32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M15.072 1C6.675 1 0 7.855 0 16.205c0 8.44 6.676 15.297 15.072 15.297 8.44 0 15.026-6.855 15.026-15.295C30.099 7.857 23.51 1 15.072 1Zm0 6.454c6.855 0 11.876 4.353 13.998 8.753-2.122 4.467-7.143 8.841-13.998 8.841-6.9 0-11.881-4.375-14.002-8.84 2.12-4.4 7.104-8.751 14.002-8.751v-.003Zm0 .692c-4.466 0-8.107 3.614-8.107 8.059a8.092 8.092 0 0 0 8.107 8.106c4.465 0 8.058-3.595 8.058-8.104a8.055 8.055 0 0 0-8.058-8.061ZM44.506 2.81c-7.883 0-13.376 5.983-13.376 13.261v.088c0 7.368 5.606 13.198 13.177 13.198 4.934 0 7.882-1.765 10.517-4.601L51.23 21.14c-2.01 1.83-3.822 3.016-6.747 3.016-4.398 0-7.457-3.689-7.457-8.086v-.066c0-4.399 3.126-7.995 7.457-7.995 2.568 0 4.578 1.094 6.566 2.904l3.595-4.155c-2.389-2.344-5.291-3.95-10.137-3.95ZM56.951 3.254v25.653h12.213c5.782 0 9.6-2.341 9.6-7.029v-.09c0-3.438-1.829-5.16-4.801-6.297 1.832-1.026 3.372-2.633 3.372-5.536V9.89c0-1.767-.581-3.195-1.765-4.378-1.472-1.45-3.772-2.257-6.698-2.257h-11.92Zm5.49 4.934h5.584c2.39 0 3.705.96 3.705 2.635v.09c0 1.898-1.585 2.702-4.085 2.702l-5.203.002V8.188Zm0 10.119h6.545c2.878 0 4.173 1.073 4.173 2.792v.087c0 1.898-1.517 2.768-3.995 2.768l-6.722.003v-5.65ZM89.833 2.876c-5.224 0-8.974 3.08-8.974 7.745v.069c0 5.093 3.347 6.523 8.506 7.84 4.287 1.115 5.179 1.829 5.179 3.258v.09c0 1.495-1.408 2.412-3.707 2.412-2.948 0-5.36-1.209-7.66-3.106L79.83 25.18c3.081 2.747 7.01 4.088 10.896 4.088v-.003c5.537 0 9.421-2.86 9.421-7.946v-.067c0-4.487-2.946-6.344-8.149-7.705-4.42-1.14-5.538-1.697-5.538-3.372v-.066c0-1.25 1.139-2.255 3.305-2.255 2.166 0 4.4.959 6.678 2.542l2.924-4.26c-2.59-2.077-5.781-3.261-9.533-3.261Z"
fill="#737373" />
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

11
src/images/logos/cnn.svg Normal file
View File

@@ -0,0 +1,11 @@
<svg width="68" height="32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M5.155 15.807c0 5.795 4.715 10.51 10.51 10.51h9.817c.617 0 1.095-.586 1.095-1.09V5.966a2.21 2.21 0 0 1 2.206-2.207c.78 0 1.508.414 1.897 1.08a91573.874 91573.874 0 0 1 12.332 21.263.918.918 0 0 0 1.701-.476V5.968c0-1.217.99-2.207 2.206-2.207.78 0 1.508.414 1.897 1.08.05.084 3.02 5.208 6.164 10.634l6.16 10.63a.918.918 0 0 0 1.7-.476V.138h-3.87V15.31S51.96 3.243 51.734 2.855C50.709 1.105 48.768 0 46.703 0a5.861 5.861 0 0 0-5.86 5.86v9.45s-7.01-12.067-7.238-12.455C32.582 1.105 30.641 0 28.575 0a5.861 5.861 0 0 0-5.86 5.86V21.39c.003.565-.422 1.057-1.04 1.059h-5.968a6.64 6.64 0 0 1 0-13.282h4.998V5.297h-5.04c-5.795 0-10.51 4.715-10.51 10.51Z"
fill="#737373" />
<path
d="M64.13.137v25.49c0 1.217-.989 2.207-2.206 2.207-.78 0-1.508-.414-1.897-1.08-.05-.084-3.02-5.209-6.163-10.634l-6.16-10.63a.918.918 0 0 0-1.7.475v19.662c-.001 1.217-.99 2.207-2.208 2.207-.78 0-1.507-.414-1.897-1.08L35.732 16.12 29.567 5.49a.917.917 0 0 0-1.7.475v19.26c0 1.269-1.115 2.381-2.385 2.381h-9.816c-6.507 0-11.8-5.293-11.8-11.8 0-6.506 5.293-11.8 11.8-11.8h5.04V.136H15.67C7.016.137 0 7.153 0 15.807c0 8.655 7.016 15.67 15.67 15.67h9.911c3.754.002 6.169-2.198 6.164-6.255v-8.938s7.06 12.153 7.238 12.456a5.86 5.86 0 0 0 10.89-3.006v-9.45s7.01 12.068 7.238 12.456c1.023 1.75 2.964 2.855 5.03 2.855A5.86 5.86 0 0 0 68 25.734V.136h-3.87Z"
fill="#737373" />
<path
d="M3.865 15.807c0 6.507 5.294 11.8 11.8 11.8h9.817c1.27 0 2.384-1.112 2.384-2.38V5.966a.917.917 0 0 1 1.7-.475c.05.084 3.159 5.445 6.165 10.629L41.9 26.755a2.202 2.202 0 0 0 1.897 1.08 2.21 2.21 0 0 0 2.207-2.207V5.967a.917.917 0 0 1 1.7-.475l6.16 10.629 6.163 10.634a2.201 2.201 0 0 0 1.897 1.08c1.218 0 2.207-.99 2.207-2.207V.138h-1.29v25.49a.918.918 0 0 1-1.7.475l-6.16-10.629c-3.145-5.426-6.114-10.55-6.164-10.634a2.201 2.201 0 0 0-1.897-1.08 2.21 2.21 0 0 0-2.206 2.207v19.66a.918.918 0 0 1-1.701.476A344293.41 344293.41 0 0 1 30.68 4.84a2.201 2.201 0 0 0-1.897-1.08 2.21 2.21 0 0 0-2.207 2.207v19.26c0 .504-.478 1.09-1.094 1.09h-9.817c-5.795 0-10.51-4.715-10.51-10.51s4.715-10.51 10.51-10.51h5.04v-1.29h-5.04c-6.506 0-11.8 5.294-11.8 11.8Z"
fill="#fff" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,5 @@
<svg width="124" height="32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd"
d="M58.787 11.975c0 2.488-.249 10.2-.249 10.2 0 1.492.498 2.154 1.907 2.154v.663H54.89v-.663c1.409 0 2.155-.662 2.155-2.155l.498-12.602c-.415-.996-.83-1.327-1.907-1.41v-.58h4.228l4.478 11.774 4.561-11.774h3.814v.58c-1.078 0-1.658.498-1.658 1.658l.498 12.189c0 1.824.331 2.322 1.824 2.322v.662h-6.385v-.662c1.244 0 1.825-.415 1.741-2.322l-.331-10.033-3.067 8.457a31.599 31.599 0 0 0-1.162 3.649l-.994.083c-.249-.912-.912-2.57-.912-2.57l-3.484-9.62Zm-5.224 13.1c-.332-.083-.663-.083-.995-.083-.663 0-1.825.332-3.234.332-5.39 0-9.37-3.233-9.37-9.203 0-5.058 3.732-8.955 9.452-8.955 1.327 0 2.82.25 4.064.747.248-.25.33-.415.58-.663h.497c-.083.912-.414 3.897-.414 3.897h-.498c-.332-1.741-1.244-2.902-4.146-2.902-3.482 0-6.633 2.736-6.633 7.794 0 5.721 3.234 8.208 6.799 8.208 2.322 0 3.73-1.326 4.643-2.985l.58.25-1.326 3.564ZM37.89 10.816h-.58c-.083-1.576-.58-2.074-1.824-2.074h-2.405V21.76c0 2.155.415 2.57 1.825 2.57v.663h-6.219v-.663c1.41 0 1.825-.415 1.825-2.654V8.741h-2.405c-1.575 0-1.825.415-2.24 2.073h-.579l.415-3.731.414.083c.166.414.498.414 1.493.414h8.043c1.493 0 1.824 0 2.156-.497h.498l-.416 3.73v.001ZM20.314 25.406c-1.161 0-2.073-.166-2.736-.415-.663-.165-1.161-.414-1.41-.58-.331.331-.58.746-.58.746l-.498-.166.415-3.897.58.084c.332 1.824 1.575 3.15 4.146 3.15 1.99 0 3.316-1.658 3.316-3.482 0-1.492-.58-2.24-2.57-3.732l-1.742-1.16c-1.824-1.16-2.985-2.488-2.985-4.643 0-2.488 2.073-4.147 4.81-4.147 1.574 0 2.57.498 2.902.663l.58-.663.414.084-.415 3.565-.58-.083c0-1.658-.995-2.404-2.653-2.404-1.575 0-2.736.83-2.736 2.404 0 1.41 1.078 2.322 2.321 3.15l1.658 1.079c2.902 2.072 3.566 3.399 3.566 5.389 0 2.901-2.238 5.057-5.803 5.057v.001Zm-9.452-14.593H10.2c0-1.493-.663-2.073-1.99-2.073H4.48v6.55h2.404c1.243 0 1.493-.662 1.658-1.74h.58v4.643h-.58c-.165-1.244-.415-1.741-1.742-1.741H4.48v5.556c0 2.072.497 2.322 1.824 2.322v.662H0v-.662c1.575 0 1.824-.415 1.824-2.322V9.819c0-1.16-.498-1.658-1.824-1.658v-.58h8.623c1.492 0 1.824-.084 2.073-.581h.58l-.415 3.814h.001Zm89.465.995v9.95c0 2.155.496 2.57 1.823 2.57v.663h-9.783v-.663c.747 0 1.409-.25 1.409-.747 0-.332-.083-.912-.249-1.493l-.747-2.404H87.31c-.084.332-1.078 3.067-1.078 3.814 0 .663.747.83 1.243.83v.663h-4.56v-.663c.829 0 1.492-.084 2.072-1.824l4.23-13.516c-.25-.58-.581-.745-1.16-.83v-.58h3.73l4.476 14.18c.416 1.491.83 2.238 1.493 2.569.996-.331 1.245-.663 1.245-2.57V9.82c-.747-.994-.83-1.658-2.24-1.658v-.58h4.229l6.964 11.855V10.4c0-1.824-.413-2.239-1.824-2.239v-.58h9.286v.58c-.58 0-1.077.249-1.077.83 0 .414.166.828.331 1.326l2.654 5.722 2.571-5.555c.413-.746.498-1.16.498-1.576 0-.497-.334-.746-1.078-.746v-.58h4.394v.58c-1.078 0-1.743.995-2.239 2.154l-3.4 6.966v4.56c0 1.99.498 2.487 1.825 2.487v.663h-6.302v-.663c1.326 0 1.824-.496 1.824-2.487v-3.897l-3.649-7.711c-.662-1.492-.911-1.823-1.327-2.073-.828.331-1.077.912-1.077 2.239v12.769l.166 2.155-1.078.083-8.125-13.598h.001Zm-10.364-.83-2.323 7.547h4.81l-2.488-7.546ZM79.68 18.526h-1.243v3.565c0 1.824.496 2.239 1.907 2.239v.663h-6.385v-.663c1.327 0 1.825-.497 1.825-2.321V10.317c0-1.823-.498-2.155-1.825-2.155v-.58h4.809c4.643 0 7.379 1.409 7.379 5.223 0 3.98-3.316 5.721-6.467 5.721Zm-.83-9.784h-.413v8.54h.745c2.737 0 4.147-1.245 4.147-4.395 0-3.15-1.244-4.145-4.478-4.145ZM50.744 21.676c-3.15 0-5.306-2.24-5.306-5.472 0-3.068 2.24-5.472 5.306-5.472 2.986 0 5.224 2.322 5.224 5.472 0 3.067-2.322 5.472-5.224 5.472Zm0-9.95c-2.155 0-2.902 2.073-2.902 4.478 0 2.24.664 4.477 2.902 4.477 2.156 0 2.82-2.24 2.82-4.56 0-2.238-.83-4.395-2.82-4.395Zm-36.481 8.955v-.58c.83 0 .995-.248.995-.497 0-.333-.083-.581-.166-.83 0 0-.167-.664-.332-1.16h-3.234l-.331 1.078c-.083.248-.166.497-.166.828 0 .331.332.58.83.58v.581H8.624v-.58c.83 0 1.161-.248 1.492-1.16l2.488-7.463c-.083-.332-.332-.58-.83-.58v-.58h2.653l2.736 7.96c.415 1.408.83 1.823 1.492 1.823v.58h-4.393ZM13.1 12.638l-1.243 4.063h2.57l-1.326-4.063Z"
fill="#737373" />
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,5 @@
<svg width="82" height="32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M49.928 11.88c-1.318 0-2.354.286-3.39.854L46.632 6 40.32 7.138v.57l.66.094c.846.19 1.13.664 1.317 1.803.19 2.277.094 14.42 0 16.412 1.696.38 3.485.665 5.276.665 4.993 0 8.008-3.132 8.008-8.064 0-3.89-2.45-6.736-5.653-6.736v-.001Zm-2.166 13.757c-.377 0-.848 0-1.13-.095-.095-1.328-.189-6.925-.095-11.858.566-.19.941-.285 1.413-.285 2.075 0 3.205 2.467 3.205 5.502 0 3.796-1.414 6.736-3.392 6.736ZM16.58 6.378H0v.854l.942.095c1.224.19 1.696.948 1.884 2.75.283 3.416.189 9.583 0 12.523-.189 1.803-.659 2.657-1.884 2.75L0 25.54v.76h10.645v-.76l-1.13-.19c-1.226-.094-1.697-.948-1.884-2.75a77.793 77.793 0 0 1-.19-5.692l2.262.095c1.413 0 2.072 1.139 2.354 2.75h.849V13.02h-.849c-.283 1.613-.941 2.75-2.354 2.75l-2.26.096c0-3.226.094-6.262.189-8.064h3.296c2.545 0 3.864 1.612 4.805 4.459l.942-.285-.094-5.598h-.001Zm5.37 5.313c4.71 0 7.065 3.226 7.065 7.495 0 4.079-2.638 7.495-7.348 7.495s-7.065-3.227-7.065-7.495c0-4.08 2.638-7.495 7.349-7.495h-.001Zm-.283.949c-2.073 0-2.638 2.846-2.638 6.546 0 3.604.942 6.545 2.826 6.545 2.166 0 2.731-2.846 2.731-6.545 0-3.605-.94-6.546-2.92-6.546h.001Zm35.138 6.64c0-3.889 2.449-7.589 7.253-7.589 3.955 0 5.84 2.942 5.84 6.83h-8.76c-.095 3.51 1.6 6.073 4.992 6.073 1.508 0 2.26-.379 3.204-1.044l.376.474c-.943 1.328-3.014 2.657-5.652 2.657-4.24-.001-7.253-3.036-7.253-7.4Zm4.332-1.802 4.428-.095c0-1.897-.283-4.743-1.883-4.743-1.601 0-2.45 2.656-2.544 4.838Zm19.974-5.028c-1.13-.475-2.638-.759-4.334-.759-3.485 0-5.653 2.087-5.653 4.554s1.6 3.51 3.864 4.27c2.355.852 3.014 1.517 3.014 2.655 0 1.139-.848 2.182-2.355 2.182-1.79 0-3.11-1.043-4.145-3.89l-.66.19.095 4.175c1.13.474 3.202.855 4.993.855 3.674 0 6.03-1.899 6.03-4.839 0-1.993-1.038-3.13-3.487-4.08-2.638-1.043-3.579-1.707-3.579-2.94 0-1.234.85-2.088 1.98-2.088 1.695 0 2.826 1.043 3.675 3.606l.659-.19-.096-3.7h-.001Zm-39.85-.379c-1.6-.948-4.427-.474-5.934 2.942l.093-3.321-6.31 1.233v.57l.66.095c.848.095 1.223.57 1.319 1.803.188 2.277.093 6.261 0 8.253-.095 1.138-.47 1.707-1.32 1.802l-.66.095v.759h8.761v-.759l-1.13-.095c-.942-.095-1.224-.665-1.32-1.802-.188-1.803-.188-5.408-.093-7.684.47-.665 2.543-1.233 4.427 0l1.508-3.89Z"
fill="#737373" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,5 @@
<svg width="142" height="32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M18.359 24.268h5.186l2.78-15.914H21.14l-1.026 5.7h-4.496l1.025-5.7h-5.186l-2.78 15.914h5.186l1.045-5.955h4.496l-1.045 5.955ZM29.264 8.335l-1.578 8.854c-.138.69-.197 1.36-.197 1.992 0 4.693 4.102 5.403 6.567 5.403 5.166 0 7.395-1.716 8.203-6.35l1.736-9.919h-5.187l-1.479 8.322c-.473 2.603-.808 3.964-2.74 3.964-1.263 0-1.874-.67-1.874-2.051 0-.533.079-1.183.237-1.992l1.498-8.243h-5.186v.02ZM71.404 24.268h5.187l.73-4.101h2.444c4.516 0 7.02-2.446 7.02-6.902 0-3.136-2.169-4.93-5.974-4.93h-6.626l-2.78 15.933Zm8.085-8.026h-1.498l.69-3.746h1.4c1.144 0 1.755.572 1.755 1.617 0 1.321-.888 2.13-2.347 2.13ZM96.862 8c-5.64 0-9.011 3.648-9.011 9.78 0 4.26 2.681 6.824 7.177 6.824 5.64 0 9.012-3.648 9.012-9.781.02-4.28-2.662-6.823-7.178-6.823Zm-1.518 12.482c-1.34 0-2.13-.966-2.13-2.583 0-.611.06-1.144.178-1.755.394-2.09 1.065-4.003 3.175-4.003 1.34 0 2.13.966 2.13 2.583 0 .612-.06 1.144-.178 1.755-.395 2.07-1.065 4.003-3.175 4.003ZM122.083 24.268h5.186l2.051-11.654h3.904l.75-4.26h-13.272l-.749 4.26h4.141l-2.011 11.654ZM113.485 14.231c-1.636-.512-2.307-.73-2.307-1.498 0-.513.335-1.124 1.321-1.124.73 0 1.341.414 1.578 1.025l4.575-1.242C118.119 9.144 116.187 8 112.854 8c-6.27 0-6.763 4.2-6.763 5.482 0 2.603 1.38 4.2 4.377 5.029.789.216 1.696.453 1.696 1.32 0 .69-.513 1.125-1.4 1.125-.808 0-1.676-.474-1.972-1.302l-4.516 1.223c.493 2.366 2.722 3.707 6.212 3.707 2.662 0 7.119-.71 7.119-5.521.019-2.406-1.341-3.984-4.122-4.832ZM5.778 24.268l2.8-15.914H0v15.914h5.778ZM136.202 8.354l-2.78 15.914H142V8.354h-5.798ZM50.186 19.575h4.358l.71-4.003h-4.358l.493-2.958h6.093l.75-4.279h-11.28l-2.78 15.933h5.186l.828-4.693ZM63.773 19.575h4.378l.71-4.003h-4.358l.493-2.958h6.093l.75-4.279h-11.28l-2.78 15.933h5.185l.809-4.693Z"
fill="#737373" />
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,5 @@
<svg width="181" height="32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M66.825 12.77v11.34h-4.157V12.77H58.48V9.14h12.54v3.63h-4.195Zm13.89 6.85h-6.632a1.77 1.77 0 0 0 1.904 1.803 5.853 5.853 0 0 0 2.911-.793l1.507 2.506a8.69 8.69 0 0 1-4.528 1.293c-3.398 0-5.241-2.405-5.241-5.852 0-3.878 2.186-5.875 5.132-5.875 2.945 0 5.002 2.041 5.002 6.215-.044.272-.044.51-.056.704h.001Zm-5.099-4.117c-.884 0-1.37.601-1.495 1.724h3.206c-.193-1.145-.578-1.723-1.711-1.723Zm12.257 8.88c-3.296 0-5.256-2.098-5.256-5.897 0-3.402 1.745-5.83 5.347-5.83A4.676 4.676 0 0 1 92.28 15.2l-2.651 2.038c-.532-.975-.895-1.452-1.733-1.452-.837 0-1.47.986-1.47 2.766s.533 2.704 1.587 2.704c.725 0 1.23-.409 1.948-1.463l2.436 1.906c-1.31 1.94-2.526 2.688-4.52 2.688l-.004-.003Zm13.142-.238V17.76c0-1.463-.488-1.849-1.28-1.849-.793 0-1.311.386-1.311 1.804v6.43h-3.851V10.071l3.85-1.543v5.115a4.348 4.348 0 0 1 2.833-.986c2.462 0 3.637 1.656 3.637 4.604v6.884h-3.878Zm13.095.239c-4.453 0-6.797-3.3-6.797-7.735 0-4.82 2.832-7.734 6.797-7.734 3.681 0 5.131 1.577 6.162 4.41l-3.761 1.471c-.544-1.39-1.053-2.268-2.424-2.268-1.734 0-2.482 1.736-2.482 4.117 0 2.382.726 4.106 2.527 4.106 1.302 0 1.858-.704 2.673-2.121l3.513 1.871a6.446 6.446 0 0 1-6.209 3.878l.001.005Zm15.701-7.247a2.411 2.411 0 0 0-1.79-.942c-.94 0-1.517.453-1.517 1.826v6.124h-3.852V12.93h3.852v.816a3.394 3.394 0 0 1 4.213-.578l-.906 3.97Zm9.165 7.009v-.749a4.259 4.259 0 0 1-2.81.987c-2.462 0-3.636-1.656-3.636-4.617v-6.839h3.863v6.35c0 1.453.498 1.838 1.291 1.838.793 0 1.28-.385 1.28-1.792v-6.396h3.874v11.25l-3.862-.033Zm13.095 0V17.76c0-1.463-.499-1.849-1.28-1.849-.782 0-1.311.386-1.311 1.804v6.43h-3.851V12.93h3.851v.749a4.349 4.349 0 0 1 2.833-.987c2.461 0 3.636 1.656 3.636 4.604v6.884l-3.878-.033Zm11.385.238c-3.296 0-5.268-2.098-5.268-5.897 0-3.403 1.756-5.83 5.347-5.83a4.714 4.714 0 0 1 4.327 2.54l-2.65 2.007c-.545-.975-.907-1.452-1.734-1.452s-1.484.987-1.484 2.767c0 1.78.533 2.703 1.586 2.703.725 0 1.246-.408 1.949-1.463l2.435 1.905c-1.302 1.973-2.526 2.722-4.509 2.722l.001-.003v.001Zm13.13-.238V17.76c0-1.463-.488-1.849-1.281-1.849-.792 0-1.302.386-1.302 1.804v6.43h-3.851V10.071l3.851-1.543v5.115a4.296 4.296 0 0 1 2.821-.986c2.47 0 3.637 1.656 3.637 4.604v6.884h-3.875ZM0 3v8.54h8.519v17.066h8.53V11.539h8.518V3H0Zm34.096 17.067V11.54h-8.53v17.067h25.578v-8.539H34.096Zm0-17.066h17.048v8.538H34.096V3.001Z"
fill="#737373" />
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,5 @@
<svg width="121" height="32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M101.512 7.74v16.645h8.198c2.291 0 3.617-.362 4.582-1.207 1.206-1.085 1.808-3.015 1.808-7.116 0-4.102-.602-6.031-1.808-7.117-.965-.844-2.291-1.206-4.582-1.206h-8.198Zm11.213 8.322c0 3.618-.241 4.463-.965 4.945-.482.362-1.085.482-2.29.482h-4.582V10.513h4.582c1.205 0 1.808 0 2.29.483.724.603.965 1.447.965 5.066Zm7.595 12.002H96.268V4h24.052v24.064Zm-43.703-17.55V7.739h14.226v5.308h-3.015v-2.534h-5.787v3.981h4.582v2.654H82.04v4.463h5.909v-2.895h3.013v5.669H76.618V21.61h2.29V10.513h-2.29Zm-12.9 9.528c0 1.81.12 3.136.36 4.222h3.257c-.122-.844-.241-2.412-.241-4.463-.122-2.412-.845-2.774-2.533-3.136 1.929-.362 2.774-1.206 2.774-4.222 0-2.412-.363-3.377-1.086-3.98-.482-.482-1.325-.724-2.653-.724H53.468v16.646h3.376V17.87h4.703c.965 0 1.325.121 1.688.362s.482.604.482 1.81Zm-6.873-4.825v-4.583h5.426c.724 0 .965.12 1.084.241.241.241.483.603.483 2.05 0 1.448-.242 1.93-.483 2.172-.119.12-.36.24-1.084.24l-5.426-.12Zm15.312 12.847H48.044V4h24.052v24.064h.06Zm-30.38-6.453v2.774H30.32V21.61h4.099V10.513h-4.1V7.74h11.454v2.775h-4.1V21.61h4.101ZM22.423 7.739H19.29L17 20.887 14.346 8.704c-.12-.844-.482-.965-1.206-.965h-1.688c-.723 0-1.085.241-1.205.965L7.595 20.887 5.305 7.739H1.929l3.255 15.802c.12.723.362.844 1.206.844h2.29c.724 0 .965-.12 1.207-.845l2.532-11.458L14.95 23.54c.12.723.361.844 1.205.844h2.17c.724 0 1.085-.12 1.206-.845l2.894-15.8h-.002Zm1.688 20.325H0V4h24.052v24.064h.06Z"
fill="#737373" />
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

1
src/images/mycelium.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

231
src/images/phone-frame.svg Normal file
View File

@@ -0,0 +1,231 @@
<svg width="366" height="729" fill="none" xmlns="http://www.w3.org/2000/svg">
<g mask="url(#mask)">
<g filter="url(#a)">
<path
d="M363.315 64.213C363.315 22.99 341.312 1 300.092 1H66.751C25.53 1 3.528 22.99 3.528 64.213v44.68l-.857.143A2 2 0 0 0 1 111.009v24.611a2 2 0 0 0 1.671 1.973l.95.158a2.26 2.26 0 0 1-.093.236v26.173c.212.1.398.296.541.643l-1.398.233A2 2 0 0 0 1 167.009v47.611a2 2 0 0 0 1.671 1.973l1.368.228c-.139.319-.314.533-.511.653v16.637c.221.104.414.313.56.689l-1.417.236A2 2 0 0 0 1 237.009v47.611a2 2 0 0 0 1.671 1.973l1.347.225c-.135.294-.302.493-.49.607v377.681c0 41.213 22 63.208 63.223 63.208h95.074c.947-.504 2.717-.843 4.745-.843l.141.001h.194l.086-.001 33.704.005c1.849.043 3.442.37 4.323.838h95.074c41.222 0 63.223-21.999 63.223-63.212v-394.63c-.259-.275-.48-.796-.63-1.47l-.011-.133 1.655-.276A2 2 0 0 0 366 266.62v-77.611a2 2 0 0 0-1.671-1.973l-1.712-.285c.148-.839.396-1.491.698-1.811V64.213Z"
fill="url(#b)" />
<path
d="M363.315 64.213C363.315 22.99 341.312 1 300.092 1H66.751C25.53 1 3.528 22.99 3.528 64.213v44.68l-.857.143A2 2 0 0 0 1 111.009v24.611a2 2 0 0 0 1.671 1.973l.95.158a2.26 2.26 0 0 1-.093.236v26.173c.212.1.398.296.541.643l-1.398.233A2 2 0 0 0 1 167.009v47.611a2 2 0 0 0 1.671 1.973l1.368.228c-.139.319-.314.533-.511.653v16.637c.221.104.414.313.56.689l-1.417.236A2 2 0 0 0 1 237.009v47.611a2 2 0 0 0 1.671 1.973l1.347.225c-.135.294-.302.493-.49.607v377.681c0 41.213 22 63.208 63.223 63.208h95.074c.947-.504 2.717-.843 4.745-.843l.141.001h.194l.086-.001 33.704.005c1.849.043 3.442.37 4.323.838h95.074c41.222 0 63.223-21.999 63.223-63.212v-394.63c-.259-.275-.48-.796-.63-1.47l-.011-.133 1.655-.276A2 2 0 0 0 366 266.62v-77.611a2 2 0 0 0-1.671-1.973l-1.712-.285c.148-.839.396-1.491.698-1.811V64.213Z"
fill="url(#c)" />
</g>
<g filter="url(#d)">
<path
d="M5 133.772v-21.15c0-1.359-.54-2.661-1.5-3.622-.844-.073-2.496.257-2.496 2.157v24.562c.406 2.023 2.605 2.023 2.605 2.023A6.363 6.363 0 0 0 5 133.772Z"
fill="url(#e)" />
<path
d="M5 133.772v-21.15c0-1.359-.54-2.661-1.5-3.622-.844-.073-2.496.257-2.496 2.157v24.562c.406 2.023 2.605 2.023 2.605 2.023A6.363 6.363 0 0 0 5 133.772Z"
fill="url(#f)" fill-opacity=".1" />
</g>
<g filter="url(#g)">
<path
d="M5 213.772v-46.15c0-1.359-.54-2.661-1.5-3.622-.844-.073-2.496.257-2.496 2.157v49.562c.406 2.023 2.605 2.023 2.605 2.023A6.363 6.363 0 0 0 5 213.772Z"
fill="url(#h)" />
<path
d="M5 213.772v-46.15c0-1.359-.54-2.661-1.5-3.622-.844-.073-2.496.257-2.496 2.157v49.562c.406 2.023 2.605 2.023 2.605 2.023A6.363 6.363 0 0 0 5 213.772Z"
fill="url(#i)" fill-opacity=".1" />
</g>
<g filter="url(#j)">
<path
d="M5 283.772v-46.15c0-1.359-.54-2.661-1.5-3.622-.844-.073-2.496.257-2.496 2.157v49.562c.406 2.023 2.605 2.023 2.605 2.023A6.363 6.363 0 0 0 5 283.772Z"
fill="url(#k)" />
<path
d="M5 283.772v-46.15c0-1.359-.54-2.661-1.5-3.622-.844-.073-2.496.257-2.496 2.157v49.562c.406 2.023 2.605 2.023 2.605 2.023A6.363 6.363 0 0 0 5 283.772Z"
fill="url(#l)" fill-opacity=".1" />
</g>
<g filter="url(#m)">
<path
d="M362.004 266.772v-78.15a5.12 5.12 0 0 1 1.5-3.622c.844-.073 2.496.257 2.496 2.157v81.562c-.406 2.023-2.605 2.023-2.605 2.023a6.359 6.359 0 0 1-1.391-3.97Z"
fill="url(#n)" />
<path
d="M362.004 266.772v-78.15a5.12 5.12 0 0 1 1.5-3.622c.844-.073 2.496.257 2.496 2.157v81.562c-.406 2.023-2.605 2.023-2.605 2.023a6.359 6.359 0 0 1-1.391-3.97Z"
fill="url(#o)" fill-opacity=".1" />
</g>
<path
d="M305 14.5H59c-24.577 0-44.5 19.923-44.5 44.5v615c0 23.472 19.028 42.5 42.5 42.5h250c23.472 0 42.5-19.028 42.5-42.5V59c0-24.577-19.923-44.5-44.5-44.5Z"
stroke="url(#p)" stroke-opacity=".5" />
<g filter="url(#q)" shape-rendering="crispEdges">
<path
d="M16 59c0-23.748 19.252-43 43-43h246c23.748 0 43 19.252 43 43v615c0 23.196-18.804 42-42 42H58c-23.196 0-42-18.804-42-42V59Z"
fill="url(#r)" fill-opacity=".3" />
<path
d="M305 15.5H59c-24.024 0-43.5 19.476-43.5 43.5v615c0 23.472 19.028 42.5 42.5 42.5h248c23.472 0 42.5-19.028 42.5-42.5V59c0-24.024-19.476-43.5-43.5-43.5Z"
stroke="#000" stroke-opacity=".07" />
</g>
<g filter="url(#s)">
<rect x="154" y="29" width="56" height="5" rx="2.5" fill="#D4D4D4" />
</g>
</g>
<defs>
<mask id="mask">
<rect width="366" height="729" fill="#fff" />
<path fill-rule="evenodd" clip-rule="evenodd"
d="M89.728 24a4.213 4.213 0 0 1 4.213 4.212v2.527c0 10.235 8.3 18.532 18.539 18.532h139.04c10.239 0 18.539-8.297 18.539-18.532v-2.527A4.212 4.212 0 0 1 274.272 24h32.864C325.286 24 340 38.71 340 56.853v618.295c0 18.144-14.714 32.853-32.864 32.853H56.864c-18.15 0-32.864-14.709-32.864-32.853V56.853C24 38.709 38.714 24 56.864 24h32.864Z"
fill="#000" />
</mask>
<linearGradient id="e" x1="1.004" y1="123.367" x2="5" y2="123.367" gradientUnits="userSpaceOnUse">
<stop stop-color="#D4D4D4" />
<stop offset="1" stop-color="#E6E6E6" />
</linearGradient>
<linearGradient id="f" x1="3.002" y1="108.991" x2="3.002" y2="116.75" gradientUnits="userSpaceOnUse">
<stop stop-color="#171717" />
<stop offset=".783" stop-color="#171717" stop-opacity="0" />
</linearGradient>
<linearGradient id="h" x1="1.004" y1="190.867" x2="5" y2="190.867" gradientUnits="userSpaceOnUse">
<stop stop-color="#D4D4D4" />
<stop offset="1" stop-color="#E6E6E6" />
</linearGradient>
<linearGradient id="i" x1="3.002" y1="163.991" x2="3.002" y2="178.497" gradientUnits="userSpaceOnUse">
<stop stop-color="#171717" />
<stop offset=".783" stop-color="#171717" stop-opacity="0" />
</linearGradient>
<linearGradient id="k" x1="1.004" y1="260.867" x2="5" y2="260.867" gradientUnits="userSpaceOnUse">
<stop stop-color="#D4D4D4" />
<stop offset="1" stop-color="#E6E6E6" />
</linearGradient>
<linearGradient id="l" x1="3.002" y1="233.991" x2="3.002" y2="248.497" gradientUnits="userSpaceOnUse">
<stop stop-color="#171717" />
<stop offset=".783" stop-color="#171717" stop-opacity="0" />
</linearGradient>
<linearGradient id="n" x1="362.004" y1="226.25" x2="366" y2="226.25" gradientUnits="userSpaceOnUse">
<stop offset=".124" stop-color="#E6E6E6" />
<stop offset="1" stop-color="#D4D4D4" />
</linearGradient>
<linearGradient id="o" x1="364.002" y1="184.991" x2="364.002" y2="208.134" gradientUnits="userSpaceOnUse">
<stop stop-color="#171717" />
<stop offset=".783" stop-color="#171717" stop-opacity="0" />
</linearGradient>
<linearGradient id="p" x1="182" y1="15" x2="182" y2="716" gradientUnits="userSpaceOnUse">
<stop stop-color="#fff" />
<stop offset=".381" stop-color="#fff" stop-opacity="0" />
</linearGradient>
<filter id="a" x="-1" y="-1" width="367" height="730.314" filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dy="-2" />
<feGaussianBlur stdDeviation="1.5" />
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" />
<feBlend in2="shape" result="effect1_innerShadow_104_2007" />
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dx="-2" />
<feGaussianBlur stdDeviation="2" />
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
<feColorMatrix values="0 0 0 0 0.0901961 0 0 0 0 0.0901961 0 0 0 0 0.0901961 0 0 0 0.17 0" />
<feBlend in2="effect1_innerShadow_104_2007" result="effect2_innerShadow_104_2007" />
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dy="2" />
<feGaussianBlur stdDeviation=".5" />
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
<feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.6 0" />
<feBlend in2="effect2_innerShadow_104_2007" result="effect3_innerShadow_104_2007" />
</filter>
<filter id="d" x="1.004" y="108.991" width="4.996" height="28.751" filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dx="1" />
<feComposite in2="hardAlpha" operator="out" />
<feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.5 0" />
<feBlend in2="BackgroundImageFix" result="effect1_dropShadow_104_2007" />
<feBlend in="SourceGraphic" in2="effect1_dropShadow_104_2007" result="shape" />
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dx="-1" />
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0" />
<feBlend in2="shape" result="effect2_innerShadow_104_2007" />
</filter>
<filter id="g" x="1.004" y="163.991" width="4.996" height="53.751" filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dx="1" />
<feComposite in2="hardAlpha" operator="out" />
<feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.5 0" />
<feBlend in2="BackgroundImageFix" result="effect1_dropShadow_104_2007" />
<feBlend in="SourceGraphic" in2="effect1_dropShadow_104_2007" result="shape" />
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dx="-1" />
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0" />
<feBlend in2="shape" result="effect2_innerShadow_104_2007" />
</filter>
<filter id="j" x="1.004" y="233.991" width="4.996" height="53.751" filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dx="1" />
<feComposite in2="hardAlpha" operator="out" />
<feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.5 0" />
<feBlend in2="BackgroundImageFix" result="effect1_dropShadow_104_2007" />
<feBlend in="SourceGraphic" in2="effect1_dropShadow_104_2007" result="shape" />
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dx="-1" />
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0" />
<feBlend in2="shape" result="effect2_innerShadow_104_2007" />
</filter>
<filter id="m" x="361.004" y="184.991" width="4.996" height="85.751" filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dx="-1" />
<feComposite in2="hardAlpha" operator="out" />
<feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.5 0" />
<feBlend in2="BackgroundImageFix" result="effect1_dropShadow_104_2007" />
<feBlend in="SourceGraphic" in2="effect1_dropShadow_104_2007" result="shape" />
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dx="1" />
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0" />
<feBlend in2="shape" result="effect2_innerShadow_104_2007" />
</filter>
<filter id="q" x="15" y="15" width="334" height="703" filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dy="1" />
<feComposite in2="hardAlpha" operator="out" />
<feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.25 0" />
<feBlend in2="BackgroundImageFix" result="effect1_dropShadow_104_2007" />
<feBlend in="SourceGraphic" in2="effect1_dropShadow_104_2007" result="shape" />
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dy="1" />
<feGaussianBlur stdDeviation="2.5" />
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.03 0" />
<feBlend in2="shape" result="effect2_innerShadow_104_2007" />
</filter>
<filter id="s" x="154" y="29" width="56" height="6" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dy="1" />
<feComposite in2="hardAlpha" operator="out" />
<feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.3 0" />
<feBlend in2="BackgroundImageFix" result="effect1_dropShadow_104_2007" />
<feBlend in="SourceGraphic" in2="effect1_dropShadow_104_2007" result="shape" />
<feColorMatrix in="SourceAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" />
<feOffset dy="1" />
<feGaussianBlur stdDeviation=".5" />
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0" />
<feBlend in2="shape" result="effect2_innerShadow_104_2007" />
</filter>
<radialGradient id="b" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0 727 -642 0 184 1)">
<stop stop-color="#FAFAFA" />
<stop offset="1" stop-color="#E6E6E6" />
</radialGradient>
<radialGradient id="c" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0 319 -295.5 0 183.5 1)">
<stop stop-color="#fff" />
<stop offset=".533" stop-color="#fff" stop-opacity="0" />
</radialGradient>
<radialGradient id="r" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0 689 -326.783 0 182 27)">
<stop offset=".319" stop-color="#D4D4D4" />
<stop offset="1" stop-color="#E6E6E6" />
</radialGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

118
src/images/qr-code.svg Normal file
View File

@@ -0,0 +1,118 @@
<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>

After

Width:  |  Height:  |  Size: 9.9 KiB

83
src/styles/tailwind.css Normal file
View File

@@ -0,0 +1,83 @@
@import 'tailwindcss';
@plugin '@tailwindcss/forms';
@theme {
--text-*: initial;
--text-xs: 0.75rem;
--text-xs--line-height: 1rem;
--text-sm: 0.875rem;
--text-sm--line-height: 1.5rem;
--text-base: 1rem;
--text-base--line-height: 1.5rem;
--text-lg: 1.125rem;
--text-lg--line-height: 2rem;
--text-xl: 1.25rem;
--text-xl--line-height: 1.75rem;
--text-2xl: 1.5rem;
--text-2xl--line-height: 2rem;
--text-3xl: 2rem;
--text-3xl--line-height: 3rem;
--text-4xl: 2.5rem;
--text-4xl--line-height: 3rem;
--text-5xl: 3rem;
--text-5xl--line-height: 1;
--text-6xl: 3.75rem;
--text-6xl--line-height: 1;
--text-7xl: 4.5rem;
--text-7xl--line-height: 1;
--text-8xl: 6rem;
--text-8xl--line-height: 1;
--text-9xl: 8rem;
--text-9xl--line-height: 1;
--animate-fade-in: fade-in 0.5s linear forwards;
--animate-spin-slow: spin 4s linear infinite;
--animate-spin-slower: spin 6s linear infinite;
--animate-spin-reverse: spin-reverse 1s linear infinite;
--animate-spin-reverse-slow: spin-reverse 4s linear infinite;
--animate-spin-reverse-slower: spin-reverse 6s linear infinite;
--radius-4xl: 2rem;
--radius-5xl: 2.5rem;
--color-gray-50: oklch(0.985 0 0);
--color-gray-100: oklch(0.97 0 0);
--color-gray-200: oklch(0.922 0 0);
--color-gray-300: oklch(0.87 0 0);
--color-gray-400: oklch(0.708 0 0);
--color-gray-500: oklch(0.556 0 0);
--color-gray-600: oklch(0.439 0 0);
--color-gray-700: oklch(0.371 0 0);
--color-gray-800: oklch(0.269 0 0);
--color-gray-900: oklch(0.205 0 0);
--color-gray-950: oklch(0.145 0 0);
--font-sans: var(--font-inter);
--container-2xl: 40rem;
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes spin-reverse {
to {
transform: rotate(-360deg);
}
}
}
@theme inline {
--animate-marquee: marquee var(--marquee-duration) linear infinite;
@keyframes marquee {
100% {
transform: translateY(-50%);
}
}
}

28
tsconfig.json Normal file
View File

@@ -0,0 +1,28 @@
{
"compilerOptions": {
"target": "es6",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}