diff --git a/CLAUDE.md b/CLAUDE.md index d1e4330..9e29ffe 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7,9 +7,6 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co Deskmeter is a productivity tool that measures time spent across desktop workspaces. It consists of four main components: - **dmcore**: Core tracking daemon (`dmapp/dmcore/main.py`) that monitors active workspace and task changes -- **dmweb**: Flask web application (`dmapp/dmweb/`) for viewing productivity data -- **dmfnt**: Angular frontend (`dmapp/dmfnt/`) for enhanced UI (in development) -- **gnome-extension**: GNOME Shell extension (`gnome-extension/deskmeter-indicator@local/`) that displays current task in the top panel ## Architecture @@ -32,21 +29,21 @@ Deskmeter is a productivity tool that measures time spent across desktop workspa ### Web Interface Structure **Flask Routes** (`dmapp/dmweb/dm.py`): -- `/` - Today's productivity summary -- `/day//` - Single day view -- `/calendar` - Google Calendar-style task timeline view (daily/weekly/monthly) -- `/switches` - Raw switch documents view (daily/weekly/monthly) -- `/workmonth` - Monthly calendar showing task totals via `dmapp/dmweb/dmcal.py` +- `/` - Today's productivity summary (large display with auto-refresh) +- `/calendar////?grid=<1|3|6>` - Google Calendar-style view with aggregated task blocks + - Scopes: `daily`, `weekly`, `monthly` + - Grid: Hour aggregation (1h, 3h, or 6h blocks) + - Shows only active workspaces (Plan/Think/Work) with gaps for idle time + - Cascading overlapping blocks for multiple tasks per time period +- `/switches////` - Raw switches view with proportional cell heights + - Shows all workspace switches with time-based height visualization +- `/work` - Work projects breakdown for today - `/totals` - All-time statistics -- `/api/current_task` - JSON API endpoint returning current task info (for GNOME extension) +- `/day//` - Single day view +- `/period//` - Custom date range +- `/api/current_task` - JSON endpoint for current task info (used by GNOME extension) - `/api/today` - HTML fragment for AJAX updates -**Task Info API** (`dmapp/dmweb/get_period_times.py`): -- `get_current_task_info()` - Retrieves current task ID and path from MongoDB state collection -- `get_task_path()` - Resolves task ID to path, with automatic task_history fallback -- `get_task_blocks_calendar()` - Groups consecutive switches by task, tracks active/idle time -- `get_raw_switches()` - Returns all switch documents for a period - ## Development Commands ### Python Backend @@ -71,24 +68,26 @@ cd dmapp/tests python3 test_dmapp.py ``` -### Angular Frontend +### Running the Web Interface + +Use the `dmweb.sh` script for flexible deployment: ```bash -cd dmapp/dmfnt +cd /home/mariano/wdir/run -# Install dependencies -npm install +# Syntax: ./dmweb.sh +./dmweb.sh dm-fend-updates 10002 1 -# Development server -npm run start - -# Build for production -npm run build - -# Run tests -npm run test +# Parameters: +# - worktree: directory name in /home/mariano/wdir/ (default: dm) +# - port: Flask server port (default: 10000) +# - debug: 1 for debug mode with auto-reload, 0 for production (default: 0) ``` +### Angular Frontend (Not Yet Implemented) + +The Angular frontend (`dmapp/dmfnt/`) mentioned in the architecture is planned but not currently implemented. All current functionality is in the Flask templates. + ### GNOME Extension ```bash @@ -243,7 +242,7 @@ Both support daily, weekly, and monthly scopes with navigation. - The system enforces task constraints within work desktops - switching to a non-work task automatically reverts to the designated work task - Task files are monitored for changes to enable automatic context switching -- Web interface runs on port 10000 by default +- Web interface runs on port 10000 by default (configurable via `dmweb.sh` script) - Core daemon sleeps for 2 seconds between workspace checks - GNOME extension debounce delay (2.2s) must be > dmcore polling interval (2s) to ensure MongoDB is updated before API query @@ -285,8 +284,63 @@ Both support daily, weekly, and monthly scopes with navigation. 4. **Gradient indicates work quality** - Visual distinction between active focus and idle time 5. **Multiple thresholds** - Different minimum block durations for different scopes reduces noise +### UI/UX Design + +**Dark Mode Theme** (applied across all views): +- Background: `#1a1a1a` +- Text: `#e0e0e0` +- Accent/links: `#6b9bd1` +- Borders: `#444` +- Component backgrounds: `#2a2a2a` + +**Calendar View Features**: +- Hour-based aggregation (configurable: 1h, 3h, 6h grids) +- Overlapping task blocks cascade right and down (8% horizontal, 4px vertical per task) +- Only active workspaces shown (Plan/Think/Work) - idle time appears as gaps +- Task colors generated via hash-based HSL for consistency +- Height proportional to time spent in each grid period + +**Switches View Features**: +- Cell heights proportional to switch duration (30px min, 200px max) +- Color-coded by task with hash-based HSL +- Dark backgrounds with reduced opacity for idle workspaces + +**Navigation**: +- Consistent nav bar across all views: Today | Calendar | Switches | Work | All Time +- All views interconnected for easy movement between different data perspectives + +## GNOME Extension + +A GNOME Shell extension displays the current task in the top panel: +- Location: `gnome-extension/deskmeter-indicator@local/` +- Polls `/api/current_task` endpoint +- Updates on workspace switch with 2.2s debounce +- Automatically truncates long task paths +- Installation: `./gnome-extension/install.sh` or `./gnome-extension/update.sh` + +## Key Implementation Details + +**Calendar Aggregation** (`dmapp/dmweb/get_period_times.py:get_task_blocks_calendar()`): +- Aggregates switches by configurable time grid (1h, 3h, or 6h) +- Only includes active workspaces: Plan, Think, Work +- Returns blocks with task_id, task_path, start time, duration, and hour +- Filters out blocks shorter than `min_block_seconds` + +**Task Path Resolution**: +- Primary: `tasks` collection (current tasks) +- Fallback: `task_history` collection (cached historical tasks) +- Last resort: On-demand file search in task directory +- Caching prevents repeated file I/O + +**Switch Height Calculation** (switches view): +- Finds max delta in current view +- Heights scale linearly: `base_height + (ratio * (max_height - base_height))` +- Base: 30px, Max: 200px + ## Tool Development Guidelines - This is a personal tool, not professionally developed -- reuse as it is as much as possible unless refactor is required explicitly, suggest improvements -- Only modify existing code if it absolutely doesn't make sense to add a new flow \ No newline at end of file +- Reuse existing code as much as possible unless refactor is required explicitly +- Only modify existing code if it absolutely doesn't make sense to add a new flow +- When adding features, maintain the dark mode theme consistency +- All new views should include the standard navigation bar diff --git a/dmapp/dmweb/templates/calendar.html b/dmapp/dmweb/templates/calendar.html index 5f85e93..497ffe4 100644 --- a/dmapp/dmweb/templates/calendar.html +++ b/dmapp/dmweb/templates/calendar.html @@ -1,32 +1,67 @@ {% extends 'layout.html' %} -{% block head %} - +{% block head %} {% endblock head %} -{% block content %} +{% block content %} - {{ content | safe }} + + +{{ content | safe }} {% endblock content %} \ No newline at end of file diff --git a/dmapp/dmweb/templates/calendar_view.html b/dmapp/dmweb/templates/calendar_view.html index a386060..cdb3aed 100644 --- a/dmapp/dmweb/templates/calendar_view.html +++ b/dmapp/dmweb/templates/calendar_view.html @@ -9,6 +9,23 @@ color: #e0e0e0; } + .nav-bar { + display: flex; + gap: 20px; + } + + .nav-bar a { + text-decoration: none; + color: #6b9bd1; + font-size: 12pt; + padding: 5px 10px; + border-radius: 3px; + } + + .nav-bar a:hover { + background-color: #2a2a2a; + } + .nav-tabs { display: flex; gap: 20px; @@ -169,6 +186,13 @@ {% block content %} + + diff --git a/dmapp/dmweb/templates/main.html b/dmapp/dmweb/templates/main.html index 88c25b0..a38cf0a 100644 --- a/dmapp/dmweb/templates/main.html +++ b/dmapp/dmweb/templates/main.html @@ -17,6 +17,27 @@ color: #e0e0e0; } + .nav-bar { + position: absolute; + top: 20px; + left: 20px; + display: flex; + gap: 15px; + } + + .nav-bar a { + text-decoration: none; + color: #6b9bd1; + font-size: 11pt; + padding: 5px 10px; + border-radius: 3px; + background-color: #2a2a2a; + } + + .nav-bar a:hover { + background-color: #3a3a3a; + } + .grey { color: #888; } @@ -57,6 +78,14 @@ + +
{% block content %} {% include 'main_content.html' %} diff --git a/dmapp/dmweb/templates/pages.html b/dmapp/dmweb/templates/pages.html index 1d65793..8ec37b7 100644 --- a/dmapp/dmweb/templates/pages.html +++ b/dmapp/dmweb/templates/pages.html @@ -1,16 +1,81 @@ {% extends 'layout.html' %} -{% block content %} +{% block head %} + +{% endblock head %} + +{% block content %} + + - {% for row in rows %} + {% for row in rows %} + {% if row["ws"] in ['Away', 'Other'] %} + {% set my_class = 'grey' %} + {% elif row["ws"] in ['Active', 'Idle'] %} + {% set my_class = 'blue' %} + {% else %} + {% set my_class = '' %} + {% endif %} - - + + -{% endfor %} + {% endfor %}
{{ row["ws"] }}{{ row["total"] }}{{ row["ws"] }}{{ row["total"] }}
- - {% endblock content %} \ No newline at end of file diff --git a/dmapp/dmweb/templates/switches_view.html b/dmapp/dmweb/templates/switches_view.html index c54008d..1291f31 100644 --- a/dmapp/dmweb/templates/switches_view.html +++ b/dmapp/dmweb/templates/switches_view.html @@ -9,6 +9,23 @@ color: #e0e0e0; } + .nav-bar { + display: flex; + gap: 20px; + } + + .nav-bar a { + text-decoration: none; + color: #6b9bd1; + font-size: 12pt; + padding: 5px 10px; + border-radius: 3px; + } + + .nav-bar a:hover { + background-color: #2a2a2a; + } + .nav-tabs { display: flex; gap: 20px; @@ -122,6 +139,13 @@ {% block content %} + +