taskwarrior web package

This commit is contained in:
Matt Nish-Lapidus 2025-04-02 19:09:02 -04:00
parent e79220af5c
commit b16d004685
16 changed files with 4093 additions and 1 deletions

View file

@ -11,7 +11,6 @@
home = {
packages = with pkgs; [
btop
nix-config.packages.x86_64-linux.taskwarrior-web
];
username = "media";
@ -78,4 +77,8 @@ sync.encryption_secret = ${config.sops.placeholder.taskchamp-key}
source = ../emenel/dotfiles/dot_local/bin;
recursive = true;
};
home.file.".local/bin/tww" = {
source = ../../modules/home/tww;
};
}

890
modules/home/tww/dist/bundle.js vendored Normal file

File diff suppressed because one or more lines are too long

2363
modules/home/tww/dist/style.css vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,24 @@
<div hx-get="tasks/active" hx-trigger="every 60s" hx-swap="outerHTML" hx-target="this">
{% if active_task %}
<div class="join">
</div>
<div class="pl-2.5 pr-6 py-1.5 bg-green-900 text-green-200 shadow-xl rounded-sm flex flex-wrap " id="active-timer">
<span class="flex-grow">{{ active_task.description }}</span>
<div class="join">
<span class="badge badge-success badge-md badge-soft join-item">
{{ timer_value(date=active_task.start) }}
</span>
<button class="btn btn-accent btn-xs join-item"
hx-post="tasks"
hx-target="#list-of-tasks"
hx-swap="innerHTML"
hx-include="[id='filtering']"
hx-vals='{"uuid":"{{ active_task.uuid }}", "action": "ToggleTimer"}'
hx-trigger="click,keyup[key=='o'] from:#cmd-inp">
<span>St<span class="shortcut_key">o</span>p</span>
</button>
</div>
</div>
{% endif %}
</div>

View file

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en" {% if DEFAULT_THEME %}data-theme="{{ DEFAULT_THEME }}" {% endif %}>
<head>
<link rel="stylesheet" href="/dist/style.css"/>
<style>
{% if USE_FONT %}
body {
font-family: '{{ USE_FONT }}', '{{ FALLBACK_FAMILY }}';
}
{% endif %}
</style>
<script src="/dist/bundle.js" type="module"></script>
<title>
Org.Me
</title>
</head>
<body>
<div id="content" class="px-5">
<main>
<div class="toast" id="toast"></div>
<div id="list-of-tasks">{% include "tasks.html" %}</div>
<div id="ledger_things"></div>
</main>
</div>
</body>
</html>

View file

@ -0,0 +1,18 @@
{% macro desc(task) %}
{% if task.annotations %}
<p>
<strong>{{ task.description }}</strong>
</p>
<ul class="pl-4 text-sm">
{% for annotation in task.annotations %}
<li class="list-outside">
[{{date(date=annotation.entry) }}] {{ annotation.description }}
</li>
{% endfor %}
</ul>
{% else %}
<p>
{{ task.description }}
</p>
{% endif %}
{% endmacro desc %}

View file

@ -0,0 +1,14 @@
<div class="items-center justify-center gap-4 rounded-lg bg-black px-5 py-3 text-white z-50"
hx-trigger="load delay:{{ timeout }}s" hx-get="/msg_clr" id="flash_msg" hx-swap="outerHTML">
<span class="text-sm font-medium hover:opacity-75">{{ msg }} {{ timeout }}</span>
<button class="rounded bg-white/20 p-1 hover:bg-white/10" hx-get="/msg_clr" hx-target="#toast" hx-swap="innerHTML">
<span class="sr-only">Close ,,,</span>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</button>
</div>

View file

