Release v1.4.2: Comprehensive UI customization and settings overhaul
Major Features: - Added complete UI element visibility controls (show/hide any element independently) - Added system tray icon with live usage percentage display - Added customizable tray icon colors and update interval (10-300 seconds) - Added application settings (start on boot, start minimized, close to tray) - Added theme customization (backgrounds, text colors, borders, opacity controls) - Added configurable update intervals for both UI and tray (10-300 seconds) - Added static color mode option for progress bars - Added dynamic window resizing based on visible elements UI/UX Improvements: - Improved settings organization with collapsible sections - Consistent typography and spacing throughout settings panel - Larger, bolder section headers for better visual hierarchy - Removed donations button from settings - Element visibility controls for both Current Session and Weekly Limit sections - Master toggles for entire sections - Independent toggles for labels, bars, percentages, circles, and time text Bug Fixes: - Fixed element centering and responsive layout - Fixed timer container visibility handling when children are hidden - Fixed slider overlap with text above - Fixed window resizing to properly fit content - Fixed manual resizing while maintaining centered content Technical Changes: - Changed UI update interval from 1-10 minutes to 10-300 seconds - Standardized all settings to use .setting-group wrapper class - Removed inline styles in favor of CSS classes - Improved CSS organization with consistent spacing rules - Added proper flexbox centering for responsive layouts - Window constraints: 320-600px width, 96-180px height - Resizable window with content-based auto-sizing Documentation: - Comprehensive README update with all v1.4.2 features - Added screenshot placeholders for user documentation - Detailed settings explanations - Troubleshooting section expanded - Version history updated 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c4c758fbbd
commit
3b5ef59c32
9 changed files with 980 additions and 123 deletions
429
README.md
429
README.md
|
|
@ -1,21 +1,44 @@
|
||||||
# Claude Usage Widget
|
# Claude Usage Widget
|
||||||
|
|
||||||
A beautiful, standalone Windows desktop widget that displays your Claude.ai usage statistics in real-time.
|
A beautiful, highly customizable Windows desktop widget that displays your Claude.ai usage statistics in real-time with system tray integration.
|
||||||
|
|
||||||

