Skip to content
46 changes: 27 additions & 19 deletions src/components/footer.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,49 @@
import { ExternalLink, Github, Heart } from "lucide-react";

export function Footer() {
const year = new Date().getFullYear();

return (
<footer className="mt-auto border-t border-slate-200/60 dark:border-slate-700/60 bg-white/70 dark:bg-slate-800/70 backdrop-blur-sm">
<footer className="mt-auto border-t border-slate-200 dark:border-slate-800">
<div className="container mx-auto px-4 py-6 max-w-6xl">
<div className="flex flex-col sm:flex-row items-center justify-between gap-4 text-sm text-slate-600 dark:text-slate-400">
{/* Left side - Author info */}
{/* Left */}
<div className="flex items-center gap-2">
<span>Built with</span>
<Heart className="h-4 w-4 text-red-500 fill-current animate-pulse" />
<span>by</span>
<a
href="https://usmans.me"
target="_blank"
rel="noopener noreferrer"
className="font-medium text-slate-900 dark:text-slate-100 hover:text-blue-600 dark:hover:text-blue-400 transition-colors duration-200 flex items-center gap-1"
>
Usman S.
<ExternalLink className="h-3 w-3" />
</a>
<span>© {year} Whim</span>
<span className="hidden sm:inline text-slate-400">•</span>
<span className="flex items-center gap-1">
Built by
<a
href="https://usmans.me"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1 font-medium text-slate-800 dark:text-slate-200 hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500/30 rounded"
>
Usman S.
<ExternalLink className="h-3.5 w-3.5 opacity-70" aria-hidden="true" />
</a>
<Heart className="h-3.5 w-3.5 text-rose-500/80 ml-1" aria-hidden="true" />
</span>
</div>

{/* Right side - Open source info */}
{/* Right */}
<div className="flex items-center gap-4">
<span className="text-xs">Open Source</span>
<span className="text-xs">Open source</span>
<a
href="https://github.com/max-programming/whim"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 px-3 py-1.5 rounded-full bg-slate-100/80 dark:bg-slate-700/80 hover:bg-slate-200/80 dark:hover:bg-slate-600/80 transition-all duration-200 text-slate-700 dark:text-slate-300"
aria-label="View Whim on GitHub"
className="inline-flex items-center gap-2 text-slate-700 dark:text-slate-300 hover:text-slate-900 dark:hover:text-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500/30 rounded"
>
<Github className="h-4 w-4" />
<span className="text-xs font-medium">View on GitHub</span>
<span className="text-xs font-medium underline underline-offset-4 decoration-slate-300/70 hover:decoration-current">
View on GitHub
</span>
</a>
</div>
</div>
</div>
</footer>
);
}
}
109 changes: 35 additions & 74 deletions src/components/landing/landing-hero.tsx
Original file line number Diff line number Diff line change
@@ -1,91 +1,52 @@
import { Clock, Lock, Shield } from "lucide-react";
import { Card, CardContent } from "~/components/ui/card";

