{# Vendor assets via asset() helper. Default mode = CDN (jsDelivr) with SRI; #} {# when `ntasker assets fetch` ran and `assets_mode=local|auto`, they come from #} {# the user-data dir under /static/vendor instead. SRI is emitted in both modes #} {# (local mode: tamper detection). `crossorigin` is only required for CDN loading. #} {# Frontend i18n bridge: js_strings is built server-side per request. #} {# Alpine magic property `$i18n('key')` is registered just below. #}
{# Sidebar: project + tag filter (full-width checkboxes). Hidden on mobile (<768px). #} {# Sticky-positioned aside outside the .page wrapper. Tabler/Bootstrap surface vars #} {# drive the bg so dark-mode behaves. Sidebar has its own scroll context; the main #} {# page-wrapper scrolls independently. #} {# Main content (full-width inside its column) #}
{# Tabler page-header: title left, view-mode switcher right. #} {# The two pseudo-tabs (Task list / Kanban) drive ``viewMode`` -- #} {# they are NOT bootstrap nav-tabs because the page wrappers below #} {# swap their entire layout, not just a tab-pane. #}
{# v2.0: projects_dir-Banner is gone -- projects emerge #} {# implicitly from tasks; no filesystem setup required. #} {# New-task form. The header doubles as an accordion toggle and #} {# the body starts collapsed, so more of the task list stays #} {# visible until the user actually wants to add something. #}

{{ t('New task') }}

{# Free-form text + AlpineJS combobox: pick an existing project #} {# (Tab/Enter accept the highlighted suggestion, like tags) or #} {# type a new name -- created implicitly when the task is saved. #} {# Empty = cross-project. #}
{# Live match indicator: green check on an exact existing-project #} {# match, a "new folder" icon on a name that does not exist yet #} {# (it will be created on first run -- see message below). #}
{# New-project notice: shown the instant a name that does not exist #} {# yet is typed. Tells the user a directory will be created on run. #}
{# Tag-Input: AlpineJS-driven combobox. Tags as badges, free-text input, autocomplete dropdown. #}
{# Dependency input: autocomplete by title/#id, picks resolve to #id chips. #}
{# Create + immediately hand the task to its agent -- only when that agent's CLI + a PTY are available. #}
{# Running-projects chips: one per project with a live agent #} {# session, so you see at a glance what is running in parallel #} {# right now. The common case (one session) makes the whole chip #} {# a link straight into that #/run/ session, with the agent #} {# logo after the name. The rare multi-session case keeps the name #} {# as a label and turns each session's logo into its own link. #} {# Auto-updates from the session poll; hidden when nothing runs. #} {# x-show sits on a plain wrapper (no Bootstrap display utility) so #} {# `.d-flex !important` cannot override Alpine's display:none. #}
{# Tabs -- list view only. Kanban renders its own column layout below. #} {# Task list #}

{{ t('No tasks') }}

{# ===== Kanban board view ===== #} {# 4 columns: 3 phase columns (planned/wip/review) + 1 collapsible #} {# Done column derived from status='done'. Drag a card between #} {# columns -> PATCH phase (or status when crossing into Done). #} {# Same filters (search / sidebar) feed the same task list; #} {# the kanban view just groups it by phase. #}
{# === Claude run view -- full-page; replaces list/kanban while open. #} {# One tab per live session; the runs keep streaming in the background #} {# when you go Back. Each tab owns its own xterm + WebSocket. === #}
{# Header: back, per-session tabs, live status + actions for the active tab. #}
{# Tab strip: one per open session. Click switches (drives the #/run/ hash). #}
{# One xterm host per tab; only the active one is shown. Stable #} {# :id lets _claudeConnect attach the Terminal to the right node. #}
{# Edit modal #}
{# Toast container (Tabler/Bootstrap-compatible). Toasts injected by app.js. #}
{# xterm.js for the interactive Claude terminal. Loaded eagerly (no defer) so #} {# the Terminal / FitAddon globals exist before app.js uses them at runtime. #}