feat: add multiple productivity features and UI enhancements (#68)
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 54s
CI / Lint & Test (push) Successful in 14m42s
CI / Build Linux (push) Successful in 19m4s
CI / Build Windows (cross-compile) (push) Successful in 28m37s

## Summary

This PR adds a collection of productivity features and UI enhancements to improve the Hikari Desktop experience:

### New Features
- **Clipboard History** (#25) - Track and manage copied code snippets with language detection, search, filtering, and pinning
- **Quick Actions Panel** (#15) - Buttons for common quick actions like "Review PR", "Run tests", "Explain file", with customizable actions
- **Git Integration Panel** (#24) - View current branch, changed/staged files, quick git actions (commit, push, pull), and branch management
- **Session Import/Export** (#8) - Export conversations to JSON and import previously saved sessions
- **Snippet Library** (#22) - Save and reuse common prompts with categories and quick insert
- **Session History** (#14) - Auto-save conversations with browsable history and search
- **High Contrast Mode** (#20) - Accessibility theme with improved visibility
- **Minimize to System Tray** (#11) - System tray support with right-click menu

### UI Enhancements
- Trans-pride gradient theme applied across UI elements
- Copy button added to code blocks
- Linter formatting and eslint-disable comments for cleaner code

## Closes

Closes #8
Closes #11
Closes #14
Closes #15
Closes #20
Closes #22
Closes #24
Closes #25
Closes #34
Closes #35
Closes #36
Closes #37
Closes #69
Closes #70

## Test Plan

- [ ] Verify clipboard history captures code from code block copy buttons
- [ ] Verify clipboard history captures manually selected text from terminal
- [ ] Test snippet library CRUD operations and insertion
- [ ] Test quick actions panel with default and custom actions
- [ ] Test git panel shows correct status, branch, and performs git operations
- [ ] Test session history auto-save and restore
- [ ] Test session import/export roundtrip
- [ ] Verify high contrast mode provides adequate contrast
- [ ] Test minimize to tray functionality and tray menu
- [ ] Verify trans-pride gradient theme displays correctly in all themes

---
* This PR was created with help from Hikari~ 🌸*

Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com>
Reviewed-on: #68
Co-authored-by: Hikari <hikari@nhcarrigan.com>
Co-committed-by: Hikari <hikari@nhcarrigan.com>
This commit was merged in pull request #68.
This commit is contained in:
2026-01-25 22:19:00 -08:00
committed by Naomi Carrigan
parent 852a4d6661
commit 4c46d4c8fd
47 changed files with 11695 additions and 319 deletions
+38 -3
View File
@@ -112,7 +112,7 @@ impl WslBridge {
return Err("Process already running".to_string());
}
// Load saved achievements when starting a new session
// Load saved achievements and stats when starting a new session
let app_clone = app.clone();
let stats = self.stats.clone();
tauri::async_runtime::spawn(async move {
@@ -122,7 +122,17 @@ impl WslBridge {
"Loaded {} unlocked achievements",
achievements.unlocked.len()
);
stats.write().achievements = achievements;
println!("Loading saved stats...");
let persisted_stats = crate::stats::load_stats(&app_clone).await;
let mut stats_guard = stats.write();
stats_guard.achievements = achievements;
if let Some(persisted) = persisted_stats {
println!("Applying persisted lifetime stats");
stats_guard.apply_persisted(persisted);
}
});
let working_dir = &options.working_dir;
@@ -440,6 +450,18 @@ impl WslBridge {
self.session_id = None;
self.mcp_config_file = None; // Temp file is automatically deleted when dropped
// Save lifetime stats before resetting session
let stats_snapshot = self.stats.read().clone();
let app_clone = app.clone();
tauri::async_runtime::spawn(async move {
println!("Saving stats on session stop...");
if let Err(e) = crate::stats::save_stats(&app_clone, &stats_snapshot).await {
eprintln!("Failed to save stats: {}", e);
} else {
println!("Stats saved successfully on session stop");
}
});
// Reset session stats on explicit disconnect
self.stats.write().reset_session();
@@ -733,10 +755,23 @@ fn process_json_line(
let current_stats = stats.read().clone();
let stats_event = StatsUpdateEvent {
stats: current_stats,
stats: current_stats.clone(),
};
let _ = app.emit("claude:stats", stats_event);
// Save stats periodically (every 10 messages to avoid excessive disk writes)
if current_stats.session_messages_exchanged.is_multiple_of(10)
&& current_stats.session_messages_exchanged > 0
{
let app_handle = app.clone();
tauri::async_runtime::spawn(async move {
println!("Periodic stats save (every 10 messages)...");
if let Err(e) = crate::stats::save_stats(&app_handle, &current_stats).await {
eprintln!("Failed to save stats: {}", e);
}
});
}
// Only emit error results - success content is already sent via Assistant message
if subtype != "success" {
if let Some(text) = result {