export function LandingHero() {
return (
<div className="space-y-9">
{/* Brand Badge with Whim */}
<div className="inline-flex items-center gap-2 bg-indigo-50 dark:bg-indigo-900/30 px-3 py-1.5 rounded-full text-indigo-700 dark:text-indigo-300 font-medium text-sm border border-indigo-100 dark:border-indigo-800">
<img src="/favicon-32x32.png" alt="Whim" className="w-6 h-6" />
Whim
<div className="space-y-8">
<div className="flex justify-center">
<div className="inline-flex items-center gap-2 bg-slate-300 dark:bg-slate-800 px-3 py-1.5 rounded-full">
<img src="/favicon-32x32.png" alt="Whim" className="w-4 h-4" />
<span className="text-sm font-medium text-slate-600 dark:text-slate-400">
Whim
</span>
</div>
</div>

{/* Headline */}
<div className="space-y-3">
<h1 className="text-3xl lg:text-4xl xl:text-5xl font-bold text-slate-900 dark:text-slate-100 leading-tight">
Share Secrets
<span className="text-indigo-600 dark:text-indigo-400 block">
Safely & Securely
<div className="space-y-4 text-center">
<h1 className="text-3xl font-semibold lg:text-4xl xl:text-5xl text-slate-900 dark:text-white capitalize">
Send secrets that
<span className="block text-indigo-600 dark:text-indigo-400">
disappear after they're read
</span>
</h1>

<p className="text-base lg:text-lg text-slate-600 dark:text-slate-300 leading-relaxed max-w-md">
Share sensitive information on a{" "}
<span className="font-medium text-slate-700 dark:text-slate-200">
whim
</span>{" "}
- your secrets automatically self-destruct after being read or when
time expires. Perfect for one-time sharing of API keys, passwords, and
confidential data.
<p className="text-base lg:text-lg text-slate-600 dark:text-slate-400 leading-relaxed max-w-xl mx-auto">
Securely share passwords, API keys, or confidential notes in a single-use,
encrypted message. Once opened, it’s gone forever — private, safe, and simple.
</p>
</div>

{/* Essential Features - Condensed on Mobile */}
<div className="grid grid-cols-3 gap-2 sm:gap-3">
<Card className="py-2 sm:py-4 shadow-sm border-2 border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800/50 hover:border-indigo-200 dark:hover:border-indigo-700 transition-colors">
<CardContent className="px-2 sm:px-4 py-0">
<div className="text-center space-y-1 sm:space-y-2">
<div className="flex justify-center">
<Shield className="w-4 h-4 sm:w-6 sm:h-6 text-indigo-600 dark:text-indigo-400" />
</div>
<div>
<div className="font-semibold text-xs sm:text-sm text-slate-900 dark:text-slate-100">
Encrypted
</div>
<div className="text-xs sm:text-xs text-slate-500 dark:text-slate-400 mt-0.5 sm:mt-1">
End-to-end encrypted
</div>
</div>
</div>
</CardContent>
</Card>

<Card className="py-2 sm:py-4 shadow-sm border-2 border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800/50 hover:border-indigo-200 dark:hover:border-indigo-700 transition-colors">
<CardContent className="px-2 sm:px-4 py-0">
<div className="text-center space-y-1 sm:space-y-2">
<div className="flex justify-center">
<Clock className="w-4 h-4 sm:w-6 sm:h-6 text-indigo-600 dark:text-indigo-400" />
</div>
<div>
<div className="font-semibold text-xs sm:text-sm text-slate-900 dark:text-slate-100">
Self-Destruct
</div>
<div className="text-xs sm:text-xs text-slate-500 dark:text-slate-400 mt-0.5 sm:mt-1">
Deleted after reading (once or multiple times)
</div>
</div>
</div>
</CardContent>
</Card>
<div className="flex flex-col lg:flex-row items-center justify-center gap-4 lg:gap-8">
<div className="flex items-center gap-2 text-sm text-slate-600 dark:text-slate-400">
<Shield className="w-4 h-4 text-slate-400" />
<span>AES-256 encrypted</span>
</div>
<div className="flex items-center gap-2 text-sm text-slate-600 dark:text-slate-400">
<Clock className="w-4 h-4 text-slate-400" />
<span>Auto-destructs</span>
</div>
<div className="flex items-center gap-2 text-sm text-slate-600 dark:text-slate-400">
<Lock className="w-4 h-4 text-slate-400" />
<span>OTP protected</span>
</div>
</div>

<Card className="py-2 sm:py-4 shadow-sm border-2 border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800/50 hover:border-indigo-200 dark:hover:border-indigo-700 transition-colors">
<CardContent className="px-2 sm:px-4 py-0">
<div className="text-center space-y-1 sm:space-y-2">
<div className="flex justify-center">
<Lock className="w-4 h-4 sm:w-6 sm:h-6 text-indigo-600 dark:text-indigo-400" />
</div>
<div>
<div className="font-semibold text-xs sm:text-sm text-slate-900 dark:text-slate-100">
Password Protected
</div>
<div className="text-xs sm:text-xs text-slate-500 dark:text-slate-400 mt-0.5 sm:mt-1">
OTP required
</div>
</div>
</div>
</CardContent>
</Card>
<div className="text-center">
<p className="text-xs text-slate-500 dark:text-slate-500">
Open source • Zero knowledge • No registration required
</p>
</div>
</div>
);
}
}
184 changes: 59 additions & 125 deletions src/components/landing/landing-process-flow.tsx
Original file line number Diff line number Diff line change
@@ -1,137 +1,71 @@
import { Clock, Edit3, Eye, Link2, Shield, Zap } from "lucide-react";
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
import { Edit3, Shield, Link2, Eye, Zap } from "lucide-react";

