mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-05-02 20:34:16 -04:00
The Great Landing Renamening of 2024
This commit is contained in:
@@ -1,70 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import dynamic from 'next/dynamic';
|
||||
import { ReactNode, Suspense, useEffect, useState } from 'react';
|
||||
import { hasWebGLContext } from '~/utils/util';
|
||||
|
||||
const FADE = {
|
||||
start: 300, // start fading out at 100px
|
||||
end: 1300 // end fading out at 300px
|
||||
};
|
||||
|
||||
const Space = dynamic(() => import('~/components/Space'), { ssr: false });
|
||||
const Bubbles = dynamic(() => import('~/components/Bubbles').then((m) => m.Bubbles), {
|
||||
ssr: false
|
||||
});
|
||||
|
||||
export function Background() {
|
||||
const [opacity, setOpacity] = useState(0.6);
|
||||
const [isWindowResizing, setIsWindowResizing] = useState(false);
|
||||
const [canUseWebGL, setCanUseWebGL] = useState(hasWebGLContext());
|
||||
const [inner, setInner] = useState<ReactNode>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
const currentScrollY = window.scrollY;
|
||||
|
||||
if (currentScrollY <= FADE.start) {
|
||||
setOpacity(0.6);
|
||||
} else if (currentScrollY <= FADE.end) {
|
||||
const range = FADE.end - FADE.start;
|
||||
const diff = currentScrollY - FADE.start;
|
||||
const ratio = diff / range;
|
||||
setOpacity(0.6 - ratio);
|
||||
} else {
|
||||
setOpacity(0);
|
||||
}
|
||||
};
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('scroll', handleScroll);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
let resizeTimer: ReturnType<typeof setTimeout>;
|
||||
const handleResize = () => {
|
||||
setIsWindowResizing(true);
|
||||
clearTimeout(resizeTimer);
|
||||
resizeTimer = setTimeout(() => {
|
||||
setIsWindowResizing(false);
|
||||
}, 100);
|
||||
};
|
||||
window.addEventListener('resize', handleResize);
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
clearTimeout(resizeTimer);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setInner(canUseWebGL ? <Space onRenderFail={() => setCanUseWebGL(false)} /> : <Bubbles />);
|
||||
}, [canUseWebGL]);
|
||||
|
||||
return (
|
||||
<div style={{ opacity }}>
|
||||
<Suspense>{!isWindowResizing && inner}</Suspense>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
Discord,
|
||||
Github,
|
||||
Instagram,
|
||||
Opencollective,
|
||||
Twitch,
|
||||
Twitter
|
||||
} from '@sd/assets/svgs/brands';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { PropsWithChildren } from 'react';
|
||||
import companyLogoFull from '~/assets/company_full_logo.svg?url';
|
||||
|
||||
import { getLatestRelease } from './docs/changelog/data';
|
||||
import { DownloadButton } from './Downloads/Button';
|
||||
import { useCurrentPlatform } from './Downloads/Platform';
|
||||
|
||||
export function Footer() {
|
||||
const currentPlatform = useCurrentPlatform();
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Download Button */}
|
||||
<div className="col-span-2 flex translate-y-3 flex-col items-center justify-center">
|
||||
<div className="translate-y-3.5">
|
||||
<DownloadButton
|
||||
name={currentPlatform?.name ?? 'macOS'}
|
||||
link={`https://spacedrive.com/api/releases/desktop/stable/${currentPlatform?.os}/x86_64`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<footer
|
||||
className="py-12 text-white"
|
||||
style={{
|
||||
backgroundImage: `url('data:image/svg+xml,%3Csvg xmlns%3D%22http%3A//www.w3.org/2000/svg%22 viewBox%3D%220 0 1920 420%22 fill%3D%22none%22%3E%3Cpath d%3D%22M0 49.5L-0.0924661 48.5043L-1 48.5886V49.5V419.998V420.998H0H1920H1921V419.998V49.5V48.5886L1920.09 48.5043L1920 49.5C1920.09 48.5043 1920.09 48.5041 1920.09 48.5037L1920.07 48.5021L1920 48.4957L1919.73 48.4704L1918.63 48.3702C1917.67 48.2817 1916.23 48.1506 1914.33 47.9795C1910.53 47.6373 1904.91 47.1354 1897.58 46.4967C1882.93 45.2193 1861.5 43.3945 1834.35 41.2048C1780.04 36.8253 1702.88 30.9861 1611.44 25.147C1428.55 13.4688 1188.53 1.78979 960 1.78968C731.47 1.78958 491.446 13.4685 308.561 25.1468C217.117 30.986 139.955 36.8252 85.654 41.2047C58.5032 43.3945 37.0674 45.2193 22.419 46.4967C15.0947 47.1354 9.46731 47.6373 5.67073 47.9795C3.77243 48.1506 2.33185 48.2817 1.36574 48.3702C0.882678 48.4144 0.518236 48.4479 0.274504 48.4704L-0.000299077 48.4957L-0.0693103 48.5021L-0.0866324 48.5037C-0.0905066 48.5041 -0.0924661 48.5043 0 49.5Z%22 fill%3D%22%23141419%22 stroke%3D%22url%28%23paint0_linear_1926_240%29%22 stroke-width%3D%222%22/%3E%3Cdefs%3E%3ClinearGradient id%3D%22paint0_linear_1926_240%22 x1%3D%220%22 y1%3D%22167.5%22 x2%3D%221920%22 y2%3D%22167.5%22 gradientUnits%3D%22userSpaceOnUse%22%3E%3Cstop offset%3D%220.319255%22 stop-color%3D%22%231E1E26%22 stop-opacity%3D%220.4%22/%3E%3Cstop offset%3D%220.495%22 stop-color%3D%22%233692DF%22/%3E%3Cstop offset%3D%220.661993%22 stop-color%3D%22%231E1E26%22 stop-opacity%3D%220.5%22/%3E%3C/linearGradient%3E%3C/defs%3E%3C/svg%3E')`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center'
|
||||
}}
|
||||
>
|
||||
<div className="stroke-[gba(30, 30, 38, 0.40)] container mx-auto grid min-h-64 w-full max-w-[100rem] flex-shrink-0 grid-cols-1 gap-8 fill-[#141419] stroke-[2px] px-8 pt-[5.388125rem] lg:grid-cols-6">
|
||||
<div className="col-span-2 flex flex-row items-center">
|
||||
<div>
|
||||
<Image
|
||||
src={companyLogoFull}
|
||||
alt="Spacedrive Technology Inc."
|
||||
width={262}
|
||||
height={73}
|
||||
className="mr-4" // Use 'mr-4' to add spacing between the image and the text
|
||||
/>
|
||||
<p className="ml-[4.575rem] mt-2 text-ink-faint">
|
||||
329 Railway St
|
||||
<br />
|
||||
Vancouver, BC V6A 1A4
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Product Links */}
|
||||
<div className="text-gray-400">
|
||||
<h2 className="mb-4 text-sm font-semibold text-gray-500">PRODUCT</h2>
|
||||
<ul>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="#">Explorer</a>
|
||||
</li>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="#">Teams</a>
|
||||
</li>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="#">Assistant</a>
|
||||
</li>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="#">Changelog</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Download Links */}
|
||||
<div className="text-gray-400">
|
||||
<h2 className="mb-4 text-sm font-semibold text-gray-500">DOWNLOADS</h2>
|
||||
<ul>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="https://spacedrive.com/api/releases/desktop/stable/darwin/aarch64">
|
||||
macOS
|
||||
</a>
|
||||
</li>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="https://spacedrive.com/api/releases/desktop/stable/darwin/x86_64">
|
||||
macOS - Intel
|
||||
</a>
|
||||
</li>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="https://spacedrive.com/api/releases/desktop/stable/windows/x86_64">
|
||||
Windows
|
||||
</a>
|
||||
</li>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="https://spacedrive.com/api/releases/desktop/stable/linux/x86_64">
|
||||
Linux
|
||||
</a>
|
||||
</li>
|
||||
<li className="pointer-events-none mb-2 text-gray-450">
|
||||
<a href="#">iOS</a>
|
||||
</li>
|
||||
<li className="pointer-events-none mb-2 text-gray-450">
|
||||
<a href="#">Android</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Developer Links */}
|
||||
<div className="text-gray-400">
|
||||
<h2 className="mb-4 text-sm font-semibold text-gray-500">DEVELOPERS</h2>
|
||||
<ul>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="#">Documentation</a>
|
||||
</li>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="#">Contribute</a>
|
||||
</li>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="#">Extensions</a>
|
||||
</li>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="#">Self Host</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Company Links */}
|
||||
<div className="text-gray-400">
|
||||
<h2 className="mb-4 text-sm font-semibold text-gray-500">COMPANY</h2>
|
||||
<ul>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="#">Open Collective</a>
|
||||
</li>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="#">License</a>
|
||||
</li>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="#">Privacy</a>
|
||||
</li>
|
||||
<li className="mb-2 hover:text-white">
|
||||
<a href="#">Terms</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function FooterLink({
|
||||
blank,
|
||||
link,
|
||||
...props
|
||||
}: PropsWithChildren<{ link: string; blank?: boolean }>) {
|
||||
return (
|
||||
<Link
|
||||
href={link}
|
||||
target={blank ? '_blank' : ''}
|
||||
className="text-gray-300 duration-300 hover:text-white hover:opacity-50"
|
||||
rel="noreferrer"
|
||||
{...props}
|
||||
>
|
||||
{props.children}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { Metadata } from 'next';
|
||||
import { useMDXComponent } from 'next-contentlayer/hooks';
|
||||
import Image from 'next/image';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { BlogTag } from '~/components/BlogTag';
|
||||
import { BlogTag } from '~/components/blog-tag';
|
||||
import { BlogMDXComponents } from '~/components/mdx';
|
||||
|
||||
export function generateStaticParams(): Array<Props['params']> {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { allPosts } from '@contentlayer/generated';
|
||||
import dayjs from 'dayjs';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { BlogTag } from '~/components/BlogTag';
|
||||
import { BlogTag } from '~/components/blog-tag';
|
||||
|
||||
export const metadata = {
|
||||
title: 'Spacedrive Blog',
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
import { PropsWithChildren } from 'react';
|
||||
import { TooltipProvider } from '@sd/ui';
|
||||
|
||||
export function Providers({ children }: PropsWithChildren) {
|
||||
export function ClientProviders({ children }: PropsWithChildren) {
|
||||
return <TooltipProvider>{children}</TooltipProvider>;
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
import { CaretRight } from '@phosphor-icons/react';
|
||||
import { useParams } from 'next/navigation';
|
||||
import { Fragment } from 'react';
|
||||
import { toTitleCase } from '~/utils/util';
|
||||
import { toTitleCase } from '~/utils/misc';
|
||||
|
||||
export function Breadcrumbs() {
|
||||
const { slug } = useParams<{ slug?: string[] }>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { iconConfig } from '~/utils/contentlayer';
|
||||
import { toTitleCase } from '~/utils/util';
|
||||
import { toTitleCase } from '~/utils/misc';
|
||||
|
||||
import { getReleasesCategories } from '../changelog/data';
|
||||
import { navigationMeta } from '../data';
|
||||
|
||||
@@ -6,7 +6,7 @@ import { getMDXComponent } from 'next-contentlayer/hooks';
|
||||
import Link from 'next/link';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { DocMDXComponents } from '~/components/mdx';
|
||||
import { toTitleCase } from '~/utils/util';
|
||||
import { toTitleCase } from '~/utils/misc';
|
||||
|
||||
import { getDoc } from '../data';
|
||||
import { Markdown } from '../Markdown';
|
||||
|
||||
@@ -3,7 +3,7 @@ import { getMDXComponent } from 'next-contentlayer/hooks';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { getRelease, githubFetch } from '~/app/api/github';
|
||||
import { DocMDXComponents } from '~/components/mdx';
|
||||
import { toTitleCase } from '~/utils/util';
|
||||
import { toTitleCase } from '~/utils/misc';
|
||||
|
||||
import { Markdown } from '../../../Markdown';
|
||||
import { getReleasesCategories } from '../../data';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getRecentReleases, getReleaseFrontmatter, githubFetch } from '~/app/api/github';
|
||||
import { toTitleCase } from '~/utils/util';
|
||||
import { toTitleCase } from '~/utils/misc';
|
||||
|
||||
import { SectionMeta } from '../data';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { IBM_Plex_Sans, Inter } from 'next/font/google';
|
||||
|
||||
export const plexSansFont = IBM_Plex_Sans({
|
||||
weight: ['400', '600', '700'],
|
||||
weight: ['300', '400', '600', '700'],
|
||||
subsets: ['latin'],
|
||||
display: 'swap',
|
||||
variable: '--font-plex-sans'
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { Metadata, Viewport } from 'next';
|
||||
import { PropsWithChildren } from 'react';
|
||||
|
||||
import { Footer } from './Footer';
|
||||
import { NavBar } from './NavBar';
|
||||
import { PropsWithChildren, useRef } from 'react';
|
||||
import { GlobalFooter } from '~/components/global-footer';
|
||||
import { NavBar } from '~/components/global-nav-bar';
|
||||
|
||||
import '@sd/ui/style/style.scss';
|
||||
import '~/styles/prism.css';
|
||||
@@ -10,9 +9,10 @@ import '~/styles/style.scss';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import PlausibleProvider from 'next-plausible';
|
||||
import { DisclaimerBanner } from '~/components/disclaimer-banner';
|
||||
|
||||
import { ClientProviders } from './client-providers';
|
||||
import { interFont, plexSansFont } from './fonts';
|
||||
import { Providers } from './Providers';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL('https://spacedrive.com'),
|
||||
@@ -29,10 +29,11 @@ export const metadata: Metadata = {
|
||||
|
||||
export const viewport: Viewport = {
|
||||
themeColor: [
|
||||
// embed color on discord, for instance
|
||||
{ color: '#E751ED', media: 'not screen' },
|
||||
// background color in Safari
|
||||
{ color: '#0E0E12', media: 'screen' }
|
||||
{ color: '#0E0E12', media: 'screen' },
|
||||
// MUST BE LAST to actually work on embeds
|
||||
// embed color on discord, for instance
|
||||
{ color: '#E751ED', media: 'not screen' }
|
||||
]
|
||||
};
|
||||
|
||||
@@ -51,17 +52,14 @@ export default function Layout({ children }: PropsWithChildren) {
|
||||
/>
|
||||
</head>
|
||||
<body className="font-plex">
|
||||
<div className="absolute top-0 z-[100] w-screen select-none bg-transparent pt-1 text-center italic text-white/30">
|
||||
The content of this site is not final and should not be considered official
|
||||
marketing or advertising from Spacedrive Technology Inc.
|
||||
</div>
|
||||
<Providers>
|
||||
<DisclaimerBanner />
|
||||
<ClientProviders>
|
||||
<div className="overflow-hidden bg-[#0E0E12]">
|
||||
<NavBar />
|
||||
<main className="z-10 m-auto max-w-[100rem]">{children}</main>
|
||||
<Footer />
|
||||
<GlobalFooter />
|
||||
</div>
|
||||
</Providers>
|
||||
</ClientProviders>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 319 KiB |
@@ -3,7 +3,7 @@
|
||||
import { SmileyXEyes } from '@phosphor-icons/react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Button } from '@sd/ui';
|
||||
import Markdown from '~/components/Markdown';
|
||||
import { MarkdownPage } from '~/components/markdown-page';
|
||||
|
||||
export const metadata = {
|
||||
title: 'Not Found - Spacedrive'
|
||||
@@ -13,7 +13,7 @@ export default function NotFound() {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<Markdown classNames="flex w-full justify-center">
|
||||
<MarkdownPage classNames="flex w-full justify-center">
|
||||
<div className="m-auto flex flex-col items-center">
|
||||
<div className="h-32" />
|
||||
<SmileyXEyes className="mb-3 size-44" />
|
||||
@@ -35,6 +35,6 @@ export default function NotFound() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-80" />
|
||||
</Markdown>
|
||||
</MarkdownPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { ArrowUp } from '@phosphor-icons/react/dist/ssr';
|
||||
import { Github } from '@sd/assets/svgs/brands';
|
||||
import Image from 'next/image';
|
||||
import { BentoBox } from '~/components/BentoBox';
|
||||
import CyclingImage from '~/components/CyclingImage';
|
||||
import { toTitleCase } from '~/utils/util';
|
||||
import { BentoBox } from '~/components/bento-box';
|
||||
import { CTAButtons } from '~/components/cta-buttons';
|
||||
import CyclingImage from '~/components/cycling-image';
|
||||
import { GoldenBadge } from '~/components/golden-badge';
|
||||
import { toTitleCase } from '~/utils/misc';
|
||||
|
||||
import { getLatestRelease, getReleaseFrontmatter, githubFetch } from './api/github';
|
||||
import { Background } from './Background';
|
||||
import { Banner } from './Banner';
|
||||
import { Downloads } from './Downloads';
|
||||
|
||||
export const metadata = {
|
||||
title: 'Spacedrive — A file manager from the future.',
|
||||
@@ -46,7 +44,7 @@ export default async function Page() {
|
||||
className="mt-[50px] lg:mt-0"
|
||||
href={`/docs/changelog/alpha/${release.tag_name}`}
|
||||
/> */}
|
||||
<Banner
|
||||
<GoldenBadge
|
||||
headline={`30k+ stars on GitHub`}
|
||||
className="mt-[50px] lg:mt-0"
|
||||
href={`/docs/changelog/alpha/${release.tag_name}`}
|
||||
@@ -60,7 +58,7 @@ export default async function Page() {
|
||||
Your files, always within reach. Experience seamless synchronization, intuitive
|
||||
management, and powerful discovery tools — all in one place.
|
||||
</p>
|
||||
<Downloads
|
||||
<CTAButtons
|
||||
latestVersion={[
|
||||
frontmatter.category && toTitleCase(frontmatter.category),
|
||||
`v${release.tag_name}`
|
||||
@@ -119,7 +117,6 @@ export default async function Page() {
|
||||
</div>
|
||||
{/* <WormHole /> */}
|
||||
{/* <BentoBoxes /> */}
|
||||
{/* <CloudStorage /> */}
|
||||
{/* <DownloadToday isWindows={deviceOs?.isWindows} /> */}
|
||||
{/* <div className="h-[100px] sm:h-[200px] w-full" /> */}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ArrowRight } from '@phosphor-icons/react/dist/ssr';
|
||||
import Link from 'next/link';
|
||||
import Markdown from '~/components/Markdown';
|
||||
import { MarkdownPage } from '~/components/markdown-page';
|
||||
|
||||
import { investors, teamMembers } from './people';
|
||||
import { TeamMember } from './TeamMember';
|
||||
@@ -12,7 +12,7 @@ export const metadata = {
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<Markdown articleClassNames="mx-auto mt-32 prose-a:text-white">
|
||||
<MarkdownPage articleClassNames="mx-auto mt-32 prose-a:text-white">
|
||||
<div className="team-page relative mx-auto">
|
||||
<div className="relative z-10">
|
||||
<h1 className="fade-in-heading text-5xl leading-tight sm:leading-snug">
|
||||
@@ -71,6 +71,6 @@ export default function Page() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Markdown>
|
||||
</MarkdownPage>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import Image from 'next/image';
|
||||
import React from 'react';
|
||||
|
||||
const AccessData = () => {
|
||||
return (
|
||||
<div className="my-[150px] md:my-[300px]">
|
||||
<Image
|
||||
width={390}
|
||||
height={300}
|
||||
quality={100}
|
||||
className="mx-auto mb-10"
|
||||
alt="data globe"
|
||||
src="/images/misc/globe.webp"
|
||||
/>
|
||||
<div className="relative">
|
||||
<h1 className="bg-gradient-to-r from-white to-violet-400 bg-clip-text text-center text-[25px] font-bold text-transparent md:text-[30px]">
|
||||
Access data from anywhere
|
||||
</h1>
|
||||
<p className="mx-auto w-full max-w-[800px] text-center text-sm text-ink-faint md:text-lg">
|
||||
users can enjoy the freedom of accessing their important files, documents, and
|
||||
media assets from any device with an internet connection, ensuring productivity
|
||||
and convenience on the go.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessData;
|
||||
@@ -1,212 +0,0 @@
|
||||
import dynamic from 'next/dynamic';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { useMemo } from 'react';
|
||||
import { Button, tw } from '@sd/ui';
|
||||
import { useWindowSize } from '~/hooks/useWindowSize';
|
||||
|
||||
import { MagicCard, MagicContainer } from './MagicCard';
|
||||
import PlatformsArt from './PlatformsArt';
|
||||
import SpacedropArt from './SpacedropArt';
|
||||
|
||||
const Heading = tw.h1`z-30 text-center font-semibold leading-tight text-white text-lg`;
|
||||
const Text = tw.p`leading-2 text-zinc-500 z-30 mb-8 mt-1 max-w-4xl text-center text-[14px] lg:leading-8"`;
|
||||
|
||||
interface Props {
|
||||
rowSpan?: number;
|
||||
colSpan?: number;
|
||||
className?: string;
|
||||
bgUrl?: string;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const BentoBox = ({ rowSpan = 1, colSpan = 1, className = '', children, bgUrl = '' }: Props) => (
|
||||
<div
|
||||
className="rounded-[12px] border border-white/10"
|
||||
style={{
|
||||
gridRow: `span ${rowSpan}`,
|
||||
gridColumn: `span ${colSpan}`,
|
||||
backgroundImage: `url('${bgUrl}')`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
height: '420px'
|
||||
}}
|
||||
>
|
||||
<MagicCard className={className}>{children}</MagicCard>
|
||||
</div>
|
||||
);
|
||||
|
||||
// const AppFrameOuter = tw.div`relative m-auto flex w-full max-w-7xl rounded-lg border border-black transition-opacity`;
|
||||
// const AppFrameInner = tw.div`z-30 flex w-full rounded-lg border-t border-app-line/50 bg-app/30 backdrop-blur`;
|
||||
|
||||
const GitHubButton = dynamic(() => import('react-github-btn'), { ssr: false });
|
||||
|
||||
const BentoBoxes = () => {
|
||||
const { width } = useWindowSize();
|
||||
const particleCount = useMemo(() => {
|
||||
if (width) {
|
||||
return width > 768 ? 50 : 25;
|
||||
}
|
||||
return 50;
|
||||
}, [width]);
|
||||
return (
|
||||
<MagicContainer className="flex h-fit w-full max-w-7xl auto-rows-[420px] flex-col gap-4 lg:grid lg:grid-cols-6">
|
||||
<BentoBox colSpan={4} className="p-6" bgUrl="images/bento/encrypt-bg.webp">
|
||||
<div className="bento-radial-gradient-fade absolute right-0 top-0 z-20 size-full" />
|
||||
<div className="relative z-20">
|
||||
<Heading>Encryption</Heading>
|
||||
<Text className="mx-auto max-w-[417px]">
|
||||
Your files and folders are fully encrypted through our algorithm, preventing
|
||||
unauthorized access and guaranteed protection.
|
||||
</Text>
|
||||
</div>
|
||||
<div className="flex h-4/5 w-auto items-start justify-center">
|
||||
<Image
|
||||
className="mx-auto"
|
||||
alt="Encryption"
|
||||
loading="lazy"
|
||||
width={200}
|
||||
height={300}
|
||||
quality={100}
|
||||
src="/images/bento/lock.webp"
|
||||
/>
|
||||
</div>
|
||||
</BentoBox>
|
||||
<BentoBox colSpan={2} className="p-6">
|
||||
<div className="flex h-3/4 w-auto items-center justify-center">
|
||||
<Image
|
||||
className="mx-auto mt-3 brightness-125"
|
||||
alt="Powerful tags"
|
||||
width={300}
|
||||
quality={100}
|
||||
loading="lazy"
|
||||
height={100}
|
||||
src="/images/bento/tags.webp"
|
||||
/>
|
||||
</div>
|
||||
<div className="bento-radial-gradient-fade absolute right-0 top-0 z-20 size-full" />
|
||||
|
||||
<div className="relative z-40 mt-2 md:mt-7">
|
||||
<Heading>Powerful tags</Heading>
|
||||
<Text>
|
||||
Create and apply tags to your files and folders, and instantly locate
|
||||
desired content through filterable tags.
|
||||
</Text>
|
||||
</div>
|
||||
</BentoBox>
|
||||
<BentoBox colSpan={2} className="p-6">
|
||||
<div className="relative z-30">
|
||||
<Heading>Search everything</Heading>
|
||||
<Text className="mx-auto max-w-[417px]">
|
||||
Easily find your files and folders through our search
|
||||
</Text>
|
||||
</div>
|
||||
<div className="bento-radial-gradient-fade absolute right-0 top-0 z-20 size-full" />
|
||||
<div className="flex h-4/5 w-auto items-start justify-center">
|
||||
<Image
|
||||
className="mx-auto brightness-110"
|
||||
alt="Search"
|
||||
width={340}
|
||||
loading="lazy"
|
||||
height={300}
|
||||
quality={100}
|
||||
src="/images/bento/search.webp"
|
||||
/>
|
||||
</div>
|
||||
</BentoBox>
|
||||
<BentoBox colSpan={2} className="p-6">
|
||||
<div className="bento-radial-gradient-fade absolute right-0 top-0 z-20 size-full" />
|
||||
<div className="flex h-4/5 w-auto items-center justify-center">
|
||||
<Image
|
||||
className="mx-auto brightness-125"
|
||||
alt="Library"
|
||||
width={340}
|
||||
height={300}
|
||||
loading="lazy"
|
||||
quality={100}
|
||||
src="/images/bento/library.webp"
|
||||
/>
|
||||
</div>
|
||||
<div className="relative z-30 mt-[30px]">
|
||||
<Heading>Full Ownership & Control</Heading>
|
||||
<Text className="mx-auto">Make Spacedrive yours</Text>
|
||||
</div>
|
||||
</BentoBox>
|
||||
<BentoBox colSpan={2} className="p-6">
|
||||
<div className="relative z-30">
|
||||
<Heading>Spacedrop</Heading>
|
||||
<Text className="mx-auto max-w-[417px]">
|
||||
Send files to other devices quickly and easily
|
||||
</Text>
|
||||
</div>
|
||||
<div className="bento-radial-gradient-fade absolute right-0 top-0 z-20 size-full" />
|
||||
<div className="flex h-4/5 w-auto items-center justify-center">
|
||||
<div
|
||||
style={
|
||||
{
|
||||
'--floatduration': '4s'
|
||||
} as React.CSSProperties
|
||||
}
|
||||
className="floating"
|
||||
>
|
||||
<SpacedropArt />
|
||||
</div>
|
||||
</div>
|
||||
</BentoBox>
|
||||
<BentoBox
|
||||
colSpan={3}
|
||||
className="h-[354px] p-6 brightness-110 lg:h-auto"
|
||||
bgUrl="images/bento/opensource-bg.webp"
|
||||
>
|
||||
<div className="relative z-30">
|
||||
<Heading>Free & Opensource</Heading>
|
||||
<Text className="mx-auto">
|
||||
Developers and users can contribute with new ideas and features
|
||||
</Text>
|
||||
</div>
|
||||
<div className="bento-radial-gradient-fade absolute right-0 top-0 z-20 h-[420px] w-full" />
|
||||
<div className="absolute-center relative z-40 mt-[40px] md:mt-0">
|
||||
<Link target="_blank" href="https://github.com/spacedriveapp/spacedrive">
|
||||
<Button
|
||||
size="lg"
|
||||
className="contribute-drop-shadow mx-auto mb-4 block cursor-pointer border-0 bg-gradient-to-r from-emerald-400 to-cyan-500 text-sm text-black !transition-all !duration-200"
|
||||
>
|
||||
{`<>`} Contribute
|
||||
</Button>
|
||||
</Link>
|
||||
<GitHubButton
|
||||
href="https://github.com/spacedriveapp/spacedrive"
|
||||
data-size="large"
|
||||
data-show-count="true"
|
||||
aria-label="Star spacedriveapp/spacedrive on GitHub"
|
||||
>
|
||||
Star
|
||||
</GitHubButton>
|
||||
</div>
|
||||
</BentoBox>
|
||||
<BentoBox colSpan={3} className="relative p-6">
|
||||
<div
|
||||
style={
|
||||
{
|
||||
'--floatduration': '4s'
|
||||
} as React.CSSProperties
|
||||
}
|
||||
className="floating mx-auto flex h-[300px] w-full max-w-[500px]"
|
||||
>
|
||||
<PlatformsArt />
|
||||
</div>
|
||||
<div className="absolute-center h-[120px] w-[300px] bg-gradient-to-r from-fuchsia-500 from-10% to-blue-500 opacity-10 blur-[175px]" />
|
||||
<div className="relative z-30">
|
||||
<Heading>Cross platform</Heading>
|
||||
<Text className="mx-auto max-w-[400px]">
|
||||
Windows, macOS, Linux, iOS, Android, and the web. Spacedrive is everywhere.
|
||||
</Text>
|
||||
</div>
|
||||
<div className="bento-radial-gradient-fade absolute right-0 top-0 z-20 size-full" />
|
||||
</BentoBox>
|
||||
</MagicContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default BentoBoxes;
|
||||
@@ -1,96 +0,0 @@
|
||||
import clsx from 'clsx';
|
||||
import { useInView } from 'framer-motion';
|
||||
import Image from 'next/image';
|
||||
import React, { useRef } from 'react';
|
||||
|
||||
import CloudStorageArt from './CloudStorageArt';
|
||||
|
||||
const CloudStorage = () => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const isInView = useInView(ref, {
|
||||
amount: 0.5,
|
||||
once: true
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={clsx(
|
||||
'relative mt-[200px] w-full max-w-[960px] opacity-0 md:mt-[250px]',
|
||||
isInView && 'fade-in-heading'
|
||||
)}
|
||||
>
|
||||
<div className="absolute-horizontal-center top-[-100px] h-[248px] w-[500px] md:top-[-55px] md:w-[960px]">
|
||||
<div className="relative right-[270px] z-10 md:right-0">
|
||||
<CloudStorageArt />
|
||||
</div>
|
||||
<Image
|
||||
src="/images/cloud-providers/gradient.webp"
|
||||
className="absolute inset-x-0 top-[-100px] mx-auto"
|
||||
width={560}
|
||||
height={200}
|
||||
alt="cloud gradient"
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-[60px] flex w-full flex-col flex-wrap items-center justify-center gap-5 md:flex-row">
|
||||
<CloudCard
|
||||
title="Dropbox"
|
||||
logoUrl="/images/cloud-providers/icons/dropbox.svg"
|
||||
imageWidth={49}
|
||||
/>
|
||||
<CloudCard title="iCloud" logoUrl="/images/cloud-providers/icons/icloud.svg" />
|
||||
<CloudCard
|
||||
title="Google drive"
|
||||
logoUrl="/images/cloud-providers/icons/google-drive.svg"
|
||||
imageWidth={53}
|
||||
/>
|
||||
<div className="flex w-full flex-col justify-center gap-5 md:flex-row">
|
||||
<CloudCard
|
||||
imageWidth={45}
|
||||
title="Mega"
|
||||
logoUrl="/images/cloud-providers/icons/mega.svg"
|
||||
/>
|
||||
<CloudCard
|
||||
title="Amazon S3"
|
||||
logoUrl="/images/cloud-providers/icons/s3.svg"
|
||||
imageWidth={40}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<h1 className="mt-[50px] bg-gradient-to-r from-white to-blue-400 bg-clip-text text-center text-[30px] font-bold leading-10 text-transparent">
|
||||
Coming soon
|
||||
</h1>
|
||||
<h1 className="bg-gradient-to-r from-white to-blue-300 bg-clip-text text-center text-[20px] text-transparent md:text-[40px] md:leading-[50px]">
|
||||
Combine all storage locations & clouds
|
||||
</h1>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface Props {
|
||||
logoUrl: string;
|
||||
title: string;
|
||||
imageWidth?: number;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const CloudCard = ({ logoUrl, title, imageWidth = 70, children }: Props) => {
|
||||
return (
|
||||
<div className="flex w-full flex-col justify-center rounded-md border border-[#161524] bg-[#080710]/30 py-6 text-center backdrop-blur-sm transition-all duration-200 hover:brightness-125 md:h-[165px] md:basis-[30%]">
|
||||
{children}
|
||||
<div className="relative z-10">
|
||||
<Image
|
||||
width={imageWidth}
|
||||
height={100}
|
||||
quality={100}
|
||||
alt="cloud storage"
|
||||
className="mx-auto"
|
||||
src={logoUrl}
|
||||
/>
|
||||
<p className="mt-3 font-semibold">{title}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CloudStorage;
|
||||
@@ -1,126 +0,0 @@
|
||||
const CloudStorageArt = () => {
|
||||
return (
|
||||
<svg
|
||||
width="971"
|
||||
height="249"
|
||||
viewBox="0 0 971 249"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0 146.095H74.6846M74.6846 146.095V248H187.161V161.425H249.699M74.6846 146.095H119.675V20.7418H226M249.699 161.425H312.236H347V138M249.699 161.425V129.411M387.82 97.3964V74.5M387.82 97.3964H347M387.82 97.3964V112.5H449.5M516.494 112.5V168.64H625.821M516.494 112.5H449.5M516.494 112.5V94.5H456V74.5M746.846 0V37.8764H638.868V52.3055M625.821 168.64H735.148V115.433H638.868V83.8691M625.821 168.64V205.615H810.733V146.095H970V79.36H896.215L869.221 52.3055H782V83.8691H638.868M625.821 168.64V135H555.5V103M638.868 52.3055H599V20.7418H501V41.3709M638.868 52.3055V83.8691M501 41.3709V62H555.5V103M501 41.3709H456V74.5M456 74.5H387.82M387.82 74.5V44.1891H339M638.868 83.8691H593.5V103H555.5M249.699 129.411V97.3964H298.349M249.699 129.411H183V79.36H226V20.7418M226 20.7418H278.943V44.1891H339M347 97.3964H298.349M347 97.3964V138M298.349 97.3964V70H339V44.1891M449.5 112.5V138H347"
|
||||
stroke="url(#paint0_linear_630_169)"
|
||||
/>
|
||||
<path
|
||||
className="gradient-path"
|
||||
d="M391.5 74.5H456V41.3333H478.5L501 41.3333V62H555.5V103H593.5V84H635.5"
|
||||
stroke="url(#paint1_linear_630_169)"
|
||||
/>
|
||||
<g className="circle-two" filter="url(#filter0_d_630_169)">
|
||||
<circle cx="388" cy="74" r="4" fill="#376FA9" className="circle-two" />
|
||||
</g>
|
||||
|
||||
<g className="circle-one" filter="url(#filter1_d_630_169)">
|
||||
<circle className="circle-one" cx="639" cy="84" r="4" fill="#376FA9" />
|
||||
</g>
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_d_630_169"
|
||||
x="372"
|
||||
y="58"
|
||||
width="32"
|
||||
height="32"
|
||||
filterUnits="userSpaceOnUse"
|
||||
colorInterpolationFilters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset />
|
||||
<feGaussianBlur stdDeviation="6" />
|
||||
<feComposite in2="hardAlpha" operator="out" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 0.231373 0 0 0 0 0.443137 0 0 0 0 0.67451 0 0 0 1 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="BackgroundImageFix"
|
||||
result="effect1_dropShadow_630_169"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="effect1_dropShadow_630_169"
|
||||
result="shape"
|
||||
/>
|
||||
</filter>
|
||||
<filter
|
||||
id="filter1_d_630_169"
|
||||
x="623"
|
||||
y="68"
|
||||
width="32"
|
||||
height="32"
|
||||
filterUnits="userSpaceOnUse"
|
||||
colorInterpolationFilters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
/>
|
||||
<feOffset />
|
||||
<feGaussianBlur stdDeviation="6" />
|
||||
<feComposite in2="hardAlpha" operator="out" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 0.235294 0 0 0 0 0.458824 0 0 0 0 0.698039 0 0 0 1 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="BackgroundImageFix"
|
||||
result="effect1_dropShadow_630_169"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="effect1_dropShadow_630_169"
|
||||
result="shape"
|
||||
/>
|
||||
</filter>
|
||||
<linearGradient
|
||||
id="paint0_linear_630_169"
|
||||
x1="49"
|
||||
y1="80.9999"
|
||||
x2="769.061"
|
||||
y2="0.547463"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#343259" stopOpacity="0" />
|
||||
<stop offset="0.593922" stopColor="#25273E" />
|
||||
<stop offset="1" stopColor="#343259" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_630_169"
|
||||
x1="633.5"
|
||||
y1="83.5"
|
||||
x2="388.5"
|
||||
y2="74"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#4AA8FF" stopOpacity="0" />
|
||||
<stop offset="0.552083" stopColor="#4AA8FF" />
|
||||
<stop offset="1" stopColor="#4AA8FF" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default CloudStorageArt;
|
||||
@@ -1,53 +0,0 @@
|
||||
import { useId } from 'react';
|
||||
|
||||
import { cn } from './MagicCard';
|
||||
|
||||
interface DotPatternProps {
|
||||
width?: any;
|
||||
height?: any;
|
||||
x?: any;
|
||||
y?: any;
|
||||
cx?: any;
|
||||
cy?: any;
|
||||
cr?: any;
|
||||
className?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
export function DotPattern({
|
||||
width = 16,
|
||||
height = 16,
|
||||
x = 0,
|
||||
y = 0,
|
||||
cx = 1,
|
||||
cy = 1,
|
||||
cr = 1,
|
||||
className,
|
||||
...props
|
||||
}: DotPatternProps) {
|
||||
const id = useId();
|
||||
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className={cn('absolute inset-0 h-full w-full fill-gray-400/30', className)}
|
||||
{...props}
|
||||
>
|
||||
<defs>
|
||||
<pattern
|
||||
id={id}
|
||||
width={width}
|
||||
height={height}
|
||||
patternUnits="userSpaceOnUse"
|
||||
patternContentUnits="userSpaceOnUse"
|
||||
x={x}
|
||||
y={y}
|
||||
>
|
||||
<circle id="pattern-circle" cx={cy} cy={cy} r={cr} />
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" strokeWidth={0} fill={`url(#${id})`} />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default DotPattern;
|
||||
@@ -1,39 +0,0 @@
|
||||
import { Download } from '@phosphor-icons/react/dist/ssr';
|
||||
import clsx from 'clsx';
|
||||
import { useInView } from 'framer-motion';
|
||||
import React, { useRef } from 'react';
|
||||
import { Button } from '@sd/ui';
|
||||
|
||||
interface Props {
|
||||
isWindows?: boolean;
|
||||
}
|
||||
|
||||
const DownloadToday = ({ isWindows }: Props) => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const isInView = useInView(ref, {
|
||||
amount: 0.5,
|
||||
once: true
|
||||
});
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={clsx(
|
||||
'relative mb-[150px] mt-10 flex h-[250px] w-full max-w-7xl flex-col justify-center bg-app-box/30 opacity-0',
|
||||
'overflow-hidden rounded-md p-2 text-center md:mb-[250px] md:h-[350px]',
|
||||
isInView && 'fade-in-heading'
|
||||
)}
|
||||
>
|
||||
<div className="relative z-10">
|
||||
<h1 className="mx-auto w-full max-w-[500px] text-[20px] font-semibold leading-tight md:text-[30px]">
|
||||
Ready to get organized?
|
||||
</h1>
|
||||
<Button className="mx-auto mt-5 flex gap-2" variant="accent" size="md">
|
||||
<Download size={20} />
|
||||
{isWindows ? 'Download on Windows' : 'Download on Mac'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DownloadToday;
|
||||
@@ -1,30 +0,0 @@
|
||||
import { type IconProps } from '@phosphor-icons/react';
|
||||
import clsx from 'clsx';
|
||||
import { Button, LinkButtonProps } from '@sd/ui';
|
||||
|
||||
interface Props extends LinkButtonProps {
|
||||
className?: string;
|
||||
text: string;
|
||||
icon?: IconProps;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export function HomeCTA({ className, text, icon, ...props }: Props) {
|
||||
return (
|
||||
<Button
|
||||
size="lg"
|
||||
className={clsx(
|
||||
'home-button-border-gradient relative z-30 flex cursor-pointer items-center gap-2 !rounded-[7px] border-0 !bg-[#2F3152]/30 py-2 text-sm !backdrop-blur-lg hover:brightness-110 md:text-[16px]',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<>
|
||||
{icon && icon}
|
||||
{text}
|
||||
</>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export default HomeCTA;
|
||||
@@ -1,246 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import clsx, { ClassValue } from 'clsx';
|
||||
import { CSSProperties, ReactNode, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
interface MousePosition {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
function useMousePosition(): MousePosition {
|
||||
const [mousePosition, setMousePosition] = useState<MousePosition>({
|
||||
x: 0,
|
||||
y: 0
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const handleMouseMove = (event: globalThis.MouseEvent) => {
|
||||
setMousePosition({ x: event.clientX, y: event.clientY });
|
||||
};
|
||||
|
||||
window.addEventListener('mousemove', handleMouseMove);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('mousemove', handleMouseMove);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return mousePosition;
|
||||
}
|
||||
|
||||
interface MagicContainerProps {
|
||||
children?: ReactNode;
|
||||
className?: any;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
const MagicContainer = ({ children, className, style }: MagicContainerProps) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const mousePosition = useMousePosition();
|
||||
const mouse = useRef<{ x: number; y: number }>({ x: 0, y: 0 });
|
||||
const containerSize = useRef<{ w: number; h: number }>({ w: 0, h: 0 });
|
||||
const [boxes, setBoxes] = useState<Array<HTMLElement>>([]);
|
||||
|
||||
const init = useCallback(() => {
|
||||
if (containerRef.current) {
|
||||
containerSize.current.w = containerRef.current.offsetWidth;
|
||||
containerSize.current.h = containerRef.current.offsetHeight;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onMouseMove = useCallback(() => {
|
||||
if (containerRef.current) {
|
||||
const rect = containerRef.current.getBoundingClientRect();
|
||||
const { w, h } = containerSize.current;
|
||||
const x = mousePosition.x - rect.left;
|
||||
const y = mousePosition.y - rect.top;
|
||||
const inside = x < w && x > 0 && y < h && y > 0;
|
||||
|
||||
mouse.current.x = x;
|
||||
mouse.current.y = y;
|
||||
boxes.forEach((box) => {
|
||||
const boxX = -(box.getBoundingClientRect().left - rect.left) + mouse.current.x;
|
||||
const boxY = -(box.getBoundingClientRect().top - rect.top) + mouse.current.y;
|
||||
box.style.setProperty('--mouse-x', `${boxX}px`);
|
||||
box.style.setProperty('--mouse-y', `${boxY}px`);
|
||||
|
||||
if (inside) {
|
||||
box.style.setProperty('--opacity', `1`);
|
||||
} else {
|
||||
box.style.setProperty('--opacity', `0`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [boxes, mousePosition]);
|
||||
|
||||
useEffect(() => {
|
||||
init();
|
||||
containerRef.current &&
|
||||
setBoxes(Array.from(containerRef.current.children).map((el) => el as HTMLElement));
|
||||
}, [init]);
|
||||
|
||||
useEffect(() => {
|
||||
init();
|
||||
window.addEventListener('resize', init);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('resize', init);
|
||||
};
|
||||
}, [setBoxes, init]);
|
||||
|
||||
useEffect(() => {
|
||||
onMouseMove();
|
||||
}, [mousePosition, onMouseMove]);
|
||||
|
||||
return (
|
||||
<div style={style} className={className} ref={containerRef}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface MagicCardProps {
|
||||
/**
|
||||
* @default div
|
||||
* @type React.ElementType
|
||||
* @description
|
||||
* The component to render the card as
|
||||
* */
|
||||
as?: React.ElementType;
|
||||
/**
|
||||
* @default ""
|
||||
* @type string
|
||||
* @description
|
||||
* The className of the card
|
||||
*/
|
||||
className?: string;
|
||||
|
||||
/**
|
||||
* @default ""
|
||||
* @type ReactNode
|
||||
* @description
|
||||
* The children of the card
|
||||
* */
|
||||
children?: ReactNode;
|
||||
|
||||
/**
|
||||
* @default 600
|
||||
* @type number
|
||||
* @description
|
||||
* The size of the spotlight effect in pixels
|
||||
* */
|
||||
size?: number;
|
||||
|
||||
/**
|
||||
* ]@default "#475569"
|
||||
* @type string
|
||||
* @description
|
||||
* The border color of the card
|
||||
*/
|
||||
borderColor?: string;
|
||||
|
||||
/**
|
||||
* @default 1
|
||||
* @type number
|
||||
* @description
|
||||
* The border width of the card
|
||||
* */
|
||||
borderWidth?: number;
|
||||
|
||||
/**
|
||||
* @default 16
|
||||
* @type number
|
||||
* @description
|
||||
* The border radius of the card
|
||||
* */
|
||||
borderRadius?: number;
|
||||
|
||||
/**
|
||||
* @default true
|
||||
* @type boolean
|
||||
* @description
|
||||
* Whether to show the spotlight
|
||||
* */
|
||||
spotlight?: boolean;
|
||||
|
||||
/**
|
||||
* @default "rgba(255,255,255,0.03)"
|
||||
* @type string
|
||||
* @description
|
||||
* The color of the spotlight
|
||||
* */
|
||||
spotlightColor?: string;
|
||||
|
||||
/**
|
||||
* @default true
|
||||
* @type boolean
|
||||
* @description
|
||||
* Whether to isolate the card which is being hovered
|
||||
* */
|
||||
isolated?: boolean;
|
||||
|
||||
/**
|
||||
* @default "transparent"
|
||||
* @type string
|
||||
* @description
|
||||
* The background of the card
|
||||
* */
|
||||
background?: string;
|
||||
}
|
||||
|
||||
const MagicCard = ({
|
||||
as: Component = 'div',
|
||||
className,
|
||||
children,
|
||||
size = 600,
|
||||
borderColor = 'rgba(86,114,157, 0.2)',
|
||||
borderWidth = 1,
|
||||
borderRadius = 10,
|
||||
spotlight = true,
|
||||
spotlightColor = 'rgba(86,114,157, 0.01)',
|
||||
isolated = false,
|
||||
background = 'rgba(255,255,255,0.03)'
|
||||
}: MagicCardProps) => {
|
||||
const spotlightStyles =
|
||||
'before:pointer-events-none before:absolute before:w-full before:h-full before:rounded-[var(--border-radius)] before:top-0 before:left-0 before:duration-500 before:transition-opacity before:bg-[radial-gradient(var(--mask-size)_circle_at_var(--mouse-x)_var(--mouse-y),var(--spotlight-color),transparent_40%)] before:z-[3] before:blur-xs';
|
||||
|
||||
const borderStyles =
|
||||
'after:pointer-events-none after:absolute after:w-full after:h-full after:rounded-[var(--border-radius)] after:top-0 after:left-0 after:duration-500 after:transition-opacity after:bg-[radial-gradient(var(--mask-size)_circle_at_var(--mouse-x)_var(--mouse-y),var(--border-color),transparent_40%)] after:z-[1]';
|
||||
return (
|
||||
<Component
|
||||
style={{
|
||||
'--border-radius': `${borderRadius}px`,
|
||||
'--border-width': `${borderWidth}px`,
|
||||
'--border-color': `${borderColor}`,
|
||||
'--mask-size': `${size}px`,
|
||||
'--spotlight-color': `${spotlightColor}`,
|
||||
background
|
||||
}}
|
||||
className={cn(
|
||||
'relative h-full w-full overflow-hidden rounded-[var(--border-radius)] transition-all duration-200 hover:brightness-[1.25]',
|
||||
isolated && [borderStyles, 'after:opacity-0 after:hover:opacity-100'],
|
||||
isolated &&
|
||||
spotlight && [spotlightStyles, 'before:opacity-0 before:hover:opacity-100'],
|
||||
!isolated && [borderStyles, 'after:opacity-[var(--opacity)]'],
|
||||
!isolated && spotlight && [spotlightStyles, 'before:opacity-[var(--opacity)]']
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'absolute inset-[var(--border-width)] z-[2] rounded-[var(--border-radius)]',
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</Component>
|
||||
);
|
||||
};
|
||||
|
||||
export { MagicCard, MagicContainer };
|
||||
@@ -1,166 +0,0 @@
|
||||
import { Book, Chat, DotsThreeVertical, MapPin, User } from '@phosphor-icons/react/dist/ssr';
|
||||
import { Academia, Discord, Github } from '@sd/assets/svgs/brands';
|
||||
import clsx from 'clsx';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { NextRouter, useRouter } from 'next/router';
|
||||
import { PropsWithChildren, useEffect, useState } from 'react';
|
||||
import { Button, Dropdown } from '@sd/ui';
|
||||
import { positions } from '~/app/careers/data';
|
||||
import { getWindow } from '~/utils/util';
|
||||
|
||||
import Logo from '../../public/logo.png';
|
||||
|
||||
function NavLink(props: PropsWithChildren<{ link?: string }>) {
|
||||
return (
|
||||
<Link
|
||||
href={props.link ?? '#'}
|
||||
target={props.link?.startsWith('http') ? '_blank' : undefined}
|
||||
className="cursor-pointer p-4 text-[11pt] text-gray-300 no-underline transition hover:text-gray-50"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{props.children}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
function link(path: string, router: NextRouter) {
|
||||
const selected = getWindow()?.location.href.includes(path);
|
||||
|
||||
return {
|
||||
selected,
|
||||
onClick: () => router.push(path),
|
||||
className: clsx(selected && 'bg-accent/20')
|
||||
};
|
||||
}
|
||||
|
||||
function redirect(href: string) {
|
||||
return () => (window.location.href = href);
|
||||
}
|
||||
|
||||
export default function NavBar() {
|
||||
const [isAtTop, setIsAtTop] = useState(true);
|
||||
const window = getWindow();
|
||||
|
||||
function onScroll() {
|
||||
if ((getWindow()?.pageYOffset || 0) < 20) setIsAtTop(true);
|
||||
else if (isAtTop) setIsAtTop(false);
|
||||
}
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
if (!window) return;
|
||||
setTimeout(onScroll, 0);
|
||||
getWindow()?.addEventListener('scroll', onScroll);
|
||||
return () => getWindow()?.removeEventListener('scroll', onScroll);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="navbar-blur fixed z-[55] h-16 w-full !bg-black/10 px-2 transition">
|
||||
<div className="relative m-auto flex h-full max-w-[100rem] items-center p-5">
|
||||
<Link href="/" className="absolute flex flex-row items-center">
|
||||
<Image alt="Spacedrive logo" src={Logo} className="z-30 mr-3 size-8" />
|
||||
<h3 className="text-xl font-bold text-white">Spacedrive</h3>
|
||||
</Link>
|
||||
|
||||
<div className="m-auto hidden space-x-4 text-white lg:block">
|
||||
<NavLink link="/roadmap">Roadmap</NavLink>
|
||||
<NavLink link="/team">Team</NavLink>
|
||||
{/* <NavLink link="/pricing">Pricing</NavLink> */}
|
||||
<NavLink link="/blog">Blog</NavLink>
|
||||
<NavLink link="/docs/product/getting-started/introduction">Docs</NavLink>
|
||||
<div className="relative inline">
|
||||
<NavLink link="/careers">Careers</NavLink>
|
||||
{positions.length > 0 ? (
|
||||
<span className="absolute -right-2 -top-1 rounded-md bg-primary/80 px-[5px] text-xs">
|
||||
{` ${positions.length} `}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 lg:hidden" />
|
||||
<Dropdown.Root
|
||||
button={
|
||||
<Button
|
||||
aria-label="mobile-menu"
|
||||
className="ml-[140px] hover:!bg-transparent"
|
||||
size="icon"
|
||||
>
|
||||
<DotsThreeVertical weight="bold" className="size-6" />
|
||||
</Button>
|
||||
}
|
||||
className="right-4 top-2 block h-6 w-44 text-white lg:hidden"
|
||||
itemsClassName="!rounded-2xl shadow-2xl shadow-black p-2 !bg-gray-850 mt-2 !border-gray-500 text-[15px]"
|
||||
>
|
||||
<Dropdown.Section>
|
||||
<Dropdown.Item
|
||||
icon={Discord}
|
||||
onClick={redirect('https://discord.gg/gTaF2Z44f5')}
|
||||
>
|
||||
Join Discord
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
icon={Github}
|
||||
onClick={redirect('https://github.com/spacedriveapp/spacedrive')}
|
||||
>
|
||||
Repository
|
||||
</Dropdown.Item>
|
||||
</Dropdown.Section>
|
||||
<Dropdown.Section>
|
||||
<Dropdown.Item icon={MapPin} {...link('/roadmap', router)}>
|
||||
Roadmap
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item icon={User} {...link('/team', router)}>
|
||||
Team
|
||||
</Dropdown.Item>
|
||||
{/* <Dropdown.Item icon={Money} {...link('/pricing', router)}>
|
||||
Pricing
|
||||
</Dropdown.Item> */}
|
||||
<Dropdown.Item icon={Chat} {...link('/blog', router)}>
|
||||
Blog
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
icon={Book}
|
||||
{...link('/docs/product/getting-started/introduction', router)}
|
||||
>
|
||||
Docs
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item icon={Academia} {...link('/careers', router)}>
|
||||
Careers
|
||||
{positions.length > 0 ? (
|
||||
<span className="ml-2 rounded-md bg-primary px-[5px] py-px text-xs">
|
||||
{positions.length}
|
||||
</span>
|
||||
) : null}
|
||||
</Dropdown.Item>
|
||||
</Dropdown.Section>
|
||||
</Dropdown.Root>
|
||||
|
||||
<div className="absolute right-3 hidden flex-row space-x-5 lg:flex">
|
||||
<Link
|
||||
aria-label="discord"
|
||||
href="https://discord.gg/gTaF2Z44f5"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Discord className="size-6 text-white opacity-100 duration-300 hover:opacity-50" />
|
||||
</Link>
|
||||
<Link
|
||||
aria-label="github"
|
||||
href="https://github.com/spacedriveapp/spacedrive"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Github className="size-6 text-white opacity-100 duration-300 hover:opacity-50" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute bottom-0 flex h-1 w-full flex-row items-center justify-center pt-4 opacity-100">
|
||||
<div className="h-px w-1/2 bg-gradient-to-r from-transparent to-white/10"></div>
|
||||
<div className="h-px w-1/2 bg-gradient-to-l from-transparent to-white/10"></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import { Newspaper } from '@phosphor-icons/react/dist/ssr';
|
||||
import clsx from 'clsx';
|
||||
import Link from 'next/link';
|
||||
|
||||
export interface NewBannerProps {
|
||||
headline: string;
|
||||
href: string;
|
||||
link: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const NewBanner: React.FC<NewBannerProps> = (props) => {
|
||||
const { headline, href, link } = props;
|
||||
|
||||
return (
|
||||
<aside
|
||||
onClick={() => (window.location.href = href)}
|
||||
className={clsx(
|
||||
props.className,
|
||||
'news-banner-border-gradient news-banner-glow animation-delay-1 fade-in-whats-new z-10 mb-5 flex w-fit cursor-pointer flex-row rounded-full bg-black/10 px-5 py-2.5 text-xs backdrop-blur-md transition hover:bg-purple-900/20 sm:w-auto sm:text-base'
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Newspaper weight="fill" className="text-white" size={20} />
|
||||
<p className="font-regular truncate text-white">{headline}</p>
|
||||
</div>
|
||||
<div role="separator" className="h-22 mx-4 w-px bg-zinc-700/70" />
|
||||
<Link
|
||||
href={href}
|
||||
className="font-regular shrink-0 bg-gradient-to-r from-violet-400 to-fuchsia-400 bg-clip-text text-transparent decoration-primary-600"
|
||||
>
|
||||
{link} <span aria-hidden="true">→</span>
|
||||
</Link>
|
||||
</aside>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewBanner;
|
||||
File diff suppressed because one or more lines are too long
@@ -1,96 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { PointMaterial, Points, Trail } from '@react-three/drei';
|
||||
import { Canvas, useFrame } from '@react-three/fiber';
|
||||
import { inSphere as randomInSphere } from 'maath/random';
|
||||
import { useRef, useState } from 'react';
|
||||
import { Color, WebGL1Renderer, WebGLRenderer, type Mesh } from 'three';
|
||||
|
||||
const Stars = (props: any) => {
|
||||
const ref = useRef<Mesh>();
|
||||
const [sphere] = useState(() => randomInSphere(new Float32Array(35000), { radius: 1 }));
|
||||
|
||||
useFrame((_, delta) => {
|
||||
if (ref.current) {
|
||||
ref.current.rotation.x -= delta / 300;
|
||||
ref.current.rotation.y -= delta / 300;
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<group rotation={[0, 0, Math.PI / 4]}>
|
||||
<Points ref={ref} positions={sphere} stride={3} frustumCulled={false} {...props}>
|
||||
<PointMaterial
|
||||
transparent
|
||||
color="#ffffff"
|
||||
size={0.001}
|
||||
sizeAttenuation={true}
|
||||
depthWrite={false}
|
||||
/>
|
||||
</Points>
|
||||
</group>
|
||||
);
|
||||
};
|
||||
|
||||
function ShootingStar() {
|
||||
const ref = useRef<any>();
|
||||
|
||||
useFrame((state) => {
|
||||
const t = state.clock.getElapsedTime() * 0.5;
|
||||
if (ref.current) {
|
||||
ref.current.position.set(
|
||||
Math.sin(t) * 4,
|
||||
Math.atan(t) * Math.cos(t / 2) * 2,
|
||||
Math.cos(t) * 4
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<Trail width={0.05} length={8} color={new Color(2, 1, 10)} attenuation={(t) => t * t}>
|
||||
<mesh ref={ref}>
|
||||
<sphereGeometry args={[0.005]} />
|
||||
<meshBasicMaterial color={[10, 1, 10]} toneMapped={false} />
|
||||
</mesh>
|
||||
</Trail>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Space({ onRenderFail }: { onRenderFail?: (error: unknown) => void }) {
|
||||
return (
|
||||
<div className="absolute left-0 top-0 z-0 h-screen w-screen bg-black opacity-50">
|
||||
<Canvas
|
||||
gl={(canvas) => {
|
||||
try {
|
||||
// https://github.com/pmndrs/react-three-fiber/blob/f2b430c/packages/fiber/src/core/index.tsx#L113-L119
|
||||
return new WebGLRenderer({
|
||||
alpha: true,
|
||||
canvas: canvas,
|
||||
antialias: true,
|
||||
powerPreference: 'high-performance'
|
||||
});
|
||||
} catch (error) {
|
||||
try {
|
||||
// Let's try WebGL1, maybe the user's browser doesn't support WebGL2
|
||||
return new WebGL1Renderer({
|
||||
alpha: true,
|
||||
canvas: canvas,
|
||||
antialias: true,
|
||||
powerPreference: 'high-performance'
|
||||
});
|
||||
} catch (error) {
|
||||
onRenderFail?.(error);
|
||||
// Return an empty renderer, just so the app doesn't crash
|
||||
return { render() {}, setSize() {}, setPixelRatio() {} };
|
||||
}
|
||||
}
|
||||
}}
|
||||
camera={{ position: [0, 0, 0] }}
|
||||
>
|
||||
<ShootingStar />
|
||||
<ShootingStar />
|
||||
<Stars />
|
||||
</Canvas>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import Image from 'next/image';
|
||||
import React from 'react';
|
||||
|
||||
const WormHole = () => {
|
||||
return (
|
||||
<div className="relative mb-[225px] mt-[240px] flex w-full max-w-[800px] items-center justify-center sm:mb-[220px] sm:mt-[250px] md:mb-[280px] md:mt-[340px] lg:my-[400px]">
|
||||
<div className="absolute top-[-150px] w-full max-w-[450px] rotate-[300deg] sm:top-[-200px] sm:max-w-[500px] md:top-[-200px] lg:top-auto lg:mr-[250px] lg:max-w-full lg:rotate-0">
|
||||
<div className="absolute left-[200px] top-[50px] z-10 size-full">
|
||||
<Image
|
||||
width={30}
|
||||
height={45}
|
||||
quality={100}
|
||||
alt="heart"
|
||||
className="heart"
|
||||
src="/images/icons/heart.svg"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute left-[200px] top-[50px] z-10 size-full">
|
||||
<Image
|
||||
width={40}
|
||||
height={45}
|
||||
quality={100}
|
||||
alt="game"
|
||||
className="game"
|
||||
src="/images/icons/game.svg"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute top-[-100px] z-10 size-full sm:left-[200px] sm:top-[10px]">
|
||||
<Image
|
||||
width={40}
|
||||
height={45}
|
||||
quality={100}
|
||||
alt="image"
|
||||
className="image"
|
||||
src="/images/icons/image.svg"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute left-[120px] top-[-50px] z-10 size-full sm:left-[200px] sm:top-[-10px]">
|
||||
<Image
|
||||
width={40}
|
||||
height={45}
|
||||
quality={100}
|
||||
alt="lock"
|
||||
className="lock"
|
||||
src="/images/icons/lock.svg"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute left-[200px] top-[350px] z-10 size-full lg:left-[200px] lg:top-[300px]">
|
||||
<Image
|
||||
width={40}
|
||||
height={45}
|
||||
quality={100}
|
||||
alt="video"
|
||||
className="videoicon"
|
||||
src="/images/icons/video.svg"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute left-[200px] top-[150px] z-10 size-full">
|
||||
<Image
|
||||
width={40}
|
||||
height={45}
|
||||
quality={100}
|
||||
alt="application"
|
||||
className="appicon"
|
||||
src="/images/icons/application.svg"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute left-[120px] top-[50px] z-10 size-full lg:left-[200px] lg:top-[120px]">
|
||||
<Image
|
||||
width={40}
|
||||
height={45}
|
||||
quality={100}
|
||||
alt="collection"
|
||||
className="collection"
|
||||
src="/images/icons/collection.svg"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute left-[120px] top-[50px] z-10 size-full sm:left-[200px] sm:top-[300px] lg:left-[200px] lg:top-[420px]">
|
||||
<Image
|
||||
width={40}
|
||||
height={45}
|
||||
quality={100}
|
||||
alt="node"
|
||||
className="node"
|
||||
src="/images/icons/node.svg"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute left-[60px] top-[-190px] z-10 size-full sm:left-[50px] sm:top-[50px] lg:left-[200px] lg:top-[490px]">
|
||||
<Image
|
||||
width={40}
|
||||
height={45}
|
||||
quality={100}
|
||||
alt="texturedmesh"
|
||||
className="texturedmesh"
|
||||
src="/images/icons/texturedmesh.png"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute left-[120px] top-[50px] z-10 size-full md:left-[200px] md:top-[350px]">
|
||||
<Image
|
||||
width={40}
|
||||
height={45}
|
||||
quality={100}
|
||||
alt="database"
|
||||
className="database"
|
||||
src="/images/icons/database.svg"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute left-[100px] top-[-200px] z-10 size-full sm:left-[150px] sm:top-[50px]">
|
||||
<Image
|
||||
width={40}
|
||||
height={45}
|
||||
quality={100}
|
||||
alt="package"
|
||||
className="package"
|
||||
src="/images/icons/package.svg"
|
||||
/>
|
||||
</div>
|
||||
<Image
|
||||
loading="eager"
|
||||
width={1500}
|
||||
height={626}
|
||||
quality={100}
|
||||
alt="wormhole"
|
||||
src="/images/misc/wormhole.webp"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
'worm-hole-border-gradient relative top-[100px] z-20 flex w-full max-w-[500px] flex-col rounded-lg',
|
||||
'items-center justify-center gap-2 bg-gradient-to-r from-[#080710]/0 to-[#080710]/50 p-8 backdrop-blur-sm'
|
||||
)}
|
||||
>
|
||||
<h1 className="bg-gradient-to-r from-white to-indigo-300 bg-clip-text text-[20px] font-bold text-transparent">
|
||||
Heading
|
||||
</h1>
|
||||
<p className="text-center text-sm text-gray-400">
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Nam, iure ea dolores
|
||||
atque unde fugit ad libero debitis nemo quis culpa sequi illum aliquam iusto
|
||||
harum quo laborum ducimus voluptas Lorem, ipsum dolor sit amet consectetur
|
||||
adipisicing elit. Similique eos, voluptatum, ipsam facilis placeat tempore
|
||||
consequuntur officia distinctio voluptate blanditiis tenetur, animi ut ea
|
||||
laboriosam laborum culpa autem accusantium reprehenderit!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WormHole;
|
||||
@@ -6,8 +6,8 @@ import clsx from 'clsx';
|
||||
import { motion } from 'framer-motion';
|
||||
import { usePlausible } from 'next-plausible';
|
||||
import { useState } from 'react';
|
||||
import DiscordButton from '~/components/discord-button';
|
||||
|
||||
import DiscordButton from '../DiscordButton';
|
||||
import { DownloadButton } from './Button';
|
||||
import { DockerDialog } from './DockerDialog';
|
||||
import { BASE_DL_LINK, Platform, platforms, useCurrentPlatform } from './Platform';
|
||||
@@ -16,7 +16,7 @@ interface Props {
|
||||
latestVersion: string;
|
||||
}
|
||||
|
||||
export function Downloads({ latestVersion }: Props) {
|
||||
export function CTAButtons({ latestVersion }: Props) {
|
||||
const [selectedPlatform, setSelectedPlatform] = useState<Platform | null>(null);
|
||||
const currentPlatform = useCurrentPlatform();
|
||||
|
||||
22
apps/landing/src/components/disclaimer-banner.tsx
Normal file
22
apps/landing/src/components/disclaimer-banner.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
export const DisclaimerBanner = () => {
|
||||
const disclaimerBannerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={disclaimerBannerRef}
|
||||
className="fixed bottom-0 left-0 z-[100] w-screen cursor-pointer select-none bg-black/75 px-2 py-1 text-center italic text-red-300/50"
|
||||
title="Click to hide"
|
||||
onClick={() => {
|
||||
disclaimerBannerRef.current &&
|
||||
(disclaimerBannerRef.current.style.visibility = 'hidden');
|
||||
}}
|
||||
>
|
||||
The content of this site is not final and should not be considered official marketing or
|
||||
advertising from Spacedrive Technology Inc.
|
||||
</div>
|
||||
);
|
||||
};
|
||||
212
apps/landing/src/components/global-footer.tsx
Normal file
212
apps/landing/src/components/global-footer.tsx
Normal file
@@ -0,0 +1,212 @@
|
||||
'use client';
|
||||
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { PropsWithChildren } from 'react';
|
||||
import companyLogoFull from '~/assets/company_full_logo.svg?url';
|
||||
import { DownloadButton } from '~/components/cta-buttons/Button';
|
||||
import { useCurrentPlatform } from '~/components/cta-buttons/Platform';
|
||||
|
||||
export function GlobalFooter() {
|
||||
const currentPlatform = useCurrentPlatform();
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Download Button */}
|
||||
<div className="col-span-2 flex translate-y-3 flex-col items-center justify-center">
|
||||
<div className="translate-y-3.5">
|
||||
<DownloadButton
|
||||
name={currentPlatform?.name ?? 'macOS'}
|
||||
link={`https://spacedrive.com/api/releases/desktop/stable/${currentPlatform?.os}/x86_64`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<footer
|
||||
className="py-12 text-gray-200"
|
||||
style={{
|
||||
backgroundImage: `url('data:image/svg+xml,%3Csvg xmlns%3D%22http%3A//www.w3.org/2000/svg%22 viewBox%3D%220 0 1920 420%22 fill%3D%22none%22%3E%3Cpath d%3D%22M0 49.5L-0.0924661 48.5043L-1 48.5886V49.5V419.998V420.998H0H1920H1921V419.998V49.5V48.5886L1920.09 48.5043L1920 49.5C1920.09 48.5043 1920.09 48.5041 1920.09 48.5037L1920.07 48.5021L1920 48.4957L1919.73 48.4704L1918.63 48.3702C1917.67 48.2817 1916.23 48.1506 1914.33 47.9795C1910.53 47.6373 1904.91 47.1354 1897.58 46.4967C1882.93 45.2193 1861.5 43.3945 1834.35 41.2048C1780.04 36.8253 1702.88 30.9861 1611.44 25.147C1428.55 13.4688 1188.53 1.78979 960 1.78968C731.47 1.78958 491.446 13.4685 308.561 25.1468C217.117 30.986 139.955 36.8252 85.654 41.2047C58.5032 43.3945 37.0674 45.2193 22.419 46.4967C15.0947 47.1354 9.46731 47.6373 5.67073 47.9795C3.77243 48.1506 2.33185 48.2817 1.36574 48.3702C0.882678 48.4144 0.518236 48.4479 0.274504 48.4704L-0.000299077 48.4957L-0.0693103 48.5021L-0.0866324 48.5037C-0.0905066 48.5041 -0.0924661 48.5043 0 49.5Z%22 fill%3D%22%23141419%22 stroke%3D%22url%28%23paint0_linear_1926_240%29%22 stroke-width%3D%222%22/%3E%3Cdefs%3E%3ClinearGradient id%3D%22paint0_linear_1926_240%22 x1%3D%220%22 y1%3D%22167.5%22 x2%3D%221920%22 y2%3D%22167.5%22 gradientUnits%3D%22userSpaceOnUse%22%3E%3Cstop offset%3D%220.319255%22 stop-color%3D%22%231E1E26%22 stop-opacity%3D%220.4%22/%3E%3Cstop offset%3D%220.495%22 stop-color%3D%22%233692DF%22/%3E%3Cstop offset%3D%220.661993%22 stop-color%3D%22%231E1E26%22 stop-opacity%3D%220.5%22/%3E%3C/linearGradient%3E%3C/defs%3E%3C/svg%3E')`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center'
|
||||
}}
|
||||
>
|
||||
<div className="container mx-auto grid min-h-64 w-full max-w-[100rem] flex-shrink-0 grid-cols-1 gap-8 fill-[#141419] px-8 pt-[5.388125rem] lg:grid-cols-6">
|
||||
<div className="col-span-2 flex flex-row items-center">
|
||||
<div>
|
||||
<Image
|
||||
src={companyLogoFull}
|
||||
alt="Spacedrive Technology Inc."
|
||||
width={262}
|
||||
height={73}
|
||||
className="mr-4"
|
||||
/>
|
||||
<p className="ml-[4.575rem] mt-0 tracking-[0.01em] text-ink-faint">
|
||||
329 Railway St
|
||||
<br />
|
||||
Vancouver, BC V6A 1A4
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Product Links */}
|
||||
<div>
|
||||
<h2 className="mb-4 font-semibold uppercase leading-[1.15] tracking-[0.08em] text-gray-400">
|
||||
Product
|
||||
</h2>
|
||||
<ul className="flex flex-col gap-[0.625rem] tracking-[0.04em]">
|
||||
<li>
|
||||
<a className="transition-colors hover:text-white" href="#">
|
||||
Explorer
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="transition-colors hover:text-white" href="#">
|
||||
Teams
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="transition-colors hover:text-white" href="#">
|
||||
Assistant
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="transition-colors hover:text-white" href="#">
|
||||
Changelog
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Download Links */}
|
||||
<div>
|
||||
<h2 className="mb-4 font-semibold uppercase leading-[1.15] tracking-[0.08em] text-gray-400">
|
||||
Downloads
|
||||
</h2>
|
||||
<ul className="flex flex-col gap-[0.625rem] tracking-[0.04em]">
|
||||
<li>
|
||||
<a
|
||||
className="transition-colors hover:text-white"
|
||||
href="https://spacedrive.com/api/releases/desktop/stable/darwin/aarch64"
|
||||
>
|
||||
macOS
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="transition-colors hover:text-white"
|
||||
href="https://spacedrive.com/api/releases/desktop/stable/darwin/x86_64"
|
||||
>
|
||||
macOS - Intel
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="transition-colors hover:text-white"
|
||||
href="https://spacedrive.com/api/releases/desktop/stable/windows/x86_64"
|
||||
>
|
||||
Windows
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className="transition-colors hover:text-white"
|
||||
href="https://spacedrive.com/api/releases/desktop/stable/linux/x86_64"
|
||||
>
|
||||
Linux
|
||||
</a>
|
||||
</li>
|
||||
<li className="w-fit cursor-not-allowed">
|
||||
<a className="pointer-events-none text-gray-450" href="#">
|
||||
iOS
|
||||
</a>
|
||||
</li>
|
||||
<li className="w-fit cursor-not-allowed">
|
||||
<a
|
||||
className="pointer-events-none cursor-not-allowed text-gray-450"
|
||||
href="#"
|
||||
>
|
||||
Android
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Developer Links */}
|
||||
<div>
|
||||
<h2 className="mb-4 font-semibold uppercase leading-[1.15] tracking-[0.08em] text-gray-400">
|
||||
Developers
|
||||
</h2>
|
||||
<ul className="flex flex-col gap-[0.625rem] tracking-[0.04em]">
|
||||
<li>
|
||||
<a className="transition-colors hover:text-white" href="#">
|
||||
Documentation
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="transition-colors hover:text-white" href="#">
|
||||
Contribute
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="transition-colors hover:text-white" href="#">
|
||||
Extensions
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="transition-colors hover:text-white" href="#">
|
||||
Self Host
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Company Links */}
|
||||
<div>
|
||||
<h2 className="mb-4 font-semibold uppercase leading-[1.15] tracking-[0.08em] text-gray-400">
|
||||
Company
|
||||
</h2>
|
||||
<ul className="flex flex-col gap-[0.625rem] tracking-[0.04em]">
|
||||
<li>
|
||||
<a className="transition-colors hover:text-white" href="#">
|
||||
Open Collective
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="transition-colors hover:text-white" href="#">
|
||||
License
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="transition-colors hover:text-white" href="#">
|
||||
Privacy
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="transition-colors hover:text-white" href="#">
|
||||
Terms
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function FooterLink({
|
||||
blank,
|
||||
link,
|
||||
...props
|
||||
}: PropsWithChildren<{ link: string; blank?: boolean }>) {
|
||||
return (
|
||||
<Link
|
||||
href={link}
|
||||
target={blank ? '_blank' : ''}
|
||||
className="text-gray-300 duration-300 hover:text-white hover:opacity-50"
|
||||
rel="noreferrer"
|
||||
{...props}
|
||||
>
|
||||
{props.children}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@@ -6,9 +6,8 @@ import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { PropsWithChildren, useState } from 'react';
|
||||
import appFullLogo from '~/assets/app_full_logo.svg?url';
|
||||
|
||||
import { DownloadButton } from '../Downloads/Button';
|
||||
import { useCurrentPlatform } from '../Downloads/Platform';
|
||||
import { DownloadButton } from '~/components/cta-buttons/Button';
|
||||
import { useCurrentPlatform } from '~/components/cta-buttons/Platform';
|
||||
|
||||
import '~/styles/navbar.css';
|
||||
|
||||
@@ -6,9 +6,8 @@ import clsx from 'clsx';
|
||||
import { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
import { Button, Dropdown } from '@sd/ui';
|
||||
import { getWindow } from '~/utils/util';
|
||||
|
||||
import { positions } from '../careers/data';
|
||||
import { positions } from '../../app/careers/data';
|
||||
|
||||
export function MobileDropdown() {
|
||||
const router = useRouter();
|
||||
@@ -2,14 +2,14 @@ import { Star } from '@phosphor-icons/react/dist/ssr';
|
||||
import clsx from 'clsx';
|
||||
import Link from 'next/link';
|
||||
|
||||
export interface BannerProps {
|
||||
export interface GoldenBadgeProps {
|
||||
headline: string;
|
||||
href?: string;
|
||||
link?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function Banner(props: BannerProps) {
|
||||
export function GoldenBadge(props: GoldenBadgeProps) {
|
||||
const { headline, href, link } = props;
|
||||
|
||||
return (
|
||||
@@ -6,7 +6,7 @@ interface MarkdownPageProps {
|
||||
articleClassNames?: string;
|
||||
}
|
||||
|
||||
function MarkdownPage(props: PropsWithChildren<MarkdownPageProps>) {
|
||||
export function MarkdownPage(props: PropsWithChildren<MarkdownPageProps>) {
|
||||
return (
|
||||
<div className={clsx('mb-10 p-4', props.classNames)}>
|
||||
<article
|
||||
@@ -21,5 +21,3 @@ function MarkdownPage(props: PropsWithChildren<MarkdownPageProps>) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MarkdownPage;
|
||||
@@ -2,9 +2,9 @@ import { MDXComponents } from 'mdx/types';
|
||||
import NextImage, { ImageProps } from 'next/image';
|
||||
import { env } from '~/env';
|
||||
|
||||
import Notice from './Notice';
|
||||
import Pre from './Pre';
|
||||
import Video from './Video';
|
||||
import Notice from './notice';
|
||||
import Pre from './pre';
|
||||
import Video from './video';
|
||||
|
||||
const Image = (props: ImageProps) => (
|
||||
<NextImage
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Doc, DocumentTypes } from '@contentlayer/generated';
|
||||
import { type Icon } from '@phosphor-icons/react';
|
||||
import { Circle, Cube, Sparkle, Star } from '@phosphor-icons/react/dist/ssr';
|
||||
|
||||
import { toTitleCase } from './util';
|
||||
import { toTitleCase } from './misc';
|
||||
|
||||
type DocsCategory = {
|
||||
title: string;
|
||||
|
||||
Reference in New Issue
Block a user