feat: improve UI styling and add streaming support

UI Improvements:
- Modern gradient buttons with hover effects and shine animation
- Better typography and spacing throughout the app
- Improved session cards with message count and timestamps
- Better styled input fields with focus states
- Smooth transitions and animations
- Added emoji icons for better visual cues
- Improved empty states with icons and better messaging

New Features:
- Added streaming toggle button in API configuration
- Real-time streaming response support with live token display
- Stop button to cancel streaming requests
- Message count display in header
- STREAMING indicator badge when enabled
- AbortController support for request cancellation
- Export now includes streaming status

Technical Changes:
- Added sendMessageStream function to llmApi
- Added streaming field to Config interface
- Updated all components to support streaming mode
- All 52 tests passing
This commit is contained in:
2026-02-26 01:45:19 +01:00
parent 8214079093
commit 0789893e19
10 changed files with 785 additions and 142 deletions
+4 -4
View File
@@ -12,7 +12,7 @@ describe('SessionDrawer', () => {
onSelectSession: vi.fn(),
onCreateSession: vi.fn(),
onDeleteSession: vi.fn(),
config: { endpoint: '', systemPrompt: '', model: 'local-swarm' } as Config,
config: { endpoint: '', systemPrompt: '', model: 'local-swarm', streaming: false } as Config,
onUpdateConfig: vi.fn()
}
@@ -22,7 +22,7 @@ describe('SessionDrawer', () => {
it('should render when open', () => {
render(<SessionDrawer {...defaultProps} />)
expect(screen.getByText(/Sessions/)).toBeInTheDocument()
expect(screen.getByText(/Your Sessions/)).toBeInTheDocument()
expect(screen.getByRole('button', { name: /New Session/i })).toBeInTheDocument()
})
@@ -71,11 +71,11 @@ describe('SessionDrawer', () => {
it('should call onUpdateConfig when save config clicked', () => {
render(<SessionDrawer {...defaultProps} />)
const endpointInput = screen.getByPlaceholderText(/openai.com/i)
const endpointInput = screen.getByPlaceholderText(/192.168/i)
fireEvent.change(endpointInput, { target: { value: 'https://new.com' } })
fireEvent.click(screen.getByRole('button', { name: /Save Config/i }))
expect(defaultProps.onUpdateConfig).toHaveBeenCalledWith({ endpoint: 'https://new.com', systemPrompt: '', model: 'local-swarm' })
expect(defaultProps.onUpdateConfig).toHaveBeenCalledWith({ endpoint: 'https://new.com', systemPrompt: '', model: 'local-swarm', streaming: false })
})
})