feat(ui): add web UI with Jinja2 templates and Gitea themes

- Add Jinja2 templates with data-testid attributes for testing
- Create light/dark themes based on Gitea color scheme
- Add theme switching with localStorage persistence
- Create base CSS, components, and layout styles
- Add mock web routes for UI demonstration
- Register web router and static files in main.py
- Add data-testid requirements to AGENTS.md
- Install jinja2 dependency
This commit is contained in:
2026-05-02 14:45:51 +03:00
parent ca4e8877a5
commit e2802d83f2
18 changed files with 2212 additions and 1 deletions

View File

@@ -0,0 +1,58 @@
{% extends "base.html" %}
{% block title %}{{ post.title }} - Blog{% endblock %}
{% block meta_description %}{{ post.content.value[:160] }}{% endblock %}
{% block content %}
<article class="post-detail" data-testid="post-detail">
<header class="post-detail-header" data-testid="post-detail-header">
<h1 class="post-detail-title" data-testid="post-detail-title">{{ post.title }}</h1>
<div class="post-detail-meta" data-testid="post-detail-meta">
<span class="post-card-meta-item" data-testid="post-detail-author">
<span class="avatar avatar-sm" data-testid="post-detail-author-avatar">{{ post.author_id[0]|upper }}</span>
<span data-testid="post-detail-author-name">{{ post.author_id }}</span>
</span>
<span class="post-card-meta-item" data-testid="post-detail-date">
{{ post.created_at.strftime('%B %d, %Y') }}
</span>
{% if post.published %}
<span class="badge badge-success" data-testid="post-detail-status">Published</span>
{% else %}
<span class="badge" data-testid="post-detail-status">Draft</span>
{% endif %}
</div>
</header>
<div class="post-detail-content" data-testid="post-detail-content">
{{ post.content.value|nl2br }}
</div>
<footer class="post-detail-footer" data-testid="post-detail-footer">
<div class="post-detail-tags" data-testid="post-detail-tags">
{% for tag in post.tags %}
<span class="tag" data-testid="post-detail-tag-{{ loop.index }}">{{ tag }}</span>
{% endfor %}
</div>
<div class="divider" data-testid="post-detail-divider"></div>
<div class="flex justify-between items-center" data-testid="post-detail-actions">
<a href="/" class="btn" data-testid="btn-back-to-posts">
← Back to posts
</a>
<div class="flex gap-2" data-testid="post-detail-edit-actions">
<a href="/posts/{{ post.id }}/edit" class="btn" data-testid="btn-edit-post">
Edit
</a>
<form action="/posts/{{ post.id }}/delete" method="POST" style="display: inline;" data-testid="form-delete-post">
<button type="submit" class="btn btn-danger" data-testid="btn-delete-post" onclick="return confirm('Are you sure you want to delete this post?');">
Delete
</button>
</form>
</div>
</div>
</footer>
</article>
{% endblock %}