@ -0,0 +1,116 @@
<div class="pl-2 pr-2 py-1.5 rounded-sm text-xs flex bg-base-100 gap-2 items-center" xmlns:hx-on="http://www.w3.org/1999/xhtml">
<div class="join" id="tag_search_bar">
<button class="btn btn-neutral btn-xs join-item" id="tag-selection-toggle" onclick="window['toggleTagPanel']()">
<span><span class="shortcut_key"
>t</span>ags</span>
</button>
<span class="btn btn-neutral btn-xs join-item" id="task_action_bar">
<button hx-get="task_action_bar" hx-target="#task_action_bar" hx-swap="outerHTML"
hx-trigger="click,keyup[key=='s'] from:#cmd-inp">ta<span class="shortcut_key">s</span>k</button>
</span>
<button class="btn btn-xs btn-neutral join-item"
hx-get="tasks/undo/report"
hx-trigger="click,keyup[{{mod_key}}key=='u'] from:#cmd-inp"
hx-target="#all-dialog-boxes"
hx-swap="innerHTML">
<span><span class="shortcut_key">u</span>ndo</span>
</button>
<button class="btn btn-xs btn-neutral join-item"
hx-get="tasks/add"
hx-include="[id='filtering']"
hx-trigger="click,keyup[{{mod_key}}key=='n'] from:#cmd-inp"
hx-target="#all-dialog-boxes"
hx-swap="innerHTML">
<span><span class="shortcut_key">n</span>ew</span>
</button>
</div>
<div class="join">
<button class="btn btn-xs join-item btn-neutral" id="pending" hx-get="tasks?status=pending"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-trigger="click,keyup[{{mod_key}}key=='p'] from:#cmd-inp"
hx-swap="innerHTML">
<span><span class="shortcut_key">p</span>ending</span>
</button>
<button class="btn btn-xs join-item btn-neutral" id="waiting" hx-get="tasks?status=waiting"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-trigger="click,keyup[{{mod_key}}key=='w'] from:#cmd-inp"
hx-swap="innerHTML">
<span><span class="shortcut_key">w</span>aiting</span>
</button>
<button class="btn btn-xs join-item btn-neutral" id="completed"
hx-get="tasks?status=completed"
hx-include="[id='filtering']"
hx-trigger="click,keyup[{{mod_key}}key=='c'] from:#cmd-inp"
hx-target="#list-of-tasks" hx-swap="innerHTML">
<span><span class="shortcut_key">c</span>ompleted</span>
</button>
<button class="btn btn-xs join-item btn-neutral"
hx-get="tasks?report=all"
hx-include="[id='filtering']"
hx-target="#list-of-tasks"
hx-trigger="click,keyup[{{mod_key}}key=='a'] from:#cmd-inp"
hx-swap="innerHTML">
<span><span class="shortcut_key">a</span>ll</span>
</button>
</div>
<div class="join">
<button class="btn btn-xs join-item btn-primary" hx-get="tasks?report=next"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-trigger="click,keyup[{{mod_key}}key=='x'] from:#cmd-inp"
hx-swap="innerHTML">
<span>ne<span class="shortcut_key">x</span>t</span>
</button>
<button class="btn btn-xs join-item btn-primary" hx-get="tasks?report=ready"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-trigger="click,keyup[{{mod_key}}key=='r'] from:#cmd-inp"
hx-swap="innerHTML">
<span><span class="shortcut_key">r</span>eady</span>
</button>
<button class="btn btn-xs join-item btn-primary" hx-get="tasks?report=new"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-trigger="click,keyup[{{mod_key}}key=='e'] from:#cmd-inp"
hx-swap="innerHTML">
<span>n<span class="shortcut_key">e</span>w</span>
</button>
</div>
<div class="join grow">
<button class="btn btn-xs join-item btn-neutral" id="priority-h" hx-get="tasks?query=priority:H"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-trigger="click,keyup[{{mod_key}}key=='h'] from:#cmd-inp"
hx-swap="innerHTML">
<span><span class="shortcut_key">H</span></span>
</button>
<button class="btn btn-xs join-item btn-neutral" id="priority-m" hx-get="tasks?query=priority:M"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-trigger="click,keyup[{{mod_key}}key=='m'] from:#cmd-inp"
hx-swap="innerHTML">
<span><span class="shortcut_key">M</span></span>
</button>
<button class="btn btn-xs join-item btn-neutral" id="priority-l" hx-get="tasks?query=priority:L"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-trigger="click,keyup[{{mod_key}}key=='l'] from:#cmd-inp"
hx-swap="innerHTML">
<span><span class="shortcut_key">L</span></span>
</button>
</div>
<!-- Other options -->
<div>
<button class="btn btn-xs btn-ghost" id="theme-switcher"></button>
</div>
<!-- CMD BAR -->
<div>
<label class="" for="cmd-inp"></label>
<input type="search" class="input input-xs input-neutral focus:border-base-100 grow input-ghost border-base-200" placeholder="Cmd Bar, Ctrl+Shift+k" id="cmd-inp"
autofocus value="" autocomplete="off" />
</div>
</div>

