mirror of
https://github.com/Snigdha-OS/Snigdha-OS.github.io.git
synced 2025-09-12 07:35:01 +02:00
🧹 chore(clean): whole repository
This commit is contained in:
@@ -1,34 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Target } from 'lucide-react';
|
||||
|
||||
export function MissionSection() {
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
whileInView={{ opacity: 1 }}
|
||||
className="bg-white/80 backdrop-blur-sm p-8 rounded-lg shadow-sm"
|
||||
>
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<Target className="h-6 w-6 text-cornflower-blue" />
|
||||
<h2 className="text-2xl font-bold text-gray-900">Our Mission</h2>
|
||||
</div>
|
||||
|
||||
<div className="prose prose-gray max-w-none">
|
||||
<p className="text-gray-600 leading-relaxed">
|
||||
Snigdha OS aims to provide security professionals and enthusiasts with the most comprehensive,
|
||||
reliable, and up-to-date collection of security tools. Our mission is to enable the security
|
||||
community to perform professional-grade security auditing and penetration testing with a
|
||||
standardized, well-documented platform.
|
||||
</p>
|
||||
|
||||
<h3 className="text-xl font-semibold mt-6 mb-3">Core Values</h3>
|
||||
<ul className="space-y-2 text-gray-600">
|
||||
<li>Open Source: Maintaining transparency and community collaboration</li>
|
||||
<li>Security: Providing robust tools for security testing</li>
|
||||
<li>Education: Supporting learning and skill development</li>
|
||||
<li>Community: Fostering a strong, supportive user community</li>
|
||||
</ul>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Users } from 'lucide-react';
|
||||
|
||||
const teamStructure = [
|
||||
{
|
||||
title: 'Core Development',
|
||||
description: 'Responsible for the base system and core tools integration',
|
||||
},
|
||||
{
|
||||
title: 'Security Tools',
|
||||
description: 'Maintains and updates the vast collection of security tools',
|
||||
},
|
||||
{
|
||||
title: 'Documentation',
|
||||
description: 'Creates and maintains user documentation and guides',
|
||||
},
|
||||
{
|
||||
title: 'Community Management',
|
||||
description: 'Manages community interactions and contributions',
|
||||
},
|
||||
];
|
||||
|
||||
export function TeamSection() {
|
||||
return (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{teamStructure.map((team, index) => (
|
||||
<motion.div
|
||||
key={team.title}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: index * 0.1 }}
|
||||
className="bg-white/80 backdrop-blur-sm p-6 rounded-lg shadow-sm"
|
||||
>
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<Users className="h-5 w-5 text-cornflower-blue" />
|
||||
<h3 className="text-lg font-semibold text-gray-900">{team.title}</h3>
|
||||
</div>
|
||||
<p className="text-gray-600">{team.description}</p>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,40 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Calendar } from 'lucide-react';
|
||||
|
||||
const releases = [
|
||||
{ version: '2024.1', date: '2024', description: 'Latest release with enhanced cloud support' },
|
||||
{ version: '2023.4', date: '2023', description: 'Major UI overhaul and tool updates' },
|
||||
{ version: '2023.1', date: '2023', description: 'Introduced new wireless testing tools' },
|
||||
{ version: '2022.4', date: '2022', description: 'Added ARM64 support improvements' },
|
||||
{ version: '2022.1', date: '2022', description: 'Enhanced container support' },
|
||||
];
|
||||
|
||||
export function Timeline() {
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className="absolute left-4 top-0 bottom-0 w-0.5 bg-gray-200" />
|
||||
|
||||
{releases.map((release, index) => (
|
||||
<motion.div
|
||||
key={release.version}
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
whileInView={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: index * 0.1 }}
|
||||
className="relative pl-12 pb-8"
|
||||
>
|
||||
<div className="absolute left-0 p-2 bg-white rounded-full border-2 border-cornflower-blue">
|
||||
<Calendar className="h-4 w-4 text-cornflower-blue" />
|
||||
</div>
|
||||
|
||||
<div className="bg-white/80 backdrop-blur-sm p-4 rounded-lg shadow-sm">
|
||||
<h3 className="text-lg font-semibold text-gray-900">
|
||||
Kali {release.version}
|
||||
</h3>
|
||||
<time className="text-sm text-gray-500">{release.date}</time>
|
||||
<p className="mt-1 text-gray-600">{release.description}</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Github, GitCommit } from 'lucide-react';
|
||||
|
||||
interface ContributorCardProps {
|
||||
login: string;
|
||||
avatarUrl: string;
|
||||
contributions: number;
|
||||
profileUrl: string;
|
||||
}
|
||||
|
||||
export function ContributorCard({ login, avatarUrl, contributions, profileUrl }: ContributorCardProps) {
|
||||
return (
|
||||
<motion.div
|
||||
whileHover={{ y: -5 }}
|
||||
className="bg-white/80 backdrop-blur-sm p-6 rounded-lg border border-gray-200"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<img
|
||||
src={avatarUrl}
|
||||
alt={`${login}'s avatar`}
|
||||
className="w-16 h-16 rounded-full"
|
||||
/>
|
||||
<div>
|
||||
<h3 className="font-semibold text-gray-900">{login}</h3>
|
||||
<div className="flex items-center gap-2 text-sm text-gray-600">
|
||||
<GitCommit className="h-4 w-4" />
|
||||
<span>{contributions} contributions</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a
|
||||
href={profileUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="mt-4 flex items-center gap-2 text-sm text-cornflower-blue hover:underline"
|
||||
>
|
||||
<Github className="h-4 w-4" />
|
||||
View Profile
|
||||
</a>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
import { Users, GitPullRequest, GitCommit } from 'lucide-react';
|
||||
|
||||
interface Stats {
|
||||
totalContributors: number;
|
||||
totalPullRequests: number;
|
||||
totalCommits: number;
|
||||
}
|
||||
|
||||
export function ContributorStats({ totalContributors, totalPullRequests, totalCommits }: Stats) {
|
||||
return (
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
{[
|
||||
{ icon: Users, label: 'Contributors', value: totalContributors },
|
||||
{ icon: GitPullRequest, label: 'Pull Requests', value: totalPullRequests },
|
||||
{ icon: GitCommit, label: 'Commits', value: totalCommits },
|
||||
].map(({ icon: Icon, label, value }) => (
|
||||
<div key={label} className="bg-white/80 backdrop-blur-sm p-6 rounded-lg">
|
||||
<Icon className="h-8 w-8 text-cornflower-blue mb-2" />
|
||||
<p className="text-2xl font-bold text-gray-900">{value.toLocaleString()}</p>
|
||||
<p className="text-sm text-gray-600">{label}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Star, GitFork, Clock } from 'lucide-react';
|
||||
import { formatDate } from '@/lib/utils';
|
||||
import type { GithubRepo } from '@/lib/github';
|
||||
|
||||
interface RepoCardProps {
|
||||
repo: GithubRepo;
|
||||
}
|
||||
|
||||
export function RepoCard({ repo }: RepoCardProps) {
|
||||
return (
|
||||
<motion.div
|
||||
whileHover={{ y: -5 }}
|
||||
className="bg-white/80 backdrop-blur-sm p-6 rounded-lg border border-gray-200"
|
||||
>
|
||||
<h3 className="text-lg font-semibold text-gray-900">
|
||||
<a
|
||||
href={repo.html_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="hover:text-cornflower-blue transition-colors"
|
||||
>
|
||||
{repo.name}
|
||||
</a>
|
||||
</h3>
|
||||
|
||||
{repo.description && (
|
||||
<p className="mt-2 text-gray-600 line-clamp-2">{repo.description}</p>
|
||||
)}
|
||||
|
||||
<div className="mt-4 flex items-center gap-4 text-sm text-gray-500">
|
||||
{repo.language && (
|
||||
<span className="flex items-center gap-1">
|
||||
<span className="w-3 h-3 rounded-full bg-cornflower-blue" />
|
||||
{repo.language}
|
||||
</span>
|
||||
)}
|
||||
|
||||
<span className="flex items-center gap-1">
|
||||
<Star className="h-4 w-4" />
|
||||
{repo.stargazers_count}
|
||||
</span>
|
||||
|
||||
<span className="flex items-center gap-1">
|
||||
<GitFork className="h-4 w-4" />
|
||||
{repo.forks_count}
|
||||
</span>
|
||||
|
||||
<span className="flex items-center gap-1">
|
||||
<Clock className="h-4 w-4" />
|
||||
{formatDate(repo.updated_at)}
|
||||
</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { MapPin, Users, Book } from 'lucide-react';
|
||||
import type { GithubUser } from '@/lib/github';
|
||||
|
||||
interface TeamMemberCardProps {
|
||||
user: GithubUser;
|
||||
role: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export function TeamMemberCard({ user, role, description }: TeamMemberCardProps) {
|
||||
return (
|
||||
<motion.div
|
||||
whileHover={{ y: -5 }}
|
||||
className="bg-white/80 backdrop-blur-sm p-6 rounded-lg border border-gray-200"
|
||||
>
|
||||
<div className="flex items-start gap-4">
|
||||
<img
|
||||
src={user.avatar_url}
|
||||
alt={`${user.login}'s avatar`}
|
||||
className="w-16 h-16 rounded-full"
|
||||
/>
|
||||
<div>
|
||||
<h3 className="font-semibold text-gray-900">{user.name || user.login}</h3>
|
||||
<p className="text-sm text-cornflower-blue">{role}</p>
|
||||
{user.location && (
|
||||
<div className="flex items-center gap-1 text-sm text-gray-500 mt-1">
|
||||
<MapPin className="h-4 w-4" />
|
||||
<span>{user.location}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="mt-4 text-gray-600">{description}</p>
|
||||
|
||||
<div className="mt-4 flex items-center gap-4 text-sm text-gray-500">
|
||||
<div className="flex items-center gap-1">
|
||||
<Users className="h-4 w-4" />
|
||||
<span>{user.followers.toLocaleString()} followers</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<Book className="h-4 w-4" />
|
||||
<span>{user.public_repos} repos</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a
|
||||
href={user.html_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="mt-4 inline-flex items-center text-sm text-cornflower-blue hover:underline"
|
||||
>
|
||||
View GitHub Profile →
|
||||
</a>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Check } from 'lucide-react';
|
||||
|
||||
interface DonationTierProps {
|
||||
name: string;
|
||||
amount: number;
|
||||
benefits: string[];
|
||||
recommended?: boolean;
|
||||
onSelect: () => void;
|
||||
}
|
||||
|
||||
export function DonationTier({ name, amount, benefits, recommended, onSelect }: DonationTierProps) {
|
||||
return (
|
||||
<motion.div
|
||||
whileHover={{ y: -5 }}
|
||||
className={`bg-white/80 backdrop-blur-sm p-6 rounded-lg border ${
|
||||
recommended ? 'border-cornflower-blue' : 'border-gray-200'
|
||||
}`}
|
||||
>
|
||||
{recommended && (
|
||||
<span className="inline-block px-3 py-1 text-xs font-medium text-cornflower-blue bg-blue-50 rounded-full mb-4">
|
||||
Recommended
|
||||
</span>
|
||||
)}
|
||||
|
||||
<h3 className="text-xl font-semibold text-gray-900">{name}</h3>
|
||||
<p className="mt-2 text-3xl font-bold text-gray-900">${amount}</p>
|
||||
|
||||
<ul className="mt-6 space-y-3">
|
||||
{benefits.map((benefit) => (
|
||||
<li key={benefit} className="flex items-start gap-2">
|
||||
<Check className="h-5 w-5 text-green-500 flex-shrink-0 mt-0.5" />
|
||||
<span className="text-gray-600">{benefit}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<button
|
||||
onClick={onSelect}
|
||||
className="mt-8 w-full py-2 px-4 bg-cornflower-blue text-white rounded-lg hover:bg-blue-600 transition-colors"
|
||||
>
|
||||
Select
|
||||
</button>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Heart } from 'lucide-react';
|
||||
|
||||
interface Donor {
|
||||
name: string;
|
||||
amount: number;
|
||||
message?: string;
|
||||
date: string;
|
||||
}
|
||||
|
||||
interface DonorWallProps {
|
||||
donors: Donor[];
|
||||
}
|
||||
|
||||
export function DonorWall({ donors }: DonorWallProps) {
|
||||
return (
|
||||
<div className="bg-white/80 backdrop-blur-sm p-6 rounded-lg">
|
||||
<h2 className="text-2xl font-semibold text-gray-900 mb-6">Recent Supporters</h2>
|
||||
|
||||
<div className="space-y-6">
|
||||
{donors.map((donor, index) => (
|
||||
<motion.div
|
||||
key={`${donor.name}-${donor.date}`}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: index * 0.1 }}
|
||||
className="flex items-start gap-4"
|
||||
>
|
||||
<Heart className="h-5 w-5 text-red-500 flex-shrink-0 mt-1" />
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<h3 className="font-medium text-gray-900">{donor.name}</h3>
|
||||
<span className="text-sm text-cornflower-blue">${donor.amount}</span>
|
||||
</div>
|
||||
{donor.message && (
|
||||
<p className="mt-1 text-sm text-gray-600">{donor.message}</p>
|
||||
)}
|
||||
<time className="text-xs text-gray-500">{donor.date}</time>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
import { Github } from 'lucide-react';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
export function GithubSponsorButton() {
|
||||
return (
|
||||
<motion.a
|
||||
href="https://github.com/sponsors/eshanized"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
className="inline-flex items-center gap-2 px-6 py-3 bg-[#2ea44f] text-white rounded-lg hover:bg-[#2c974b] transition-colors"
|
||||
>
|
||||
<Github className="h-5 w-5" />
|
||||
Sponsor on GitHub
|
||||
</motion.a>
|
||||
);
|
||||
}
|
@@ -1,59 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Building2 } from 'lucide-react';
|
||||
import { useQueries } from '@tanstack/react-query';
|
||||
import { fetchGithubUser } from '@/lib/github';
|
||||
import { keySponsors } from '@/data/sponsors';
|
||||
import { formatINR } from '@/lib/currency';
|
||||
|
||||
export function KeySponsors() {
|
||||
const queries = useQueries({
|
||||
queries: keySponsors.map(sponsor => ({
|
||||
queryKey: ['github-user', sponsor.githubUsername],
|
||||
queryFn: () => fetchGithubUser(sponsor.githubUsername),
|
||||
})),
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="bg-gradient-to-r from-cornflower-blue/5 to-blue-50/50 rounded-2xl p-8">
|
||||
<h2 className="text-2xl font-bold text-gray-900 text-center mb-8">
|
||||
Key Sponsors
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{keySponsors.map((sponsor, index) => {
|
||||
const query = queries[index];
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
key={sponsor.name}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: index * 0.1 }}
|
||||
className="bg-white/90 backdrop-blur-sm rounded-xl p-6 border border-cornflower-blue/20 shadow-sm"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
{query.data ? (
|
||||
<img
|
||||
src={query.data.avatar_url}
|
||||
alt={`${sponsor.name}'s profile`}
|
||||
className="w-12 h-12 rounded-full"
|
||||
/>
|
||||
) : (
|
||||
<div className="p-3 bg-cornflower-blue/10 rounded-lg">
|
||||
<Building2 className="h-8 w-8 text-cornflower-blue" />
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<h3 className="font-semibold text-gray-900">{sponsor.name}</h3>
|
||||
<p className="text-sm text-gray-600">{sponsor.description}</p>
|
||||
<p className="text-sm font-medium text-cornflower-blue mt-1">
|
||||
{formatINR(sponsor.amount)}/month
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Building2 } from 'lucide-react';
|
||||
import { type UseQueryResult } from '@tanstack/react-query';
|
||||
import { type GithubUser } from '@/lib/github';
|
||||
import { type Sponsor } from '@/types/sponsor';
|
||||
import { formatINR } from '@/lib/currency';
|
||||
|
||||
interface SponsorCardProps {
|
||||
sponsor: Sponsor;
|
||||
query: UseQueryResult<GithubUser>;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export function SponsorCard({ sponsor, query, index }: SponsorCardProps) {
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: index * 0.1 }}
|
||||
className="bg-white/90 backdrop-blur-sm rounded-xl p-6 border border-cornflower-blue/20 shadow-sm"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
{query.data && !query.error ? (
|
||||
<img
|
||||
src={query.data.avatar_url}
|
||||
alt={`${sponsor.name}'s profile`}
|
||||
className="w-12 h-12 rounded-full"
|
||||
/>
|
||||
) : (
|
||||
<div className="p-3 bg-cornflower-blue/10 rounded-lg">
|
||||
<Building2 className="h-8 w-8 text-cornflower-blue" />
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<h3 className="font-semibold text-gray-900">{sponsor.name}</h3>
|
||||
<p className="text-sm text-gray-600">{sponsor.description}</p>
|
||||
<p className="text-sm font-medium text-cornflower-blue mt-1">
|
||||
{formatINR(sponsor.amount)}/month
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
import { useQueries } from '@tanstack/react-query';
|
||||
import { fetchGithubUser } from '@/lib/github';
|
||||
import { keySponsors } from '@/data/sponsors';
|
||||
import { SponsorCard } from './SponsorCard';
|
||||
|
||||
export function KeySponsors() {
|
||||
const queries = useQueries({
|
||||
queries: keySponsors.map(sponsor => ({
|
||||
queryKey: ['github-user', sponsor.githubUsername],
|
||||
queryFn: () => fetchGithubUser(sponsor.githubUsername),
|
||||
retry: 1, // Only retry once to avoid excessive API calls
|
||||
staleTime: 1000 * 60 * 5, // Cache for 5 minutes
|
||||
})),
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="bg-gradient-to-r from-cornflower-blue/5 to-blue-50/50 rounded-2xl p-8">
|
||||
<h2 className="text-2xl font-bold text-gray-900 text-center mb-8">
|
||||
Key Sponsors
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{keySponsors.map((sponsor, index) => (
|
||||
<SponsorCard
|
||||
key={sponsor.name}
|
||||
sponsor={sponsor}
|
||||
query={queries[index]}
|
||||
index={index}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Users, Star, Heart } from 'lucide-react';
|
||||
import { formatINR } from '@/lib/currency';
|
||||
|
||||
const stats = [
|
||||
{
|
||||
label: 'Current Sponsors',
|
||||
value: '50+',
|
||||
icon: Users,
|
||||
color: 'text-blue-500'
|
||||
},
|
||||
{
|
||||
label: 'Monthly Support',
|
||||
value: formatINR(200000),
|
||||
icon: Heart,
|
||||
color: 'text-red-500'
|
||||
},
|
||||
{
|
||||
label: 'GitHub Stars',
|
||||
value: '1.2K+',
|
||||
icon: Star,
|
||||
color: 'text-yellow-500'
|
||||
}
|
||||
];
|
||||
|
||||
export function SponsorshipStats() {
|
||||
return (
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
{stats.map((stat, index) => (
|
||||
<motion.div
|
||||
key={stat.label}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: index * 0.1 }}
|
||||
className="bg-white/80 backdrop-blur-sm p-6 rounded-xl border border-gray-200"
|
||||
>
|
||||
<stat.icon className={`h-8 w-8 ${stat.color} mb-2`} />
|
||||
<p className="text-2xl font-bold text-gray-900">{stat.value}</p>
|
||||
<p className="text-gray-600">{stat.label}</p>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,98 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Check } from 'lucide-react';
|
||||
import { formatINR } from '@/lib/currency';
|
||||
|
||||
const tiers = [
|
||||
{
|
||||
name: 'Community Hero',
|
||||
amount: 399,
|
||||
description: 'Support the ongoing development of Snigdha OS',
|
||||
benefits: [
|
||||
'Special recognition on our GitHub repository',
|
||||
'Access to sponsor-only updates',
|
||||
'Vote on feature priorities'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Security Champion',
|
||||
amount: 799,
|
||||
description: 'Help shape the future of security testing',
|
||||
benefits: [
|
||||
'All Community Hero benefits',
|
||||
'Early access to new features',
|
||||
'Priority support on GitHub',
|
||||
'Exclusive security tips newsletter'
|
||||
],
|
||||
featured: true
|
||||
},
|
||||
{
|
||||
name: 'Enterprise Partner',
|
||||
amount: 1999,
|
||||
description: 'Perfect for organizations using Snigdha OS',
|
||||
benefits: [
|
||||
'All Security Champion benefits',
|
||||
'Custom support channel',
|
||||
'Training materials access',
|
||||
'Team collaboration features',
|
||||
'Priority feature requests'
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
export function SponsorshipTiers() {
|
||||
return (
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
{tiers.map((tier) => (
|
||||
<motion.div
|
||||
key={tier.name}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
className={`relative rounded-2xl ${
|
||||
tier.featured
|
||||
? 'bg-gradient-to-b from-cornflower-blue/10 to-cornflower-blue/5 border-2 border-cornflower-blue'
|
||||
: 'bg-white/80 border border-gray-200'
|
||||
} backdrop-blur-sm p-6 shadow-lg`}
|
||||
>
|
||||
{tier.featured && (
|
||||
<div className="absolute -top-4 left-1/2 -translate-x-1/2">
|
||||
<span className="px-4 py-1 bg-cornflower-blue text-white text-sm rounded-full">
|
||||
Most Popular
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-4">
|
||||
<h3 className="text-xl font-semibold text-gray-900">{tier.name}</h3>
|
||||
<div className="mt-2">
|
||||
<span className="text-3xl font-bold text-gray-900">{formatINR(tier.amount)}</span>
|
||||
<span className="text-gray-600">/month</span>
|
||||
</div>
|
||||
<p className="mt-2 text-gray-600">{tier.description}</p>
|
||||
</div>
|
||||
|
||||
<ul className="space-y-3 mb-6">
|
||||
{tier.benefits.map((benefit) => (
|
||||
<li key={benefit} className="flex items-start gap-2">
|
||||
<Check className="h-5 w-5 text-green-500 flex-shrink-0 mt-0.5" />
|
||||
<span className="text-gray-600">{benefit}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<a
|
||||
href={`https://github.com/sponsors/eshanized?frequency=monthly&sponsor=${encodeURIComponent(tier.name)}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={`block w-full text-center py-2 px-4 rounded-lg transition-colors ${
|
||||
tier.featured
|
||||
? 'bg-cornflower-blue text-white hover:bg-blue-600'
|
||||
: 'bg-gray-100 text-gray-900 hover:bg-gray-200'
|
||||
}`}
|
||||
>
|
||||
Become a {tier.name}
|
||||
</a>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
import { Shield } from 'lucide-react';
|
||||
|
||||
interface ChecksumProps {
|
||||
sha256: string;
|
||||
gpg: string;
|
||||
}
|
||||
|
||||
export function Checksum({ sha256, gpg }: ChecksumProps) {
|
||||
return (
|
||||
<div className="bg-white/80 backdrop-blur-sm p-6 rounded-lg">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<Shield className="h-5 w-5 text-cornflower-blue" />
|
||||
<h2 className="text-xl font-semibold text-gray-900">Verify Download</h2>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-700 mb-1">SHA256 Checksum</h3>
|
||||
<code className="block p-2 bg-gray-100 rounded text-sm break-all">{sha256}</code>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-700 mb-1">GPG Signature</h3>
|
||||
<code className="block p-2 bg-gray-100 rounded text-sm break-all">{gpg}</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
import { Download } from 'lucide-react';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
interface DownloadButtonProps {
|
||||
version: string;
|
||||
size: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export function DownloadButton({ version, size, url }: DownloadButtonProps) {
|
||||
return (
|
||||
<motion.a
|
||||
href={url}
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
className="flex items-center justify-between w-full p-4 bg-white/80 backdrop-blur-sm rounded-lg border border-gray-200 hover:border-cornflower-blue transition-colors"
|
||||
>
|
||||
<div>
|
||||
<h3 className="font-semibold text-gray-900">Snigdha OS {version}</h3>
|
||||
<p className="text-sm text-gray-500">{size}</p>
|
||||
</div>
|
||||
<Download className="h-5 w-5 text-cornflower-blue" />
|
||||
</motion.a>
|
||||
);
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Globe, Wifi, Download } from 'lucide-react';
|
||||
import { type Mirror } from '@/types/download';
|
||||
import { formatSpeed } from '@/lib/utils';
|
||||
|
||||
interface MirrorListProps {
|
||||
mirrors: Mirror[];
|
||||
onSelect: (mirror: Mirror) => void;
|
||||
}
|
||||
|
||||
export function MirrorList({ mirrors, onSelect }: MirrorListProps) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{mirrors.map((mirror, index) => (
|
||||
<motion.div
|
||||
key={mirror.id}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: index * 0.1 }}
|
||||
className="bg-white/80 backdrop-blur-sm p-4 rounded-lg border border-gray-200 hover:border-cornflower-blue transition-colors"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<Globe className="h-5 w-5 text-cornflower-blue" />
|
||||
<div>
|
||||
<h3 className="font-medium text-gray-900">{mirror.name}</h3>
|
||||
<p className="text-sm text-gray-500">{mirror.location}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-1 text-sm text-gray-600">
|
||||
<Wifi className="h-4 w-4" />
|
||||
{formatSpeed(mirror.speed)}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => onSelect(mirror)}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-cornflower-blue text-white rounded-lg hover:bg-blue-600 transition-colors"
|
||||
>
|
||||
<Download className="h-4 w-4" />
|
||||
Select
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
import { Wifi } from 'lucide-react';
|
||||
|
||||
interface NetworkSpeedProps {
|
||||
speed: number;
|
||||
}
|
||||
|
||||
export function NetworkSpeed({ speed }: NetworkSpeedProps) {
|
||||
const getRecommendation = (speed: number) => {
|
||||
if (speed >= 100) return 'Excellent for fast downloads';
|
||||
if (speed >= 50) return 'Good for normal downloads';
|
||||
if (speed >= 20) return 'Moderate speed, downloads may take longer';
|
||||
return 'Slow connection, consider using a different mirror';
|
||||
};
|
||||
|
||||
const getSpeedClass = (speed: number) => {
|
||||
if (speed >= 100) return 'text-green-500';
|
||||
if (speed >= 50) return 'text-blue-500';
|
||||
if (speed >= 20) return 'text-yellow-500';
|
||||
return 'text-red-500';
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white/80 backdrop-blur-sm p-6 rounded-lg">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<Wifi className="h-5 w-5 text-cornflower-blue" />
|
||||
<h2 className="text-xl font-semibold text-gray-900">Network Speed</h2>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className={`text-2xl font-bold ${getSpeedClass(speed)}`}>
|
||||
{speed} Mbps
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-gray-600">{getRecommendation(speed)}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,34 +0,0 @@
|
||||
import { MapPin } from 'lucide-react';
|
||||
import { type Mirror } from '@/types/download';
|
||||
import { type UserLocation } from '@/lib/location';
|
||||
|
||||
interface SuggestedMirrorProps {
|
||||
mirror: Mirror;
|
||||
userLocation: UserLocation;
|
||||
onSelect: (mirror: Mirror) => void;
|
||||
}
|
||||
|
||||
export function SuggestedMirror({ mirror, userLocation, onSelect }: SuggestedMirrorProps) {
|
||||
return (
|
||||
<div className="bg-white/80 backdrop-blur-sm p-6 rounded-lg border-2 border-cornflower-blue">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<MapPin className="h-5 w-5 text-cornflower-blue" />
|
||||
<div>
|
||||
<h3 className="font-medium text-gray-900">Suggested Mirror</h3>
|
||||
<p className="text-sm text-gray-500">Based on your location: {userLocation.city}, {userLocation.country}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<p className="font-medium text-gray-900">{mirror.name}</p>
|
||||
<p className="text-sm text-gray-600">{mirror.location}</p>
|
||||
<button
|
||||
onClick={() => onSelect(mirror)}
|
||||
className="w-full mt-2 px-4 py-2 bg-cornflower-blue text-white rounded-lg hover:bg-blue-600 transition-colors"
|
||||
>
|
||||
Use This Mirror
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
import { Check } from 'lucide-react';
|
||||
|
||||
const requirements = [
|
||||
'Minimum 2GB RAM (4GB recommended)',
|
||||
'20GB disk space',
|
||||
'CPU with virtualization support',
|
||||
'DVD drive / USB boot support',
|
||||
'Internet connectivity for updates',
|
||||
];
|
||||
|
||||
export function SystemRequirements() {
|
||||
return (
|
||||
<div className="bg-white/80 backdrop-blur-sm p-6 rounded-lg">
|
||||
<h2 className="text-xl font-semibold text-gray-900 mb-4">System Requirements</h2>
|
||||
<ul className="space-y-3">
|
||||
{requirements.map((req) => (
|
||||
<li key={req} className="flex items-center gap-2">
|
||||
<Check className="h-5 w-5 text-green-500 flex-shrink-0" />
|
||||
<span className="text-gray-600">{req}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
interface CategoryFilterProps {
|
||||
categories: string[];
|
||||
selectedCategory: string;
|
||||
onSelect: (category: string) => void;
|
||||
}
|
||||
|
||||
export function CategoryFilter({ categories, selectedCategory, onSelect }: CategoryFilterProps) {
|
||||
return (
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{categories.map((category) => (
|
||||
<motion.button
|
||||
key={category}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
onClick={() => onSelect(category)}
|
||||
className={`px-4 py-2 rounded-full text-sm font-medium transition-colors ${
|
||||
selectedCategory === category
|
||||
? 'bg-cornflower-blue text-white'
|
||||
: 'bg-white/80 text-gray-600 hover:bg-gray-100'
|
||||
}`}
|
||||
>
|
||||
{category}
|
||||
</motion.button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,22 +0,0 @@
|
||||
import { Search } from 'lucide-react';
|
||||
import { ChangeEvent } from 'react';
|
||||
|
||||
interface SearchBarProps {
|
||||
value: string;
|
||||
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
|
||||
}
|
||||
|
||||
export function SearchBar({ value, onChange }: SearchBarProps) {
|
||||
return (
|
||||
<div className="relative">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-gray-400" />
|
||||
<input
|
||||
type="text"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
placeholder="Search tools..."
|
||||
className="w-full pl-10 pr-4 py-2 bg-white/80 backdrop-blur-sm border border-gray-200 rounded-lg focus:ring-2 focus:ring-cornflower-blue focus:border-transparent outline-none"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Terminal } from 'lucide-react';
|
||||
|
||||
interface ToolCardProps {
|
||||
name: string;
|
||||
description: string;
|
||||
category: string;
|
||||
command: string;
|
||||
}
|
||||
|
||||
export function ToolCard({ name, description, category, command }: ToolCardProps) {
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
whileHover={{ y: -5 }}
|
||||
className="bg-white/80 backdrop-blur-sm p-6 rounded-lg shadow-sm border border-gray-100"
|
||||
>
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<Terminal className="h-5 w-5 text-cornflower-blue" />
|
||||
<h3 className="text-lg font-semibold text-gray-900">{name}</h3>
|
||||
</div>
|
||||
|
||||
<p className="text-gray-600 mb-4">{description}</p>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm font-medium text-cornflower-blue">{category}</span>
|
||||
<code className="text-sm bg-gray-100 px-2 py-1 rounded">{command}</code>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
interface CategoryFilterProps {
|
||||
categories: string[];
|
||||
selectedCategory: string;
|
||||
onSelect: (category: string) => void;
|
||||
}
|
||||
|
||||
export function CategoryFilter({ categories, selectedCategory, onSelect }: CategoryFilterProps) {
|
||||
return (
|
||||
<div className="flex flex-wrap justify-center gap-3 mb-8">
|
||||
{categories.map((category) => (
|
||||
<motion.button
|
||||
key={category}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
whileTap={{ scale: 0.95 }}
|
||||
onClick={() => onSelect(category)}
|
||||
className={`px-4 py-2 rounded-full text-sm font-medium transition-colors ${
|
||||
selectedCategory === category
|
||||
? 'bg-cornflower-blue text-white'
|
||||
: 'bg-white text-gray-600 hover:bg-gray-100'
|
||||
}`}
|
||||
>
|
||||
{category}
|
||||
</motion.button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,30 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
interface GalleryImageProps {
|
||||
src: string;
|
||||
alt: string;
|
||||
category: string;
|
||||
}
|
||||
|
||||
export function GalleryImage({ src, alt, category }: GalleryImageProps) {
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
whileInView={{ opacity: 1, scale: 1 }}
|
||||
whileHover={{ y: -5 }}
|
||||
className="relative group overflow-hidden rounded-lg"
|
||||
>
|
||||
<img
|
||||
src={src}
|
||||
alt={alt}
|
||||
className="w-full h-64 object-cover transform group-hover:scale-110 transition-transform duration-500"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/70 to-transparent opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<div className="absolute bottom-0 left-0 right-0 p-4">
|
||||
<p className="text-white font-medium">{alt}</p>
|
||||
<span className="text-sm text-gray-300">{category}</span>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
@@ -1,60 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Check, X } from 'lucide-react';
|
||||
|
||||
const features = [
|
||||
'Advanced Security Tools',
|
||||
'Regular Updates',
|
||||
'Community Support',
|
||||
'Hardware Compatibility',
|
||||
'Custom Tools',
|
||||
'Enterprise Support',
|
||||
];
|
||||
|
||||
export function ComparisonSection() {
|
||||
return (
|
||||
<section className="py-20 bg-gray-50">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="text-center mb-12">
|
||||
<h2 className="text-3xl font-bold text-gray-900">Why Choose Snigdha OS?</h2>
|
||||
<p className="mt-4 text-lg text-gray-600">
|
||||
Compare and see why security professionals prefer Snigdha OS
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
{['Other Distros', 'Snigdha OS', 'Commercial Tools'].map((title, colIndex) => (
|
||||
<motion.div
|
||||
key={title}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: colIndex * 0.2 }}
|
||||
className={`bg-white rounded-lg shadow-lg overflow-hidden ${
|
||||
colIndex === 1 ? 'ring-2 ring-cornflower-blue' : ''
|
||||
}`}
|
||||
>
|
||||
<div className={`p-6 ${
|
||||
colIndex === 1 ? 'bg-cornflower-blue text-white' : 'bg-gray-50'
|
||||
}`}>
|
||||
<h3 className="text-xl font-semibold">{title}</h3>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<ul className="space-y-4">
|
||||
{features.map((feature) => (
|
||||
<li key={feature} className="flex items-center gap-2">
|
||||
{colIndex === 1 ? (
|
||||
<Check className="h-5 w-5 text-green-500" />
|
||||
) : (
|
||||
<X className="h-5 w-5 text-red-500" />
|
||||
)}
|
||||
<span className="text-gray-600">{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
@@ -1,30 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { LucideIcon } from 'lucide-react';
|
||||
|
||||
interface FeatureCardProps {
|
||||
title: string;
|
||||
description: string;
|
||||
icon: LucideIcon;
|
||||
delay?: number;
|
||||
}
|
||||
|
||||
export function FeatureCard({ title, description, icon: Icon, delay = 0 }: FeatureCardProps) {
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5, delay }}
|
||||
viewport={{ once: true }}
|
||||
whileHover={{ y: -5 }}
|
||||
className="relative group"
|
||||
>
|
||||
<div className="rounded-xl bg-white/80 backdrop-blur p-8 ring-1 ring-gray-200 hover:ring-cornflower-blue transition-all shadow-lg overflow-hidden">
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-cornflower-blue/0 to-cornflower-blue/0 group-hover:from-cornflower-blue/5 group-hover:to-cornflower-blue/10 transition-colors" />
|
||||
|
||||
<Icon className="h-10 w-10 text-cornflower-blue mb-4" />
|
||||
<h3 className="text-xl font-semibold text-gray-900 mb-2">{title}</h3>
|
||||
<p className="text-gray-600">{description}</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
@@ -1,76 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Download, ChevronRight, Terminal } from 'lucide-react';
|
||||
|
||||
export function HeroSection() {
|
||||
return (
|
||||
<section className="relative min-h-[90vh] flex items-center overflow-hidden bg-gradient-to-r from-gray-900 to-gray-800">
|
||||
<div className="absolute inset-0 bg-[url('https://images.unsplash.com/photo-1629654297299-c8506221ca97?auto=format&fit=crop&q=80')] bg-cover bg-center opacity-10" />
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-transparent to-gray-900/50" />
|
||||
|
||||
<div className="relative mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8, ease: "easeOut" }}
|
||||
className="text-center"
|
||||
>
|
||||
<motion.div
|
||||
animate={{
|
||||
rotate: [0, 5, -5, 0],
|
||||
scale: [1, 1.1, 1]
|
||||
}}
|
||||
transition={{ duration: 2, repeat: Infinity, repeatDelay: 3 }}
|
||||
>
|
||||
<Terminal className="mx-auto h-20 w-20 text-cornflower-blue" />
|
||||
</motion.div>
|
||||
|
||||
<motion.h1
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.3 }}
|
||||
className="mt-6 text-4xl font-bold tracking-tight text-white sm:text-6xl"
|
||||
>
|
||||
The Future of
|
||||
<span className="text-cornflower-blue"> Security Testing </span>
|
||||
is Here
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.6 }}
|
||||
className="mt-6 text-lg leading-8 text-gray-300 max-w-2xl mx-auto"
|
||||
>
|
||||
Snigdha OS redefines penetration testing with advanced tools, intuitive interface, and unmatched performance.
|
||||
</motion.p>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.9 }}
|
||||
className="mt-10 flex items-center justify-center gap-x-6"
|
||||
>
|
||||
<Link
|
||||
to="/download"
|
||||
className="group relative rounded-lg bg-cornflower-blue px-8 py-3 text-sm font-semibold text-white shadow-lg hover:bg-blue-600 transition-colors overflow-hidden"
|
||||
>
|
||||
<span className="relative flex items-center gap-2">
|
||||
<Download className="h-4 w-4" />
|
||||
Download Now
|
||||
</span>
|
||||
<div className="absolute inset-0 bg-white/20 transform -skew-x-12 -translate-x-full group-hover:translate-x-full transition-transform duration-700" />
|
||||
</Link>
|
||||
<Link
|
||||
to="/features"
|
||||
className="text-sm font-semibold leading-6 text-white flex items-center group"
|
||||
>
|
||||
Learn more
|
||||
<ChevronRight className="ml-1 h-4 w-4 transform group-hover:translate-x-1 transition-transform" />
|
||||
</Link>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Users, Wrench, Star } from 'lucide-react';
|
||||
|
||||
const stats = [
|
||||
{ label: 'Active Users', value: '50K+', icon: Users },
|
||||
{ label: 'Security Tools', value: '600+', icon: Wrench },
|
||||
{ label: 'GitHub Stars', value: '15K+', icon: Star },
|
||||
];
|
||||
|
||||
export function StatsSection() {
|
||||
return (
|
||||
<section className="py-20 bg-gradient-to-b from-white to-gray-50">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
{stats.map((stat, index) => (
|
||||
<motion.div
|
||||
key={stat.label}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: index * 0.2 }}
|
||||
viewport={{ once: true }}
|
||||
className="text-center"
|
||||
>
|
||||
<stat.icon className="h-8 w-8 text-cornflower-blue mx-auto mb-4" />
|
||||
<motion.p
|
||||
initial={{ scale: 0.5 }}
|
||||
whileInView={{ scale: 1 }}
|
||||
transition={{ delay: index * 0.2 + 0.2 }}
|
||||
viewport={{ once: true }}
|
||||
className="text-4xl font-bold text-gray-900 mb-2"
|
||||
>
|
||||
{stat.value}
|
||||
</motion.p>
|
||||
<p className="text-gray-600">{stat.label}</p>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
@@ -1,27 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Quote } from 'lucide-react';
|
||||
|
||||
interface TestimonialProps {
|
||||
content: string;
|
||||
author: string;
|
||||
role: string;
|
||||
delay?: number;
|
||||
}
|
||||
|
||||
export function TestimonialCard({ content, author, role, delay = 0 }: TestimonialProps) {
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay }}
|
||||
className="bg-white/80 backdrop-blur-sm p-6 rounded-lg shadow-lg relative"
|
||||
>
|
||||
<Quote className="absolute top-4 right-4 h-8 w-8 text-cornflower-blue/20" />
|
||||
<p className="text-gray-600 mb-4">{content}</p>
|
||||
<div>
|
||||
<p className="font-semibold text-gray-900">{author}</p>
|
||||
<p className="text-sm text-gray-500">{role}</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Terminal, Shield, Wifi, Globe, Lock, Database } from 'lucide-react';
|
||||
|
||||
const tools = [
|
||||
{ name: 'Network Analysis', icon: Globe, color: 'text-blue-500' },
|
||||
{ name: 'Penetration Testing', icon: Shield, color: 'text-green-500' },
|
||||
{ name: 'Wireless Security', icon: Wifi, color: 'text-purple-500' },
|
||||
{ name: 'Cryptography', icon: Lock, color: 'text-red-500' },
|
||||
{ name: 'Forensics', icon: Database, color: 'text-yellow-500' },
|
||||
{ name: 'Exploitation', icon: Terminal, color: 'text-pink-500' },
|
||||
];
|
||||
|
||||
export function ToolsShowcase() {
|
||||
return (
|
||||
<section className="py-20 bg-gradient-to-b from-gray-50 to-white">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="text-center mb-12">
|
||||
<h2 className="text-3xl font-bold text-gray-900">Security Tools Suite</h2>
|
||||
<p className="mt-4 text-lg text-gray-600">
|
||||
Comprehensive toolkit for security professionals
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-8">
|
||||
{tools.map((tool, index) => (
|
||||
<motion.div
|
||||
key={tool.name}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: index * 0.1 }}
|
||||
className="flex flex-col items-center p-6 bg-white rounded-lg shadow-sm hover:shadow-md transition-shadow"
|
||||
>
|
||||
<tool.icon className={`h-10 w-10 ${tool.color} mb-4`} />
|
||||
<h3 className="text-lg font-semibold text-gray-900">{tool.name}</h3>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
@@ -1,103 +0,0 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Github, Twitter, Youtube, Mail, Book, FileText, MessageSquare, Newspaper, HelpCircle } from 'lucide-react';
|
||||
|
||||
const footerNavigation = {
|
||||
main: [
|
||||
{ name: 'Gallery', href: '/gallery' },
|
||||
{ name: 'Developers', href: '/developers' },
|
||||
{ name: 'Donate', href: '/donate' },
|
||||
],
|
||||
resources: [
|
||||
{ name: 'Documentation', href: '/docs', icon: Book },
|
||||
{ name: 'Blog', href: '/blog', icon: Newspaper },
|
||||
{ name: 'Support', href: '/support', icon: HelpCircle },
|
||||
],
|
||||
community: [
|
||||
{ name: 'Community', href: '/community', icon: MessageSquare },
|
||||
{ name: 'GitHub', href: 'https://github.com/Snigdha-OS', icon: Github },
|
||||
{ name: 'Twitter', href: 'https://twitter.com', icon: Twitter },
|
||||
{ name: 'YouTube', href: 'https://youtube.com', icon: Youtube },
|
||||
],
|
||||
};
|
||||
|
||||
export function Footer() {
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
return (
|
||||
<footer className="bg-gray-900 text-gray-300">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-8">
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-lg font-semibold text-white">Snigdha OS</h3>
|
||||
<p className="text-sm">
|
||||
The most advanced penetration testing distribution, designed for security professionals and enthusiasts.
|
||||
</p>
|
||||
<div className="flex space-x-4">
|
||||
{footerNavigation.community.map((item) => (
|
||||
<a
|
||||
key={item.name}
|
||||
href={item.href}
|
||||
className="hover:text-white transition-colors"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<item.icon className="h-5 w-5" />
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-white uppercase tracking-wider mb-4">Navigation</h3>
|
||||
<ul className="space-y-3">
|
||||
{footerNavigation.main.map((item) => (
|
||||
<li key={item.name}>
|
||||
<Link to={item.href} className="hover:text-white transition-colors">
|
||||
{item.name}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-white uppercase tracking-wider mb-4">Resources</h3>
|
||||
<ul className="space-y-3">
|
||||
{footerNavigation.resources.map((item) => (
|
||||
<li key={item.name}>
|
||||
<Link to={item.href} className="flex items-center gap-2 hover:text-white transition-colors">
|
||||
<item.icon className="h-4 w-4" />
|
||||
{item.name}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-white uppercase tracking-wider mb-4">Community</h3>
|
||||
<ul className="space-y-3">
|
||||
{footerNavigation.community.map((item) => (
|
||||
<li key={item.name}>
|
||||
<a
|
||||
href={item.href}
|
||||
className="flex items-center gap-2 hover:text-white transition-colors"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<item.icon className="h-4 w-4" />
|
||||
{item.name}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-12 pt-8 border-t border-gray-800 text-sm text-center">
|
||||
<p>© {currentYear} Snigdha OS. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
import { Mail, MapPin, Phone } from 'lucide-react';
|
||||
|
||||
export function ContactSection() {
|
||||
return (
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-white uppercase tracking-wider mb-4">Contact Us</h3>
|
||||
<ul className="space-y-3">
|
||||
<li>
|
||||
<a
|
||||
href="mailto:contact@snigdhaos.org"
|
||||
className="flex items-center gap-2 hover:text-white transition-colors"
|
||||
>
|
||||
<Mail className="h-4 w-4" />
|
||||
contact@snigdhaos.org
|
||||
</a>
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<MapPin className="h-4 w-4" />
|
||||
<span>Bangalore, India</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<Phone className="h-4 w-4" />
|
||||
<span>+91 (080) 4567-8900</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,75 +0,0 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Github, Twitter, Youtube, Book, MessageSquare, Newspaper, HelpCircle } from 'lucide-react';
|
||||
import { ContactSection } from './ContactSection';
|
||||
import { footerNavigation } from '@/data/footerNavigation';
|
||||
|
||||
export function Footer() {
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
return (
|
||||
<footer className="bg-gray-900 text-gray-300">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||
<div className="grid grid-cols-1 md:grid-cols-5 gap-8">
|
||||
<div className="space-y-4 md:col-span-2">
|
||||
<h3 className="text-lg font-semibold text-white">Snigdha OS</h3>
|
||||
<p className="text-sm">
|
||||
The most advanced penetration testing distribution, designed for security professionals and enthusiasts.
|
||||
</p>
|
||||
<div className="flex space-x-4">
|
||||
{footerNavigation.community.map((item) => (
|
||||
<a
|
||||
key={item.name}
|
||||
href={item.href}
|
||||
className="hover:text-white transition-colors"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<item.icon className="h-5 w-5" />
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-white uppercase tracking-wider mb-4">Resources</h3>
|
||||
<ul className="space-y-3">
|
||||
{footerNavigation.resources.map((item) => (
|
||||
<li key={item.name}>
|
||||
<Link to={item.href} className="flex items-center gap-2 hover:text-white transition-colors">
|
||||
<item.icon className="h-4 w-4" />
|
||||
{item.name}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-white uppercase tracking-wider mb-4">Community</h3>
|
||||
<ul className="space-y-3">
|
||||
{footerNavigation.community.map((item) => (
|
||||
<li key={item.name}>
|
||||
<a
|
||||
href={item.href}
|
||||
className="flex items-center gap-2 hover:text-white transition-colors"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<item.icon className="h-4 w-4" />
|
||||
{item.name}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<ContactSection />
|
||||
</div>
|
||||
|
||||
<div className="mt-12 pt-8 border-t border-gray-800 text-sm text-center">
|
||||
<p>© {currentYear} Snigdha OS. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
@@ -1,84 +0,0 @@
|
||||
import { useState } from 'react';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import { Menu, X } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { navigation } from '@/data/navigation';
|
||||
|
||||
function Logo() {
|
||||
return (
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16 2L3 9V23L16 30L29 23V9L16 2Z" stroke="#6495ED" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
<path d="M16 2V16M16 16V30M16 16L29 9M16 16L3 9" stroke="#6495ED" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export function Navbar() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const location = useLocation();
|
||||
|
||||
return (
|
||||
<nav className="fixed w-full z-50 bg-white/80 backdrop-blur-lg border-b border-gray-200">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex justify-between h-16">
|
||||
<div className="flex">
|
||||
<Link to="/" className="flex-shrink-0 flex items-center">
|
||||
<Logo />
|
||||
<span className="ml-2 text-xl font-bold text-gray-900">Snigdha OS</span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="hidden sm:flex sm:items-center sm:space-x-8">
|
||||
{navigation.map((item) => (
|
||||
<Link
|
||||
key={item.name}
|
||||
to={item.href}
|
||||
className={cn(
|
||||
'px-3 py-2 rounded-md text-sm font-medium transition-colors flex items-center gap-2',
|
||||
location.pathname === item.href
|
||||
? 'text-cornflower-blue'
|
||||
: 'text-gray-600 hover:text-cornflower-blue'
|
||||
)}
|
||||
>
|
||||
<item.icon className="h-4 w-4" />
|
||||
{item.name}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center sm:hidden">
|
||||
<button
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100"
|
||||
>
|
||||
{isOpen ? <X className="h-6 w-6" /> : <Menu className="h-6 w-6" />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isOpen && (
|
||||
<div className="sm:hidden bg-white/90 backdrop-blur-lg">
|
||||
<div className="px-2 pt-2 pb-3 space-y-1">
|
||||
{navigation.map((item) => (
|
||||
<Link
|
||||
key={item.name}
|
||||
to={item.href}
|
||||
className={cn(
|
||||
'block px-3 py-2 rounded-md text-base font-medium flex items-center gap-2',
|
||||
location.pathname === item.href
|
||||
? 'text-cornflower-blue bg-blue-50'
|
||||
: 'text-gray-600 hover:text-cornflower-blue hover:bg-blue-50'
|
||||
)}
|
||||
onClick={() => setIsOpen(false)}
|
||||
>
|
||||
<item.icon className="h-4 w-4" />
|
||||
{item.name}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</nav>
|
||||
);
|
||||
}
|
@@ -1,34 +0,0 @@
|
||||
import { ErrorBoundary as ReactErrorBoundary } from 'react-error-boundary';
|
||||
import { AlertCircle } from 'lucide-react';
|
||||
|
||||
function ErrorFallback({ error }: { error: Error }) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-gray-50">
|
||||
<div className="max-w-md w-full p-6 bg-white/80 backdrop-blur-lg rounded-lg shadow-lg">
|
||||
<div className="flex items-center justify-center text-red-500 mb-4">
|
||||
<AlertCircle size={48} />
|
||||
</div>
|
||||
<h2 className="text-2xl font-bold text-gray-900 text-center mb-4">
|
||||
Something went wrong
|
||||
</h2>
|
||||
<pre className="text-sm bg-gray-100 p-4 rounded overflow-auto">
|
||||
{error.message}
|
||||
</pre>
|
||||
<button
|
||||
onClick={() => window.location.reload()}
|
||||
className="mt-4 w-full bg-cornflower-blue text-white py-2 px-4 rounded hover:bg-blue-600 transition-colors"
|
||||
>
|
||||
Try again
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ErrorBoundary({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<ReactErrorBoundary FallbackComponent={ErrorFallback}>
|
||||
{children}
|
||||
</ReactErrorBoundary>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user