Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 38 additions & 37 deletions web/virtual_lab/templates/virtual_lab/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,48 @@
{% extends "virtual_lab/layout.html" %}

{% load static %}
{% load i18n %}

{% block virtual_lab_content %}
<div class="max-w-5xl mx-auto px-6 py-8">
<div class="container mx-auto px-4 py-8">
<div class="bg-white dark:bg-gray-800 shadow-lg rounded-lg overflow-hidden">
<div class="px-8 py-6">
<h2 class="text-4xl font-extrabold text-gray-800 dark:text-gray-100 mb-4">Welcome to the Alpha Science Lab</h2>
<p class="text-gray-600 dark:text-gray-300 mb-8">
Dive into interactive experiments and deepen your understanding of fundamental concepts. Click on any card below to begin.
</p>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
<!-- Pendulum Motion Card -->
<a href="{% url 'virtual_lab:physics_pendulum' %}"
class="block bg-gradient-to-b from-blue-50 dark:from-blue-900 to-white dark:to-gray-800 border border-blue-200 dark:border-blue-700 rounded-lg p-6 shadow hover:shadow-md transition">
<h3 class="text-2xl font-semibold text-blue-700 dark:text-blue-300 mb-2">Pendulum Motion</h3>
<p class="text-blue-600 dark:text-blue-400">Visualize how length affects a pendulum's period.</p>
</a>
<!-- Projectile Motion Card -->
<a href="{% url 'virtual_lab:physics_projectile' %}"
class="block bg-gradient-to-b from-green-50 dark:from-green-900 to-white dark:to-gray-800 border border-green-200 dark:border-green-700 rounded-lg p-6 shadow hover:shadow-md transition">
<h3 class="text-2xl font-semibold text-green-700 dark:text-green-300 mb-2">Projectile Motion</h3>
<p class="text-green-600 dark:text-green-400">Launch a projectile and observe its real‐time trajectory.</p>
</a>
<!-- Inclined Plane Card -->
<a href="{% url 'virtual_lab:physics_inclined' %}"
class="block bg-gradient-to-b from-yellow-50 dark:from-yellow-900 to-white dark:to-gray-800 border border-yellow-200 dark:border-yellow-700 rounded-lg p-6 shadow hover:shadow-md transition">
<h3 class="text-2xl font-semibold text-yellow-800 dark:text-yellow-300 mb-2">Inclined Plane</h3>
<p class="text-yellow-700 dark:text-yellow-400">See a block slide down and discover acceleration on a ramp.</p>
</a>
<!-- Mass–Spring Oscillation Card -->
<a href="{% url 'virtual_lab:physics_mass_spring' %}"
class="block bg-gradient-to-b from-purple-50 dark:from-purple-900 to-white dark:to-gray-800 border border-purple-200 dark:border-purple-700 rounded-lg p-6 shadow hover:shadow-md transition">
<h3 class="text-2xl font-semibold text-purple-700 dark:text-purple-300 mb-2">Mass–Spring Oscillation</h3>
<p class="text-purple-600 dark:text-purple-400">Set k and m, drag the mass, then watch it oscillate and view x(t).</p>
</a>
<!-- Basic Electrical Circuit Card -->
<a href="{% url 'virtual_lab:physics_electrical_circuit' %}"
class="block bg-gradient-to-b from-teal-50 dark:from-teal-900 to-white dark:to-gray-800 border border-teal-200 dark:border-teal-700 rounded-lg p-6 shadow hover:shadow-md transition">
<h3 class="text-2xl font-semibold text-teal-700 dark:text-teal-300 mb-2">Basic Electrical Circuit</h3>
<p class="text-teal-600 dark:text-teal-400">
Build an RC circuit, adjust R, C, and V₀, and watch the capacitor charge in real time.
</p>
<h2 class="text-4xl font-extrabold text-gray-800 dark:text-gray-100 mb-4">
{% trans "Welcome to the Alpha Science Lab" %}
</h2>
<p class="text-gray-600 dark:text-gray-300 mb-8">{% trans "Choose a subject to explore available virtual labs." %}</p>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-6">
{% for subject in virtual_lab_subjects %}
{% if subject.key == "physics" %}
<a href="{% url subject.url_name %}"
class="block bg-blue-50 dark:bg-blue-900 border border-blue-200 dark:border-blue-700 rounded-lg p-6 shadow hover:shadow-md transition focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-300 dark:focus:ring-blue-400 dark:focus:ring-offset-gray-800">
<h3 class="text-2xl font-semibold text-blue-700 dark:text-blue-300 mb-2">{{ subject.label }}</h3>
<p class="text-blue-600 dark:text-blue-400">
{% blocktrans with count=subject.labs|length %}Explore {{ count }} labs{% endblocktrans %}
</p>
</a>
{% elif subject.key == "chemistry" %}
<a href="{% url subject.url_name %}"
class="block bg-green-50 dark:bg-green-900 border border-green-200 dark:border-green-700 rounded-lg p-6 shadow hover:shadow-md transition focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-300 dark:focus:ring-green-400 dark:focus:ring-offset-gray-800">
<h3 class="text-2xl font-semibold text-green-700 dark:text-green-300 mb-2">{{ subject.label }}</h3>
<p class="text-green-600 dark:text-green-400">
{% blocktrans with count=subject.labs|length %}Explore {{ count }} labs{% endblocktrans %}
</p>
</a>
{% else %}
<a href="{% url subject.url_name %}"
class="block bg-indigo-50 dark:bg-indigo-900 border border-indigo-200 dark:border-indigo-700 rounded-lg p-6 shadow hover:shadow-md transition focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-300 dark:focus:ring-indigo-400 dark:focus:ring-offset-gray-800">
<h3 class="text-2xl font-semibold text-indigo-700 dark:text-indigo-300 mb-2">{{ subject.label }}</h3>
<p class="text-indigo-600 dark:text-indigo-400">
{% blocktrans with count=subject.labs|length %}Explore {{ count }} labs{% endblocktrans %}
</p>
</a>
{% endif %}
{% endfor %}
Comment on lines +16 to +42

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider data-driven styling to reduce template conditionals.