|
**[SCREENSHOT: Main widget showing session and weekly usage]**
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- 🎯 **Real-time Usage Tracking** - Monitor both session and weekly usage limits
|
### Core Features
|
||||||
- 📊 **Visual Progress Bars** - Clean, gradient progress indicators
|
- 🎯 **Real-time Usage Tracking** - Monitor both 5-hour session and 7-day weekly usage limits
|
||||||
- ⏱️ **Countdown Timers** - Circular timers showing time until reset
|
- 📊 **Visual Progress Bars** - Clean, gradient progress indicators with customizable colors
|
||||||
- 🔄 **Auto-refresh** - Updates every 5 minutes automatically
|
- ⏱️ **Countdown Timers** - Circular timers showing time until session/weekly reset
|
||||||
- 🎨 **Modern UI** - Sleek, draggable widget with dark theme
|
- 🔄 **Configurable Auto-refresh** - Adjustable update interval (10-300 seconds)
|
||||||
- 🎨 **Customizable Colors** - Personalize progress bar colors for each usage level
|
- 🎨 **Fully Customizable UI** - Toggle any element on/off, customize all colors and theme
|
||||||
- ⚙️ **Settings Panel** - Easy-to-use settings window for customization
|
|
||||||
- 🔒 **Secure** - Encrypted credential storage
|
|
||||||
- 📍 **Always on Top** - Stays visible across all workspaces
|
- 📍 **Always on Top** - Stays visible across all workspaces
|
||||||
- 💾 **System Tray** - Minimizes to tray for easy access
|
- 🔒 **Secure** - Encrypted credential storage using electron-store
|
||||||
|
|
||||||
|
### System Tray Integration
|
||||||
|
- 💾 **Live Tray Icon** - Real-time usage percentage displayed in system tray
|
||||||
|
- 🎨 **Customizable Tray Colors** - Independent color schemes for tray icon
|
||||||
|
- ⚙️ **Tray Update Interval** - Configurable refresh rate (10-300 seconds)
|
||||||
|
- 📊 **Switchable Metrics** - Display either session or weekly usage in tray
|
||||||
|
- 🔢 **Toggle Percentage Text** - Show/hide percentage number on tray icon
|
||||||
|
|
||||||
|
### Advanced Customization
|
||||||
|
- 🎨 **Theme Editor** - Customize background gradients, text colors, borders, and title bar
|
||||||
|
- 🖼️ **Element Visibility Controls** - Show/hide any UI element independently:
|
||||||
|
- Section labels (Current Session / Weekly Limit)
|
||||||
|
- Progress bars
|
||||||
|
- Percentage text
|
||||||
|
- Countdown circles
|
||||||
|
- Time remaining text
|
||||||
|
- 📏 **Dynamic Resizing** - Window automatically adjusts to fit visible elements
|
||||||
|
- 💎 **Static or Gradient Colors** - Choose between static colors or gradient progressions
|
||||||
|
- 🎯 **Color Coding by Usage** - Different colors for normal (0-74%), warning (75-89%), and danger (90-100%)
|
||||||
|
|
||||||
|
### Application Settings
|
||||||
|
- 🚀 **Start on System Boot** - Automatically launch when Windows starts
|
||||||
|
- 🔽 **Start Minimized** - Begin in system tray without showing window
|
||||||
|
- 📌 **Close to Tray** - Minimize to tray instead of exiting application
|
||||||
|
- 💾 **Persistent Window Position** - Remembers and restores window location
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|
@ -54,71 +77,189 @@ The installer will be created in the `dist/` folder.
|
||||||
### First Launch
|
### First Launch
|
||||||
|
|
||||||
1. Launch the widget
|
1. Launch the widget
|
||||||
2. Click "Login to Claude" when prompted
|
2. The app will attempt to auto-login using stored credentials
|
||||||
3. A browser window will open - login to your Claude.ai account
|
3. If no credentials exist, click "Login to Claude"
|
||||||
4. The widget will automatically capture your session
|
4. A browser window will open - login to your Claude.ai account
|
||||||
5. Usage data will start displaying immediately
|
5. The widget will automatically capture your session
|
||||||
|
6. Usage data will start displaying immediately
|
||||||
|
|
||||||
|
**[SCREENSHOT: Login screen]**
|
||||||
|
|
||||||
### Widget Controls
|
### Widget Controls
|
||||||
|
|
||||||
- **Drag** - Click and drag the title bar to move the widget
|
**Title Bar:**
|
||||||
- **Refresh** - Click the refresh icon to update data immediately
|
- **Drag** - Click and drag anywhere on the title bar to move the widget
|
||||||
- **Minimize** - Click the minus icon to hide to system tray
|
- **Settings Icon** - Open the comprehensive settings panel
|
||||||
- **Close** - Click the X to minimize to tray (doesn't exit)
|
- **Refresh Icon** - Update usage data immediately
|
||||||
|
- **Minimize** - Hide to system tray
|
||||||
|
- **Close** - Minimize to tray or exit (depending on settings)
|
||||||
|
|
||||||
### System Tray Menu
|
**[SCREENSHOT: Widget with controls highlighted]**
|
||||||
|
|
||||||
Right-click the tray icon for:
|
### System Tray
|
||||||
- Show/Hide widget
|
|
||||||
- Refresh usage data
|
**Tray Icon:**
|
||||||
- Re-login (if session expires)
|
- Displays real-time usage percentage
|
||||||
- Settings - Open customization panel
|
- Color changes based on usage level (normal/warning/danger)
|
||||||
- Exit application
|
- Switches between session and weekly usage (configurable in settings)
|
||||||
|
- Updates independently with configurable interval
|
||||||
|
|
||||||
|
**Tray Menu (Right-click):**
|
||||||
|
- **Show/Hide Widget** - Toggle main window visibility
|
||||||
|
- **Refresh Usage** - Update data immediately
|
||||||
|
- **Re-login** - Clear credentials and login again
|
||||||
|
- **Settings** - Open settings panel
|
||||||
|
- **Exit** - Quit application completely
|
||||||
|
|
||||||
|
**[SCREENSHOT: System tray icon and menu]**
|
||||||
|
|
||||||
|
## Settings
|
||||||
|
|
||||||
|
Access settings by clicking the gear icon on the widget or via the system tray menu.
|
||||||
|
|
||||||
|
### Main Window Settings
|
||||||
|
|
||||||
|
#### Colors
|
||||||
|
Customize progress bar colors with gradient or static options:
|
||||||
|
|
||||||
|
**Static Color Mode:**
|
||||||
|
- Enable "Use Static Color" toggle
|
||||||
|
- Choose a single color for the progress bar (ignores usage levels)
|
||||||
|
|
||||||
|
**Gradient Mode (Default):**
|
||||||
|
- **Normal** (0-74% usage) - Default: Purple gradient (#8b5cf6 → #a78bfa)
|
||||||
|
- **Warning** (75-89% usage) - Default: Orange gradient (#f59e0b → #fbbf24)
|
||||||
|
- **Danger** (90-100% usage) - Default: Red gradient (#ef4444 → #f87171)
|
||||||
|
|
||||||
|
Each level has independent start and end colors for smooth gradients.
|
||||||
|
|
||||||
|
**[SCREENSHOT: Color customization panel]**
|
||||||
|
|
||||||
|
#### Theme
|
||||||
|
Customize the entire widget appearance:
|
||||||
|
- **Background Gradient** - Start and end colors
|
||||||
|
- **Text Colors** - Primary and secondary text
|
||||||
|
- **Title Bar** - Background color and opacity (0-100%)
|
||||||
|
- **Borders** - Border color and opacity (0-100%)
|
||||||
|
|
||||||
|
**[SCREENSHOT: Theme customization panel]**
|
||||||
|
|
||||||
|
#### Update Interval
|
||||||
|
- Range: 10-300 seconds (default: 30 seconds)
|
||||||
|
- Controls how often the main widget refreshes usage data
|
||||||
|
- Lower values = more current data, higher API usage
|
||||||
|
- Slider with real-time value display
|
||||||
|
|
||||||
|
#### Current Session Elements
|
||||||
|
Control visibility of each element in the Current Session section:
|
||||||
|
- **Show Current Session** - Master toggle for entire section
|
||||||
|
- **Show Label Text** - "CURRENT SESSION" label
|
||||||
|
- **Show Progress Bar** - Usage progress bar
|
||||||
|
- **Show Percentage Text** - Usage percentage number
|
||||||
|
- **Show Countdown Circle** - Circular timer graphic
|
||||||
|
- **Show Time Text** - Time remaining until reset
|
||||||
|
|
||||||
|
**[SCREENSHOT: Element visibility controls]**
|
||||||
|
|
||||||
|
#### Weekly Limit Elements
|
||||||
|
Identical controls for the Weekly Limit section:
|
||||||
|
- Master toggle to show/hide entire section
|
||||||
|
- Individual toggles for label, bar, percentage, circle, and time
|
||||||
|
|
||||||
|
**Example Configurations:**
|
||||||
|
- Minimal: Just progress bars (hide everything else)
|
||||||
|
- Data-rich: All elements visible (default)
|
||||||
|
- Custom: Any combination you prefer
|
||||||
|
|
||||||
|
### Tray Icon Settings
|
||||||
|
|
||||||
|
#### Display Mode
|
||||||
|
Choose which metric to display in the system tray:
|
||||||
|
- **Session Usage** (5-hour limit)
|
||||||
|
- **Weekly Usage** (7-day limit)
|
||||||
|
|
||||||
|
#### Update Interval
|
||||||
|
- Range: 10-300 seconds (default: 30 seconds)
|
||||||
|
- Independent from main widget update interval
|
||||||
|
- Tray icon updates on its own schedule
|
||||||
|
|
||||||
|
#### Show Percentage Text
|
||||||
|
- Toggle percentage number on/off in tray icon
|
||||||
|
- When disabled, shows only the colored ring
|
||||||
|
|
||||||
|
#### Colors
|
||||||
|
Separate color customization for tray icon:
|
||||||
|
- Static or gradient mode (same as main widget)
|
||||||
|
- Independent color schemes
|
||||||
|
- Normal/Warning/Danger levels
|
||||||
|
|
||||||
|
**[SCREENSHOT: Tray icon settings]**
|
||||||
|
|
||||||
|
### Application Settings
|
||||||
|
|
||||||
|
#### Start on System Boot
|
||||||
|
- Automatically launch widget when Windows starts
|
||||||
|
- Registers with Windows startup items
|
||||||
|
- Disable to manually start the widget
|
||||||
|
|
||||||
|
#### Start Minimized
|
||||||
|
- Launch hidden in system tray
|
||||||
|
- Widget won't show window on startup
|
||||||
|
- Access via tray icon
|
||||||
|
|
||||||
|
#### Close to Tray
|
||||||
|
- When enabled: Clicking X minimizes to tray
|
||||||
|
- When disabled: Clicking X exits application
|
||||||
|
- Minimize button always goes to tray
|
||||||
|
|
||||||
|
**[SCREENSHOT: Application settings]**
|
||||||
|
|
||||||
|
### Account
|
||||||
|
|
||||||
|
**Log Out** - Clears stored credentials and returns to login screen
|
||||||
|
|
||||||
## Understanding the Display
|
## Understanding the Display
|
||||||
|
|
||||||
### Current Session
|
### Current Session (5-Hour Limit)
|
||||||
- **Progress Bar** - Shows usage from 0-100%
|
- **Progress Bar** - Visual representation of usage (0-100%)
|
||||||
- **Timer** - Time remaining until 5-hour session resets
|
- **Percentage** - Exact usage percentage
|
||||||
|
- **Countdown Circle** - Circular timer showing progress toward reset
|
||||||
|
- **Time Remaining** - Hours and minutes until session resets (e.g., "2h 34m")
|
||||||
- **Color Coding**:
|
- **Color Coding**:
|
||||||
- Purple: Normal usage (0-74%)
|
- Purple: Normal usage (0-74%)
|
||||||
- Orange: High usage (75-89%)
|
- Orange: High usage (75-89%)
|
||||||
- Red: Critical usage (90-100%)
|
- Red: Critical usage (90-100%)
|
||||||
|
|
||||||
### Weekly Limit
|
### Weekly Limit (7-Day Rolling Window)
|
||||||
- **Progress Bar** - Shows weekly usage from 0-100%
|
- **Progress Bar** - Weekly usage from 0-100%
|
||||||
- **Timer** - Time remaining until weekly reset (Wednesdays 7:00 AM)
|
- **Percentage** - Exact weekly usage percentage
|
||||||
- **Same color coding** as session usage
|
- **Countdown Circle** - Progress toward weekly reset
|
||||||
|
- **Time Remaining** - Days/hours until weekly reset (e.g., "3d 5h")
|
||||||
|
- Same color coding as session usage
|
||||||
|
|
||||||
## Customization
|
**[SCREENSHOT: Usage display explanation with labels]**
|
||||||
|
|
||||||
### Color Preferences
|
## Window Behavior
|
||||||
|
|
||||||
Customize the progress bar colors to match your preferences:
|
### Dynamic Resizing
|
||||||
|
- Window automatically resizes based on visible elements
|
||||||
|
- Shows only what you've enabled in settings
|
||||||
|
- Maintains minimum size for readability
|
||||||
|
- Cannot be manually resized smaller than content
|
||||||
|
|
||||||
1. Right-click the system tray icon
|
### Manual Resizing
|
||||||
2. Select "Settings"
|
- Drag edges to resize window
|
||||||
3. Use the color pickers to customize each usage level:
|
- Constraints: 320-600px width, 96-180px height
|
||||||
- **Normal** (0-74% usage) - Default: Purple gradient
|
- Content stays centered at all sizes
|
||||||
- **Warning** (75-89% usage) - Default: Orange gradient
|
|
||||||
- **Danger** (90-100% usage) - Default: Red gradient
|
|
||||||
4. Changes apply instantly to the main widget
|
|
||||||
5. Click "Reset to Defaults" to restore original colors
|
|
||||||
|
|
||||||

|
### Position Persistence
|
||||||
|
- Window position saved automatically when moved
|
||||||
|
- Restored on next launch
|
||||||
|
- Per-display awareness
|
||||||
|
|
||||||
### Auto-start on Windows Boot
|
## Keyboard Shortcuts
|
||||||
|
|
||||||
1. Press `Win + R`
|
Currently, the widget does not have keyboard shortcuts. This may be added in a future version.
|
||||||
2. Type `shell:startup` and press Enter
|
|
||||||
3. Create a shortcut to the widget executable in this folder
|
|
||||||
|
|
||||||
### Custom Refresh Interval
|
|
||||||
|
|
||||||
Edit `src/renderer/app.js`:
|
|
||||||
```javascript
|
|
||||||
const UPDATE_INTERVAL = 5 * 60 * 1000; // Change to your preference (in milliseconds)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|
@ -126,16 +267,31 @@ const UPDATE_INTERVAL = 5 * 60 * 1000; // Change to your preference (in millisec
|
||||||
- Your Claude.ai session may have expired
|
- Your Claude.ai session may have expired
|
||||||
- Click "Login to Claude" to re-authenticate
|
- Click "Login to Claude" to re-authenticate
|
||||||
- Check that you're logging into the correct account
|
- Check that you're logging into the correct account
|
||||||
|
- Verify Claude.ai is accessible in your region
|
||||||
|
|
||||||
### Widget not updating
|
### Widget not updating
|
||||||
- Check your internet connection
|
- Check your internet connection
|
||||||
- Click the refresh button manually
|
- Click the refresh button manually
|
||||||
- Ensure Claude.ai is accessible in your region
|
- Ensure Claude.ai API is accessible
|
||||||
- Try re-logging in from the system tray menu
|
- Try increasing update interval if experiencing rate limits
|
||||||
|
- Re-login from system tray menu
|
||||||
|
|
||||||
### Widget position not saving
|
### Tray icon not showing/updating
|
||||||
- Window position is now saved automatically when you drag it
|
- Check that "Show Percentage Text" is enabled to see text
|
||||||
- Position will be restored when you restart the app
|
- Verify update interval isn't too long
|
||||||
|
- Try changing display mode (session ↔ weekly)
|
||||||
|
- Restart the application
|
||||||
|
|
||||||
|
### Window too small/elements cut off
|
||||||
|
- Check element visibility settings
|
||||||
|
- Enable more elements to expand window
|
||||||
|
- Window automatically sizes to fit enabled elements
|
||||||
|
- Reset to defaults if layout seems broken
|
||||||
|
|
||||||
|
### Auto-start not working
|
||||||
|
- Verify "Start on System Boot" is enabled in settings
|
||||||
|
- Check Windows Task Manager > Startup tab
|
||||||
|
- May require administrator rights on some systems
|
||||||
|
|
||||||
### Build errors
|
### Build errors
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -146,10 +302,11 @@ npm install
|
||||||
|
|
||||||
## Privacy & Security
|
## Privacy & Security
|
||||||
|
|
||||||
- Your session credentials are stored **locally only** using encrypted storage
|
- **Local Storage Only** - Your session credentials are stored locally using encrypted electron-store
|
||||||
- No data is sent to any third-party servers
|
- **No Third-Party Servers** - No data is sent to any servers except Claude.ai official API
|
||||||
- The widget only communicates with Claude.ai official API
|
- **Official API Only** - Widget only communicates with Claude.ai API endpoints
|
||||||
- Session cookies are stored using Electron's secure storage
|
- **Secure Cookies** - Session cookies stored using Electron's secure storage
|
||||||
|
- **Open Source** - All code is publicly available for audit
|
||||||
|
|
||||||
## Technical Details
|
## Technical Details
|
||||||
|
|
||||||
|
|
@ -157,11 +314,14 @@ npm install
|
||||||
- Electron 28.0.0
|
- Electron 28.0.0
|
||||||
- Pure JavaScript (no framework overhead)
|
- Pure JavaScript (no framework overhead)
|
||||||
- Native Node.js APIs
|
- Native Node.js APIs
|
||||||
- electron-store for secure storage
|
- electron-store for encrypted secure storage
|
||||||
|
- axios for HTTP requests
|
||||||
|
- Canvas API for tray icon generation
|
||||||
|
|
||||||
**API Endpoint:**
|
**API Endpoints:**
|
||||||
```
|
```
|
||||||
https://claude.ai/api/organizations/{org_id}/usage
|
https://claude.ai/api/organizations/{org_id}/usage
|
||||||
|
https://claude.ai/api/organizations
|
||||||
```
|
```
|
||||||
|
|
||||||
**Storage Location:**
|
**Storage Location:**
|
||||||
|
|
@ -169,37 +329,152 @@ https://claude.ai/api/organizations/{org_id}/usage
|
||||||
%APPDATA%/claude-usage-widget/config.json (encrypted)
|
%APPDATA%/claude-usage-widget/config.json (encrypted)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Configuration Keys:**
|
||||||
|
- `sessionKey` - Encrypted Claude.ai session token
|
||||||
|
- `organizationId` - Your Claude organization UUID
|
||||||
|
- `colorPreferences` - Custom color settings
|
||||||
|
- `traySettings` - Tray icon configuration
|
||||||
|
- `themeSettings` - Widget theme preferences
|
||||||
|
- `appSettings` - Application behavior settings
|
||||||
|
- `uiVisibility` - Element visibility toggles
|
||||||
|
- `windowPosition` - Saved window location
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
claude-usage-widget/
|
||||||
|
├── main.js # Electron main process
|
||||||
|
├── preload.js # IPC bridge (security)
|
||||||
|
├── package.json # Dependencies and scripts
|
||||||
|
├── assets/
|
||||||
|
│ ├── icon.ico # Application icon
|
||||||
|
│ └── logo.png # Widget logo
|
||||||
|
└── src/
|
||||||
|
└── renderer/
|
||||||
|
├── index.html # Main widget UI
|
||||||
|
├── app.js # Widget logic
|
||||||
|
├── styles.css # Widget styles
|
||||||
|
├── settings.html # Settings panel UI
|
||||||
|
├── settings.js # Settings logic
|
||||||
|
└── settings-styles.css # Settings styles
|
||||||
|
```
|
||||||
|
|
||||||
|
## Version History
|
||||||
|
|
||||||
|
### v1.4.2 (Current)
|
||||||
|
- ✨ Added comprehensive UI element visibility controls
|
||||||
|
- ✨ Added system tray icon with live usage display
|
||||||
|
- ✨ Added customizable tray icon colors and update interval
|
||||||
|
- ✨ Added application settings (start on boot, start minimized, close to tray)
|
||||||
|
- ✨ Added theme customization (backgrounds, text colors, borders, opacity)
|
||||||
|
- ✨ Added configurable update intervals for UI and tray
|
||||||
|
- ✨ Added static color mode for progress bars
|
||||||
|
- ✨ Added dynamic window resizing based on visible elements
|
||||||
|
- 🎨 Improved settings organization with collapsible sections
|
||||||
|
- 🎨 Consistent typography and spacing throughout settings
|
||||||
|
- 🐛 Fixed element centering and responsive layout
|
||||||
|
- 🐛 Fixed timer container visibility handling
|
||||||
|
|
||||||
|
### v1.4.1
|
||||||
|
- Added color customization
|
||||||
|
- Added settings panel
|
||||||
|
- Improved window position persistence
|
||||||
|
|
||||||
|
### v1.4.0
|
||||||
|
- Added custom color themes
|
||||||
|
- Added settings window
|
||||||
|
- Remember window position
|
||||||
|
|
||||||
|
### v1.3.0
|
||||||
|
- Initial public release
|
||||||
|
- Real-time usage tracking
|
||||||
|
- System tray support
|
||||||
|
- Auto-refresh functionality
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
|
### Planned Features
|
||||||
- [ ] macOS support
|
- [ ] macOS support
|
||||||
- [ ] Linux support
|
- [ ] Linux support
|
||||||
- [x] Custom color themes
|
|
||||||
- [ ] Notification alerts at usage thresholds
|
- [ ] Notification alerts at usage thresholds
|
||||||
- [x] Remember window position
|
|
||||||
- [x] Settings panel
|
|
||||||
- [ ] Usage history graphs
|
- [ ] Usage history graphs
|
||||||
|
- [ ] Export usage data (CSV/JSON)
|
||||||
- [ ] Multiple account support
|
- [ ] Multiple account support
|
||||||
- [ ] Keyboard shortcuts
|
- [ ] Keyboard shortcuts
|
||||||
|
- [ ] Mini mode (ultra-compact view)
|
||||||
|
- [ ] Desktop widget mode (frameless, always-on-desktop)
|
||||||
|
- [ ] Custom notification sounds
|
||||||
|
|
||||||
|
### Completed
|
||||||
|
- [x] Custom color themes
|
||||||
|
- [x] Remember window position
|
||||||
|
- [x] Settings panel
|
||||||
|
- [x] System tray integration
|
||||||
|
- [x] Tray icon with live usage
|
||||||
|
- [x] Element visibility controls
|
||||||
|
- [x] Theme customization
|
||||||
|
- [x] Configurable update intervals
|
||||||
|
- [x] Auto-start on boot
|
||||||
|
- [x] Static color mode
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Contributions are welcome! Please feel free to submit a Pull Request.
|
Contributions are welcome! Here's how you can help:
|
||||||
|
|
||||||
|
1. **Fork the repository**
|
||||||
|
2. **Create a feature branch** (`git checkout -b feature/amazing-feature`)
|
||||||
|
3. **Commit your changes** (`git commit -m 'Add some amazing feature'`)
|
||||||
|
4. **Push to the branch** (`git push origin feature/amazing-feature`)
|
||||||
|
5. **Open a Pull Request**
|
||||||
|
|
||||||
|
### Development Guidelines
|
||||||
|
- Follow existing code style
|
||||||
|
- Test thoroughly before submitting PR
|
||||||
|
- Update README if adding features
|
||||||
|
- Add comments for complex logic
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT License - feel free to use and modify as needed.
|
MIT License - feel free to use, modify, and distribute as needed.
|
||||||
|
|
||||||
|
See [LICENSE](LICENSE) file for full details.
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
|
|
||||||
This is an unofficial tool and is not affiliated with or endorsed by Anthropic. Use at your own discretion.
|
**This is an unofficial tool and is not affiliated with, endorsed by, or connected to Anthropic or Claude.ai in any way.**
|
||||||
|
|
||||||
|
- Use at your own risk and discretion
|
||||||
|
- No warranties or guarantees provided
|
||||||
|
- Not responsible for any issues arising from use
|
||||||
|
- May break if Claude.ai changes their API
|
||||||
|
- Respect Anthropic's Terms of Service
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
If you encounter issues:
|
If you encounter issues:
|
||||||
1. Check the [Issues](issues) page
|
|
||||||
2. Create a new issue with details about your problem
|
1. **Check existing issues** - [Issues page](../../issues)
|
||||||
3. Include your OS version and any error messages
|
2. **Create a new issue** with:
|
||||||
|
- Your Windows version
|
||||||
|
- Widget version
|
||||||
|
- Steps to reproduce
|
||||||
|
- Error messages (if any)
|
||||||
|
- Screenshots (if relevant)
|
||||||
|
|
||||||
|
**Before reporting:**
|
||||||
|
- Try restarting the widget
|
||||||
|
- Try re-logging in
|
||||||
|
- Check if Claude.ai is accessible in browser
|
||||||
|
- Verify you have the latest version
|
||||||
|
|
||||||
|
## Acknowledgments
|
||||||
|
|
||||||
|
- Built for the Claude.ai community
|
||||||
|
- Inspired by the need for easy usage monitoring
|
||||||
|
- Thanks to all contributors and users
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Made with ❤️ for the Claude.ai community
|
**Made with ❤️ for the Claude.ai community**
|
||||||
|
|
||||||
|
**Star ⭐ this repo if you find it useful!**
|
||||||
|
|
|
||||||
95
main.js
95
main.js
|
|
@ -31,10 +31,14 @@ function createMainWindow() {
|
||||||
const windowOptions = {
|
const windowOptions = {
|
||||||
width: WIDGET_WIDTH,
|
width: WIDGET_WIDTH,
|
||||||
height: WIDGET_HEIGHT,
|
height: WIDGET_HEIGHT,
|
||||||
|
minWidth: 320,
|
||||||
|
maxWidth: 600,
|
||||||
|
minHeight: 96,
|
||||||
|
maxHeight: 180,
|
||||||
frame: false,
|
frame: false,
|
||||||
transparent: true,
|
transparent: true,
|
||||||
alwaysOnTop: true,
|
alwaysOnTop: true,
|
||||||
resizable: false,
|
resizable: true,
|
||||||
skipTaskbar: false,
|
skipTaskbar: false,
|
||||||
icon: path.join(__dirname, 'assets/icon.ico'),
|
icon: path.join(__dirname, 'assets/icon.ico'),
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
|
|
@ -579,7 +583,12 @@ ipcMain.on('minimize-window', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('close-window', () => {
|
ipcMain.on('close-window', () => {
|
||||||
|
const appSettings = store.get('appSettings', { closeToTray: false });
|
||||||
|
if (appSettings.closeToTray) {
|
||||||
|
mainWindow.hide();
|
||||||
|
} else {
|
||||||
app.quit();
|
app.quit();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('get-window-position', () => {
|
ipcMain.handle('get-window-position', () => {
|
||||||
|
|
@ -597,6 +606,19 @@ ipcMain.handle('set-window-position', (event, { x, y }) => {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.on('set-window-height', (event, height) => {
|
||||||
|
if (mainWindow) {
|
||||||
|
const currentBounds = mainWindow.getBounds();
|
||||||
|
mainWindow.setSize(currentBounds.width, Math.round(height));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('set-window-size', (event, { width, height }) => {
|
||||||
|
if (mainWindow) {
|
||||||
|
mainWindow.setSize(Math.round(width), Math.round(height));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ipcMain.on('open-external', (event, url) => {
|
ipcMain.on('open-external', (event, url) => {
|
||||||
shell.openExternal(url);
|
shell.openExternal(url);
|
||||||
});
|
});
|
||||||
|
|
@ -735,13 +757,84 @@ ipcMain.handle('notify-theme-change', (event, theme) => {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// App settings
|
||||||
|
ipcMain.handle('get-app-settings', () => {
|
||||||
|
return store.get('appSettings', {
|
||||||
|
startOnBoot: false,
|
||||||
|
startMinimized: false,
|
||||||
|
closeToTray: false,
|
||||||
|
uiUpdateInterval: 30 // 30 seconds
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('set-app-settings', (event, settings) => {
|
||||||
|
const currentSettings = store.get('appSettings', {});
|
||||||
|
const newSettings = { ...currentSettings, ...settings };
|
||||||
|
store.set('appSettings', newSettings);
|
||||||
|
|
||||||
|
// Apply auto-launch setting
|
||||||
|
if (settings.hasOwnProperty('startOnBoot')) {
|
||||||
|
app.setLoginItemSettings({
|
||||||
|
openAtLogin: settings.startOnBoot,
|
||||||
|
path: process.execPath
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// UI visibility settings
|
||||||
|
ipcMain.handle('get-ui-visibility', () => {
|
||||||
|
return store.get('uiVisibility', {
|
||||||
|
showSessionSection: true,
|
||||||
|
showWeeklySection: true,
|
||||||
|
sessionShowLabel: true,
|
||||||
|
sessionShowBar: true,
|
||||||
|
sessionShowPercentage: true,
|
||||||
|
sessionShowCircle: true,
|
||||||
|
sessionShowTime: true,
|
||||||
|
weeklyShowLabel: true,
|
||||||
|
weeklyShowBar: true,
|
||||||
|
weeklyShowPercentage: true,
|
||||||
|
weeklyShowCircle: true,
|
||||||
|
weeklyShowTime: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('set-ui-visibility', (event, visibility) => {
|
||||||
|
store.set('uiVisibility', visibility);
|
||||||
|
// Notify main window to update visibility
|
||||||
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||||
|
mainWindow.webContents.send('ui-visibility-changed', visibility);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
// App lifecycle
|
// App lifecycle
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
|
// Apply startup settings
|
||||||
|
const appSettings = store.get('appSettings', {
|
||||||
|
startOnBoot: false,
|
||||||
|
startMinimized: false,
|
||||||
|
closeToTray: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set auto-launch
|
||||||
|
app.setLoginItemSettings({
|
||||||
|
openAtLogin: appSettings.startOnBoot,
|
||||||
|
path: process.execPath
|
||||||
|
});
|
||||||
|
|
||||||
createMainWindow();
|
createMainWindow();
|
||||||
createTray();
|
createTray();
|
||||||
createIconGeneratorWindow();
|
createIconGeneratorWindow();
|
||||||
startTrayUpdateTimer();
|
startTrayUpdateTimer();
|
||||||
|
|
||||||
|
// Start minimized if enabled
|
||||||
|
if (appSettings.startMinimized) {
|
||||||
|
mainWindow.hide();
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we have credentials
|
// Check if we have credentials
|
||||||
// const hasCredentials = store.get('sessionKey') && store.get('organizationId');
|
// const hasCredentials = store.get('sessionKey') && store.get('organizationId');
|
||||||
// if (!hasCredentials) {
|
// if (!hasCredentials) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "claude-usage-widget",
|
"name": "claude-usage-widget",
|
||||||
"version": "1.4.0",
|
"version": "1.4.2",
|
||||||
"description": "Desktop widget for Claude.ai usage monitoring",
|
"description": "Desktop widget for Claude.ai usage monitoring",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
13
preload.js
13
preload.js
|
|
@ -17,6 +17,8 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||||
// Window position
|
// Window position
|
||||||
getWindowPosition: () => ipcRenderer.invoke('get-window-position'),
|
getWindowPosition: () => ipcRenderer.invoke('get-window-position'),
|
||||||
setWindowPosition: (position) => ipcRenderer.invoke('set-window-position', position),
|
setWindowPosition: (position) => ipcRenderer.invoke('set-window-position', position),
|
||||||
|
setWindowHeight: (height) => ipcRenderer.send('set-window-height', height),
|
||||||
|
setWindowSize: (size) => ipcRenderer.send('set-window-size', size),
|
||||||
|
|
||||||
// Event listeners
|
// Event listeners
|
||||||
onLoginSuccess: (callback) => {
|
onLoginSuccess: (callback) => {
|
||||||
|
|
@ -60,5 +62,16 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||||
notifyThemeChange: (theme) => ipcRenderer.invoke('notify-theme-change', theme),
|
notifyThemeChange: (theme) => ipcRenderer.invoke('notify-theme-change', theme),
|
||||||
onThemeChanged: (callback) => {
|
onThemeChanged: (callback) => {
|
||||||
ipcRenderer.on('theme-changed', (event, theme) => callback(theme));
|
ipcRenderer.on('theme-changed', (event, theme) => callback(theme));
|
||||||
|
},
|
||||||
|
|
||||||
|
// App settings
|
||||||
|
getAppSettings: () => ipcRenderer.invoke('get-app-settings'),
|
||||||
|
setAppSettings: (settings) => ipcRenderer.invoke('set-app-settings', settings),
|
||||||
|
|
||||||
|
// UI visibility settings
|
||||||
|
getUIVisibility: () => ipcRenderer.invoke('get-ui-visibility'),
|
||||||
|
setUIVisibility: (visibility) => ipcRenderer.invoke('set-ui-visibility', visibility),
|
||||||
|
onUIVisibilityChanged: (callback) => {
|
||||||
|
ipcRenderer.on('ui-visibility-changed', (event, visibility) => callback(visibility));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,10 @@ async function init() {
|
||||||
const themeSettings = await window.electronAPI.getThemeSettings();
|
const themeSettings = await window.electronAPI.getThemeSettings();
|
||||||
applyThemePreferences(themeSettings);
|
applyThemePreferences(themeSettings);
|
||||||
|
|
||||||
|
// Load and apply UI visibility settings
|
||||||
|
const uiVisibility = await window.electronAPI.getUIVisibility();
|
||||||
|
applyUIVisibility(uiVisibility);
|
||||||
|
|
||||||
if (credentials.sessionKey && credentials.organizationId) {
|
if (credentials.sessionKey && credentials.organizationId) {
|
||||||
showMainContent();
|
showMainContent();
|
||||||
await fetchUsageData();
|
await fetchUsageData();
|
||||||
|
|
@ -124,6 +128,12 @@ function setupEventListeners() {
|
||||||
console.log('Theme changed, applying new theme');
|
console.log('Theme changed, applying new theme');
|
||||||
applyThemePreferences(theme);
|
applyThemePreferences(theme);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Listen for UI visibility changes from settings window
|
||||||
|
window.electronAPI.onUIVisibilityChanged((visibility) => {
|
||||||
|
console.log('UI visibility changed, applying new settings');
|
||||||
|
applyUIVisibility(visibility);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch usage data from Claude API
|
// Fetch usage data from Claude API
|
||||||
|
|
@ -434,12 +444,164 @@ function applyThemePreferences(theme) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UI visibility management
|
||||||
|
function applyUIVisibility(visibility) {
|
||||||
|
const usageSections = document.querySelectorAll('.usage-section');
|
||||||
|
if (usageSections.length < 2) return;
|
||||||
|
|
||||||
|
const sessionSection = usageSections[0];
|
||||||
|
const weeklySection = usageSections[1];
|
||||||
|
|
||||||
|
// Default to true if not explicitly set to false
|
||||||
|
const showSessionSection = visibility.showSessionSection !== false;
|
||||||
|
const showWeeklySection = visibility.showWeeklySection !== false;
|
||||||
|
const sessionShowLabel = visibility.sessionShowLabel !== false;
|
||||||
|
const sessionShowBar = visibility.sessionShowBar !== false;
|
||||||
|
const sessionShowPercentage = visibility.sessionShowPercentage !== false;
|
||||||
|
const sessionShowCircle = visibility.sessionShowCircle !== false;
|
||||||
|
const sessionShowTime = visibility.sessionShowTime !== false;
|
||||||
|
const weeklyShowLabel = visibility.weeklyShowLabel !== false;
|
||||||
|
const weeklyShowBar = visibility.weeklyShowBar !== false;
|
||||||
|
const weeklyShowPercentage = visibility.weeklyShowPercentage !== false;
|
||||||
|
const weeklyShowCircle = visibility.weeklyShowCircle !== false;
|
||||||
|
const weeklyShowTime = visibility.weeklyShowTime !== false;
|
||||||
|
|
||||||
|
// Session elements
|
||||||
|
const sessionLabel = sessionSection.querySelector('.usage-label');
|
||||||
|
const sessionBar = sessionSection.querySelector('.progress-bar');
|
||||||
|
const sessionPercentage = sessionSection.querySelector('.usage-percentage');
|
||||||
|
const sessionTimerContainer = sessionSection.querySelector('.timer-container');
|
||||||
|
const sessionTimerSVG = sessionSection.querySelector('.mini-timer');
|
||||||
|
const sessionTimeText = sessionSection.querySelector('.timer-text');
|
||||||
|
|
||||||
|
if (sessionLabel) sessionLabel.style.display = sessionShowLabel ? 'block' : 'none';
|
||||||
|
if (sessionBar) sessionBar.style.display = sessionShowBar ? 'block' : 'none';
|
||||||
|
if (sessionPercentage) sessionPercentage.style.display = sessionShowPercentage ? 'block' : 'none';
|
||||||
|
if (sessionTimerSVG) sessionTimerSVG.style.display = sessionShowCircle ? 'block' : 'none';
|
||||||
|
if (sessionTimeText) sessionTimeText.style.display = sessionShowTime ? 'block' : 'none';
|
||||||
|
|
||||||
|
// Hide timer container if both circle and time are hidden
|
||||||
|
if (sessionTimerContainer) {
|
||||||
|
sessionTimerContainer.style.display = (sessionShowCircle || sessionShowTime) ? 'flex' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Weekly elements
|
||||||
|
const weeklyLabel = weeklySection.querySelector('.usage-label');
|
||||||
|
const weeklyBar = weeklySection.querySelector('.progress-bar');
|
||||||
|
const weeklyPercentage = weeklySection.querySelector('.usage-percentage');
|
||||||
|
const weeklyTimerContainer = weeklySection.querySelector('.timer-container');
|
||||||
|
const weeklyTimerSVG = weeklySection.querySelector('.mini-timer');
|
||||||
|
const weeklyTimeText = weeklySection.querySelector('.timer-text');
|
||||||
|
|
||||||
|
if (weeklyLabel) weeklyLabel.style.display = weeklyShowLabel ? 'block' : 'none';
|
||||||
|
if (weeklyBar) weeklyBar.style.display = weeklyShowBar ? 'block' : 'none';
|
||||||
|
if (weeklyPercentage) weeklyPercentage.style.display = weeklyShowPercentage ? 'block' : 'none';
|
||||||
|
if (weeklyTimerSVG) weeklyTimerSVG.style.display = weeklyShowCircle ? 'block' : 'none';
|
||||||
|
if (weeklyTimeText) weeklyTimeText.style.display = weeklyShowTime ? 'block' : 'none';
|
||||||
|
|
||||||
|
// Hide timer container if both circle and time are hidden
|
||||||
|
if (weeklyTimerContainer) {
|
||||||
|
weeklyTimerContainer.style.display = (weeklyShowCircle || weeklyShowTime) ? 'flex' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show/hide entire sections
|
||||||
|
if (sessionSection) sessionSection.style.display = showSessionSection ? 'flex' : 'none';
|
||||||
|
if (weeklySection) weeklySection.style.display = showWeeklySection ? 'flex' : 'none';
|
||||||
|
|
||||||
|
// Adjust window height based on visible content
|
||||||
|
adjustWindowHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust window size based on visible content
|
||||||
|
function adjustWindowHeight() {
|
||||||
|
const usageSections = document.querySelectorAll('.usage-section');
|
||||||
|
let visibleSections = 0;
|
||||||
|
let maxWidthNeeded = 0;
|
||||||
|
|
||||||
|
usageSections.forEach(section => {
|
||||||
|
if (section.style.display !== 'none') {
|
||||||
|
visibleSections++;
|
||||||
|
|
||||||
|
// Calculate width needed for this section
|
||||||
|
let sectionWidth = 60; // Base padding (30px left + 30px right for safety)
|
||||||
|
|
||||||
|
// Check what's visible in this section
|
||||||
|
const label = section.querySelector('.usage-label');
|
||||||
|
const bar = section.querySelector('.progress-bar');
|
||||||
|
const percentage = section.querySelector('.usage-percentage');
|
||||||
|
const timerContainer = section.querySelector('.timer-container');
|
||||||
|
|
||||||
|
// Count visible elements and calculate width
|
||||||
|
let visibleElements = 0;
|
||||||
|
|
||||||
|
if (label && label.style.display !== 'none') {
|
||||||
|
sectionWidth += 120; // Label width + buffer
|
||||||
|
visibleElements++;
|
||||||
|
}
|
||||||
|
if (bar && bar.style.display !== 'none') {
|
||||||
|
sectionWidth += 150; // Minimum readable bar width
|
||||||
|
visibleElements++;
|
||||||
|
}
|
||||||
|
if (percentage && percentage.style.display !== 'none') {
|
||||||
|
sectionWidth += 55; // Percentage width
|
||||||
|
visibleElements++;
|
||||||
|
}
|
||||||
|
if (timerContainer) {
|
||||||
|
const timerSVG = timerContainer.querySelector('.mini-timer');
|
||||||
|
const timeText = timerContainer.querySelector('.timer-text');
|
||||||
|
if ((timerSVG && timerSVG.style.display !== 'none') ||
|
||||||
|
(timeText && timeText.style.display !== 'none')) {
|
||||||
|
sectionWidth += 100; // Timer container width
|
||||||
|
visibleElements++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add gaps between elements (16px each)
|
||||||
|
if (visibleElements > 1) {
|
||||||
|
sectionWidth += (visibleElements - 1) * 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure minimum width even if only one element visible
|
||||||
|
sectionWidth = Math.max(sectionWidth, 200);
|
||||||
|
|
||||||
|
maxWidthNeeded = Math.max(maxWidthNeeded, sectionWidth);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Calculate height: title bar (36px) + padding + sections
|
||||||
|
const titleBarHeight = 36;
|
||||||
|
const contentPadding = 40; // 20px top + 20px bottom
|
||||||
|
const sectionHeight = 40;
|
||||||
|
const newHeight = titleBarHeight + contentPadding + (visibleSections * sectionHeight);
|
||||||
|
|
||||||
|
// Title bar needs space for "Claude Usage" + buttons
|
||||||
|
// Minimum: logo (19px) + gap (8px) + text (~110px) + buttons (4 * 28px + 3 * 8px gaps) = ~280px
|
||||||
|
const minTitleBarWidth = 300;
|
||||||
|
|
||||||
|
// Ensure we have content width or use minimum
|
||||||
|
const contentWidth = Math.max(maxWidthNeeded, 200);
|
||||||
|
|
||||||
|
// Final dimensions - use the larger of content width or title bar width
|
||||||
|
const finalWidth = Math.max(contentWidth, minTitleBarWidth);
|
||||||
|
const finalHeight = Math.max(newHeight, titleBarHeight + 60);
|
||||||
|
|
||||||
|
// Clamp to window constraints
|
||||||
|
const clampedWidth = Math.min(Math.max(finalWidth, 320), 600);
|
||||||
|
const clampedHeight = Math.min(Math.max(finalHeight, 96), 180);
|
||||||
|
|
||||||
|
window.electronAPI.setWindowSize({ width: clampedWidth, height: clampedHeight });
|
||||||
|
}
|
||||||
|
|
||||||
// Auto-update management
|
// Auto-update management
|
||||||
function startAutoUpdate() {
|
async function startAutoUpdate() {
|
||||||
stopAutoUpdate();
|
stopAutoUpdate();
|
||||||
|
// Load update interval from settings
|
||||||
|
const appSettings = await window.electronAPI.getAppSettings();
|
||||||
|
const intervalMs = (appSettings.uiUpdateInterval || 300) * 1000; // Convert to milliseconds
|
||||||
|
|
||||||
updateInterval = setInterval(() => {
|
updateInterval = setInterval(() => {
|
||||||
fetchUsageData();
|
fetchUsageData();
|
||||||
}, UPDATE_INTERVAL);
|
}, intervalMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopAutoUpdate() {
|
function stopAutoUpdate() {
|
||||||
|
|
|
||||||
|
|
@ -95,10 +95,11 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-section h2 {
|
.settings-section h2 {
|
||||||
font-size: 16px;
|
font-size: 20px;
|
||||||
font-weight: 600;
|
font-weight: 700;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 20px;
|
||||||
color: #e0e0e0;
|
color: #e0e0e0;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 2-Column Grid for Color Pickers */
|
/* 2-Column Grid for Color Pickers */
|
||||||
|
|
@ -233,7 +234,11 @@ body {
|
||||||
|
|
||||||
/* Setting Groups */
|
/* Setting Groups */
|
||||||
.setting-group {
|
.setting-group {
|
||||||
margin-bottom: 25px;
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-group:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-group h3 {
|
.setting-group h3 {
|
||||||
|
|
@ -308,6 +313,7 @@ body {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
margin-top: 12px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -436,7 +442,17 @@ body {
|
||||||
|
|
||||||
/* Collapsible Sections */
|
/* Collapsible Sections */
|
||||||
.collapsible-section {
|
.collapsible-section {
|
||||||
margin-bottom: 16px;
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsible-section:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add extra space when a setting-group follows a collapsible-section */
|
||||||
|
.collapsible-section + .setting-group {
|
||||||
|
margin-top: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.collapsible-header {
|
.collapsible-header {
|
||||||
|
|
@ -487,6 +503,22 @@ body {
|
||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Setting Item Spacing */
|
||||||
|
.setting-item {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-item:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-item .setting-description {
|
||||||
|
margin: 4px 0 0 60px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: rgba(255, 255, 255, 0.5);
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
/* Theme Grid */
|
/* Theme Grid */
|
||||||
.theme-grid {
|
.theme-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,139 @@
|
||||||
<button class="btn-secondary" id="resetThemeBtn">Reset Theme</button>
|
<button class="btn-secondary" id="resetThemeBtn">Reset Theme</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- UI Update Interval -->
|
||||||
|
<div class="setting-group">
|
||||||
|
<h3>Update Interval</h3>
|
||||||
|
<p class="setting-description">How often to refresh usage data (in seconds)</p>
|
||||||
|
|
||||||
|
<div class="slider-container">
|
||||||
|
<input type="range" id="uiUpdateInterval" min="10" max="300" value="30" step="10">
|
||||||
|
<div class="slider-value">
|
||||||
|
<span id="uiUpdateIntervalValue">30</span> seconds
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Current Session Elements -->
|
||||||
|
<div class="collapsible-section">
|
||||||
|
<button class="collapsible-header" id="sessionElementsHeader">
|
||||||
|
<span>Current Session Elements</span>
|
||||||
|
<svg class="chevron" width="16" height="16" viewBox="0 0 16 16" fill="none">
|
||||||
|
<path d="M4 6L8 10L12 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div class="collapsible-content" id="sessionElementsContent">
|
||||||
|
<div class="setting-item" style="margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid rgba(255, 255, 255, 0.1);">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="showSessionSection" checked>
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
<span class="toggle-label">Show Current Session</span>
|
||||||
|
</label>
|
||||||
|
<p class="setting-description">Hide entire Current Session section</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-item">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="sessionShowLabel" checked>
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
<span class="toggle-label">Show Label Text</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-item">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="sessionShowBar" checked>
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
<span class="toggle-label">Show Progress Bar</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-item">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="sessionShowPercentage" checked>
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
<span class="toggle-label">Show Percentage Text</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-item">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="sessionShowCircle" checked>
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
<span class="toggle-label">Show Countdown Circle</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-item">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="sessionShowTime" checked>
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
<span class="toggle-label">Show Time Text</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Weekly Limit Elements -->
|
||||||
|
<div class="collapsible-section">
|
||||||
|
<button class="collapsible-header" id="weeklyElementsHeader">
|
||||||
|
<span>Weekly Limit Elements</span>
|
||||||
|
<svg class="chevron" width="16" height="16" viewBox="0 0 16 16" fill="none">
|
||||||
|
<path d="M4 6L8 10L12 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div class="collapsible-content" id="weeklyElementsContent">
|
||||||
|
<div class="setting-item" style="margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid rgba(255, 255, 255, 0.1);">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="showWeeklySection" checked>
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
<span class="toggle-label">Show Weekly Limit</span>
|
||||||
|
</label>
|
||||||
|
<p class="setting-description">Hide entire Weekly Limit section</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-item">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="weeklyShowLabel" checked>
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
<span class="toggle-label">Show Label Text</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-item">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="weeklyShowBar" checked>
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
<span class="toggle-label">Show Progress Bar</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-item">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="weeklyShowPercentage" checked>
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
<span class="toggle-label">Show Percentage Text</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-item">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="weeklyShowCircle" checked>
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
<span class="toggle-label">Show Countdown Circle</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-item">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="weeklyShowTime" checked>
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
<span class="toggle-label">Show Time Text</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
|
@ -282,26 +415,49 @@
|
||||||
|
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
|
|
||||||
<!-- Support -->
|
<!-- Application Settings -->
|
||||||
<section class="settings-section">
|
<section class="settings-section">
|
||||||
<button class="btn-coffee" id="coffeeBtn">
|
<h2>Application</h2>
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
|
||||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
<div class="setting-group">
|
||||||
<path d="M17 8h1a4 4 0 1 1 0 8h-1" />
|
<h3>Start on System Boot</h3>
|
||||||
<path d="M3 8h14v9a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4Z" />
|
<p class="setting-description">Automatically launch when Windows starts</p>
|
||||||
<line x1="6" y1="2" x2="6" y2="4" />
|
|
||||||
<line x1="10" y1="2" x2="10" y2="4" />
|
<label class="toggle-switch">
|
||||||
<line x1="14" y1="2" x2="14" y2="4" />
|
<input type="checkbox" id="startOnBoot">
|
||||||
</svg>
|
<span class="toggle-slider"></span>
|
||||||
If you find this useful, buy me a coffee!
|
<span class="toggle-label">Enabled</span>
|
||||||
</button>
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-group">
|
||||||
|
<h3>Start Minimized</h3>
|
||||||
|
<p class="setting-description">Start hidden in system tray</p>
|
||||||
|
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="startMinimized">
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
<span class="toggle-label">Enabled</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-group">
|
||||||
|
<h3>Close to Tray</h3>
|
||||||
|
<p class="setting-description">Minimize to tray instead of closing</p>
|
||||||
|
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="closeToTray">
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
<span class="toggle-label">Enabled</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Disclaimer -->
|
<!-- Disclaimer -->
|
||||||
<p class="disclaimer">
|
<p class="disclaimer" style="margin-top: 32px; text-align: center;">
|
||||||
<strong>Disclaimer:</strong> Unofficial tool not affiliated with Anthropic. Use at your own
|
<strong>Disclaimer:</strong> Unofficial tool not affiliated with Anthropic. Use at your own
|
||||||
discretion.
|
discretion.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ const elements = {
|
||||||
colorDangerEnd: document.getElementById('colorDangerEnd'),
|
colorDangerEnd: document.getElementById('colorDangerEnd'),
|
||||||
resetColorsBtn: document.getElementById('resetColorsBtn'),
|
resetColorsBtn: document.getElementById('resetColorsBtn'),
|
||||||
logoutBtn: document.getElementById('logoutBtn'),
|
logoutBtn: document.getElementById('logoutBtn'),
|
||||||
coffeeBtn: document.getElementById('coffeeBtn'),
|
|
||||||
minimizeBtn: document.getElementById('minimizeBtn'),
|
minimizeBtn: document.getElementById('minimizeBtn'),
|
||||||
closeBtn: document.getElementById('closeBtn'),
|
closeBtn: document.getElementById('closeBtn'),
|
||||||
// Tray icon elements
|
// Tray icon elements
|
||||||
|
|
@ -45,7 +44,28 @@ const elements = {
|
||||||
borderColor: document.getElementById('borderColor'),
|
borderColor: document.getElementById('borderColor'),
|
||||||
borderOpacity: document.getElementById('borderOpacity'),
|
borderOpacity: document.getElementById('borderOpacity'),
|
||||||
borderOpacityValue: document.getElementById('borderOpacityValue'),
|
borderOpacityValue: document.getElementById('borderOpacityValue'),
|
||||||
resetThemeBtn: document.getElementById('resetThemeBtn')
|
resetThemeBtn: document.getElementById('resetThemeBtn'),
|
||||||
|
// App settings
|
||||||
|
startOnBoot: document.getElementById('startOnBoot'),
|
||||||
|
startMinimized: document.getElementById('startMinimized'),
|
||||||
|
closeToTray: document.getElementById('closeToTray'),
|
||||||
|
uiUpdateInterval: document.getElementById('uiUpdateInterval'),
|
||||||
|
uiUpdateIntervalValue: document.getElementById('uiUpdateIntervalValue'),
|
||||||
|
// Section visibility
|
||||||
|
showSessionSection: document.getElementById('showSessionSection'),
|
||||||
|
showWeeklySection: document.getElementById('showWeeklySection'),
|
||||||
|
// Session element visibility
|
||||||
|
sessionShowLabel: document.getElementById('sessionShowLabel'),
|
||||||
|
sessionShowBar: document.getElementById('sessionShowBar'),
|
||||||
|
sessionShowPercentage: document.getElementById('sessionShowPercentage'),
|
||||||
|
sessionShowCircle: document.getElementById('sessionShowCircle'),
|
||||||
|
sessionShowTime: document.getElementById('sessionShowTime'),
|
||||||
|
// Weekly element visibility
|
||||||
|
weeklyShowLabel: document.getElementById('weeklyShowLabel'),
|
||||||
|
weeklyShowBar: document.getElementById('weeklyShowBar'),
|
||||||
|
weeklyShowPercentage: document.getElementById('weeklyShowPercentage'),
|
||||||
|
weeklyShowCircle: document.getElementById('weeklyShowCircle'),
|
||||||
|
weeklyShowTime: document.getElementById('weeklyShowTime')
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
|
|
@ -65,6 +85,14 @@ async function init() {
|
||||||
const interval = await window.electronAPI.getTrayUpdateInterval();
|
const interval = await window.electronAPI.getTrayUpdateInterval();
|
||||||
loadTrayUpdateInterval(interval);
|
loadTrayUpdateInterval(interval);
|
||||||
|
|
||||||
|
// Load app settings
|
||||||
|
const appSettings = await window.electronAPI.getAppSettings();
|
||||||
|
loadAppSettings(appSettings);
|
||||||
|
|
||||||
|
// Load UI visibility settings
|
||||||
|
const uiVisibility = await window.electronAPI.getUIVisibility();
|
||||||
|
loadUIVisibility(uiVisibility);
|
||||||
|
|
||||||
// Load theme settings
|
// Load theme settings
|
||||||
await loadThemeSettings();
|
await loadThemeSettings();
|
||||||
|
|
||||||
|
|
@ -114,10 +142,6 @@ function setupEventListeners() {
|
||||||
window.electronAPI.openLogin();
|
window.electronAPI.openLogin();
|
||||||
});
|
});
|
||||||
|
|
||||||
elements.coffeeBtn.addEventListener('click', () => {
|
|
||||||
window.electronAPI.openExternal('https://paypal.me/SlavomirDurej?country.x=GB&locale.x=en_GB');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Window controls
|
// Window controls
|
||||||
elements.minimizeBtn.addEventListener('click', () => {
|
elements.minimizeBtn.addEventListener('click', () => {
|
||||||
window.electronAPI.minimizeWindow();
|
window.electronAPI.minimizeWindow();
|
||||||
|
|
@ -220,6 +244,35 @@ function setupEventListeners() {
|
||||||
|
|
||||||
// Reset theme button
|
// Reset theme button
|
||||||
elements.resetThemeBtn.addEventListener('click', resetTheme);
|
elements.resetThemeBtn.addEventListener('click', resetTheme);
|
||||||
|
|
||||||
|
// App settings event listeners
|
||||||
|
elements.startOnBoot.addEventListener('change', saveAppSettings);
|
||||||
|
elements.startMinimized.addEventListener('change', saveAppSettings);
|
||||||
|
elements.closeToTray.addEventListener('change', saveAppSettings);
|
||||||
|
|
||||||
|
elements.uiUpdateInterval.addEventListener('input', () => {
|
||||||
|
elements.uiUpdateIntervalValue.textContent = elements.uiUpdateInterval.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
elements.uiUpdateInterval.addEventListener('change', saveAppSettings);
|
||||||
|
|
||||||
|
// Section visibility event listeners
|
||||||
|
elements.showSessionSection.addEventListener('change', saveUIVisibility);
|
||||||
|
elements.showWeeklySection.addEventListener('change', saveUIVisibility);
|
||||||
|
|
||||||
|
// Session element visibility event listeners
|
||||||
|
elements.sessionShowLabel.addEventListener('change', saveUIVisibility);
|
||||||
|
elements.sessionShowBar.addEventListener('change', saveUIVisibility);
|
||||||
|
elements.sessionShowPercentage.addEventListener('change', saveUIVisibility);
|
||||||
|
elements.sessionShowCircle.addEventListener('change', saveUIVisibility);
|
||||||
|
elements.sessionShowTime.addEventListener('change', saveUIVisibility);
|
||||||
|
|
||||||
|
// Weekly element visibility event listeners
|
||||||
|
elements.weeklyShowLabel.addEventListener('change', saveUIVisibility);
|
||||||
|
elements.weeklyShowBar.addEventListener('change', saveUIVisibility);
|
||||||
|
elements.weeklyShowPercentage.addEventListener('change', saveUIVisibility);
|
||||||
|
elements.weeklyShowCircle.addEventListener('change', saveUIVisibility);
|
||||||
|
elements.weeklyShowTime.addEventListener('change', saveUIVisibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
|
|
@ -463,6 +516,69 @@ function applyThemeToSettings(theme) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// App settings functions
|
||||||
|
function loadAppSettings(settings) {
|
||||||
|
elements.startOnBoot.checked = settings.startOnBoot || false;
|
||||||
|
elements.startMinimized.checked = settings.startMinimized || false;
|
||||||
|
elements.closeToTray.checked = settings.closeToTray || false;
|
||||||
|
elements.uiUpdateInterval.value = settings.uiUpdateInterval || 30;
|
||||||
|
elements.uiUpdateIntervalValue.textContent = settings.uiUpdateInterval || 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveAppSettings() {
|
||||||
|
const settings = {
|
||||||
|
startOnBoot: elements.startOnBoot.checked,
|
||||||
|
startMinimized: elements.startMinimized.checked,
|
||||||
|
closeToTray: elements.closeToTray.checked,
|
||||||
|
uiUpdateInterval: parseInt(elements.uiUpdateInterval.value)
|
||||||
|
};
|
||||||
|
|
||||||
|
await window.electronAPI.setAppSettings(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
// UI visibility functions
|
||||||
|
function loadUIVisibility(visibility) {
|
||||||
|
// Section visibility
|
||||||
|
elements.showSessionSection.checked = visibility.showSessionSection !== false;
|
||||||
|
elements.showWeeklySection.checked = visibility.showWeeklySection !== false;
|
||||||
|
|
||||||
|
// Session elements
|
||||||
|
elements.sessionShowLabel.checked = visibility.sessionShowLabel !== false;
|
||||||
|
elements.sessionShowBar.checked = visibility.sessionShowBar !== false;
|
||||||
|
elements.sessionShowPercentage.checked = visibility.sessionShowPercentage !== false;
|
||||||
|
elements.sessionShowCircle.checked = visibility.sessionShowCircle !== false;
|
||||||
|
elements.sessionShowTime.checked = visibility.sessionShowTime !== false;
|
||||||
|
|
||||||
|
// Weekly elements
|
||||||
|
elements.weeklyShowLabel.checked = visibility.weeklyShowLabel !== false;
|
||||||
|
elements.weeklyShowBar.checked = visibility.weeklyShowBar !== false;
|
||||||
|
elements.weeklyShowPercentage.checked = visibility.weeklyShowPercentage !== false;
|
||||||
|
elements.weeklyShowCircle.checked = visibility.weeklyShowCircle !== false;
|
||||||
|
elements.weeklyShowTime.checked = visibility.weeklyShowTime !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveUIVisibility() {
|
||||||
|
const visibility = {
|
||||||
|
// Section visibility
|
||||||
|
showSessionSection: elements.showSessionSection.checked,
|
||||||
|
showWeeklySection: elements.showWeeklySection.checked,
|
||||||
|
// Session elements
|
||||||
|
sessionShowLabel: elements.sessionShowLabel.checked,
|
||||||
|
sessionShowBar: elements.sessionShowBar.checked,
|
||||||
|
sessionShowPercentage: elements.sessionShowPercentage.checked,
|
||||||
|
sessionShowCircle: elements.sessionShowCircle.checked,
|
||||||
|
sessionShowTime: elements.sessionShowTime.checked,
|
||||||
|
// Weekly elements
|
||||||
|
weeklyShowLabel: elements.weeklyShowLabel.checked,
|
||||||
|
weeklyShowBar: elements.weeklyShowBar.checked,
|
||||||
|
weeklyShowPercentage: elements.weeklyShowPercentage.checked,
|
||||||
|
weeklyShowCircle: elements.weeklyShowCircle.checked,
|
||||||
|
weeklyShowTime: elements.weeklyShowTime.checked
|
||||||
|
};
|
||||||
|
|
||||||
|
await window.electronAPI.setUIVisibility(visibility);
|
||||||
|
}
|
||||||
|
|
||||||
// Setup collapsible sections
|
// Setup collapsible sections
|
||||||
function setupCollapsibleSections() {
|
function setupCollapsibleSections() {
|
||||||
const collapsibleHeaders = document.querySelectorAll('.collapsible-header');
|
const collapsibleHeaders = document.querySelectorAll('.collapsible-header');
|
||||||
|
|
|
||||||
|
|
@ -289,17 +289,25 @@ body {
|
||||||
/* Main Content */
|
/* Main Content */
|
||||||
.content {
|
.content {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.usage-section {
|
.usage-section {
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-columns: 125px 1fr 45px 100px;
|
|
||||||
/* Fixed width labels for alignment */
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 12px;
|
justify-content: center;
|
||||||
margin-bottom: 2px;
|
gap: 16px;
|
||||||
padding: 0 16px;
|
margin-bottom: 8px;
|
||||||
height: 32px;
|
padding: 0 20px;
|
||||||
|
min-height: 32px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.usage-section:last-of-type {
|
.usage-section:last-of-type {
|
||||||
|
|
@ -331,6 +339,8 @@ body {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
flex-shrink: 0;
|
||||||
|
min-width: 110px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.usage-percentage {
|
.usage-percentage {
|
||||||
|
|
@ -338,6 +348,8 @@ body {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
flex-shrink: 0;
|
||||||
|
min-width: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Progress Bar */
|
/* Progress Bar */
|
||||||
|
|
@ -347,7 +359,7 @@ body {
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
/* Remove margin as it is in grid */
|
flex: 1;
|
||||||
min-width: 80px;
|
min-width: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -372,12 +384,10 @@ body {
|
||||||
.timer-container {
|
.timer-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: flex-end;
|
||||||
/* Text on left, chart on right */
|
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
/* space between text and pie chart */
|
flex-shrink: 0;
|
||||||
padding-left: 8px;
|
min-width: 90px;
|
||||||
/* Alignment adjustment */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mini-timer {
|
.mini-timer {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue