- Per-app skeleton completion: property/client/setting now have services/,
tasks.py, views.py, urls.py, serializers.py, templates/<app>/, tests/
- admin.py added to all 10 apps (per spec §2.108 / §17.3)
- Top-level templates/: base.html, layouts/{app,auth}.html, components/
{topbar,sidebar,pagination,toast,modal,empty-state}.html, errors/
{403,404,500}.html
- static/: css/main.css (Tailwind entry), js/main.js (HTMX toast +
CSRF wiring per §7.4), vendor/.gitkeep
- tailwind.config.js: Primary teal + neutral slate + semantic colors,
Inter font stack, z-60/z-70, shadow-xs, slide-in-right animation per
UI_SYSTEM §2.7/§10.1
- package.json: tailwindcss-only build/watch
- Dockerfile + docker-compose.yml (6 services: web/db/redis/celery/
celery-beat/tailwind) + docker-compose.prod.yml + Makefile
- tests/ root: conftest.py with TenantClient fixture per §720,
integration/{property,client,release}/, e2e/, schemathesis skeleton
- Removed empty apps/tenant/models/ (tenant uses models.py per §17.1)
Validated: manage.py check passes; tree matches spec §2 exactly.
39 lines
1.2 KiB
HTML
39 lines
1.2 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block body_class %}bg-neutral-50 text-neutral-900{% endblock %}
|
||
|
||
{% block content %}
|
||
<div x-data="{ sidebarOpen: $persist(true) }" class="min-h-screen flex flex-col">
|
||
{% include "components/topbar.html" %}
|
||
|
||
<div class="flex flex-1">
|
||
{% include "components/sidebar.html" %}
|
||
|
||
<main :class="sidebarOpen ? 'ml-60' : 'ml-16'" class="flex-1 px-6 py-4 transition-all">
|
||
{% block main %}{% endblock %}
|
||
</main>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="small-screen-gate"
|
||
class="hidden fixed inset-0 bg-neutral-900/95 text-white items-center justify-center z-[100] text-center px-6">
|
||
<p class="text-lg">Fonrey 当前仅支持桌面端(≥1280px),请在电脑上访问</p>
|
||
</div>
|
||
<script>
|
||
(function () {
|
||
var gate = document.getElementById('small-screen-gate');
|
||
function check() {
|
||
if (window.innerWidth < 1280) {
|
||
gate.classList.remove('hidden');
|
||
gate.classList.add('flex');
|
||
} else {
|
||
gate.classList.add('hidden');
|
||
gate.classList.remove('flex');
|
||
}
|
||
}
|
||
window.addEventListener('resize', check);
|
||
check();
|
||
})();
|
||
</script>
|
||
{% endblock %}
|