View file

@ -0,0 +1,51 @@
<div class="flex flex-wrap gap-2 p-4">
<div class="join">
<button
id="tag-btn-back"
class="btn btn-warning btn-xs join-item"
hx-get="tasks"
hx-trigger="click,keyup[key=='Escape'] from:#task-inp"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
><span><span class="shortcut_key">ESC</span></span></button>
<label for="tag-inp" class="hidden"></label>
<input type="text" id="tag-inp"
class="input input-xs input-accent join-item"
placeholder="Tag Bar"
hx-trigger="changes delay:2s"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-swap="innerHTML"
autofocus
onkeyup="if (this.value.length >= 2) { document.getElementById(this.value).click() }"
/>
</div>
{% for tag, shortcut in tags_map %}
{% if tag is keyword_tag %}
{% endif %}
{% if tag is user_tag %}
{% endif %}
<div class="mb-2">
<div class="flex gap-2">
<button id="{{shortcut}}"
{% if tag is starting_with('+') %}
class="btn btn-xs btn-accent shrink"
hx-get="tasks?query={{ tag | replace(from='+', to='%2B') }}"
{% elif tag is starting_with('@') %}
class="btn btn-xs btn-info shrink"
hx-get="tasks?query={{ tag | trim_start_matches(pat='@') }}"
{% else %}
class="btn btn-xs btn-neutral shrink"
hx-get="tasks?query={% if tag is starting_with('project:') %}{{ tag }}{% else %}project:{{tag}}{% endif %}"
{% endif %}
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-swap="innerHTML"
>{{ shortcut }}</button>
<div class="text-xs pt-1">{{ tag | trim_start_matches(pat='@') }}</div>
</div>
</div>
{% endfor %}
</div>

View file

@ -0,0 +1,23 @@
<div class="join">
<button
id="tag-btn-back"
class="btn btn-warning btn-xs"
hx-get="tasks"
hx-trigger="click,keyup[key=='Escape'] from:#task-inp"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
><span><span class="shortcut_key">ESC</span></span></button>
<label for="task-inp" class="hidden"></label>
<input type="text" id="task-inp"
class="input input-neutral input-xs join-item"
placeholder="Enter Shortcut"
hx-trigger="changes delay:2s"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-swap="innerHTML"
autofocus
onkeyup="if (this.value.length >= 2) { document.getElementById(this.value).click() }"
onfocus="document.querySelectorAll('.task-shortcut-tag').forEach((e) => e.classList.remove('hidden'))"
onblur="document.querySelectorAll('.task-shortcut-tag').forEach((e) => e.classList.add('hidden'));"
/>
</div>

View file

