Files
Todoist-Actual-Backup/todoist_backup_template.html

242 lines
11 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Todoist Backup - {{ date }}</title>
<style>
body { font-family: Arial, sans-serif; background: #f8f9fa; color: #222; margin: 0; padding: 0; }
.container { max-width: 960px; margin: 2em auto; background: #fff; padding: 2em; border-radius: 8px; box-shadow: 0 2px 8px #0001; }
h1, h2, h3 { color: #2d72d9; }
nav ul { list-style: none; padding: 0; margin: 0; }
nav li { margin: 0.25em 0; }
nav a { text-decoration: none; color: #2d72d9; }
nav a:hover { text-decoration: underline; }
.project { margin-bottom: 3em; }
.task-list { margin: 0 0 1em 0; }
.task { border-bottom: 1px solid #eee; padding: 0.75em 0; }
.task:last-child { border-bottom: none; }
.task.level-0 { margin-left: 0; }
.task.level-1 { margin-left: 1.5em; }
.task.level-2 { margin-left: 3em; }
.task.level-3 { margin-left: 4.5em; }
.taskname { font-weight: 600; }
.taskdesc { margin: 0.35em 0; color: #555; }
.meta { color: #777; font-size: 0.9em; display: inline-block; margin-top: 0.25em; }
.field-name { font-weight: 600; }
.attachments ul,
.comments ul { margin: 0.5em 0 0 1.2em; }
.attachments li,
.comments li { margin-bottom: 0.35em; }
.attachment-link { color: #2d72d9; }
.attachment-link:hover { text-decoration: underline; }
.comments { margin-top: 0.5em; }
.comment-attachment { margin-top: 0.25em; }
.task.completed { background: #f3f6ff; padding: 0.75em; border-radius: 6px; border: 1px solid #d6e2ff; }
</style>
</head>
<body>
<div class="container">
<h1>Todoist Backup ({{ date }})</h1>
{% macro render_task(task, level=0) %}
<div class="task level-{{ level }}">
<span class="taskname">{{ task.content | markdown | safe }}</span><br>
{% if task.description %}
<div class="taskdesc">{{ task.description | markdown | safe }}</div>
{% endif %}
<span class="meta">
{% set meta_fields = [] %}
{% if task.id is not none %}
{% set _ = meta_fields.append('ID: ' ~ task.id) %}
{% endif %}
{% if task.due and task.due.date %}
{% set due_dt = task.due.date %}
{% if due_dt.__class__.__name__ == 'datetime' or due_dt.__class__.__name__ == 'date' %}
{% set due_fmt = due_dt.strftime('%Y-%m-%d') %}
{% else %}
{% set due_str = due_dt|string %}
{% if 'T' in due_str %}
{% set due_fmt = due_str[:10] %}
{% else %}
{% set due_fmt = due_str %}
{% endif %}
{% endif %}
{% set _ = meta_fields.append('Due: ' ~ due_fmt) %}
{% endif %}
{% if task.due and task.due.is_recurring %}
{% if task.due.string %}
{% set _ = meta_fields.append('Recurring: ' ~ task.due.string) %}
{% endif %}
{% endif %}
{% if task.priority is not none %}
{% set _ = meta_fields.append('Priority: ' ~ task.priority) %}
{% endif %}
{{ meta_fields|join(' | ') }}
</span><br>
{% if task.attachments %}
<div class="attachments">
<span class="field-name">Attachments:</span>
<ul>
{% for att in task.attachments %}
<li><a class="attachment-link" href="{{ att.local_file }}" download>{{ att.file_name or att.local_file }}</a></li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if task.comments %}
<div class="comments">
<span class="field-name">Comments:</span>
<ul>
{% for comment in task.comments %}
<li>
{{ comment.content | markdown | safe }}
<span class="meta">({{ comment.posted_at }})</span>
{% set attachment = comment.attachment %}
{% if attachment and (attachment.local_file or attachment.file_url) %}
<div class="comment-attachment">
Attachment:
{% if attachment.local_file %}
<a class="attachment-link" href="{{ attachment.local_file }}" download>{{ attachment.file_name or attachment.local_file }}</a>
{% elif attachment.file_url %}
<a class="attachment-link" href="{{ attachment.file_url }}" target="_blank">{{ attachment.file_name or attachment.file_url }}</a>
{% endif %}
</div>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if task.subtasks %}
<div class="subtasks">
{% for child in task.subtasks %}
{{ render_task(child, level + 1) }}
{% endfor %}
</div>
{% endif %}
</div>
{% endmacro %}
<nav style="margin-bottom:2em;">
<h2 style="font-size:1.2em;">Projects</h2>
<ul>
{% for project in projects %}
<li><a href="#project-{{ project.id }}">{{ project.name }}{% if project.is_archived %} <span class="meta">[Archived]</span>{% endif %}</a></li>
{% endfor %}
</ul>
</nav>
{% for project in projects %}
<div class="project" id="project-{{ project.id }}">
<h2>{{ project.name }} {% if project.is_archived %}<span class="meta">[Archived]</span>{% endif %}</h2>
<div class="meta">
<span>ID: {{ project.id }}</span> | <span>Color: {{ project.color }}</span> | <span>Created: {{ project.created_at }}</span>
</div>
<h3>Active Tasks</h3>
<div class="task-list">
{% for task in project.tasks %}
{{ render_task(task, 0) }}
{% else %}
<p class="meta">No active tasks.</p>
{% endfor %}
</div>
<h3>Completed Tasks</h3>
<div class="task-list">
{% for task in project.completed_tasks %}
<div class="task completed">
<span class="task-name">{{ task.content | markdown | safe }}</span><br>
{% if task.description %}
<div class="taskdesc">{{ task.description | markdown | safe }}</div>
{% endif %}
<span class="meta">
{% set meta_fields = [] %}
{% if task.id is not none %}
{% set _ = meta_fields.append('ID: ' ~ task.id) %}
{% endif %}
{% if task.due and task.due.date %}
{% set due_dt = task.due.date %}
{% if due_dt.__class__.__name__ == 'datetime' or due_dt.__class__.__name__ == 'date' %}
{% set due_fmt = due_dt.strftime('%Y-%m-%d') %}
{% else %}
{% set due_str = due_dt|string %}
{% if 'T' in due_str %}
{% set due_fmt = due_str[:10] %}
{% else %}
{% set due_fmt = due_str %}
{% endif %}
{% endif %}
{% set _ = meta_fields.append('Due: ' ~ due_fmt) %}
{% endif %}
{% if task.due and task.due.is_recurring %}
{% if task.due.string %}
{% set _ = meta_fields.append('Recurring: ' ~ task.due.string) %}
{% endif %}
{% endif %}
{% if task.priority is not none %}
{% set _ = meta_fields.append('Priority: ' ~ task.priority) %}
{% endif %}
{% if task.completed_at %}
{% if task.completed_at.__class__.__name__ == 'datetime' or task.completed_at.__class__.__name__ == 'date' %}
{% set completed_fmt = task.completed_at.strftime('%Y-%m-%d') %}
{% else %}
{% set completed_str = task.completed_at|string %}
{% if 'T' in completed_str %}
{% set completed_fmt = completed_str[:10] %}
{% else %}
{% set completed_fmt = completed_str %}
{% endif %}
{% endif %}
{% set _ = meta_fields.append('Completed: ' ~ completed_fmt) %}
{% endif %}
{{ meta_fields|join(' | ') }}
</span><br>
{% if task.parent_task %}
<div class="meta">Parent task: {{ task.parent_task.content | markdown | safe }}</div>
{% endif %}
{% if task.attachments %}
<div class="attachments">
<span class="field-name">Attachments:</span>
<ul>
{% for att in task.attachments %}
<li><a class="attachment-link" href="{{ att.local_file }}" download>{{ att.file_name or att.local_file }}</a></li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if task.comments %}
<div class="comments">
<span class="field-name">Comments:</span>
<ul>
{% for comment in task.comments %}
<li>
{{ comment.content | markdown | safe }}
<span class="meta">({{ comment.posted_at }})</span>
{% set attachment = comment.attachment %}
{% if attachment and (attachment.local_file or attachment.file_url) %}
<div class="comment-attachment">
Attachment:
{% if attachment.local_file %}
<a class="attachment-link" href="{{ attachment.local_file }}" download>{{ attachment.file_name or attachment.local_file }}</a>
{% elif attachment.file_url %}
<a class="attachment-link" href="{{ attachment.file_url }}" target="_blank">{{ attachment.file_name or attachment.file_url }}</a>
{% endif %}
</div>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
{% else %}
<p class="meta">No completed tasks in this period.</p>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
</body>
</html>