diff --git a/web/virtual_lab/templates/virtual_lab/home.html b/web/virtual_lab/templates/virtual_lab/home.html index 159d14f36..16ae85a74 100644 --- a/web/virtual_lab/templates/virtual_lab/home.html +++ b/web/virtual_lab/templates/virtual_lab/home.html @@ -2,47 +2,48 @@ {% extends "virtual_lab/layout.html" %} {% load static %} +{% load i18n %} {% block virtual_lab_content %} -
+
-

Welcome to the Alpha Science Lab

-

- Dive into interactive experiments and deepen your understanding of fundamental concepts. Click on any card below to begin. -

- diff --git a/web/virtual_lab/templates/virtual_lab/layout.html b/web/virtual_lab/templates/virtual_lab/layout.html index dd8ebcdc3..7e733c813 100644 --- a/web/virtual_lab/templates/virtual_lab/layout.html +++ b/web/virtual_lab/templates/virtual_lab/layout.html @@ -8,31 +8,46 @@
-
+
Alpha Science Lab
diff --git a/web/virtual_lab/templates/virtual_lab/physics/index.html b/web/virtual_lab/templates/virtual_lab/physics/index.html new file mode 100644 index 000000000..2756740f8 --- /dev/null +++ b/web/virtual_lab/templates/virtual_lab/physics/index.html @@ -0,0 +1,51 @@ +{% extends "virtual_lab/layout.html" %} + +{% load i18n %} + +{% block virtual_lab_content %} + +{% endblock virtual_lab_content %} diff --git a/web/virtual_lab/urls.py b/web/virtual_lab/urls.py index bd8b6714c..65f90d989 100644 --- a/web/virtual_lab/urls.py +++ b/web/virtual_lab/urls.py @@ -6,6 +6,7 @@ evaluate_code, ph_indicator_view, physics_electrical_circuit_view, + physics_home, physics_inclined_view, physics_mass_spring_view, physics_pendulum_view, @@ -21,17 +22,18 @@ urlpatterns = [ path("", virtual_lab_home, name="virtual_lab_home"), + path("physics/", physics_home, name="physics_home"), path("physics/pendulum/", physics_pendulum_view, name="physics_pendulum"), path("physics/projectile/", physics_projectile_view, name="physics_projectile"), path("physics/inclined/", physics_inclined_view, name="physics_inclined"), path("physics/mass_spring/", physics_mass_spring_view, name="physics_mass_spring"), path("physics/circuit/", physics_electrical_circuit_view, name="physics_electrical_circuit"), - path("virtual_lab/chemistry/", chemistry_home, name="chemistry_home"), - path("virtual_lab/chemistry/titration/", titration_view, name="titration"), - path("virtual_lab/chemistry/reaction-rate/", reaction_rate_view, name="reaction_rate"), - path("virtual_lab/chemistry/solubility/", solubility_view, name="solubility"), - path("virtual_lab/chemistry/precipitation/", precipitation_view, name="precipitation"), - path("virtual_lab/chemistry/ph-indicator/", ph_indicator_view, name="ph_indicator"), + path("chemistry/", chemistry_home, name="chemistry_home"), + path("chemistry/titration/", titration_view, name="titration"), + path("chemistry/reaction-rate/", reaction_rate_view, name="reaction_rate"), + path("chemistry/solubility/", solubility_view, name="solubility"), + path("chemistry/precipitation/", precipitation_view, name="precipitation"), + path("chemistry/ph-indicator/", ph_indicator_view, name="ph_indicator"), path("code-editor/", code_editor_view, name="code_editor"), path("evaluate-code/", evaluate_code, name="evaluate_code"), ] diff --git a/web/virtual_lab/views.py b/web/virtual_lab/views.py index cee652a8e..0e9680b64 100644 --- a/web/virtual_lab/views.py +++ b/web/virtual_lab/views.py @@ -4,77 +4,131 @@ import logging import requests -from django.http import JsonResponse +from django.http import HttpRequest, HttpResponse, JsonResponse from django.shortcuts import render +from django.utils.translation import gettext_lazy as _ from django.views.decorators.http import require_POST logger = logging.getLogger(__name__) +def build_virtual_lab_subjects() -> list[dict[str, object]]: + """Return subject and lab metadata for virtual lab navigation and landing pages.""" + return [ + { + "key": "physics", + "label": _("Physics"), + "url_name": "virtual_lab:physics_home", + "labs": [ + {"label": _("Pendulum Motion"), "url_name": "virtual_lab:physics_pendulum"}, + {"label": _("Projectile Motion"), "url_name": "virtual_lab:physics_projectile"}, + {"label": _("Inclined Plane"), "url_name": "virtual_lab:physics_inclined"}, + {"label": _("Mass-Spring Oscillation"), "url_name": "virtual_lab:physics_mass_spring"}, + {"label": _("Basic Electrical Circuit"), "url_name": "virtual_lab:physics_electrical_circuit"}, + ], + }, + { + "key": "chemistry", + "label": _("Chemistry"), + "url_name": "virtual_lab:chemistry_home", + "labs": [ + {"label": _("Acid-Base Titration"), "url_name": "virtual_lab:titration"}, + {"label": _("Reaction Rate"), "url_name": "virtual_lab:reaction_rate"}, + {"label": _("Solubility & Saturation"), "url_name": "virtual_lab:solubility"}, + {"label": _("Precipitation Reaction"), "url_name": "virtual_lab:precipitation"}, + {"label": _("pH Indicator"), "url_name": "virtual_lab:ph_indicator"}, + ], + }, + ] + + +def render_virtual_lab_page( + request: HttpRequest, template_name: str, extra_context: dict[str, object] | None = None +) -> HttpResponse: + """Render a virtual lab template with common navigation context.""" + context = { + "virtual_lab_subjects": build_virtual_lab_subjects(), + } + if extra_context: + context.update(extra_context) + return render(request, template_name, context) + + def virtual_lab_home(request): """ Renders the Virtual Lab home page (home.html). """ - return render(request, "virtual_lab/home.html") + return render_virtual_lab_page(request, "virtual_lab/home.html") + + +def physics_home(request): + """Render the Physics lab overview page.""" + return render_virtual_lab_page(request, "virtual_lab/physics/index.html") def physics_pendulum_view(request): """ Renders the Pendulum Motion simulation page (physics/pendulum.html). """ - return render(request, "virtual_lab/physics/pendulum.html") + return render_virtual_lab_page(request, "virtual_lab/physics/pendulum.html") def physics_projectile_view(request): """ Renders the Projectile Motion simulation page (physics/projectile.html). """ - return render(request, "virtual_lab/physics/projectile.html") + return render_virtual_lab_page(request, "virtual_lab/physics/projectile.html") def physics_inclined_view(request): """ Renders the Inclined Plane simulation page (physics/inclined.html). """ - return render(request, "virtual_lab/physics/inclined.html") + return render_virtual_lab_page(request, "virtual_lab/physics/inclined.html") def physics_mass_spring_view(request): """ Renders the Mass-Spring Oscillation simulation page (physics/mass_spring.html). """ - return render(request, "virtual_lab/physics/mass_spring.html") + return render_virtual_lab_page(request, "virtual_lab/physics/mass_spring.html") def physics_electrical_circuit_view(request): """ Renders the Electrical Circuit simulation page (physics/circuit.html). """ - return render(request, "virtual_lab/physics/circuit.html") + return render_virtual_lab_page(request, "virtual_lab/physics/circuit.html") def chemistry_home(request): - return render(request, "virtual_lab/chemistry/index.html") + """Render the Chemistry lab overview page.""" + return render_virtual_lab_page(request, "virtual_lab/chemistry/index.html") def titration_view(request): - return render(request, "virtual_lab/chemistry/titration.html") + """Render the Acid-Base Titration simulation page.""" + return render_virtual_lab_page(request, "virtual_lab/chemistry/titration.html") def reaction_rate_view(request): - return render(request, "virtual_lab/chemistry/reaction_rate.html") + """Render the Reaction Rate simulation page.""" + return render_virtual_lab_page(request, "virtual_lab/chemistry/reaction_rate.html") def solubility_view(request): - return render(request, "virtual_lab/chemistry/solubility.html") + """Render the Solubility and Saturation simulation page.""" + return render_virtual_lab_page(request, "virtual_lab/chemistry/solubility.html") def precipitation_view(request): - return render(request, "virtual_lab/chemistry/precipitation.html") + """Render the Precipitation Reaction simulation page.""" + return render_virtual_lab_page(request, "virtual_lab/chemistry/precipitation.html") def ph_indicator_view(request): - return render(request, "virtual_lab/chemistry/ph_indicator.html") + """Render the pH Indicator simulation page.""" + return render_virtual_lab_page(request, "virtual_lab/chemistry/ph_indicator.html") # Piston’s public execute endpoint (rate-limited to 5 req/s) :contentReference[oaicite:0]{index=0} @@ -89,7 +143,8 @@ def ph_indicator_view(request): def code_editor_view(request): - return render(request, "virtual_lab/code_editor/code_editor.html") + """Render the virtual lab code editor page.""" + return render_virtual_lab_page(request, "virtual_lab/code_editor/code_editor.html") @require_POST