Latest Updated Pages
E2E Test Suite / Critical User Journeys (push) Has been skipped
E2E Test Suite / API Integration Tests (push) Has been skipped
Deploy to Production / Build & Verify (push) Failing after 13s
Ping Search Engines / Notify Search Engines (push) Successful in 3s
Deploy to Production / Pre-Deploy Tests (push) Has been skipped
Deploy to Production / Deploy to Railway (push) Has been skipped
Deploy to Production / Deploy to Render (push) Has been skipped
Deploy to Production / Deploy to VPS (PM2) (push) Has been skipped
Deploy to Production / Deploy to Fly.io (push) Has been skipped
Deploy to Production / Post-Deploy Verification (push) Has been skipped
Deploy to Production / Notify on Failure (push) Successful in 1s
E2E Test Suite / Smoke Tests (P0) (push) Failing after 9m36s
E2E Test Suite / Form Interaction Tests (push) Failing after 12m6s
E2E Test Suite / Destructive & Chaos Tests (push) Failing after 11m46s
E2E Test Suite / Cross-Browser Regression (chromium) (push) Failing after 9m31s
E2E Test Suite / Cross-Browser Regression (firefox) (push) Failing after 11m5s
E2E Test Suite / Cross-Browser Regression (webkit) (push) Failing after 15m24s
E2E Test Suite / Security Header Tests (push) Failing after 7m55s
E2E Test Suite / Test Report Summary (push) Failing after 6s
E2E Test Suite / Mobile Device Tests (push) Failing after 3h12m28s
Uptime Monitor / Health & Response Time (push) Successful in 5s
Uptime Monitor / SSL Certificate (push) Successful in 3s
Uptime Monitor / Send Alerts (push) Has been skipped
Uptime Monitor / Record Uptime Success (push) Successful in 2s

