)}
- {posts.length === 0 && !isFiltered && (
+ {postSubset.length === 0 && !isFiltered && (
)}
@@ -1541,7 +1582,12 @@ export const Sidebar: React.FC = () => {
return (
- {activeView === 'posts' &&
}
+
+
{activeView === 'media' &&
}
{activeView === 'settings' &&
}
{activeView === 'tags' &&
}
diff --git a/src/renderer/store/appStore.ts b/src/renderer/store/appStore.ts
index 558a402..e2ab29f 100644
--- a/src/renderer/store/appStore.ts
+++ b/src/renderer/store/appStore.ts
@@ -50,7 +50,7 @@ interface AppState {
activeTabId: string | null;
// UI State
- activeView: 'posts' | 'media' | 'settings' | 'tags' | 'chat' | 'import';
+ activeView: 'posts' | 'pages' | 'media' | 'settings' | 'tags' | 'chat' | 'import';
sidebarVisible: boolean;
panelVisible: boolean;
selectedPostId: string | null;
@@ -96,7 +96,7 @@ interface AppState {
restoreTabState: (state: TabState) => void;
// Actions
- setActiveView: (view: 'posts' | 'media' | 'settings' | 'tags' | 'chat' | 'import') => void;
+ setActiveView: (view: 'posts' | 'pages' | 'media' | 'settings' | 'tags' | 'chat' | 'import') => void;
toggleSidebar: () => void;
togglePanel: () => void;
setSelectedPost: (id: string | null) => void;
diff --git a/tests/renderer/components/PagesShortcut.test.tsx b/tests/renderer/components/PagesShortcut.test.tsx
new file mode 100644
index 0000000..4659fd1
--- /dev/null
+++ b/tests/renderer/components/PagesShortcut.test.tsx
@@ -0,0 +1,90 @@
+import React from 'react';
+import { describe, it, expect, beforeEach, vi } from 'vitest';
+import { render, screen, within } from '@testing-library/react';
+import { ActivityBar } from '../../../src/renderer/components/ActivityBar/ActivityBar';
+import { Sidebar } from '../../../src/renderer/components/Sidebar/Sidebar';
+import { useAppStore, type PostData } from '../../../src/renderer/store';
+
+const createMockPost = (overrides: Partial
= {}): PostData => ({
+ id: `post-${Math.random().toString(36).slice(2)}`,
+ projectId: 'project-1',
+ title: 'Test Post',
+ slug: 'test-post',
+ content: 'content',
+ status: 'published',
+ createdAt: new Date().toISOString(),
+ updatedAt: new Date().toISOString(),
+ tags: [],
+ categories: [],
+ ...overrides,
+});
+
+describe('Pages shortcut UI', () => {
+ beforeEach(() => {
+ const now = new Date().toISOString();
+
+ useAppStore.setState({
+ activeView: 'posts',
+ sidebarVisible: true,
+ tabs: [],
+ activeTabId: null,
+ posts: [
+ createMockPost({
+ id: 'post-page',
+ title: 'About Page',
+ categories: ['page'],
+ updatedAt: now,
+ }),
+ createMockPost({
+ id: 'post-article',
+ title: 'Regular Article',
+ categories: ['article'],
+ updatedAt: now,
+ }),
+ ],
+ hasMorePosts: false,
+ totalPosts: 2,
+ });
+
+ window.electronAPI.posts.getTags = vi.fn().mockResolvedValue([]);
+ window.electronAPI.posts.getCategories = vi.fn().mockResolvedValue(['page', 'article']);
+ window.electronAPI.posts.getByYearMonth = vi.fn().mockResolvedValue([]);
+ (window.electronAPI as any).tags = {
+ getAll: vi.fn().mockResolvedValue([]),
+ };
+ window.electronAPI.posts.search = vi.fn().mockResolvedValue([]);
+ window.electronAPI.posts.filter = vi.fn().mockResolvedValue([]);
+ window.electronAPI.posts.get = vi.fn().mockResolvedValue(null);
+ });
+
+ it('shows a pages button in the activity bar', () => {
+ render();
+
+ expect(screen.getByTitle('Pages (click again to toggle sidebar)')).toBeInTheDocument();
+ });
+
+ it('uses a distinct pages icon shape', () => {
+ render();
+
+ const pagesButton = screen.getByTitle('Pages (click again to toggle sidebar)');
+ const pagesSvg = pagesButton.querySelector('svg');
+
+ expect(pagesSvg).not.toBeNull();
+ expect(pagesSvg?.querySelector('path')?.getAttribute('d')).toBe(
+ 'M4 4h10v4h6v12H4V4zm10 1.5V9h4.5L14 5.5zM7 12h10v1.5H7V12zm0 3h10v1.5H7V15z'
+ );
+ });
+
+ it('shows only page-category posts when pages view is active', async () => {
+ useAppStore.setState({ activeView: 'pages', sidebarVisible: true });
+
+ render();
+
+ const pagesHeader = await screen.findByText('PAGES');
+ const pagesPanel = pagesHeader.closest('.sidebar-content');
+
+ expect(pagesPanel).not.toBeNull();
+ expect(within(pagesPanel as HTMLElement).getByText('About Page')).toBeInTheDocument();
+ expect(within(pagesPanel as HTMLElement).queryByText('Regular Article')).not.toBeInTheDocument();
+ });
+});
\ No newline at end of file