- Wrap heatmap in collapsible "Activity" section, collapsed by default
- Lazy-load heatmap only when expanded to avoid loading full archive
- Disable autoFocus at all dialog call sites to prevent keyboard popup
- Icon-only action buttons on small screens with aria-labels
- Rename "Remove for" to "Skip for" with consistent confirmation dialog
- Save button raised, Remove button warn color
Lock cdkDragLockAxis to Y on small screens (<600px) for task-list and
planner components, matching the breakpoint where planner switches to
single-column and bottom nav appears. Nav menu tree always locks Y.
Uses reactive LayoutService.isXs() so orientation changes work correctly.
Throttle tree-dnd onDragMoved with requestAnimationFrame to reduce
layout thrashing from getBoundingClientRect/elementFromPoint calls.
- moveItemAfterAnchor: preserve current position when anchor is
concurrently deleted instead of appending to end (which corrupted
ordering on remote clients). For cross-list moves, append to end
as fallback to prevent data loss.
- Prevent double-write of deferred actions: track buffered actions in
a WeakSet and filter them in the effect so they are only written
once by processDeferredActions().
- Propagate skipDequeue through handleQuotaExceeded retry path to
prevent queue desync when deferred actions hit storage quota.
- Add e2e tests for concurrent delete + reorder sync scenarios.
Angular emulated ViewEncapsulation shares the same _ngcontent attribute
across all instances of the same component type. The :host:focus
.inner-wrapper > .box selector therefore matches subtask .box elements
when the parent task is focused. Override with a more specific selector
that includes .sub-tasks to reset border-color back to defaults.
Switch task-title edit-mode trigger from mousedown to click so that
mousedown propagates freely to CDK drag. CDK's built-in 5px threshold
distinguishes drag from click naturally.
* Fix#6290: Prevent banner flickering on action change
To prevent this, I updated the logic so that now
the banner only closes when the id changes, in other
words, the banner only closes when we complete the
session. It doesn't close the session if we only
change the action(play, stop...)
* test(banner): move isKeepVisibleAfterAction tests to component spec
The dismiss-on-action logic lives in BannerComponent.action(), not in
BannerService. Move tests to a component spec so they exercise the
actual code path: component.action() conditionally calls dismiss()
based on banner.isKeepVisibleAfterAction before invoking the callback.
---------
Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
Extract done-toggle and swipe-block into shared UI components and reuse
them in planner-task, giving it the same checkmark toggle, swipe
gestures, and drag-ready indication as the regular task component.
- Extract DoneToggleComponent with SVG checkmark, progress ring, and
keyboard accessibility
- Extract SwipeBlockComponent with pan gesture handling, action
thresholds, and visual feedback blocks
- Add PanDirective pancancel event for proper touchcancel cleanup
- Add PAN_MAX_START_DELAY derived from DRAG_DELAY_FOR_TOUCH to
distinguish swipe gestures from long-press drag intent
- Stop touch event propagation during panning to prevent nested
swipe-blocks from interfering
- Add long-press drag delay and drag-ready visual indication for
touch devices in planner views
- Show subtask count and time estimates in planner task layout
- Restore desktop right-click context menu on planner tasks
- Apply zen theme styling refinements for planner tasks
- Replace BaseComponent inheritance with takeUntilDestroyed()
- Remove unused dead code (moveToProjectList$, Log.log, etc.)
- Fix misleading label: "When project is open" → "When context is open"
since polling also works for tag contexts, not just projects
- Hide pollingMode field for ICAL providers since calendar providers
already poll globally via selectAllCalendarIssueTasks
Use CDK's built-in cdk-overlay-dark-backdrop class on touch devices
instead of fighting the overlay system with custom scrim hacks. CDK
handles both the dimmed backdrop and tap-to-close natively. Clear CDK's
inline width/height on the bounding box so inset:0 stretches it for
bottom-sheet layout. Smooth slide-up animation with disabled Material
animation to prevent conflicts. Add task title header and source task
highlight via CSS class with proper takeUntil cleanup.
Add a pollingMode setting ('whenProjectOpen' | 'always') to issue
providers. When set to 'always', both issue update polling and backlog
import polling run continuously in the background regardless of which
project or tag is currently active.
- Add pollingMode field to IssueProviderBase model and default config
- Add polling mode select field to common issue provider form
- Split update-polling and backlog-polling into context-scoped and
always-running effects with proper lifecycle management
- Always-mode effects start once after sync and react only to provider
config changes, not context switches
- Use from() + catchError inside switchMap for async error resilience
- Add translation keys for form labels
- Add comprehensive tests including error resilience and no-restart
behavior
* fix: address review findings from daily changes
- Add setPermissionCheckHandler alongside setPermissionRequestHandler
for defense-in-depth in Electron (permission queries now also denied)
- Fix tagIds merge ordering in issue service: provider adapter tags are
now merged with default tags instead of being silently overwritten
- Execute deleteTask action last in automations to prevent subsequent
actions from failing on a deleted task
- Add unit tests for getTaskDefaults logic (TODAY_TAG filtering,
defaultNote, tagIds merging, deduplication, context tags)
- Add test for deleteTask execution ordering in ActionExecutor
https://claude.ai/code/session_01UhoR5g7RQgm4E6bZCvU9PS
* refactor: revert YAGNI changes from review fixes
- Revert tagIds merge in issue.service.ts: no provider currently sets
tagIds in getAddTaskData, so merging solves a hypothetical problem
- Revert deleteTask sort in action-executor: the automations feature is
new and nobody has hit this edge case yet
- Remove tests for reverted behavior, keep tests for existing features
(TODAY_TAG filtering, defaultNote, note override prevention)
https://claude.ai/code/session_01UhoR5g7RQgm4E6bZCvU9PS
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat(task-view): add deadline support for sort, group, and filter
Add deadline as an option alongside scheduled date for sorting, grouping,
and filtering tasks. Uses the same date-range presets (today, tomorrow,
this week, next week, this month, next month) with deadline-specific
labels ("Due Today", "Due This Week", etc.).
Closes#6895
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor(task-view): extract shared date filter and sort helpers
Extract _filterByDateFields and _sortByDateFields to eliminate ~60 lines
of duplicated logic between scheduledDate and deadline filter/sort cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(task-view): use translation key for deadline grouping fallback and add tests
Replace hardcoded 'No deadline' string in deadline grouping with a
translated key (GROUP_DEADLINE_NONE). Add unit tests for deadline
filter, sort, and grouping logic.
---------
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
* feat(benchmark): add task title link rendering benchmark
- Creates benchmark page at /benchmark route
- Generates 1000 test tasks (1/3 no links, 1/3 URLs, 1/3 markdown)
- Measures initial render time
- Measures scrolling FPS during 2s scroll animation
- Includes toggle for link rendering (not yet functional)
- Baseline for measuring performance impact of link rendering
* feat(benchmark): increase to 5000 tasks and improve results display
- Increase task count from 1000 to 5000 for more measurable differences
- Add copyable results display with pre-formatted text
- Add 'Copy Results' button for easy sharing
- Include link rendering state in results output
- Format results in monospace font for better readability
* feat(benchmark): measure initial render from blank state
- Start with empty task list instead of pre-generating on page load
- Generate tasks only when benchmark runs
- Clear existing tasks before each benchmark run
- Use double requestAnimationFrame to ensure complete render
- Provides accurate measurement of initial render performance
- Reset now clears tasks instead of regenerating them
* refactor(benchmark): remove redundant reset button
Run Benchmark now handles resetting state, making the separate
reset button unnecessary
* feat(task-title): render URLs and markdown links as clickable links
- Detect URLs (https://, http://, file://, www.) and markdown [title](url) syntax
- Render as <a> tags with target="_blank" rel="noopener noreferrer"
- XSS protection: HTML-escape all user content, validate URL schemes
- ReDoS protection: limit URL length to 2000 chars in regex
- ~0 perf cost when disabled via renderLinks signal input
- string.includes() pre-check skips regex for plain-text tasks
- Direct HTML escaping (4 replace calls) instead of DomSanitizer for speed
- readonly input disables editing and uses inherit cursor
- Add unit tests: XSS protection, ReDoS, readonly mode, click propagation
* feat(config): add isEnableLinkRendering setting to short syntax config
Add a checkbox in Settings → Short Syntax to toggle clickable link rendering
in task titles. Defaults to enabled. Wired to the renderLinks input of task-title.
* feat(task-title): render links in planner-task and schedule-event via pipe
Add RenderLinksPipe to convert URLs and markdown links to clickable <a> tags
without including the full task-title component. Use [innerHTML] with the pipe
in planner-task and schedule-event to keep their existing styling intact.
* refactor(task-title): use RenderLinksPipe to eliminate duplicate link-rendering code
Remove inline URL/markdown processing (URL_REGEX, MARKDOWN_LINK_REGEX,
_escapeHtml, _isUrlSchemeSafe, displayHtml computed) from task-title
component and delegate to the shared RenderLinksPipe instead.
The hasUrlsOrMarkdown() fast pre-check (includes() scan) is preserved as
a template guard so the pipe is only invoked for tasks that actually
contain URLs or markdown - plain text tasks still use cheap interpolation.
* fix(task-title): Better XSS protection when rendering links
* fix(task-title): Move XSS tests
* fix(task-title): fix parentheses counting in markdown links
* fix(task-tests): add signal in one place to compute if links should be rendered or not
* fix(task-title): prevent clicks from propagating when they shouldn't
* fix(task-title): convert readonly inputs on task title
* fix(task-title): Add aria-label to the urls
* fix(task-title): mock pipe in tests
* fix: focus mode test
* fix(task-title): add ocmment why we have duplicated content
* fix(task-title): exclude a few more schemes
* fix(task-title): harden link rendering security and performance
- Fix ReDoS in MARKDOWN_LINK_REGEX by using [^()]+ instead of [^()]*
to break catastrophic backtracking (fixes CodeQL failure)
- Add single-quote escaping to _escapeHtml for defense-in-depth
- Replace permissive URL scheme fallback with strict /^[a-z]+:/
detection to reject tel:, mailto:, and other non-browsable schemes
- Remove /benchmark route from production (component kept for dev use)
- Extract LINK_HINT_* constants shared between pipe and component
- Add fast-path optimization to planner-task to skip [innerHTML]
for plain-text tasks
* perf(task-title): optimize link rendering hot path
- Replace 5 chained _escapeHtml regex calls with single-pass lookup table
- Replace new URL() in _ariaLabelForUrl with manual hostname extraction
- Hoist all regexes to module-level constants (SCHEME_RE, TRAILING_PUNCT_RE)
- Replace _stripUrlTrailing match() array allocations with charCode loop
- Replace _normalizeHref regex with startsWith checks
- Move helpers to module-level arrow consts (removes method dispatch overhead)
* refactor(task-title): extract hasLinkHints utility and add schedule fast-path
- Extract shared hasLinkHints() function from duplicated hint checks
- Add fast-path optimization to schedule-event (was missing, unlike
planner-task and task-title which already had it)
- Optimize _stripUrlTrailing to use single substring instead of
repeated slice allocations
- Simplify imports across consuming components
* fix(task-title): reject empty URLs and clean up benchmark component
- Reject empty markdown URLs [text]() that would produce broken
href="http://" links
- Remove unnecessary CommonModule import from benchmark component
- Remove redundant standalone: true (default since Angular 19)
* fix(task-title): make links clickable on touch devices and schedule view
Links were unreachable in two contexts due to inherited pointer-events: none:
- task.component sets pointer-events: none on task-title for touch-primary
devices (to allow drag-and-drop)
- schedule-event.component.scss sets pointer-events: none on all direct
children of :host (so clicks bubble to the host handler)
Fix by adding pointer-events: auto on <a> tags in both task-title and
schedule-event styles. This overrides the inherited value so links are
clickable while preserving drag behavior on surrounding text.
* fix(task-title): use unrolled loop regex to fix CodeQL ReDoS warning
The previous [^()]+ fix wasn't sufficient — consecutive non-paren
characters could still be split across iterations of the outer *
in exponentially many ways when the match fails.
Restructure to [^()]*(?:\([^()]*\)[^()]*)* where each iteration
of * MUST start with a literal '(' — eliminating partition ambiguity.
Verified: pathological 50-char input completes in <0.1ms.
* fix(schedule): lift links above ::before overlay with z-index
The schedule-event ::before pseudo-element at z-index: 3 covers the
entire host, intercepting pointer events before they reach <a> tags
even with pointer-events: auto. Add position: relative and z-index: 4
to links so they stack above the overlay.
* refactor(task-title): remove link rendering toggle, always render links
Remove the isEnableLinkRendering config option and all plumbing:
- Delete config model field, default, form checkbox, service signal
- Delete translation key and string
- Remove renderLinks parameter from pipe (always renders)
- Remove renderLinks input from task-title component
- Remove GlobalConfigService injection from 3 components that only
needed it for this setting
- Remove isLinkRenderingEnabled property from all 6 consuming components
- Remove mock setup from 3 test files
- Simplify hasLinkHints checks (no setting gate needed)
This eliminates ~100 lines of config threading code. The pipe's internal
fast-path still skips regex for plain-text tasks.
* chore: remove unused benchmark component
---------
Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
* fix(plugin-bridge): enhance task update logic and validation for project movement
* fix(plugin-bridge): include changes in task update event payload
* feat(RuleEditor): add tests for rule editing functionality and enhance action handling
* test(RuleEditor): add comprehensive tests for rule editing and condition handling
* feat(RuleRegistry): enhance rule validation and add support for advanced conditions and actions
* feat(types): extend condition and action types for enhanced automation capabilities
* feat(conditions): add regex support for title conditions and enhance checks
* feat(actions): add ActionMoveToProject to move tasks between projects
* feat(ActionDialog, ActionInput): add support for moveToProject action and enhance input handling
* feat(ConditionDialog, ConditionInput): add support for titleStartsWith and weekdayIs conditions, enhance regex handling
* feat(styles): add new input-with-toggle and field-error styles for improved layout and error handling
* feat(automation): add titleStartsWith condition and enhance task event handling
* feat(automations): add delete task action
add a new `deleteTask` action to the automations plugin
- register the action in the automation runtime
- expose it in the rule editor UI
- restrict it to task-based triggers
- validate and persist rules using `deleteTask`
- add focused tests for runtime behavior, validation, persistence, and UI
* feat(automations): remove false trigger workaround
remove the temporary taskCreated fallback after confirming the
reported trigger bug was a mistaken assumption
* fix(automations): address PR review feedback
- Add regex pattern length cap (200 chars) to mitigate ReDoS risk
- Use project ID instead of title as option value to prevent duplicate name collisions
- Replace dynamic import('rxjs') with static import for firstValueFrom
- Replace any[] with proper types for projects/tags props
- Replace changes?: any with Record<string, unknown> in TaskEvent
- Use createMemo + <Show> for regexError to avoid double reactive computation
- Remove noisy/inconsistent debug logging from automation-manager
- Remove verbose intermediate log from moveToProject action
- Clean up mock: remove unused moveTaskToProject, restore PluginAPI type
- Prefer ID lookup over title in ActionMoveToProject
* fix(automations): harden regex, use IDs for conditions, add validation and tests
- Add dangerous-pattern heuristic to reject nested quantifiers (e.g. (a+)+$)
that cause catastrophic backtracking, supplementing the length cap
- Switch projectIs/hasTag condition dropdowns to store IDs instead of titles
to survive project/tag renames (with title fallback for backward compat)
- Disable ActionDialog Save button when value is empty (except deleteTask)
- Fix webhook test to actually validate payload sanitization
- Add test for HTML escaping in ActionDisplayDialog
- Add tests for regex length cap and dangerous-pattern rejection
- Add tests for ConditionWeekdayIs (7 test cases covering full names,
abbreviations, comma-separated lists, case insensitivity, edge cases)
* test(automations): build dangerous regex pattern dynamically to avoid CodeQL flag
The test intentionally uses a catastrophic-backtracking pattern to verify
our safety heuristic rejects it. Build it via string concatenation so
CodeQL's static analysis doesn't flag the test itself.
* fix(automations): addTag lookup by ID, widen ReDoS heuristic to catch {n,}
- ActionAddTag now looks up tags by ID first (with title fallback),
consistent with all other condition/action lookups
- Extend DANGEROUS_REGEX_PATTERN to also detect {n,} quantifiers
inside nested groups (e.g. (a{2,})+) which also cause backtracking
---------
Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
* fix: make sub-tasks visually distinct in search results
- Add parentTitle to SearchItem for sub-task breadcrumb display
- Show subdirectory_arrow_right icon for sub-tasks
- Display parent task title as breadcrumb (Parent › Sub-task)
- Add indentation, italic styling for sub-task titles
- Update unit tests for parentTitle resolution
Fixes#6785
* fix(search): move subtask styles inside ::ng-deep and simplify CSS
- Move .subtask-icon, .subtask-breadcrumb, .task-subtask inside the
::ng-deep block so styles reach projected content in mat-list-item
- Replace hardcoded › character with chevron_right Material icon
- Remove unused search-result-subtask class from mat-list-item
- Simplify CSS: drop extra font-size overrides, use consistent units
* refactor(search): use [class.*] bindings and fix orphan subtask styling
- Replace [ngClass] with [class.*] bindings to match project convention
- Remove unused NgClass import
- Align italic condition with breadcrumb condition (use parentTitle
instead of parentId) so orphan subtasks don't get unexplained italic
---------
Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
The play triangle on the checkbox was visible for 200ms during the done
animation because setDone() is called after a timeout. Check
showDoneAnimation() to hide it instantly.
* fix(tasks): hide horizontal scrollbar on task context menu
The mat-mdc-menu-panel has overflow:auto by default, causing a
horizontal scrollbar when menu item content (text + keyboard shortcut
badges) slightly exceeds the panel width. Menus never need horizontal
scrolling, so overflow-x is set to hidden.
https://claude.ai/code/session_01JVV5tUzoQKzimTvBJxBWc1
* fix(tasks): fix root cause of context menu horizontal overflow
The .menuItemLeft flex child had no min-width:0, so it refused to
shrink below its intrinsic content width (flex items default to
min-width:auto). When translated text + icon + keyboard shortcut badge
exceeded the panel's 280px max-width, the content overflowed.
Adding min-width:0 and overflow:hidden allows the flex item to shrink
properly and truncate text with ellipsis.
https://claude.ai/code/session_01JVV5tUzoQKzimTvBJxBWc1
---------
Co-authored-by: Claude <noreply@anthropic.com>
The schedule task dialog can shift vertically when calendar content
changes, which creates a jumpy experience while picking dates.
Set a fixed height on the embedded mat-calendar in the schedule task
dialog to keep layout stable and improve usability.
Closes#6556
* feat(issue): add default tags and note for issue provider imports
Allow users to configure default tags and a default note on issue
provider settings. Imported tasks automatically receive these defaults.
Tags use the existing ChipListInputComponent pattern from the recurring
task config dialog. The default note is a textarea in the advanced
config section.
Closes#6652
* fix(issue): address review feedback for default tags/note feature
- Remove unused `computed` import
- Use translation keys for default tags and note labels
- Change `defaultNote: undefined` to `null` for consistency
- Rename `getProjectOrTagId` to `getTaskDefaults`
* fix(issue): update defaultNote type to accept null
Align with defaultProjectId and pinnedSearch types which also
include null in their union types.
* fix(issue): clean up orphaned defaultTagIds on tag deletion and preserve provider notes
Remove deleted tag IDs from issue provider defaultTagIds in the
tag-shared meta-reducer, preventing stale references from being
applied to future imported tasks.
Only apply defaultNote when the provider didn't already set notes
(CalDAV, iCal, Nextcloud Deck return issue-specific notes that
should take priority over the generic default).
* fix(issue): add TODAY_TAG guard on defaultTagIds and remove stale comment
Filter TODAY_TAG.id from defaultTagIds before applying to imported
tasks, enforcing the architectural invariant that TODAY_TAG must
never appear in task.tagIds. The UI already excludes it from
suggestions, but this guards against corrupted data or sync payloads.
Also removes stale comment about tags being overwritten, since
getTaskDefaults() now handles tags directly.
---------
Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
* fix: add UTF-8 BOM for CSV export to fix Chinese character encoding
* fix: add UTF-8 BOM for CSV export only on download
* fix(worklog): remove unused simpleDownloadData getter
---------
Co-authored-by: Sa-Vampire <vampireio1589@gmail.com>
Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
Guard against undefined task in pushFieldsOnTaskUpdate$ effect. When a
task is deleted (e.g. during repeating task cleanup at day boundary) but
an updateTask action is still dispatched for it, selectTaskById returns
undefined. Without the null check, accessing .issueType on undefined
crashes with "Cannot read properties of undefined (reading 'issueType')".
Closes#6907
Rename layoutService.isScrolled to isWorkViewScrolled for clarity and
expose it as a host class on app-root. The zen theme uses this to give
the current task a background when stuck, preventing content bleed-through.
When tasks already exist (e.g. from example tasks), skip the
"create-task" hint but still show the "explore" hint instead of ending
all onboarding hints. Remove unused selectHasAnyTasks selector,
write-only ONBOARDING_PRESET_ID storage key and its setItem call.
* fix(tasks): cap done sound pitch to prevent inaudible high frequencies
The pitch increases by 50 cents per completed task with no upper limit,
making the sound inaudible after many tasks. Cap at 800 cents (one octave
above original) so the sound remains audible.
https://claude.ai/code/session_014DbHEDfK1Dj2Q8nJmZkx99
* fix(tasks): lower done sound pitch cap from 800 to 300 cents
800 cents was still too high — the upper ~30% of the range was hard to
hear. 300 cents (a minor third above original) keeps the sound
comfortably audible throughout.
https://claude.ai/code/session_014DbHEDfK1Dj2Q8nJmZkx99
---------
Co-authored-by: Claude <noreply@anthropic.com>
Remove the AddScheduledTodayOrTomorrowBtnComponent and its usage from
the work view. The service is kept as it's still used by task-due effects.
https://claude.ai/code/session_01XzgzMHEbLV7kMWSB4BzJUe
Co-authored-by: Claude <noreply@anthropic.com>
* fix: remove duplicate keys and improve cleanup in review fixes
- Remove duplicate isFinishDayEnabled entry in app-features-form config
- Remove duplicate FINISH_DAY translation key in en.json
- Add OnDestroy with timeout/rAF cleanup to context menu component
- Extract animation timing magic numbers into named constants
https://claude.ai/code/session_01YNw7hecnt3eJPkafqTSHvT
* chore: update package-lock.json after npm install
https://claude.ai/code/session_01YNw7hecnt3eJPkafqTSHvT
* fix(tasks): prevent dialog subscription from being cancelled on context menu destroy
The ngOnDestroy we added triggers _destroy$ which cancels the
takeUntil(this._destroy$) pipe on the delete confirmation dialog's
afterClosed subscription. This prevented the delete from executing
after the user confirmed. Dialog subscriptions auto-complete on
dialog close, so takeUntil is unnecessary here.
https://claude.ai/code/session_01YNw7hecnt3eJPkafqTSHvT
* fix(tasks): remove takeUntil from remaining dialog subscriptions in context menu
Same issue as the delete confirmation fix: the context menu component
is destroyed when the menu closes, firing _destroy$ and cancelling
dialog afterClosed subscriptions for time estimate and attachment
dialogs before the user interacts with them.
https://claude.ai/code/session_01YNw7hecnt3eJPkafqTSHvT
---------
Co-authored-by: Claude <noreply@anthropic.com>
* perf(tasks): conditionally render play indicator SVG elements
Previously, progress-ring and play-indicator SVG elements were rendered
in the DOM for every task (with opacity: 0), even though only the single
current task needs them. With 100+ tasks, this created hundreds of
unnecessary DOM nodes and the infinite CSS animation caused continuous
GPU compositing.
Now these elements are wrapped in @if (isCurrent() && !t.isDone) so they
only exist in the DOM for the active task.
https://claude.ai/code/session_01FGFicJ9Rk6hZ89by3k6yHB
* chore: update package-lock.json
https://claude.ai/code/session_01FGFicJ9Rk6hZ89by3k6yHB
* chore: update package-lock.json dependencies
https://claude.ai/code/session_01FGFicJ9Rk6hZ89by3k6yHB
* fix(tasks): restore hover transition on play indicator elements
The transition property was accidentally removed, causing the hover
fade-out of progress-ring and play-indicator to be instant instead
of smooth.
https://claude.ai/code/session_01FGFicJ9Rk6hZ89by3k6yHB
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat/we-need-some-sort-of-play-indication-e620e3:
fix(tasks): speed up circle draw phase to ~2s with longer pause
fix(tasks): slow circle-draw to every 3s with 3s pause
fix(tasks): match idle circle brightness and add 2s pause between draws
fix(tasks): add round stroke-linecap to progress ring
fix(tasks): use currentColor for play indicator and match 2s pulse timing
fix(tasks): use regular color for progress ring and hide background circle
fix(tasks): use decorative circle-draw animation and subtle play indicator
feat(tasks): add play indicator and progress ring to done-toggle circle
- Replace progress-based ring with CSS-only circle-draw animation (3s eased loop from 12 o'clock)
- Make play triangle more subtle (0.5 opacity)
- On hover: hide play indicator and progress ring, show default checkbox circle
- Remove JS animation code (no longer needed - pure CSS)
display: flex on the plan-view host caused .days to stretch to the
container height via align-items: stretch, so content overflow stayed
inside .days and never triggered the overflow: auto scrollbar.
Changing to display: block lets .days grow to its natural content
height, restoring both vertical and horizontal scrolling.
Adds a minimal theme that removes task backgrounds and shadows for a
clean, borderless look. Tasks get an opaque background on hover (controls
only) and when dragged. Also sorts theme list alphabetically.