export function LandingProcessFlow() {
return (
<div>
<Card className="shadow-sm border-2 border-slate-200 dark:border-slate-700 bg-slate-50/50 dark:bg-slate-800/30 hover:border-indigo-200 dark:hover:border-indigo-700 transition-colors">
<CardHeader className="pb-4">
<CardTitle className="text-xl text-slate-900 dark:text-slate-100 flex items-center gap-2">
<Shield className="w-5 h-5 text-indigo-600 dark:text-indigo-400" />
How It Works
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
{/* Step 1 */}
<div className="flex items-start gap-3">
<div className="flex-shrink-0 w-8 h-8 bg-indigo-100 dark:bg-indigo-900/50 rounded-full flex items-center justify-center">
<span className="text-indigo-600 dark:text-indigo-400 font-semibold text-sm">
1
</span>
</div>
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<Edit3 className="w-4 h-4 text-indigo-600 dark:text-indigo-400" />
<h3 className="font-semibold text-sm text-slate-900 dark:text-slate-100">
Write Your Secret
</h3>
</div>
<p className="text-sm text-slate-600 dark:text-slate-300">
Type your sensitive information (API keys, passwords, private
notes) into the secure form.
</p>
</div>
</div>

{/* Step 2 */}
<div className="flex items-start gap-3">
<div className="flex-shrink-0 w-8 h-8 bg-indigo-100 dark:bg-indigo-900/50 rounded-full flex items-center justify-center">
<span className="text-indigo-600 dark:text-indigo-400 font-semibold text-sm">
2
</span>
</div>
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<Shield className="w-4 h-4 text-indigo-600 dark:text-indigo-400" />
<h3 className="font-semibold text-sm text-slate-900 dark:text-slate-100">
Encrypt & Generate
</h3>
</div>
<p className="text-sm text-slate-600 dark:text-slate-300">
Your secret is encrypted end-to-end and a unique URL + one-time
password (OTP) are generated.
</p>
</div>
</div>
const steps = [
{
icon: Edit3,
title: "Write your secret",
description: "Enter your sensitive information in the secure form",
},
{
icon: Shield,
title: "Encrypt automatically",
description: "Your message is encrypted with AES-256 before leaving your browser",
},
{
icon: Link2,
title: "Share credentials",
description: "Send the unique URL and OTP to your recipient",
},
{
icon: Eye,
title: "Recipient views once",
description: "They access the secret with the OTP for the set number of times",
},
{
icon: Zap,
title: "Auto-destruction",
description: "The secret vanishes forever after viewing",
isLast: true,
},
];

{/* Step 3 */}
<div className="flex items-start gap-3">
<div className="flex-shrink-0 w-8 h-8 bg-indigo-100 dark:bg-indigo-900/50 rounded-full flex items-center justify-center">
<span className="text-indigo-600 dark:text-indigo-400 font-semibold text-sm">
3
</span>
</div>
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<Link2 className="w-4 h-4 text-indigo-600 dark:text-indigo-400" />
<h3 className="font-semibold text-sm text-slate-900 dark:text-slate-100">
Share the Link & OTP
</h3>
</div>
<p className="text-sm text-slate-600 dark:text-slate-300">
Send the URL and OTP to your recipient through separate channels
for maximum security.
</p>
</div>
</div>

{/* Step 4 */}
<div className="flex items-start gap-3">
<div className="flex-shrink-0 w-8 h-8 bg-indigo-100 dark:bg-indigo-900/50 rounded-full flex items-center justify-center">
<span className="text-indigo-600 dark:text-indigo-400 font-semibold text-sm">
4
</span>
</div>
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<Eye className="w-4 h-4 text-indigo-600 dark:text-indigo-400" />
<h3 className="font-semibold text-sm text-slate-900 dark:text-slate-100">
Limited Access
</h3>
return (
<div className="space-y-4">
<div className="space-y-3">
{steps.map((step, index) => (
<div key={index} className="flex gap-4">
<div className="flex-shrink-0">
<div className={`
w-8 h-8 rounded-full flex items-center justify-center text-sm
${step.isLast
? 'bg-red-50 dark:bg-red-950/20 text-red-600 dark:text-red-400'
: 'bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400'
}
`}>
{index + 1}
</div>
<p className="text-sm text-slate-600 dark:text-slate-300">
The recipient opens the link, enters the OTP, and views your
secret for the allowed number of times.
</p>
</div>
</div>

{/* Step 5 */}
<div className="flex items-start gap-3">
<div className="flex-shrink-0 w-8 h-8 bg-red-100 dark:bg-red-900/50 rounded-full flex items-center justify-center">
<span className="text-red-600 dark:text-red-400 font-semibold text-sm">
5
</span>
</div>
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<Zap className="w-4 h-4 text-red-600 dark:text-red-400" />
<h3 className="font-semibold text-sm text-slate-900 dark:text-slate-100">
Automatic Destruction
</h3>
<div className="flex-1 space-y-1">
<div className="flex items-center gap-2">
<step.icon className="w-3 h-3 text-slate-400" />
<h4 className="text-sm font-medium text-slate-900 dark:text-white">
{step.title}
</h4>
</div>
<p className="text-sm text-slate-600 dark:text-slate-300">
The secret is permanently deleted from our servers after all
allowed accesses are used.
<p className="text-xs text-slate-500 dark:text-slate-500 leading-relaxed">
{step.description}
</p>
</div>
</div>
))}
</div>

{/* Security Note */}
<div className="bg-indigo-50 dark:bg-indigo-900/20 border border-indigo-200 dark:border-indigo-800 rounded-lg p-3 mt-4">
<div className="flex items-start gap-2">
<Clock className="w-4 h-4 text-indigo-600 dark:text-indigo-400 mt-0.5 flex-shrink-0" />
<div className="text-sm text-indigo-800 dark:text-indigo-200">
<p className="font-medium mb-1">Zero-Knowledge Security</p>
<p className="text-indigo-700 dark:text-indigo-300">
Your secret is encrypted in your browser before being sent to
our servers. We never see your data in plain text.
</p>
</div>
</div>
</div>
</CardContent>
</Card>
<div className="pt-3 border-t border-slate-200 dark:border-slate-800">
<p className="text-xs text-slate-500 dark:text-slate-500">
Zero-knowledge architecture • We never see your unencrypted data
</p>
</div>
</div>
);
}
}
Loading
Loading