R1 foundation - Phase 1 live build
This commit is contained in:
22
templates/area_form.html
Normal file
22
templates/area_form.html
Normal file
@@ -0,0 +1,22 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="breadcrumb"><a href="/areas">Areas</a><span class="sep">/</span><span>{{ 'Edit' if item else 'New Area' }}</span></div>
|
||||
<div class="page-header"><h1 class="page-title">{{ 'Edit Area' if item else 'New Area' }}</h1></div>
|
||||
<div class="card">
|
||||
<form method="post" action="{{ '/areas/' ~ item.id ~ '/edit' if item else '/areas/create' }}">
|
||||
<div class="form-grid">
|
||||
<div class="form-group"><label class="form-label">Name *</label><input type="text" name="name" class="form-input" required value="{{ item.name if item else '' }}"></div>
|
||||
<div class="form-group"><label class="form-label">Domain *</label>
|
||||
<select name="domain_id" class="form-select" required>
|
||||
{% for d in domains %}<option value="{{ d.id }}" {{ 'selected' if (item and item.domain_id|string == d.id|string) or (not item and prefill_domain_id == d.id|string) }}>{{ d.name }}</option>{% endfor %}
|
||||
</select></div>
|
||||
<div class="form-group"><label class="form-label">Status</label>
|
||||
<select name="status" class="form-select">
|
||||
<option value="active" {{ 'selected' if not item or item.status == 'active' }}>Active</option>
|
||||
<option value="inactive" {{ 'selected' if item and item.status == 'inactive' }}>Inactive</option>
|
||||
</select></div>
|
||||
<div class="form-group full-width"><label class="form-label">Description</label><textarea name="description" class="form-textarea" rows="3">{{ item.description if item and item.description else '' }}</textarea></div>
|
||||
<div class="form-actions"><button type="submit" class="btn btn-primary">{{ 'Save' if item else 'Create' }}</button><a href="/areas" class="btn btn-secondary">Cancel</a></div>
|
||||
</div>
|
||||
</form></div>
|
||||
{% endblock %}
|
||||
25
templates/areas.html
Normal file
25
templates/areas.html
Normal file
@@ -0,0 +1,25 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Areas<span class="page-count">{{ items|length }}</span></h1>
|
||||
<a href="/areas/create" class="btn btn-primary">+ New Area</a>
|
||||
</div>
|
||||
{% if items %}
|
||||
<div class="card">
|
||||
{% for item in items %}
|
||||
<div class="list-row">
|
||||
<span class="row-domain-tag" style="background:{{ item.domain_color or '#4F6EF7' }}22;color:{{ item.domain_color or '#4F6EF7' }}">{{ item.domain_name }}</span>
|
||||
<span class="row-title">{{ item.name }}</span>
|
||||
{% if item.description %}<span class="row-meta">{{ item.description[:60] }}</span>{% endif %}
|
||||
<span class="status-badge status-{{ item.status }}">{{ item.status }}</span>
|
||||
<div class="row-actions">
|
||||
<a href="/areas/{{ item.id }}/edit" class="btn btn-ghost btn-xs">Edit</a>
|
||||
<form action="/areas/{{ item.id }}/delete" method="post" data-confirm="Delete this area?" style="display:inline"><button class="btn btn-ghost btn-xs" style="color:var(--red)">Del</button></form>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state"><div class="empty-state-text">No areas yet</div><a href="/areas/create" class="btn btn-primary">Create Area</a></div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
111
templates/base.html
Normal file
111
templates/base.html
Normal file
@@ -0,0 +1,111 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{ page_title or "Life OS" }} - Life OS</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-layout">
|
||||
<!-- Sidebar -->
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<a href="/" class="sidebar-logo">Life<span>OS</span></a>
|
||||
</div>
|
||||
<nav class="sidebar-nav">
|
||||
<div class="nav-section">
|
||||
<a href="/" class="nav-item {{ 'active' if active_nav == 'dashboard' }}">
|
||||
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
|
||||
Dashboard
|
||||
</a>
|
||||
<a href="/focus" class="nav-item {{ 'active' if active_nav == 'focus' }}">
|
||||
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></svg>
|
||||
Focus
|
||||
{% if sidebar.focus_count %}<span class="badge">{{ sidebar.focus_count }}</span>{% endif %}
|
||||
</a>
|
||||
<a href="/tasks" class="nav-item {{ 'active' if active_nav == 'tasks' }}">
|
||||
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>
|
||||
All Tasks
|
||||
</a>
|
||||
<a href="/projects" class="nav-item {{ 'active' if active_nav == 'projects' }}">
|
||||
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>
|
||||
Projects
|
||||
</a>
|
||||
<a href="/notes" class="nav-item {{ 'active' if active_nav == 'notes' }}">
|
||||
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>
|
||||
Notes
|
||||
</a>
|
||||
<a href="/contacts" class="nav-item {{ 'active' if active_nav == 'contacts' }}">
|
||||
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
|
||||
Contacts
|
||||
</a>
|
||||
<a href="/links" class="nav-item {{ 'active' if active_nav == 'links' }}">
|
||||
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
|
||||
Links
|
||||
</a>
|
||||
<a href="/capture" class="nav-item {{ 'active' if active_nav == 'capture' }}">
|
||||
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="22 12 16 12 14 15 10 15 8 12 2 12"/><path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/></svg>
|
||||
Capture
|
||||
{% if sidebar.capture_count %}<span class="badge">{{ sidebar.capture_count }}</span>{% endif %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Domain hierarchy -->
|
||||
<div class="nav-section">
|
||||
<div class="nav-section-label">Domains</div>
|
||||
{% for domain in sidebar.domain_tree %}
|
||||
<div class="domain-group">
|
||||
<div class="domain-header" data-domain-id="{{ domain.id }}">
|
||||
<span class="domain-dot" style="background: {{ domain.color or '#4F6EF7' }}"></span>
|
||||
{{ domain.name }}
|
||||
</div>
|
||||
<div class="domain-children" data-domain-id="{{ domain.id }}">
|
||||
{% for area in domain.areas %}
|
||||
<div class="area-label">{{ area.name }}</div>
|
||||
{% for p in area.projects %}
|
||||
<a href="/projects/{{ p.id }}" class="project-link">{{ p.name }}</a>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% for p in domain.standalone_projects %}
|
||||
<a href="/projects/{{ p.id }}" class="project-link">{{ p.name }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="nav-section" style="margin-top: auto; padding-bottom: 12px;">
|
||||
<a href="/domains" class="nav-item {{ 'active' if active_nav == 'domains' }}">
|
||||
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M12 1v6m0 6v6m-7-7h6m6 0h6"/></svg>
|
||||
Manage Domains
|
||||
</a>
|
||||
<a href="/areas" class="nav-item {{ 'active' if active_nav == 'areas' }}">
|
||||
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="9" y1="21" x2="9" y2="9"/></svg>
|
||||
Manage Areas
|
||||
</a>
|
||||
<div class="nav-item" onclick="toggleTheme()" style="cursor: pointer;">
|
||||
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
|
||||
Toggle Theme
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<!-- Main content -->
|
||||
<main class="main-content">
|
||||
<header class="topbar">
|
||||
{% if request.state.environment == 'development' %}
|
||||
<span class="topbar-env">DEV</span>
|
||||
{% endif %}
|
||||
<div class="topbar-spacer"></div>
|
||||
</header>
|
||||
|
||||
<div class="page-content">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<script src="/static/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
42
templates/capture.html
Normal file
42
templates/capture.html
Normal file
@@ -0,0 +1,42 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Capture<span class="page-count">{{ items|length }}</span></h1>
|
||||
</div>
|
||||
|
||||
<!-- Quick capture input -->
|
||||
<div class="card mb-4">
|
||||
<form action="/capture/add" method="post">
|
||||
<label class="form-label mb-2">Quick Capture (one item per line)</label>
|
||||
<textarea name="raw_text" class="form-textarea" rows="3" placeholder="Type or paste items here... Each line becomes a separate capture item"></textarea>
|
||||
<div class="mt-2"><button type="submit" class="btn btn-primary">Capture</button></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<a href="/capture?show=unprocessed" class="btn {{ 'btn-primary' if show != 'all' else 'btn-secondary' }} btn-sm">Unprocessed</a>
|
||||
<a href="/capture?show=all" class="btn {{ 'btn-primary' if show == 'all' else 'btn-secondary' }} btn-sm">All</a>
|
||||
</div>
|
||||
|
||||
{% if items %}
|
||||
{% for item in items %}
|
||||
<div class="capture-item {{ 'completed' if item.processed }}">
|
||||
<div class="capture-text {{ 'text-muted' if item.processed }}" style="{{ 'text-decoration:line-through' if item.processed }}">{{ item.raw_text }}</div>
|
||||
{% if not item.processed %}
|
||||
<div class="capture-actions">
|
||||
<form action="/capture/{{ item.id }}/to-task" method="post" class="flex gap-2">
|
||||
<select name="domain_id" class="filter-select" style="font-size:0.75rem;padding:3px 6px" required>
|
||||
{% for d in sidebar.domain_tree %}<option value="{{ d.id }}">{{ d.name }}</option>{% endfor %}
|
||||
</select>
|
||||
<button type="submit" class="btn btn-ghost btn-xs" style="color:var(--green)">To Task</button>
|
||||
</form>
|
||||
<form action="/capture/{{ item.id }}/dismiss" method="post" style="display:inline"><button class="btn btn-ghost btn-xs">Dismiss</button></form>
|
||||
<form action="/capture/{{ item.id }}/delete" method="post" style="display:inline"><button class="btn btn-ghost btn-xs" style="color:var(--red)">×</button></form>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="empty-state"><div class="empty-state-icon">📥</div><div class="empty-state-text">Capture queue is empty</div></div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
25
templates/contact_detail.html
Normal file
25
templates/contact_detail.html
Normal file
@@ -0,0 +1,25 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="breadcrumb"><a href="/contacts">Contacts</a><span class="sep">/</span><span>{{ item.first_name }} {{ item.last_name or '' }}</span></div>
|
||||
<div class="detail-header">
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="detail-title">{{ item.first_name }} {{ item.last_name or '' }}</h1>
|
||||
<div class="flex gap-2">
|
||||
<a href="/contacts/{{ item.id }}/edit" class="btn btn-secondary btn-sm">Edit</a>
|
||||
<form action="/contacts/{{ item.id }}/delete" method="post" data-confirm="Delete?" style="display:inline"><button class="btn btn-danger btn-sm">Delete</button></form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-meta mt-2">
|
||||
{% if item.company %}<span class="row-tag">{{ item.company }}</span>{% endif %}
|
||||
{% if item.role %}<span class="detail-meta-item">{{ item.role }}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="form-grid" style="gap:12px">
|
||||
{% if item.email %}<div class="form-group"><div class="form-label">Email</div><a href="mailto:{{ item.email }}">{{ item.email }}</a></div>{% endif %}
|
||||
{% if item.phone %}<div class="form-group"><div class="form-label">Phone</div><a href="tel:{{ item.phone }}">{{ item.phone }}</a></div>{% endif %}
|
||||
{% if item.notes %}<div class="form-group full-width"><div class="form-label">Notes</div><div class="detail-body" style="white-space:pre-wrap">{{ item.notes }}</div></div>{% endif %}
|
||||
{% if item.tags %}<div class="form-group full-width"><div class="form-label">Tags</div><div class="flex gap-2">{% for tag in item.tags %}<span class="row-tag">{{ tag }}</span>{% endfor %}</div></div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
19
templates/contact_form.html
Normal file
19
templates/contact_form.html
Normal file
@@ -0,0 +1,19 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="breadcrumb"><a href="/contacts">Contacts</a><span class="sep">/</span><span>{{ 'Edit' if item else 'New Contact' }}</span></div>
|
||||
<div class="page-header"><h1 class="page-title">{{ 'Edit Contact' if item else 'New Contact' }}</h1></div>
|
||||
<div class="card">
|
||||
<form method="post" action="{{ '/contacts/' ~ item.id ~ '/edit' if item else '/contacts/create' }}">
|
||||
<div class="form-grid">
|
||||
<div class="form-group"><label class="form-label">First Name *</label><input type="text" name="first_name" class="form-input" required value="{{ item.first_name if item else '' }}"></div>
|
||||
<div class="form-group"><label class="form-label">Last Name</label><input type="text" name="last_name" class="form-input" value="{{ item.last_name if item and item.last_name else '' }}"></div>
|
||||
<div class="form-group"><label class="form-label">Company</label><input type="text" name="company" class="form-input" value="{{ item.company if item and item.company else '' }}"></div>
|
||||
<div class="form-group"><label class="form-label">Role</label><input type="text" name="role" class="form-input" value="{{ item.role if item and item.role else '' }}"></div>
|
||||
<div class="form-group"><label class="form-label">Email</label><input type="email" name="email" class="form-input" value="{{ item.email if item and item.email else '' }}"></div>
|
||||
<div class="form-group"><label class="form-label">Phone</label><input type="tel" name="phone" class="form-input" value="{{ item.phone if item and item.phone else '' }}"></div>
|
||||
<div class="form-group full-width"><label class="form-label">Notes</label><textarea name="notes" class="form-textarea" rows="4">{{ item.notes if item and item.notes else '' }}</textarea></div>
|
||||
<div class="form-group full-width"><label class="form-label">Tags</label><input type="text" name="tags" class="form-input" value="{{ item.tags|join(', ') if item and item.tags else '' }}"></div>
|
||||
<div class="form-actions"><button type="submit" class="btn btn-primary">{{ 'Save' if item else 'Create' }}</button><a href="/contacts" class="btn btn-secondary">Cancel</a></div>
|
||||
</div>
|
||||
</form></div>
|
||||
{% endblock %}
|
||||
25
templates/contacts.html
Normal file
25
templates/contacts.html
Normal file
@@ -0,0 +1,25 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Contacts<span class="page-count">{{ items|length }}</span></h1>
|
||||
<a href="/contacts/create" class="btn btn-primary">+ New Contact</a>
|
||||
</div>
|
||||
{% if items %}
|
||||
<div class="card">
|
||||
{% for item in items %}
|
||||
<div class="list-row">
|
||||
<span class="row-title"><a href="/contacts/{{ item.id }}">{{ item.first_name }} {{ item.last_name or '' }}</a></span>
|
||||
{% if item.company %}<span class="row-tag">{{ item.company }}</span>{% endif %}
|
||||
{% if item.role %}<span class="row-meta">{{ item.role }}</span>{% endif %}
|
||||
{% if item.email %}<span class="row-meta">{{ item.email }}</span>{% endif %}
|
||||
<div class="row-actions">
|
||||
<a href="/contacts/{{ item.id }}/edit" class="btn btn-ghost btn-xs">Edit</a>
|
||||
<form action="/contacts/{{ item.id }}/delete" method="post" data-confirm="Delete?" style="display:inline"><button class="btn btn-ghost btn-xs" style="color:var(--red)">Del</button></form>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state"><div class="empty-state-icon">👤</div><div class="empty-state-text">No contacts yet</div><a href="/contacts/create" class="btn btn-primary">Add Contact</a></div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
86
templates/dashboard.html
Normal file
86
templates/dashboard.html
Normal file
@@ -0,0 +1,86 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Dashboard</h1>
|
||||
</div>
|
||||
|
||||
<!-- Stats -->
|
||||
<div class="dashboard-grid mb-4">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ stats.open_tasks or 0 }}</div>
|
||||
<div class="stat-label">Open Tasks</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ stats.in_progress or 0 }}</div>
|
||||
<div class="stat-label">In Progress</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ stats.done_this_week or 0 }}</div>
|
||||
<div class="stat-label">Done This Week</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ focus_items|length }}</div>
|
||||
<div class="stat-label">Today's Focus</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-grid">
|
||||
<!-- Today's Focus -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Today's Focus</h2>
|
||||
<a href="/focus" class="btn btn-ghost btn-sm">View All</a>
|
||||
</div>
|
||||
{% if focus_items %}
|
||||
{% for item in focus_items %}
|
||||
<div class="focus-item {{ 'completed' if item.completed }}">
|
||||
<span class="priority-dot priority-{{ item.priority }}"></span>
|
||||
<a href="/tasks/{{ item.task_id }}" class="focus-title">{{ item.title }}</a>
|
||||
{% if item.project_name %}
|
||||
<span class="row-meta">{{ item.project_name }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<div class="empty-state-text">No focus items for today</div>
|
||||
<a href="/focus" class="btn btn-primary btn-sm">Set Focus</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Overdue + Upcoming -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Upcoming</h2>
|
||||
</div>
|
||||
{% if overdue_tasks %}
|
||||
<div class="text-xs text-muted mb-2" style="font-weight:600; color: var(--red);">OVERDUE</div>
|
||||
{% for t in overdue_tasks %}
|
||||
<div class="list-row">
|
||||
<span class="priority-dot priority-{{ t.priority }}"></span>
|
||||
<span class="row-title"><a href="/tasks/{{ t.id }}">{{ t.title }}</a></span>
|
||||
<span class="row-meta overdue">{{ t.due_date }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if upcoming_tasks %}
|
||||
<div class="text-xs text-muted mb-2 {{ 'mt-3' if overdue_tasks }}" style="font-weight:600;">NEXT 7 DAYS</div>
|
||||
{% for t in upcoming_tasks %}
|
||||
<div class="list-row">
|
||||
<span class="priority-dot priority-{{ t.priority }}"></span>
|
||||
<span class="row-title"><a href="/tasks/{{ t.id }}">{{ t.title }}</a></span>
|
||||
<span class="row-meta">{{ t.due_date }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if not overdue_tasks and not upcoming_tasks %}
|
||||
<div class="empty-state">
|
||||
<div class="empty-state-text">No upcoming deadlines</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
17
templates/domain_form.html
Normal file
17
templates/domain_form.html
Normal file
@@ -0,0 +1,17 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="breadcrumb"><a href="/domains">Domains</a><span class="sep">/</span><span>{{ 'Edit' if item else 'New Domain' }}</span></div>
|
||||
<div class="page-header"><h1 class="page-title">{{ 'Edit Domain' if item else 'New Domain' }}</h1></div>
|
||||
<div class="card">
|
||||
<form method="post" action="{{ '/domains/' ~ item.id ~ '/edit' if item else '/domains/create' }}">
|
||||
<div class="form-grid">
|
||||
<div class="form-group"><label class="form-label">Name *</label><input type="text" name="name" class="form-input" required value="{{ item.name if item else '' }}"></div>
|
||||
<div class="form-group"><label class="form-label">Color</label><input type="color" name="color" class="form-input" value="{{ item.color if item and item.color else '#4F6EF7' }}" style="height:42px;padding:4px"></div>
|
||||
<div class="form-group full-width"><label class="form-label">Description</label><textarea name="description" class="form-textarea" rows="3">{{ item.description if item and item.description else '' }}</textarea></div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">{{ 'Save' if item else 'Create' }}</button>
|
||||
<a href="/domains" class="btn btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</form></div>
|
||||
{% endblock %}
|
||||
26
templates/domains.html
Normal file
26
templates/domains.html
Normal file
@@ -0,0 +1,26 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Domains<span class="page-count">{{ items|length }}</span></h1>
|
||||
<a href="/domains/create" class="btn btn-primary">+ New Domain</a>
|
||||
</div>
|
||||
{% if items %}
|
||||
<div class="card">
|
||||
{% for item in items %}
|
||||
<div class="list-row">
|
||||
<span class="domain-dot" style="background: {{ item.color or '#4F6EF7' }}"></span>
|
||||
<span class="row-title"><a href="/tasks?domain_id={{ item.id }}">{{ item.name }}</a></span>
|
||||
{% if item.description %}<span class="row-meta">{{ item.description }}</span>{% endif %}
|
||||
<div class="row-actions">
|
||||
<a href="/domains/{{ item.id }}/edit" class="btn btn-ghost btn-xs">Edit</a>
|
||||
<form action="/domains/{{ item.id }}/delete" method="post" data-confirm="Delete this domain and all its contents?" style="display:inline">
|
||||
<button class="btn btn-ghost btn-xs" style="color:var(--red)">Del</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state"><div class="empty-state-text">No domains. Create your first life domain.</div><a href="/domains/create" class="btn btn-primary">Create Domain</a></div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
58
templates/focus.html
Normal file
58
templates/focus.html
Normal file
@@ -0,0 +1,58 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Daily Focus</h1>
|
||||
<div class="flex items-center gap-2">
|
||||
{% if total_estimated %}<span class="text-sm text-muted">~{{ total_estimated }}min estimated</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<a href="/focus?focus_date={{ (focus_date|string)[:10] }}" class="btn btn-ghost btn-sm">Today</a>
|
||||
<span class="text-sm" style="font-weight:600">{{ focus_date }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Focus items -->
|
||||
{% if items %}
|
||||
{% for item in items %}
|
||||
<div class="focus-item {{ 'completed' if item.completed }}">
|
||||
<form action="/focus/{{ item.id }}/toggle" method="post" style="display:inline">
|
||||
<div class="row-check">
|
||||
<input type="checkbox" id="f-{{ item.id }}" {{ 'checked' if item.completed }} onchange="this.form.submit()">
|
||||
<label for="f-{{ item.id }}"></label>
|
||||
</div>
|
||||
</form>
|
||||
<span class="priority-dot priority-{{ item.priority }}"></span>
|
||||
<a href="/tasks/{{ item.task_id }}" class="focus-title">{{ item.title }}</a>
|
||||
{% if item.project_name %}<span class="row-tag">{{ item.project_name }}</span>{% endif %}
|
||||
{% if item.estimated_minutes %}<span class="focus-meta">~{{ item.estimated_minutes }}min</span>{% endif %}
|
||||
{% if item.due_date %}<span class="focus-meta">{{ item.due_date }}</span>{% endif %}
|
||||
<form action="/focus/{{ item.id }}/remove" method="post" style="display:inline">
|
||||
<button class="btn btn-ghost btn-xs" style="color:var(--red)" title="Remove from focus">×</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="empty-state mb-4"><div class="empty-state-text">No focus items for this day</div></div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Add task to focus -->
|
||||
{% if available_tasks %}
|
||||
<div class="card mt-4">
|
||||
<div class="card-header"><h2 class="card-title">Add to Focus</h2></div>
|
||||
{% for t in available_tasks[:15] %}
|
||||
<div class="list-row">
|
||||
<span class="priority-dot priority-{{ t.priority }}"></span>
|
||||
<span class="row-title">{{ t.title }}</span>
|
||||
{% if t.project_name %}<span class="row-tag">{{ t.project_name }}</span>{% endif %}
|
||||
{% if t.due_date %}<span class="row-meta">{{ t.due_date }}</span>{% endif %}
|
||||
<form action="/focus/add" method="post" style="display:inline">
|
||||
<input type="hidden" name="task_id" value="{{ t.id }}">
|
||||
<input type="hidden" name="focus_date" value="{{ focus_date }}">
|
||||
<button class="btn btn-ghost btn-xs" style="color:var(--green)">+ Focus</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
18
templates/link_form.html
Normal file
18
templates/link_form.html
Normal file
@@ -0,0 +1,18 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="breadcrumb"><a href="/links">Links</a><span class="sep">/</span><span>{{ 'Edit' if item else 'New Link' }}</span></div>
|
||||
<div class="page-header"><h1 class="page-title">{{ 'Edit Link' if item else 'New Link' }}</h1></div>
|
||||
<div class="card">
|
||||
<form method="post" action="{{ '/links/' ~ item.id ~ '/edit' if item else '/links/create' }}">
|
||||
<div class="form-grid">
|
||||
<div class="form-group"><label class="form-label">Label *</label><input type="text" name="label" class="form-input" required value="{{ item.label if item else '' }}"></div>
|
||||
<div class="form-group"><label class="form-label">URL *</label><input type="url" name="url" class="form-input" required value="{{ item.url if item else '' }}"></div>
|
||||
<div class="form-group"><label class="form-label">Domain *</label>
|
||||
<select name="domain_id" class="form-select" required>{% for d in domains %}<option value="{{ d.id }}" {{ 'selected' if (item and item.domain_id|string == d.id|string) or (not item and prefill_domain_id == d.id|string) }}>{{ d.name }}</option>{% endfor %}</select></div>
|
||||
<div class="form-group"><label class="form-label">Project</label>
|
||||
<select name="project_id" class="form-select"><option value="">-- None --</option>{% for p in projects %}<option value="{{ p.id }}" {{ 'selected' if (item and item.project_id and item.project_id|string == p.id|string) or (not item and prefill_project_id == p.id|string) }}>{{ p.name }}</option>{% endfor %}</select></div>
|
||||
<div class="form-group full-width"><label class="form-label">Description</label><textarea name="description" class="form-textarea" rows="3">{{ item.description if item and item.description else '' }}</textarea></div>
|
||||
<div class="form-actions"><button type="submit" class="btn btn-primary">{{ 'Save' if item else 'Create' }}</button><a href="/links" class="btn btn-secondary">Cancel</a></div>
|
||||
</div>
|
||||
</form></div>
|
||||
{% endblock %}
|
||||
25
templates/links.html
Normal file
25
templates/links.html
Normal file
@@ -0,0 +1,25 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Links<span class="page-count">{{ items|length }}</span></h1>
|
||||
<a href="/links/create" class="btn btn-primary">+ New Link</a>
|
||||
</div>
|
||||
{% if items %}
|
||||
<div class="card">
|
||||
{% for item in items %}
|
||||
<div class="list-row">
|
||||
{% if item.domain_color %}<span class="row-domain-tag" style="background:{{ item.domain_color }}22;color:{{ item.domain_color }}">{{ item.domain_name }}</span>{% endif %}
|
||||
<span class="row-title"><a href="{{ item.url }}" target="_blank">{{ item.label }}</a></span>
|
||||
{% if item.project_name %}<span class="row-tag">{{ item.project_name }}</span>{% endif %}
|
||||
<span class="row-meta">{{ item.url[:50] }}{% if item.url|length > 50 %}...{% endif %}</span>
|
||||
<div class="row-actions">
|
||||
<a href="/links/{{ item.id }}/edit" class="btn btn-ghost btn-xs">Edit</a>
|
||||
<form action="/links/{{ item.id }}/delete" method="post" data-confirm="Delete?" style="display:inline"><button class="btn btn-ghost btn-xs" style="color:var(--red)">Del</button></form>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state"><div class="empty-state-icon">🔗</div><div class="empty-state-text">No links yet</div><a href="/links/create" class="btn btn-primary">Add Link</a></div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
26
templates/note_detail.html
Normal file
26
templates/note_detail.html
Normal file
@@ -0,0 +1,26 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="breadcrumb">
|
||||
{% if domain %}<span style="color:{{ domain.color }}">{{ domain.name }}</span><span class="sep">/</span>{% endif %}
|
||||
{% if project %}<a href="/projects/{{ project.id }}">{{ project.name }}</a><span class="sep">/</span>{% endif %}
|
||||
<span>{{ item.title }}</span>
|
||||
</div>
|
||||
<div class="detail-header">
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="detail-title">{{ item.title }}</h1>
|
||||
<div class="flex gap-2">
|
||||
<a href="/notes/{{ item.id }}/edit" class="btn btn-secondary btn-sm">Edit</a>
|
||||
<form action="/notes/{{ item.id }}/delete" method="post" data-confirm="Delete?" style="display:inline"><button class="btn btn-danger btn-sm">Delete</button></form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-meta mt-2">
|
||||
<span class="detail-meta-item">Updated {{ item.updated_at.strftime('%Y-%m-%d %H:%M') if item.updated_at else '' }}</span>
|
||||
{% if item.tags %}{% for tag in item.tags %}<span class="row-tag">{{ tag }}</span>{% endfor %}{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if item.body %}
|
||||
<div class="card"><div class="detail-body" style="white-space:pre-wrap;font-family:var(--font-body)">{{ item.body }}</div></div>
|
||||
{% else %}
|
||||
<div class="card"><div class="text-muted" style="padding:20px">No content yet. <a href="/notes/{{ item.id }}/edit">Start writing</a></div></div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
19
templates/note_form.html
Normal file
19
templates/note_form.html
Normal file
@@ -0,0 +1,19 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="breadcrumb"><a href="/notes">Notes</a><span class="sep">/</span><span>{{ 'Edit' if item else 'New Note' }}</span></div>
|
||||
<div class="page-header"><h1 class="page-title">{{ 'Edit Note' if item else 'New Note' }}</h1></div>
|
||||
<div class="card">
|
||||
<form method="post" action="{{ '/notes/' ~ item.id ~ '/edit' if item else '/notes/create' }}">
|
||||
<div class="form-grid">
|
||||
<div class="form-group full-width"><label class="form-label">Title *</label><input type="text" name="title" class="form-input" required value="{{ item.title if item else '' }}"></div>
|
||||
<div class="form-group"><label class="form-label">Domain *</label>
|
||||
<select name="domain_id" class="form-select" required>{% for d in domains %}<option value="{{ d.id }}" {{ 'selected' if (item and item.domain_id|string == d.id|string) or (not item and prefill_domain_id == d.id|string) }}>{{ d.name }}</option>{% endfor %}</select></div>
|
||||
<div class="form-group"><label class="form-label">Project</label>
|
||||
<select name="project_id" class="form-select"><option value="">-- None --</option>{% for p in projects %}<option value="{{ p.id }}" {{ 'selected' if (item and item.project_id and item.project_id|string == p.id|string) or (not item and prefill_project_id == p.id|string) }}>{{ p.name }}</option>{% endfor %}</select></div>
|
||||
<div class="form-group full-width"><label class="form-label">Content</label><textarea name="body" class="form-textarea" rows="15" style="font-family:var(--font-mono);font-size:0.88rem">{{ item.body if item and item.body else '' }}</textarea></div>
|
||||
<div class="form-group full-width"><label class="form-label">Tags</label><input type="text" name="tags" class="form-input" value="{{ item.tags|join(', ') if item and item.tags else '' }}"></div>
|
||||
<input type="hidden" name="content_format" value="rich">
|
||||
<div class="form-actions"><button type="submit" class="btn btn-primary">{{ 'Save' if item else 'Create' }}</button><a href="{{ '/notes/' ~ item.id if item else '/notes' }}" class="btn btn-secondary">Cancel</a></div>
|
||||
</div>
|
||||
</form></div>
|
||||
{% endblock %}
|
||||
25
templates/notes.html
Normal file
25
templates/notes.html
Normal file
@@ -0,0 +1,25 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Notes<span class="page-count">{{ items|length }}</span></h1>
|
||||
<a href="/notes/create" class="btn btn-primary">+ New Note</a>
|
||||
</div>
|
||||
{% if items %}
|
||||
<div class="card">
|
||||
{% for item in items %}
|
||||
<div class="list-row">
|
||||
{% if item.domain_color %}<span class="row-domain-tag" style="background:{{ item.domain_color }}22;color:{{ item.domain_color }}">{{ item.domain_name }}</span>{% endif %}
|
||||
<span class="row-title"><a href="/notes/{{ item.id }}">{{ item.title }}</a></span>
|
||||
{% if item.project_name %}<span class="row-tag">{{ item.project_name }}</span>{% endif %}
|
||||
<span class="row-meta">{{ item.updated_at.strftime('%Y-%m-%d') if item.updated_at else '' }}</span>
|
||||
<div class="row-actions">
|
||||
<a href="/notes/{{ item.id }}/edit" class="btn btn-ghost btn-xs">Edit</a>
|
||||
<form action="/notes/{{ item.id }}/delete" method="post" data-confirm="Delete?" style="display:inline"><button class="btn btn-ghost btn-xs" style="color:var(--red)">Del</button></form>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state"><div class="empty-state-icon">📄</div><div class="empty-state-text">No notes yet</div><a href="/notes/create" class="btn btn-primary">Create Note</a></div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
95
templates/project_detail.html
Normal file
95
templates/project_detail.html
Normal file
@@ -0,0 +1,95 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="breadcrumb">
|
||||
{% if domain %}<span style="color: {{ domain.color or '#4F6EF7' }}">{{ domain.name }}</span><span class="sep">/</span>{% endif %}
|
||||
{% if area %}<span>{{ area.name }}</span><span class="sep">/</span>{% endif %}
|
||||
<span>{{ item.name }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-header">
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="detail-title">{{ item.name }}</h1>
|
||||
<div class="flex gap-2">
|
||||
<a href="/projects/{{ item.id }}/edit" class="btn btn-secondary btn-sm">Edit</a>
|
||||
<form action="/projects/{{ item.id }}/delete" method="post" data-confirm="Delete this project?" style="display:inline">
|
||||
<button class="btn btn-danger btn-sm">Delete</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-meta mt-2">
|
||||
<span class="status-badge status-{{ item.status }}">{{ item.status|replace('_', ' ') }}</span>
|
||||
<span class="detail-meta-item"><span class="priority-dot priority-{{ item.priority }}"></span> P{{ item.priority }}</span>
|
||||
{% if item.target_date %}<span class="detail-meta-item">Target: {{ item.target_date }}</span>{% endif %}
|
||||
</div>
|
||||
<div class="mt-2" style="max-width: 300px;">
|
||||
<div class="progress-bar"><div class="progress-fill" style="width: {{ progress }}%"></div></div>
|
||||
<div class="progress-text">{{ done_count }}/{{ task_count }} tasks complete ({{ progress }}%)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if item.description %}
|
||||
<div class="card mb-4"><div class="detail-body">{{ item.description }}</div></div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Tabs -->
|
||||
<div class="tab-strip">
|
||||
<a href="/projects/{{ item.id }}?tab=tasks" class="tab-item {{ 'active' if tab == 'tasks' }}">Tasks ({{ tasks|length }})</a>
|
||||
<a href="/projects/{{ item.id }}?tab=notes" class="tab-item {{ 'active' if tab == 'notes' }}">Notes ({{ notes|length }})</a>
|
||||
<a href="/projects/{{ item.id }}?tab=links" class="tab-item {{ 'active' if tab == 'links' }}">Links ({{ links|length }})</a>
|
||||
</div>
|
||||
|
||||
{% if tab == 'tasks' %}
|
||||
<form class="quick-add" action="/tasks/quick-add" method="post">
|
||||
<input type="hidden" name="domain_id" value="{{ item.domain_id }}">
|
||||
<input type="hidden" name="project_id" value="{{ item.id }}">
|
||||
<input type="text" name="title" placeholder="Quick add task to this project..." required>
|
||||
<button type="submit" class="btn btn-primary btn-sm">Add</button>
|
||||
</form>
|
||||
<a href="/tasks/create?domain_id={{ item.domain_id }}&project_id={{ item.id }}" class="btn btn-ghost btn-sm mb-3">+ Full Task Form</a>
|
||||
|
||||
{% for t in tasks %}
|
||||
<div class="list-row {{ 'completed' if t.status == 'done' }}">
|
||||
<div class="row-check">
|
||||
<form action="/tasks/{{ t.id }}/toggle" method="post" style="display:inline">
|
||||
<input type="checkbox" id="pt-{{ t.id }}" {{ 'checked' if t.status == 'done' }} onchange="this.form.submit()">
|
||||
<label for="pt-{{ t.id }}"></label>
|
||||
</form>
|
||||
</div>
|
||||
<span class="priority-dot priority-{{ t.priority }}"></span>
|
||||
<span class="row-title"><a href="/tasks/{{ t.id }}">{{ t.title }}</a></span>
|
||||
{% if t.due_date %}<span class="row-meta">{{ t.due_date }}</span>{% endif %}
|
||||
<span class="status-badge status-{{ t.status }}">{{ t.status|replace('_', ' ') }}</span>
|
||||
<div class="row-actions">
|
||||
<a href="/tasks/{{ t.id }}/edit" class="btn btn-ghost btn-xs">Edit</a>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state"><div class="empty-state-text">No tasks yet</div></div>
|
||||
{% endfor %}
|
||||
|
||||
{% elif tab == 'notes' %}
|
||||
<a href="/notes/create?domain_id={{ item.domain_id }}&project_id={{ item.id }}" class="btn btn-ghost btn-sm mb-3">+ New Note</a>
|
||||
{% for n in notes %}
|
||||
<div class="list-row">
|
||||
<span class="row-title"><a href="/notes/{{ n.id }}">{{ n.title }}</a></span>
|
||||
<span class="row-meta">{{ n.updated_at.strftime('%Y-%m-%d') if n.updated_at else '' }}</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state"><div class="empty-state-text">No notes yet</div></div>
|
||||
{% endfor %}
|
||||
|
||||
{% elif tab == 'links' %}
|
||||
<a href="/links/create?domain_id={{ item.domain_id }}&project_id={{ item.id }}" class="btn btn-ghost btn-sm mb-3">+ New Link</a>
|
||||
{% for l in links %}
|
||||
<div class="list-row">
|
||||
<span class="row-title"><a href="{{ l.url }}" target="_blank">{{ l.label }}</a></span>
|
||||
<span class="row-meta">{{ l.url[:50] }}{% if l.url|length > 50 %}...{% endif %}</span>
|
||||
<div class="row-actions">
|
||||
<a href="/links/{{ l.id }}/edit" class="btn btn-ghost btn-xs">Edit</a>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state"><div class="empty-state-text">No links yet</div></div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
69
templates/project_form.html
Normal file
69
templates/project_form.html
Normal file
@@ -0,0 +1,69 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="breadcrumb"><a href="/projects">Projects</a><span class="sep">/</span><span>{{ 'Edit' if item else 'New Project' }}</span></div>
|
||||
<div class="page-header"><h1 class="page-title">{{ 'Edit Project' if item else 'New Project' }}</h1></div>
|
||||
<div class="card">
|
||||
<form method="post" action="{{ '/projects/' ~ item.id ~ '/edit' if item else '/projects/create' }}">
|
||||
<div class="form-grid">
|
||||
<div class="form-group full-width">
|
||||
<label class="form-label">Name *</label>
|
||||
<input type="text" name="name" class="form-input" required value="{{ item.name if item else '' }}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Domain *</label>
|
||||
<select name="domain_id" class="form-select" required>
|
||||
{% for d in domains %}
|
||||
<option value="{{ d.id }}" {{ 'selected' if (item and item.domain_id|string == d.id|string) or (not item and prefill_domain_id == d.id|string) }}>{{ d.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Area</label>
|
||||
<select name="area_id" class="form-select">
|
||||
<option value="">-- None --</option>
|
||||
{% for a in areas %}
|
||||
<option value="{{ a.id }}" {{ 'selected' if (item and item.area_id and item.area_id|string == a.id|string) or (not item and prefill_area_id == a.id|string) }}>{{ a.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Status</label>
|
||||
<select name="status" class="form-select">
|
||||
{% for s in ['active', 'on_hold', 'completed', 'archived'] %}
|
||||
<option value="{{ s }}" {{ 'selected' if item and item.status == s }}>{{ s|replace('_', ' ')|title }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Priority</label>
|
||||
<select name="priority" class="form-select">
|
||||
<option value="1" {{ 'selected' if item and item.priority == 1 }}>Critical</option>
|
||||
<option value="2" {{ 'selected' if item and item.priority == 2 }}>High</option>
|
||||
<option value="3" {{ 'selected' if (item and item.priority == 3) or not item }}>Normal</option>
|
||||
<option value="4" {{ 'selected' if item and item.priority == 4 }}>Low</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Start Date</label>
|
||||
<input type="date" name="start_date" class="form-input" value="{{ item.start_date if item and item.start_date else '' }}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Target Date</label>
|
||||
<input type="date" name="target_date" class="form-input" value="{{ item.target_date if item and item.target_date else '' }}">
|
||||
</div>
|
||||
<div class="form-group full-width">
|
||||
<label class="form-label">Description</label>
|
||||
<textarea name="description" class="form-textarea">{{ item.description if item and item.description else '' }}</textarea>
|
||||
</div>
|
||||
<div class="form-group full-width">
|
||||
<label class="form-label">Tags (comma-separated)</label>
|
||||
<input type="text" name="tags" class="form-input" value="{{ item.tags|join(', ') if item and item.tags else '' }}">
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">{{ 'Save Changes' if item else 'Create Project' }}</button>
|
||||
<a href="{{ '/projects/' ~ item.id if item else '/projects' }}" class="btn btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
48
templates/projects.html
Normal file
48
templates/projects.html
Normal file
@@ -0,0 +1,48 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Projects<span class="page-count">{{ items|length }}</span></h1>
|
||||
<a href="/projects/create" class="btn btn-primary">+ New Project</a>
|
||||
</div>
|
||||
|
||||
<form class="filters-bar" method="get" action="/projects">
|
||||
<select name="domain_id" class="filter-select" onchange="this.form.submit()">
|
||||
<option value="">All Domains</option>
|
||||
{% for d in domains %}
|
||||
<option value="{{ d.id }}" {{ 'selected' if current_domain_id == d.id|string }}>{{ d.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<select name="status" class="filter-select" onchange="this.form.submit()">
|
||||
<option value="">All Statuses</option>
|
||||
{% for s in ['active', 'on_hold', 'completed', 'archived'] %}
|
||||
<option value="{{ s }}" {{ 'selected' if current_status == s }}>{{ s|replace('_', ' ')|title }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</form>
|
||||
|
||||
{% if items %}
|
||||
<div class="card">
|
||||
{% for item in items %}
|
||||
<div class="list-row">
|
||||
<span class="row-domain-tag" style="background: {{ item.domain_color or '#4F6EF7' }}22; color: {{ item.domain_color or '#4F6EF7' }}">{{ item.domain_name }}</span>
|
||||
<span class="row-title"><a href="/projects/{{ item.id }}">{{ item.name }}</a></span>
|
||||
{% if item.area_name %}<span class="row-meta">{{ item.area_name }}</span>{% endif %}
|
||||
<span class="status-badge status-{{ item.status }}">{{ item.status|replace('_', ' ') }}</span>
|
||||
<div style="width: 80px;">
|
||||
<div class="progress-bar"><div class="progress-fill" style="width: {{ item.progress }}%"></div></div>
|
||||
<div class="progress-text">{{ item.done_count }}/{{ item.task_count }}</div>
|
||||
</div>
|
||||
<div class="row-actions">
|
||||
<a href="/projects/{{ item.id }}/edit" class="btn btn-ghost btn-xs">Edit</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<div class="empty-state-icon">📂</div>
|
||||
<div class="empty-state-text">No projects found</div>
|
||||
<a href="/projects/create" class="btn btn-primary">Create First Project</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
79
templates/task_detail.html
Normal file
79
templates/task_detail.html
Normal file
@@ -0,0 +1,79 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="breadcrumb">
|
||||
{% if domain %}<a href="/tasks?domain_id={{ item.domain_id }}">{{ domain.name }}</a><span class="sep">/</span>{% endif %}
|
||||
{% if project %}<a href="/projects/{{ project.id }}">{{ project.name }}</a><span class="sep">/</span>{% endif %}
|
||||
<span>{{ item.title }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-header">
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="detail-title">{{ item.title }}</h1>
|
||||
<div class="flex gap-2">
|
||||
<a href="/tasks/{{ item.id }}/edit" class="btn btn-secondary btn-sm">Edit</a>
|
||||
<form action="/tasks/{{ item.id }}/toggle" method="post" style="display:inline">
|
||||
<button class="btn {{ 'btn-secondary' if item.status == 'done' else 'btn-primary' }} btn-sm">
|
||||
{{ 'Reopen' if item.status == 'done' else 'Complete' }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-meta mt-2">
|
||||
<span class="status-badge status-{{ item.status }}">{{ item.status|replace('_', ' ') }}</span>
|
||||
<span class="detail-meta-item"><span class="priority-dot priority-{{ item.priority }}"></span> P{{ item.priority }}</span>
|
||||
{% if domain %}<span class="row-domain-tag" style="background: {{ domain.color or '#4F6EF7' }}22; color: {{ domain.color or '#4F6EF7' }}">{{ domain.name }}</span>{% endif %}
|
||||
{% if project %}<span class="row-tag">{{ project.name }}</span>{% endif %}
|
||||
{% if item.due_date %}<span class="detail-meta-item">Due: {{ item.due_date }}</span>{% endif %}
|
||||
{% if item.context %}<span class="detail-meta-item">@{{ item.context }}</span>{% endif %}
|
||||
{% if item.estimated_minutes %}<span class="detail-meta-item">~{{ item.estimated_minutes }}min</span>{% endif %}
|
||||
{% if item.energy_required %}<span class="detail-meta-item">Energy: {{ item.energy_required }}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if item.description %}
|
||||
<div class="card mb-4">
|
||||
<div class="detail-body">{{ item.description }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if item.tags %}
|
||||
<div class="flex gap-2 mb-4">
|
||||
{% for tag in item.tags %}<span class="row-tag">{{ tag }}</span>{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if parent %}
|
||||
<div class="card mb-4">
|
||||
<div class="card-title text-sm">Parent Task</div>
|
||||
<a href="/tasks/{{ parent.id }}">{{ parent.title }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Subtasks -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Subtasks<span class="page-count">{{ subtasks|length }}</span></h2>
|
||||
<a href="/tasks/create?parent_id={{ item.id }}&domain_id={{ item.domain_id }}&project_id={{ item.project_id or '' }}" class="btn btn-ghost btn-sm">+ Add Subtask</a>
|
||||
</div>
|
||||
{% for sub in subtasks %}
|
||||
<div class="list-row {{ 'completed' if sub.status == 'done' }}">
|
||||
<div class="row-check">
|
||||
<form action="/tasks/{{ sub.id }}/toggle" method="post" style="display:inline">
|
||||
<input type="checkbox" id="sub-{{ sub.id }}" {{ 'checked' if sub.status == 'done' }} onchange="this.form.submit()">
|
||||
<label for="sub-{{ sub.id }}"></label>
|
||||
</form>
|
||||
</div>
|
||||
<span class="priority-dot priority-{{ sub.priority }}"></span>
|
||||
<span class="row-title"><a href="/tasks/{{ sub.id }}">{{ sub.title }}</a></span>
|
||||
<span class="status-badge status-{{ sub.status }}">{{ sub.status|replace('_', ' ') }}</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-sm text-muted" style="padding: 12px;">No subtasks</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="text-xs text-muted mt-4">
|
||||
Created {{ item.created_at.strftime('%Y-%m-%d %H:%M') if item.created_at else '' }}
|
||||
{% if item.completed_at %} | Completed {{ item.completed_at.strftime('%Y-%m-%d %H:%M') }}{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
119
templates/task_form.html
Normal file
119
templates/task_form.html
Normal file
@@ -0,0 +1,119 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="breadcrumb">
|
||||
<a href="/tasks">Tasks</a>
|
||||
<span class="sep">/</span>
|
||||
<span>{{ 'Edit' if item else 'New Task' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">{{ 'Edit Task' if item else 'New Task' }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<form method="post" action="{{ '/tasks/' ~ item.id ~ '/edit' if item else '/tasks/create' }}">
|
||||
<div class="form-grid">
|
||||
<div class="form-group full-width">
|
||||
<label class="form-label">Title *</label>
|
||||
<input type="text" name="title" class="form-input" required
|
||||
value="{{ item.title if item else '' }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Domain *</label>
|
||||
<select name="domain_id" class="form-select" required>
|
||||
{% for d in domains %}
|
||||
<option value="{{ d.id }}"
|
||||
{{ 'selected' if (item and item.domain_id|string == d.id|string) or (not item and prefill_domain_id == d.id|string) }}>
|
||||
{{ d.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Project</label>
|
||||
<select name="project_id" class="form-select">
|
||||
<option value="">-- No Project --</option>
|
||||
{% for p in projects %}
|
||||
<option value="{{ p.id }}"
|
||||
{{ 'selected' if (item and item.project_id and item.project_id|string == p.id|string) or (not item and prefill_project_id == p.id|string) }}>
|
||||
{{ p.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Priority</label>
|
||||
<select name="priority" class="form-select">
|
||||
<option value="1" {{ 'selected' if item and item.priority == 1 }}>1 - Critical</option>
|
||||
<option value="2" {{ 'selected' if item and item.priority == 2 }}>2 - High</option>
|
||||
<option value="3" {{ 'selected' if (item and item.priority == 3) or not item }}>3 - Normal</option>
|
||||
<option value="4" {{ 'selected' if item and item.priority == 4 }}>4 - Low</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Status</label>
|
||||
<select name="status" class="form-select">
|
||||
{% for s in ['open', 'in_progress', 'blocked', 'done', 'cancelled'] %}
|
||||
<option value="{{ s }}" {{ 'selected' if item and item.status == s }}>{{ s|replace('_', ' ')|title }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Due Date</label>
|
||||
<input type="date" name="due_date" class="form-input"
|
||||
value="{{ item.due_date if item and item.due_date else '' }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Context</label>
|
||||
<select name="context" class="form-select">
|
||||
<option value="">-- None --</option>
|
||||
{% for ct in context_types %}
|
||||
<option value="{{ ct.value }}"
|
||||
{{ 'selected' if item and item.context == ct.value }}>{{ ct.label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Estimated Minutes</label>
|
||||
<input type="number" name="estimated_minutes" class="form-input" min="0"
|
||||
value="{{ item.estimated_minutes if item and item.estimated_minutes else '' }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Energy Required</label>
|
||||
<select name="energy_required" class="form-select">
|
||||
<option value="">-- None --</option>
|
||||
<option value="high" {{ 'selected' if item and item.energy_required == 'high' }}>High</option>
|
||||
<option value="medium" {{ 'selected' if item and item.energy_required == 'medium' }}>Medium</option>
|
||||
<option value="low" {{ 'selected' if item and item.energy_required == 'low' }}>Low</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group full-width">
|
||||
<label class="form-label">Description</label>
|
||||
<textarea name="description" class="form-textarea">{{ item.description if item and item.description else '' }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group full-width">
|
||||
<label class="form-label">Tags (comma-separated)</label>
|
||||
<input type="text" name="tags" class="form-input"
|
||||
value="{{ item.tags|join(', ') if item and item.tags else '' }}">
|
||||
</div>
|
||||
|
||||
{% if prefill_parent_id %}
|
||||
<input type="hidden" name="parent_id" value="{{ prefill_parent_id }}">
|
||||
{% endif %}
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">{{ 'Save Changes' if item else 'Create Task' }}</button>
|
||||
<a href="{{ '/tasks/' ~ item.id if item else '/tasks' }}" class="btn btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
91
templates/tasks.html
Normal file
91
templates/tasks.html
Normal file
@@ -0,0 +1,91 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">All Tasks<span class="page-count">{{ items|length }}</span></h1>
|
||||
<a href="/tasks/create" class="btn btn-primary">+ New Task</a>
|
||||
</div>
|
||||
|
||||
<!-- Quick Add -->
|
||||
<form class="quick-add" action="/tasks/quick-add" method="post">
|
||||
<input type="text" name="title" placeholder="Quick add task..." required>
|
||||
<button type="submit" class="btn btn-primary btn-sm">Add</button>
|
||||
</form>
|
||||
|
||||
<!-- Filters -->
|
||||
<form class="filters-bar" method="get" action="/tasks">
|
||||
<select name="status" class="filter-select" data-auto-submit onchange="this.form.submit()">
|
||||
<option value="">All Statuses</option>
|
||||
<option value="open" {{ 'selected' if current_status == 'open' }}>Open</option>
|
||||
<option value="in_progress" {{ 'selected' if current_status == 'in_progress' }}>In Progress</option>
|
||||
<option value="blocked" {{ 'selected' if current_status == 'blocked' }}>Blocked</option>
|
||||
<option value="done" {{ 'selected' if current_status == 'done' }}>Done</option>
|
||||
</select>
|
||||
<select name="priority" class="filter-select" onchange="this.form.submit()">
|
||||
<option value="">All Priorities</option>
|
||||
<option value="1" {{ 'selected' if current_priority == '1' }}>Critical</option>
|
||||
<option value="2" {{ 'selected' if current_priority == '2' }}>High</option>
|
||||
<option value="3" {{ 'selected' if current_priority == '3' }}>Normal</option>
|
||||
<option value="4" {{ 'selected' if current_priority == '4' }}>Low</option>
|
||||
</select>
|
||||
<select name="domain_id" class="filter-select" onchange="this.form.submit()">
|
||||
<option value="">All Domains</option>
|
||||
{% for d in domains %}
|
||||
<option value="{{ d.id }}" {{ 'selected' if current_domain_id == d.id|string }}>{{ d.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<select name="project_id" class="filter-select" onchange="this.form.submit()">
|
||||
<option value="">All Projects</option>
|
||||
{% for p in projects %}
|
||||
<option value="{{ p.id }}" {{ 'selected' if current_project_id == p.id|string }}>{{ p.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<select name="sort" class="filter-select" onchange="this.form.submit()">
|
||||
<option value="sort_order" {{ 'selected' if current_sort == 'sort_order' }}>Manual Order</option>
|
||||
<option value="priority" {{ 'selected' if current_sort == 'priority' }}>Priority</option>
|
||||
<option value="due_date" {{ 'selected' if current_sort == 'due_date' }}>Due Date</option>
|
||||
<option value="created_at" {{ 'selected' if current_sort == 'created_at' }}>Newest</option>
|
||||
<option value="title" {{ 'selected' if current_sort == 'title' }}>Title</option>
|
||||
</select>
|
||||
</form>
|
||||
|
||||
<!-- Task List -->
|
||||
{% if items %}
|
||||
<div class="card">
|
||||
{% for item in items %}
|
||||
<div class="list-row {{ 'completed' if item.status in ['done', 'cancelled'] }}">
|
||||
<div class="row-check">
|
||||
<form action="/tasks/{{ item.id }}/toggle" method="post" style="display:inline">
|
||||
<input type="checkbox" id="check-{{ item.id }}" {{ 'checked' if item.status == 'done' }}
|
||||
onchange="this.form.submit()">
|
||||
<label for="check-{{ item.id }}"></label>
|
||||
</form>
|
||||
</div>
|
||||
<span class="priority-dot priority-{{ item.priority }}"></span>
|
||||
<span class="row-title"><a href="/tasks/{{ item.id }}">{{ item.title }}</a></span>
|
||||
{% if item.project_name %}
|
||||
<span class="row-tag">{{ item.project_name }}</span>
|
||||
{% endif %}
|
||||
{% if item.domain_name %}
|
||||
<span class="row-domain-tag" style="background: {{ item.domain_color or '#4F6EF7' }}22; color: {{ item.domain_color or '#4F6EF7' }}">{{ item.domain_name }}</span>
|
||||
{% endif %}
|
||||
{% if item.due_date %}
|
||||
<span class="row-meta {{ 'overdue' if item.due_date|string < now_date|default('9999') }}">{{ item.due_date }}</span>
|
||||
{% endif %}
|
||||
<span class="status-badge status-{{ item.status }}">{{ item.status|replace('_', ' ') }}</span>
|
||||
<div class="row-actions">
|
||||
<a href="/tasks/{{ item.id }}/edit" class="btn btn-ghost btn-xs">Edit</a>
|
||||
<form action="/tasks/{{ item.id }}/delete" method="post" data-confirm="Delete this task?" style="display:inline">
|
||||
<button type="submit" class="btn btn-ghost btn-xs" style="color: var(--red)">Del</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<div class="empty-state-icon">☑</div>
|
||||
<div class="empty-state-text">No tasks found</div>
|
||||
<a href="/tasks/create" class="btn btn-primary">Create First Task</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user