Files
openchamber/packages/ui/src/components/chat/message/parts/useDurationTicker.ts
T
Bohdan TriapitsynandIuliia Ivashko 321cc7252a Major UI refresh: sidebar redesign, theme expansion, and chat performance optimizations (#706)
## 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>
2026-03-20 01:01:03 +02:00

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;
};