Phase 2: T-201 至 T-206 前台 MVP 全部实现(11 templates + CSS + 31 tests)

This commit is contained in:
ila
2026-07-06 22:57:08 +08:00
parent 5604e2cde5
commit cff3c64c19
20 changed files with 996 additions and 98 deletions
@@ -0,0 +1,19 @@
{% extends "base.html" %}
{% block content %}
<h1>{{ page.title }}</h1>
{% if page.get_children.live %}
<div class="card-grid">
{% for article in page.get_children.live %}
<a class="card" href="{% url 'wagtail_serve' '' %}articles/{{ article.slug }}/">
<h3>{{ article.title }}</h3>
</a>
{% endfor %}
</div>
{% else %}
{% include "includes/empty_state.html" with message="No articles yet." %}
{% endif %}
{% endblock %}
+21
View File
@@ -0,0 +1,21 @@
{% extends "base.html" %}
{% block content %}
<h1>{{ page.title }}</h1>
<div class="rich-text">{{ page.body|safe }}</div>
{% if page.related_projects.exists %}
<h2>Related Projects</h2>
<div class="card-grid">
{% for project in page.related_projects.all %}
<a class="card" href="{% url 'wagtail_serve' '' %}projects/{{ project.slug }}/">
<h3>{{ project.title }}</h3>
<p>{{ project.summary|truncatewords:20 }}</p>
</a>
{% endfor %}
</div>
{% endif %}
{% endblock %}
@@ -0,0 +1,85 @@
{% extends "base.html" %}
{% block content %}
<h1>{{ page.title }}</h1>
<form class="filters" method="get">
<label>
Language:
<select name="language">
<option value="">All</option>
{% for lang in languages %}
<option value="{{ lang.slug }}" {% if current_language == lang.slug %}selected{% endif %}>{{ lang.name }}</option>
{% endfor %}
</select>
</label>
<label>
Framework:
<select name="framework">
<option value="">All</option>
{% for fw in frameworks %}
<option value="{{ fw.slug }}" {% if current_framework == fw.slug %}selected{% endif %}>{{ fw.name }}</option>
{% endfor %}
</select>
</label>
<label>
Database:
<select name="database">
<option value="">All</option>
{% for db in databases %}
<option value="{{ db.slug }}" {% if current_database == db.slug %}selected{% endif %}>{{ db.name }}</option>
{% endfor %}
</select>
</label>
<label>
Min Score:
<input type="number" name="min_score" min="0" max="30" value="{{ current_min_score }}" style="width:5ch;">
</label>
<label>
Search:
<input type="text" name="q" value="{{ current_q }}" placeholder="Keyword...">
</label>
<button type="submit">Filter</button>
</form>
{% if projects %}
<div class="card-grid">
{% for project in projects %}
<a class="card" href="{% url 'wagtail_serve' '' %}projects/{{ project.slug }}/">
<h3>{{ project.title }}</h3>
<p>{{ project.summary|truncatewords:20 }}</p>
<div class="score-bar">
<span class="score-total">{{ project.total_score }}/30</span>
<span class="score-detail">AI-Friendly Score</span>
</div>
<div class="tag-list">
{% for lang in project.languages.all|slice:":3" %}
<span class="tag">{{ lang.name }}</span>
{% endfor %}
</div>
</a>
{% endfor %}
</div>
{% if projects.paginator.num_pages > 1 %}
<nav class="pagination">
{% if projects.has_previous %}
<a href="?{% for k,v in request.GET.items %}{% if k != 'page' %}{{ k }}={{ v }}&{% endif %}{% endfor %}page={{ projects.previous_page_number }}">&laquo; Prev</a>
{% endif %}
<span class="current">Page {{ projects.number }} of {{ projects.paginator.num_pages }}</span>
{% if projects.has_next %}
<a href="?{% for k,v in request.GET.items %}{% if k != 'page' %}{{ k }}={{ v }}&{% endif %}{% endfor %}page={{ projects.next_page_number }}">Next &raquo;</a>
{% endif %}
</nav>
{% endif %}
{% else %}
{% include "includes/empty_state.html" with message="No projects match your filters." %}
{% endif %}
{% endblock %}
+29
View File
@@ -0,0 +1,29 @@
{% extends "base.html" %}
{% block content %}
<h1>{{ page.title }}</h1>
{% if projects %}
<div class="card-grid">
{% for project in projects %}
<a class="card" href="{% url 'wagtail_serve' '' %}projects/{{ project.slug }}/">
<h3>{{ project.title }}</h3>
<p>{{ project.summary|truncatewords:20 }}</p>
<div class="score-bar">
<span class="score-total">{{ project.total_score }}/30</span>
<span class="score-detail">AI-Friendly Score</span>
</div>
<div class="tag-list">
{% for lang in project.languages.all|slice:":3" %}
<span class="tag">{{ lang.name }}</span>
{% endfor %}
</div>
</a>
{% endfor %}
</div>
{% else %}
{% include "includes/empty_state.html" with message="No projects found in this scenario." %}
{% endif %}
{% endblock %}
@@ -0,0 +1,76 @@
{% extends "base.html" %}
{% block content %}
<article>
<h1>
{{ page.title }}
{% if page.is_featured %}<span class="badge badge-featured">Featured</span>{% endif %}
{% if page.is_sponsored %}{% include "includes/sponsored_badge.html" %}{% endif %}
</h1>
<p class="rich-text">{{ page.summary }}</p>
<table class="data-table">
<tr><th>GitHub</th><td><a href="{{ page.github_url }}" target="_blank" rel="noopener">{{ page.github_url }}</a></td></tr>
{% if page.official_url %}
<tr><th>Official Site</th><td><a href="{{ page.official_url }}" target="_blank" rel="noopener">{{ page.official_url }}</a></td></tr>
{% endif %}
{% if page.license_name %}
<tr><th>License</th><td>{{ page.license_name }}</td></tr>
{% endif %}
<tr><th>Maturity</th><td>{{ page.get_maturity_display }}</td></tr>
<tr><th>Maintenance</th><td>{{ page.get_maintenance_status_display }}</td></tr>
{% if page.scenarios.exists %}
<tr><th>Scenarios</th><td>
{% for s in page.scenarios.all %}<span class="tag">{{ s.title }}</span>{% endfor %}
</td></tr>
{% endif %}
{% if page.languages.exists %}
<tr><th>Languages</th><td>
{% for l in page.languages.all %}<span class="tag">{{ l.name }}</span>{% endfor %}
</td></tr>
{% endif %}
{% if page.frameworks.exists %}
<tr><th>Frameworks</th><td>
{% for f in page.frameworks.all %}<span class="tag">{{ f.name }}</span>{% endfor %}
</td></tr>
{% endif %}
{% if page.databases.exists %}
<tr><th>Databases</th><td>
{% for d in page.databases.all %}<span class="tag">{{ d.name }}</span>{% endfor %}
</td></tr>
{% endif %}
{% if page.features.exists %}
<tr><th>Features</th><td>
{% for feat in page.features.all %}<span class="tag">{{ feat.name }}</span>{% endfor %}
</td></tr>
{% endif %}
</table>
<h2>Scores</h2>
<table class="data-table">
<tr><th>Structure</th><td>{{ page.structure_score }}/5</td></tr>
<tr><th>Documentation</th><td>{{ page.docs_score }}/5</td></tr>
<tr><th>Testing</th><td>{{ page.tests_score }}/5</td></tr>
<tr><th>Examples</th><td>{{ page.example_score }}/5</td></tr>
<tr><th>Dependency Control</th><td>{{ page.dependency_score }}/5</td></tr>
<tr><th>Incremental Development</th><td>{{ page.incremental_score }}/5</td></tr>
<tr><th>Total</th><td><strong>{{ page.total_score }}/30</strong></td></tr>
</table>
<h2>Recommended For</h2>
<div class="rich-text">{{ page.recommended_for|safe }}</div>
{% if page.not_recommended_for %}
<h2>Not Recommended For</h2>
<div class="rich-text">{{ page.not_recommended_for|safe }}</div>
{% endif %}
{% if page.review_notes %}
<h2>Review Notes</h2>
<div class="rich-text">{{ page.review_notes|safe }}</div>
{% endif %}
</article>
{% endblock %}