Skip to content

Commit 6767a7f

Browse files
Merge branch 'main' into main
2 parents e41ac73 + ad14c09 commit 6767a7f

3 files changed

Lines changed: 250 additions & 54 deletions

File tree

web-app/css/styles.css

Lines changed: 132 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,48 +1299,149 @@ main>.hero-section:has(.hero-code-snippets) {
12991299
}
13001300

13011301

1302-
/* ── Hero Meta ─────────────────────────────────────────────── */
1303-
.hero-meta {
1302+
/* ── Stats Dashboard ───────────────────────────────────────── */
1303+
.stats-dashboard {
1304+
display: grid;
1305+
grid-template-columns: repeat(6, 1fr);
1306+
gap: 1rem;
1307+
width: 100%;
1308+
max-width: 1200px;
1309+
margin: 2rem auto 0;
1310+
padding: 0 1rem;
1311+
box-sizing: border-box;
1312+
}
1313+
1314+
.stats-card {
13041315
display: flex;
1305-
gap: 0.8rem;
1306-
flex-wrap: wrap;
1316+
flex-direction: column;
1317+
align-items: center;
13071318
justify-content: center;
1308-
font-family: var(--font-mono);
1309-
font-size: 0.78rem;
1310-
color: var(--text-secondary);
1311-
margin: 1.25rem 0 0;
1319+
background: rgba(255, 255, 255, 0.45);
1320+
backdrop-filter: blur(16px);
1321+
-webkit-backdrop-filter: blur(16px);
1322+
border: 1px solid rgba(255, 255, 255, 0.5);
1323+
border-radius: 16px;
1324+
padding: 1.25rem 1rem;
1325+
cursor: pointer;
1326+
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
1327+
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.05);
1328+
outline: none;
1329+
font-family: inherit;
1330+
color: inherit;
1331+
box-sizing: border-box;
13121332
}
13131333

