Release v0.2.0: Task comments, recurring calendar, system tray, app branding

New features:
- Task comments with date-stamped entries and last-comment summary
- Recurring tasks expanded on calendar (daily/weekly/monthly/yearly)
- System tray mode replacing CMD window (Windows/macOS/Linux)
- Ironpad logo as exe icon, tray icon, favicon, and header logo

Technical changes:
- Backend restructured for dual-mode: dev (API-only) / prod (tray + server)
- tray-item crate for cross-platform tray, winresource for icon embedding
- Calendar view refactored with CalendarEntry interface for recurring merging
- Added CHANGELOG.md, build-local.ps1, version bumped to 0.2.0

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
skepsismusic
2026-02-16 13:48:54 +01:00
parent b150a243fd
commit 781ea28097
29 changed files with 1735 additions and 219 deletions

View File

@@ -10,8 +10,9 @@ use std::fs;
use crate::config;
use crate::routes::tasks::{
create_task_handler, delete_task_handler, get_task_handler, list_project_tasks_handler,
toggle_task_handler, update_task_content_handler, update_task_meta_handler, CreateTaskRequest,
add_comment_handler, create_task_handler, delete_comment_handler, delete_task_handler,
get_task_handler, list_project_tasks_handler, toggle_task_handler,
update_task_content_handler, update_task_meta_handler, AddCommentRequest, CreateTaskRequest,
UpdateTaskMetaRequest,
};
use crate::services::filesystem;
@@ -91,6 +92,14 @@ pub fn router() -> Router {
)
.route("/{id}/tasks/{task_id}/toggle", put(toggle_project_task))
.route("/{id}/tasks/{task_id}/meta", put(update_project_task_meta))
.route(
"/{id}/tasks/{task_id}/comments",
axum::routing::post(add_project_task_comment),
)
.route(
"/{id}/tasks/{task_id}/comments/{comment_index}",
axum::routing::delete(delete_project_task_comment),
)
// Note routes
.route(
"/{id}/notes",
@@ -143,6 +152,19 @@ async fn delete_project_task(Path((id, task_id)): Path<(String, String)>) -> imp
delete_task_handler(id, task_id).await
}
async fn add_project_task_comment(
Path((id, task_id)): Path<(String, String)>,
Json(payload): Json<AddCommentRequest>,
) -> impl IntoResponse {
add_comment_handler(id, task_id, payload).await
}
async fn delete_project_task_comment(
Path((id, task_id, comment_index)): Path<(String, String, usize)>,
) -> impl IntoResponse {
delete_comment_handler(id, task_id, comment_index).await
}
async fn list_projects() -> impl IntoResponse {
match list_projects_impl() {
Ok(projects) => Json(projects).into_response(),