no usage display notice implemented
remembering the last known position implemented
This commit is contained in:
parent
5680558060
commit
2cfa69cc5d
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
|
- Try re-logging in from the system tray menu
|
||||||
|
|
||||||
### Widget position not saving
|
### Widget position not saving
|
||||||
- Position is reset on each launch
|
- Window position is now saved automatically when you drag it
|
||||||
- Future version will include position memory
|
- Position will be restored when you restart the app
|
||||||
|
|
||||||
### Build errors
|
### Build errors
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -158,7 +158,7 @@ https://claude.ai/api/organizations/{org_id}/usage
|
||||||
- [ ] Linux support
|
- [ ] Linux support
|
||||||
- [ ] Custom themes
|
- [ ] Custom themes
|
||||||
- [ ] Notification alerts at usage thresholds
|
- [ ] Notification alerts at usage thresholds
|
||||||
- [ ] Remember window position
|
- [x] Remember window position
|
||||||
- [ ] Settings panel
|
- [ ] Settings panel
|
||||||
- [ ] Usage history graphs
|
- [ ] Usage history graphs
|
||||||
- [ ] Multiple account support
|
- [ ] Multiple account support
|
||||||
|
|
|
||||||
20
main.js
20
main.js
|
|
@ -16,7 +16,9 @@ const WIDGET_WIDTH = 480;
|
||||||
const WIDGET_HEIGHT = 140;
|
const WIDGET_HEIGHT = 140;
|
||||||
|
|
||||||
function createMainWindow() {
|
function createMainWindow() {
|
||||||
mainWindow = new BrowserWindow({
|
// Load saved position or use defaults
|
||||||
|
const savedPosition = store.get('windowPosition');
|
||||||
|
const windowOptions = {
|
||||||
width: WIDGET_WIDTH,
|
width: WIDGET_WIDTH,
|
||||||
height: WIDGET_HEIGHT,
|
height: WIDGET_HEIGHT,
|
||||||
frame: false,
|
frame: false,
|
||||||
|
|
@ -30,7 +32,15 @@ function createMainWindow() {
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
preload: path.join(__dirname, 'preload.js')
|
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');
|
mainWindow.loadFile('src/renderer/index.html');
|
||||||
|
|
||||||
|
|
@ -38,6 +48,12 @@ function createMainWindow() {
|
||||||
mainWindow.setAlwaysOnTop(true, 'floating');
|
mainWindow.setAlwaysOnTop(true, 'floating');
|
||||||
mainWindow.setVisibleOnAllWorkspaces(true);
|
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.on('closed', () => {
|
||||||
mainWindow = null;
|
mainWindow = null;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ const UPDATE_INTERVAL = 5 * 60 * 1000; // 5 minutes
|
||||||
const elements = {
|
const elements = {
|
||||||
loadingContainer: document.getElementById('loadingContainer'),
|
loadingContainer: document.getElementById('loadingContainer'),
|
||||||
loginContainer: document.getElementById('loginContainer'),
|
loginContainer: document.getElementById('loginContainer'),
|
||||||
|
noUsageContainer: document.getElementById('noUsageContainer'),
|
||||||
mainContent: document.getElementById('mainContent'),
|
mainContent: document.getElementById('mainContent'),
|
||||||
loginBtn: document.getElementById('loginBtn'),
|
loginBtn: document.getElementById('loginBtn'),
|
||||||
refreshBtn: document.getElementById('refreshBtn'),
|
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
|
// Update UI with usage data
|
||||||
function updateUI(data) {
|
function updateUI(data) {
|
||||||
latestUsageData = data;
|
latestUsageData = data;
|
||||||
|
|
||||||
|
// Check if there's no usage data
|
||||||
|
if (hasNoUsage(data)) {
|
||||||
|
showNoUsage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showMainContent();
|
||||||
refreshTimers();
|
refreshTimers();
|
||||||
startCountdown();
|
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
|
// Track if we've already triggered a refresh for expired timers
|
||||||
|
|
@ -301,19 +315,29 @@ function updateTimer(timerElement, textElement, resetsAt, totalMinutes) {
|
||||||
function showLoading() {
|
function showLoading() {
|
||||||
elements.loadingContainer.style.display = 'block';
|
elements.loadingContainer.style.display = 'block';
|
||||||
elements.loginContainer.style.display = 'none';
|
elements.loginContainer.style.display = 'none';
|
||||||
|
elements.noUsageContainer.style.display = 'none';
|
||||||
elements.mainContent.style.display = 'none';
|
elements.mainContent.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
function showLoginRequired() {
|
function showLoginRequired() {
|
||||||
elements.loadingContainer.style.display = 'none';
|
elements.loadingContainer.style.display = 'none';
|
||||||
elements.loginContainer.style.display = 'flex'; // Use flex to preserve centering
|
elements.loginContainer.style.display = 'flex'; // Use flex to preserve centering
|
||||||
|
elements.noUsageContainer.style.display = 'none';
|
||||||
elements.mainContent.style.display = 'none';
|
elements.mainContent.style.display = 'none';
|
||||||
stopAutoUpdate();
|
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() {
|
function showMainContent() {
|
||||||
elements.loadingContainer.style.display = 'none';
|
elements.loadingContainer.style.display = 'none';
|
||||||
elements.loginContainer.style.display = 'none';
|
elements.loginContainer.style.display = 'none';
|
||||||
|
elements.noUsageContainer.style.display = 'none';
|
||||||
elements.mainContent.style.display = 'block';
|
elements.mainContent.style.display = 'block';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,19 @@
|
||||||
</div>
|
</div>
|
||||||
</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 -->
|
<!-- Main Content -->
|
||||||
<div class="content" id="mainContent" style="display: none;">
|
<div class="content" id="mainContent" style="display: none;">
|
||||||
<!-- Session Usage -->
|
<!-- Session Usage -->
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-logo {
|
.app-logo {
|
||||||
width: 19px;
|
width: 19px;npm
|
||||||
height: 19px;
|
height: 19px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
|
|
@ -188,6 +188,48 @@ body {
|
||||||
box-shadow: 0 4px 12px rgba(139, 92, 246, 0.3);
|
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 */
|
/* Main Content */
|
||||||
.content {
|
.content {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue