mirror of
https://github.com/Snigdha-OS/Snigdha-OS.github.io.git
synced 2025-09-05 20:26:43 +02:00
🧹 chore(clean): whole repository
This commit is contained in:
51
SECURITY.md
51
SECURITY.md
@@ -1,51 +0,0 @@
|
||||
# Snigdha OS Web Dev Security Policy 🔐
|
||||
|
||||
Thank you for taking an interest in the security of Snigdha OS Web Dev! We take security seriously and encourage responsible disclosure of vulnerabilities.
|
||||
|
||||
## 🚨 Reporting a Vulnerability
|
||||
|
||||
If you discover a security vulnerability, please follow these steps to report it responsibly:
|
||||
|
||||
1. **Do not open a public issue** on GitHub. This helps prevent potential exploitation by malicious users.
|
||||
2. Send a detailed email to us at **security@snigdhaos.org**.
|
||||
3. In the email, include the following details:
|
||||
- A description of the vulnerability.
|
||||
- The steps to reproduce the issue.
|
||||
- Any potential exploit or sample code (if possible).
|
||||
- Your contact information (optional but helpful).
|
||||
|
||||
## 🔒 Security Response Process
|
||||
|
||||
Once we receive your report, we will follow these steps:
|
||||
|
||||
1. **Acknowledge receipt**: We will confirm that we've received your report within 24-48 hours.
|
||||
2. **Assessment**: We will assess the issue, determine its severity, and prioritize fixing it.
|
||||
3. **Fix the issue**: We will implement the necessary fixes or patches and test them.
|
||||
4. **Public disclosure**: After fixing the issue, we will publicly disclose the vulnerability in the form of a GitHub release or security advisory.
|
||||
5. **Follow-up**: We will notify you of the resolution and, if appropriate, credit you for the discovery.
|
||||
|
||||
## 🔑 Security Best Practices
|
||||
|
||||
We recommend the following best practices to help keep Snigdha OS Web Dev secure:
|
||||
|
||||
- Always ensure your development environment is up to date with the latest security patches.
|
||||
- Use secure libraries and frameworks when contributing to the project.
|
||||
- Avoid storing sensitive information like passwords, API keys, or credentials in the codebase.
|
||||
- Regularly check for known vulnerabilities in dependencies and update them as necessary.
|
||||
- Use HTTPS for all communications between clients and servers.
|
||||
|
||||
## 🛠 Security Tools We Use
|
||||
|
||||
We actively use the following tools to help ensure security in Snigdha OS Web Dev:
|
||||
|
||||
- **Code scanning** tools like GitHub's built-in security features to check for vulnerabilities in the codebase.
|
||||
- **Dependabot** to monitor and automatically update vulnerable dependencies.
|
||||
- Regular security audits by our team to identify and mitigate potential threats.
|
||||
|
||||
## 👥 Responsible Disclosure
|
||||
|
||||
By following our security policy and responsibly reporting any discovered vulnerabilities, you help improve the security of Snigdha OS Web Dev for everyone. We appreciate your efforts in making our project more secure.
|
||||
|
||||
Thank you for being a responsible member of the Snigdha OS Web Dev community!
|
||||
|
||||
For further details, refer to our [CONTRIBUTING.md](CONTRIBUTING.md) file for how you can contribute to the Snigdha OS Web Dev project in a safe and secure manner.
|
26
deploy.sh
26
deploy.sh
@@ -1,26 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# abort on errors
|
||||
set -e
|
||||
|
||||
# build
|
||||
npm run build
|
||||
|
||||
# navigate into the build output directory
|
||||
cd dist
|
||||
|
||||
# place .nojekyll to bypass Jekyll processing
|
||||
echo > .nojekyll
|
||||
|
||||
# if you are deploying to a custom domain
|
||||
# echo 'www.example.com' > CNAME
|
||||
|
||||
git init
|
||||
git checkout -B master
|
||||
git add -A
|
||||
git commit -m 'deploy'
|
||||
|
||||
# if you are deploying to https://<USERNAME>.github.io/<REPO>
|
||||
git push -f git@github.com:<USERNAME>/snigdha-os.git master:gh-pages
|
||||
|
||||
cd -
|
@@ -1,28 +0,0 @@
|
||||
import js from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
import reactHooks from 'eslint-plugin-react-hooks';
|
||||
import reactRefresh from 'eslint-plugin-react-refresh';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ['dist'] },
|
||||
{
|
||||
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
plugins: {
|
||||
'react-hooks': reactHooks,
|
||||
'react-refresh': reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
}
|
||||
);
|
31
index.html
31
index.html
@@ -1,31 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Sans:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<title>Snigdha OS - Advanced Penetration Testing Distribution</title>
|
||||
<!-- Start Single Page Apps for GitHub Pages -->
|
||||
<script type="text/javascript">
|
||||
// Single Page Apps for GitHub Pages
|
||||
// MIT License
|
||||
// https://github.com/rafgraph/spa-github-pages
|
||||
(function(l) {
|
||||
if (l.search[1] === '/' ) {
|
||||
var decoded = l.search.slice(1).split('&').map(function(s) {
|
||||
return s.replace(/~and~/g, '&')
|
||||
}).join('?');
|
||||
window.history.replaceState(null, null,
|
||||
l.pathname.slice(0, -1) + decoded + l.hash
|
||||
);
|
||||
}
|
||||
}(window.location))
|
||||
</script>
|
||||
<!-- End Single Page Apps for GitHub Pages -->
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
4204
package-lock.json
generated
4204
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
44
package.json
44
package.json
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"name": "snigdha-os",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"homepage": "https://snigdha-os.github.io/",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview",
|
||||
"predeploy": "npm run build",
|
||||
"deploy": "gh-pages -d dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tanstack/react-query": "^5.25.0",
|
||||
"clsx": "^2.1.0",
|
||||
"framer-motion": "^11.0.8",
|
||||
"lucide-react": "^0.344.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-error-boundary": "^4.0.13",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"tailwind-merge": "^2.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.9.1",
|
||||
"@types/node": "^22.10.2",
|
||||
"@types/react": "^18.3.5",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"autoprefixer": "^10.4.18",
|
||||
"eslint": "^9.9.1",
|
||||
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.11",
|
||||
"gh-pages": "^6.2.0",
|
||||
"globals": "^15.9.0",
|
||||
"postcss": "^8.4.35",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5.5.3",
|
||||
"typescript-eslint": "^8.3.0",
|
||||
"vite": "^5.4.2"
|
||||
}
|
||||
}
|
2915
pnpm-lock.yaml
generated
2915
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +0,0 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
@@ -1,24 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Snigdha OS</title>
|
||||
<script type="text/javascript">
|
||||
// Single Page Apps for GitHub Pages
|
||||
// MIT License
|
||||
// https://github.com/rafgraph/spa-github-pages
|
||||
var pathSegmentsToKeep = 1;
|
||||
|
||||
var l = window.location;
|
||||
l.replace(
|
||||
l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +
|
||||
l.pathname.split('/').slice(0, 1 + pathSegmentsToKeep).join('/') + '/?/' +
|
||||
l.pathname.slice(1).split('/').slice(pathSegmentsToKeep).join('/').replace(/&/g, '~and~') +
|
||||
(l.search ? '&' + l.search.slice(1).replace(/&/g, '~and~') : '') +
|
||||
l.hash
|
||||
);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
38
src/App.tsx
38
src/App.tsx
@@ -1,38 +0,0 @@
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { ErrorBoundary } from '@/components/ui/ErrorBoundary';
|
||||
import { Navbar } from '@/components/layout/Navbar';
|
||||
import { Footer } from '@/components/layout/Footer';
|
||||
import { AppRoutes } from '@/routes';
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
staleTime: 1000 * 60 * 5, // 5 minutes
|
||||
retry: 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
function App() {
|
||||
// Use basename for GitHub Pages
|
||||
const basename = import.meta.env.DEV ? '/' : '/snigdha-os';
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Router basename={basename}>
|
||||
<div className="min-h-screen bg-gray-50 font-fira-sans flex flex-col">
|
||||
<Navbar />
|
||||
<main className="flex-grow pt-16">
|
||||
<AppRoutes />
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
</Router>
|
||||
</QueryClientProvider>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
@@ -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>
|
||||
);
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
export const donationTiers = [
|
||||
{
|
||||
name: 'Supporter',
|
||||
amount: 10,
|
||||
benefits: [
|
||||
'Name on donor wall',
|
||||
'Special Discord role',
|
||||
'Monthly newsletter',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Contributor',
|
||||
amount: 25,
|
||||
benefits: [
|
||||
'Name on donor wall',
|
||||
'Special Discord role',
|
||||
'Monthly newsletter',
|
||||
'Early access to releases',
|
||||
'Exclusive wallpapers',
|
||||
],
|
||||
recommended: true,
|
||||
},
|
||||
{
|
||||
name: 'Sustainer',
|
||||
amount: 50,
|
||||
benefits: [
|
||||
'Name on donor wall',
|
||||
'Special Discord role',
|
||||
'Monthly newsletter',
|
||||
'Early access to releases',
|
||||
'Exclusive wallpapers',
|
||||
'Private support channel',
|
||||
'Vote on future features',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const recentDonors = [
|
||||
{
|
||||
name: 'Alice Johnson',
|
||||
amount: 25,
|
||||
message: 'Keep up the amazing work!',
|
||||
date: '2024-03-15',
|
||||
},
|
||||
{
|
||||
name: 'Bob Smith',
|
||||
amount: 50,
|
||||
date: '2024-03-14',
|
||||
},
|
||||
{
|
||||
name: 'Carol Williams',
|
||||
amount: 10,
|
||||
message: 'Love using Snigdha OS for security research',
|
||||
date: '2024-03-13',
|
||||
},
|
||||
];
|
@@ -1,17 +0,0 @@
|
||||
export interface DownloadVersion {
|
||||
version: string;
|
||||
size: string;
|
||||
url: string;
|
||||
sha256: string;
|
||||
gpg: string;
|
||||
}
|
||||
|
||||
export const downloads: DownloadVersion[] = [
|
||||
{
|
||||
version: '2024.1',
|
||||
size: '4.2 GB',
|
||||
url: 'https://snigdhaos.org/downloads/snigdhaos-2024.1-installer-amd64.iso',
|
||||
sha256: 'e4654e5633f4e1f8f57a9fb3dca02f9db06e9acb5e346f0fae9d9f5c3a9c0e9',
|
||||
gpg: '-----BEGIN PGP SIGNATURE-----\nVersion: GnuPG v2\n...',
|
||||
},
|
||||
];
|
@@ -1,15 +0,0 @@
|
||||
import { Github, Twitter, Youtube, Book, MessageSquare, Newspaper, HelpCircle } from 'lucide-react';
|
||||
|
||||
export const footerNavigation = {
|
||||
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 },
|
||||
],
|
||||
};
|
@@ -1,34 +0,0 @@
|
||||
export const galleryImages = [
|
||||
{
|
||||
src: 'https://images.unsplash.com/photo-1526374965328-7f61d4dc18c5',
|
||||
alt: 'Security Dashboard',
|
||||
category: 'Interface',
|
||||
},
|
||||
{
|
||||
src: 'https://images.unsplash.com/photo-1544197150-b99a580bb7a8',
|
||||
alt: 'Network Analysis',
|
||||
category: 'Tools',
|
||||
},
|
||||
{
|
||||
src: 'https://images.unsplash.com/photo-1555949963-ff9fe0c870eb',
|
||||
alt: 'Terminal Environment',
|
||||
category: 'Interface',
|
||||
},
|
||||
{
|
||||
src: 'https://images.unsplash.com/photo-1526374870839-e155464bb9b2',
|
||||
alt: 'Security Testing',
|
||||
category: 'Tools',
|
||||
},
|
||||
{
|
||||
src: 'https://images.unsplash.com/photo-1551808525-51a94da548ce',
|
||||
alt: 'Hardware Support',
|
||||
category: 'Hardware',
|
||||
},
|
||||
{
|
||||
src: 'https://images.unsplash.com/photo-1558494949-ef010cbdcc31',
|
||||
alt: 'Wireless Testing',
|
||||
category: 'Hardware',
|
||||
},
|
||||
];
|
||||
|
||||
export const categories = ['All', 'Interface', 'Tools', 'Hardware'];
|
@@ -1,25 +0,0 @@
|
||||
import { Mirror } from '@/types/download';
|
||||
|
||||
export const mirrors: Mirror[] = [
|
||||
{
|
||||
id: 'us-east',
|
||||
name: 'US East Mirror',
|
||||
location: 'New York, USA',
|
||||
url: 'https://mirror-east.snigdhaos.org',
|
||||
speed: 120,
|
||||
},
|
||||
{
|
||||
id: 'eu-central',
|
||||
name: 'EU Central Mirror',
|
||||
location: 'Frankfurt, Germany',
|
||||
url: 'https://mirror-eu.snigdhaos.org',
|
||||
speed: 100,
|
||||
},
|
||||
{
|
||||
id: 'asia-east',
|
||||
name: 'Asia East Mirror',
|
||||
location: 'Singapore',
|
||||
url: 'https://mirror-asia.snigdhaos.org',
|
||||
speed: 80,
|
||||
},
|
||||
];
|
@@ -1,25 +0,0 @@
|
||||
import { type Mirror } from '@/types/download';
|
||||
|
||||
export const africanMirrors: Mirror[] = [
|
||||
{
|
||||
id: 'za-cape',
|
||||
name: 'South Africa Mirror',
|
||||
location: 'Cape Town, South Africa',
|
||||
url: 'https://mirror-za.snigdhaos.org',
|
||||
speed: 75,
|
||||
},
|
||||
{
|
||||
id: 'eg-cairo',
|
||||
name: 'Egypt Mirror',
|
||||
location: 'Cairo, Egypt',
|
||||
url: 'https://mirror-eg.snigdhaos.org',
|
||||
speed: 65,
|
||||
},
|
||||
{
|
||||
id: 'ke-nairobi',
|
||||
name: 'Kenya Mirror',
|
||||
location: 'Nairobi, Kenya',
|
||||
url: 'https://mirror-ke.snigdhaos.org',
|
||||
speed: 60,
|
||||
},
|
||||
];
|
@@ -1,32 +0,0 @@
|
||||
import { type Mirror } from '@/types/download';
|
||||
|
||||
export const americasMirrors: Mirror[] = [
|
||||
{
|
||||
id: 'us-east',
|
||||
name: 'US East Mirror',
|
||||
location: 'New York, USA',
|
||||
url: 'https://mirror-us-east.snigdhaos.org',
|
||||
speed: 130,
|
||||
},
|
||||
{
|
||||
id: 'us-west',
|
||||
name: 'US West Mirror',
|
||||
location: 'San Francisco, USA',
|
||||
url: 'https://mirror-us-west.snigdhaos.org',
|
||||
speed: 125,
|
||||
},
|
||||
{
|
||||
id: 'ca-central',
|
||||
name: 'Canada Mirror',
|
||||
location: 'Toronto, Canada',
|
||||
url: 'https://mirror-ca.snigdhaos.org',
|
||||
speed: 115,
|
||||
},
|
||||
{
|
||||
id: 'br-sao',
|
||||
name: 'Brazil Mirror',
|
||||
location: 'São Paulo, Brazil',
|
||||
url: 'https://mirror-br.snigdhaos.org',
|
||||
speed: 90,
|
||||
},
|
||||
];
|
@@ -1,32 +0,0 @@
|
||||
import { type Mirror } from '@/types/download';
|
||||
|
||||
export const asianMirrors: Mirror[] = [
|
||||
{
|
||||
id: 'sg-central',
|
||||
name: 'Singapore Mirror',
|
||||
location: 'Singapore',
|
||||
url: 'https://mirror-sg.snigdhaos.org',
|
||||
speed: 120,
|
||||
},
|
||||
{
|
||||
id: 'jp-tokyo',
|
||||
name: 'Japan Mirror',
|
||||
location: 'Tokyo, Japan',
|
||||
url: 'https://mirror-jp.snigdhaos.org',
|
||||
speed: 150,
|
||||
},
|
||||
{
|
||||
id: 'in-mumbai',
|
||||
name: 'India Mirror',
|
||||
location: 'Mumbai, India',
|
||||
url: 'https://mirror-in.snigdhaos.org',
|
||||
speed: 85,
|
||||
},
|
||||
{
|
||||
id: 'kr-seoul',
|
||||
name: 'South Korea Mirror',
|
||||
location: 'Seoul, South Korea',
|
||||
url: 'https://mirror-kr.snigdhaos.org',
|
||||
speed: 140,
|
||||
},
|
||||
];
|
@@ -1,32 +0,0 @@
|
||||
import { type Mirror } from '@/types/download';
|
||||
|
||||
export const europeanMirrors: Mirror[] = [
|
||||
{
|
||||
id: 'de-frankfurt',
|
||||
name: 'Germany Mirror',
|
||||
location: 'Frankfurt, Germany',
|
||||
url: 'https://mirror-de.snigdhaos.org',
|
||||
speed: 130,
|
||||
},
|
||||
{
|
||||
id: 'uk-london',
|
||||
name: 'UK Mirror',
|
||||
location: 'London, UK',
|
||||
url: 'https://mirror-uk.snigdhaos.org',
|
||||
speed: 125,
|
||||
},
|
||||
{
|
||||
id: 'fr-paris',
|
||||
name: 'France Mirror',
|
||||
location: 'Paris, France',
|
||||
url: 'https://mirror-fr.snigdhaos.org',
|
||||
speed: 120,
|
||||
},
|
||||
{
|
||||
id: 'nl-amsterdam',
|
||||
name: 'Netherlands Mirror',
|
||||
location: 'Amsterdam, Netherlands',
|
||||
url: 'https://mirror-nl.snigdhaos.org',
|
||||
speed: 135,
|
||||
},
|
||||
];
|
@@ -1,14 +0,0 @@
|
||||
import { africanMirrors } from './africa';
|
||||
import { americasMirrors } from './americas';
|
||||
import { asianMirrors } from './asia';
|
||||
import { europeanMirrors } from './europe';
|
||||
import { oceaniaMirrors } from './oceania';
|
||||
import { type Mirror } from '@/types/download';
|
||||
|
||||
export const mirrors: Mirror[] = [
|
||||
...americasMirrors,
|
||||
...europeanMirrors,
|
||||
...asianMirrors,
|
||||
...oceaniaMirrors,
|
||||
...africanMirrors,
|
||||
];
|
@@ -1,18 +0,0 @@
|
||||
import { type Mirror } from '@/types/download';
|
||||
|
||||
export const oceaniaMirrors: Mirror[] = [
|
||||
{
|
||||
id: 'au-sydney',
|
||||
name: 'Australia Mirror',
|
||||
location: 'Sydney, Australia',
|
||||
url: 'https://mirror-au.snigdhaos.org',
|
||||
speed: 100,
|
||||
},
|
||||
{
|
||||
id: 'nz-auckland',
|
||||
name: 'New Zealand Mirror',
|
||||
location: 'Auckland, New Zealand',
|
||||
url: 'https://mirror-nz.snigdhaos.org',
|
||||
speed: 95,
|
||||
},
|
||||
];
|
@@ -1,11 +0,0 @@
|
||||
import { Home, Info, Layout, Image, Download, Code, Heart } from 'lucide-react';
|
||||
|
||||
export const navigation = [
|
||||
{ name: 'Home', href: '/', icon: Home },
|
||||
{ name: 'About', href: '/about', icon: Info },
|
||||
{ name: 'Features', href: '/features', icon: Layout },
|
||||
{ name: 'Gallery', href: '/gallery', icon: Image },
|
||||
{ name: 'Download', href: '/download', icon: Download },
|
||||
{ name: 'Developers', href: '/developers', icon: Code },
|
||||
{ name: 'Donate', href: '/donate', icon: Heart },
|
||||
];
|
@@ -1,16 +0,0 @@
|
||||
import { type Sponsor } from '@/types/sponsor';
|
||||
|
||||
export const keySponsors: Sponsor[] = [
|
||||
{
|
||||
name: 'TONMOY INFRASTRUCTURE',
|
||||
description: 'Enterprise Partner & Infrastructure Provider',
|
||||
githubUsername: 'TIAsCode', // Using a real GitHub username
|
||||
amount: 5000,
|
||||
},
|
||||
{
|
||||
name: 'IX INTERNATION CO.',
|
||||
description: 'Strategic Development Partner',
|
||||
githubUsername: 'IXINTL', // Using a real GitHub username
|
||||
amount: 3500,
|
||||
},
|
||||
];
|
@@ -1,17 +0,0 @@
|
||||
export const teamMembers = [
|
||||
{
|
||||
username: 'eshanized', // Using placeholder usernames that exist on GitHub
|
||||
role: 'Core Development',
|
||||
description: 'Leading the development of Snigdha OS core system and architecture',
|
||||
},
|
||||
{
|
||||
username: 'd3v1l0n',
|
||||
role: 'Security Tools',
|
||||
description: 'Managing security tools integration and package maintenance',
|
||||
},
|
||||
{
|
||||
username: 'alokified',
|
||||
role: 'Project Lead',
|
||||
description: 'Overseeing project direction and community engagement',
|
||||
},
|
||||
];
|
@@ -1,17 +0,0 @@
|
||||
export const testimonials = [
|
||||
{
|
||||
content: "Snigdha OS has revolutionized our security testing workflow. The tools and interface are exceptional.",
|
||||
author: "Sarah Chen",
|
||||
role: "Security Engineer at TechCorp"
|
||||
},
|
||||
{
|
||||
content: "The best security-focused distribution I've used. Regular updates and great community support.",
|
||||
author: "Michael Rodriguez",
|
||||
role: "Penetration Tester"
|
||||
},
|
||||
{
|
||||
content: "Perfect for both beginners and advanced users. The documentation is comprehensive and helpful.",
|
||||
author: "Emma Thompson",
|
||||
role: "Cybersecurity Consultant"
|
||||
}
|
||||
];
|
@@ -1,62 +0,0 @@
|
||||
export interface Tool {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
category: string;
|
||||
command: string;
|
||||
}
|
||||
|
||||
export const tools: Tool[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Nmap',
|
||||
description: 'Network exploration tool and security scanner',
|
||||
category: 'Information Gathering',
|
||||
command: 'nmap',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Wireshark',
|
||||
description: 'Network protocol analyzer for real-time packet capture',
|
||||
category: 'Sniffing & Spoofing',
|
||||
command: 'wireshark',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'Metasploit',
|
||||
description: 'Penetration testing framework',
|
||||
category: 'Exploitation Tools',
|
||||
command: 'msfconsole',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
name: 'Burp Suite',
|
||||
description: 'Web vulnerability scanner and proxy tool',
|
||||
category: 'Web Applications',
|
||||
command: 'burpsuite',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
name: 'Aircrack-ng',
|
||||
description: 'Complete suite for wireless network security assessment',
|
||||
category: 'Wireless Attacks',
|
||||
command: 'aircrack-ng',
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
name: 'John the Ripper',
|
||||
description: 'Password cracker and hash analyzer',
|
||||
category: 'Password Attacks',
|
||||
command: 'john',
|
||||
},
|
||||
];
|
||||
|
||||
export const categories = [
|
||||
'All',
|
||||
'Information Gathering',
|
||||
'Sniffing & Spoofing',
|
||||
'Exploitation Tools',
|
||||
'Web Applications',
|
||||
'Wireless Attacks',
|
||||
'Password Attacks',
|
||||
];
|
@@ -1,25 +0,0 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { getUserLocation, type UserLocation } from '@/lib/location';
|
||||
|
||||
export function useLocation() {
|
||||
const [location, setLocation] = useState<UserLocation | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchLocation() {
|
||||
try {
|
||||
const userLocation = await getUserLocation();
|
||||
setLocation(userLocation);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err : new Error('Failed to get location'));
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
fetchLocation();
|
||||
}, []);
|
||||
|
||||
return { location, isLoading, error };
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { measureNetworkSpeed } from '@/lib/network';
|
||||
|
||||
export function useNetworkSpeed() {
|
||||
const [speed, setSpeed] = useState<number | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
async function checkSpeed() {
|
||||
try {
|
||||
const measuredSpeed = await measureNetworkSpeed();
|
||||
setSpeed(measuredSpeed);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err : new Error('Failed to measure network speed'));
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
checkSpeed();
|
||||
}, []);
|
||||
|
||||
return { speed, isLoading, error };
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
body {
|
||||
font-family: 'Fira Sans', sans-serif;
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
export function formatINR(amount: number) {
|
||||
return new Intl.NumberFormat('en-IN', {
|
||||
style: 'currency',
|
||||
currency: 'INR',
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 0,
|
||||
}).format(amount);
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
const GITHUB_API_URL = 'https://api.github.com';
|
||||
|
||||
export interface GithubUser {
|
||||
login: string;
|
||||
name: string | null;
|
||||
avatar_url: string;
|
||||
html_url: string;
|
||||
bio: string | null;
|
||||
public_repos: number;
|
||||
followers: number;
|
||||
location: string | null;
|
||||
}
|
||||
|
||||
export interface GithubRepo {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
html_url: string;
|
||||
stargazers_count: number;
|
||||
forks_count: number;
|
||||
language: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export async function fetchGithubUser(username: string): Promise<GithubUser> {
|
||||
try {
|
||||
const response = await fetch(`${GITHUB_API_URL}/users/${username}`);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
console.error(`GitHub API Error (${response.status}):`, errorData);
|
||||
throw new Error(`Failed to fetch user ${username}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error(`Error fetching GitHub user ${username}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchOrgRepos(org: string): Promise<GithubRepo[]> {
|
||||
try {
|
||||
const response = await fetch(`${GITHUB_API_URL}/orgs/${org}/repos?sort=updated&per_page=100`);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
console.error(`GitHub API Error (${response.status}):`, errorData);
|
||||
throw new Error(`Failed to fetch repositories: ${response.statusText}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Error fetching repositories:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
export interface UserLocation {
|
||||
country: string;
|
||||
city: string;
|
||||
continent: string;
|
||||
}
|
||||
|
||||
export async function getUserLocation(): Promise<UserLocation> {
|
||||
const response = await fetch('https://ipapi.co/json/');
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch location');
|
||||
}
|
||||
const data = await response.json();
|
||||
return {
|
||||
country: data.country_name,
|
||||
city: data.city,
|
||||
continent: data.continent_code,
|
||||
};
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
export async function measureNetworkSpeed(): Promise<number> {
|
||||
const startTime = performance.now();
|
||||
const response = await fetch('https://www.cloudflare.com/cdn-cgi/trace', { cache: 'no-store' });
|
||||
const endTime = performance.now();
|
||||
const duration = endTime - startTime;
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to measure network speed');
|
||||
}
|
||||
|
||||
const data = await response.text();
|
||||
const size = new Blob([data]).size;
|
||||
|
||||
// Calculate speed in Mbps (megabits per second)
|
||||
const speedMbps = (size * 8) / (duration / 1000) / 1000000;
|
||||
|
||||
return Math.round(speedMbps * 100) / 100;
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
import { type ClassValue, clsx } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
export function formatDate(date: string) {
|
||||
return new Date(date).toLocaleDateString('en-US', {
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
});
|
||||
}
|
||||
|
||||
export function formatSpeed(speed: number) {
|
||||
return `${speed} Mbps`;
|
||||
}
|
10
src/main.tsx
10
src/main.tsx
@@ -1,10 +0,0 @@
|
||||
import { StrictMode } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import App from './App.tsx';
|
||||
import './index.css';
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>
|
||||
);
|
@@ -1,39 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Timeline } from '@/components/about/Timeline';
|
||||
import { TeamSection } from '@/components/about/TeamSection';
|
||||
import { MissionSection } from '@/components/about/MissionSection';
|
||||
|
||||
export default function About() {
|
||||
return (
|
||||
<div className="py-12">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h1 className="text-4xl font-bold text-gray-900">About Snigdha OS</h1>
|
||||
<p className="mt-4 text-lg text-gray-600">
|
||||
The most advanced penetration testing distribution, made for security professionals.
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="space-y-16">
|
||||
<section>
|
||||
<MissionSection />
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 className="text-2xl font-bold text-gray-900 mb-8">Our Team Structure</h2>
|
||||
<TeamSection />
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 className="text-2xl font-bold text-gray-900 mb-8">Release Timeline</h2>
|
||||
<Timeline />
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,84 +0,0 @@
|
||||
import { useQueries, useQuery } from '@tanstack/react-query';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { TeamMemberCard } from '@/components/developers/TeamMemberCard';
|
||||
import { RepoCard } from '@/components/developers/RepoCard';
|
||||
import { fetchGithubUser, fetchOrgRepos } from '@/lib/github';
|
||||
import { teamMembers } from '@/data/team';
|
||||
|
||||
export default function Developers() {
|
||||
const queries = useQueries({
|
||||
queries: teamMembers.map(member => ({
|
||||
queryKey: ['github-user', member.username],
|
||||
queryFn: () => fetchGithubUser(member.username),
|
||||
})),
|
||||
});
|
||||
|
||||
const { data: repos, isLoading: loadingRepos, error: reposError } = useQuery({
|
||||
queryKey: ['github-repos', 'Snigdha-OS'],
|
||||
queryFn: () => fetchOrgRepos('Snigdha-OS'),
|
||||
});
|
||||
|
||||
const isLoading = queries.some(query => query.isLoading) || loadingRepos;
|
||||
const isError = queries.some(query => query.isError) || reposError;
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="min-h-[50vh] flex items-center justify-center">
|
||||
<Loader2 className="h-8 w-8 animate-spin text-cornflower-blue" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<div className="min-h-[50vh] flex items-center justify-center">
|
||||
<p className="text-red-500">Failed to load data</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="py-12">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h1 className="text-4xl font-bold text-gray-900">Our Team</h1>
|
||||
<p className="mt-4 text-lg text-gray-600">
|
||||
Meet the dedicated team behind Snigdha OS
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-16">
|
||||
{queries.map((query, index) => (
|
||||
query.data && (
|
||||
<TeamMemberCard
|
||||
key={query.data.login}
|
||||
user={query.data}
|
||||
role={teamMembers[index].role}
|
||||
description={teamMembers[index].description}
|
||||
/>
|
||||
)
|
||||
))}
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.2 }}
|
||||
className="mt-16"
|
||||
>
|
||||
<h2 className="text-3xl font-bold text-gray-900 mb-8">Our Repositories</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{repos?.map((repo) => (
|
||||
<RepoCard key={repo.id} repo={repo} />
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { Heart } from 'lucide-react';
|
||||
import { GithubSponsorButton } from '@/components/donate/GithubSponsorButton';
|
||||
import { SponsorshipTiers } from '@/components/donate/SponsorshipTiers';
|
||||
import { SponsorshipStats } from '@/components/donate/SponsorshipStats';
|
||||
import { KeySponsors } from '@/components/donate/KeySponsors';
|
||||
|
||||
export default function Donate() {
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-b from-gray-50 to-white py-12">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<Heart className="h-12 w-12 text-red-500 mx-auto mb-4" />
|
||||
<h1 className="text-4xl font-bold text-gray-900">Support Snigdha OS</h1>
|
||||
<p className="mt-4 text-lg text-gray-600 max-w-2xl mx-auto">
|
||||
Your support helps us maintain and improve Snigdha OS, keeping it free and open source for the security community.
|
||||
</p>
|
||||
<div className="mt-8">
|
||||
<GithubSponsorButton />
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<div className="space-y-16">
|
||||
<section>
|
||||
<KeySponsors />
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<SponsorshipStats />
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 className="text-2xl font-bold text-gray-900 text-center mb-8">
|
||||
Choose Your Sponsorship Tier
|
||||
</h2>
|
||||
<SponsorshipTiers />
|
||||
</section>
|
||||
|
||||
<section className="max-w-3xl mx-auto text-center bg-cornflower-blue/5 rounded-2xl p-8">
|
||||
<h2 className="text-2xl font-bold text-gray-900 mb-4">
|
||||
Why Sponsor Snigdha OS?
|
||||
</h2>
|
||||
<p className="text-gray-600">
|
||||
Your sponsorship directly supports the development of cutting-edge security tools,
|
||||
maintenance of our infrastructure, and helps us keep Snigdha OS at the forefront
|
||||
of security testing. Join our community of sponsors and help shape the future of
|
||||
security testing.
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,95 +0,0 @@
|
||||
import { useState } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { DownloadButton } from '@/components/download/DownloadButton';
|
||||
import { SystemRequirements } from '@/components/download/SystemRequirements';
|
||||
import { Checksum } from '@/components/download/Checksum';
|
||||
import { MirrorList } from '@/components/download/MirrorList';
|
||||
import { NetworkSpeed } from '@/components/download/NetworkSpeed';
|
||||
import { SuggestedMirror } from '@/components/download/SuggestedMirror';
|
||||
import { downloads } from '@/data/download';
|
||||
import { mirrors } from '@/data/mirrors';
|
||||
import { type Mirror } from '@/types/download';
|
||||
import { useNetworkSpeed } from '@/hooks/useNetworkSpeed';
|
||||
import { useLocation } from '@/hooks/useLocation';
|
||||
|
||||
export default function Download() {
|
||||
const latestVersion = downloads[0];
|
||||
const [selectedMirror, setSelectedMirror] = useState<Mirror | null>(null);
|
||||
const { speed, isLoading: loadingSpeed } = useNetworkSpeed();
|
||||
const { location, isLoading: loadingLocation } = useLocation();
|
||||
|
||||
const handleMirrorSelect = (mirror: Mirror) => {
|
||||
setSelectedMirror(mirror);
|
||||
};
|
||||
|
||||
// Sort mirrors by speed and location
|
||||
const sortedMirrors = [...mirrors].sort((a, b) => {
|
||||
if (!speed) return 0;
|
||||
const aDiff = Math.abs(a.speed - speed);
|
||||
const bDiff = Math.abs(b.speed - speed);
|
||||
return aDiff - bDiff;
|
||||
});
|
||||
|
||||
// Get suggested mirror based on location and speed
|
||||
const suggestedMirror = location ? sortedMirrors[0] : null;
|
||||
|
||||
if (loadingSpeed || loadingLocation) {
|
||||
return (
|
||||
<div className="min-h-[50vh] flex items-center justify-center">
|
||||
<Loader2 className="h-8 w-8 animate-spin text-cornflower-blue" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="py-12">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h1 className="text-4xl font-bold text-gray-900">Download Snigdha OS</h1>
|
||||
<p className="mt-4 text-lg text-gray-600">
|
||||
Get the latest version of the most advanced penetration testing distribution
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
<div className="lg:col-span-2 space-y-8">
|
||||
<DownloadButton {...latestVersion} />
|
||||
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold text-gray-900 mb-4">Download Mirrors</h2>
|
||||
<p className="text-sm text-gray-600 mb-4">
|
||||
Mirrors are sorted by compatibility with your connection speed for optimal download performance
|
||||
</p>
|
||||
<MirrorList
|
||||
mirrors={sortedMirrors}
|
||||
onSelect={handleMirrorSelect}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Checksum
|
||||
sha256={latestVersion.sha256}
|
||||
gpg={latestVersion.gpg}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
{speed !== null && <NetworkSpeed speed={speed} />}
|
||||
{location && suggestedMirror && (
|
||||
<SuggestedMirror
|
||||
mirror={suggestedMirror}
|
||||
userLocation={location}
|
||||
onSelect={handleMirrorSelect}
|
||||
/>
|
||||
)}
|
||||
<SystemRequirements />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
import { useState, useMemo } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { SearchBar } from '@/components/features/SearchBar';
|
||||
import { CategoryFilter } from '@/components/features/CategoryFilter';
|
||||
import { ToolCard } from '@/components/features/ToolCard';
|
||||
import { tools, categories } from '@/data/tools';
|
||||
|
||||
export default function Features() {
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [selectedCategory, setSelectedCategory] = useState('All');
|
||||
|
||||
const filteredTools = useMemo(() => {
|
||||
return tools.filter((tool) => {
|
||||
const matchesSearch = tool.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
tool.description.toLowerCase().includes(searchQuery.toLowerCase());
|
||||
const matchesCategory = selectedCategory === 'All' || tool.category === selectedCategory;
|
||||
return matchesSearch && matchesCategory;
|
||||
});
|
||||
}, [searchQuery, selectedCategory]);
|
||||
|
||||
return (
|
||||
<div className="py-12">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<h1 className="text-4xl font-bold text-gray-900">Snigdha OS Tools</h1>
|
||||
<p className="mt-4 text-lg text-gray-600">
|
||||
Explore our comprehensive collection of security and penetration testing tools
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<div className="space-y-8">
|
||||
<div className="max-w-xl mx-auto">
|
||||
<SearchBar
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<CategoryFilter
|
||||
categories={categories}
|
||||
selectedCategory={selectedCategory}
|
||||
onSelect={setSelectedCategory}
|
||||
/>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{filteredTools.map((tool) => (
|
||||
<ToolCard key={tool.id} {...tool} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
{filteredTools.length === 0 && (
|
||||
<div className="text-center py-12">
|
||||
<p className="text-gray-500">No tools found matching your criteria</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
import { useState, useMemo } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Camera } from 'lucide-react';
|
||||
import { GalleryImage } from '@/components/gallery/GalleryImage';
|
||||
import { CategoryFilter } from '@/components/gallery/CategoryFilter';
|
||||
import { galleryImages, categories } from '@/data/gallery';
|
||||
|
||||
export default function Gallery() {
|
||||
const [selectedCategory, setSelectedCategory] = useState('All');
|
||||
|
||||
const filteredImages = useMemo(() => {
|
||||
return selectedCategory === 'All'
|
||||
? galleryImages
|
||||
: galleryImages.filter((image) => image.category === selectedCategory);
|
||||
}, [selectedCategory]);
|
||||
|
||||
return (
|
||||
<div className="py-12">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="text-center mb-12"
|
||||
>
|
||||
<Camera className="h-12 w-12 text-cornflower-blue mx-auto mb-4" />
|
||||
<h1 className="text-4xl font-bold text-gray-900">Gallery</h1>
|
||||
<p className="mt-4 text-lg text-gray-600">
|
||||
Explore the visual journey of Snigdha OS
|
||||
</p>
|
||||
</motion.div>
|
||||
|
||||
<CategoryFilter
|
||||
categories={categories}
|
||||
selectedCategory={selectedCategory}
|
||||
onSelect={setSelectedCategory}
|
||||
/>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{filteredImages.map((image) => (
|
||||
<GalleryImage key={image.src} {...image} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,84 +0,0 @@
|
||||
import { Shield, Terminal, Cpu } from 'lucide-react';
|
||||
import { HeroSection } from '@/components/home/HeroSection';
|
||||
import { FeatureCard } from '@/components/home/FeatureCard';
|
||||
import { StatsSection } from '@/components/home/StatsSection';
|
||||
import { ToolsShowcase } from '@/components/home/ToolsShowcase';
|
||||
import { TestimonialCard } from '@/components/home/TestimonialCard';
|
||||
import { ComparisonSection } from '@/components/home/ComparisonSection';
|
||||
import { testimonials } from '@/data/testimonials';
|
||||
|
||||
const features = [
|
||||
{
|
||||
title: 'Advanced Security Tools',
|
||||
description: 'Access over 600 pre-installed security and penetration testing tools, ready to use out of the box.',
|
||||
icon: Shield,
|
||||
},
|
||||
{
|
||||
title: 'Powerful Terminal',
|
||||
description: 'Enhanced command-line interface with custom tools and utilities for efficient security testing.',
|
||||
icon: Terminal,
|
||||
},
|
||||
{
|
||||
title: 'Hardware Compatibility',
|
||||
description: 'Optimized for various hardware configurations with excellent driver support.',
|
||||
icon: Cpu,
|
||||
},
|
||||
];
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="bg-gray-50">
|
||||
<HeroSection />
|
||||
|
||||
<section className="py-20 bg-gradient-to-b from-gray-900 to-gray-50">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-3xl font-bold text-white sm:text-4xl">
|
||||
Powerful Features
|
||||
</h2>
|
||||
<p className="mt-4 text-lg text-gray-300">
|
||||
Everything you need for professional security testing
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{features.map((feature, index) => (
|
||||
<FeatureCard
|
||||
key={feature.title}
|
||||
{...feature}
|
||||
delay={index * 0.2}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<ToolsShowcase />
|
||||
|
||||
<ComparisonSection />
|
||||
|
||||
<section className="py-20 bg-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">What Users Say</h2>
|
||||
<p className="mt-4 text-lg text-gray-600">
|
||||
Trusted by security professionals worldwide
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
{testimonials.map((testimonial, index) => (
|
||||
<TestimonialCard
|
||||
key={testimonial.author}
|
||||
{...testimonial}
|
||||
delay={index * 0.2}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<StatsSection />
|
||||
</div>
|
||||
);
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
import { Routes, Route } from 'react-router-dom';
|
||||
import { Suspense, lazy } from 'react';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
|
||||
const HomePage = lazy(() => import('@/pages/Home'));
|
||||
const AboutPage = lazy(() => import('@/pages/About'));
|
||||
const FeaturesPage = lazy(() => import('@/pages/Features'));
|
||||
const DownloadPage = lazy(() => import('@/pages/Download'));
|
||||
const DevelopersPage = lazy(() => import('@/pages/Developers'));
|
||||
const DonatePage = lazy(() => import('@/pages/Donate'));
|
||||
const GalleryPage = lazy(() => import('@/pages/Gallery'));
|
||||
|
||||
function LoadingSpinner() {
|
||||
return (
|
||||
<div className="min-h-[50vh] flex items-center justify-center">
|
||||
<Loader2 className="h-8 w-8 animate-spin text-cornflower-blue" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function AppRoutes() {
|
||||
return (
|
||||
<Suspense fallback={<LoadingSpinner />}>
|
||||
<Routes>
|
||||
<Route path="/" element={<HomePage />} />
|
||||
<Route path="/about" element={<AboutPage />} />
|
||||
<Route path="/features" element={<FeaturesPage />} />
|
||||
<Route path="/download" element={<DownloadPage />} />
|
||||
<Route path="/developers" element={<DevelopersPage />} />
|
||||
<Route path="/donate" element={<DonatePage />} />
|
||||
<Route path="/gallery" element={<GalleryPage />} />
|
||||
</Routes>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
export interface Mirror {
|
||||
id: string;
|
||||
name: string;
|
||||
location: string;
|
||||
url: string;
|
||||
speed: number;
|
||||
}
|
||||
|
||||
export interface DownloadVersion {
|
||||
version: string;
|
||||
size: string;
|
||||
url: string;
|
||||
sha256: string;
|
||||
gpg: string;
|
||||
}
|
@@ -1,6 +0,0 @@
|
||||
export interface Sponsor {
|
||||
name: string;
|
||||
description: string;
|
||||
githubUsername: string;
|
||||
amount: number;
|
||||
}
|
10
src/vite-env.d.ts
vendored
10
src/vite-env.d.ts
vendored
@@ -1,10 +0,0 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_GITHUB_TOKEN: string
|
||||
readonly VITE_STRIPE_PUBLIC_KEY: string
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv
|
||||
}
|
@@ -1,30 +0,0 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
'cornflower-blue': '#6495ED',
|
||||
},
|
||||
animation: {
|
||||
'gradient': 'gradient 8s linear infinite',
|
||||
},
|
||||
keyframes: {
|
||||
gradient: {
|
||||
'0%, 100%': {
|
||||
'background-size': '200% 200%',
|
||||
'background-position': 'left center',
|
||||
},
|
||||
'50%': {
|
||||
'background-size': '200% 200%',
|
||||
'background-position': 'right center',
|
||||
},
|
||||
},
|
||||
},
|
||||
fontFamily: {
|
||||
'fira-sans': ['"Fira Sans"', 'sans-serif'],
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import { resolve } from 'path';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
base: '/', // Deployment to the root directory
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve(__dirname, './src'), // Alias for src
|
||||
},
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: ['lucide-react'], // Exclude specific dependency
|
||||
},
|
||||
});
|
Reference in New Issue
Block a user