## Summary Complete sidebar redesign and comprehensive UI polish pass with performance optimizations, theme system refinements, and desktop integration improvements. ## Key Changes **Sidebar & Navigation Redesign** - Redesigned sessions sidebar layout with unified button primitives - Added activity sections with project grouping and improved session organization - Refined sidebar corners, spacing, and visual hierarchy - Removed NavRail component in favor of streamlined sidebar - Stabilized sessions bar toggle position in fullscreen mode **Performance Optimizations** - Reduced chat streaming CPU usage and storage churn - Optimized task tool polling and live timers with debouncing - Prevented chat state races and reduced background request load - Debounced draft writes and coalesced session reloads - Optimized message store updates and turn tracking **Theme & Visual System** - Added theme-aware window corners (desktop) and border radius tokens - Introduced glassmorphism effects on desktop sidebar - Added backdrop blur to UI elements **Chat Experience** - Added session-based permission auto-accept toggle in chat input - Polished permission shield UX with improved icon sizing and spacing - Fixed chat scroll-to-bottom behavior and timeline tracking - Enhanced tool output display with better path label detection - Removed duplicate draft context details in chat header - Added text selection menu to chat messages **Git Improvements** - Refreshed git history visual design with cleaner dividers - Added remote removal action in sync selector - Stabilized git polling to prevent excessive requests - Improved tool output rendering for git operations **Settings & Panels** - Fixed mobile scrolling on settings pages - Made outside-click settings close instantly - Reduced settings load churn and CPU spikes - Improved services dropdown layout and spacing - Softened panel resize handles **Desktop Integration** - Synced macOS window theme with app theme - Restored window dragging in sidebar header zones - Fixed system window corners on macOS - Improved header session metadata and action controls **Button & Component Standardization** - Unified button primitives across all components - Standardized destructive action patterns - Removed unused button variants (button-large, button-small) - Aligned context tab close hit areas --------- Co-authored-by: Iuliia Ivashko <yulia.ivashko@gmail.com>
71 lines
1.8 KiB
TypeScript
71 lines
1.8 KiB
TypeScript
import React from 'react';
|
|
|
|
type Subscriber = (now: number) => void;
|
|
|
|
type TickerChannel = {
|
|
subscribers: Set<Subscriber>;
|
|
timerId: number | null;
|
|
};
|
|
|
|
const tickerChannels = new Map<number, TickerChannel>();
|
|
|
|
const getTickerChannel = (intervalMs: number): TickerChannel => {
|
|
const existing = tickerChannels.get(intervalMs);
|
|
if (existing) {
|
|
return existing;
|
|
}
|
|
|
|
const created: TickerChannel = {
|
|
subscribers: new Set<Subscriber>(),
|
|
timerId: null,
|
|
};
|
|
tickerChannels.set(intervalMs, created);
|
|
return created;
|
|
};
|
|
|
|
const subscribeToTicker = (intervalMs: number, subscriber: Subscriber): (() => void) => {
|
|
const channel = getTickerChannel(intervalMs);
|
|
channel.subscribers.add(subscriber);
|
|
subscriber(Date.now());
|
|
|
|
if (channel.timerId === null && typeof window !== 'undefined') {
|
|
channel.timerId = window.setInterval(() => {
|
|
const now = Date.now();
|
|
channel.subscribers.forEach((listener) => {
|
|
listener(now);
|
|
});
|
|
}, intervalMs);
|
|
}
|
|
|
|
return () => {
|
|
const tracked = tickerChannels.get(intervalMs);
|
|
if (!tracked) {
|
|
return;
|
|
}
|
|
|
|
tracked.subscribers.delete(subscriber);
|
|
if (tracked.subscribers.size > 0) {
|
|
return;
|
|
}
|
|
|
|
if (tracked.timerId !== null && typeof window !== 'undefined') {
|
|
window.clearInterval(tracked.timerId);
|
|
}
|
|
tickerChannels.delete(intervalMs);
|
|
};
|
|
};
|
|
|
|
export const useDurationTickerNow = (active: boolean, intervalMs: number = 250): number => {
|
|
const [now, setNow] = React.useState(() => Date.now());
|
|
|
|
React.useEffect(() => {
|
|
if (!active) {
|
|
return;
|
|
}
|
|
|
|
return subscribeToTicker(intervalMs, setNow);
|
|
}, [active, intervalMs]);
|
|
|
|
return now;
|
|
};
|