fix(web): add page title for snippet

This commit is contained in:
JzoNg 2026-04-15 18:22:20 +08:00
parent b5dc774093
commit f1da2c76d1
3 changed files with 112 additions and 1 deletions

View File

@ -103,7 +103,7 @@ const CreatorsFilter = ({
baseChipClassName,
isSelected
? 'border-components-button-secondary-border bg-components-button-secondary-bg shadow-xs hover:bg-state-base-hover'
: 'border-transparent bg-[#f9f9f9] text-text-tertiary hover:bg-components-input-bg-hover',
: 'border-transparent bg-components-input-bg-normal text-text-tertiary hover:bg-components-input-bg-hover',
)}
/>
)}

View File

@ -0,0 +1,108 @@
import type { ReactNode } from 'react'
import type { SnippetDetail } from '@/models/snippet'
import { render, screen } from '@testing-library/react'
import SnippetLayout from '../snippet-layout'
const mockSetAppSidebarExpand = vi.fn()
const mockUseDocumentTitle = vi.fn()
vi.mock('@/app/components/app/store', () => ({
useStore: (selector: (state: { setAppSidebarExpand: typeof mockSetAppSidebarExpand }) => unknown) => selector({
setAppSidebarExpand: mockSetAppSidebarExpand,
}),
}))
vi.mock('@/hooks/use-breakpoints', () => ({
default: () => 'desktop',
MediaType: {
mobile: 'mobile',
desktop: 'desktop',
},
}))
vi.mock('@/hooks/use-document-title', () => ({
default: (title: string) => mockUseDocumentTitle(title),
}))
vi.mock('@/app/components/app-sidebar', () => ({
default: ({
renderHeader,
renderNavigation,
}: {
renderHeader?: (mode: string) => ReactNode
renderNavigation?: (mode: string) => ReactNode
}) => (
<div data-testid="app-sidebar">
{renderHeader?.('expand')}
{renderNavigation?.('expand')}
</div>
),
}))
vi.mock('@/app/components/app-sidebar/nav-link', () => ({
default: ({ name, href, active }: { name: string, href: string, active: boolean }) => (
<a
aria-current={active ? 'page' : undefined}
href={href}
>
{name}
</a>
),
}))
vi.mock('@/app/components/app-sidebar/snippet-info', () => ({
default: ({ snippet }: { snippet: SnippetDetail }) => <div>{snippet.name}</div>,
}))
const createSnippet = (overrides: Partial<SnippetDetail> = {}): SnippetDetail => ({
id: 'snippet-1',
name: 'Snippet Title',
description: 'Snippet description',
author: 'tester',
updatedAt: '2026-04-15',
usage: '42',
icon: 'emoji',
iconBackground: '#ffffff',
...overrides,
})
describe('SnippetLayout', () => {
beforeEach(() => {
vi.clearAllMocks()
localStorage.clear()
})
describe('Document title', () => {
it('should set the document title to the snippet name when snippet detail is available', () => {
render(
<SnippetLayout
snippetId="snippet-1"
snippet={createSnippet()}
section="orchestrate"
>
<div>content</div>
</SnippetLayout>,
)
expect(mockUseDocumentTitle).toHaveBeenCalledWith('Snippet Title')
})
})
describe('Navigation', () => {
it('should render snippet navigation links', () => {
render(
<SnippetLayout
snippetId="snippet-1"
snippet={createSnippet()}
section="evaluation"
>
<div>content</div>
</SnippetLayout>,
)
expect(screen.getByRole('link', { name: 'snippet.sectionOrchestrate' })).toHaveAttribute('href', '/snippets/snippet-1/orchestrate')
expect(screen.getByRole('link', { name: 'snippet.sectionEvaluation' })).toHaveAttribute('href', '/snippets/snippet-1/evaluation')
expect(screen.getByRole('link', { name: 'snippet.sectionEvaluation' })).toHaveAttribute('aria-current', 'page')
})
})
})

View File

@ -16,6 +16,7 @@ import NavLink from '@/app/components/app-sidebar/nav-link'
import SnippetInfo from '@/app/components/app-sidebar/snippet-info'
import { useStore as useAppStore } from '@/app/components/app/store'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import useDocumentTitle from '@/hooks/use-document-title'
type SnippetLayoutProps = {
children: ReactNode
@ -45,6 +46,8 @@ const SnippetLayout = ({
const isMobile = media === MediaType.mobile
const setAppSidebarExpand = useAppStore(state => state.setAppSidebarExpand)
useDocumentTitle(snippet.name || t('typeLabel'))
useEffect(() => {
const localeMode = localStorage.getItem('app-detail-collapse-or-expand') || 'expand'
const mode = isMobile ? 'collapse' : 'expand'