1314-
.hero-meta span {
1315-
padding: 0.6rem 0.95rem;
1316-
border-radius: 12px;
1317-
background: rgba(255, 255, 255, 0.78);
1318-
border: 1px solid rgba(128, 104, 85, 0.08);
1319-
font-size: 0.82rem;
1320-
box-shadow: 0 2px 6px rgba(146, 111, 74, 0.04);
1321-
display: inline-flex;
1322-
align-items: center;
1323-
gap: 0.45rem;
1334+
[data-theme="dark"] .stats-card {
1335+
background: rgba(255, 255, 255, 0.03);
1336+
border: 1px solid rgba(255, 255, 255, 0.08);
1337+
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
13241338
}
13251339

1326-
.hero-meta strong {
1327-
color: var(--text);
1328-
font-weight: 600;
1340+
/* Hover and focus styles */
1341+
.stats-card:hover,
1342+
.stats-card:focus-visible {
1343+
transform: translateY(-5px) scale(1.03);
1344+
background: rgba(255, 255, 255, 0.6);
1345+
border-color: rgba(34, 197, 94, 0.5); /* Glowing green border on hover */
1346+
box-shadow: 0 0 15px rgba(34, 197, 94, 0.3), 0 12px 40px rgba(31, 38, 135, 0.08);
13291347
}
13301348

1331-
.hero-meta span::before {
1332-
content: "";
1333-
width: 4px;
1334-
height: 4px;
1349+
[data-theme="dark"] .stats-card:hover,
1350+
[data-theme="dark"] .stats-card:focus-visible {
1351+
background: rgba(255, 255, 255, 0.07);
1352+
border-color: rgba(74, 222, 128, 0.6); /* Green glowing border in dark mode */
1353+
box-shadow: 0 0 20px rgba(74, 222, 128, 0.3), 0 12px 40px rgba(0, 0, 0, 0.5);
1354+
}
1355+
1356+
/* Active/selected state filter highlight */
1357+
.stats-card.active {
1358+
background: rgba(255, 255, 255, 0.7);
1359+
border-color: rgba(34, 197, 94, 0.8);
1360+
box-shadow: 0 0 20px rgba(34, 197, 94, 0.4), 0 8px 24px rgba(31, 38, 135, 0.06);
1361+
}
1362+
1363+
[data-theme="dark"] .stats-card.active {
1364+
background: rgba(255, 255, 255, 0.09);
1365+
border-color: rgba(74, 222, 128, 0.9);
1366+
box-shadow: 0 0 25px rgba(74, 222, 128, 0.5), 0 8px 24px rgba(0, 0, 0, 0.4);
1367+
}
1368+
1369+
/* Accents and text elements */
1370+
.stats-icon {
1371+
margin-bottom: 0.75rem;
1372+
display: flex;
1373+
align-items: center;
1374+
justify-content: center;
1375+
width: 44px;
1376+
height: 44px;
13351377
border-radius: 50%;
1336-
background: var(--accent);
1337-
opacity: 0.6;
1378+
background: rgba(34, 197, 94, 0.1);
1379+
color: #22c55e;
1380+
transition: transform 0.3s ease;
13381381
}
13391382

1340-
[data-theme="dark"] .hero-meta span {
1341-
background: rgba(255, 255, 255, 0.08);
1342-
border-color: rgba(255, 239, 223, 0.1);
1343-
box-shadow: none;
1383+
[data-theme="dark"] .stats-icon {
1384+
background: rgba(74, 222, 128, 0.15);
1385+
color: #4ade80;
1386+
}
1387+
1388+
.stats-icon svg {
1389+
width: 20px;
1390+
height: 20px;
1391+
stroke-width: 2.25;
1392+
}
1393+
1394+
.stats-card:hover .stats-icon {
1395+
transform: rotate(8deg) scale(1.1);
1396+
}
1397+
1398+
.stats-info {
1399+
display: flex;
1400+
flex-direction: column;
1401+
align-items: center;
1402+
}
1403+
1404+
/* customized green accents for metrics counters */
1405+
.stats-info strong {
1406+
font-size: 1.75rem;
1407+
font-weight: 700;
1408+
line-height: 1.2;
1409+
color: #166534; /* customized dark-green accent */
1410+
transition: all 0.3s ease;
1411+
}
1412+
1413+
[data-theme="dark"] .stats-info strong {
1414+
color: #4ade80; /* customized light-green/neon accent for dark mode */
1415+
}
1416+
1417+
.stats-info span {
1418+
font-size: 0.8rem;
1419+
font-weight: 500;
1420+
color: var(--text-secondary);
1421+
text-transform: uppercase;
1422+
letter-spacing: 0.05em;
1423+
margin-top: 0.25rem;
1424+
text-align: center;
1425+
}
1426+
1427+
@media (max-width: 1024px) {
1428+
.stats-dashboard {
1429+
grid-template-columns: repeat(3, 1fr);
1430+
gap: 1rem;
1431+
}
1432+
}
1433+
1434+
@media (max-width: 640px) {
1435+
.stats-dashboard {
1436+
grid-template-columns: repeat(2, 1fr);
1437+
gap: 0.75rem;
1438+
}
1439+
}
1440+
1441+
@media (max-width: 400px) {
1442+
.stats-dashboard {
1443+
grid-template-columns: 1fr;
1444+
}
13441445
}
13451446

13461447

web-app/index.html

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -237,17 +237,61 @@ <h1 class="hero-title">
237237
</a>
238238
</div>
239239

240-
<div class="hero-meta">
241-
<div>
242-
<span><strong id="heroProjectCount">0</strong> total projects</span>
243-
<span><strong id="heroGameCount">0</strong> games</span>
244-
<span><strong id="heroMathCount">0</strong> maths</span>
245-
<span><strong id="heroUtilityCount">0</strong> utilities</span>
246-
</div>
247-
<div>
248-
<span data-filter="favorites"><strong id="heroFavoriteCount">0</strong>Favorites</span>
249-
<span><strong id="heroViewedCount">0</strong>Recently Viewed</span>
250-
</div>
240+
<div class="stats-dashboard">
241+
<button class="stats-card active" data-filter="all" type="button" aria-label="Show all projects">
242+
<div class="stats-icon">
243+
<svg data-lucide="layers"></svg>
244+
</div>
245+
<div class="stats-info">
246+
<strong id="heroProjectCount">0</strong>
247+
<span>Total Projects</span>
248+
</div>
249+
</button>
250+
<button class="stats-card" data-filter="games" type="button" aria-label="Filter games">
251+
<div class="stats-icon">
252+
<svg data-lucide="gamepad-2"></svg>
253+
</div>
254+
<div class="stats-info">
255+
<strong id="heroGameCount">0</strong>
256+
<span>Games</span>
257+
</div>
258+
</button>
259+
<button class="stats-card" data-filter="math" type="button" aria-label="Filter mathematics projects">
260+
<div class="stats-icon">
261+
<svg data-lucide="calculator"></svg>
262+
</div>
263+
<div class="stats-info">
264+
<strong id="heroMathCount">0</strong>
265+
<span>Maths</span>
266+
</div>
267+
</button>
268+
<button class="stats-card" data-filter="utilities" type="button" aria-label="Filter utilities">
269+
<div class="stats-icon">
270+
<svg data-lucide="wrench"></svg>
271+
</div>
272+
<div class="stats-info">
273+
<strong id="heroUtilityCount">0</strong>
274+
<span>Utilities</span>
275+
</div>
276+
</button>
277+
<button class="stats-card" data-filter="favorites" type="button" aria-label="Filter favorite projects">
278+
<div class="stats-icon">
279+
<svg data-lucide="star"></svg>
280+
</div>
281+
<div class="stats-info">
282+
<strong id="heroFavoriteCount">0</strong>
283+
<span>Favorites</span>
284+
</div>
285+
</button>
286+
<button class="stats-card" data-filter="recent" type="button" aria-label="Scroll to recently viewed projects">
287+
<div class="stats-icon">
288+
<svg data-lucide="history"></svg>
289+
</div>
290+
<div class="stats-info">
291+
<strong id="heroViewedCount">0</strong>
292+
<span>Recently Viewed</span>
293+
</div>
294+
</button>
251295
</div>
252296
</div>
253297
</section>
@@ -456,9 +500,9 @@ <h3>Stay Updated</h3>
456500
</div>
457501
<div class="footer-bottom">
458502
<div class="footer-bottom-links">
459-
<a href="#">Privacy Policy</a>
503+
<a href="privacy-policy.html">Privacy Policy</a>
460504
<span class="separator"></span>
461-
<a href="#">Terms of Service</a>
505+
<a href="terms-condition.html">Terms of Service</a>
462506
</div>
463507
<p>Made with ❤️ for Python learners everywhere &copy; 2026</p>
464508
</div>

web-app/js/main.js

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,13 @@ document.addEventListener("DOMContentLoaded", function () {
588588
currentCategory = category;
589589
syncSidebarTabs(category);
590590
syncStickyTabs(category);
591+
592+
// Sync stats cards highlight
593+
var statsCards = document.querySelectorAll(".stats-card");
594+
statsCards.forEach(function (card) {
595+
card.classList.toggle("active", card.getAttribute("data-filter") === category);
596+
});
597+
591598
var visibleCount = 0;
592599
var favorites = JSON.parse(localStorage.getItem("favorites") || "[]");
593600
projectCards.forEach(function (card) {
@@ -647,6 +654,10 @@ document.addEventListener("DOMContentLoaded", function () {
647654
function showPlaygroundSection() {
648655
playgroundActive = true;
649656
syncStickyTabs("playground");
657+
var statsCards = document.querySelectorAll(".stats-card");
658+
statsCards.forEach(function (card) {
659+
card.classList.remove("active");
660+
});
650661
if (projectsSection) projectsSection.style.display = "none";
651662
if (playgroundSection) {
652663
playgroundSection.style.display = "";
@@ -766,6 +777,35 @@ document.addEventListener("DOMContentLoaded", function () {
766777
});
767778
});
768779

780+
/* ── Stats Cards ──────────────────────────────────────────── */
781+
var statsCards = document.querySelectorAll(".stats-card");
782+
statsCards.forEach(function (card) {
783+
card.addEventListener("click", function () {
784+
var category = card.getAttribute("data-filter");
785+
786+
// Update active highlight class on stats cards
787+
statsCards.forEach(function (c) {
788+
c.classList.toggle("active", c === card);
789+
});
790+
791+
if (category === "recent") {
792+
var section = document.getElementById("recentlyViewedSection");
793+
if (section) {
794+
section.scrollIntoView({ behavior: "smooth", block: "start" });
795+
}
796+
} else {
797+
showProjectsSection();
798+
applyCategoryFilter(category);
799+
if (projectsSection) {
800+
projectsSection.scrollIntoView({
801+
behavior: "smooth",
802+
block: "start",
803+
});
804+
}
805+
}
806+
});
807+
});
808+
769809
/* ── Sticky Filter Bar Visibility ─────────────────────────── */
770810
if (stickyFilterBar && heroSection) {
771811
var heroObserver = new IntersectionObserver(
@@ -816,10 +856,20 @@ document.addEventListener("DOMContentLoaded", function () {
816856
if (stickyTabs.length) syncStickyTabs("all");
817857

818858
/* ── Sidebar Active Scroll Observer ───────────────────────── */
819-
if (!pageCategory && projectsSection) {
859+
if (!pageCategory && projectsSection) {
820860
console.log('Setting up sidebar observer');
821861

822862
const checkAndToggleSidebar = () => {
863+
// FIX #1364: Never show sidebar if Playground is active
864+
if (playgroundActive) {
865+
document.body.classList.remove("sidebar-active");
866+
const fixedThemeToggle = document.getElementById("fixed-theme-toggle");
867+
if (fixedThemeToggle) {
868+
fixedThemeToggle.style.display = "block";
869+
}
870+
return;
871+
}
872+
823873
if (window.innerWidth <= 768) {
824874
return;
825875
}
@@ -830,10 +880,9 @@ document.addEventListener("DOMContentLoaded", function () {
830880
const showSidebar = rect.top < window.innerHeight && window.scrollY > heroBottom - 100;
831881

832882
document.body.classList.toggle("sidebar-active", showSidebar);
833-
console.log('Sidebar active:', showSidebar, 'scrollY:', window.scrollY);
883+
console.log('Sidebar active:', showSidebar, 'scrollY:', window.scrollY, 'playgroundActive:', playgroundActive);
834884

835885
// Hide fixed-theme-toggle if sidebar is active
836-
837886
const fixedThemeToggle = document.getElementById("fixed-theme-toggle");
838887
if (fixedThemeToggle) {
839888
if (showSidebar) {
@@ -843,12 +892,12 @@ document.addEventListener("DOMContentLoaded", function () {
843892
fixedThemeToggle.style.display = "block";
844893
}
845894
}
846-
847895
};
848896

849897
window.addEventListener('scroll', checkAndToggleSidebar);
850898
checkAndToggleSidebar();
851-
}
899+
}
900+
852901
/* ═══════════════════════════════════════════════════════════════
853902
SEARCH - FIXED & IMPROVED
854903
═══════════════════════════════════════════════════════════════ */
@@ -1784,11 +1833,13 @@ card.appendChild(badge);
17841833
const historyBadge =
17851834
document.getElementById("historyCountBadge");
17861835

1787-
if(historyBadge){
1788-
1789-
historyBadge.textContent=`(${recent.length})`;
1790-
1791-
}
1836+
if(historyBadge){
1837+
historyBadge.textContent=`(${recent.length})`;
1838+
}
1839+
const heroViewedCount = document.getElementById("heroViewedCount");
1840+
if (heroViewedCount) {
1841+
heroViewedCount.textContent = String(recent.length);
1842+
}
17921843
console.log("[DEBUG] recentProjects array:", recent); if (recent.length === 0) {
17931844
section.style.display = "none";
17941845
return;

0 commit comments

Comments
 (0)