@ -0,0 +1,98 @@
{% set bg_color = "bg-neutral-800" %}
<div class="modal-box">
<h2 class="text-lg font-bold text-neutral-content-50">Adding new task</h2>
<form class="mt-2 text-sm" id="task_add_form"
hx-post="tasks/add"
hx-include="[id='filtering']"
hx-target="#list-of-tasks"
>
<div class="my-1">
<label
for="desc"
class="block overflow-hidden rounded-md border border-gray-200 px-3 py-2 shadow-sm focus-within:border-blue-600 focus-within:ring-1 focus-within:ring-blue-600 dark:border-neutral-700 dark:{{bg_color}}"
>
<span class="text-xs font-medium text-gray-700 dark:text-gray-200">Description</span>
<input
autofocus
type="text"
id="desc"
name="description"
placeholder="Task description"
class="mt-1 w-full border-none bg-transparent p-0 focus:border-transparent focus:outline-none focus:ring-0 sm:text-sm dark:text-white"
/>
</label>
</div>
<div class="my-1">
<label
for="tags"
class="block overflow-hidden rounded-md border border-gray-200 px-3 py-2 shadow-sm focus-within:border-blue-600 focus-within:ring-1 focus-within:ring-blue-600 dark:border-gray-700 dark:{{bg_color}}"
>
<span class="text-xs font-medium text-gray-700 dark:text-gray-200">Tags</span>
<input
type="text"
id="tags"
name="tags"
placeholder="Tags. separate by ,"
value="{{ tags }}"
class="mt-1 w-full border-none bg-transparent p-0 focus:border-transparent focus:outline-none focus:ring-0 sm:text-sm dark:text-white"
/>
</label>
</div>
<div class="my-1">
<label
for="project"
class="block overflow-hidden rounded-md border border-gray-200 px-3 py-2 shadow-sm focus-within:border-blue-600 focus-within:ring-1 focus-within:ring-blue-600 dark:border-gray-700 dark:{{bg_color}}"
>
<span class="text-xs font-medium text-gray-700 dark:text-gray-200">Project</span>
<input
type="text"
id="project"
name="project"
placeholder="Project"
value="{{ project }}"
class="mt-1 w-full border-none bg-transparent p-0 focus:border-transparent focus:outline-none focus:ring-0 sm:text-sm dark:text-white"
/>
</label>
</div>
<div class="my-1">
<label
for="additional"
class="block overflow-hidden rounded-md border border-gray-200 px-3 py-2 shadow-sm focus-within:border-blue-600 focus-within:ring-1 focus-within:ring-blue-600 dark:border-neutral-700 dark:{{bg_color}}"
>
<span class="text-xs font-medium text-gray-700 dark:text-gray-200">Additional options, these will be added to task parameters directly</span>
<input
autofocus
type="text"
id="additional"
name="additional"
placeholder="Additional options"
class="mt-1 w-full border-none bg-transparent p-0 focus:border-transparent focus:outline-none focus:ring-0 sm:text-sm dark:text-white"
/>
</label>
</div>
</form>
<div class="modal-action" id="model-add-task">
<button class="btn btn-md btn-success" id="btn-mdl-yes" form="task_add_form"
hx-trigger="click,keyup[key=='Enter']">
<kbd class="shortcut_key">Enter</kbd>
</button>
<button class="btn btn-md btn-warning"
hx-get="tasks"
hx-trigger="click,keyup[key=='Escape'] from:body"
hx-include="[id='filtering']"
hx-target="#list-of-tasks">
<kbd class="shortcut_key">Esc</kbd>
</button>
</div>
<script>
document.getElementById('all-dialog-boxes').showModal()
</script>
</div>

View file

