From 8a19f35922c57b6b8607b2f43d94178209876f9b Mon Sep 17 00:00:00 2001 From: Naomi Carrigan Date: Sun, 25 Jan 2026 20:06:03 -0800 Subject: [PATCH] feat: add user profile with avatar, bio, and lifetime stats - Add profile fields to HikariConfig (name, avatar path, bio) - Create ProfilePanel component with trans-pride themed styling - Add profile button to StatusBar for easy access - Display lifetime stats (messages, tokens, code blocks, files, cost) - Show achievement completion progress bar - Support file picker for avatar image selection - Remove global stats from StatsDisplay (now in Profile) Co-Authored-By: Hikari --- src-tauri/src/config.rs | 19 + src/lib/components/ConfigSidebar.svelte | 3 + src/lib/components/ProfilePanel.svelte | 517 ++++++++++++++++++++++++ src/lib/components/StatsDisplay.svelte | 9 - src/lib/components/StatusBar.svelte | 23 ++ src/lib/stores/config.ts | 6 + 6 files changed, 568 insertions(+), 9 deletions(-) create mode 100644 src/lib/components/ProfilePanel.svelte diff --git a/src-tauri/src/config.rs b/src-tauri/src/config.rs index cc626e0..fa73cbe 100644 --- a/src-tauri/src/config.rs +++ b/src-tauri/src/config.rs @@ -82,6 +82,16 @@ pub struct HikariConfig { #[serde(default)] pub compact_mode: bool, + + // Profile fields + #[serde(default)] + pub profile_name: Option, + + #[serde(default)] + pub profile_avatar_path: Option, + + #[serde(default)] + pub profile_bio: Option, } impl Default for HikariConfig { @@ -105,6 +115,9 @@ impl Default for HikariConfig { streamer_mode: false, streamer_hide_paths: false, compact_mode: false, + profile_name: None, + profile_avatar_path: None, + profile_bio: None, } } } @@ -162,6 +175,9 @@ mod tests { assert!(!config.streamer_mode); assert!(!config.streamer_hide_paths); assert!(!config.compact_mode); + assert!(config.profile_name.is_none()); + assert!(config.profile_avatar_path.is_none()); + assert!(config.profile_bio.is_none()); } #[test] @@ -185,6 +201,9 @@ mod tests { streamer_mode: false, streamer_hide_paths: false, compact_mode: false, + profile_name: Some("Test User".to_string()), + profile_avatar_path: None, + profile_bio: Some("A test bio".to_string()), }; let json = serde_json::to_string(&config).unwrap(); diff --git a/src/lib/components/ConfigSidebar.svelte b/src/lib/components/ConfigSidebar.svelte index de5d69d..3dd3673 100644 --- a/src/lib/components/ConfigSidebar.svelte +++ b/src/lib/components/ConfigSidebar.svelte @@ -30,6 +30,9 @@ streamer_mode: false, streamer_hide_paths: false, compact_mode: false, + profile_name: null, + profile_avatar_path: null, + profile_bio: null, }); let isOpen = $state(false); diff --git a/src/lib/components/ProfilePanel.svelte b/src/lib/components/ProfilePanel.svelte new file mode 100644 index 0000000..ec0de05 --- /dev/null +++ b/src/lib/components/ProfilePanel.svelte @@ -0,0 +1,517 @@ + + + + + diff --git a/src/lib/components/StatsDisplay.svelte b/src/lib/components/StatsDisplay.svelte index 705433d..8590fc3 100644 --- a/src/lib/components/StatsDisplay.svelte +++ b/src/lib/components/StatsDisplay.svelte @@ -14,7 +14,6 @@
Messages: {$formattedStats.messagesSession} - / {$formattedStats.messagesTotal}
@@ -32,11 +31,6 @@ Output: {$formattedStats.sessionOutputTokens}
-
- Total: - {$formattedStats.totalTokens} - {$formattedStats.totalCost} -
@@ -44,17 +38,14 @@
Code blocks: {$formattedStats.codeBlocksSession} - / {$formattedStats.codeBlocksTotal}
Files edited: {$formattedStats.filesEditedSession} - / {$formattedStats.filesEditedTotal}
Files created: {$formattedStats.filesCreatedSession} - / {$formattedStats.filesCreatedTotal}
diff --git a/src/lib/components/StatusBar.svelte b/src/lib/components/StatusBar.svelte index 25d48d2..e109abe 100644 --- a/src/lib/components/StatusBar.svelte +++ b/src/lib/components/StatusBar.svelte @@ -22,6 +22,7 @@ import { achievementProgress } from "$lib/stores/achievements"; import SessionHistoryPanel from "./SessionHistoryPanel.svelte"; import GitPanel from "./GitPanel.svelte"; + import ProfilePanel from "./ProfilePanel.svelte"; const DISCORD_URL = "https://chat.nhcarrigan.com"; const DONATE_URL = "https://donate.nhcarrigan.com"; @@ -38,6 +39,7 @@ let showKeyboardShortcuts = $state(false); let showSessionHistory = $state(false); let showGitPanel = $state(false); + let showProfile = $state(false); const progress = $derived($achievementProgress); let currentConfig: HikariConfig = $state({ model: null, @@ -58,6 +60,9 @@ streamer_mode: false, streamer_hide_paths: false, compact_mode: false, + profile_name: null, + profile_avatar_path: null, + profile_bio: null, }); let streamerModeActive = $state(false); @@ -222,6 +227,20 @@ title="Streamer mode active (Ctrl+Shift+S to toggle)" > {/if} +