From 6c477881c4aa96bcabb51b60997a71984f4c3e3b Mon Sep 17 00:00:00 2001 From: chenchen Date: Wed, 13 May 2026 15:53:22 +0800 Subject: [PATCH] =?UTF-8?q?release:=200.1.4=20=E2=80=94=20sidebar=20time?= =?UTF-8?q?=20filter=20+=20clickable=20user=20card?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Sidebar search row gains a recency-filter chip (All / 1d / 3d / 7d). Active filter highlights brand color; selection persists in localStorage (`cc-haha.sidebar.timeFilter`). Default `all` keeps current behavior. - SidebarUserCard becomes a button — clicking the avatar/name pill opens https://code.xinghanlab.com/ in the system browser via @tauri-apps/plugin-shell, with window.open fallback for dev builds. Collapsed-sidebar avatar circle also clickable. - i18n: `sidebar.timeFilter.title/all` + `sidebar.userCard.openProfile` added in zh + en. Co-Authored-By: Claude Opus 4.7 (1M context) --- cc-haha/desktop/package.json | 2 +- cc-haha/desktop/src-tauri/Cargo.toml | 2 +- cc-haha/desktop/src-tauri/tauri.conf.json | 2 +- .../desktop/src/components/layout/Sidebar.tsx | 132 ++++++++++++++++-- cc-haha/desktop/src/i18n/locales/en.ts | 3 + cc-haha/desktop/src/i18n/locales/zh.ts | 3 + 6 files changed, 130 insertions(+), 14 deletions(-) diff --git a/cc-haha/desktop/package.json b/cc-haha/desktop/package.json index 219a66d..5e38f0f 100644 --- a/cc-haha/desktop/package.json +++ b/cc-haha/desktop/package.json @@ -1,7 +1,7 @@ { "name": "heicode-desktop", "private": true, - "version": "0.1.3", + "version": "0.1.4", "type": "module", "scripts": { "dev": "vite", diff --git a/cc-haha/desktop/src-tauri/Cargo.toml b/cc-haha/desktop/src-tauri/Cargo.toml index 4e94c19..6acd08d 100644 --- a/cc-haha/desktop/src-tauri/Cargo.toml +++ b/cc-haha/desktop/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "heicode-desktop" -version = "0.1.3" +version = "0.1.4" edition = "2021" [lib] diff --git a/cc-haha/desktop/src-tauri/tauri.conf.json b/cc-haha/desktop/src-tauri/tauri.conf.json index 78484de..bd86c1e 100644 --- a/cc-haha/desktop/src-tauri/tauri.conf.json +++ b/cc-haha/desktop/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/nicegui/nicegui/main/nicegui/static/tauri-schema-v2.json", "productName": "HeiCode", - "version": "0.1.3", + "version": "0.1.4", "identifier": "com.heicode.desktop", "build": { "frontendDist": "../dist", diff --git a/cc-haha/desktop/src/components/layout/Sidebar.tsx b/cc-haha/desktop/src/components/layout/Sidebar.tsx index e5a1720..19c8cb7 100644 --- a/cc-haha/desktop/src/components/layout/Sidebar.tsx +++ b/cc-haha/desktop/src/components/layout/Sidebar.tsx @@ -21,6 +21,30 @@ type TimeGroup = 'within1day' | 'within3days' | 'within7days' | 'older' const TIME_GROUP_ORDER: TimeGroup[] = ['within1day', 'within3days', 'within7days', 'older'] +// User-selectable time filter for the sidebar history list. 'all' means +// no filtering — all groups visible. Persisted in localStorage so a chosen +// window survives reloads. +type TimeFilter = 'all' | '1d' | '3d' | '7d' +const TIME_FILTER_OPTIONS: TimeFilter[] = ['all', '1d', '3d', '7d'] +const TIME_FILTER_KEY = 'cc-haha.sidebar.timeFilter' + +function loadTimeFilter(): TimeFilter { + if (typeof window === 'undefined') return 'all' + const v = window.localStorage.getItem(TIME_FILTER_KEY) + return TIME_FILTER_OPTIONS.includes(v as TimeFilter) ? (v as TimeFilter) : 'all' +} + +function saveTimeFilter(v: TimeFilter) { + if (typeof window === 'undefined') return + try { window.localStorage.setItem(TIME_FILTER_KEY, v) } catch { /* quota */ } +} + +function timeFilterCutoffMs(filter: TimeFilter): number | null { + if (filter === 'all') return null + const days = filter === '1d' ? 1 : filter === '3d' ? 3 : 7 + return Date.now() - days * 86400000 +} + export function Sidebar() { const sessions = useSessionStore((s) => s.sessions) const selectedProjects = useSessionStore((s) => s.selectedProjects) @@ -48,6 +72,9 @@ export function Sidebar() { const [renamingId, setRenamingId] = useState(null) const [renameValue, setRenameValue] = useState('') const [isLoggingOut, setIsLoggingOut] = useState(false) + const [timeFilter, setTimeFilter] = useState(() => loadTimeFilter()) + const [timeFilterOpen, setTimeFilterOpen] = useState(false) + const timeFilterRef = useRef(null) useEffect(() => { fetchSessions() @@ -74,8 +101,24 @@ export function Sidebar() { const q = searchQuery.toLowerCase() result = result.filter((s) => s.title.toLowerCase().includes(q)) } + const cutoff = timeFilterCutoffMs(timeFilter) + if (cutoff !== null) { + result = result.filter((s) => new Date(s.modifiedAt).getTime() >= cutoff) + } return result - }, [sessions, selectedProjects, searchQuery]) + }, [sessions, selectedProjects, searchQuery, timeFilter]) + + // Click-outside to close the time-range popover. + useEffect(() => { + if (!timeFilterOpen) return + const onClick = (e: MouseEvent) => { + if (timeFilterRef.current && !timeFilterRef.current.contains(e.target as Node)) { + setTimeFilterOpen(false) + } + } + document.addEventListener('mousedown', onClick) + return () => document.removeEventListener('mousedown', onClick) + }, [timeFilterOpen]) const timeGroups = useMemo(() => groupByTime(filteredSessions), [filteredSessions]) @@ -236,7 +279,7 @@ export function Sidebar() { className="sidebar-section sidebar-section--visible relative z-20 flex-none px-3 pb-2" style={{ overflow: 'visible' }} > -
+
@@ -514,8 +604,21 @@ function NavItem({ // Logged-in user card in the bottom sidebar — gradient-filled avatar + // name + email + role badge. Always visible so the user can see who they -// are signed in as without clicking anywhere. Two layouts: expanded (full -// pill) and collapsed (small avatar circle with title tooltip). +// are signed in as without clicking anywhere. Clicking the card opens the +// account page on Heicode Manager (code.xinghanlab.com) in the system +// browser, so users can manage their balance / API keys / etc. Two +// layouts: expanded (full pill) and collapsed (small avatar circle with +// title tooltip). +const HEICODE_MANAGER_URL = 'https://code.xinghanlab.com/' + +function openManagerProfile() { + // Tauri shell plugin in the bundled app; falls back to window.open in + // the dev/preview build where the plugin isn't injected. + import('@tauri-apps/plugin-shell') + .then((mod) => mod.open(HEICODE_MANAGER_URL)) + .catch(() => window.open(HEICODE_MANAGER_URL, '_blank')) +} + function SidebarUserCard({ user, collapsed, @@ -532,22 +635,29 @@ function SidebarUserCard({ const initial = (name.slice(0, 1) || '?').toUpperCase() const role = user.role?.trim().toLowerCase() const roleBadge = role && role !== 'user' && role !== '1' ? role : null + const t = useTranslation() + const profileTitle = t('sidebar.userCard.openProfile') if (collapsed) { return ( -
{initial} -
+ ) } return ( -
)} -
+ ) } diff --git a/cc-haha/desktop/src/i18n/locales/en.ts b/cc-haha/desktop/src/i18n/locales/en.ts index 9d2d6eb..0b4f006 100644 --- a/cc-haha/desktop/src/i18n/locales/en.ts +++ b/cc-haha/desktop/src/i18n/locales/en.ts @@ -35,6 +35,9 @@ export const en = { 'sidebar.timeGroup.within3days': 'Past 3 days', 'sidebar.timeGroup.within7days': 'Past 7 days', 'sidebar.timeGroup.older': 'All older', + 'sidebar.timeFilter.title': 'Filter by recency', + 'sidebar.timeFilter.all': 'All', + 'sidebar.userCard.openProfile': 'Open account on Heicode Manager', 'sidebar.collapse': 'Collapse sidebar', 'sidebar.expand': 'Expand sidebar', 'sidebar.logout': 'Log out', diff --git a/cc-haha/desktop/src/i18n/locales/zh.ts b/cc-haha/desktop/src/i18n/locales/zh.ts index ca5ae5e..4e4b671 100644 --- a/cc-haha/desktop/src/i18n/locales/zh.ts +++ b/cc-haha/desktop/src/i18n/locales/zh.ts @@ -37,6 +37,9 @@ export const zh: Record = { 'sidebar.timeGroup.within3days': '3 天内', 'sidebar.timeGroup.within7days': '7 天内', 'sidebar.timeGroup.older': '全部', + 'sidebar.timeFilter.title': '按时间筛选', + 'sidebar.timeFilter.all': '全部', + 'sidebar.userCard.openProfile': '在 Heicode Manager 查看账号', 'sidebar.collapse': '折叠侧边栏', 'sidebar.expand': '展开侧边栏', 'sidebar.logout': '退出登录',