@ -0,0 +1,203 @@
{% import "desc.html" as desc %}
<div class="modal-box">
<h2 class="text-lg font-bold text-neutral-content-200">Task Details</h2>
<div class="join mb-3">
<button class="btn btn-xs btn-warning join-item"
id="tag-btn-back-details"
hx-get="tasks"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-trigger="click,keyup[key=='Escape'] from:#task-details-inp">
<kbd class="shortcut_key">Esc</kbd>
</button>
<button
class="btn btn-success btn-xs join-item"
id="btn-mark-as-done"
hx-post="tasks"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
{% if task.status !="completed" %}
hx-vals='{"status": "completed", "uuid":"{{ task.uuid }}", "action": "StatusUpdate"}'
{% else %}
hx-vals='{"status": "pending", "uuid":"{{ task.uuid }}", "query": "status:completed", "action": "StatusUpdate" }'
{% endif %}
hx-trigger="click,keyup[key=='d'] from:#task-details-inp"
><span><span class="shortcut_key">d</span>one</span></button>
<button
class="btn btn-accent btn-xs join-item"
id="btn-denotate-task"
hx-post="tasks"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-vals='{"uuid":"{{ task.uuid }}", "action": "DenotateTask"}'
hx-trigger="click,keyup[key=='n'] from:#task-details-inp"
>
<span>de<span class="shortcut_key">n</span>otate</span>
</button>
<button
class="btn btn-info btn-xs join-item"
id="btn-timer-toggle"
hx-post="tasks"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-vals='{"uuid":"{{ task.uuid }}", "action": "ToggleTimer"}'
hx-trigger="click,keyup[key=='s'] from:#task-details-inp">
<span>
{% if task.start %}
<span class="shortcut_key">s</span>top
{% else %}
<span class="shortcut_key">s</span>tart
{% endif %}
</span>
</button>
<span class="join-item">
<label for="task-details-inp" class="hidden"></label>
<input type="text" id="task-details-inp"
class="input input-neutral input-xs join-item"
placeholder="Cmd Bar, Ctrl+Shift+K"
autofocus /></span>
</div>
<table class="table table-xs table-zebra">
<tbody>
<tr>
<th>Description</th>
<td class="text-wrap w-2/3">
{{ desc::desc(task=task) }}
</td>
</tr>
<tr>
<th class="w-1/6">
<label for="task-edit-inp">Modify</label>
</th>
<td>
<input type="text" id="task-edit-inp"
class="input-neutral input input-xs"
placeholder="Edit task with command"
hx-trigger="keyup[key=='Enter'] from:#task-edit-inp"
hx-post="tasks"
hx-target="#list-of-tasks"
hx-include="[this],[id='filtering']"
name="task_entry"
hx-vals='{"uuid":"{{ task.uuid }}", "action": "ModifyTask"}'
/>
</td>
</tr>
<tr>
<th>
<label for="task-annot-inp">Annotate</label>
</th>
<td>
<input type="text" id="task-annot-inp"
class="input-neutral input input-xs"
placeholder="Annotate task"
hx-trigger="keyup[key=='Enter'] from:#task-annot-inp"
hx-post="tasks"
hx-target="#list-of-tasks"
hx-include="[this],[id='filtering']"
name="task_entry"
hx-vals='{"uuid":"{{ task.uuid }}", "action": "AnnotateTask"}'
/>
</td>
</tr>
<tr>
<th>Age</th>
<td>{% if task.entry %}{{ date_proper(date=task.entry) }}{% endif %}</td>
</tr>
<tr>
<th>Depends on</th>
<td>
{% if task.depends %}
{% for uuid in task.depends %}
{%if tasks_db[uuid] %}{{ tasks_db[uuid].id }}{% endif %}
{% endfor %}
{% endif %}
</td>
</tr>
<tr>
<th>Project</th>
<td>
{% if task.project %}
<div class="breadcrumbs text-sm">
<ul>
{% for p in task.project | split(pat=".") %}
<li class="">
{{ p }}
</li>
{% endfor %}
</ul>
</div>
{% endif %}
</td>
</tr>
<tr>
<th>Tags</th>
<td>
<div>
{% if task.tags %}
{% for p in task.tags %}
<span class="badge-sm badge badge-accent">
{{ p }}
</span>
{% endfor %}
{% endif %}
{% if task.priority %}
<span class="badge badge-sm badge-secondary">{{ task.priority }}</span>
{% endif %}
</div>
</td>
</tr>
<tr>
<th>Urgency</th>
<td>{{ task.urgency }}</td>
</tr>
<tr>
{% if task.start %}
<th>Start</th>
<td>
{{ date_proper(date=task.start) }}
</td>
</tr>
<tr>
{% endif %}
{% if task.due and task.status != 'completed' %}
<th>Due</th>
<td>
{{ date_proper(date=task.due, in_future=true) }}
</td>
{% endif %}
</tr>
<tr>
{% if task.scheduled %}
<th>Schd</th>
<td>
{{ date_proper(date=task.scheduled, in_future=true) }}
</td>
{% endif%}
</tr>
<tr>
{% if task.end %}
<th>End</th>
<td>
{{ date_proper(date=task.end) }}
</td>
{% endif %}
</tr>
<tr>
{% if task.recur %}
<th>RECUR</th>
<td>
{{task.recur}}
</td>
{% endif %}
</tr>
</tbody>
</table>
<script>
try {
document.getElementById('task-inp').value = '';
} catch (e) {
}
document.getElementById('all-dialog-boxes').showModal()
</script>
</div>