The if/elif/else chain for subject-specific colors works but is verbose. If more subjects are added, this pattern will grow. Consider adding color classes to the subject data structure in build_virtual_lab_subjects().

♻️ Example approach

In views.py, add color metadata:

{
    "key": "physics",
    "label": _("Physics"),
    "color": "blue",  # or "bg_class": "bg-blue-50 dark:bg-blue-900", etc.
    ...
}

Then simplify the template to use subject.color directly in class interpolation or a template filter.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/virtual_lab/templates/virtual_lab/home.html` around lines 16 - 42, The
template conditional chain should be replaced by data-driven styling: update
build_virtual_lab_subjects() to include a color (or full class strings like
bg_class, text_class, ring_class) on each subject dict (e.g., "color": "blue" or
"bg_class": "bg-blue-50 dark:bg-blue-900"), then simplify the virtual_lab home
template to interpolate those subject properties (e.g., use subject.bg_class,
subject.text_class, subject.ring_class) in the <a> and <h3>/<p> class attributes
instead of the if/elif/else block so adding new subjects only requires adding
metadata in build_virtual_lab_subjects().

<a href="{% url 'virtual_lab:code_editor' %}"
class="block bg-teal-50 dark:bg-teal-900 border border-teal-200 dark:border-teal-700 rounded-lg p-6 shadow hover:shadow-md transition focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-teal-300 dark:focus:ring-teal-400 dark:focus:ring-offset-gray-800">
<h3 class="text-2xl font-semibold text-teal-700 dark:text-teal-300 mb-2">{% trans "Code Editor" %}</h3>
<p class="text-teal-600 dark:text-teal-400">{% trans "Write and run code directly from the virtual lab." %}</p>
</a>
</div>
</div>
Expand Down
51 changes: 33 additions & 18 deletions web/virtual_lab/templates/virtual_lab/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,46 @@
<div class="min-h-screen flex flex-col bg-gray-50 dark:bg-gray-900">
<!-- Header -->
<header class="bg-white dark:bg-gray-800 shadow-sm">
<div class="max-w-6xl mx-auto px-6 py-4 flex items-center justify-between">
<div class="container mx-auto px-4 py-4 flex items-center justify-between">
<a href="{% url 'virtual_lab:virtual_lab_home' %}"
class="text-2xl font-bold text-indigo-600 dark:text-indigo-400 hover:text-indigo-800 dark:hover:text-indigo-300 transition">Alpha Science Lab</a>
<nav class="space-x-8 text-gray-700 dark:text-gray-300">
<!-- Home Link -->
<a href="{% url 'virtual_lab:virtual_lab_home' %}"
class="hover:text-indigo-600 dark:hover:text-indigo-400 transition">{% trans "Home" %}</a>
<!-- Physics Dropdown -->
<div class="relative group inline-block">
<button class="hover:text-indigo-600 dark:hover:text-indigo-400 transition focus:outline-none focus:ring-2 focus:ring-indigo-500">
{% trans "Physics" %}
</button>
<div class="absolute left-0 mt-2 w-40 bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-md shadow-lg opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 transition pointer-events-none group-hover:pointer-events-auto group-focus-within:pointer-events-auto">
<a href="{% url 'virtual_lab:physics_pendulum' %}"
class="block px-4 py-2 text-gray-700 dark:text-gray-300 hover:bg-indigo-50 dark:hover:bg-indigo-900 transition">{% trans "Pendulum" %}</a>
<a href="{% url 'virtual_lab:physics_projectile' %}"
class="block px-4 py-2 text-gray-700 dark:text-gray-300 hover:bg-green-50 dark:hover:bg-green-900 transition">{% trans "Projectile" %}</a>
<a href="{% url 'virtual_lab:physics_inclined' %}"
class="block px-4 py-2 text-gray-700 dark:text-gray-300 hover:bg-yellow-50 dark:hover:bg-yellow-900 transition">{% trans "Inclined Plane" %}</a>
class="hover:text-gray-900 dark:hover:text-white transition focus:text-gray-900 dark:focus:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-300 dark:focus:ring-indigo-400 dark:focus:ring-offset-gray-800">{% trans "Home" %}</a>
{% for subject in virtual_lab_subjects %}
<div class="relative group inline-block"
x-data="{ open: false }"
@mouseenter="open = true"
@mouseleave="open = false"
@focusin="open = true"
@focusout="if (!$el.contains($event.relatedTarget)) open = false">
<a href="{% url subject.url_name %}"
id="subject-menu-button-{{ forloop.counter }}"
aria-haspopup="menu"
:aria-expanded="open ? 'true' : 'false'"
aria-controls="subject-menu-{{ forloop.counter }}"
class="hover:text-gray-900 dark:hover:text-white transition focus:text-gray-900 dark:focus:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-400 dark:focus:ring-gray-300 dark:focus:ring-offset-gray-800">
{{ subject.label }}
</a>
<div id="subject-menu-{{ forloop.counter }}"
role="menu"
aria-labelledby="subject-menu-button-{{ forloop.counter }}"
class="absolute left-0 top-full pt-1 w-56 opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 transition pointer-events-none group-hover:pointer-events-auto group-focus-within:pointer-events-auto z-20"
:class="open ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'">
<div class="bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-md shadow-lg">
{% for lab in subject.labs %}
<a href="{% url lab.url_name %}"
role="menuitem"
:tabindex="open ? 0 : -1"
class="block px-4 py-2 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-600 transition">{{ lab.label }}</a>
{% endfor %}
</div>
</div>
</div>
</div>
<a href="{% url 'virtual_lab:chemistry_home' %}"
class="hover:text-indigo-600 dark:hover:text-indigo-400 transition">{% trans "Chemistry" %}</a>
{% endfor %}
<a href="{% url 'virtual_lab:code_editor' %}"
class="hover:text-indigo-600 dark:hover:text-indigo-400 transition">{% trans "Code Editor" %}</a>
class="hover:text-gray-900 dark:hover:text-white transition focus:text-gray-900 dark:focus:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-teal-300 dark:focus:ring-teal-400 dark:focus:ring-offset-gray-800">{% trans "Code Editor" %}</a>
</nav>
</div>
</header>
Expand Down
51 changes: 51 additions & 0 deletions web/virtual_lab/templates/virtual_lab/physics/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{% extends "virtual_lab/layout.html" %}

{% load i18n %}

{% block virtual_lab_content %}
<div class="container mx-auto px-4 py-8">
<div class="bg-white dark:bg-gray-800 shadow-lg rounded-lg overflow-hidden">
<div class="px-8 py-6">
<h2 class="text-4xl font-extrabold text-gray-800 dark:text-gray-100 mb-4">{% trans "Physics Experiments" %}</h2>
<p class="text-gray-600 dark:text-gray-300 mb-8">
{% trans "Explore these interactive physics simulations. Click on any card below to begin." %}
</p>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
<a href="{% url 'virtual_lab:physics_pendulum' %}"
class="block bg-gradient-to-b from-blue-50 dark:from-blue-900 to-white dark:to-gray-800 border border-blue-200 dark:border-blue-700 rounded-lg p-6 shadow hover:shadow-md transition focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:focus:ring-offset-gray-800">
<h3 class="text-2xl font-semibold text-blue-700 dark:text-blue-300 mb-2">{% trans "Pendulum Motion" %}</h3>
<p class="text-blue-600 dark:text-blue-400">{% trans "Visualize how length affects a pendulum's period." %}</p>
</a>
<a href="{% url 'virtual_lab:physics_projectile' %}"
class="block bg-gradient-to-b from-green-50 dark:from-green-900 to-white dark:to-gray-800 border border-green-200 dark:border-green-700 rounded-lg p-6 shadow hover:shadow-md transition focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 dark:focus:ring-offset-gray-800">
<h3 class="text-2xl font-semibold text-green-700 dark:text-green-300 mb-2">{% trans "Projectile Motion" %}</h3>
<p class="text-green-600 dark:text-green-400">
{% trans "Launch a projectile and observe its real-time trajectory." %}
</p>
</a>
<a href="{% url 'virtual_lab:physics_inclined' %}"
class="block bg-gradient-to-b from-yellow-50 dark:from-yellow-900 to-white dark:to-gray-800 border border-yellow-200 dark:border-yellow-700 rounded-lg p-6 shadow hover:shadow-md transition focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-yellow-500 dark:focus:ring-offset-gray-800">
<h3 class="text-2xl font-semibold text-yellow-800 dark:text-yellow-300 mb-2">{% trans "Inclined Plane" %}</h3>
<p class="text-yellow-700 dark:text-yellow-400">
{% trans "See a block slide down and discover acceleration on a ramp." %}
</p>
</a>
<a href="{% url 'virtual_lab:physics_mass_spring' %}"
class="block bg-gradient-to-b from-purple-50 dark:from-purple-900 to-white dark:to-gray-800 border border-purple-200 dark:border-purple-700 rounded-lg p-6 shadow hover:shadow-md transition focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500 dark:focus:ring-offset-gray-800">
<h3 class="text-2xl font-semibold text-purple-700 dark:text-purple-300 mb-2">{% trans "Mass-Spring Oscillation" %}</h3>
<p class="text-purple-600 dark:text-purple-400">
{% trans "Set k and m, drag the mass, then watch it oscillate and view x(t)." %}
</p>
</a>
<a href="{% url 'virtual_lab:physics_electrical_circuit' %}"
class="block bg-gradient-to-b from-teal-50 dark:from-teal-900 to-white dark:to-gray-800 border border-teal-200 dark:border-teal-700 rounded-lg p-6 shadow hover:shadow-md transition focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-teal-500 dark:focus:ring-offset-gray-800">
<h3 class="text-2xl font-semibold text-teal-700 dark:text-teal-300 mb-2">{% trans "Basic Electrical Circuit" %}</h3>
<p class="text-teal-600 dark:text-teal-400">
{% trans "Build an RC circuit, adjust R, C, and V0, and watch the capacitor charge in real time." %}
</p>
</a>
</div>
</div>
</div>
</div>
{% endblock virtual_lab_content %}
14 changes: 8 additions & 6 deletions web/virtual_lab/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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"),
]
Loading
Loading