diff --git a/projects/challenge 11/portifolio(work_in_progress)/.test/.sql/portfolio.sql b/projects/challenge 11/portifolio(work_in_progress)/.test/.sql/portfolio.sql new file mode 100644 index 0000000..b085e70 --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/.test/.sql/portfolio.sql @@ -0,0 +1,24 @@ +-- Create database +CREATE DATABASE IF NOT EXISTS portfolio; +USE portfolio; + +-- Create projects table +CREATE TABLE IF NOT EXISTS projects ( + id INT AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL, + description TEXT, + image_url VARCHAR(255), + project_url VARCHAR(255), + tags VARCHAR(255), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Insert a sample project +INSERT INTO projects (title, description, image_url, project_url, tags) +VALUES ( + 'Sample Project', + 'This is a sample project description.', + 'assets/sample.jpg', + 'https://example.com', + 'html,css,school' +); \ No newline at end of file diff --git a/projects/challenge 11/portifolio(work_in_progress)/.test/.sql/update_projects.sql b/projects/challenge 11/portifolio(work_in_progress)/.test/.sql/update_projects.sql new file mode 100644 index 0000000..8d2252b --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/.test/.sql/update_projects.sql @@ -0,0 +1,5 @@ +-- Add long_description column to projects table +ALTER TABLE projects ADD COLUMN long_description TEXT AFTER description; + +-- Update existing projects with long descriptions (optional) +UPDATE projects SET long_description = description WHERE long_description IS NULL; \ No newline at end of file diff --git a/projects/challenge 11/portifolio(work_in_progress)/.test/test-dark-mode.html b/projects/challenge 11/portifolio(work_in_progress)/.test/test-dark-mode.html new file mode 100644 index 0000000..bb30a7b --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/.test/test-dark-mode.html @@ -0,0 +1,75 @@ + + + + + + Dark Mode Test + + + + + + + + + + + + + + + +
+

Dark Mode Test Page

+ +
+

Test Content

+

+ This is a test page to verify that the dark mode toggle button appears and works correctly. +

+

+ You should see a dark mode toggle button in the bottom-left corner of the screen. +

+
+ +
+ Back to Main Page +
+
+ + + + + + + \ No newline at end of file diff --git a/projects/challenge 11/portifolio(work_in_progress)/assets/favicon.svg b/projects/challenge 11/portifolio(work_in_progress)/assets/favicon.svg new file mode 100644 index 0000000..885b49a --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/assets/favicon.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/projects/challenge 11/portifolio(work_in_progress)/assets/img_68532b2c9db398.90652024.webp b/projects/challenge 11/portifolio(work_in_progress)/assets/img_68532b2c9db398.90652024.webp new file mode 100644 index 0000000..2359e98 Binary files /dev/null and b/projects/challenge 11/portifolio(work_in_progress)/assets/img_68532b2c9db398.90652024.webp differ diff --git a/projects/challenge 11/portifolio(work_in_progress)/assets/img_68532c22650974.25780946.webp b/projects/challenge 11/portifolio(work_in_progress)/assets/img_68532c22650974.25780946.webp new file mode 100644 index 0000000..c6526e9 Binary files /dev/null and b/projects/challenge 11/portifolio(work_in_progress)/assets/img_68532c22650974.25780946.webp differ diff --git a/projects/challenge 11/portifolio(work_in_progress)/assets/img_685332e2c19726.68679915.webp b/projects/challenge 11/portifolio(work_in_progress)/assets/img_685332e2c19726.68679915.webp new file mode 100644 index 0000000..271a26f Binary files /dev/null and b/projects/challenge 11/portifolio(work_in_progress)/assets/img_685332e2c19726.68679915.webp differ diff --git a/projects/challenge 11/portifolio(work_in_progress)/assets/img_68533428d7dbf7.04812047.webp b/projects/challenge 11/portifolio(work_in_progress)/assets/img_68533428d7dbf7.04812047.webp new file mode 100644 index 0000000..75b94d9 Binary files /dev/null and b/projects/challenge 11/portifolio(work_in_progress)/assets/img_68533428d7dbf7.04812047.webp differ diff --git a/projects/challenge 11/portifolio(work_in_progress)/assets/img_68533897b6e606.91354272.webp b/projects/challenge 11/portifolio(work_in_progress)/assets/img_68533897b6e606.91354272.webp new file mode 100644 index 0000000..1d6b018 Binary files /dev/null and b/projects/challenge 11/portifolio(work_in_progress)/assets/img_68533897b6e606.91354272.webp differ diff --git a/projects/challenge 11/portifolio(work_in_progress)/assets/img_68533a4fae17a2.61602173.webp b/projects/challenge 11/portifolio(work_in_progress)/assets/img_68533a4fae17a2.61602173.webp new file mode 100644 index 0000000..b4aab28 Binary files /dev/null and b/projects/challenge 11/portifolio(work_in_progress)/assets/img_68533a4fae17a2.61602173.webp differ diff --git a/projects/challenge 11/portifolio(work_in_progress)/assets/img_68533d573a8017.49535201.webp b/projects/challenge 11/portifolio(work_in_progress)/assets/img_68533d573a8017.49535201.webp new file mode 100644 index 0000000..db436b8 Binary files /dev/null and b/projects/challenge 11/portifolio(work_in_progress)/assets/img_68533d573a8017.49535201.webp differ diff --git a/projects/challenge 11/portifolio(work_in_progress)/assets/img_6853423c94f733.00653812.webp b/projects/challenge 11/portifolio(work_in_progress)/assets/img_6853423c94f733.00653812.webp new file mode 100644 index 0000000..dfed976 Binary files /dev/null and b/projects/challenge 11/portifolio(work_in_progress)/assets/img_6853423c94f733.00653812.webp differ diff --git a/projects/challenge 11/portifolio(work_in_progress)/assets/img_685343f1288b20.49230464.webp b/projects/challenge 11/portifolio(work_in_progress)/assets/img_685343f1288b20.49230464.webp new file mode 100644 index 0000000..b145588 Binary files /dev/null and b/projects/challenge 11/portifolio(work_in_progress)/assets/img_685343f1288b20.49230464.webp differ diff --git a/projects/challenge 11/portifolio(work_in_progress)/assets/pano_left.webp b/projects/challenge 11/portifolio(work_in_progress)/assets/pano_left.webp new file mode 100644 index 0000000..ad382c9 Binary files /dev/null and b/projects/challenge 11/portifolio(work_in_progress)/assets/pano_left.webp differ diff --git a/projects/challenge 11/portifolio(work_in_progress)/css/animations.css b/projects/challenge 11/portifolio(work_in_progress)/css/animations.css new file mode 100644 index 0000000..a15ea61 --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/css/animations.css @@ -0,0 +1,240 @@ +/* Custom animations and keyframes */ + +/* Fade in animation */ +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +/* Slide up animation */ +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Bounce in animation */ +@keyframes bounceIn { + 0% { + opacity: 0; + transform: scale(0.3); + } + 50% { + opacity: 1; + transform: scale(1.05); + } + 70% { + transform: scale(0.9); + } + 100% { + opacity: 1; + transform: scale(1); + } +} + +/* Pulse animation */ +@keyframes pulse { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } +} + +/* Shimmer effect for loading states */ +@keyframes shimmer { + 0% { + background-position: -200px 0; + } + 100% { + background-position: calc(200px + 100%) 0; + } +} + +/* Floating animation */ +@keyframes float { + 0%, 100% { + transform: translateY(0px); + } + 50% { + transform: translateY(-10px); + } +} + +/* Gradient animation */ +@keyframes gradientShift { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +} + +/* Typing animation */ +@keyframes typing { + from { + width: 0; + } + to { + width: 100%; + } +} + +/* Blink animation for cursor */ +@keyframes blink { + 0%, 50% { + opacity: 1; + } + 51%, 100% { + opacity: 0; + } +} + +/* Utility classes for animations */ +.animate-fade-in { + animation: fadeIn 0.6s ease-out; +} + +.animate-slide-up { + animation: slideUp 0.8s ease-out; +} + +.animate-bounce-in { + animation: bounceIn 1s ease-out; +} + +.animate-pulse { + animation: pulse 2s infinite; +} + +.animate-float { + animation: float 3s ease-in-out infinite; +} + +.animate-gradient { + background-size: 200% 200%; + animation: gradientShift 3s ease infinite; +} + +.animate-shimmer { + background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent); + background-size: 200px 100%; + animation: shimmer 1.5s infinite; +} + +/* Staggered animations for lists */ +.stagger-animation > * { + opacity: 0; + animation: slideUp 0.6s ease-out forwards; +} + +.stagger-animation > *:nth-child(1) { animation-delay: 0.1s; } +.stagger-animation > *:nth-child(2) { animation-delay: 0.2s; } +.stagger-animation > *:nth-child(3) { animation-delay: 0.3s; } +.stagger-animation > *:nth-child(4) { animation-delay: 0.4s; } +.stagger-animation > *:nth-child(5) { animation-delay: 0.5s; } +.stagger-animation > *:nth-child(6) { animation-delay: 0.6s; } + +/* Hover animations */ +.hover-lift { + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.hover-lift:hover { + transform: translateY(-5px); + box-shadow: 0 10px 25px rgba(0,0,0,0.15); +} + +.hover-scale { + transition: transform 0.3s ease; +} + +.hover-scale:hover { + transform: scale(1.05); +} + +.hover-glow { + transition: box-shadow 0.3s ease; +} + +.hover-glow:hover { + box-shadow: 0 0 20px rgba(79, 172, 254, 0.4); +} + +/* Loading spinner */ +.spinner { + width: 40px; + height: 40px; + border: 4px solid rgba(0, 0, 0, 0.1); + border-left-color: #4facfe; + border-radius: 50%; + animation: spin 1s linear infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +/* Text reveal animation */ +.text-reveal { + overflow: hidden; + position: relative; +} + +.text-reveal::after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: var(--bg-primary); + animation: textReveal 1.5s ease-out forwards; +} + +@keyframes textReveal { + 0% { + transform: translateX(0); + } + 100% { + transform: translateX(100%); + } +} + +/* Parallax effect */ +.parallax { + transform: translateZ(0); + will-change: transform; +} + +/* Smooth scrolling */ +html { + scroll-behavior: smooth; +} + +/* Reduced motion for accessibility */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} \ No newline at end of file diff --git a/projects/challenge 11/portifolio(work_in_progress)/css/styles.css b/projects/challenge 11/portifolio(work_in_progress)/css/styles.css new file mode 100644 index 0000000..8ad41d9 --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/css/styles.css @@ -0,0 +1,306 @@ +/* Custom CSS for enhanced styling with dark/light theme support */ + +/* Custom properties for theme colors */ +:root { + --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + --secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); + --accent-gradient: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); + --success-gradient: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); + + /* Light theme colors */ + --bg-primary: #ffffff; + --bg-secondary: #f8fafc; + --bg-card: #ffffff; + --text-primary: #1e293b; + --text-secondary: #64748b; + --border-color: #e2e8f0; + --shadow-color: rgba(0, 0, 0, 0.1); + --shadow-hover: rgba(0, 0, 0, 0.15); + + /* Animation variables */ + --transition-fast: 0.2s ease; + --transition-normal: 0.3s ease; + --transition-slow: 0.5s ease; +} + +/* Dark theme colors */ +.dark { + --bg-primary: #0f172a; + --bg-secondary: #1e293b; + --bg-card: #334155; + --text-primary: #f1f5f9; + --text-secondary: #94a3b8; + --border-color: #475569; + --shadow-color: rgba(0, 0, 0, 0.3); + --shadow-hover: rgba(0, 0, 0, 0.4); +} + +/* Global styles */ +* { + box-sizing: border-box; +} + +body { + background: var(--bg-primary); + color: var(--text-primary); + transition: background-color var(--transition-normal), color var(--transition-normal); + font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + line-height: 1.6; +} + +/* Enhanced header with gradient and animation */ +header { + background: var(--primary-gradient) !important; + position: relative; + overflow: hidden; +} + +header::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.1'%3E%3Ccircle cx='30' cy='30' r='2'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); + animation: float 20s ease-in-out infinite; +} + +@keyframes float { + 0%, 100% { transform: translateY(0px) rotate(0deg); } + 50% { transform: translateY(-20px) rotate(180deg); } +} + +/* Enhanced project cards */ +.project-card { + background: var(--bg-card); + border: 1px solid var(--border-color); + border-radius: 16px; + box-shadow: 0 4px 6px var(--shadow-color); + transition: all var(--transition-normal); + position: relative; + overflow: hidden; +} + +.project-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 4px; + background: var(--accent-gradient); + transform: scaleX(0); + transition: transform var(--transition-normal); +} + +.project-card:hover::before { + transform: scaleX(1); +} + +.project-card:hover { + transform: translateY(-8px) scale(1.02); + box-shadow: 0 20px 25px var(--shadow-hover); + border-color: transparent; +} + +/* Enhanced images */ +.project-image { + border-radius: 12px; + transition: transform var(--transition-normal); + position: relative; + overflow: hidden; +} + +.project-card:hover .project-image { + transform: scale(1.05); +} + +.project-image::after { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(45deg, transparent 30%, rgba(255,255,255,0.1) 50%, transparent 70%); + transform: translateX(-100%); + transition: transform var(--transition-slow); +} + +.project-card:hover .project-image::after { + transform: translateX(100%); +} + +/* Enhanced tags */ +.tag { + background: var(--accent-gradient); + color: white; + font-weight: 500; + border-radius: 20px; + padding: 4px 12px; + font-size: 0.75rem; + transition: all var(--transition-fast); + position: relative; + overflow: hidden; +} + +.tag::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent); + transition: left var(--transition-slow); +} + +.tag:hover::before { + left: 100%; +} + +.tag:hover { + transform: translateY(-2px); + box-shadow: 0 4px 8px rgba(0,0,0,0.2); +} + +/* Enhanced buttons */ +.btn-primary { + background: var(--primary-gradient); + color: white; + border: none; + border-radius: 12px; + padding: 12px 24px; + font-weight: 600; + transition: all var(--transition-normal); + position: relative; + overflow: hidden; +} + +.btn-primary::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent); + transition: left var(--transition-slow); +} + +.btn-primary:hover::before { + left: 100%; +} + +.btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 8px 16px rgba(0,0,0,0.2); +} + +/* Enhanced modal */ +.modal-overlay { + backdrop-filter: blur(8px); + background: rgba(0, 0, 0, 0.6); +} + +.modal-content { + background: var(--bg-card); + border-radius: 20px; + border: 1px solid var(--border-color); + box-shadow: 0 25px 50px var(--shadow-hover); +} + +/* Enhanced theme toggle */ +.theme-toggle { + background: var(--bg-card); + border: 2px solid var(--border-color); + border-radius: 50%; + box-shadow: 0 4px 12px var(--shadow-color); + transition: all var(--transition-normal); +} + +.theme-toggle:hover { + transform: scale(1.1) rotate(180deg); + box-shadow: 0 8px 20px var(--shadow-hover); +} + +/* Loading animation */ +.loading { + display: inline-block; + width: 20px; + height: 20px; + border: 3px solid var(--border-color); + border-radius: 50%; + border-top-color: var(--primary-gradient); + animation: spin 1s ease-in-out infinite; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +/* Enhanced typography */ +h1, h2, h3 { + background: var(--primary-gradient); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +header h1 { + color: #f0f6ff; + background: none; + -webkit-background-clip: initial; + -webkit-text-fill-color: initial; +} + +/* Scrollbar styling */ +::-webkit-scrollbar { + width: 8px; +} + +::-webkit-scrollbar-track { + background: var(--bg-secondary); +} + +::-webkit-scrollbar-thumb { + background: var(--accent-gradient); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--secondary-gradient); +} + +/* Responsive enhancements */ +@media (max-width: 768px) { + .project-card:hover { + transform: translateY(-4px) scale(1.01); + } + + .theme-toggle:hover { + transform: scale(1.05) rotate(90deg); + } +} + +/* Focus states for accessibility */ +button:focus, +a:focus { + outline: 2px solid var(--accent-gradient); + outline-offset: 2px; +} + +/* Print styles */ +@media print { + .theme-toggle, + .modal-overlay { + display: none !important; + } + + .project-card { + break-inside: avoid; + box-shadow: none; + border: 1px solid #ccc; + } +} \ No newline at end of file diff --git a/projects/challenge 11/portifolio(work_in_progress)/db/add_project.php b/projects/challenge 11/portifolio(work_in_progress)/db/add_project.php new file mode 100644 index 0000000..4a427b6 --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/db/add_project.php @@ -0,0 +1,159 @@ +Image upload failed.'; + } + } else if (!empty($_POST['image_url'])) { + $image_url = $_POST['image_url']; + } + if (!$message) { + try { + $pdo = get_pdo(); + $stmt = $pdo->prepare('INSERT INTO projects (title, description, long_description, image_url, project_url, tags) VALUES (?, ?, ?, ?, ?, ?)'); + $stmt->execute([$title, $description, $long_description, $image_url, $project_url, $tags]); + $message = '
Project added successfully!
'; + } catch (Exception $e) { + $message = '
Error: ' . htmlspecialchars($e->getMessage()) . '
'; + } + } +} +?> + + + + + + Add Project + + + + + + + + + + + + + + + + + + + + + + + + Back to Home + + +
+
+
+

Add New Project

+

Create a new project for your portfolio

+
+ + + + + Back to Projects + +
+ + + +
+
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+ +
+
+ + +

Upload an image file (JPG, PNG, GIF)

+
+
+ + +

Or provide a URL to an image

+
+
+ +
+ + +

Separate tags with commas (e.g., HTML, CSS, JavaScript)

+
+ +
+ + Cancel +
+
+
+ + + + + \ No newline at end of file diff --git a/projects/challenge 11/portifolio(work_in_progress)/db/index.php b/projects/challenge 11/portifolio(work_in_progress)/db/index.php new file mode 100644 index 0000000..a716fd6 --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/db/index.php @@ -0,0 +1,255 @@ +prepare('DELETE FROM projects WHERE id = ?')->execute([$id]); + $message = '
Project deleted.
'; + } catch (Exception $e) { + $message = '
Error: ' . htmlspecialchars($e->getMessage()) . '
'; + } +} + +// Handle update +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['edit_id'])) { + $id = intval($_POST['edit_id']); + $title = $_POST['title'] ?? ''; + $description = $_POST['description'] ?? ''; + $long_description = $_POST['long_description'] ?? ''; + $project_url = $_POST['project_url'] ?? ''; + $tags = $_POST['tags'] ?? ''; + $image_url = $_POST['image_url'] ?? ''; + // Handle image upload + if (isset($_FILES['image_file']) && $_FILES['image_file']['error'] === UPLOAD_ERR_OK) { + $ext = pathinfo($_FILES['image_file']['name'], PATHINFO_EXTENSION); + $filename = uniqid('img_', true) . '.' . strtolower($ext); + $target = '/var/www/alvnx.xyz/public_html/assets/' . $filename; + if (move_uploaded_file($_FILES['image_file']['tmp_name'], $target)) { + $image_url = 'assets/' . $filename; + } else { + $message = '
Image upload failed.
'; + } + } + if (!$message) { + try { + $pdo = get_pdo(); + $stmt = $pdo->prepare('UPDATE projects SET title=?, description=?, long_description=?, image_url=?, project_url=?, tags=? WHERE id=?'); + $stmt->execute([$title, $description, $long_description, $image_url, $project_url, $tags, $id]); + $message = '
Project updated.
'; + } catch (Exception $e) { + $message = '
Error: ' . htmlspecialchars($e->getMessage()) . '
'; + } + } +} + +// Fetch all projects +try { + $pdo = get_pdo(); + $projects = $pdo->query('SELECT * FROM projects ORDER BY created_at DESC')->fetchAll(); +} catch (Exception $e) { + $projects = []; + $message = '
Error: ' . htmlspecialchars($e->getMessage()) . '
'; +} + +// If editing, fetch project +$edit_project = null; +if (isset($_GET['edit'])) { + $id = intval($_GET['edit']); + foreach ($projects as $p) { + if ($p['id'] == $id) { + $edit_project = $p; + break; + } + } +} +?> + + + + + + Manage Projects + + + + + + + + + + + + + + + + + + + + + + + + Back to Home + + +
+ +
+
+

Manage Projects

+

Add, edit, and manage your portfolio projects

+
+ +
+ + + + + + +
+

+ + + + Edit Project +

+
+ +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + + + +
+ No image +
+ +
+
+ + +
+
+
+ + +
+
+ + +

Separate tags with commas

+
+
+ + Cancel +
+
+
+ + + +
+ +
+ + + +

+

+ +
+ + + +
+ +
+ + View Project → + +
+ Edit + Delete +
+
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/projects/challenge 11/portifolio(work_in_progress)/db/login.php b/projects/challenge 11/portifolio(work_in_progress)/db/login.php new file mode 100644 index 0000000..c700b5a --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/db/login.php @@ -0,0 +1,129 @@ + + + + + + + Login - Manage Projects + + + + + + + + + + + + + + + + + + + + + + + + Back to Home + + + +
+
+

Sign In

+

Access your project management dashboard

+
+ + +
+
+ + + + +
+
+ + +
+
+ +
+ + + + +
+
+ +
+ +
+ + + + +
+
+ + +
+ +
+ + + + + \ No newline at end of file diff --git a/projects/challenge 11/portifolio(work_in_progress)/index.php b/projects/challenge 11/portifolio(work_in_progress)/index.php new file mode 100644 index 0000000..9128d0c --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/index.php @@ -0,0 +1,136 @@ + + + + + + + My School Projects Portfolio + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+

+ My School Projects Portfolio +

+

+ A showcase of all my school projects, loaded from a database. +

+
+
+ + + + Dynamic content +
+
+ + + + Responsive design +
+
+
+ +
+
+
+ + +
+ + Manage + +
+
+ + +
+ +
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/projects/challenge 11/portifolio(work_in_progress)/js/dark-mode.js b/projects/challenge 11/portifolio(work_in_progress)/js/dark-mode.js new file mode 100644 index 0000000..50975b9 --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/js/dark-mode.js @@ -0,0 +1,143 @@ +// Dark mode functionality with enhanced animations +function initDarkMode() { + + // Check for saved theme preference or use system preference + const savedTheme = localStorage.getItem('theme'); + const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; + + if (savedTheme === 'dark' || (!savedTheme && systemPrefersDark)) { + document.documentElement.classList.add('dark'); + } else { + + } + + // Remove existing toggle button if it exists + const existingButton = document.getElementById('theme-toggle'); + if (existingButton) { + existingButton.remove(); + } + + // Create and add the theme toggle button with fallback styling + const toggleButton = document.createElement('button'); + toggleButton.id = 'theme-toggle'; + toggleButton.setAttribute('aria-label', 'Toggle dark mode'); + + // Use inline styles as fallback + const isDark = document.documentElement.classList.contains('dark'); + toggleButton.style.cssText = ` + position: fixed; + bottom: 1rem; + left: 1rem; + z-index: 9999; + background: ${isDark ? '#334155' : '#ffffff'}; + border: 2px solid ${isDark ? '#475569' : '#e2e8f0'}; + border-radius: 50%; + padding: 0.75rem; + box-shadow: 0 4px 12px ${isDark ? 'rgba(0,0,0,0.3)' : 'rgba(0,0,0,0.1)'}; + transition: all 0.3s ease; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + width: 3rem; + height: 3rem; + `; + + toggleButton.innerHTML = ` + + + + + `; + + document.body.appendChild(toggleButton); + + // Add click handler with enhanced animation + toggleButton.addEventListener('click', () => { + + // Add click animation + toggleButton.style.transform = 'scale(0.9)'; + setTimeout(() => { + toggleButton.style.transform = ''; + }, 150); + + // Toggle theme + const newIsDark = document.documentElement.classList.toggle('dark'); + localStorage.setItem('theme', newIsDark ? 'dark' : 'light'); + + // Update button styles + toggleButton.style.background = newIsDark ? '#334155' : '#ffffff'; + toggleButton.style.borderColor = newIsDark ? '#475569' : '#e2e8f0'; + toggleButton.style.boxShadow = newIsDark ? '0 4px 12px rgba(0,0,0,0.3)' : '0 4px 12px rgba(0,0,0,0.1)'; + + const svg = toggleButton.querySelector('svg'); + svg.style.color = newIsDark ? '#f1f5f9' : '#1e293b'; + + const sunIcon = toggleButton.querySelector('.sun-icon'); + const moonIcon = toggleButton.querySelector('.moon-icon'); + + if (newIsDark) { + sunIcon.style.display = 'none'; + moonIcon.style.display = 'block'; + } else { + sunIcon.style.display = 'block'; + moonIcon.style.display = 'none'; + } + + // Add theme transition effect + addThemeTransitionEffect(); + }); + + // Listen for system theme changes + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => { + if (!localStorage.getItem('theme')) { + if (e.matches) { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + } + }); +} + +function addThemeTransitionEffect() { + // Create a temporary overlay for smooth transition + const overlay = document.createElement('div'); + overlay.style.cssText = ` + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: ${document.documentElement.classList.contains('dark') ? '#0f172a' : '#ffffff'}; + z-index: 9998; + opacity: 0; + pointer-events: none; + transition: opacity 0.3s ease; + `; + document.body.appendChild(overlay); + + // Fade in and out + requestAnimationFrame(() => { + overlay.style.opacity = '0.1'; + setTimeout(() => { + overlay.style.opacity = '0'; + setTimeout(() => { + if (document.body.contains(overlay)) { + document.body.removeChild(overlay); + } + }, 300); + }, 150); + }); +} + +// Initialize dark mode when the DOM is loaded +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initDarkMode); +} else { + // DOM is already loaded + initDarkMode(); +} + +// Also try to initialize after a short delay to ensure everything is ready +setTimeout(initDarkMode, 100); \ No newline at end of file diff --git a/projects/challenge 11/portifolio(work_in_progress)/js/main.js b/projects/challenge 11/portifolio(work_in_progress)/js/main.js new file mode 100644 index 0000000..de691d2 --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/js/main.js @@ -0,0 +1,188 @@ +document.addEventListener('DOMContentLoaded', () => { + const container = document.getElementById('projects'); + + // Add loading state with enhanced spinner + container.innerHTML = '

Loading projects...

'; + + // Create modal element with enhanced styling + const modal = document.createElement('div'); + modal.className = 'modal-overlay fixed inset-0 hidden items-center justify-center z-50 transition-opacity duration-300'; + modal.innerHTML = ` + + `; + document.body.appendChild(modal); + + // Add modal functions to window + window.openModal = (project) => { + const modalTitle = modal.querySelector('h2'); + const modalImage = modal.querySelector('.modal-image'); + const modalDescription = modal.querySelector('.modal-description'); + const modalTags = modal.querySelector('.modal-tags'); + const modalLinks = modal.querySelector('.modal-links'); + const modalContent = modal.querySelector('.modal-content'); + + modalTitle.textContent = project.title; + + if (project.image_url) { + modalImage.innerHTML = `${project.title}`; + } else { + modalImage.innerHTML = '
'; + } + + modalDescription.innerHTML = ` +

${project.description || ''}

+ ${project.long_description ? `

${project.long_description}

` : ''} + `; + + if (project.tags) { + modalTags.innerHTML = ` +
+ ${project.tags.split(',').map(tag => + `${tag.trim()}` + ).join('')} +
+ `; + } else { + modalTags.innerHTML = ''; + } + + modalLinks.innerHTML = project.project_url ? + `View Project →` : ''; + + // Show modal with animation + modal.classList.remove('hidden'); + modal.classList.add('flex'); + document.body.style.overflow = 'hidden'; + + // Trigger animation + requestAnimationFrame(() => { + modalContent.classList.remove('scale-95', 'opacity-0'); + modalContent.classList.add('scale-100', 'opacity-100'); + }); + }; + + window.closeModal = () => { + const modalContent = modal.querySelector('.modal-content'); + + // Start closing animation + modalContent.classList.remove('scale-100', 'opacity-100'); + modalContent.classList.add('scale-95', 'opacity-0'); + + // Wait for animation to finish before hiding + setTimeout(() => { + modal.classList.add('hidden'); + modal.classList.remove('flex'); + document.body.style.overflow = ''; + }, 300); + }; + + // Close modal when clicking outside + modal.addEventListener('click', (e) => { + if (e.target === modal) { + closeModal(); + } + }); + + // Close modal with Escape key + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && !modal.classList.contains('hidden')) { + closeModal(); + } + }); + + // Enhanced project fetching with error handling + fetch('php/get_projects.php') + .then(res => { + if (!res.ok) { + throw new Error(`HTTP error! status: ${res.status}`); + } + return res.json(); + }) + .then(projects => { + if (!Array.isArray(projects) || projects.length === 0) { + container.innerHTML = ` +
+
+ + + +
+

No projects found.

+

Projects will appear here once added.

+
`; + return; + } + + container.innerHTML = ''; + + // Add projects with CSS animations + projects.forEach((project) => { + const card = document.createElement('div'); + card.className = 'project-card p-5 flex flex-col cursor-pointer hover-lift'; + + card.onclick = () => openModal(project); + + if (project.image_url) { + card.innerHTML += `${project.title}`; + } else { + card.innerHTML += `
`; + } + + card.innerHTML += ` +

${project.title}

+

${project.description || ''}

+ ${project.tags ? `
${project.tags.split(',').map(tag => `${tag.trim()}`).join('')}
` : ''} + ${project.project_url ? `View Project →` : ''} + `; + + container.appendChild(card); + }); + }) + .catch(err => { + console.error('Error fetching projects:', err); + container.innerHTML = ` +
+
+ + + +
+

Failed to load projects.

+

Error: ${err.message}

+ +
`; + }); +}); + +// Add fadeInUp animation +const style = document.createElement('style'); +style.textContent = ` + @keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } + } +`; +document.head.appendChild(style); \ No newline at end of file diff --git a/projects/challenge 11/portifolio(work_in_progress)/php/config.php b/projects/challenge 11/portifolio(work_in_progress)/php/config.php new file mode 100644 index 0000000..fa2ba77 --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/php/config.php @@ -0,0 +1,18 @@ + PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, +]; +function get_pdo() { + global $dsn, $user, $pass, $options; + return new PDO($dsn, $user, $pass, $options); +} \ No newline at end of file diff --git a/projects/challenge 11/portifolio(work_in_progress)/php/get_projects.php b/projects/challenge 11/portifolio(work_in_progress)/php/get_projects.php new file mode 100644 index 0000000..93a1797 --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/php/get_projects.php @@ -0,0 +1,21 @@ +query('SELECT id, title, description, long_description, image_url, project_url, tags, created_at FROM projects ORDER BY created_at DESC'); + $projects = $stmt->fetchAll(PDO::FETCH_ASSOC); + echo json_encode($projects); +} catch (Exception $e) { + http_response_code(500); + echo json_encode(['error' => $e->getMessage()]); +} \ No newline at end of file diff --git a/projects/challenge 11/portifolio(work_in_progress)/php/phpinfo.php b/projects/challenge 11/portifolio(work_in_progress)/php/phpinfo.php new file mode 100644 index 0000000..e974c40 --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/php/phpinfo.php @@ -0,0 +1 @@ +"; + + // Test query + $stmt = $pdo->query('SELECT COUNT(*) as count FROM projects'); + $result = $stmt->fetch(); + echo "Number of projects in database: " . $result['count']; +} catch (Exception $e) { + echo "Error: " . $e->getMessage(); +} \ No newline at end of file diff --git a/projects/challenge 11/portifolio(work_in_progress)/robots.txt b/projects/challenge 11/portifolio(work_in_progress)/robots.txt new file mode 100644 index 0000000..a0c656f --- /dev/null +++ b/projects/challenge 11/portifolio(work_in_progress)/robots.txt @@ -0,0 +1,160 @@ +# Allow all well-behaved bots +User-agent: * +Disallow: + +# Block specific bots +User-agent: AI2Bot +Disallow: /db + +User-agent: Ai2Bot-Dolma +Disallow: /db + +User-agent: aiHitBot +Disallow: /db + +User-agent: Amazonbot +Disallow: /db + +User-agent: anthropic-ai +Disallow: /db + +User-agent: Applebot +Disallow: /db + +User-agent: Applebot-Extended +Disallow: /db + +User-agent: Brightbot 1.0 +Disallow: /db + +User-agent: Bytespider +Disallow: /db + +User-agent: CCBot +Disallow: /db + +User-agent: ChatGPT-User +Disallow: /db + +User-agent: Claude-Web +Disallow: /db + +User-agent: ClaudeBot +Disallow: /db + +User-agent: cohere-ai +Disallow: /db + +User-agent: cohere-training-data-crawler +Disallow: /db + +User-agent: Cotoyogi +Disallow: /db + +User-agent: Crawlspace +Disallow: /db + +User-agent: Diffbot +Disallow: /db + +User-agent: DuckAssistBot +Disallow: /db + +User-agent: FacebookBot +Disallow: /db + +User-agent: Factset_spyderbot +Disallow: /db + +User-agent: FirecrawlAgent +Disallow: /db + +User-agent: FriendlyCrawler +Disallow: /db + +User-agent: GPTBot +Disallow: /db + +User-agent: iaskspider/2.0 +Disallow: /db + +User-agent: ICC-Crawler +Disallow: /db + +User-agent: ImagesiftBot +Disallow: /db + +User-agent: img2dataset +Disallow: /db + +User-agent: imgproxy +Disallow: /db + +User-agent: ISSCyberRiskCrawler +Disallow: /db + +User-agent: Kangaroo Bot +Disallow: /db + +User-agent: Meta-ExternalAgent +Disallow: /db + +User-agent: Meta-ExternalFetcher +Disallow: /db + +User-agent: NovaAct +Disallow: /db + +User-agent: OAI-SearchBot +Disallow: /db + +User-agent: omgili +Disallow: /db + +User-agent: omgilibot +Disallow: /db + +User-agent: Operator +Disallow: /db + +User-agent: PanguBot +Disallow: /db + +User-agent: Perplexity-User +Disallow: /db + +User-agent: PerplexityBot +Disallow: /db + +User-agent: PetalBot +Disallow: /db + +User-agent: Scrapy +Disallow: /db + +User-agent: SemrushBot-OCOB +Disallow: /db + +User-agent: SemrushBot-SWA +Disallow: /db + +User-agent: Sidetrade indexer bot +Disallow: /db + +User-agent: TikTokSpider +Disallow: /db + +User-agent: Timpibot +Disallow: /db + +User-agent: VelenPublicWebCrawler +Disallow: /db + +User-agent: Webzio-Extended +Disallow: /db + +User-agent: YouBot +Disallow: /db + +# Sitemap location +Sitemap: https://alvnx.xyz/sitemap.xml