| <!DOCTYPE html> |
| <html lang="en"> |
|
|
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=yes"> |
|
|
| <meta name="description" content="Ibrahim Al-Asfar Portfolio API - Full-stack web developer portfolio backend API"> |
| <meta name="keywords" content="portfolio, API, Node.js, Express, MongoDB, developer, OAuth, JWT"> |
| <meta name="author" content="Ibrahim Al-Asfar"> |
| <meta name="robots" content="index, follow"> |
|
|
| <!-- Open Graph / Social Media --> |
| <meta property="og:title" content="Ibrahim Al-Asfar Portfolio API"> |
| <meta property="og:description" |
| content="Full-stack web developer portfolio API with authentication and AI features"> |
| <meta property="og:type" content="website"> |
| <meta property="og:url" content="https://mgzon-server.hf.space"> |
| <meta property="og:image" content="https://mgzon-server.hf.space/images/logo.png"> |
|
|
|
|
| <!-- Open Graph / Social Media --> |
| <meta property="og:title" content="Ibrahim Al-Asfar Portfolio API"> |
| <meta property="og:description" |
| content="Full-stack web developer portfolio backend API with authentication, project management, and AI features"> |
| <meta property="og:type" content="website"> |
| <meta property="og:url" content="https://mgzon-server.hf.space"> |
| <meta property="og:image" content="https://mgzon-server.hf.space/images/profile.jpg"> |
| <meta property="og:image:alt" content="Ibrahim Al-Asfar Profile Picture"> |
| <meta property="og:site_name" content="Ibrahim Al-Asfar Portfolio"> |
|
|
| <!-- Twitter Card --> |
| <meta name="twitter:card" content="summary_large_image"> |
| <meta name="twitter:title" content="Ibrahim Al-Asfar Portfolio API"> |
| <meta name="twitter:description" content="Full-stack web developer portfolio backend API"> |
| <meta name="twitter:image" content="https://mgzon-server.hf.space/images/profile.jpg"> |
| <meta name="twitter:image:alt" content="Ibrahim Al-Asfar Profile"> |
| <meta name="twitter:site" content="@MarkLasfar"> |
| <meta name="twitter:creator" content="@MarkLasfar"> |
|
|
| <!-- Author --> |
| <meta name="author" content="Ibrahim Al-Asfar (Mark Elasfar)"> |
|
|
| <!-- Twitter Card --> |
| <meta name="twitter:card" content="summary_large_image"> |
| <meta name="twitter:title" content="Ibrahim Al-Asfar Portfolio API"> |
| <meta name="twitter:description" content="Full-stack web developer portfolio API"> |
| <meta name="twitter:image" content="https://mgzon-server.hf.space/images/logo.png"> |
|
|
| <!-- Favicon --> |
| <link rel="icon" type="image/png" href="/images/logo.png"> |
| <link rel="apple-touch-icon" href="/images/logo.png"> |
|
|
| <title> Portfolio API</title> |
|
|
| <!-- Tailwind CSS --> |
| <script src="https://cdn.tailwindcss.com"></script> |
|
|
| <!-- Font Awesome --> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"> |
|
|
| <!-- Custom Styles --> |
| <style> |
| * { |
| margin: 0; |
| padding: 0; |
| box-sizing: border-box; |
| } |
|
|
| @keyframes fadeInUp { |
| from { |
| opacity: 0; |
| transform: translateY(30px); |
| } |
|
|
| to { |
| opacity: 1; |
| transform: translateY(0); |
| } |
| } |
|
|
| @keyframes float { |
|
|
| 0%, |
| 100% { |
| transform: translateY(0px); |
| } |
|
|
| 50% { |
| transform: translateY(-10px); |
| } |
| } |
|
|
| .animate-fadeInUp { |
| animation: fadeInUp 0.6s ease-out; |
| } |
|
|
| .animate-float { |
| animation: float 3s ease-in-out infinite; |
| } |
|
|
| .gradient-bg { |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| } |
|
|
| .gradient-text { |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| -webkit-background-clip: text; |
| -webkit-text-fill-color: transparent; |
| background-clip: text; |
| } |
|
|
| .card-hover { |
| transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); |
| } |
|
|
| .card-hover:hover { |
| transform: translateY(-5px); |
| box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); |
| } |
|
|
| .btn-hover { |
| transition: all 0.3s ease; |
| position: relative; |
| overflow: hidden; |
| } |
|
|
| .btn-hover:hover { |
| transform: scale(1.05); |
| } |
|
|
| /* Custom scrollbar */ |
| ::-webkit-scrollbar { |
| width: 10px; |
| } |
|
|
| ::-webkit-scrollbar-track { |
| background: #f1f1f1; |
| border-radius: 10px; |
| } |
|
|
| ::-webkit-scrollbar-thumb { |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| border-radius: 10px; |
| } |
|
|
| ::-webkit-scrollbar-thumb:hover { |
| background: #5a67d8; |
| } |
|
|
| /* Logo styling */ |
| .logo-img { |
| width: 40px; |
| height: 40px; |
| object-fit: contain; |
| border-radius: 10px; |
| } |
|
|
| /* Glass effect */ |
| .glass-card { |
| background: rgba(255, 255, 255, 0.9); |
| backdrop-filter: blur(10px); |
| } |
|
|
| /* Fallback styles */ |
| .bg-gradient-to-br { |
| background: linear-gradient(to bottom right, #f9fafb, #f3f4f6); |
| } |
|
|
| .shadow-lg { |
| box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); |
| } |
|
|
| .rounded-lg { |
| border-radius: 0.5rem; |
| } |
|
|
| .rounded-xl { |
| border-radius: 0.75rem; |
| } |
|
|
| .p-2 { |
| padding: 0.5rem; |
| } |
|
|
| .p-3 { |
| padding: 0.75rem; |
| } |
|
|
| .p-4 { |
| padding: 1rem; |
| } |
|
|
| .p-5 { |
| padding: 1.25rem; |
| } |
|
|
| .p-6 { |
| padding: 1.5rem; |
| } |
|
|
| .py-8 { |
| padding-top: 2rem; |
| padding-bottom: 2rem; |
| } |
|
|
| .py-12 { |
| padding-top: 3rem; |
| padding-bottom: 3rem; |
| } |
|
|
| .py-16 { |
| padding-top: 4rem; |
| padding-bottom: 4rem; |
| } |
|
|
| .py-20 { |
| padding-top: 5rem; |
| padding-bottom: 5rem; |
| } |
|
|
| .px-4 { |
| padding-left: 1rem; |
| padding-right: 1rem; |
| } |
|
|
| .px-8 { |
| padding-left: 2rem; |
| padding-right: 2rem; |
| } |
|
|
| .text-center { |
| text-align: center; |
| } |
|
|
| .text-white { |
| color: white; |
| } |
|
|
| .text-gray-600 { |
| color: #4b5563; |
| } |
|
|
| .text-gray-800 { |
| color: #1f2937; |
| } |
|
|
| .text-xl { |
| font-size: 1.25rem; |
| } |
|
|
| .text-2xl { |
| font-size: 1.5rem; |
| } |
|
|
| .text-3xl { |
| font-size: 1.875rem; |
| } |
|
|
| .text-5xl { |
| font-size: 3rem; |
| } |
|
|
| .font-bold { |
| font-weight: 700; |
| } |
|
|
| .font-semibold { |
| font-weight: 600; |
| } |
|
|
| .bg-white { |
| background-color: white; |
| } |
|
|
| .bg-gray-800 { |
| background-color: #1f2937; |
| } |
|
|
| .bg-green-500 { |
| background-color: #10b981; |
| } |
|
|
| .bg-red-500 { |
| background-color: #ef4444; |
| } |
|
|
| .mb-2 { |
| margin-bottom: 0.5rem; |
| } |
|
|
| .mb-4 { |
| margin-bottom: 1rem; |
| } |
|
|
| .mb-6 { |
| margin-bottom: 1.5rem; |
| } |
|
|
| .mb-8 { |
| margin-bottom: 2rem; |
| } |
|
|
| .mb-12 { |
| margin-bottom: 3rem; |
| } |
|
|
| .mt-2 { |
| margin-top: 0.5rem; |
| } |
|
|
| .mr-2 { |
| margin-right: 0.5rem; |
| } |
|
|
| .ml-2 { |
| margin-left: 0.5rem; |
| } |
|
|
| .flex { |
| display: flex; |
| } |
|
|
| .inline-flex { |
| display: inline-flex; |
| } |
|
|
| .grid { |
| display: grid; |
| } |
|
|
| .items-center { |
| align-items: center; |
| } |
|
|
| .justify-center { |
| justify-content: center; |
| } |
|
|
| .justify-between { |
| justify-content: space-between; |
| } |
|
|
| .gap-4 { |
| gap: 1rem; |
| } |
|
|
| .gap-6 { |
| gap: 1.5rem; |
| } |
|
|
| .gap-8 { |
| gap: 2rem; |
| } |
|
|
| .max-w-2xl { |
| max-width: 42rem; |
| } |
|
|
| .max-w-7xl { |
| max-width: 80rem; |
| } |
|
|
| .mx-auto { |
| margin-left: auto; |
| margin-right: auto; |
| } |
|
|
| .w-12 { |
| width: 3rem; |
| } |
|
|
| .h-12 { |
| height: 3rem; |
| } |
|
|
| .w-16 { |
| width: 4rem; |
| } |
|
|
| .h-16 { |
| height: 4rem; |
| } |
|
|
| .w-3 { |
| width: 0.75rem; |
| } |
|
|
| .h-3 { |
| height: 0.75rem; |
| } |
|
|
| .rounded-full { |
| border-radius: 9999px; |
| } |
|
|
| .cursor-pointer { |
| cursor: pointer; |
| } |
|
|
| .animate-pulse { |
| animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; |
| } |
|
|
| @keyframes pulse { |
|
|
| 0%, |
| 100% { |
| opacity: 1; |
| } |
|
|
| 50% { |
| opacity: .5; |
| } |
| } |
|
|
| .sticky { |
| position: sticky; |
| } |
|
|
| .top-0 { |
| top: 0; |
| } |
|
|
| .z-50 { |
| z-index: 50; |
| } |
|
|
| .absolute { |
| position: absolute; |
| } |
|
|
| .relative { |
| position: relative; |
| } |
|
|
| .inset-0 { |
| top: 0; |
| right: 0; |
| bottom: 0; |
| left: 0; |
| } |
|
|
| .overflow-hidden { |
| overflow: hidden; |
| } |
|
|
| .bg-opacity-10 { |
| opacity: 0.1; |
| } |
|
|
| .transition { |
| transition-property: all; |
| transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); |
| transition-duration: 150ms; |
| } |
|
|
| .hover\:shadow-xl:hover { |
| box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); |
| } |
|
|
| .hover\:shadow-2xl:hover { |
| box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); |
| } |
|
|
| .hover\:bg-gray-900:hover { |
| background-color: #111827; |
| } |
|
|
| .hover\:text-purple-600:hover { |
| color: #7c3aed; |
| } |
|
|
| .hover\:scale-105:hover { |
| transform: scale(1.05); |
| } |
|
|
| @media (min-width: 640px) { |
| .sm\:px-6 { |
| padding-left: 1.5rem; |
| padding-right: 1.5rem; |
| } |
| } |
|
|
| @media (min-width: 768px) { |
| .md\:grid-cols-2 { |
| grid-template-columns: repeat(2, minmax(0, 1fr)); |
| } |
|
|
| .md\:grid-cols-3 { |
| grid-template-columns: repeat(3, minmax(0, 1fr)); |
| } |
|
|
| .md\:grid-cols-4 { |
| grid-template-columns: repeat(4, minmax(0, 1fr)); |
| } |
|
|
| .md\:text-6xl { |
| font-size: 3.75rem; |
| } |
| } |
|
|
| @media (min-width: 1024px) { |
| .lg\:grid-cols-3 { |
| grid-template-columns: repeat(3, minmax(0, 1fr)); |
| } |
|
|
| .lg\:grid-cols-4 { |
| grid-template-columns: repeat(4, minmax(0, 1fr)); |
| } |
|
|
| .lg\:px-8 { |
| padding-left: 2rem; |
| padding-right: 2rem; |
| } |
| } |
|
|
| /* Toast notification */ |
| .toast { |
| position: fixed; |
| bottom: 20px; |
| right: 20px; |
| background: white; |
| border-radius: 8px; |
| padding: 12px 20px; |
| box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); |
| z-index: 1000; |
| animation: slideIn 0.3s ease; |
| } |
|
|
| @keyframes slideIn { |
| from { |
| transform: translateX(100%); |
| opacity: 0; |
| } |
|
|
| to { |
| transform: translateX(0); |
| opacity: 1; |
| } |
| } |
|
|
| .toast.success { |
| border-left: 4px solid #10b981; |
| } |
|
|
| .toast.error { |
| border-left: 4px solid #ef4444; |
| } |
|
|
| .toast.info { |
| border-left: 4px solid #3b82f6; |
| } |
|
|
|
|
| /* ุชุญุณููุงุช ููู
ูุจุงูู */ |
| @media (max-width: 640px) { |
|
|
| /* ุชูููู padding ูู ุงูุฃูุณุงู
*/ |
| .py-20 { |
| padding-top: 3rem; |
| padding-bottom: 3rem; |
| } |
|
|
| .py-16 { |
| padding-top: 2rem; |
| padding-bottom: 2rem; |
| } |
|
|
| /* ุฌุนู ุงููุต ุฃุตุบุฑ */ |
| .text-5xl { |
| font-size: 2rem; |
| } |
|
|
| .text-3xl { |
| font-size: 1.5rem; |
| } |
|
|
| .text-xl { |
| font-size: 1rem; |
| } |
|
|
| /* ุชุญุณูู ุงูุดุจูุฉ */ |
| .grid { |
| gap: 1rem; |
| } |
|
|
| /* ุชุญุณูู ุงูุจุทุงูุงุช */ |
| .card-hover { |
| margin-bottom: 0.5rem; |
| } |
|
|
| /* ุชุญุณูู ุงูููุฏุฑ */ |
| .h-16 { |
| height: auto; |
| padding: 0.5rem 0; |
| } |
|
|
| .flex { |
| flex-wrap: wrap; |
| } |
|
|
| /* ุฌุนู ุงูุฃุฒุฑุงุฑ full width */ |
| .btn-hover, |
| .gradient-bg { |
| width: 100%; |
| text-align: center; |
| justify-content: center; |
| } |
|
|
| /* ุชุญุณูู OAuth buttons */ |
| .grid-cols-1.md\:grid-cols-2.lg\:grid-cols-4 { |
| grid-template-columns: repeat(2, 1fr); |
| } |
| } |
|
|
| @media (max-width: 480px) { |
|
|
| /* ููุดุงุดุงุช ุงูุตุบูุฑุฉ ุฌุฏุงู */ |
| .grid-cols-1.md\:grid-cols-2.lg\:grid-cols-4 { |
| grid-template-columns: 1fr; |
| } |
|
|
| .flex.flex-wrap.justify-center.gap-8 { |
| gap: 1rem; |
| } |
|
|
| .logo-img { |
| width: 30px; |
| height: 30px; |
| } |
| } |
| </style> |
|
|
| <!-- Structured Data / Schema.org --> |
| <script type="application/ld+json"> |
| { |
| "@context": "https://schema.org", |
| "@type": "Person", |
| "@id": "https://mgzon-server.hf.space/#person", |
| "name": "Ibrahim Al-Asfar", |
| "alternateName": ["Mark Elasfar", "Mark Al-Asfar", "ibrahim elasfar", "ibrahim Al-asfar", "alasfar"], |
| "givenName": "Ibrahim", |
| "familyName": "Al-Asfar", |
| "email": "marklasfar@gmail.com", |
| "url": "https://mgzon-server.hf.space", |
| "image": "https://mgzon-server.hf.space/images/profile.jpg", |
| "sameAs": [ |
| "https://github.com/Mark-Lasfar", |
| "https://linkedin.com/in/ibrahim-elasfar", |
| "https://twitter.com/MarkLasfar" |
| ], |
| "jobTitle": "Full-stack Web Developer", |
| "worksFor": { |
| "@type": "Organization", |
| "name": "MGZon", |
| "url": "https://mgzon.com", |
| "logo": "https://mgzon-server.hf.space/images/mgzon-logo.png" |
| }, |
| "knowsAbout": ["Node.js", "Express", "MongoDB", "React", "GraphQL", "Docker", "AWS", "OAuth", "JWT", "REST API"], |
| "alumniOf": [ |
| { |
| "@type": "CollegeOrUniversity", |
| "name": "Computer Science Department" |
| } |
| ], |
| "description": "Full-stack web developer portfolio backend API with authentication, project management, and AI features" |
| } |
| </script> |
|
|
| <!-- WebApplication Schema --> |
| <script type="application/ld+json"> |
| { |
| "@context": "https://schema.org", |
| "@type": "WebApplication", |
| "name": "Portfolio API", |
| "description": "Full-stack web developer portfolio backend API with authentication, project management, and AI features", |
| "url": "https://mgzon-server.hf.space", |
| "applicationCategory": "DeveloperApplication", |
| "operatingSystem": "All", |
| "softwareVersion": "1.0.0", |
| "author": { |
| "@type": "Person", |
| "@id": "https://mgzon-server.hf.space/#person" |
| }, |
| "creator": { |
| "@type": "Person", |
| "name": "Ibrahim Al-Asfar" |
| }, |
| "provider": { |
| "@type": "Organization", |
| "name": "MGZon", |
| "url": "https://mgzon.com", |
| "logo": "https://mgzon-server.hf.space/images/mgzon-logo.png" |
| }, |
| "offers": { |
| "@type": "Offer", |
| "price": "0", |
| "priceCurrency": "USD" |
| }, |
| "featureList": [ |
| "JWT Authentication", |
| "OAuth Integration (Google, Facebook, GitHub, MGZon)", |
| "Project Management", |
| "File Upload with Cloudinary", |
| "AI Chatbot", |
| "PDF/DOCX Resume Export", |
| "Real-time Analytics" |
| ] |
| } |
| </script> |
|
|
| <!-- Organization Schema --> |
| <script type="application/ld+json"> |
| { |
| "@context": "https://schema.org", |
| "@type": "Organization", |
| "name": "MGZon", |
| "url": "https://mgzon.com", |
| "logo": "https://mgzon-server.hf.space/images/mgzon-logo.png", |
| "sameAs": [ |
| "https://github.com/MGZon", |
| "https://twitter.com/MGZon" |
| ] |
| } |
| </script> |
|
|
| </head> |
|
|
| <body class="bg-gradient-to-br from-gray-50 to-gray-100 min-h-screen"> |
|
|
| <!-- Navigation --> |
| <nav class="bg-white/90 backdrop-blur-md shadow-lg sticky top-0 z-50"> |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> |
| <div class="flex flex-wrap justify-between items-center py-2 md:py-0 md:h-16"> |
| <div class="flex items-center space-x-3"> |
| <img src="/images/logo.png" alt="Logo" class="logo-img"> |
| <h1 class="text-lg md:text-xl font-bold gradient-text">Portfolio API</h1> |
| </div> |
| <div class="flex items-center space-x-3 mt-2 md:mt-0"> |
| <a href="/api-docs" class="text-gray-600 hover:text-purple-600 transition p-2"> |
| <i class="fas fa-book text-base md:text-lg"></i> |
| </a> |
| <a href="https://github.com/Mark-Lasfar" class="text-gray-600 hover:text-purple-600 transition p-2"> |
| <i class="fab fa-github text-base md:text-lg"></i> |
| </a> |
| <a href="https://linkedin.com/in/ibrahim-elasfar" |
| class="text-gray-600 hover:text-purple-600 transition p-2"> |
| <i class="fab fa-linkedin text-base md:text-lg"></i> |
| </a> |
| </div> |
| </div> |
| </div> |
| </nav> |
|
|
| <!-- Hero Section --> |
| <div class="relative overflow-hidden"> |
| <div class="absolute inset-0 bg-gradient-to-r from-purple-600 to-blue-600 opacity-10"></div> |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20"> |
| <div class="text-center animate-fadeInUp"> |
| <div class="inline-flex items-center justify-center p-2 bg-green-100 rounded-full mb-4"> |
| <i class="fas fa-check-circle text-green-600 mr-2"></i> |
| <span class="text-green-600 text-sm font-medium" id="api-status">API is running</span> |
| </div> |
| <h1 class="text-5xl md:text-6xl font-bold gradient-text mb-6"> |
| Welcome to My Portfolio API |
| </h1> |
| <p class="text-xl text-gray-600 mb-8 max-w-2xl mx-auto"> |
| Full-stack web developer passionate about building modern web applications with cutting-edge |
| technologies. |
| </p> |
| <div class="flex flex-wrap justify-center gap-4"> |
| <a href="/api-docs" |
| class="gradient-bg text-white px-8 py-3 rounded-lg font-semibold btn-hover inline-flex items-center"> |
| <i class="fas fa-rocket mr-2"></i> |
| Explore API |
| </a> |
| <a href="#test-api" |
| class="bg-gray-800 text-white px-8 py-3 rounded-lg font-semibold btn-hover inline-flex items-center" |
| id="test-api-btn"> |
| <i class="fas fa-vial mr-2"></i> |
| Test API |
| </a> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <!-- Stats Section with Real-time Data --> |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16"> |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-8"> |
| <div class="bg-white rounded-xl shadow-lg p-6 card-hover animate-fadeInUp" style="animation-delay: 0.1s"> |
| <div class="gradient-bg w-12 h-12 rounded-lg flex items-center justify-center mb-4"> |
| <i class="fas fa-database text-white text-xl"></i> |
| </div> |
| <h3 class="text-2xl font-bold text-gray-800 mb-2">Database Status</h3> |
| <div class="flex items-center"> |
| <div class="w-3 h-3 bg-green-500 rounded-full animate-pulse mr-2"></div> |
| <p class="text-gray-600" id="db-status">Checking...</p> |
| </div> |
| </div> |
|
|
| <div class="bg-white rounded-xl shadow-lg p-6 card-hover animate-fadeInUp" style="animation-delay: 0.2s"> |
| <div class="gradient-bg w-12 h-12 rounded-lg flex items-center justify-center mb-4"> |
| <i class="fas fa-cloud-upload-alt text-white text-xl"></i> |
| </div> |
| <h3 class="text-2xl font-bold text-gray-800 mb-2">Cloudinary</h3> |
| <p class="text-gray-600" id="cloudinary-status">Checking...</p> |
| </div> |
|
|
| <div class="bg-white rounded-xl shadow-lg p-6 card-hover animate-fadeInUp" style="animation-delay: 0.3s"> |
| <div class="gradient-bg w-12 h-12 rounded-lg flex items-center justify-center mb-4"> |
| <i class="fas fa-chart-line text-white text-xl"></i> |
| </div> |
| <h3 class="text-2xl font-bold text-gray-800 mb-2">Analytics</h3> |
| <p class="text-gray-600" id="sentry-status">Checking...</p> |
| </div> |
| </div> |
| </div> |
|
|
| <!-- OAuth Authentication Section --> |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16"> |
| <h2 class="text-3xl font-bold text-center text-gray-800 mb-12">๐ Authentication Providers</h2> |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"> |
| <!-- Google OAuth --> |
| <a href="/auth/google" class="bg-white rounded-xl shadow-lg p-6 card-hover text-center group" |
| target="_blank"> |
| <div class="w-16 h-16 mx-auto mb-4"> |
| <i class="fab fa-google text-5xl text-red-500 group-hover:scale-110 transition-transform"></i> |
| </div> |
| <h3 class="font-semibold text-gray-800">Sign in with Google</h3> |
| <p class="text-xs text-gray-500 mt-2">OAuth 2.0</p> |
| <span |
| class="inline-block mt-3 text-purple-600 text-sm opacity-0 group-hover:opacity-100 transition">Click |
| to test โ</span> |
| </a> |
|
|
| <!-- Facebook OAuth --> |
| <a href="/auth/facebook" class="bg-white rounded-xl shadow-lg p-6 card-hover text-center group" |
| target="_blank"> |
| <div class="w-16 h-16 mx-auto mb-4"> |
| <i class="fab fa-facebook text-5xl text-blue-600 group-hover:scale-110 transition-transform"></i> |
| </div> |
| <h3 class="font-semibold text-gray-800">Sign in with Facebook</h3> |
| <p class="text-xs text-gray-500 mt-2">OAuth 2.0</p> |
| <span |
| class="inline-block mt-3 text-purple-600 text-sm opacity-0 group-hover:opacity-100 transition">Click |
| to test โ</span> |
| </a> |
|
|
| <!-- GitHub OAuth --> |
| <a href="/auth/github" class="bg-white rounded-xl shadow-lg p-6 card-hover text-center group" |
| target="_blank"> |
| <div class="w-16 h-16 mx-auto mb-4"> |
| <i class="fab fa-github text-5xl text-gray-800 group-hover:scale-110 transition-transform"></i> |
| </div> |
| <h3 class="font-semibold text-gray-800">Sign in with GitHub</h3> |
| <p class="text-xs text-gray-500 mt-2">OAuth 2.0</p> |
| <span |
| class="inline-block mt-3 text-purple-600 text-sm opacity-0 group-hover:opacity-100 transition">Click |
| to test โ</span> |
| </a> |
|
|
| <!-- MGZon OAuth --> |
| <a href="/auth/mgz" class="bg-white rounded-xl shadow-lg p-6 card-hover text-center group" target="_blank"> |
| <div class="w-16 h-16 mx-auto mb-4"> |
| <img src="https://mgzon-server.hf.space/images/logo.png" alt="MGZon" |
| class="w-16 h-16 rounded-full mx-auto group-hover:scale-110 transition-transform" |
| onerror="this.onerror=null; this.parentElement.innerHTML='<div class=\'w-16 h-16 gradient-bg rounded-full flex items-center justify-center mx-auto group-hover:scale-110 transition-transform\'><i class=\'fas fa-globe text-white text-2xl\'></i></div>'"> |
| </div> |
| <h3 class="font-semibold text-gray-800">Sign in with MGZon</h3> |
| <p class="text-xs text-gray-500 mt-2">OAuth 2.0</p> |
| <span |
| class="inline-block mt-3 text-purple-600 text-sm opacity-0 group-hover:opacity-100 transition">Click |
| to test โ</span> |
| </a> |
| </div> |
| </div> |
|
|
| <!-- API Test Section --> |
| <div id="test-api" class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16"> |
| <h2 class="text-3xl font-bold text-center text-gray-800 mb-12">๐งช API Test Panel</h2> |
| <div class="bg-white rounded-xl shadow-lg p-6"> |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> |
| <div> |
| <label class="block text-sm font-medium text-gray-700 mb-2">Endpoint</label> |
| <select id="api-endpoint" |
| class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent"> |
| <option value="/api/health">GET /api/health</option> |
| <option value="/api/projects">GET /api/projects</option> |
| <option value="/api/skills">GET /api/skills</option> |
| <option value="/api/register">POST /api/register</option> |
| <option value="/api/login">POST /api/login</option> |
| </select> |
| </div> |
| <div> |
| <label class="block text-sm font-medium text-gray-700 mb-2">Request Body (JSON)</label> |
| <textarea id="api-body" rows="3" |
| class="w-full px-4 py-2 border border-gray-300 rounded-lg font-mono text-sm" |
| placeholder='{"email": "test@example.com", "password": "12345678"}'></textarea> |
| </div> |
| </div> |
| <div class="mt-4 flex justify-center"> |
| <button id="send-request" class="gradient-bg text-white px-8 py-2 rounded-lg font-semibold btn-hover"> |
| <i class="fas fa-paper-plane mr-2"></i> |
| Send Request |
| </button> |
| </div> |
| <div class="mt-6"> |
| <label class="block text-sm font-medium text-gray-700 mb-2">Response</label> |
| <pre id="api-response" |
| class="bg-gray-900 text-green-400 p-4 rounded-lg overflow-x-auto font-mono text-sm max-h-96">Click "Send Request" to test API...</pre> |
| </div> |
| </div> |
| </div> |
|
|
| <!-- API Endpoints Section --> |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16"> |
| <h2 class="text-3xl font-bold text-center text-gray-800 mb-12">๐ก API Endpoints</h2> |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> |
| <div class="bg-white rounded-lg shadow-md p-5 card-hover"> |
| <div class="flex items-center justify-between mb-3"> |
| <span class="bg-green-100 text-green-600 text-xs font-semibold px-2 py-1 rounded">GET</span> |
| <i class="fas fa-users text-gray-400"></i> |
| </div> |
| <code class="text-sm text-gray-700">/api/projects</code> |
| <p class="text-gray-500 text-sm mt-2">Get all public projects</p> |
| <button onclick="testEndpoint('/api/projects')" |
| class="mt-3 text-purple-600 text-sm hover:underline">Test โ</button> |
| </div> |
|
|
| <div class="bg-white rounded-lg shadow-md p-5 card-hover"> |
| <div class="flex items-center justify-between mb-3"> |
| <span class="bg-green-100 text-green-600 text-xs font-semibold px-2 py-1 rounded">GET</span> |
| <i class="fas fa-chart-simple text-gray-400"></i> |
| </div> |
| <code class="text-sm text-gray-700">/api/skills</code> |
| <p class="text-gray-500 text-sm mt-2">Get all skills</p> |
| <button onclick="testEndpoint('/api/skills')" class="mt-3 text-purple-600 text-sm hover:underline">Test |
| โ</button> |
| </div> |
|
|
| <div class="bg-white rounded-lg shadow-md p-5 card-hover"> |
| <div class="flex items-center justify-between mb-3"> |
| <span class="bg-green-100 text-green-600 text-xs font-semibold px-2 py-1 rounded">GET</span> |
| <i class="fas fa-heart text-gray-400"></i> |
| </div> |
| <code class="text-sm text-gray-700">/api/health</code> |
| <p class="text-gray-500 text-sm mt-2">Check system health</p> |
| <button onclick="testEndpoint('/api/health')" class="mt-3 text-purple-600 text-sm hover:underline">Test |
| โ</button> |
| </div> |
|
|
| <div class="bg-white rounded-lg shadow-md p-5 card-hover"> |
| <div class="flex items-center justify-between mb-3"> |
| <span class="bg-blue-100 text-blue-600 text-xs font-semibold px-2 py-1 rounded">POST</span> |
| <i class="fas fa-user-plus text-gray-400"></i> |
| </div> |
| <code class="text-sm text-gray-700">/api/register</code> |
| <p class="text-gray-500 text-sm mt-2">Create new account</p> |
| <button |
| onclick="testEndpoint('/api/register', 'POST', {email: 'test@example.com', password: '12345678', username: 'testuser'})" |
| class="mt-3 text-purple-600 text-sm hover:underline">Test โ</button> |
| </div> |
|
|
| <div class="bg-white rounded-lg shadow-md p-5 card-hover"> |
| <div class="flex items-center justify-between mb-3"> |
| <span class="bg-blue-100 text-blue-600 text-xs font-semibold px-2 py-1 rounded">POST</span> |
| <i class="fas fa-sign-in-alt text-gray-400"></i> |
| </div> |
| <code class="text-sm text-gray-700">/api/login</code> |
| <p class="text-gray-500 text-sm mt-2">Authenticate user</p> |
| <button onclick="testEndpoint('/api/login', 'POST', {email: 'admin@elasfar.com', password: 'admin123'})" |
| class="mt-3 text-purple-600 text-sm hover:underline">Test โ</button> |
| </div> |
|
|
| <div class="bg-white rounded-lg shadow-md p-5 card-hover"> |
| <div class="flex items-center justify-between mb-3"> |
| <span class="bg-purple-100 text-purple-600 text-xs font-semibold px-2 py-1 rounded">GET</span> |
| <i class="fab fa-google text-gray-400"></i> |
| </div> |
| <code class="text-sm text-gray-700">/auth/google</code> |
| <p class="text-gray-500 text-sm mt-2">Google OAuth Login</p> |
| <a href="/auth/google" target="_blank" |
| class="mt-3 text-purple-600 text-sm hover:underline inline-block">Open โ</a> |
| </div> |
| </div> |
| </div> |
|
|
| <!-- Tech Stack Section --> |
| <div class="bg-white py-16"> |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> |
| <h2 class="text-3xl font-bold text-center text-gray-800 mb-12">โก Technology Stack</h2> |
| <div class="flex flex-wrap justify-center gap-8"> |
| <div class="text-center"> |
| <i class="fab fa-node-js text-5xl text-green-600"></i> |
| <p class="mt-2 text-gray-600">Node.js</p> |
| </div> |
| <div class="text-center"> |
| <i class="fab fa-react text-5xl text-blue-500"></i> |
| <p class="mt-2 text-gray-600">React</p> |
| </div> |
| <div class="text-center"> |
| <i class="fas fa-database text-5xl text-green-700"></i> |
| <p class="mt-2 text-gray-600">MongoDB</p> |
| </div> |
| <div class="text-center"> |
| <i class="fas fa-project-diagram text-5xl text-pink-500"></i> |
| <p class="mt-2 text-gray-600">GraphQL</p> |
| </div> |
| <div class="text-center"> |
| <i class="fab fa-docker text-5xl text-blue-600"></i> |
| <p class="mt-2 text-gray-600">Docker</p> |
| </div> |
| <div class="text-center"> |
| <i class="fab fa-aws text-5xl text-orange-500"></i> |
| <p class="mt-2 text-gray-600">AWS</p> |
| </div> |
| <div class="text-center"> |
| <i class="fas fa-shield-alt text-5xl text-purple-600"></i> |
| <p class="mt-2 text-gray-600">JWT Auth</p> |
| </div> |
| <div class="text-center"> |
| <i class="fas fa-cloud-upload-alt text-5xl text-blue-400"></i> |
| <p class="mt-2 text-gray-600">Cloudinary</p> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <!-- Footer --> |
| <footer class="bg-gray-800 text-white py-8 mt-8"> |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center"> |
| <p class="text-gray-400 text-sm">© 2026 Ibrahim Al-Asfar. All rights reserved.</p> |
| <p class="text-gray-500 text-xs mt-2">Built with โค๏ธ using Node.js, Express, MongoDB & TailwindCSS</p> |
| <p class="text-gray-600 text-xs mt-3"> |
| <i class="fas fa-code mr-1"></i> API Version 1.0.0 |
| </p> |
|
|
| <!-- โ
ุฑูุงุจุท ูุงููููุฉ --> |
| <div class="flex flex-wrap justify-center gap-3 mt-4"> |
| <a href="/privacy" class="text-gray-500 hover:text-purple-400 text-xs transition">Privacy Policy</a> |
| <span class="text-gray-600 text-xs">โข</span> |
| <a href="/terms" class="text-gray-500 hover:text-purple-400 text-xs transition">Terms of Service</a> |
| <span class="text-gray-600 text-xs">โข</span> |
| <a href="/sitemap.xml" class="text-gray-500 hover:text-purple-400 text-xs transition">Sitemap</a> |
| <span class="text-gray-600 text-xs">โข</span> |
| <a href="/api-docs" class="text-gray-500 hover:text-purple-400 text-xs transition">API Docs</a> |
| </div> |
|
|
| <!-- โ
ุฑูุงุจุท Social Media --> |
| <div class="flex justify-center gap-4 mt-4"> |
| <a href="https://github.com/Mark-Lasfar" target="_blank" |
| class="text-gray-500 hover:text-white transition"> |
| <i class="fab fa-github text-lg"></i> |
| </a> |
| <a href="https://linkedin.com/in/ibrahim-elasfar" target="_blank" |
| class="text-gray-500 hover:text-white transition"> |
| <i class="fab fa-linkedin text-lg"></i> |
| </a> |
| <a href="https://twitter.com/MarkLasfar" target="_blank" |
| class="text-gray-500 hover:text-white transition"> |
| <i class="fab fa-twitter text-lg"></i> |
| </a> |
| </div> |
| </div> |
| </footer> |
|
|
| <!-- Toast Container --> |
| <div id="toast-container" class="fixed bottom-4 right-4 z-50"></div> |
|
|
| <script> |
| // Show toast notification |
| function showToast(message, type = 'success') { |
| const container = document.getElementById('toast-container'); |
| const toast = document.createElement('div'); |
| toast.className = `toast ${type} mb-2`; |
| toast.innerHTML = ` |
| <div class="flex items-center gap-3"> |
| <i class="fas ${type === 'success' ? 'fa-check-circle text-green-500' : type === 'error' ? 'fa-exclamation-circle text-red-500' : 'fa-info-circle text-blue-500'}"></i> |
| <span>${message}</span> |
| </div> |
| `; |
| container.appendChild(toast); |
| setTimeout(() => toast.remove(), 3000); |
| } |
|
|
| // Test API endpoint |
| async function testEndpoint(url, method = 'GET', body = null) { |
| const responseDiv = document.getElementById('api-response'); |
| responseDiv.textContent = 'Loading...'; |
|
|
| try { |
| const options = { method, headers: { 'Content-Type': 'application/json' } }; |
| if (body && method !== 'GET') { |
| options.body = JSON.stringify(body); |
| } |
|
|
| const response = await fetch(url, options); |
| const data = await response.json(); |
| responseDiv.textContent = JSON.stringify(data, null, 2); |
| showToast(`โ
${url} - Status: ${response.status}`, 'success'); |
| } catch (error) { |
| responseDiv.textContent = `Error: ${error.message}`; |
| showToast(`โ ${url} - ${error.message}`, 'error'); |
| } |
| } |
|
|
| // Fetch real-time data |
| async function fetchStats() { |
| try { |
| const response = await fetch('/api/health'); |
| const data = await response.json(); |
| console.log('System Health:', data); |
|
|
| document.getElementById('db-status').innerHTML = data.mongodb === 'connected' ? 'MongoDB Connected โ
' : 'MongoDB Error โ'; |
| document.getElementById('db-status').className = data.mongodb === 'connected' ? 'text-green-600' : 'text-red-600'; |
|
|
| document.getElementById('cloudinary-status').innerHTML = data.cloudinary === 'configured' ? 'Cloudinary Active โ
' : 'Cloudinary Not Configured โ ๏ธ'; |
| document.getElementById('cloudinary-status').className = data.cloudinary === 'configured' ? 'text-green-600' : 'text-yellow-600'; |
|
|
| document.getElementById('sentry-status').innerHTML = data.sentry === 'configured' ? 'Sentry Active โ
' : 'Sentry Not Configured โ ๏ธ'; |
| document.getElementById('sentry-status').className = data.sentry === 'configured' ? 'text-green-600' : 'text-yellow-600'; |
| } catch (error) { |
| console.error('Error fetching stats:', error); |
| document.getElementById('db-status').innerHTML = 'Connection Error โ'; |
| document.getElementById('db-status').className = 'text-red-600'; |
| showToast('Failed to fetch system health', 'error'); |
| } |
| } |
|
|
| // API Test Panel |
| document.getElementById('send-request')?.addEventListener('click', async () => { |
| const endpoint = document.getElementById('api-endpoint').value; |
| const bodyText = document.getElementById('api-body').value; |
| let body = null; |
|
|
| if (bodyText && (endpoint.includes('/register') || endpoint.includes('/login'))) { |
| try { |
| body = JSON.parse(bodyText); |
| } catch (e) { |
| showToast('Invalid JSON format', 'error'); |
| return; |
| } |
| } |
|
|
| const method = endpoint.includes('/register') || endpoint.includes('/login') ? 'POST' : 'GET'; |
| await testEndpoint(endpoint, method, body); |
| }); |
|
|
| // Load stats on page load |
| fetchStats(); |
|
|
| // Refresh stats every 30 seconds |
| setInterval(fetchStats, 30000); |
|
|
| // Dark mode handling |
| if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) { |
| document.documentElement.classList.add('dark'); |
| } else { |
| document.documentElement.classList.remove('dark'); |
| } |
|
|
| // Scroll to test section |
| document.getElementById('test-api-btn')?.addEventListener('click', (e) => { |
| e.preventDefault(); |
| document.getElementById('test-api').scrollIntoView({ behavior: 'smooth' }); |
| }); |
|
|
| // Add page load animation |
| window.addEventListener('load', () => { |
| document.body.style.opacity = '0'; |
| document.body.style.transition = 'opacity 0.5s ease'; |
| setTimeout(() => { |
| document.body.style.opacity = '1'; |
| }, 100); |
| }); |
|
|
| // Show welcome toast |
| setTimeout(() => { |
| showToast('Welcome to Portfolio API! ๐', 'info'); |
| }, 1000); |
| </script> |
| </body> |
|
|
| </html> |