mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 02:29:55 +02:00
feat(docs): streamline product and privacy pages
This commit is contained in:
@@ -1,48 +1,54 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { ApprovalDemo } from "@/components/approval-demo";
|
||||
import { HeroIllustration } from "@/components/hero-illustration";
|
||||
import { Icon, type IconName } from "@/components/icons";
|
||||
import { InvitationShowcase } from "@/components/invitation-showcase";
|
||||
import { NetworkIllustration } from "@/components/network-illustration";
|
||||
import { PlatformOrbit } from "@/components/platform-orbit";
|
||||
import { PlatformIcon, supportedPlatforms } from "@/components/platform-icon";
|
||||
import { Reveal } from "@/components/reveal";
|
||||
import { TransferFlow } from "@/components/transfer-flow";
|
||||
|
||||
const trustItems = [
|
||||
{ value: "No account", detail: "Open the app and start sharing" },
|
||||
{ value: "No hosted copy", detail: "Your transfer is not parked in our cloud" },
|
||||
{ value: "No silent overwrite", detail: "Existing files stay untouched" },
|
||||
];
|
||||
|
||||
const privacyPoints: Array<{
|
||||
const steps: Array<{
|
||||
icon: IconName;
|
||||
number: string;
|
||||
title: string;
|
||||
text: string;
|
||||
}> = [
|
||||
{
|
||||
icon: "lock",
|
||||
icon: "folder",
|
||||
number: "01",
|
||||
title: "Encrypted in transit",
|
||||
text: "Each connection is authenticated and end-to-end encrypted, including through a relay.",
|
||||
title: "Choose what to send",
|
||||
text: "Pick files, a batch, or a complete folder. VniDrop preserves the folder structure.",
|
||||
},
|
||||
{
|
||||
icon: "qr",
|
||||
number: "02",
|
||||
title: "Share an invitation",
|
||||
text: "Introduce the devices with a QR code, NFC tap, or portable .vnd invitation.",
|
||||
},
|
||||
{
|
||||
icon: "shield",
|
||||
number: "02",
|
||||
title: "Approval by default",
|
||||
text: "An invitation helps devices meet. It is not automatic permission to download.",
|
||||
number: "03",
|
||||
title: "Approve and transfer",
|
||||
text: "The receiver asks first. Once approved, the files move over an authenticated encrypted connection.",
|
||||
},
|
||||
];
|
||||
|
||||
const trustItems: Array<{
|
||||
icon: IconName;
|
||||
title: string;
|
||||
text: string;
|
||||
}> = [
|
||||
{
|
||||
icon: "devices",
|
||||
title: "Direct when possible",
|
||||
text: "Devices connect directly when they can. An encrypted relay forwards traffic when they cannot.",
|
||||
},
|
||||
{
|
||||
icon: "lock",
|
||||
title: "No hosted copy",
|
||||
text: "A relay is a route, not storage. Your transfer is never turned into a cloud download.",
|
||||
},
|
||||
{
|
||||
icon: "verified",
|
||||
number: "03",
|
||||
title: "Verified on arrival",
|
||||
text: "Content addressing checks that incoming bytes match exactly what was offered.",
|
||||
},
|
||||
{
|
||||
icon: "stop",
|
||||
number: "04",
|
||||
title: "Revocable access",
|
||||
text: "Stop a share at any time and the invitation can no longer be used.",
|
||||
text: "Content addressing checks that the received bytes match exactly what you sent.",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -67,224 +73,95 @@ export default function HomePage() {
|
||||
between devices.
|
||||
</h1>
|
||||
<p className="hero-lead">
|
||||
Send files and folders directly when possible, with an end-to-end encrypted relay
|
||||
when needed. No account. No hosted transfer copy. You decide who receives them.
|
||||
Send files and folders across your devices—direct when possible, private by design,
|
||||
and always under your control.
|
||||
</p>
|
||||
<div className="hero-actions">
|
||||
<a className="button button-primary" href="#how-it-works">
|
||||
See how it works
|
||||
<Icon name="arrow" />
|
||||
</a>
|
||||
<a
|
||||
className="button button-ghost"
|
||||
href="https://github.com/vnidrop/vnidrop"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Icon name="github" />
|
||||
Explore the project
|
||||
</a>
|
||||
</div>
|
||||
<div className="hero-platforms" aria-label="Supported platforms">
|
||||
<span>Available across</span>
|
||||
<ul>
|
||||
<li>Android</li>
|
||||
<li>iOS</li>
|
||||
<li>macOS</li>
|
||||
<li>Windows</li>
|
||||
<li>Linux</li>
|
||||
{supportedPlatforms.map((platform) => (
|
||||
<li key={platform} aria-label={platform} title={platform}>
|
||||
<PlatformIcon className="platform-glyph" platform={platform} />
|
||||
<span className="sr-only">{platform}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
<Reveal className="hero-art-reveal" delay={120}>
|
||||
<HeroIllustration />
|
||||
<figure className="hero-app-preview">
|
||||
<Image
|
||||
className="hero-app-preview-image"
|
||||
src="/App.png"
|
||||
width={2338}
|
||||
height={1873}
|
||||
sizes="(max-width: 920px) calc(100vw - 32px), 56vw"
|
||||
alt="VniDrop running on desktop and iPhone, showing transfer review, receiver permissions, and invitation options."
|
||||
priority
|
||||
unoptimized
|
||||
/>
|
||||
</figure>
|
||||
</Reveal>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="trust-section" aria-label="VniDrop principles">
|
||||
<div className="page-shell trust-grid">
|
||||
{trustItems.map((item, index) => (
|
||||
<Reveal key={item.value} className="trust-item" delay={index * 70}>
|
||||
<span className="trust-number">0{index + 1}</span>
|
||||
<div>
|
||||
<strong>{item.value}</strong>
|
||||
<p>{item.detail}</p>
|
||||
</div>
|
||||
</Reveal>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div className="word-stream" aria-hidden="true">
|
||||
<div>
|
||||
<span>FILES</span><i>◆</i><span>FOLDERS</span><i>◆</i><span>PHOTOS</span><i>◆</i>
|
||||
<span>PROJECTS</span><i>◆</i><span>FILES</span><i>◆</i><span>FOLDERS</span><i>◆</i>
|
||||
<span>PHOTOS</span><i>◆</i><span>PROJECTS</span><i>◆</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section id="how-it-works" className="section flow-section">
|
||||
<section id="how-it-works" className="simple-section simple-flow-section">
|
||||
<div className="page-shell">
|
||||
<Reveal className="section-heading section-heading-centered">
|
||||
<span className="kicker">ONE DROP, FIVE MOMENTS</span>
|
||||
<h2>A handoff that stays in your hands.</h2>
|
||||
<Reveal className="simple-heading">
|
||||
<span className="kicker">HOW IT WORKS</span>
|
||||
<h2>Three steps. No account.</h2>
|
||||
<p>
|
||||
VniDrop keeps the transfer understandable from first selection to final verified file.
|
||||
Choose the files, introduce the devices, and approve the handoff. VniDrop handles the
|
||||
secure route.
|
||||
</p>
|
||||
</Reveal>
|
||||
<Reveal delay={100}>
|
||||
<TransferFlow />
|
||||
</Reveal>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="invitations" className="section invitation-section">
|
||||
<div className="page-shell">
|
||||
<Reveal className="section-heading section-heading-split">
|
||||
<div>
|
||||
<span className="kicker">MAKE THE INTRODUCTION</span>
|
||||
<h2>One transfer. Three ways to meet.</h2>
|
||||
</div>
|
||||
<p>
|
||||
The invitation is small enough to scan, tap, or send. Your files stay where they are
|
||||
until a receiver connects and you allow the transfer.
|
||||
</p>
|
||||
</Reveal>
|
||||
<Reveal delay={100}>
|
||||
<InvitationShowcase />
|
||||
</Reveal>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="section approval-section">
|
||||
<div className="page-shell approval-layout">
|
||||
<Reveal className="approval-copy">
|
||||
<span className="kicker">CONTROL IS BUILT IN</span>
|
||||
<h2>A link is not permission.</h2>
|
||||
<p className="section-lead">
|
||||
Every new receiver knocks by default. Approve people you recognize, refuse the rest,
|
||||
and follow progress for each device.
|
||||
</p>
|
||||
<ul className="check-list">
|
||||
<li><Icon name="check" /> See the receiver before anything moves</li>
|
||||
<li><Icon name="check" /> Cancel a transfer already in progress</li>
|
||||
<li><Icon name="check" /> Stop sharing to revoke future access</li>
|
||||
</ul>
|
||||
<p className="approval-note">
|
||||
Need an open handoff? An optional “Anyone with this transfer” mode is available for
|
||||
non-sensitive files.
|
||||
</p>
|
||||
</Reveal>
|
||||
<Reveal className="approval-demo-wrap" delay={120}>
|
||||
<ApprovalDemo />
|
||||
<span className="demo-hint"><Icon name="spark" /> Try the controls</span>
|
||||
</Reveal>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="privacy" className="privacy-principles-section">
|
||||
<div className="page-shell">
|
||||
<Reveal className="privacy-intro">
|
||||
<span className="kicker kicker-light">PRIVACY BY DESIGN</span>
|
||||
<h2>The file never becomes our file.</h2>
|
||||
<p>
|
||||
VniDrop coordinates a secure handoff. It does not turn your transfer into a hosted
|
||||
download sitting on someone else’s storage.
|
||||
</p>
|
||||
</Reveal>
|
||||
<div className="privacy-point-grid">
|
||||
{privacyPoints.map((point, index) => (
|
||||
<Reveal key={point.number} className="privacy-point" delay={index * 70}>
|
||||
<div className="privacy-point-top">
|
||||
<span><Icon name={point.icon} /></span>
|
||||
<small>{point.number}</small>
|
||||
<div className="simple-steps">
|
||||
{steps.map((step) => (
|
||||
<article key={step.number} className="simple-step">
|
||||
<div className="simple-step-top">
|
||||
<span>{step.number}</span>
|
||||
<Icon name={step.icon} />
|
||||
</div>
|
||||
<h3>{point.title}</h3>
|
||||
<p>{point.text}</p>
|
||||
</Reveal>
|
||||
<h3>{step.title}</h3>
|
||||
<p>{step.text}</p>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
<Reveal className="privacy-policy-link" delay={120}>
|
||||
<p>Diagnostics are optional and exclude invitations, file paths, and transfer contents.</p>
|
||||
<Link href="/privacy/">
|
||||
Read the full privacy policy
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="privacy" className="trust-summary-section">
|
||||
<div className="page-shell trust-summary">
|
||||
<Reveal className="trust-summary-copy">
|
||||
<span className="kicker kicker-light">PRIVACY BY DESIGN</span>
|
||||
<h2>What VniDrop does—and doesn’t do.</h2>
|
||||
<p>
|
||||
The transfer happens between devices. These are the details that matter when you
|
||||
decide what to share and who can receive it.
|
||||
</p>
|
||||
<Link className="simple-text-link" href="/privacy/">
|
||||
Read the privacy policy
|
||||
<Icon name="arrow" />
|
||||
</Link>
|
||||
</Reveal>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="network-section">
|
||||
<div className="page-shell network-layout">
|
||||
<Reveal className="network-copy">
|
||||
<span className="kicker kicker-light">DIRECT WHEN POSSIBLE</span>
|
||||
<h2>The shortest safe path, chosen automatically.</h2>
|
||||
<p>
|
||||
VniDrop tries to connect devices directly—even across home routers and mobile
|
||||
networks. If that path is not available, a relay forwards the same encrypted
|
||||
connection without becoming a file store.
|
||||
</p>
|
||||
<blockquote>
|
||||
<span>“</span>
|
||||
The relay can move the envelope. It cannot open it.
|
||||
</blockquote>
|
||||
</Reveal>
|
||||
<Reveal delay={120}>
|
||||
<NetworkIllustration />
|
||||
</Reveal>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="platforms" className="section platforms-section">
|
||||
<div className="page-shell platforms-layout">
|
||||
<Reveal className="platforms-copy">
|
||||
<span className="kicker">ONE FAMILIAR HANDOFF</span>
|
||||
<h2>At home on every screen.</h2>
|
||||
<p className="section-lead">
|
||||
Android, iOS, macOS, Windows, and Linux share one clear transfer experience while each
|
||||
platform keeps control of its own file picker and save destination.
|
||||
</p>
|
||||
<div className="platform-feature-list">
|
||||
<span><Icon name="devices" /> Cross-platform by design</span>
|
||||
<span><Icon name="folder" /> Native file destinations</span>
|
||||
<span><Icon name="code" /> Open-source core</span>
|
||||
</div>
|
||||
</Reveal>
|
||||
<Reveal className="orbit-wrap" delay={100}>
|
||||
<PlatformOrbit />
|
||||
</Reveal>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="final-cta-section">
|
||||
<div className="page-shell">
|
||||
<Reveal className="final-cta">
|
||||
<div className="final-cta-orb final-cta-orb-one" aria-hidden="true" />
|
||||
<div className="final-cta-orb final-cta-orb-two" aria-hidden="true" />
|
||||
<span className="kicker kicker-light">OPEN SOURCE · APACHE 2.0</span>
|
||||
<h2>Drop the cloud holding pen. Keep the control.</h2>
|
||||
<p>
|
||||
VniDrop is in early development. Explore the code, build the app, and help shape a
|
||||
more direct way to share.
|
||||
</p>
|
||||
<div className="final-cta-actions">
|
||||
<a
|
||||
className="button button-light"
|
||||
href="https://github.com/vnidrop/vnidrop"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Icon name="github" />
|
||||
View the source
|
||||
</a>
|
||||
<Link className="button button-dark-ghost" href="/privacy/">
|
||||
Privacy policy
|
||||
<Icon name="arrow" />
|
||||
</Link>
|
||||
</div>
|
||||
</Reveal>
|
||||
<div className="trust-summary-list">
|
||||
{trustItems.map((item) => (
|
||||
<article key={item.title} className="trust-summary-item">
|
||||
<span><Icon name={item.icon} /></span>
|
||||
<div>
|
||||
<h3>{item.title}</h3>
|
||||
<p>{item.text}</p>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user