diff --git a/src/renderer/components/ActivityBar/ActivityBar.tsx b/src/renderer/components/ActivityBar/ActivityBar.tsx
index 4effda6..425bc6e 100644
--- a/src/renderer/components/ActivityBar/ActivityBar.tsx
+++ b/src/renderer/components/ActivityBar/ActivityBar.tsx
@@ -66,8 +66,8 @@ export const ActivityBar: React.FC = () => {
// Check if settings view is active (either tab or sidebar)
const isSettingsActive = (activeView === 'settings' && sidebarVisible) || isSettingsTabActive;
- // Check if tags tab is currently active
- const isTagsTabActive = tabs.some(t => t.type === 'tags' && t.id === activeTabId);
+ // Check if tags sidebar is active
+ const isTagsActive = activeView === 'tags' && sidebarVisible;
// Check if chat sidebar is active (activeView === 'chat' and sidebar is visible)
const isChatActive = activeView === 'chat' && sidebarVisible;
@@ -108,8 +108,16 @@ export const ActivityBar: React.FC = () => {
};
const handleTagsClick = () => {
- // Open tags as a dedicated (non-transient) tab
- openTab({ type: 'tags', id: 'tags', isTransient: false });
+ // Toggle sidebar if tags is already active, otherwise switch to tags
+ if (activeView === 'tags' && sidebarVisible) {
+ toggleSidebar();
+ } else {
+ openTab({ type: 'tags', id: 'tags', isTransient: false });
+ setActiveView('tags');
+ if (!sidebarVisible) {
+ toggleSidebar();
+ }
+ }
};
const handleImportClick = () => {
@@ -148,9 +156,9 @@ export const ActivityBar: React.FC = () => {
diff --git a/src/renderer/components/Sidebar/Sidebar.tsx b/src/renderer/components/Sidebar/Sidebar.tsx
index efec9cc..1b48ce0 100644
--- a/src/renderer/components/Sidebar/Sidebar.tsx
+++ b/src/renderer/components/Sidebar/Sidebar.tsx
@@ -1223,11 +1223,19 @@ import { scrollToTagsSection, TagsCategory } from '../TagsView';
const TagsNav: React.FC = () => {
const { t } = useI18n();
+ const { tabs, activeTabId, openTab } = useAppStore();
const [activeSection, setActiveSection] = useState(null);
+ const isTagsTabActive = tabs.some(t => t.type === 'tags' && t.id === activeTabId);
+
const handleNavClick = (category: TagsCategory) => {
+ if (!isTagsTabActive) {
+ openTab({ type: 'tags', id: 'tags', isTransient: false });
+ }
setActiveSection(category);
- scrollToTagsSection(category);
+ setTimeout(() => {
+ scrollToTagsSection(category);
+ }, isTagsTabActive ? 0 : 100);
};
return (
diff --git a/tests/renderer/components/ActivityBar.test.tsx b/tests/renderer/components/ActivityBar.test.tsx
new file mode 100644
index 0000000..b70ee9a
--- /dev/null
+++ b/tests/renderer/components/ActivityBar.test.tsx
@@ -0,0 +1,98 @@
+import React from 'react';
+import { beforeEach, describe, expect, it } from 'vitest';
+import { fireEvent, render, screen } from '@testing-library/react';
+import { ActivityBar } from '../../../src/renderer/components/ActivityBar/ActivityBar';
+import { I18nProvider } from '../../../src/renderer/i18n';
+import { useAppStore } from '../../../src/renderer/store';
+
+describe('ActivityBar tags behavior', () => {
+ beforeEach(() => {
+ useAppStore.setState({
+ activeView: 'posts',
+ sidebarVisible: true,
+ tabs: [],
+ activeTabId: null,
+ });
+ });
+
+ it('opens tags tab and switches sidebar to tags view when clicking Tags', () => {
+ render(
+
+
+
+ );
+
+ fireEvent.click(screen.getByTitle('Tags (click again to toggle sidebar)'));
+
+ const state = useAppStore.getState();
+ expect(state.activeView).toBe('tags');
+ expect(state.sidebarVisible).toBe(true);
+ expect(state.activeTabId).toBe('tags');
+ expect(state.tabs).toContainEqual({ type: 'tags', id: 'tags', isTransient: false });
+ });
+
+ it('toggles tags sidebar off when tags view is already active', () => {
+ useAppStore.setState({
+ activeView: 'tags',
+ sidebarVisible: true,
+ tabs: [{ type: 'tags', id: 'tags', isTransient: false }],
+ activeTabId: 'tags',
+ });
+
+ render(
+
+
+
+ );
+
+ fireEvent.click(screen.getByTitle('Tags (click again to toggle sidebar)'));
+
+ expect(useAppStore.getState().sidebarVisible).toBe(false);
+ });
+
+ it('shows tags sidebar when hidden and tags view is active', () => {
+ useAppStore.setState({
+ activeView: 'tags',
+ sidebarVisible: false,
+ tabs: [{ type: 'tags', id: 'tags', isTransient: false }],
+ activeTabId: 'tags',
+ });
+
+ render(
+
+
+
+ );
+
+ fireEvent.click(screen.getByTitle('Tags (click again to toggle sidebar)'));
+
+ expect(useAppStore.getState().sidebarVisible).toBe(true);
+ });
+
+ it('does not mark tags icon active when tags editor tab is open but another sidebar is active', () => {
+ useAppStore.setState({
+ activeView: 'posts',
+ sidebarVisible: true,
+ tabs: [{ type: 'tags', id: 'tags', isTransient: false }],
+ activeTabId: 'tags',
+ });
+
+ render(
+
+
+
+ );
+
+ expect(screen.getByTitle('Tags (click again to toggle sidebar)')).not.toHaveClass('active');
+ });
+
+ it('uses the shared toggle hint in the tags activity button title', () => {
+ render(
+
+
+
+ );
+
+ expect(screen.getByTitle('Tags (click again to toggle sidebar)')).toBeInTheDocument();
+ });
+});