feat: domain > area > project hierarchy for daily focus with compact padding

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-03 15:11:36 +00:00
parent 50200c23cc
commit ec2bd51585
2 changed files with 77 additions and 29 deletions

View File

@@ -39,7 +39,11 @@ async def focus_view(
t.project_id, t.due_date, t.estimated_minutes,
COALESCE(p.name, lp.name) as project_name,
COALESCE(t.project_id, l.project_id) as effective_project_id,
d.name as domain_name, d.color as domain_color,
COALESCE(d.name, ld.name) as domain_name,
COALESCE(d.color, ld.color) as domain_color,
COALESCE(d.id, ld.id) as effective_domain_id,
COALESCE(a.name, la.name) as area_name,
COALESCE(a.id, la.id) as effective_area_id,
li.content as list_item_content, li.list_id as list_item_list_id,
li.completed as list_item_completed,
l.name as list_name
@@ -47,24 +51,50 @@ async def focus_view(
LEFT JOIN tasks t ON df.task_id = t.id
LEFT JOIN projects p ON t.project_id = p.id
LEFT JOIN domains d ON t.domain_id = d.id
LEFT JOIN areas a ON t.area_id = a.id
LEFT JOIN list_items li ON df.list_item_id = li.id
LEFT JOIN lists l ON li.list_id = l.id
LEFT JOIN projects lp ON l.project_id = lp.id
LEFT JOIN domains ld ON l.domain_id = ld.id
LEFT JOIN areas la ON l.area_id = la.id
WHERE df.focus_date = :target_date AND df.is_deleted = false
ORDER BY df.sort_order, df.created_at
"""), {"target_date": target_date})
items = [dict(r._mapping) for r in result]
# Group items by project for template rendering
# Build Domain > Area > Project hierarchy
from collections import OrderedDict
_groups = OrderedDict()
domain_map = OrderedDict()
for item in items:
key = item.get("effective_project_id") or "__general__"
label = item.get("project_name") or "General"
if key not in _groups:
_groups[key] = {"label": label, "rows": []}
_groups[key]["rows"].append(item)
grouped_items = list(_groups.values())
dk = item.get("effective_domain_id") or "__none__"
dl = item.get("domain_name") or "General"
dc = item.get("domain_color") or ""
if dk not in domain_map:
domain_map[dk] = {"label": dl, "color": dc, "areas": OrderedDict()}
ak = item.get("effective_area_id") or "__none__"
al = item.get("area_name") or ""
area_map = domain_map[dk]["areas"]
if ak not in area_map:
area_map[ak] = {"label": al, "projects": OrderedDict()}
pk = item.get("effective_project_id") or "__none__"
pl = item.get("project_name") or ""
proj_map = area_map[ak]["projects"]
if pk not in proj_map:
proj_map[pk] = {"label": pl, "rows": []}
proj_map[pk]["rows"].append(item)
# Convert to nested lists for Jinja
hierarchy = []
for dk, dv in domain_map.items():
domain_group = {"label": dv["label"], "color": dv["color"], "areas": []}
for ak, av in dv["areas"].items():
area_group = {"label": av["label"], "projects": []}
for pk, pv in av["projects"].items():
area_group["projects"].append({"label": pv["label"], "rows": pv["rows"]})
domain_group["areas"].append(area_group)
hierarchy.append(domain_group)
# --- Available tasks ---
available_tasks = []
@@ -152,7 +182,7 @@ async def focus_view(
return templates.TemplateResponse("focus.html", {
"request": request, "sidebar": sidebar,
"items": items, "grouped_items": grouped_items,
"items": items, "hierarchy": hierarchy,
"available_tasks": available_tasks,
"available_list_items": available_list_items,
"focus_date": target_date,