Skip to content

Commit 69febc5

Browse files
Merge pull request #137 from priya05-git/main
Title: [PR]: Add Random Project Generator Feature 🎲
2 parents 4ab1f3f + 7a65b50 commit 69febc5

4 files changed

Lines changed: 176 additions & 80 deletions

File tree

web-app/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ An interactive web application showcasing Python mini projects with beautiful vi
88
- 🎨 **Beautiful UI** - Modern design with smooth animations
99
- 🌓 **Dark/Light Mode** - Toggle between themes
1010
- 📱 **Responsive** - Works on desktop, tablet, and mobile
11+
- 🎲 **Random Project Generator** - Discover random projects with a single click!
1112
- 🚀 **Zero Setup** - Just open index.html and play!
1213

1314
## 🎯 Included Projects
@@ -116,10 +117,36 @@ Edit CSS variables in `css/styles.css`:
116117
### UX Features
117118
- Smooth transitions and animations
118119
- Category filtering (All, Games, Math, Utilities)
120+
- **Random Project Generator** - Shuffles through projects based on current category
119121
- Modal system for focused project interaction
120122
- Responsive design for all screen sizes
121123
- Theme persistence with localStorage
122124

125+
## 🎲 Random Project Generator
126+
127+
### Overview
128+
Can't decide which project to try? Use the **Random Project 🎲** button to instantly discover a random project!
129+
130+
### Features
131+
- **Smart Selection** - Only picks from projects in your current category filter
132+
- **Smooth Animation** - Button shuffles with a fun dice-roll animation
133+
- **Instant Discovery** - Opens the selected project automatically
134+
- **Fair Randomization** - Equal chance for all available projects
135+
- **Category-Aware** - Respects your current filter (Games, Math, Utilities, or All)
136+
137+
### How to Use
138+
1. Click the **Random Project 🎲** button in the top navigation
139+
2. Watch the shuffle animation
140+
3. The project modal opens automatically with your randomly selected project
141+
4. Enjoy exploring something new!
142+
143+
### Implementation Details
144+
- **Location**: Top navigation bar, next to category filters
145+
- **Animation**: Custom CSS shuffle animation (0.6s duration)
146+
- **Logic**: JavaScript function `selectRandomProject()` in `main.js`
147+
- **Selection**: Uses `Math.random()` for fair distribution
148+
- **Filtering**: Gets all visible project cards based on current category
149+
123150
## 📱 Browser Compatibility
124151

125152
- ✅ Chrome (recommended)

web-app/css/styles.css

Lines changed: 85 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,76 @@ body {
726726
transform: scale(0.98);
727727
}
728728

