The Great Landing Renamening of 2024

This commit is contained in:
lynx
2024-08-31 01:38:58 -05:00
parent 1107a725fa
commit ed7ea2b432
47 changed files with 281 additions and 3204 deletions

View File

@@ -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>
);
}

View File

@@ -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>
);
}

View File

@@ -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']> {

View File

@@ -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',

View File

@@ -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>;
}

View File

@@ -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[] }>();

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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'

View File

@@ -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>
);

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 KiB

View File

@@ -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>
);
}

View File

@@ -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>

View File

@@ -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>
);
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 };

View File

@@ -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>
);
}

View File

@@ -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">&rarr;</span>
</Link>
</aside>
);
};
export default NewBanner;

View File

File diff suppressed because one or more lines are too long

View File

@@ -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>
);
}

View File

@@ -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;

View File

@@ -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();

View 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>
);
};

View 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>
);
}

View File

@@ -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';

View File

@@ -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();

View File

@@ -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 (

View File

@@ -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;

View File

@@ -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

View File

@@ -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;