This commit is contained in:
2026-03-22 14:37:17 +05:30
parent d402256547
commit 0614ae6f85
80 changed files with 11667 additions and 687 deletions
+40 -42
View File
@@ -1,7 +1,6 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
import SEO from '../components/SEO.astro';
import Footer from '../components/Footer.astro';
const projects = [
{
@@ -279,11 +278,11 @@ const featuredProjects = projects.filter(p => p.featured);
</section>
<!-- Featured Projects -->
<section class="bg-white py-16 lg:py-20">
<section class="bg-white dark:bg-secondary-900 py-16 lg:py-20">
<div class="container-wrapper">
<div class="mb-10 reveal-on-scroll">
<span class="text-primary-500 font-semibold text-sm uppercase tracking-wider">Highlighted Work</span>
<h2 class="mt-2 text-3xl font-bold text-secondary-900 sm:text-4xl">Featured Projects</h2>
<h2 class="mt-2 text-3xl font-bold text-secondary-900 dark:text-secondary-100 sm:text-4xl">Featured Projects</h2>
</div>
<div class="grid gap-8 lg:grid-cols-3 reveal-on-scroll reveal-delay-1">
{featuredProjects.map((project, idx) => (
@@ -352,7 +351,7 @@ const featuredProjects = projects.filter(p => p.featured);
</section>
<!-- Filter & Grid Section -->
<section class="bg-secondary-50 py-16 lg:py-24">
<section class="bg-secondary-50 dark:bg-secondary-900 py-16 lg:py-24">
<div class="container-wrapper">
<!-- Search + Filter Controls -->
<div class="mb-10 space-y-6 reveal-on-scroll">
@@ -368,7 +367,7 @@ const featuredProjects = projects.filter(p => p.featured);
id="project-search"
type="search"
placeholder="Search by project name or technology..."
class="w-full rounded-xl border border-secondary-200 bg-white py-3 pl-12 pr-4 text-secondary-800 shadow-sm placeholder-secondary-400 focus:border-primary-400 focus:outline-none focus:ring-2 focus:ring-primary-400/20 transition-colors"
class="w-full rounded-xl border border-secondary-200 dark:border-secondary-600 bg-white dark:bg-secondary-800 py-3 pl-12 pr-4 text-secondary-800 dark:text-secondary-100 shadow-sm placeholder-secondary-400 dark:placeholder-secondary-500 focus:border-primary-400 focus:outline-none focus:ring-2 focus:ring-primary-400/20 transition-colors"
autocomplete="off"
/>
<div id="search-clear" class="absolute inset-y-0 right-0 hidden items-center pr-4">
@@ -393,7 +392,7 @@ const featuredProjects = projects.filter(p => p.featured);
</button>
<button
data-filter="web"
class="filter-btn rounded-full bg-white px-6 py-2.5 font-semibold text-secondary-600 shadow-sm transition-all duration-300 hover:bg-secondary-100 hover:shadow-md focus:outline-none focus:ring-2 focus:ring-primary-400 focus:ring-offset-2"
class="filter-btn rounded-full bg-white dark:bg-secondary-800 px-6 py-2.5 font-semibold text-secondary-600 dark:text-secondary-400 shadow-sm transition-all duration-300 hover:bg-secondary-100 dark:hover:bg-secondary-700 hover:shadow-md focus:outline-none focus:ring-2 focus:ring-primary-400 focus:ring-offset-2"
role="tab"
aria-selected="false"
aria-controls="projects-grid"
@@ -402,7 +401,7 @@ const featuredProjects = projects.filter(p => p.featured);
</button>
<button
data-filter="mobile"
class="filter-btn rounded-full bg-white px-6 py-2.5 font-semibold text-secondary-600 shadow-sm transition-all duration-300 hover:bg-secondary-100 hover:shadow-md focus:outline-none focus:ring-2 focus:ring-primary-400 focus:ring-offset-2"
class="filter-btn rounded-full bg-white dark:bg-secondary-800 px-6 py-2.5 font-semibold text-secondary-600 dark:text-secondary-400 shadow-sm transition-all duration-300 hover:bg-secondary-100 dark:hover:bg-secondary-700 hover:shadow-md focus:outline-none focus:ring-2 focus:ring-primary-400 focus:ring-offset-2"
role="tab"
aria-selected="false"
aria-controls="projects-grid"
@@ -411,7 +410,7 @@ const featuredProjects = projects.filter(p => p.featured);
</button>
<button
data-filter="ai"
class="filter-btn rounded-full bg-white px-6 py-2.5 font-semibold text-secondary-600 shadow-sm transition-all duration-300 hover:bg-secondary-100 hover:shadow-md focus:outline-none focus:ring-2 focus:ring-primary-400 focus:ring-offset-2"
class="filter-btn rounded-full bg-white dark:bg-secondary-800 px-6 py-2.5 font-semibold text-secondary-600 dark:text-secondary-400 shadow-sm transition-all duration-300 hover:bg-secondary-100 dark:hover:bg-secondary-700 hover:shadow-md focus:outline-none focus:ring-2 focus:ring-primary-400 focus:ring-offset-2"
role="tab"
aria-selected="false"
aria-controls="projects-grid"
@@ -424,7 +423,7 @@ const featuredProjects = projects.filter(p => p.featured);
<div class="text-center">
<button
id="tech-filter-toggle"
class="inline-flex items-center gap-2 text-sm font-medium text-secondary-500 hover:text-secondary-700 transition-colors focus:outline-none"
class="inline-flex items-center gap-2 text-sm font-medium text-secondary-500 dark:text-secondary-400 hover:text-secondary-700 dark:hover:text-secondary-200 transition-colors focus:outline-none"
aria-expanded="false"
aria-controls="tech-filter-panel"
>
@@ -451,7 +450,7 @@ const featuredProjects = projects.filter(p => p.featured);
{allTechs.map((tech) => (
<button
data-tech={tech}
class="tech-btn rounded-full bg-white px-4 py-1.5 text-xs font-semibold text-secondary-600 shadow-sm transition-all duration-200 hover:bg-secondary-100 focus:outline-none focus:ring-2 focus:ring-secondary-400"
class="tech-btn rounded-full bg-white dark:bg-secondary-800 px-4 py-1.5 text-xs font-semibold text-secondary-600 dark:text-secondary-400 shadow-sm transition-all duration-200 hover:bg-secondary-100 dark:hover:bg-secondary-700 focus:outline-none focus:ring-2 focus:ring-secondary-400"
>
{tech}
</button>
@@ -460,13 +459,13 @@ const featuredProjects = projects.filter(p => p.featured);
</div>
<!-- Active filter indicator + count -->
<div class="flex items-center justify-between text-sm text-secondary-500">
<div class="flex items-center justify-between text-sm text-secondary-500 dark:text-secondary-400">
<span id="results-count" aria-live="polite" aria-atomic="true">
Showing <strong id="count-num" class="text-secondary-800">{projects.length}</strong> projects
Showing <strong id="count-num" class="text-secondary-800 dark:text-secondary-100">{projects.length}</strong> projects
</span>
<button
id="clear-filters"
class="hidden text-primary-600 hover:text-primary-700 font-medium transition-colors focus:outline-none"
class="hidden text-primary-600 dark:text-primary-400 hover:text-primary-700 dark:hover:text-primary-300 font-medium transition-colors focus:outline-none"
>
Clear all filters
</button>
@@ -482,7 +481,7 @@ const featuredProjects = projects.filter(p => p.featured);
>
{projects.map((project) => (
<article
class="project-card group relative overflow-hidden rounded-2xl bg-white shadow-md transition-all duration-500 hover:-translate-y-2 hover:shadow-2xl cursor-pointer reveal-on-scroll"
class="project-card group relative overflow-hidden rounded-2xl bg-white dark:bg-secondary-800 shadow-md transition-all duration-500 hover:-translate-y-2 hover:shadow-2xl cursor-pointer reveal-on-scroll"
data-category={project.category}
data-project-id={project.id}
data-tech={project.techStack.join(',')}
@@ -542,33 +541,33 @@ const featuredProjects = projects.filter(p => p.featured);
<!-- Content -->
<div class="p-6">
<h3 class="text-xl font-bold text-secondary-900 transition-colors group-hover:text-primary">
<h3 class="text-xl font-bold text-secondary-900 dark:text-secondary-100 transition-colors group-hover:text-primary dark:group-hover:text-primary-400">
{project.title}
</h3>
<p class="mt-2 line-clamp-2 text-sm text-secondary-600">
<p class="mt-2 line-clamp-2 text-sm text-secondary-600 dark:text-secondary-400">
{project.description}
</p>
<!-- Key metric pill -->
<div class="mt-3 inline-flex items-center gap-1.5 rounded-full bg-secondary-100 px-3 py-1">
<div class="mt-3 inline-flex items-center gap-1.5 rounded-full bg-secondary-100 dark:bg-secondary-700 px-3 py-1">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5 text-emerald-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6" />
</svg>
<span class="text-xs font-semibold text-secondary-700">{project.stats[0].value} {project.stats[0].label}</span>
<span class="text-xs font-semibold text-secondary-700 dark:text-secondary-300">{project.stats[0].value} {project.stats[0].label}</span>
</div>
<!-- Tech Stack Tags -->
<div class="mt-4 flex flex-wrap gap-1.5">
{project.techStack.map((tech) => (
<span class="rounded-md bg-secondary-100 px-2.5 py-1 text-xs font-medium text-secondary-700 hover:bg-primary-50 hover:text-primary-700 transition-colors cursor-pointer tech-tag" data-tech-tag={tech}>
<span class="rounded-md bg-secondary-100 dark:bg-secondary-700 px-2.5 py-1 text-xs font-medium text-secondary-700 dark:text-secondary-300 hover:bg-primary-50 dark:hover:bg-primary-900/30 hover:text-primary-700 dark:hover:text-primary-400 transition-colors cursor-pointer tech-tag" data-tech-tag={tech}>
{tech}
</span>
))}
</div>
<!-- Footer row: client + arrow -->
<div class="mt-5 flex items-center justify-between border-t border-secondary-100 pt-4">
<span class="text-xs text-secondary-500">{project.client}</span>
<div class="mt-5 flex items-center justify-between border-t border-secondary-100 dark:border-secondary-700 pt-4">
<span class="text-xs text-secondary-500 dark:text-secondary-400">{project.client}</span>
<span class="inline-flex items-center gap-1 text-xs font-semibold text-primary transition-all group-hover:gap-2">
Details
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
@@ -583,13 +582,13 @@ const featuredProjects = projects.filter(p => p.featured);
<!-- No Results Message -->
<div id="no-results" class="hidden py-20 text-center">
<div class="mx-auto h-20 w-20 rounded-2xl bg-secondary-100 flex items-center justify-center mb-6">
<svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10 text-secondary-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<div class="mx-auto h-20 w-20 rounded-2xl bg-secondary-100 dark:bg-secondary-800 flex items-center justify-center mb-6">
<svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10 text-secondary-300 dark:text-secondary-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</div>
<p class="text-lg font-semibold text-secondary-700">No projects match your filters</p>
<p class="mt-2 text-secondary-500">Try adjusting your search or filter criteria.</p>
<p class="text-lg font-semibold text-secondary-700 dark:text-secondary-300">No projects match your filters</p>
<p class="mt-2 text-secondary-500 dark:text-secondary-400">Try adjusting your search or filter criteria.</p>
<button
id="reset-filters-btn"
class="mt-6 inline-flex items-center gap-2 rounded-lg bg-primary px-6 py-2.5 font-semibold text-white transition-all hover:bg-primary-600 focus:outline-none focus:ring-2 focus:ring-primary-400 focus:ring-offset-2"
@@ -608,7 +607,7 @@ const featuredProjects = projects.filter(p => p.featured);
aria-modal="true"
aria-labelledby="modal-title"
>
<div class="modal-content relative w-full max-w-5xl scale-95 transform rounded-2xl bg-white opacity-0 shadow-2xl transition-all duration-300 my-4">
<div class="modal-content relative w-full max-w-5xl scale-95 transform rounded-2xl bg-white dark:bg-secondary-800 opacity-0 shadow-2xl transition-all duration-300 my-4">
<!-- Close Button -->
<button
id="close-modal-btn"
@@ -656,7 +655,6 @@ const featuredProjects = projects.filter(p => p.featured);
</div>
</section>
<Footer />
</BaseLayout>
<script define:vars={{ projects }}>
@@ -963,11 +961,11 @@ const featuredProjects = projects.filter(p => p.featured);
<!-- Body -->
<div class="p-6 sm:p-8 lg:p-10">
<!-- Stats row -->
<div class="grid grid-cols-3 gap-4 mb-8 p-5 bg-secondary-50 rounded-2xl">
<div class="grid grid-cols-3 gap-4 mb-8 p-5 bg-secondary-50 dark:bg-secondary-700/50 rounded-2xl">
${project.stats.map((stat: any) => `
<div class="text-center">
<p class="text-2xl sm:text-3xl font-bold text-secondary-900">${stat.value}</p>
<p class="text-xs text-secondary-500 mt-1">${stat.label}</p>
<p class="text-2xl sm:text-3xl font-bold text-secondary-900 dark:text-secondary-100">${stat.value}</p>
<p class="text-xs text-secondary-500 dark:text-secondary-400 mt-1">${stat.label}</p>
</div>
`).join('')}
</div>
@@ -975,34 +973,34 @@ const featuredProjects = projects.filter(p => p.featured);
<!-- Two column layout: overview + challenge/solution -->
<div class="grid gap-8 lg:grid-cols-2 mb-8">
<div>
<h3 class="text-sm font-semibold uppercase tracking-wide text-secondary-400 mb-3">Project Overview</h3>
<p class="text-secondary-700 leading-relaxed text-sm">${project.fullDescription}</p>
<h3 class="text-sm font-semibold uppercase tracking-wide text-secondary-400 dark:text-secondary-500 mb-3">Project Overview</h3>
<p class="text-secondary-700 dark:text-secondary-300 leading-relaxed text-sm">${project.fullDescription}</p>
</div>
<div class="space-y-5">
<div>
<h3 class="text-sm font-semibold uppercase tracking-wide text-secondary-400 mb-2">The Challenge</h3>
<p class="text-secondary-700 text-sm leading-relaxed">${project.challenge}</p>
<h3 class="text-sm font-semibold uppercase tracking-wide text-secondary-400 dark:text-secondary-500 mb-2">The Challenge</h3>
<p class="text-secondary-700 dark:text-secondary-300 text-sm leading-relaxed">${project.challenge}</p>
</div>
<div>
<h3 class="text-sm font-semibold uppercase tracking-wide text-secondary-400 mb-2">Our Solution</h3>
<p class="text-secondary-700 text-sm leading-relaxed">${project.solution}</p>
<h3 class="text-sm font-semibold uppercase tracking-wide text-secondary-400 dark:text-secondary-500 mb-2">Our Solution</h3>
<p class="text-secondary-700 dark:text-secondary-300 text-sm leading-relaxed">${project.solution}</p>
</div>
</div>
</div>
<!-- Bottom row: tech stack + results -->
<div class="grid gap-6 sm:grid-cols-2 pt-6 border-t border-secondary-100">
<div class="grid gap-6 sm:grid-cols-2 pt-6 border-t border-secondary-100 dark:border-secondary-700">
<div>
<h3 class="text-sm font-semibold uppercase tracking-wide text-secondary-400 mb-3">Tech Stack</h3>
<h3 class="text-sm font-semibold uppercase tracking-wide text-secondary-400 dark:text-secondary-500 mb-3">Tech Stack</h3>
<div class="flex flex-wrap gap-2">
${project.techStack.map((tech: string) => `<span class="rounded-lg bg-secondary-100 px-3 py-1.5 text-xs font-semibold text-secondary-700">${tech}</span>`).join('')}
${project.techStack.map((tech: string) => `<span class="rounded-lg bg-secondary-100 dark:bg-secondary-700 px-3 py-1.5 text-xs font-semibold text-secondary-700 dark:text-secondary-300">${tech}</span>`).join('')}
</div>
</div>
<div>
<h3 class="text-sm font-semibold uppercase tracking-wide text-secondary-400 mb-3">Key Results</h3>
<h3 class="text-sm font-semibold uppercase tracking-wide text-secondary-400 dark:text-secondary-500 mb-3">Key Results</h3>
<ul class="space-y-2">
${project.results.map((result: string) => `
<li class="flex items-center gap-2 text-sm text-secondary-700">
<li class="flex items-center gap-2 text-sm text-secondary-700 dark:text-secondary-300">
<svg class="h-4 w-4 flex-shrink-0 text-emerald-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M5 13l4 4L19 7" />
</svg>
@@ -1015,7 +1013,7 @@ const featuredProjects = projects.filter(p => p.featured);
<!-- CTA -->
<div class="mt-8 flex flex-col sm:flex-row gap-3 justify-end">
<button id="modal-close-cta" class="order-2 sm:order-1 inline-flex items-center justify-center px-5 py-2.5 rounded-lg border border-secondary-200 text-secondary-600 text-sm font-medium hover:bg-secondary-50 transition-colors focus:outline-none focus:ring-2 focus:ring-secondary-400">
<button id="modal-close-cta" class="order-2 sm:order-1 inline-flex items-center justify-center px-5 py-2.5 rounded-lg border border-secondary-200 dark:border-secondary-600 text-secondary-600 dark:text-secondary-400 text-sm font-medium hover:bg-secondary-50 dark:hover:bg-secondary-700 transition-colors focus:outline-none focus:ring-2 focus:ring-secondary-400">
Back to Portfolio
</button>
<a href="/contact" class="order-1 sm:order-2 inline-flex items-center justify-center px-6 py-2.5 rounded-lg bg-primary text-white text-sm font-semibold hover:bg-primary-600 transition-colors focus:outline-none focus:ring-2 focus:ring-primary-400">