729+
/* Tabs Wrapper */
730+
.tabs-wrapper {
731+
display: flex;
732+
align-items: center;
733+
justify-content: space-between;
734+
gap: 2rem;
735+
flex-wrap: wrap;
736+
}
737+
738+
.tabs-wrapper .tabs {
739+
flex: 1;
740+
min-width: 300px;
741+
}
742+
743+
/* Random Project Button */
744+
.btn-random-project {
745+
background: linear-gradient(135deg, var(--secondary-color), var(--primary-color));
746+
border: 2px solid var(--secondary-color);
747+
color: white;
748+
padding: 0.75rem 1.5rem;
749+
border-radius: 50px;
750+
cursor: pointer;
751+
font-size: 1rem;
752+
font-weight: 600;
753+
transition: var(--transition);
754+
display: flex;
755+
align-items: center;
756+
gap: 0.5rem;
757+
white-space: nowrap;
758+
box-shadow: 0 4px 15px rgba(139, 92, 246, 0.3);
759+
}
760+
761+
.btn-random-project:hover {
762+
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
763+
border-color: var(--primary-color);
764+
transform: translateY(-2px);
765+
box-shadow: 0 6px 20px rgba(139, 92, 246, 0.5);
766+
}
767+
768+
.btn-random-project:active {
769+
transform: translateY(0);
770+
}
771+
772+
/* Shuffle Animation */
773+
@keyframes shuffle {
774+
0% {
775+
transform: rotateZ(0deg) scale(1);
776+
}
777+
25% {
778+
transform: rotateZ(-10deg) scale(1.05);
779+
}
780+
50% {
781+
transform: rotateZ(10deg) scale(1.05);
782+
}
783+
75% {
784+
transform: rotateZ(-5deg) scale(1.05);
785+
}
786+
100% {
787+
transform: rotateZ(0deg) scale(1);
788+
}
789+
}
790+
791+
.btn-random-project.shuffle {
792+
animation: shuffle 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
793+
}
794+
795+
.btn-random-project i {
796+
font-size: 1.1rem;
797+
}
798+
729799
/* Projects Section */
730800
.projects-section {
731801
padding: 4rem 0;
@@ -988,6 +1058,16 @@ body {
9881058
grid-template-columns: 1fr;
9891059
}
9901060

1061+
.tabs-wrapper {
1062+
flex-direction: column;
1063+
gap: 1rem;
1064+
align-items: stretch;
1065+
}
1066+
1067+
.tabs-wrapper .tabs {
1068+
min-width: unset;
1069+
}
1070+
9911071
.tabs {
9921072
gap: 0.5rem;
9931073
}
@@ -996,56 +1076,11 @@ body {
9961076
padding: 0.5rem 1rem;
9971077
font-size: 0.9rem;
9981078
}
999-
1000-
1001-
.back-to-top {
1002-
right: 1rem;
1003-
bottom: 6.5rem;
1004-
width: 3rem;
1005-
height: 3rem;
1006-
}
1007-
1008-
.search-wrapper {
1009-
max-width: 100%;
1010-
padding: 0 1rem;
1011-
}
1012-
1013-
.search-input {
1014-
font-size: 0.95rem;
1015-
padding: 0.85rem 0;
1016-
}
1017-
1018-
.search-shortcut {
1019-
display: none;
1020-
}
1021-
1022-
.search-dropdown {
1023-
width: 100vw;
1024-
left: 50%;
1025-
transform: translateX(-50%);
1026-
border-radius: 12px;
1027-
margin-top: 0.5rem;
1028-
}
1029-
1030-
.dropdown-section-title {
1031-
padding: 0.5rem 1rem;
1032-
font-size: 0.75rem;
1033-
}
1034-
1035-
.dropdown-item,
1036-
.dropdown-recent-item,
1037-
.dropdown-tips {
1038-
padding-left: 1rem;
1039-
padding-right: 1rem;
1040-
}
1041-
1042-
.search-icon-wrapper {
1043-
margin-right: 0.5rem;
1044-
}
1045-
1046-
.search-icon {
1047-
font-size: 1rem;
1048-
1079+
1080+
.btn-random-project {
1081+
width: 100%;
1082+
justify-content: center;
1083+
padding: 0.75rem 1rem;
10491084
}
10501085
}
10511086

web-app/index.html

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,23 +46,16 @@ <h1>🎮 Python Mini Projects</h1>
4646
<!-- Search & Category Tabs -->
4747
<section class="tabs-section" aria-label="Search and Project categories">
4848
<div class="container">
49-
<div class="search-container">
50-
<div class="search-box">
51-
<i class="fas fa-search" aria-hidden="true"></i>
52-
<input type="text" id="projectSearch" placeholder="Search for projects (e.g. 'rock', 'dice', 'prime')..." aria-label="Search for projects">
49+
<div class="tabs-wrapper">
50+
<div class="tabs">
51+
<button class="tab active" data-category="all">🌟 All Projects</button>
52+
<button class="tab" data-category="games">🎮 Games</button>
53+
<button class="tab" data-category="math">🔢 Math</button>
54+
<button class="tab" data-category="utilities">🔐 Utilities</button>
5355
</div>
54-
</div>
55-
<div class="tabs" role="tablist" aria-label="Filter projects by category">
56-
<button type="button" class="tab active" role="tab" id="tab-all" data-category="all" aria-selected="true" aria-controls="projectsGrid" tabindex="0">🌟 All Projects</button>
57-
<button type="button" class="tab" role="tab" id="tab-games" data-category="games" aria-selected="false" aria-controls="projectsGrid" tabindex="-1">🎮 Games</button>
58-
<button type="button" class="tab" role="tab" id="tab-math" data-category="math" aria-selected="false" aria-controls="projectsGrid" tabindex="-1">🔢 Math</button>
59-
<button type="button" class="tab" role="tab" id="tab-utilities" data-category="utilities" aria-selected="false" aria-controls="projectsGrid" tabindex="-1">🔐 Utilities</button>
60-
</div>
61-
62-
<!-- Empty State Message -->
63-
<div class="empty-state" id="emptyState" style="display: none;">
64-
<p>📭 No projects match your search.</p>
65-
<p class="empty-state-hint">Try different keywords or browse all projects.</p>
56+
<button class="btn-random-project" id="randomProjectBtn" title="Discover a random project!">
57+
<i class="fas fa-dice"></i> Random Project 🎲
58+
</button>
6659
</div>
6760
</div>
6861
</section>

web-app/js/main.js

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -369,20 +369,61 @@ document.addEventListener('DOMContentLoaded', () => {
369369
}
370370
tabs.forEach(tab => tab.addEventListener('click', () => { tabs.forEach(t => t.classList.remove('active')); tab.classList.add('active'); applyFilter(tab.getAttribute('data-category') || 'all'); }));
371371

372-
// Modal helpers
373-
let removeTrap = null;
374-
function openProjectSafe(name, trigger) {
375-
if (!modal || !modalBody) return;
376-
lastFocusedElement = trigger || document.activeElement;
377-
if (modalTitle && trigger) {
378-
const card = trigger.closest('.project-card');
379-
const h = card?.querySelector('h3')?.textContent?.trim();
380-
modalTitle.textContent = h || (name || 'Project');
381-
}
382-
modal.classList.add('active');
383-
modal.setAttribute('aria-hidden', 'false');
384-
document.body.style.overflow = 'hidden';
385-
setMainInert(true);
372+
// Random Project Generator
373+
const randomProjectBtn = document.getElementById('randomProjectBtn');
374+
375+
function getRandomProject() {
376+
// Get all visible project cards (based on current filter)
377+
const visibleCards = Array.from(projectCards).filter(card => {
378+
return card.style.display !== 'none';
379+
});
380+
381+
if (visibleCards.length === 0) {
382+
// If no cards are visible (shouldn't happen), get all cards
383+
return projectCards[Math.floor(Math.random() * projectCards.length)];
384+
}
385+
386+
return visibleCards[Math.floor(Math.random() * visibleCards.length)];
387+
}
388+
389+
function selectRandomProject() {
390+
const randomCard = getRandomProject();
391+
392+
// Add shuffle animation to the button
393+
randomProjectBtn.classList.add('shuffle');
394+
395+
// Remove animation class after it completes
396+
setTimeout(() => {
397+
randomProjectBtn.classList.remove('shuffle');
398+
}, 600);
399+
400+
// Open the random project after a short delay for effect
401+
setTimeout(() => {
402+
const projectName = randomCard.getAttribute('data-project');
403+
openProject(projectName);
404+
405+
// Optional: Scroll to project card smoothly
406+
randomCard.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
407+
}, 300);
408+
}
409+
410+
randomProjectBtn.addEventListener('click', selectRandomProject);
411+
412+
// Open Project Modal
413+
projectCards.forEach(card => {
414+
const playButton = card.querySelector('.btn-play');
415+
416+
playButton.addEventListener('click', (e) => {
417+
e.stopPropagation();
418+
const projectName = card.getAttribute('data-project');
419+
openProject(projectName);
420+
});
421+
422+
card.addEventListener('click', () => {
423+
const projectName = card.getAttribute('data-project');
424+
openProject(projectName);
425+
});
426+
});
386427

387428
// load content safely
388429
safeRun(() => {

0 commit comments

Comments
 (0)