no usage display notice implemented
remembering the last known position implemented
This commit is contained in:
parent
ba504455e8
commit
8500ccfaad
5 changed files with 107 additions and 12 deletions
|
|
@ -117,8 +117,8 @@ const UPDATE_INTERVAL = 5 * 60 * 1000; // Change to your preference (in millisec
|
|||
- Try re-logging in from the system tray menu
|
||||
|
||||
### Widget position not saving
|
||||
- Position is reset on each launch
|
||||
- Future version will include position memory
|
||||
- Window position is now saved automatically when you drag it
|
||||
- Position will be restored when you restart the app
|
||||
|
||||
### Build errors
|
||||
```bash
|
||||
|
|
@ -158,7 +158,7 @@ https://claude.ai/api/organizations/{org_id}/usage
|
|||
- [ ] Linux support
|
||||
- [ ] Custom themes
|
||||
- [ ] Notification alerts at usage thresholds
|
||||
- [ ] Remember window position
|
||||
- [x] Remember window position
|
||||
- [ ] Settings panel
|
||||
- [ ] Usage history graphs
|
||||
- [ ] Multiple account support
|
||||
|
|
|
|||
20
main.js
20
main.js
|
|
@ -16,7 +16,9 @@ const WIDGET_WIDTH = 480;
|
|||
const WIDGET_HEIGHT = 140;
|
||||
|
||||
function createMainWindow() {
|
||||
mainWindow = new BrowserWindow({
|
||||
// Load saved position or use defaults
|
||||
const savedPosition = store.get('windowPosition');
|
||||
const windowOptions = {
|
||||
width: WIDGET_WIDTH,
|
||||
height: WIDGET_HEIGHT,
|
||||
frame: false,
|
||||
|
|
@ -30,7 +32,15 @@ function createMainWindow() {
|
|||
contextIsolation: true,
|
||||
preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Apply saved position if it exists
|
||||
if (savedPosition) {
|
||||
windowOptions.x = savedPosition.x;
|
||||
windowOptions.y = savedPosition.y;
|
||||
}
|
||||
|
||||
mainWindow = new BrowserWindow(windowOptions);
|
||||
|
||||
mainWindow.loadFile('src/renderer/index.html');
|
||||
|
||||
|
|
@ -38,6 +48,12 @@ function createMainWindow() {
|
|||
mainWindow.setAlwaysOnTop(true, 'floating');
|
||||
mainWindow.setVisibleOnAllWorkspaces(true);
|
||||
|
||||
// Save position when window is moved
|
||||
mainWindow.on('move', () => {
|
||||
const position = mainWindow.getBounds();
|
||||
store.set('windowPosition', { x: position.x, y: position.y });
|
||||
});
|
||||
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = null;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ const UPDATE_INTERVAL = 5 * 60 * 1000; // 5 minutes
|
|||
const elements = {
|
||||
loadingContainer: document.getElementById('loadingContainer'),
|
||||
loginContainer: document.getElementById('loginContainer'),
|
||||
noUsageContainer: document.getElementById('noUsageContainer'),
|
||||
mainContent: document.getElementById('mainContent'),
|
||||
loginBtn: document.getElementById('loginBtn'),
|
||||
refreshBtn: document.getElementById('refreshBtn'),
|
||||
|
|
@ -130,17 +131,30 @@ async function fetchUsageData() {
|
|||
}
|
||||
}
|
||||
|
||||
// Update UI with usage data
|
||||
// Check if there's no usage data
|
||||
function hasNoUsage(data) {
|
||||
const sessionUtilization = data.five_hour?.utilization || 0;
|
||||
const sessionResetsAt = data.five_hour?.resets_at;
|
||||
const weeklyUtilization = data.seven_day?.utilization || 0;
|
||||
const weeklyResetsAt = data.seven_day?.resets_at;
|
||||
|
||||
return sessionUtilization === 0 && !sessionResetsAt &&
|
||||
weeklyUtilization === 0 && !weeklyResetsAt;
|
||||
}
|
||||
|
||||
// Update UI with usage data
|
||||
function updateUI(data) {
|
||||
latestUsageData = data;
|
||||
|
||||
// Check if there's no usage data
|
||||
if (hasNoUsage(data)) {
|
||||
showNoUsage();
|
||||
return;
|
||||
}
|
||||
|
||||
showMainContent();
|
||||
refreshTimers();
|
||||
startCountdown();
|
||||
|
||||
// Update timestamp
|
||||
// Update timestamp
|
||||
// const now = new Date();
|
||||
// elements.lastUpdate.textContent = `Updated ${now.toLocaleTimeString()}`;
|
||||
}
|
||||
|
||||
// Track if we've already triggered a refresh for expired timers
|
||||
|
|
@ -301,19 +315,29 @@ function updateTimer(timerElement, textElement, resetsAt, totalMinutes) {
|
|||
function showLoading() {
|
||||
elements.loadingContainer.style.display = 'block';
|
||||
elements.loginContainer.style.display = 'none';
|
||||
elements.noUsageContainer.style.display = 'none';
|
||||
elements.mainContent.style.display = 'none';
|
||||
}
|
||||
|
||||
function showLoginRequired() {
|
||||
elements.loadingContainer.style.display = 'none';
|
||||
elements.loginContainer.style.display = 'flex'; // Use flex to preserve centering
|
||||
elements.noUsageContainer.style.display = 'none';
|
||||
elements.mainContent.style.display = 'none';
|
||||
stopAutoUpdate();
|
||||
}
|
||||
|
||||
function showNoUsage() {
|
||||
elements.loadingContainer.style.display = 'none';
|
||||
elements.loginContainer.style.display = 'none';
|
||||
elements.noUsageContainer.style.display = 'flex';
|
||||
elements.mainContent.style.display = 'none';
|
||||
}
|
||||
|
||||
function showMainContent() {
|
||||
elements.loadingContainer.style.display = 'none';
|
||||
elements.loginContainer.style.display = 'none';
|
||||
elements.noUsageContainer.style.display = 'none';
|
||||
elements.mainContent.style.display = 'block';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,19 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- No Usage State -->
|
||||
<div class="no-usage-container" id="noUsageContainer" style="display: none;">
|
||||
<div class="no-usage-content">
|
||||
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
|
||||
</svg>
|
||||
<div class="no-usage-text-group">
|
||||
<h3>No Usage Yet</h3>
|
||||
<p>Start chatting with Claude to see your usage stats</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="content" id="mainContent" style="display: none;">
|
||||
<!-- Session Usage -->
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ body {
|
|||
}
|
||||
|
||||
.app-logo {
|
||||
width: 19px;
|
||||
width: 19px;npm
|
||||
height: 19px;
|
||||
border-radius: 6px;
|
||||
opacity: 0.8;
|
||||
|
|
@ -188,6 +188,48 @@ body {
|
|||
box-shadow: 0 4px 12px rgba(139, 92, 246, 0.3);
|
||||
}
|
||||
|
||||
/* No Usage State */
|
||||
.no-usage-container {
|
||||
padding: 0 16px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.no-usage-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.no-usage-content svg {
|
||||
color: #8b5cf6;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.no-usage-text-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.no-usage-content h3 {
|
||||
color: #e0e0e0;
|
||||
font-size: 14px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.no-usage-content p {
|
||||
color: #a0a0a0;
|
||||
font-size: 11px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Main Content */
|
||||
.content {
|
||||
padding: 20px;
|
||||
|
|
|
|||
Loading…
Reference in a new issue