From 9e877aca8ae9831776443355f4ec47a7e7f2b027 Mon Sep 17 00:00:00 2001 From: DESIREDDY MOHITH REDDY Date: Fri, 26 Jun 2026 16:41:10 +0530 Subject: [PATCH] Feat: Implement Server-Side Pagination and Explore page (#1175) - Added /explore route in main_routes.py with pagination, sorting and filtering support - Created explore.html Jinja2 template using the existing design system - Updated site navigation to link to Explore All page - Added test_explore_route to tests/test_basic.py --- rewrite_explore.py | 156 +++++ src/routes/main_routes.py | 79 +++ src/templates/explore.html | 1304 ++++++++++++++++++++++++++++++++++++ src/templates/index.html | 2 + tests/test_basic.py | 11 + 5 files changed, 1552 insertions(+) create mode 100644 rewrite_explore.py create mode 100644 src/templates/explore.html diff --git a/rewrite_explore.py b/rewrite_explore.py new file mode 100644 index 00000000..fb49abbe --- /dev/null +++ b/rewrite_explore.py @@ -0,0 +1,156 @@ +import re + +with open("src/templates/explore.html", "r") as f: + content = f.read() + +# Replace the hero section, stats section, etc. with a simple explore layout. +# We will find the
tag or
and remove everything until
+start_tag = '
' +end_tag = ' + + + +
+
+

Showing {{ projects|length }} of {{ total_items }} projects

+
+ + {% if projects %} +
+ {% for project in projects %} +
+

{{ project.title }}

+

{{ project.description | truncate(120) }}

+
+ {% for skill in project.skills %} + {{ skill }} + {% endfor %} + {{ project.level }} + Time: {{ project.time }} +
+ +
+ {% endfor %} +
+ + + + {% else %} +
+

No Projects Found

+

Try adjusting your filters or search term.

+ Clear Filters +
+ {% endif %} +
+ +
+""" + new_body = new_body.replace("{% end从业%}", "{% endfor %}") + content = content[:start_idx] + new_body + content[end_idx:] + +with open("src/templates/explore.html", "w") as f: + f.write(content) + +print("Done") diff --git a/src/routes/main_routes.py b/src/routes/main_routes.py index dec859bd..424ea1ad 100644 --- a/src/routes/main_routes.py +++ b/src/routes/main_routes.py @@ -19,6 +19,7 @@ ) from config import Config import os +import math # Interest categories that currently have no project recommendations available NO_PROJECT_INTERESTS = { @@ -51,6 +52,84 @@ def index(): return render_template("index.html", stats=stats, available_levels=available_levels, config=Config) +@main.route("/explore") +def explore(): + """Render the explore page with server-side pagination, filtering, and sorting.""" + page = request.args.get("page", 1, type=int) + per_page = request.args.get("per_page", 12, type=int) + search_query = request.args.get("search", "").strip().lower() + level_filter = request.args.get("level", "").strip().lower() + interest_filter = request.args.get("interest", "").strip().lower() + time_filter = request.args.get("time", "").strip().lower() + sort_by = request.args.get("sort", "id_asc") + + all_projects = load_all_projects() + filtered_projects = [] + + for p in all_projects: + # Search text + if search_query: + searchable_text = ( + p.get("title", "") + " " + + p.get("description", "") + " " + + " ".join(p.get("skills", [])) + ).lower() + if search_query not in searchable_text: + continue + + if level_filter and p.get("level", "").lower() != level_filter: + continue + + if interest_filter and p.get("interest", "").lower() != interest_filter: + continue + + if time_filter and p.get("time", "").lower() != time_filter: + continue + + filtered_projects.append(p) + + # Sorting + if sort_by == "title_asc": + filtered_projects.sort(key=lambda x: x.get("title", "").lower()) + elif sort_by == "title_desc": + filtered_projects.sort(key=lambda x: x.get("title", "").lower(), reverse=True) + elif sort_by == "id_desc": + filtered_projects.sort(key=lambda x: x.get("id", 0), reverse=True) + else: # id_asc + filtered_projects.sort(key=lambda x: x.get("id", 0)) + + total_items = len(filtered_projects) + total_pages = math.ceil(total_items / per_page) if total_items > 0 else 1 + + # Bound page number + if page < 1: + page = 1 + elif page > total_pages: + page = total_pages + + start_idx = (page - 1) * per_page + end_idx = start_idx + per_page + + paginated_projects = filtered_projects[start_idx:end_idx] + + # Also pass filter dropdown options to UI + available_levels = get_available_levels() + + return render_template( + "explore.html", + projects=paginated_projects, + page=page, + total_pages=total_pages, + total_items=total_items, + search=search_query, + level=level_filter, + interest=interest_filter, + time=time_filter, + sort=sort_by, + available_levels=available_levels, + config=Config + ) + @main.route("/contact") def contact(): return render_template("contact.html") diff --git a/src/templates/explore.html b/src/templates/explore.html new file mode 100644 index 00000000..c65a3356 --- /dev/null +++ b/src/templates/explore.html @@ -0,0 +1,1304 @@ + + + + + + + + DevPath — Find Projects Based On Your Skills + + + + + + + + + + + + + + + + + + + + {% include 'partials/theme_head.html' %} + + + + + + + + + + + + + + + +
+
+
+
+ + Open Source Developer Tool +
+ +

+ Build Projects
+ That Actually Matter +

+ +

+ Tell DevPath what you know, what interests you, and how much time + you have. Get matched to real coding projects with step-by-step + roadmaps and ready-to-run starter code. +

+ + +
+ +
+
+
+ + + + +
+
+ Starter Code Ready + Download and start immediately +
+
+ +
+
+ + + + expense_tracker.py +
+
+ def add_expense(category, amount): + # Save entry to CSV + date = datetime.now() + with open(DATA_FILE) as f: + writer.writerow([date, ...]) +   + def monthly_summary(): + # TODO: implement + pass +
+
+ +
+
+ + + +
+
+ 7-Step Roadmap + Clear path from start to finish +
+
+
+
+ +
+
+
+
+ + +
+
+
+
+
+ + + +
+
+ {{ stats.total_projects }} + Real Projects +
+
+ +
+
+ + + +
+
+ {{ stats.unique_skills }} + Unique Skills +
+
+ +
+
+ + + + +
+
+ {{ stats.beginner_friendly }} + Beginner Friendly +
+
+
+
+
+ + +
+
+
Your DevPath Profile
+

Track Progress, Unlock Badges, and See Your Growth

+

Local progress is saved in your browser so you can build momentum without signing in.

+ +
+
+
+ Total Points + + + + +
+
0
+
+
+ 0% +
+
+ +
+ +
+
+ Badges Earned + + + +
+
+ +
+ +
+
+ Your Activity + + + +
+
+
+ 0 + Searches +
+
+ 0 + Viewed +
+
+ 0 + Code Opens +
+
+ 0 + Completed +
+
+
+
+ +
+
+
+

Completed Projects

+ + + + +
+
+
+ + + + + + +

No completed projects yet

+ Start a project to see it here +
+
+
+ +
+
+ + +
+ +
+
    +
  1. Complete projects to see rankings
  2. +
+ +
+ +
+
    +
  • Complete actions to earn achievements
  • +
+ +
+
+
+
+
+ +
+ + +
+
+ Supports skills including: +
+ Python + JavaScript + HTML / CSS + Flask + SQL + React + Node.js + pandas + C++ + Java + TypeScript + Go + Rust + C# + Kotlin +
+
+
+ + +
+
+
How DevPath Works
+

From Your Skills to Your
Next Project in Minutes

+

Three simple steps. No account required. No fluff.

+ +
+
+
01
+

Enter Your Skills

+

Type your programming skills or click quick-select chips. Add as many as you like.

+
+
+ + + +
+
+
02
+

Set Your Preferences

+

Select your experience level, area of interest, and how much time you can commit.

+
+
+ + + +
+
+
03
+

Get Matched Projects

+

DevPath returns your top three matched projects with roadmaps and starter code.

+
+
+
+
+ + +
+
+
What You Get
+

Everything You Need to Start Building

+

Every recommendation comes with practical resources — not just a project name.

+ +
+
+
+ + + + + + +
+

Personalized Matches

+

Projects are scored against your exact skills, level, and interest — not pulled from a generic list.

+ Try it now +
+ +
+
+ + + +
+

Step-by-Step Roadmaps

+

Each project includes a numbered roadmap so you always know what to build next, without guessing.

+ Explore roadmaps +
+ +
+
+ + + + +
+

Starter Code Included

+

Download a working template for every project. Skip the blank-page problem and start building immediately.

+ Get starter code +

Download a working template for every project. Skip the blank-page problem and start building immediately. +

+ Get starter code +
+
+
+
+ + +
+
+
Get Your Recommendations
+

Find The Project

+

Fill in your details below and DevPath will match you to the most relevant projects.

+ +
+
+
+ + +
+
+ + + + +
+ +
+ +
+
+
+
+
+
+ + +
+ + +
+ + + Add one or more skills you are comfortable with. Example: Python, React, SQL, Git. + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ +
+ Select your current proficiency level such as Beginner or Intermediate. +
+
+ +
+ +
+ +
+ Pick the domain you want to explore such as Web Development, Automation, or Games. +
+
+
+ +
+ +
+ +
+ Include coding, debugging, learning, and reviewing time in your estimate. +
+
+ +
+ +
+ + +
+ +
+
+
+
+
+ + + + + +
+
+
+

Start Building.
A New Skill Awaits.

+

Find a project that challenges you and grow with every line of code.

+ Find My Project +
+
+
+ + +
+
+
About Us
+

Our Story

+

DevPath was built to help learners move from scattered tutorials to projects with a clear + path, practical code, and meaningful momentum.

+ +
+
+

Why it exists

+

Too many project ideas stop at the title. DevPath focuses on the next steps that make starting and + finishing feel manageable.

+
+
+

How it helps

+

Each recommendation includes a roadmap and starter code so users can spend time building instead of + searching for structure.

+
+
+

What it leads to

+

A smoother path from curiosity to a finished project, with fewer dead ends and more confidence along the + way.

+
+
+
+
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/templates/index.html b/src/templates/index.html index 9ae9e04f..c65a3356 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -415,6 +415,7 @@ How It Works Features Find Project + Explore All Compare Contact Quick Links
  • Home
  • How It Works
  • Features
  • +
  • Explore All
  • Find Project
  • Find Project
  • Contact Us
  • diff --git a/tests/test_basic.py b/tests/test_basic.py index b256c61c..ae664e7a 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -449,6 +449,17 @@ def test_home_route(): response = client.get("/") assert response.status_code == 200 + +def test_explore_route(): + """Explore route should return 200 OK and handle pagination.""" + client = get_client() + response = client.get("/explore?page=1&per_page=5") + assert response.status_code == 200 + html = response.data.decode("utf-8") + assert "Explore All Projects" in html + # The max per_page is 5, so there should be pagination controls or fewer items. + assert 'class="project-card"' in html + def test_security_headers_present(): """Security headers should be included in all responses.""" client = get_client()