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
|
||||
|
||||
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
|
||||
|
||||
- 🎯 **Real-time Usage Tracking** - Monitor both session and weekly usage limits
|
||||
- 📊 **Visual Progress Bars** - Clean, gradient progress indicators
|
||||
- ⏱️ **Countdown Timers** - Circular timers showing time until reset
|
||||
- 🔄 **Auto-refresh** - Updates every 5 minutes automatically
|
||||
- 🎨 **Modern UI** - Sleek, draggable widget with dark theme
|
||||
- 🎨 **Customizable Colors** - Personalize progress bar colors for each usage level
|
||||
- ⚙️ **Settings Panel** - Easy-to-use settings window for customization
|
||||
- 🔒 **Secure** - Encrypted credential storage
|
||||
### Core Features
|
||||
- 🎯 **Real-time Usage Tracking** - Monitor both 5-hour session and 7-day weekly usage limits
|
||||
- 📊 **Visual Progress Bars** - Clean, gradient progress indicators with customizable colors
|
||||
- ⏱️ **Countdown Timers** - Circular timers showing time until session/weekly reset
|
||||
- 🔄 **Configurable Auto-refresh** - Adjustable update interval (10-300 seconds)
|
||||
- 🎨 **Fully Customizable UI** - Toggle any element on/off, customize all colors and theme
|
||||
- 📍 **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
|
||||
|
||||
|
|
@ -54,71 +77,189 @@ The installer will be created in the `dist/` folder.
|
|||
### First Launch
|
||||
|
||||
1. Launch the widget
|
||||
2. Click "Login to Claude" when prompted
|
||||
3. A browser window will open - login to your Claude.ai account
|
||||
4. The widget will automatically capture your session
|
||||
5. Usage data will start displaying immediately
|
||||
2. The app will attempt to auto-login using stored credentials
|
||||
3. If no credentials exist, click "Login to Claude"
|
||||
4. A browser window will open - login to your Claude.ai account
|
||||
5. The widget will automatically capture your session
|
||||
6. Usage data will start displaying immediately
|
||||
|
||||
**[SCREENSHOT: Login screen]**
|
||||
|
||||
### Widget Controls
|
||||
|
||||
- **Drag** - Click and drag the title bar to move the widget
|
||||
- **Refresh** - Click the refresh icon to update data immediately
|
||||
- **Minimize** - Click the minus icon to hide to system tray
|
||||
- **Close** - Click the X to minimize to tray (doesn't exit)
|
||||
**Title Bar:**
|
||||
- **Drag** - Click and drag anywhere on the title bar to move the widget
|
||||
- **Settings Icon** - Open the comprehensive settings panel
|
||||
- **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:
|
||||
- Show/Hide widget
|
||||
- Refresh usage data
|
||||
- Re-login (if session expires)
|
||||
- Settings - Open customization panel
|
||||
- Exit application
|
||||
### System Tray
|
||||
|
||||
**Tray Icon:**
|
||||
- Displays real-time usage percentage
|
||||
- Color changes based on usage level (normal/warning/danger)
|
||||
- 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
|
||||
|
||||
### Current Session
|
||||
- **Progress Bar** - Shows usage from 0-100%
|
||||
- **Timer** - Time remaining until 5-hour session resets
|
||||
### Current Session (5-Hour Limit)
|
||||
- **Progress Bar** - Visual representation of usage (0-100%)
|
||||
- **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**:
|
||||
- Purple: Normal usage (0-74%)
|
||||
- Orange: High usage (75-89%)
|
||||
- Red: Critical usage (90-100%)
|
||||
|
||||
### Weekly Limit
|
||||
- **Progress Bar** - Shows weekly usage from 0-100%
|
||||
- **Timer** - Time remaining until weekly reset (Wednesdays 7:00 AM)
|
||||
- **Same color coding** as session usage
|
||||
### Weekly Limit (7-Day Rolling Window)
|
||||
- **Progress Bar** - Weekly usage from 0-100%
|
||||
- **Percentage** - Exact weekly usage percentage
|
||||
- **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
|
||||
2. Select "Settings"
|
||||
3. Use the color pickers to customize each usage level:
|
||||
- **Normal** (0-74% usage) - Default: Purple gradient
|
||||
- **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
|
||||
### Manual Resizing
|
||||
- Drag edges to resize window
|
||||
- Constraints: 320-600px width, 96-180px height
|
||||
- Content stays centered at all sizes
|
||||
|
||||

|
||||
### 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`
|
||||
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)
|
||||
```
|
||||
Currently, the widget does not have keyboard shortcuts. This may be added in a future version.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
|
@ -126,16 +267,31 @@ const UPDATE_INTERVAL = 5 * 60 * 1000; // Change to your preference (in millisec
|
|||
- Your Claude.ai session may have expired
|
||||
- Click "Login to Claude" to re-authenticate
|
||||
- Check that you're logging into the correct account
|
||||
- Verify Claude.ai is accessible in your region
|
||||
|
||||
### Widget not updating
|
||||
- Check your internet connection
|
||||
- Click the refresh button manually
|
||||
- Ensure Claude.ai is accessible in your region
|
||||
- Try re-logging in from the system tray menu
|
||||
- Ensure Claude.ai API is accessible
|
||||
- Try increasing update interval if experiencing rate limits
|
||||
- Re-login from system tray menu
|
||||
|
||||
### Widget position not saving
|
||||
- Window position is now saved automatically when you drag it
|
||||
- Position will be restored when you restart the app
|
||||
### Tray icon not showing/updating
|
||||
- Check that "Show Percentage Text" is enabled to see text
|
||||
- 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
|
||||
```bash
|
||||
|
|
@ -146,10 +302,11 @@ npm install
|
|||
|
||||
## Privacy & Security
|
||||
|
||||
- Your session credentials are stored **locally only** using encrypted storage
|
||||
- No data is sent to any third-party servers
|
||||
- The widget only communicates with Claude.ai official API
|
||||
- Session cookies are stored using Electron's secure storage
|
||||
- **Local Storage Only** - Your session credentials are stored locally using encrypted electron-store
|
||||
- **No Third-Party Servers** - No data is sent to any servers except Claude.ai official API
|
||||
- **Official API Only** - Widget only communicates with Claude.ai API endpoints
|
||||
- **Secure Cookies** - Session cookies stored using Electron's secure storage
|
||||
- **Open Source** - All code is publicly available for audit
|
||||
|
||||
## Technical Details
|
||||
|
||||
|
|
@ -157,11 +314,14 @@ npm install
|
|||
- Electron 28.0.0
|
||||
- Pure JavaScript (no framework overhead)
|
||||
- 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
|
||||
```
|
||||
|
||||
**Storage Location:**
|
||||
|
|
@ -169,37 +329,152 @@ https://claude.ai/api/organizations/{org_id}/usage
|
|||
%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
|
||||
|
||||
### Planned Features
|
||||
- [ ] macOS support
|
||||
- [ ] Linux support
|
||||
- [x] Custom color themes
|
||||
- [ ] Notification alerts at usage thresholds
|
||||
- [x] Remember window position
|
||||
- [x] Settings panel
|
||||
- [ ] Usage history graphs
|
||||
- [ ] Export usage data (CSV/JSON)
|
||||
- [ ] Multiple account support
|
||||
- [ ] 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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
If you encounter issues:
|
||||
1. Check the [Issues](issues) page
|
||||
2. Create a new issue with details about your problem
|
||||
3. Include your OS version and any error messages
|
||||
|
||||
1. **Check existing issues** - [Issues page](../../issues)
|
||||
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 = {
|
||||
width: WIDGET_WIDTH,
|
||||
height: WIDGET_HEIGHT,
|
||||
minWidth: 320,
|
||||
maxWidth: 600,
|
||||
minHeight: 96,
|
||||
maxHeight: 180,
|
||||
frame: false,
|
||||
transparent: true,
|
||||
alwaysOnTop: true,
|
||||
resizable: false,
|
||||
resizable: true,
|
||||
skipTaskbar: false,
|
||||
icon: path.join(__dirname, 'assets/icon.ico'),
|
||||
webPreferences: {
|
||||
|
|
@ -579,7 +583,12 @@ ipcMain.on('minimize-window', () => {
|
|||
});
|
||||
|
||||
ipcMain.on('close-window', () => {
|
||||
const appSettings = store.get('appSettings', { closeToTray: false });
|
||||
if (appSettings.closeToTray) {
|
||||
mainWindow.hide();
|
||||
} else {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('get-window-position', () => {
|
||||
|
|
@ -597,6 +606,19 @@ ipcMain.handle('set-window-position', (event, { x, y }) => {
|
|||
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) => {
|
||||
shell.openExternal(url);
|
||||
});
|
||||
|
|
@ -735,13 +757,84 @@ ipcMain.handle('notify-theme-change', (event, theme) => {
|
|||
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.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();
|
||||
createTray();
|
||||
createIconGeneratorWindow();
|
||||
startTrayUpdateTimer();
|
||||
|
||||
// Start minimized if enabled
|
||||
if (appSettings.startMinimized) {
|
||||
mainWindow.hide();
|
||||
}
|
||||
|
||||
// Check if we have credentials
|
||||
// const hasCredentials = store.get('sessionKey') && store.get('organizationId');
|
||||
// if (!hasCredentials) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "claude-usage-widget",
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.2",
|
||||
"description": "Desktop widget for Claude.ai usage monitoring",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
13
preload.js
13
preload.js
|
|
@ -17,6 +17,8 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
|||
// Window position
|
||||
getWindowPosition: () => ipcRenderer.invoke('get-window-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
|
||||
onLoginSuccess: (callback) => {
|
||||
|
|
@ -60,5 +62,16 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
|||
notifyThemeChange: (theme) => ipcRenderer.invoke('notify-theme-change', theme),
|
||||
onThemeChanged: (callback) => {
|
||||
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();
|
||||
applyThemePreferences(themeSettings);
|
||||
|
||||
// Load and apply UI visibility settings
|
||||
const uiVisibility = await window.electronAPI.getUIVisibility();
|
||||
applyUIVisibility(uiVisibility);
|
||||
|
||||
if (credentials.sessionKey && credentials.organizationId) {
|
||||
showMainContent();
|
||||
await fetchUsageData();
|
||||
|
|
@ -124,6 +128,12 @@ function setupEventListeners() {
|
|||
console.log('Theme changed, applying new 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
|
||||
|
|
@ -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
|
||||
function startAutoUpdate() {
|
||||
async function startAutoUpdate() {
|
||||
stopAutoUpdate();
|
||||
// Load update interval from settings
|
||||
const appSettings = await window.electronAPI.getAppSettings();
|
||||
const intervalMs = (appSettings.uiUpdateInterval || 300) * 1000; // Convert to milliseconds
|
||||
|
||||
updateInterval = setInterval(() => {
|
||||
fetchUsageData();
|
||||
}, UPDATE_INTERVAL);
|
||||
}, intervalMs);
|
||||
}
|
||||
|
||||
function stopAutoUpdate() {
|
||||
|
|
|
|||
|
|
@ -95,10 +95,11 @@ body {
|
|||
}
|
||||
|
||||
.settings-section h2 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16px;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 20px;
|
||||
color: #e0e0e0;
|
||||
letter-spacing: 0.3px;
|
||||
}
|
||||
|
||||
/* 2-Column Grid for Color Pickers */
|
||||
|
|
@ -233,7 +234,11 @@ body {
|
|||
|
||||
/* Setting Groups */
|
||||
.setting-group {
|
||||
margin-bottom: 25px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.setting-group:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.setting-group h3 {
|
||||
|
|
@ -308,6 +313,7 @@ body {
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
|
|
@ -436,7 +442,17 @@ body {
|
|||
|
||||
/* Collapsible Sections */
|
||||
.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 {
|
||||
|
|
@ -487,6 +503,22 @@ body {
|
|||
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 {
|
||||
display: grid;
|
||||
|
|
|
|||
|
|
@ -149,6 +149,139 @@
|
|||
<button class="btn-secondary" id="resetThemeBtn">Reset Theme</button>
|
||||
</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>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
|
@ -282,26 +415,49 @@
|
|||
|
||||
<div class="divider"></div>
|
||||
|
||||
<!-- Support -->
|
||||
<!-- Application Settings -->
|
||||
<section class="settings-section">
|
||||
<button class="btn-coffee" id="coffeeBtn">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M17 8h1a4 4 0 1 1 0 8h-1" />
|
||||
<path d="M3 8h14v9a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4Z" />
|
||||
<line x1="6" y1="2" x2="6" y2="4" />
|
||||
<line x1="10" y1="2" x2="10" y2="4" />
|
||||
<line x1="14" y1="2" x2="14" y2="4" />
|
||||
</svg>
|
||||
If you find this useful, buy me a coffee!
|
||||
</button>
|
||||
<h2>Application</h2>
|
||||
|
||||
<div class="setting-group">
|
||||
<h3>Start on System Boot</h3>
|
||||
<p class="setting-description">Automatically launch when Windows starts</p>
|
||||
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="startOnBoot">
|
||||
<span class="toggle-slider"></span>
|
||||
<span class="toggle-label">Enabled</span>
|
||||
</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 -->
|
||||
<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
|
||||
discretion.
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ const elements = {
|
|||
colorDangerEnd: document.getElementById('colorDangerEnd'),
|
||||
resetColorsBtn: document.getElementById('resetColorsBtn'),
|
||||
logoutBtn: document.getElementById('logoutBtn'),
|
||||
coffeeBtn: document.getElementById('coffeeBtn'),
|
||||
minimizeBtn: document.getElementById('minimizeBtn'),
|
||||
closeBtn: document.getElementById('closeBtn'),
|
||||
// Tray icon elements
|
||||
|
|
@ -45,7 +44,28 @@ const elements = {
|
|||
borderColor: document.getElementById('borderColor'),
|
||||
borderOpacity: document.getElementById('borderOpacity'),
|
||||
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
|
||||
|
|
@ -65,6 +85,14 @@ async function init() {
|
|||
const interval = await window.electronAPI.getTrayUpdateInterval();
|
||||
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
|
||||
await loadThemeSettings();
|
||||
|
||||
|
|
@ -114,10 +142,6 @@ function setupEventListeners() {
|
|||
window.electronAPI.openLogin();
|
||||
});
|
||||
|
||||
elements.coffeeBtn.addEventListener('click', () => {
|
||||
window.electronAPI.openExternal('https://paypal.me/SlavomirDurej?country.x=GB&locale.x=en_GB');
|
||||
});
|
||||
|
||||
// Window controls
|
||||
elements.minimizeBtn.addEventListener('click', () => {
|
||||
window.electronAPI.minimizeWindow();
|
||||
|
|
@ -220,6 +244,35 @@ function setupEventListeners() {
|
|||
|
||||
// Reset theme button
|
||||
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
|
||||
|
|
@ -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
|
||||
function setupCollapsibleSections() {
|
||||
const collapsibleHeaders = document.querySelectorAll('.collapsible-header');
|
||||
|
|
|
|||
|
|
@ -289,17 +289,25 @@ body {
|
|||
/* Main Content */
|
||||
.content {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.usage-section {
|
||||
display: grid;
|
||||
grid-template-columns: 125px 1fr 45px 100px;
|
||||
/* Fixed width labels for alignment */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 2px;
|
||||
padding: 0 16px;
|
||||
height: 32px;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
margin-bottom: 8px;
|
||||
padding: 0 20px;
|
||||
min-height: 32px;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.usage-section:last-of-type {
|
||||
|
|
@ -331,6 +339,8 @@ body {
|
|||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
min-width: 110px;
|
||||
}
|
||||
|
||||
.usage-percentage {
|
||||
|
|
@ -338,6 +348,8 @@ body {
|
|||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
text-align: right;
|
||||
flex-shrink: 0;
|
||||
min-width: 40px;
|
||||
}
|
||||
|
||||
/* Progress Bar */
|
||||
|
|
@ -347,7 +359,7 @@ body {
|
|||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
/* Remove margin as it is in grid */
|
||||
flex: 1;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
|
|
@ -372,12 +384,10 @@ body {
|
|||
.timer-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
/* Text on left, chart on right */
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
/* space between text and pie chart */
|
||||
padding-left: 8px;
|
||||
/* Alignment adjustment */
|
||||
flex-shrink: 0;
|
||||
min-width: 90px;
|
||||
}
|
||||
|
||||
.mini-timer {
|
||||
|
|
|
|||
Loading…
Reference in a new issue