View file

@ -0,0 +1,230 @@
{% import "desc.html" as desc %}
{% if has_toast %}
<div hx-swap-oob="beforeend:#toast">
<div class="items-center justify-items-center gap-4 px-5 py-3 text-neutral-300 fixed h-18 top-0 left-0 w-full z-50 bg-cyan-700 shadow-xs shadow-black"
hx-trigger="load delay:{{ toast_timeout }}s" hx-get="/msg_clr" id="flash_msg" hx-swap="outerHTML">
<div class="flex flex-row">
<span class="text-sm font-medium hover:opacity-75 flex-grow">{{ toast_msg }}</span>
<span>
<button class="rounded bg-white/20 p-1 hover:bg-white/10" hx-get="/msg_clr" hx-target="#toast"
hx-trigger="click,keyup[key=='Escape'] from:#cmd-inp"
autofocus
hx-swap="innerHTML">
<span class="shortcut_key">[Esc]</span>
</button>
</span>
</div>
</div>
</div>
{% endif %}
<div class="mb-auto h-max">
<dialog id="all-dialog-boxes" class="modal"></dialog>
<div id="task_form_div"></div>
<div id="task_details"></div>
<!-- Open the modal using ID.showModal() method -->
{% set on_all = "all" %}
{% set on_complete = "btn-success" %}
{% set on_pending = "btn-warning" %}
{% set on_waiting = "btn-accent" %}
{% set mod_key = "" %}
<div class="fixed top-0 left-0 h-[18] z-40 w-full pb-2 shadow-sm shadow-black bg-base-100">
{% include 'left_action_bar.html' %}
<!-- TAG LIST -->
<div class="pl-2 flex justify-center join">
{% for f in current_filter %}
<button class="btn btn-xs join-item {% if f is starting_with('project:') %}btn-accent{% else %}btn-neutral {% endif %}"
hx-include="[id='filtering']"
hx-get="tasks?query={{ f | replace(from='+', to='%2B') }}"
hx-target="#list-of-tasks">
{{ remove_project_tag(task=f) }}
</button>
{% endfor %}
<button class="btn btn-disabled btn-xs btn-neutral join-item"></button>
</div>
<input type="hidden" id="filtering" name="filter_value" value="{{ filter_value }}">
<!-- // -->
</div>
<div class="relative overflow-x-auto shadow-md sm:rounded-b-lg overflow-y-auto mt-20 pt-0 pb-2 mb-5">
{% if display_time_of_the_day == 1 %}
<div class="justify-start items-center h-4" id="time_of_the_day">
<div class="flex-1 w-full rounded-sm text-accent-content text-xs">
<div class="[min-width:4px] mt-1 bg-accent shadow-inner shadow-accent rounded-sm fill-accent px-2 content-end">
</div>
</div>
</div>
{% endif %}
<span hx-get="tasks/active" hx-trigger="load" hx-swap="outerHTML" hx-target="this"></span>
<div class="grid grid-cols-1">
<div id="tags_map_drawer" class="pt-4 hidden mb-2">
<div class="flex flex-wrap gap-2 p-4 bg-base-300">
<div class="join">
<button
id="tag-btn-back"
class="btn btn-warning btn-xs join-item"
hx-get="tasks"
hx-trigger="click,keyup[key=='Escape'] from:#task-inp"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
><span><span class="shortcut_key">ESC</span></span></button>
<label for="tag-inp" class="hidden"></label>
<input type="text" id="tag-inp"
class="input input-xs input-accent join-item"
placeholder="Tag Bar"
hx-trigger="changes delay:2s"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-swap="innerHTML"
autofocus
onkeyup="if (this.value.length >= 2) { document.getElementById(this.value).click() }"
/>
</div>
{% for tag, shortcut in tags_map %}
{% if tag is keyword_tag %}
{% endif %}
{% if tag is user_tag %}
{% endif %}
<div class="mb-2">
<div class="flex gap-2">
<button id="{{shortcut}}"
{% if tag is starting_with('+') %}
class="btn btn-xs btn-accent-content shrink"
hx-get="tasks?query={{ tag | replace(from='+', to='%2B') }}"
{% elif tag is starting_with('@') %}
class="btn btn-xs btn-info shrink"
hx-get="tasks?query={{ tag | trim_start_matches(pat='@') }}"
{% else %}
class="btn btn-xs btn-neutral shrink"
hx-get="tasks?query={% if tag is starting_with('project:') %}{{ tag }}{% else %}project:{{tag}}{% endif %}"
{% endif %}
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-swap="innerHTML"
>{{ shortcut }}</button>
<div class="text-xs pt-1">{{ tag | trim_start_matches(pat='@') | trim_start_matches(pat='project:') }}</div>
</div>
</div>
{% endfor %}
</div>
</div>
<div>
<ul class="list bg-base-100 rounded-box shadow-md text-sm">
{% for task in tasks %}
<li class="list-row {% if task.start %} bg-green-700 text-green-200 {% endif %} p-2">
<div>
<input type="checkbox"
class="checkbox checkbox-sm"
name="checkbox-{{ task.uuid }}"
id="{{ task_shortcuts[task.uuid] }}"
hx-trigger="change"
hx-post="tasks" hx-target="#list-of-tasks"
hx-include="[id='filtering']"
{% if task.status !="completed" %}
hx-vals='{"status": "completed", "uuid":"{{ task.uuid }}", "action": "StatusUpdate"}'
hx-swap="innerHTML"
{% else %}
checked="checked"
hx-vals='{"status": "pending", "uuid":"{{ task.uuid }}", "query": "status:completed", "action": "StatusUpdate" }'
hx-swap="innerHTML"
{% endif %}>
<button class="btn btn-xs btn-primary hidden task-shortcut-tag">{{ task_shortcuts[task.uuid] }}</button>
<button
id="{{ task_shortcuts[task.id] }}"
class="btn btn-secondary static btn-xs is-a-tag min-w-12"
hx-trigger="click"
hx-get="task_details?task_id={{ task.uuid }}"
hx-target="#all-dialog-boxes"
>
{{ task.id }} <span class="shortcut_key hidden task-shortcut-tag">{{ task_shortcuts[task.id] }}</span>
</button>
</div>
<div class="max-w-3xl">
{{ desc::desc(task=task) }}
</div>
<div class="join">
{% if task.project %}
{% for p in task.project | split(pat=".") %}
{% set ptag = ["project", p] | join(sep=":") %}
<button class="join-item btn btn-accent btn-xs is-a-tag"
hx-include="[id='filtering']"
hx-target="#list-of-tasks"
hx-get="tasks?query=project:{{ project_name(full_name=task.project, index=loop.index) }}">
{{ p }}
</button>
{% endfor %}
{% endif %}
{% if task.priority %}
<button class="btn btn-xs {{ task.priority }} btn-neutral"
hx-get="tasks?query=priority:{{ task.priority }}"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-swap="innerHTML"
>{{ task.priority }}
</button>
{% endif %}
{% if task.tags %}
{% for p in task.tags %}
<button class="btn btn-xs btn-neutral join-item is-a-tag"
hx-get="tasks?query={{ p | replace(from='+', to='%2B') }}"
hx-target="#list-of-tasks"
hx-include="[id='filtering']"
hx-swap="innerHTML">
{{ p }}
</button>
{% endfor %}
{% else %}
<button class="btn btn-disabled btn-xs btn-neutral join-item"></button>
{% endif %}
</div>
<div class="join">
{% if task.depends %}
{% for uuid in task.depends %}
{%if tasks_db[uuid] %}
<button class="btn btn-secondary btn-xs is-a-tag join-item"
hx-trigger="click"
hx-get="task_details?task_id={{ tasks_db[uuid].uuid }}"
hx-target="#task_details">
{{ tasks_db[uuid].id }}
</button>
{% endif %}
{% endfor %}
{% endif %}
{% if task.urgency > 20 %}
<div class="btn btn-xs btn-warning join-item">{{ task.urgency }}</div>
{% elif task.urgency > 10 %}
<div class="btn btn-xs btn-primary join-item">{{ task.urgency }}</div>
{% else %}
<div class="btn btn-xs btn-neutral join-item">
{{ task.urgency }}</div>
{% endif %}
{% if task.due and task.status != 'completed' %}
<div class="btn btn-neutral btn-xs join-item">
{{ date_proper(date=task.due, in_future=true) }}
</div>
{% endif %}
{% if task.start %}
<div class="btn btn-neutral btn-xs join-item">{{ date_proper(date=task.start) }}</div>
{% endif %}
{% if task.end %}
<div class="btn btn-neutral btn-xs join-item">{{ date_proper(date=task.end) }}</div>
{% endif %}
<div class="btn btn-neutral btn-xs join-item">
{% if task.entry %}{{ date_proper(date=task.entry) }}{% endif %}
</div>
</div>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,32 @@
<div class="modal-box">
<h2 class="text-lg font-bold text-neutral-50">{{ heading }}</h2>
<p class="mt-2 text-sm text-neutral-400">
The undo command is not reversible. Are you sure you want to revert to the previous state?
<ul class="text-neutral-500 text-sm mb-4">
{% for line in report %}
<li class="mt-2">{{line | replace(from='\t', to=' ') }}</li>
{% endfor %}
</ul>
</p>
<div class="modal-action" id="model-undo">
<button class="btn btn-warning btn-md"
id="btn-mdl-yes"
hx-include="[id='filtering']"
hx-target="#list-of-tasks"
hx-trigger="click,keyup[key=='Enter'] from:body"
hx-post="tasks/undo/confirmed">
<kbd class="shortcut_key">Enter</kbd> Yes, Sure
</button>
<button class="btn btn-success btn-md"
hx-get="tasks"
hx-trigger="click,keyup[key=='Escape'] from:all-dialog-boxes"
hx-include="[id='filtering']"
hx-target="#list-of-tasks">
<kbd class="shortcut_key">Esc</kbd> Cancel
</button>
</div>
<script>
document.getElementById('all-dialog-boxes').showModal()
</script>
</div>

BIN
modules/home/tww/taskwarrior-web Executable file

Binary file not shown.

1
result Symbolic link
View file

@ -0,0 +1 @@
/nix/store/64k46yhc7x77z100km28q7xvxk8xcvc0-taskwarrior-web-2025-04-01