upgrade
This commit is contained in:
34
frontend_example/App.tsx
Normal file
34
frontend_example/App.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
import '@radix-ui/themes/styles.css';
|
||||
import { Theme } from '@radix-ui/themes';
|
||||
import { ToastContainer } from 'react-toastify';
|
||||
import 'react-toastify/dist/ReactToastify.css';
|
||||
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
||||
|
||||
import Home from './src/pages/Home';
|
||||
import NotFound from './src/pages/NotFound';
|
||||
|
||||
const App: React.FC = () => {
|
||||
return (
|
||||
<Theme appearance="inherit" radius="large" scaling="100%">
|
||||
<Router>
|
||||
<main className="min-h-screen font-inter">
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="*" element={<NotFound />} />
|
||||
</Routes>
|
||||
<ToastContainer
|
||||
position="top-right"
|
||||
autoClose={3000}
|
||||
newestOnTop
|
||||
closeOnClick
|
||||
pauseOnHover
|
||||
theme="dark"
|
||||
/>
|
||||
</main>
|
||||
</Router>
|
||||
</Theme>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
26
frontend_example/eslint.config.js
Normal file
26
frontend_example/eslint.config.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import js from '@eslint/js'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import { defineConfig, globalIgnores } from 'eslint/config'
|
||||
import globals from 'globals'
|
||||
import tseslint from 'typescript-eslint'
|
||||
|
||||
export default defineConfig([
|
||||
globalIgnores(['dist']),
|
||||
{
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
extends: [
|
||||
js.configs.recommended,
|
||||
tseslint.configs.recommended,
|
||||
reactHooks.configs['recommended-latest'],
|
||||
reactRefresh.configs.vite,
|
||||
],
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
},
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
},
|
||||
])
|
||||
26
frontend_example/index.html
Normal file
26
frontend_example/index.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/x-icon" href="https://meku.dev/favicon.ico" />
|
||||
<title>Vontor.cz Creative Portfolio Website</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<meta name="generator" content="Meku" />
|
||||
<meta name="description" content="Vontor.cz Creative Portfolio Website Generated with Meku" />
|
||||
<meta name="author" content="Meku" />
|
||||
|
||||
<meta property="og:title" content="Vontor.cz Creative Portfolio Website" />
|
||||
<meta property="og:description" content="Vontor.cz Creative Portfolio Website Generated with Meku" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:image" content="https://meku.dev/images/meku.png" />
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:site" content="@meku_dev" />
|
||||
<meta name="twitter:image" content="https://meku.dev/images/meku.png" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
50
frontend_example/index.tsx
Normal file
50
frontend_example/index.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import App from './App.tsx';
|
||||
import './styles.css';
|
||||
|
||||
// Send logs to parent frame (like a preview system)
|
||||
function postToParent(level: string, ...args: any[]): void {
|
||||
if (window.parent !== window) {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
type: 'iframe-console',
|
||||
level,
|
||||
args,
|
||||
},
|
||||
'*'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Global error handler
|
||||
window.onerror = function (message, source, lineno, colno, error) {
|
||||
const errPayload = {
|
||||
message,
|
||||
source,
|
||||
lineno,
|
||||
colno,
|
||||
stack: error?.stack,
|
||||
};
|
||||
postToParent('error', '[Meku_Error_Caught]', errPayload);
|
||||
};
|
||||
|
||||
// Unhandled promise rejection
|
||||
window.onunhandledrejection = function (event) {
|
||||
postToParent('error', '[Meku_Error_Caught]', { reason: event.reason });
|
||||
};
|
||||
|
||||
// Patch console
|
||||
(['log', 'warn', 'info', 'error'] as const).forEach((level) => {
|
||||
const original = console[level];
|
||||
console[level] = (...args: any[]) => {
|
||||
postToParent(level, ...args);
|
||||
original(...args);
|
||||
};
|
||||
});
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
44
frontend_example/package.json
Normal file
44
frontend_example/package.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "vontor.cz-creative-portfolio-website",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"globals": "^16.4.0",
|
||||
"@hookform/resolvers": "^5.2.1",
|
||||
"@radix-ui/themes": "^3.2.1",
|
||||
"@vitejs/plugin-react": "^5.0.2",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"date-fns": "^3.6.0",
|
||||
"framer-motion": "^12.12.2",
|
||||
"lucide-react": "^0.462.0",
|
||||
"postcss": "^8.4.38",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-hook-form": "^7.53.0",
|
||||
"react-resizable-panels": "^2.1.3",
|
||||
"react-router-dom": "^6.23.0",
|
||||
"react-toastify": "^11.0.5",
|
||||
"recharts": "^2.12.7",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"vite": "^7.1.6",
|
||||
"zod": "^3.23.8",
|
||||
"@supabase/supabase-js": "^2.57.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.35.0",
|
||||
"@types/react": "^19.1.13",
|
||||
"@types/react-dom": "^19.1.9",
|
||||
"eslint": "^9.35.0",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.20",
|
||||
"typescript": "~5.8.3",
|
||||
"typescript-eslint": "^8.43.0"
|
||||
}
|
||||
}
|
||||
6
frontend_example/postcss.config.mjs
Normal file
6
frontend_example/postcss.config.mjs
Normal file
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
14
frontend_example/public/robots.txt
Normal file
14
frontend_example/public/robots.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
User-agent: Googlebot
|
||||
Allow: /
|
||||
|
||||
User-agent: Bingbot
|
||||
Allow: /
|
||||
|
||||
User-agent: Twitterbot
|
||||
Allow: /
|
||||
|
||||
User-agent: facebookexternalhit
|
||||
Allow: /
|
||||
|
||||
User-agent: *
|
||||
Allow: /
|
||||
244
frontend_example/src/components/Contact.tsx
Normal file
244
frontend_example/src/components/Contact.tsx
Normal file
@@ -0,0 +1,244 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Mail, Phone, MapPin, Send, CheckCircle, AlertCircle } from 'lucide-react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
const contactSchema = z.object({
|
||||
name: z.string().min(2, 'Name must be at least 2 characters'),
|
||||
email: z.string().email('Please enter a valid email address'),
|
||||
subject: z.string().min(5, 'Subject must be at least 5 characters'),
|
||||
message: z.string().min(10, 'Message must be at least 10 characters')
|
||||
});
|
||||
|
||||
type ContactFormData = z.infer<typeof contactSchema>;
|
||||
|
||||
const Contact: React.FC = () => {
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { errors }
|
||||
} = useForm<ContactFormData>({
|
||||
resolver: zodResolver(contactSchema)
|
||||
});
|
||||
|
||||
const onSubmit = async (data: ContactFormData) => {
|
||||
setIsSubmitting(true);
|
||||
|
||||
try {
|
||||
// Simulate form submission
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
console.log('Form submitted:', data);
|
||||
toast.success('Message sent successfully! I\'ll get back to you soon.');
|
||||
reset();
|
||||
} catch (error) {
|
||||
toast.error('Failed to send message. Please try again.');
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const contactInfo = [
|
||||
{
|
||||
icon: <Mail size={24} />,
|
||||
title: 'Email',
|
||||
value: 'hello@vontor.cz',
|
||||
link: 'mailto:hello@vontor.cz'
|
||||
},
|
||||
{
|
||||
icon: <Phone size={24} />,
|
||||
title: 'Phone',
|
||||
value: '+420 XXX XXX XXX',
|
||||
link: 'tel:+420XXXXXXXXX'
|
||||
},
|
||||
{
|
||||
icon: <MapPin size={24} />,
|
||||
title: 'Location',
|
||||
value: 'Czech Republic',
|
||||
link: null
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<section id="contact" className="py-20 bg-gradient-to-b from-slate-900 to-black">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-4xl lg:text-5xl font-bold mb-6">
|
||||
<span className="bg-gradient-to-r from-fuchsia-600 to-orange-500 bg-clip-text text-transparent">
|
||||
Get In Touch
|
||||
</span>
|
||||
</h2>
|
||||
<p className="text-xl text-gray-300 max-w-3xl mx-auto">
|
||||
Ready to bring your ideas to life? Let's discuss your next project and create something amazing together.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<div className="grid lg:grid-cols-2 gap-12">
|
||||
|
||||
{/* Contact Information */}
|
||||
<div>
|
||||
<h3 className="text-3xl font-bold text-white mb-8">Let's Connect</h3>
|
||||
<p className="text-gray-300 text-lg mb-8 leading-relaxed">
|
||||
I'm always excited to work on new projects and collaborate with creative minds.
|
||||
Whether you need a website, web application, or technical consultation,
|
||||
I'm here to help turn your vision into reality.
|
||||
</p>
|
||||
|
||||
{/* Contact Info Cards */}
|
||||
<div className="space-y-6 mb-8">
|
||||
{contactInfo.map((info, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center gap-4 p-4 bg-slate-800 rounded-xl border border-slate-700 hover:border-violet-400/50 transition-all duration-300"
|
||||
>
|
||||
<div className="p-3 bg-gradient-to-r from-fuchsia-600 to-orange-500 rounded-lg">
|
||||
<div className="text-white">
|
||||
{info.icon}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-white font-semibold mb-1">{info.title}</h4>
|
||||
{info.link ? (
|
||||
<a
|
||||
href={info.link}
|
||||
className="text-gray-300 hover:text-fuchsia-600 transition-colors duration-300"
|
||||
>
|
||||
{info.value}
|
||||
</a>
|
||||
) : (
|
||||
<span className="text-gray-300">{info.value}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Availability Status */}
|
||||
<div className="bg-slate-800 rounded-xl p-6 border border-slate-700">
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<CheckCircle className="text-green-500" size={24} />
|
||||
<h4 className="text-white font-semibold">Currently Available</h4>
|
||||
</div>
|
||||
<p className="text-gray-300 text-sm">
|
||||
I'm currently accepting new projects and collaborations.
|
||||
Typical response time is within 24 hours.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Contact Form */}
|
||||
<div className="bg-slate-800 rounded-2xl p-8 border border-slate-700">
|
||||
<h3 className="text-2xl font-bold text-white mb-6">Send a Message</h3>
|
||||
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label htmlFor="name" className="block text-white font-medium mb-2">
|
||||
Name *
|
||||
</label>
|
||||
<input
|
||||
{...register('name')}
|
||||
type="text"
|
||||
id="name"
|
||||
className="w-full px-4 py-3 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-gray-400 focus:border-violet-400 focus:outline-none transition-colors duration-300"
|
||||
placeholder="Your name"
|
||||
/>
|
||||
{errors.name && (
|
||||
<p className="text-red-400 text-sm mt-1 flex items-center gap-1">
|
||||
<AlertCircle size={16} />
|
||||
{errors.name.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="email" className="block text-white font-medium mb-2">
|
||||
Email *
|
||||
</label>
|
||||
<input
|
||||
{...register('email')}
|
||||
type="email"
|
||||
id="email"
|
||||
className="w-full px-4 py-3 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-gray-400 focus:border-violet-400 focus:outline-none transition-colors duration-300"
|
||||
placeholder="your@email.com"
|
||||
/>
|
||||
{errors.email && (
|
||||
<p className="text-red-400 text-sm mt-1 flex items-center gap-1">
|
||||
<AlertCircle size={16} />
|
||||
{errors.email.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="subject" className="block text-white font-medium mb-2">
|
||||
Subject *
|
||||
</label>
|
||||
<input
|
||||
{...register('subject')}
|
||||
type="text"
|
||||
id="subject"
|
||||
className="w-full px-4 py-3 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-gray-400 focus:border-violet-400 focus:outline-none transition-colors duration-300"
|
||||
placeholder="Project inquiry, collaboration, etc."
|
||||
/>
|
||||
{errors.subject && (
|
||||
<p className="text-red-400 text-sm mt-1 flex items-center gap-1">
|
||||
<AlertCircle size={16} />
|
||||
{errors.subject.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="message" className="block text-white font-medium mb-2">
|
||||
Message *
|
||||
</label>
|
||||
<textarea
|
||||
{...register('message')}
|
||||
id="message"
|
||||
rows={6}
|
||||
className="w-full px-4 py-3 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-gray-400 focus:border-violet-400 focus:outline-none transition-colors duration-300 resize-vertical"
|
||||
placeholder="Tell me about your project, timeline, budget, and any specific requirements..."
|
||||
/>
|
||||
{errors.message && (
|
||||
<p className="text-red-400 text-sm mt-1 flex items-center gap-1">
|
||||
<AlertCircle size={16} />
|
||||
{errors.message.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="w-full flex items-center justify-center gap-3 px-8 py-4 bg-gradient-to-r from-fuchsia-600 to-orange-500 text-white font-semibold rounded-lg hover:shadow-lg hover:shadow-fuchsia-600/25 transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<>
|
||||
<div className="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin"></div>
|
||||
Sending...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Send size={20} />
|
||||
Send Message
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Contact;
|
||||
178
frontend_example/src/components/DonateShop.tsx
Normal file
178
frontend_example/src/components/DonateShop.tsx
Normal file
@@ -0,0 +1,178 @@
|
||||
import React from 'react';
|
||||
import { Coffee, Zap, Battery, Heart, Gift } from 'lucide-react';
|
||||
|
||||
interface DonationTier {
|
||||
id: string;
|
||||
name: string;
|
||||
price: string;
|
||||
description: string;
|
||||
icon: React.ReactNode;
|
||||
features: string[];
|
||||
popular?: boolean;
|
||||
}
|
||||
|
||||
const DonateShop: React.FC = () => {
|
||||
const donationTiers: DonationTier[] = [
|
||||
{
|
||||
id: 'coffee',
|
||||
name: 'Buy Me a Coffee',
|
||||
price: '$5',
|
||||
description: 'Fuel my coding sessions with caffeine',
|
||||
icon: <Coffee size={32} />,
|
||||
features: [
|
||||
'Support ongoing projects',
|
||||
'Keep me caffeinated',
|
||||
'Thank you message',
|
||||
'Good karma points'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'gpu',
|
||||
name: 'GPU Upgrade Fund',
|
||||
price: '$50',
|
||||
description: 'Help upgrade my development setup',
|
||||
icon: <Zap size={32} />,
|
||||
features: [
|
||||
'Better performance',
|
||||
'Faster rendering',
|
||||
'Enhanced productivity',
|
||||
'Priority support',
|
||||
'Exclusive updates'
|
||||
],
|
||||
popular: true
|
||||
},
|
||||
{
|
||||
id: 'drone',
|
||||
name: 'Drone Battery Pack',
|
||||
price: '$25',
|
||||
description: 'Extended flight time for aerial photography',
|
||||
icon: <Battery size={32} />,
|
||||
features: [
|
||||
'Longer flight sessions',
|
||||
'More aerial content',
|
||||
'Better coverage',
|
||||
'Behind-the-scenes access'
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const handleDonate = (tierId: string) => {
|
||||
// Placeholder for donation handling
|
||||
console.log(`Donate to tier: ${tierId}`);
|
||||
// In a real implementation, this would integrate with a payment processor
|
||||
};
|
||||
|
||||
return (
|
||||
<section id="donate" className="py-20 bg-gradient-to-b from-slate-800 to-slate-900">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="text-center mb-16">
|
||||
<div className="flex items-center justify-center gap-3 mb-6">
|
||||
<Heart className="text-fuchsia-600" size={40} />
|
||||
<h2 className="text-4xl lg:text-5xl font-bold">
|
||||
<span className="bg-gradient-to-r from-fuchsia-600 to-orange-500 bg-clip-text text-transparent">
|
||||
Support My Work
|
||||
</span>
|
||||
</h2>
|
||||
</div>
|
||||
<p className="text-xl text-gray-300 max-w-3xl mx-auto">
|
||||
Your support helps me create better content, upgrade equipment, and continue
|
||||
developing innovative projects. Every contribution makes a difference!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Donation Tiers */}
|
||||
<div className="grid md:grid-cols-3 gap-8 max-w-6xl mx-auto mb-16">
|
||||
{donationTiers.map((tier) => (
|
||||
<div
|
||||
key={tier.id}
|
||||
className={`relative bg-slate-800 rounded-2xl p-8 shadow-xl border transition-all duration-300 hover:transform hover:scale-105 ${
|
||||
tier.popular
|
||||
? 'border-fuchsia-600 shadow-fuchsia-600/20'
|
||||
: 'border-slate-700 hover:border-violet-400/50'
|
||||
}`}
|
||||
>
|
||||
{tier.popular && (
|
||||
<div className="absolute -top-4 left-1/2 transform -translate-x-1/2">
|
||||
<span className="bg-gradient-to-r from-fuchsia-600 to-orange-500 text-white px-4 py-2 rounded-full text-sm font-semibold">
|
||||
Most Popular
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="text-center mb-6">
|
||||
<div className={`inline-flex p-4 rounded-2xl mb-4 ${
|
||||
tier.popular
|
||||
? 'bg-gradient-to-r from-fuchsia-600 to-orange-500'
|
||||
: 'bg-slate-700'
|
||||
}`}>
|
||||
<div className="text-white">
|
||||
{tier.icon}
|
||||
</div>
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold text-white mb-2">{tier.name}</h3>
|
||||
<div className="text-4xl font-bold mb-2">
|
||||
<span className="bg-gradient-to-r from-fuchsia-600 to-orange-500 bg-clip-text text-transparent">
|
||||
{tier.price}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-gray-400">{tier.description}</p>
|
||||
</div>
|
||||
|
||||
<ul className="space-y-3 mb-8">
|
||||
{tier.features.map((feature, index) => (
|
||||
<li key={index} className="flex items-center gap-3 text-gray-300">
|
||||
<div className="w-2 h-2 bg-violet-400 rounded-full flex-shrink-0"></div>
|
||||
{feature}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<button
|
||||
onClick={() => handleDonate(tier.id)}
|
||||
className={`w-full py-4 rounded-xl font-semibold transition-all duration-300 ${
|
||||
tier.popular
|
||||
? 'bg-gradient-to-r from-fuchsia-600 to-orange-500 text-white hover:shadow-lg hover:shadow-fuchsia-600/25'
|
||||
: 'bg-slate-700 text-white hover:bg-slate-600 border border-slate-600 hover:border-violet-400'
|
||||
}`}
|
||||
>
|
||||
Donate {tier.price}
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Custom Amount Section */}
|
||||
<div className="max-w-2xl mx-auto">
|
||||
<div className="bg-slate-800 rounded-2xl p-8 border border-slate-700 text-center">
|
||||
<Gift className="text-violet-400 mx-auto mb-4" size={48} />
|
||||
<h3 className="text-2xl font-bold text-white mb-4">Custom Amount</h3>
|
||||
<p className="text-gray-300 mb-6">
|
||||
Want to contribute a different amount? You can choose any amount that feels right for you.
|
||||
</p>
|
||||
<div className="flex gap-4 max-w-md mx-auto">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="Enter amount"
|
||||
className="flex-1 px-4 py-3 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-gray-400 focus:border-violet-400 focus:outline-none"
|
||||
/>
|
||||
<button className="px-8 py-3 bg-gradient-to-r from-fuchsia-600 to-orange-500 text-white font-semibold rounded-lg hover:shadow-lg hover:shadow-fuchsia-600/25 transition-all duration-300">
|
||||
Donate
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Thank You Message */}
|
||||
<div className="text-center mt-12">
|
||||
<p className="text-gray-400 max-w-2xl mx-auto">
|
||||
Thank you for considering supporting my work! Your contributions help me continue creating
|
||||
innovative projects and sharing knowledge with the community. Every donation, no matter the size,
|
||||
is deeply appreciated. ❤️
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default DonateShop;
|
||||
160
frontend_example/src/components/Footer.tsx
Normal file
160
frontend_example/src/components/Footer.tsx
Normal file
@@ -0,0 +1,160 @@
|
||||
import React from 'react';
|
||||
import { Instagram, Twitter, Youtube, Github, Linkedin, Gamepad2, Mail, MapPin, Phone } from 'lucide-react';
|
||||
|
||||
const Footer: React.FC = () => {
|
||||
const socialLinks = [
|
||||
{ name: 'Instagram', icon: <Instagram size={20} />, url: 'https://instagram.com', color: 'hover:text-pink-500' },
|
||||
{ name: 'Twitter/X', icon: <Twitter size={20} />, url: 'https://twitter.com', color: 'hover:text-blue-400' },
|
||||
{ name: 'YouTube', icon: <Youtube size={20} />, url: 'https://youtube.com', color: 'hover:text-red-500' },
|
||||
{ name: 'GitHub', icon: <Github size={20} />, url: 'https://github.com', color: 'hover:text-gray-300' },
|
||||
{ name: 'LinkedIn', icon: <Linkedin size={20} />, url: 'https://linkedin.com', color: 'hover:text-blue-600' },
|
||||
{ name: 'Steam', icon: <Gamepad2 size={20} />, url: 'https://steamcommunity.com', color: 'hover:text-blue-500' }
|
||||
];
|
||||
|
||||
const quickLinks = [
|
||||
{ name: 'Home', href: '#home' },
|
||||
{ name: 'Portfolio', href: '#portfolio' },
|
||||
{ name: 'Skills', href: '#skills' },
|
||||
{ name: 'Donate', href: '#donate' },
|
||||
{ name: 'Contact', href: '#contact' }
|
||||
];
|
||||
|
||||
const legalLinks = [
|
||||
{ name: 'Privacy Policy', href: '#' },
|
||||
{ name: 'Terms of Service', href: '#' },
|
||||
{ name: 'Cookie Policy', href: '#' }
|
||||
];
|
||||
|
||||
const scrollToSection = (href: string) => {
|
||||
const element = document.querySelector(href);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<footer className="bg-slate-900 border-t border-slate-800">
|
||||
<div className="container mx-auto px-4 py-16">
|
||||
<div className="grid lg:grid-cols-4 md:grid-cols-2 gap-8">
|
||||
|
||||
{/* Brand Section */}
|
||||
<div className="lg:col-span-1">
|
||||
<div className="text-3xl font-bold bg-gradient-to-r from-fuchsia-600 to-orange-500 bg-clip-text text-transparent mb-4">
|
||||
Vontor.cz
|
||||
</div>
|
||||
<p className="text-gray-400 mb-6 leading-relaxed">
|
||||
Creative tech solutions and innovative design by Bruno Vontor.
|
||||
Bringing ideas to life through code, creativity, and cutting-edge technology.
|
||||
</p>
|
||||
|
||||
{/* Social Media Links */}
|
||||
<div className="flex flex-wrap gap-4">
|
||||
{socialLinks.map((social) => (
|
||||
<a
|
||||
key={social.name}
|
||||
href={social.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={`p-3 bg-slate-800 rounded-lg border border-slate-700 text-gray-400 transition-all duration-300 hover:border-violet-400/50 hover:transform hover:scale-110 ${social.color}`}
|
||||
aria-label={social.name}
|
||||
>
|
||||
{social.icon}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Quick Links */}
|
||||
<div>
|
||||
<h3 className="text-xl font-semibold text-white mb-6">Quick Links</h3>
|
||||
<ul className="space-y-3">
|
||||
{quickLinks.map((link) => (
|
||||
<li key={link.name}>
|
||||
<button
|
||||
onClick={() => scrollToSection(link.href)}
|
||||
className="text-gray-400 hover:text-fuchsia-600 transition-colors duration-300"
|
||||
>
|
||||
{link.name}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Contact Info */}
|
||||
<div>
|
||||
<h3 className="text-xl font-semibold text-white mb-6">Contact Info</h3>
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-3 text-gray-400">
|
||||
<Mail size={18} className="text-fuchsia-600" />
|
||||
<span>hello@vontor.cz</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 text-gray-400">
|
||||
<MapPin size={18} className="text-fuchsia-600" />
|
||||
<span>Czech Republic</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 text-gray-400">
|
||||
<Phone size={18} className="text-fuchsia-600" />
|
||||
<span>Available on request</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Newsletter */}
|
||||
<div>
|
||||
<h3 className="text-xl font-semibold text-white mb-6">Stay Updated</h3>
|
||||
<p className="text-gray-400 mb-4">
|
||||
Subscribe to get notified about new projects and updates.
|
||||
</p>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Enter your email"
|
||||
className="flex-1 px-4 py-3 bg-slate-800 border border-slate-700 rounded-lg text-white placeholder-gray-400 focus:border-violet-400 focus:outline-none"
|
||||
/>
|
||||
<button className="px-6 py-3 bg-gradient-to-r from-fuchsia-600 to-orange-500 text-white font-semibold rounded-lg hover:shadow-lg hover:shadow-fuchsia-600/25 transition-all duration-300">
|
||||
Subscribe
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom Section */}
|
||||
<div className="border-t border-slate-800 mt-12 pt-8">
|
||||
<div className="flex flex-col md:flex-row justify-between items-center gap-4">
|
||||
|
||||
{/* Copyright */}
|
||||
<div className="text-gray-400 text-center md:text-left">
|
||||
<p>
|
||||
© 2025 Vontor.cz - All rights reserved. Built with ❤️ by{' '}
|
||||
<a
|
||||
href="https://meku.dev"
|
||||
target="_blank"
|
||||
rel="nofollow noopener noreferrer"
|
||||
className="text-fuchsia-600 hover:text-orange-500 transition-colors duration-300"
|
||||
>
|
||||
Meku.dev
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Legal Links */}
|
||||
<div className="flex flex-wrap gap-6">
|
||||
{legalLinks.map((link) => (
|
||||
<a
|
||||
key={link.name}
|
||||
href={link.href}
|
||||
className="text-gray-400 hover:text-fuchsia-600 transition-colors duration-300 text-sm"
|
||||
>
|
||||
{link.name}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Footer;
|
||||
84
frontend_example/src/components/Header.tsx
Normal file
84
frontend_example/src/components/Header.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Menu, X } from 'lucide-react';
|
||||
|
||||
const Header: React.FC = () => {
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||
const [isScrolled, setIsScrolled] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
setIsScrolled(window.scrollY > 50);
|
||||
};
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
return () => window.removeEventListener('scroll', handleScroll);
|
||||
}, []);
|
||||
|
||||
const navItems = [
|
||||
{ name: 'Home', href: '#home' },
|
||||
{ name: 'Portfolio', href: '#portfolio' },
|
||||
{ name: 'Skills', href: '#skills' },
|
||||
{ name: 'Donate/Shop', href: '#donate' },
|
||||
{ name: 'Contact', href: '#contact' }
|
||||
];
|
||||
|
||||
const scrollToSection = (href: string) => {
|
||||
const element = document.querySelector(href);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
setIsMenuOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<header className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
|
||||
isScrolled ? 'bg-slate-800/95 backdrop-blur-md shadow-lg' : 'bg-transparent'
|
||||
}`}>
|
||||
<nav className="container mx-auto px-4 py-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="text-2xl font-bold bg-gradient-to-r from-fuchsia-600 to-orange-500 bg-clip-text text-transparent">
|
||||
Vontor.cz
|
||||
</div>
|
||||
|
||||
{/* Desktop Navigation */}
|
||||
<div className="hidden md:flex space-x-8">
|
||||
{navItems.map((item) => (
|
||||
<button
|
||||
key={item.name}
|
||||
onClick={() => scrollToSection(item.href)}
|
||||
className="text-white hover:text-fuchsia-600 transition-colors duration-300 font-medium"
|
||||
>
|
||||
{item.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu Button */}
|
||||
<button
|
||||
className="md:hidden text-white hover:text-fuchsia-600 transition-colors"
|
||||
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
{isMenuOpen ? <X size={24} /> : <Menu size={24} />}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Mobile Navigation */}
|
||||
{isMenuOpen && (
|
||||
<div className="md:hidden mt-4 py-4 bg-slate-800/95 rounded-lg backdrop-blur-md">
|
||||
{navItems.map((item) => (
|
||||
<button
|
||||
key={item.name}
|
||||
onClick={() => scrollToSection(item.href)}
|
||||
className="block w-full text-left px-4 py-2 text-white hover:text-fuchsia-600 hover:bg-slate-700/50 transition-all duration-300"
|
||||
>
|
||||
{item.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</nav>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
144
frontend_example/src/components/Hero.tsx
Normal file
144
frontend_example/src/components/Hero.tsx
Normal file
@@ -0,0 +1,144 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { ChevronLeft, ChevronRight, Play } from 'lucide-react';
|
||||
|
||||
const Hero: React.FC = () => {
|
||||
const [currentSlide, setCurrentSlide] = useState(0);
|
||||
|
||||
const slides = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Creative Tech Solutions",
|
||||
subtitle: "Innovative development meets stunning design",
|
||||
videoId: "dQw4w9WgXcQ" // Placeholder YouTube ID
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Drone Photography",
|
||||
subtitle: "Capturing perspectives from above",
|
||||
videoId: "dQw4w9WgXcQ" // Placeholder YouTube ID
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Full-Stack Development",
|
||||
subtitle: "Building the future, one line at a time",
|
||||
videoId: "dQw4w9WgXcQ" // Placeholder YouTube ID
|
||||
}
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
setCurrentSlide((prev) => (prev + 1) % slides.length);
|
||||
}, 8000);
|
||||
return () => clearInterval(timer);
|
||||
}, [slides.length]);
|
||||
|
||||
const nextSlide = () => {
|
||||
setCurrentSlide((prev) => (prev + 1) % slides.length);
|
||||
};
|
||||
|
||||
const prevSlide = () => {
|
||||
setCurrentSlide((prev) => (prev - 1 + slides.length) % slides.length);
|
||||
};
|
||||
|
||||
return (
|
||||
<section id="home" className="relative min-h-screen flex items-center justify-center overflow-hidden">
|
||||
{/* Background Gradient */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-slate-800 via-slate-900 to-black"></div>
|
||||
|
||||
{/* Animated Background Elements */}
|
||||
<div className="absolute inset-0">
|
||||
<div className="absolute top-1/4 left-1/4 w-64 h-64 bg-fuchsia-600/10 rounded-full blur-3xl animate-pulse"></div>
|
||||
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-orange-500/10 rounded-full blur-3xl animate-pulse delay-1000"></div>
|
||||
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-80 h-80 bg-violet-400/10 rounded-full blur-3xl animate-pulse delay-2000"></div>
|
||||
</div>
|
||||
|
||||
{/* Content Container */}
|
||||
<div className="relative z-10 container mx-auto px-4 py-20">
|
||||
<div className="grid lg:grid-cols-2 gap-12 items-center">
|
||||
|
||||
{/* Text Content */}
|
||||
<div className="text-center lg:text-left">
|
||||
<h1 className="text-5xl lg:text-7xl font-bold mb-6 leading-tight">
|
||||
<span className="bg-gradient-to-r from-fuchsia-600 via-orange-500 to-violet-400 bg-clip-text text-transparent">
|
||||
Welcome to
|
||||
</span>
|
||||
<br />
|
||||
<span className="text-white">Vontor.cz</span>
|
||||
</h1>
|
||||
<p className="text-xl lg:text-2xl text-gray-300 mb-8 leading-relaxed">
|
||||
Creative Tech & Design by <span className="text-fuchsia-600 font-semibold">Bruno Vontor</span>
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center lg:justify-start">
|
||||
<button
|
||||
onClick={() => document.querySelector('#portfolio')?.scrollIntoView({ behavior: 'smooth' })}
|
||||
className="px-8 py-4 bg-gradient-to-r from-fuchsia-600 to-orange-500 text-white font-semibold rounded-lg hover:shadow-lg hover:shadow-fuchsia-600/25 transition-all duration-300 transform hover:scale-105"
|
||||
>
|
||||
View Portfolio
|
||||
</button>
|
||||
<button
|
||||
onClick={() => document.querySelector('#contact')?.scrollIntoView({ behavior: 'smooth' })}
|
||||
className="px-8 py-4 border-2 border-violet-400 text-violet-400 font-semibold rounded-lg hover:bg-violet-400 hover:text-white transition-all duration-300"
|
||||
>
|
||||
Get In Touch
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Video Carousel */}
|
||||
<div className="relative">
|
||||
<div className="relative aspect-video bg-slate-800 rounded-xl overflow-hidden shadow-2xl">
|
||||
<iframe
|
||||
src={`https://www.youtube.com/embed/${slides[currentSlide].videoId}?autoplay=1&mute=1&loop=1&playlist=${slides[currentSlide].videoId}`}
|
||||
title={slides[currentSlide].title}
|
||||
className="w-full h-full"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
|
||||
{/* Overlay */}
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent pointer-events-none"></div>
|
||||
|
||||
{/* Slide Info */}
|
||||
<div className="absolute bottom-4 left-4 text-white">
|
||||
<h3 className="text-lg font-semibold">{slides[currentSlide].title}</h3>
|
||||
<p className="text-sm text-gray-300">{slides[currentSlide].subtitle}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Navigation Buttons */}
|
||||
<button
|
||||
onClick={prevSlide}
|
||||
className="absolute left-4 top-1/2 transform -translate-y-1/2 bg-black/50 hover:bg-black/70 text-white p-2 rounded-full transition-all duration-300"
|
||||
aria-label="Previous slide"
|
||||
>
|
||||
<ChevronLeft size={24} />
|
||||
</button>
|
||||
<button
|
||||
onClick={nextSlide}
|
||||
className="absolute right-4 top-1/2 transform -translate-y-1/2 bg-black/50 hover:bg-black/70 text-white p-2 rounded-full transition-all duration-300"
|
||||
aria-label="Next slide"
|
||||
>
|
||||
<ChevronRight size={24} />
|
||||
</button>
|
||||
|
||||
{/* Slide Indicators */}
|
||||
<div className="flex justify-center mt-4 space-x-2">
|
||||
{slides.map((_, index) => (
|
||||
<button
|
||||
key={index}
|
||||
onClick={() => setCurrentSlide(index)}
|
||||
className={`w-3 h-3 rounded-full transition-all duration-300 ${
|
||||
index === currentSlide ? 'bg-fuchsia-600' : 'bg-gray-600 hover:bg-gray-400'
|
||||
}`}
|
||||
aria-label={`Go to slide ${index + 1}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Hero;
|
||||
171
frontend_example/src/components/HostingSecurity.tsx
Normal file
171
frontend_example/src/components/HostingSecurity.tsx
Normal file
@@ -0,0 +1,171 @@
|
||||
import React from 'react';
|
||||
import { Shield, Server, Lock, Zap, CheckCircle, Globe } from 'lucide-react';
|
||||
|
||||
const HostingSecurity: React.FC = () => {
|
||||
const benefits = [
|
||||
{
|
||||
icon: <Shield size={24} />,
|
||||
title: 'Enhanced Security',
|
||||
description: 'Full control over security configurations, custom firewalls, and regular security updates'
|
||||
},
|
||||
{
|
||||
icon: <Zap size={24} />,
|
||||
title: 'Better Performance',
|
||||
description: 'Optimized server configurations, custom caching, and dedicated resources for faster loading'
|
||||
},
|
||||
{
|
||||
icon: <Lock size={24} />,
|
||||
title: 'Data Privacy',
|
||||
description: 'Complete ownership of your data with no third-party access or data mining concerns'
|
||||
},
|
||||
{
|
||||
icon: <Server size={24} />,
|
||||
title: 'Cost Effective',
|
||||
description: 'Lower long-term costs compared to managed hosting services with better resource allocation'
|
||||
},
|
||||
{
|
||||
icon: <Globe size={24} />,
|
||||
title: 'Custom Domains',
|
||||
description: 'Easy setup of custom domains, subdomains, and SSL certificates for professional presence'
|
||||
},
|
||||
{
|
||||
icon: <CheckCircle size={24} />,
|
||||
title: 'Full Control',
|
||||
description: 'Complete administrative access to configure, customize, and scale your hosting environment'
|
||||
}
|
||||
];
|
||||
|
||||
const techStack = [
|
||||
'Ubuntu Server 22.04 LTS',
|
||||
'Nginx Web Server',
|
||||
'Docker Containerization',
|
||||
'SSL/TLS Encryption',
|
||||
'Automated Backups',
|
||||
'Monitoring & Alerts',
|
||||
'Fail2ban Security',
|
||||
'UFW Firewall'
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="py-20 bg-slate-800">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-4xl lg:text-5xl font-bold mb-6">
|
||||
<span className="bg-gradient-to-r from-fuchsia-600 to-orange-500 bg-clip-text text-transparent">
|
||||
Self-Hosting & Security
|
||||
</span>
|
||||
</h2>
|
||||
<p className="text-xl text-gray-300 max-w-3xl mx-auto">
|
||||
Why I choose self-hosting for better control, security, and performance
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="max-w-6xl mx-auto">
|
||||
{/* Main Info Panel */}
|
||||
<div className="bg-slate-900 rounded-2xl p-8 mb-12 border border-slate-700">
|
||||
<div className="grid lg:grid-cols-2 gap-12 items-center">
|
||||
<div>
|
||||
<h3 className="text-3xl font-bold text-white mb-6">
|
||||
Why Self-Hosting Matters
|
||||
</h3>
|
||||
<p className="text-gray-300 text-lg leading-relaxed mb-6">
|
||||
Self-hosting provides unparalleled control over your digital infrastructure.
|
||||
By managing my own servers, I ensure optimal performance, enhanced security,
|
||||
and complete data ownership while reducing long-term costs.
|
||||
</p>
|
||||
<p className="text-gray-300 leading-relaxed">
|
||||
This approach allows for custom configurations, better resource allocation,
|
||||
and the flexibility to scale applications according to specific needs without
|
||||
vendor lock-in or arbitrary limitations.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="relative">
|
||||
<div className="bg-slate-800 rounded-xl p-6 border border-slate-600">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<Server className="text-fuchsia-600" size={32} />
|
||||
<h4 className="text-xl font-semibold text-white">Server Status</h4>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-gray-300">Uptime</span>
|
||||
<span className="text-green-500 font-semibold">99.9%</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-gray-300">Response Time</span>
|
||||
<span className="text-green-500 font-semibold">< 200ms</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-gray-300">SSL Grade</span>
|
||||
<span className="text-green-500 font-semibold">A+</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-gray-300">Security Score</span>
|
||||
<span className="text-green-500 font-semibold">95/100</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 pt-4 border-t border-slate-600">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-3 h-3 bg-green-500 rounded-full animate-pulse"></div>
|
||||
<span className="text-green-500 text-sm font-medium">All Systems Operational</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Benefits Grid */}
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
|
||||
{benefits.map((benefit, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="bg-slate-800 rounded-xl p-6 border border-slate-700 hover:border-violet-400/50 transition-all duration-300 hover:transform hover:scale-105"
|
||||
>
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="p-2 bg-gradient-to-r from-fuchsia-600 to-orange-500 rounded-lg">
|
||||
<div className="text-white">
|
||||
{benefit.icon}
|
||||
</div>
|
||||
</div>
|
||||
<h4 className="text-lg font-semibold text-white">{benefit.title}</h4>
|
||||
</div>
|
||||
<p className="text-gray-300 text-sm leading-relaxed">
|
||||
{benefit.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Tech Stack */}
|
||||
<div className="bg-slate-900 rounded-2xl p-8 border border-slate-700">
|
||||
<h3 className="text-2xl font-bold text-white mb-6 text-center">
|
||||
Technology Stack
|
||||
</h3>
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{techStack.map((tech, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="bg-slate-800 rounded-lg p-4 border border-slate-600 text-center hover:border-violet-400/50 transition-all duration-300"
|
||||
>
|
||||
<span className="text-gray-300 font-medium">{tech}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-8 text-center">
|
||||
<p className="text-gray-400 max-w-2xl mx-auto">
|
||||
This robust technology stack ensures reliable, secure, and high-performance hosting
|
||||
for all projects while maintaining full control over the infrastructure.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default HostingSecurity;
|
||||
242
frontend_example/src/components/Portfolio.tsx
Normal file
242
frontend_example/src/components/Portfolio.tsx
Normal file
@@ -0,0 +1,242 @@
|
||||
import React, { useState } from 'react';
|
||||
import { ExternalLink, Github, X } from 'lucide-react';
|
||||
|
||||
interface Project {
|
||||
id: number;
|
||||
title: string;
|
||||
description: string;
|
||||
image: string;
|
||||
technologies: string[];
|
||||
liveUrl?: string;
|
||||
githubUrl?: string;
|
||||
category: string;
|
||||
}
|
||||
|
||||
const Portfolio: React.FC = () => {
|
||||
const [selectedProject, setSelectedProject] = useState<Project | null>(null);
|
||||
const [filter, setFilter] = useState('all');
|
||||
|
||||
const projects: Project[] = [
|
||||
{
|
||||
id: 1,
|
||||
title: "E-Commerce Platform",
|
||||
description: "Full-stack e-commerce solution with React, Node.js, and PostgreSQL. Features include user authentication, payment processing, inventory management, and admin dashboard.",
|
||||
image: "https://images.unsplash.com/photo-1556742049-0cfed4f6a45d?w=800&h=600&fit=crop",
|
||||
technologies: ["React", "Node.js", "PostgreSQL", "Stripe"],
|
||||
liveUrl: "https://example.com",
|
||||
githubUrl: "https://github.com",
|
||||
category: "web"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Drone Photography Portfolio",
|
||||
description: "Stunning aerial photography showcase with interactive gallery, location mapping, and client booking system. Built with modern web technologies.",
|
||||
image: "https://images.unsplash.com/photo-1473968512647-3e447244af8f?w=800&h=600&fit=crop",
|
||||
technologies: ["React", "TypeScript", "Mapbox", "Framer Motion"],
|
||||
liveUrl: "https://example.com",
|
||||
githubUrl: "https://github.com",
|
||||
category: "photography"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Trading Dashboard",
|
||||
description: "Real-time trading analytics dashboard with live data visualization, portfolio tracking, and automated trading signals integration.",
|
||||
image: "https://images.unsplash.com/photo-1611974789855-9c2a0a7236a3?w=800&h=600&fit=crop",
|
||||
technologies: ["React", "D3.js", "WebSocket", "Trading212 API"],
|
||||
liveUrl: "https://example.com",
|
||||
githubUrl: "https://github.com",
|
||||
category: "web"
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "Mobile App Design",
|
||||
description: "Modern mobile application UI/UX design with focus on user experience, accessibility, and brand consistency across iOS and Android platforms.",
|
||||
image: "https://images.unsplash.com/photo-1512941937669-90a1b58e7e9c?w=800&h=600&fit=crop",
|
||||
technologies: ["Figma", "React Native", "TypeScript", "Expo"],
|
||||
liveUrl: "https://example.com",
|
||||
category: "design"
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: "DevOps Infrastructure",
|
||||
description: "Scalable cloud infrastructure setup with Docker containers, CI/CD pipelines, monitoring, and automated deployment processes.",
|
||||
image: "https://images.unsplash.com/photo-1558494949-ef010cbdcc31?w=800&h=600&fit=crop",
|
||||
technologies: ["Docker", "Kubernetes", "AWS", "GitHub Actions"],
|
||||
githubUrl: "https://github.com",
|
||||
category: "devops"
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: "AI-Powered Analytics",
|
||||
description: "Machine learning application for data analysis and prediction with interactive visualizations and real-time processing capabilities.",
|
||||
image: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=800&h=600&fit=crop",
|
||||
technologies: ["Python", "TensorFlow", "React", "FastAPI"],
|
||||
liveUrl: "https://example.com",
|
||||
githubUrl: "https://github.com",
|
||||
category: "web"
|
||||
}
|
||||
];
|
||||
|
||||
const categories = [
|
||||
{ id: 'all', name: 'All Projects' },
|
||||
{ id: 'web', name: 'Web Development' },
|
||||
{ id: 'photography', name: 'Photography' },
|
||||
{ id: 'design', name: 'Design' },
|
||||
{ id: 'devops', name: 'DevOps' }
|
||||
];
|
||||
|
||||
const filteredProjects = filter === 'all'
|
||||
? projects
|
||||
: projects.filter(project => project.category === filter);
|
||||
|
||||
return (
|
||||
<section id="portfolio" className="py-20 bg-gradient-to-b from-slate-900 to-slate-800">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-4xl lg:text-5xl font-bold mb-6">
|
||||
<span className="bg-gradient-to-r from-fuchsia-600 to-orange-500 bg-clip-text text-transparent">
|
||||
Portfolio
|
||||
</span>
|
||||
</h2>
|
||||
<p className="text-xl text-gray-300 max-w-3xl mx-auto">
|
||||
Explore my latest projects showcasing creative solutions in web development,
|
||||
design, and technology innovation.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Filter Buttons */}
|
||||
<div className="flex flex-wrap justify-center gap-4 mb-12">
|
||||
{categories.map((category) => (
|
||||
<button
|
||||
key={category.id}
|
||||
onClick={() => setFilter(category.id)}
|
||||
className={`px-6 py-3 rounded-lg font-medium transition-all duration-300 ${
|
||||
filter === category.id
|
||||
? 'bg-gradient-to-r from-fuchsia-600 to-orange-500 text-white shadow-lg'
|
||||
: 'bg-slate-700 text-gray-300 hover:bg-slate-600 hover:text-white'
|
||||
}`}
|
||||
>
|
||||
{category.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Projects Grid */}
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{filteredProjects.map((project) => (
|
||||
<div
|
||||
key={project.id}
|
||||
className="group bg-slate-800 rounded-xl overflow-hidden shadow-lg hover:shadow-2xl hover:shadow-fuchsia-600/10 transition-all duration-300 transform hover:scale-105 cursor-pointer"
|
||||
onClick={() => setSelectedProject(project)}
|
||||
>
|
||||
<div className="relative overflow-hidden">
|
||||
<img
|
||||
src={project.image}
|
||||
alt={project.title}
|
||||
className="w-full h-48 object-cover group-hover:scale-110 transition-transform duration-300"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
||||
</div>
|
||||
|
||||
<div className="p-6">
|
||||
<h3 className="text-xl font-semibold text-white mb-2 group-hover:text-fuchsia-600 transition-colors">
|
||||
{project.title}
|
||||
</h3>
|
||||
<p className="text-gray-400 text-sm mb-4 line-clamp-2">
|
||||
{project.description}
|
||||
</p>
|
||||
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{project.technologies.slice(0, 3).map((tech) => (
|
||||
<span
|
||||
key={tech}
|
||||
className="px-3 py-1 bg-slate-700 text-violet-400 text-xs rounded-full"
|
||||
>
|
||||
{tech}
|
||||
</span>
|
||||
))}
|
||||
{project.technologies.length > 3 && (
|
||||
<span className="px-3 py-1 bg-slate-700 text-gray-400 text-xs rounded-full">
|
||||
+{project.technologies.length - 3} more
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Project Modal */}
|
||||
{selectedProject && (
|
||||
<div className="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 flex items-center justify-center p-4">
|
||||
<div className="bg-slate-800 rounded-xl max-w-4xl w-full max-h-[90vh] overflow-y-auto">
|
||||
<div className="relative">
|
||||
<img
|
||||
src={selectedProject.image}
|
||||
alt={selectedProject.title}
|
||||
className="w-full h-64 lg:h-80 object-cover"
|
||||
/>
|
||||
<button
|
||||
onClick={() => setSelectedProject(null)}
|
||||
className="absolute top-4 right-4 bg-black/50 hover:bg-black/70 text-white p-2 rounded-full transition-all duration-300"
|
||||
aria-label="Close modal"
|
||||
>
|
||||
<X size={24} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="p-8">
|
||||
<h3 className="text-3xl font-bold text-white mb-4">{selectedProject.title}</h3>
|
||||
<p className="text-gray-300 text-lg mb-6 leading-relaxed">
|
||||
{selectedProject.description}
|
||||
</p>
|
||||
|
||||
<div className="mb-6">
|
||||
<h4 className="text-lg font-semibold text-white mb-3">Technologies Used:</h4>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{selectedProject.technologies.map((tech) => (
|
||||
<span
|
||||
key={tech}
|
||||
className="px-4 py-2 bg-slate-700 text-violet-400 rounded-lg"
|
||||
>
|
||||
{tech}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4">
|
||||
{selectedProject.liveUrl && (
|
||||
<a
|
||||
href={selectedProject.liveUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-2 px-6 py-3 bg-gradient-to-r from-fuchsia-600 to-orange-500 text-white font-semibold rounded-lg hover:shadow-lg hover:shadow-fuchsia-600/25 transition-all duration-300"
|
||||
>
|
||||
<ExternalLink size={20} />
|
||||
Live Demo
|
||||
</a>
|
||||
)}
|
||||
{selectedProject.githubUrl && (
|
||||
<a
|
||||
href={selectedProject.githubUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-2 px-6 py-3 border-2 border-violet-400 text-violet-400 font-semibold rounded-lg hover:bg-violet-400 hover:text-white transition-all duration-300"
|
||||
>
|
||||
<Github size={20} />
|
||||
View Code
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Portfolio;
|
||||
191
frontend_example/src/components/Skills.tsx
Normal file
191
frontend_example/src/components/Skills.tsx
Normal file
@@ -0,0 +1,191 @@
|
||||
import React from 'react';
|
||||
import { Code, Database, Globe, Server, Wrench, Award } from 'lucide-react';
|
||||
|
||||
interface Skill {
|
||||
name: string;
|
||||
level: number;
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
interface SkillCategory {
|
||||
title: string;
|
||||
icon: React.ReactNode;
|
||||
skills: Skill[];
|
||||
color: string;
|
||||
}
|
||||
|
||||
const Skills: React.FC = () => {
|
||||
const skillCategories: SkillCategory[] = [
|
||||
{
|
||||
title: 'Frontend Development',
|
||||
icon: <Globe size={24} />,
|
||||
color: 'from-fuchsia-600 to-pink-600',
|
||||
skills: [
|
||||
{ name: 'React/Next.js', level: 95 },
|
||||
{ name: 'TypeScript', level: 90 },
|
||||
{ name: 'Tailwind CSS', level: 95 },
|
||||
{ name: 'Vue.js', level: 80 },
|
||||
{ name: 'JavaScript ES6+', level: 95 },
|
||||
{ name: 'HTML5/CSS3', level: 98 }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Backend Development',
|
||||
icon: <Server size={24} />,
|
||||
color: 'from-orange-500 to-red-500',
|
||||
skills: [
|
||||
{ name: 'Node.js', level: 90 },
|
||||
{ name: 'Python', level: 85 },
|
||||
{ name: 'PostgreSQL', level: 88 },
|
||||
{ name: 'MongoDB', level: 82 },
|
||||
{ name: 'REST APIs', level: 92 },
|
||||
{ name: 'GraphQL', level: 78 }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'DevOps & Hosting',
|
||||
icon: <Database size={24} />,
|
||||
color: 'from-violet-400 to-purple-600',
|
||||
skills: [
|
||||
{ name: 'Docker', level: 85 },
|
||||
{ name: 'AWS/Cloud', level: 80 },
|
||||
{ name: 'Linux/Ubuntu', level: 88 },
|
||||
{ name: 'Nginx', level: 82 },
|
||||
{ name: 'CI/CD', level: 78 },
|
||||
{ name: 'Self-Hosting', level: 90 }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Other Tools',
|
||||
icon: <Wrench size={24} />,
|
||||
color: 'from-green-500 to-teal-500',
|
||||
skills: [
|
||||
{ name: 'Git/GitHub', level: 95 },
|
||||
{ name: 'Figma/Design', level: 85 },
|
||||
{ name: 'Photoshop', level: 80 },
|
||||
{ name: 'Drone Photography', level: 88 },
|
||||
{ name: 'Video Editing', level: 75 },
|
||||
{ name: 'Trading Analysis', level: 70 }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const experience = [
|
||||
{
|
||||
title: 'Full-Stack Developer',
|
||||
company: 'Freelance',
|
||||
period: '2020 - Present',
|
||||
description: 'Developing custom web applications and providing technical consulting'
|
||||
},
|
||||
{
|
||||
title: 'Frontend Developer',
|
||||
company: 'Tech Startup',
|
||||
period: '2019 - 2020',
|
||||
description: 'Built responsive web applications using React and modern JavaScript'
|
||||
},
|
||||
{
|
||||
title: 'Web Developer',
|
||||
company: 'Digital Agency',
|
||||
period: '2018 - 2019',
|
||||
description: 'Created websites and web applications for various clients'
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<section id="skills" className="py-20 bg-gradient-to-b from-slate-900 to-slate-800">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-4xl lg:text-5xl font-bold mb-6">
|
||||
<span className="bg-gradient-to-r from-fuchsia-600 to-orange-500 bg-clip-text text-transparent">
|
||||
Skills & Experience
|
||||
</span>
|
||||
</h2>
|
||||
<p className="text-xl text-gray-300 max-w-3xl mx-auto">
|
||||
A comprehensive overview of my technical expertise and professional journey
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Experience Section */}
|
||||
<div className="mb-20">
|
||||
<div className="flex items-center gap-3 mb-8">
|
||||
<Award className="text-fuchsia-600" size={32} />
|
||||
<h3 className="text-3xl font-bold text-white">Experience</h3>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-3 gap-6">
|
||||
{experience.map((exp, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="bg-slate-800 rounded-xl p-6 border border-slate-700 hover:border-violet-400/50 transition-all duration-300"
|
||||
>
|
||||
<h4 className="text-xl font-semibold text-white mb-2">{exp.title}</h4>
|
||||
<p className="text-fuchsia-600 font-medium mb-2">{exp.company}</p>
|
||||
<p className="text-gray-400 text-sm mb-3">{exp.period}</p>
|
||||
<p className="text-gray-300 text-sm">{exp.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Skills Grid */}
|
||||
<div className="grid lg:grid-cols-2 gap-8">
|
||||
{skillCategories.map((category, categoryIndex) => (
|
||||
<div
|
||||
key={categoryIndex}
|
||||
className="bg-slate-800 rounded-2xl p-8 border border-slate-700 hover:border-violet-400/50 transition-all duration-300"
|
||||
>
|
||||
<div className="flex items-center gap-4 mb-8">
|
||||
<div className={`p-3 rounded-xl bg-gradient-to-r ${category.color}`}>
|
||||
<div className="text-white">
|
||||
{category.icon}
|
||||
</div>
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold text-white">{category.title}</h3>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
{category.skills.map((skill, skillIndex) => (
|
||||
<div key={skillIndex}>
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<span className="text-white font-medium">{skill.name}</span>
|
||||
<span className="text-gray-400 text-sm">{skill.level}%</span>
|
||||
</div>
|
||||
<div className="w-full bg-slate-700 rounded-full h-2">
|
||||
<div
|
||||
className={`h-2 rounded-full bg-gradient-to-r ${category.color} transition-all duration-1000 ease-out`}
|
||||
style={{ width: `${skill.level}%` }}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Certifications/Achievements */}
|
||||
<div className="mt-16 text-center">
|
||||
<div className="bg-slate-800 rounded-2xl p-8 border border-slate-700">
|
||||
<h3 className="text-2xl font-bold text-white mb-6">Achievements & Certifications</h3>
|
||||
<div className="grid md:grid-cols-3 gap-6">
|
||||
<div className="p-4">
|
||||
<div className="text-3xl font-bold text-fuchsia-600 mb-2">50+</div>
|
||||
<p className="text-gray-300">Projects Completed</p>
|
||||
</div>
|
||||
<div className="p-4">
|
||||
<div className="text-3xl font-bold text-orange-500 mb-2">5+</div>
|
||||
<p className="text-gray-300">Years Experience</p>
|
||||
</div>
|
||||
<div className="p-4">
|
||||
<div className="text-3xl font-bold text-violet-400 mb-2">100%</div>
|
||||
<p className="text-gray-300">Client Satisfaction</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Skills;
|
||||
109
frontend_example/src/components/TradingGraph.tsx
Normal file
109
frontend_example/src/components/TradingGraph.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import React from 'react';
|
||||
import { TrendingUp, DollarSign, BarChart3, Activity } from 'lucide-react';
|
||||
|
||||
const TradingGraph: React.FC = () => {
|
||||
return (
|
||||
<section className="py-20 bg-slate-900">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-4xl lg:text-5xl font-bold mb-6">
|
||||
<span className="bg-gradient-to-r from-fuchsia-600 to-orange-500 bg-clip-text text-transparent">
|
||||
Trading Dashboard
|
||||
</span>
|
||||
</h2>
|
||||
<p className="text-xl text-gray-300 max-w-3xl mx-auto">
|
||||
Real-time market analysis and portfolio tracking with advanced analytics
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="max-w-6xl mx-auto">
|
||||
{/* Main Trading Window */}
|
||||
<div className="bg-slate-800 rounded-2xl p-8 shadow-2xl border border-slate-700 hover:border-fuchsia-600/50 transition-all duration-300">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="p-3 bg-gradient-to-r from-fuchsia-600 to-orange-500 rounded-lg">
|
||||
<TrendingUp className="text-white" size={24} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-2xl font-bold text-white">Trading212 Portfolio</h3>
|
||||
<p className="text-gray-400">Live market data and analytics</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-3 h-3 bg-green-500 rounded-full animate-pulse"></div>
|
||||
<span className="text-green-500 font-medium">Live</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Trading Graph Placeholder */}
|
||||
<div className="relative bg-slate-900 rounded-xl p-6 mb-6 min-h-[400px] border border-slate-600">
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<BarChart3 className="text-gray-600 mx-auto mb-4" size={64} />
|
||||
<p className="text-gray-400 text-lg">Trading212 Graph Integration</p>
|
||||
<p className="text-gray-500 text-sm mt-2">Real-time market data will be displayed here</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Simulated Graph Elements */}
|
||||
<div className="absolute bottom-6 left-6 right-6">
|
||||
<div className="flex justify-between items-end h-20 opacity-20">
|
||||
{Array.from({ length: 12 }).map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="bg-gradient-to-t from-fuchsia-600 to-orange-500 rounded-t"
|
||||
style={{
|
||||
height: `${Math.random() * 60 + 20}%`,
|
||||
width: '6%'
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stats Grid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div className="bg-slate-700 rounded-xl p-6 border border-slate-600 hover:border-violet-400/50 transition-all duration-300">
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<DollarSign className="text-green-500" size={24} />
|
||||
<h4 className="text-white font-semibold">Portfolio Value</h4>
|
||||
</div>
|
||||
<p className="text-3xl font-bold text-green-500">$12,847.32</p>
|
||||
<p className="text-green-400 text-sm mt-1">+2.34% today</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-slate-700 rounded-xl p-6 border border-slate-600 hover:border-violet-400/50 transition-all duration-300">
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<Activity className="text-orange-500" size={24} />
|
||||
<h4 className="text-white font-semibold">Active Positions</h4>
|
||||
</div>
|
||||
<p className="text-3xl font-bold text-white">8</p>
|
||||
<p className="text-gray-400 text-sm mt-1">Across 5 markets</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-slate-700 rounded-xl p-6 border border-slate-600 hover:border-violet-400/50 transition-all duration-300">
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<TrendingUp className="text-fuchsia-600" size={24} />
|
||||
<h4 className="text-white font-semibold">Monthly Return</h4>
|
||||
</div>
|
||||
<p className="text-3xl font-bold text-fuchsia-600">+8.7%</p>
|
||||
<p className="text-gray-400 text-sm mt-1">Above average</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Integration Note */}
|
||||
<div className="mt-6 p-4 bg-slate-700/50 rounded-lg border border-slate-600">
|
||||
<p className="text-gray-300 text-sm">
|
||||
<span className="text-violet-400 font-medium">Note:</span> This dashboard integrates with Trading212 API
|
||||
for real-time portfolio tracking and market analysis. Data updates every 30 seconds during market hours.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default TradingGraph;
|
||||
28
frontend_example/src/pages/Home.tsx
Normal file
28
frontend_example/src/pages/Home.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import Header from '../components/Header';
|
||||
import Hero from '../components/Hero';
|
||||
import Portfolio from '../components/Portfolio';
|
||||
import TradingGraph from '../components/TradingGraph';
|
||||
import DonateShop from '../components/DonateShop';
|
||||
import Skills from '../components/Skills';
|
||||
import HostingSecurity from '../components/HostingSecurity';
|
||||
import Contact from '../components/Contact';
|
||||
import Footer from '../components/Footer';
|
||||
|
||||
const Home: React.FC = () => {
|
||||
return (
|
||||
<div className="min-h-screen bg-slate-900">
|
||||
<Header />
|
||||
<Hero />
|
||||
<Portfolio />
|
||||
<TradingGraph />
|
||||
<Skills />
|
||||
<DonateShop />
|
||||
<HostingSecurity />
|
||||
<Contact />
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
||||
179
frontend_example/src/pages/NotFound.tsx
Normal file
179
frontend_example/src/pages/NotFound.tsx
Normal file
@@ -0,0 +1,179 @@
|
||||
import React from 'react';
|
||||
|
||||
const NotFound: React.FC = () => {
|
||||
return (
|
||||
<section className="relative flex py-10 min-h-screen items-center justify-center overflow-hidden bg-black">
|
||||
<div className="mx-auto relative z-30 w-full max-w-[600px] text-center px-4">
|
||||
{/* Large 404 Text */}
|
||||
<div className="mb-8">
|
||||
<svg
|
||||
width="472"
|
||||
height="158"
|
||||
viewBox="0 0 472 158"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M26.4028 0.5224C29.8616 0.5224 32.6655 3.3263 32.6655 6.7851V58.7187H75.8726V9.4306C75.8726 5.97182 78.6765 3.16794 82.1353 3.16791H102.236C105.694 3.16817 108.499 5.97196 108.499 9.4306V151.215C108.498 154.673 105.694 157.477 102.235 157.477H82.1353C78.6766 157.477 75.8727 154.673 75.8726 151.215V91.3437H23.0571C19.5983 91.3437 16.7944 88.5398 16.7944 85.081V78.1181H6.30322C2.84444 78.1181 0.0405444 75.3142 0.0405273 71.8554V6.7851C0.0405355 3.32631 2.84444 0.522409 6.30322 0.5224H26.4028Z"
|
||||
fill="url(#paint0_linear_11881_2293)"
|
||||
/>
|
||||
<path
|
||||
d="M262.328 82.4706C263.99 82.4708 265.338 83.8187 265.338 85.4814V97.8544H277.712C279.375 97.8546 280.723 99.2018 280.723 100.864V116.31C280.723 117.973 279.375 119.321 277.712 119.321H260.835C259.173 119.321 257.825 117.973 257.825 116.31V103.937H214.175V116.31C214.175 117.973 212.827 119.321 211.165 119.321H194.289C192.626 119.321 191.278 117.973 191.278 116.31V100.864C191.278 99.2017 192.626 97.8544 194.289 97.8544H207.02V85.4814C207.02 83.8186 208.368 82.4706 210.031 82.4706H262.328Z"
|
||||
fill="url(#paint1_linear_11881_2293)"
|
||||
/>
|
||||
<path
|
||||
d="M222.614 41.3251C224.277 41.3251 225.625 42.6731 225.625 44.3359V59.7812C225.625 61.4439 224.277 62.7919 222.614 62.7919H205.737C204.074 62.7917 202.727 61.4438 202.727 59.7812V44.3359C202.727 42.6733 204.074 41.3254 205.737 41.3251H222.614Z"
|
||||
fill="url(#paint2_linear_11881_2293)"
|
||||
/>
|
||||
<path
|
||||
d="M266.263 41.3251C267.926 41.3252 269.274 42.6732 269.274 44.3359V59.7812C269.274 61.4439 267.926 62.7918 266.263 62.7919H249.386C247.724 62.7918 246.375 61.4439 246.375 59.7812V44.3359C246.375 42.6732 247.724 41.3252 249.386 41.3251H266.263Z"
|
||||
fill="url(#paint3_linear_11881_2293)"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M291.231 3.16693C313.322 3.16693 331.231 21.0755 331.231 43.1669V117.477L331.218 118.51C330.671 140.124 312.977 157.477 291.231 157.477H180.769C158.678 157.477 140.769 139.569 140.769 117.477V43.1669C140.769 21.0755 158.678 3.16693 180.769 3.16693H291.231ZM180.769 27.1669C171.932 27.1669 164.769 34.3304 164.769 43.1669V117.477C164.769 126.314 171.932 133.477 180.769 133.477H291.231C300.068 133.477 307.231 126.314 307.231 117.477V43.1669C307.231 34.3304 300.068 27.1669 291.231 27.1669H180.769Z"
|
||||
fill="url(#paint4_linear_11881_2293)"
|
||||
/>
|
||||
<path
|
||||
d="M389.865 0.5224C393.324 0.522421 396.127 3.32632 396.127 6.7851V58.7187H439.334V9.4306C439.334 5.9718 442.138 3.16791 445.597 3.16791H465.697C469.156 3.16791 471.959 5.9718 471.959 9.4306V151.215C471.959 154.673 469.155 157.477 465.697 157.477H445.597C442.138 157.477 439.335 154.673 439.334 151.215V91.3437H386.518C383.059 91.3436 380.255 88.5397 380.255 85.081V78.1181H369.765C366.306 78.1181 363.502 75.3142 363.502 71.8554V6.7851C363.502 3.3263 366.306 0.5224 369.765 0.5224H389.865Z"
|
||||
fill="url(#paint5_linear_11881_2293)"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear_11881_2293"
|
||||
x1="471.959"
|
||||
y1="157.477"
|
||||
x2="448.654"
|
||||
y2="-49.8952"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#3D404D" />
|
||||
<stop offset="1" stopColor="#8F95B2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_11881_2293"
|
||||
x1="471.959"
|
||||
y1="157.477"
|
||||
x2="448.654"
|
||||
y2="-49.8952"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#3D404D" />
|
||||
<stop offset="1" stopColor="#8F95B2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint2_linear_11881_2293"
|
||||
x1="471.959"
|
||||
y1="157.477"
|
||||
x2="448.654"
|
||||
y2="-49.8952"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#3D404D" />
|
||||
<stop offset="1" stopColor="#8F95B2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint3_linear_11881_2293"
|
||||
x1="471.959"
|
||||
y1="157.477"
|
||||
x2="448.654"
|
||||
y2="-49.8952"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#3D404D" />
|
||||
<stop offset="1" stopColor="#8F95B2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint4_linear_11881_2293"
|
||||
x1="471.959"
|
||||
y1="157.477"
|
||||
x2="448.654"
|
||||
y2="-49.8952"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#3D404D" />
|
||||
<stop offset="1" stopColor="#8F95B2" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint5_linear_11881_2293"
|
||||
x1="471.959"
|
||||
y1="157.477"
|
||||
x2="448.654"
|
||||
y2="-49.8952"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#3D404D" />
|
||||
<stop offset="1" stopColor="#8F95B2" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h1 className="mb-4 text-3xl font-bold text-white sm:text-4xl">
|
||||
OPPS! Page Not Found
|
||||
</h1>
|
||||
<p className="mb-8 text-base text-white/60 sm:text-lg">
|
||||
We can't seem to find the page you are looking for!
|
||||
</p>
|
||||
<a
|
||||
href={typeof window !== 'undefined' ? window.location.origin : '/'}
|
||||
className="inline-flex items-center gap-2 rounded-full bg-white px-6 py-3 text-sm font-medium text-black transition-colors hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-black"
|
||||
>
|
||||
Back to homepage
|
||||
</a>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="mt-16">
|
||||
<p className="text-sm text-gray-600">
|
||||
© {new Date().getFullYear()} - Meku.dev
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="absolute inset-0 bg-[url(https://meku.dev/images/grain.png)] bg-cover bg-center opacity-60 mix-blend-soft-light z-20"></div>
|
||||
|
||||
<div className="absolute bottom-0 left-0 right-0 z-10">
|
||||
<svg
|
||||
width="2192"
|
||||
height="771"
|
||||
viewBox="0 0 2192 771"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g opacity="0.35" filter="url(#filter0_f_3740_75)">
|
||||
<path
|
||||
d="M199.999 258.919C199.999 86.6144 601.152 347.404 1096 347.404C1590.85 347.404 1992 86.6146 1992 258.919C1992 431.223 1590.85 570.904 1096 570.904C601.152 570.904 199.999 431.223 199.999 258.919Z"
|
||||
fill="#C0C2CF"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_f_3740_75"
|
||||
x="-0.000732422"
|
||||
y="0.0515137"
|
||||
width="2192"
|
||||
height="770.852"
|
||||
filterUnits="userSpaceOnUse"
|
||||
colorInterpolationFilters="sRGB"
|
||||
>
|
||||
<feFlood floodOpacity="0" result="BackgroundImageFix" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
/>
|
||||
<feGaussianBlur
|
||||
stdDeviation="100"
|
||||
result="effect1_foregroundBlur_3740_75"
|
||||
/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotFound;
|
||||
5
frontend_example/styles.css
Normal file
5
frontend_example/styles.css
Normal file
@@ -0,0 +1,5 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap');
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
16
frontend_example/tailwind.config.js
Normal file
16
frontend_example/tailwind.config.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{js,ts,jsx,tsx}",
|
||||
"./App.tsx",
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
inter: ['Inter', 'sans-serif'],
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
28
frontend_example/tsconfig.app.json
Normal file
28
frontend_example/tsconfig.app.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"target": "ES2022",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noImplicitAny": false,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
7
frontend_example/tsconfig.json
Normal file
7
frontend_example/tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
||||
26
frontend_example/tsconfig.node.json
Normal file
26
frontend_example/tsconfig.node.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
"target": "ES2023",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noImplicitAny": false,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
1
frontend_example/vite-env.d.ts
vendored
Normal file
1
frontend_example/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
42
frontend_example/vite.config.ts
Normal file
42
frontend_example/vite.config.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import react from "@vitejs/plugin-react";
|
||||
import { defineConfig } from "vite";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
server: {
|
||||
allowedHosts: true,
|
||||
},
|
||||
esbuild: {
|
||||
logOverride: {
|
||||
'ignored-directive': 'silent',
|
||||
},
|
||||
},
|
||||
logLevel: 'info',
|
||||
build: {
|
||||
rollupOptions: {
|
||||
onwarn(warning, warn) {
|
||||
// ignore certain harmless warnings
|
||||
if (
|
||||
warning.message.includes('Module level directives') ||
|
||||
warning.message.includes('"use client"') ||
|
||||
warning.message.includes('"was ignored"')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FAIL build on unresolved imports
|
||||
if (warning.code === 'UNRESOLVED_IMPORT') {
|
||||
throw new Error(`Build failed due to unresolved import:\n${warning.message}`);
|
||||
}
|
||||
|
||||
// FAIL build on missing exports (like your Input error)
|
||||
if (warning.code === 'PLUGIN_WARNING' && /is not exported/.test(warning.message)) {
|
||||
throw new Error(`Build failed due to missing export:\n${warning.message}`);
|
||||
}
|
||||
|
||||
// other warnings: log normally
|
||||
warn(warning);
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user