feat(web): render durable session titles

This commit is contained in:
Tianyi Cui
2026-07-22 23:43:53 +08:00
parent 690c53dc03
commit a9ea193e31
39 changed files with 481 additions and 57 deletions

View File

@@ -0,0 +1,22 @@
import { useEffect, useRef } from 'react'
/** Props for the shell-owned browser title projection. */
export interface DocumentTitleProps {
/** Durable title of the selected session, or undefined for the product title. */
title?: string
}
/**
* Project the selected durable session title into the browser title and
* restore the shell's original product title when unmounted.
* @param props - selected session title projection.
* @returns no rendered content.
*/
export function DocumentTitle({ title }: DocumentTitleProps): null {
const original = useRef(document.title)
useEffect(() => {
document.title = title === undefined ? original.current : `${title} — ${original.current}`
return () => { document.title = original.current }
}, [title])
return null
}

View File

@@ -11,6 +11,7 @@ import {
createSessionProvider, RootBindingProvider, scopedSlots,
} from '@deepseek-ai/dsh-client-web-react'
import type { SessionId, SessionsService } from '@deepseek-ai/dsh-client-runtime/client'
import { DocumentTitle } from './DocumentTitle.tsx'
type LayoutExports = typeof import('@deepseek-ai/dsh-client-ui-layout/client')
@@ -47,6 +48,11 @@ export function buildRenderApp(deps: AssemblyDeps): () => ReactNode {
const useDetails = layout.details.useSelector
const setSidebarWidth = (px: number): void => { layout.setSidebarWidth(px) }
const setDetailsWidth = (px: number): void => { layout.setDetailsWidth(px) }
const SessionDocumentTitle = (): ReactNode => {
const id = useCurrent()
const title = sessions.list.useSelector(state => id === undefined ? undefined : state.byId[id]?.title)
return <DocumentTitle {...title === undefined ? {} : { title }} />
}
const renderBody = (id: SessionId): ReactNode => (
<>
@@ -75,6 +81,7 @@ export function buildRenderApp(deps: AssemblyDeps): () => ReactNode {
return () => (
<RootBindingProvider value={rootBinding}>
<SessionDocumentTitle />
<AppFrame
useSidebar={useSidebar}
useDetails={useDetails}

View File

@@ -8,4 +8,5 @@
export { bootWebShell } from './boot.tsx'
export { AppRoot, type AppRootProps } from './AppRoot.tsx'
export { buildRenderApp, type AssemblyDeps } from './app.tsx'
export { DocumentTitle, type DocumentTitleProps } from './DocumentTitle.tsx'
export { seedModules } from './seed.ts'