mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
wip
fix: docs
This commit is contained in:
@@ -13,6 +13,7 @@ import { useEffect, useRef } from 'react'
|
||||
import { useSyncExternalStore } from 'react'
|
||||
import clsx from 'clsx'
|
||||
import { IconCheckOutline16, useAnchoredMaxHeight } from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'
|
||||
import { filterOptions } from './popup.ts'
|
||||
import type { PopupSelectController } from './popup.ts'
|
||||
import css from './PopupSelectView.module.css'
|
||||
@@ -26,12 +27,15 @@ export interface PopupSelectInjected {
|
||||
popup: PopupSelectController
|
||||
}
|
||||
|
||||
/** Full shell props: injected face + the locale seat. */
|
||||
export type PopupSelectViewProps = PopupSelectInjected & PropsLocale<'command'>
|
||||
|
||||
/**
|
||||
* Render the popupSelect shell overlay entry.
|
||||
* @param props - injected face: the session's shell controller.
|
||||
* @param props - injected face: the session's shell controller; `t` rides the standard locale seat.
|
||||
* @returns the select card while open; null while closed.
|
||||
*/
|
||||
export function PopupSelectView({ popup }: PopupSelectInjected) {
|
||||
export function PopupSelectView({ popup, t }: PopupSelectViewProps) {
|
||||
const state = useSyncExternalStore(
|
||||
fn => popup.state.subscribe(fn),
|
||||
() => popup.state.getSnapshot(),
|
||||
@@ -103,15 +107,15 @@ export function PopupSelectView({ popup }: PopupSelectInjected) {
|
||||
ref={cardRef}
|
||||
className={css.card}
|
||||
style={{ maxHeight }}
|
||||
aria-label={`/${String(state.command)} options`}
|
||||
aria-label={t('overlay.aria', { command: String(state.command) })}
|
||||
onKeyDown={onKeyDown}
|
||||
>
|
||||
<input
|
||||
ref={searchRef}
|
||||
className={css.search}
|
||||
type="text"
|
||||
placeholder="Search…"
|
||||
aria-label="Filter options"
|
||||
placeholder={t('search.placeholder')}
|
||||
aria-label={t('search.aria')}
|
||||
value={state.search}
|
||||
readOnly={state.submitting}
|
||||
onChange={(ev) => { popup.setSearch(ev.currentTarget.value) }}
|
||||
@@ -120,15 +124,15 @@ export function PopupSelectView({ popup }: PopupSelectInjected) {
|
||||
<div className={css.error} role="alert">
|
||||
<span className={css.errorText}>{state.error}</span>
|
||||
{state.status === 'failed' && (
|
||||
<button type="button" className={css.retry} onClick={() => { popup.retry() }}>Retry</button>
|
||||
<button type="button" className={css.retry} onClick={() => { popup.retry() }}>{t('retry')}</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{state.status === 'pending' && <div className={css.status}>Loading options…</div>}
|
||||
{state.submitting && <div className={css.status}>Applying…</div>}
|
||||
{state.status === 'ready' && rows.length === 0 && <div className={css.status}>No options</div>}
|
||||
{state.status === 'pending' && <div className={css.status}>{t('status.loading')}</div>}
|
||||
{state.submitting && <div className={css.status}>{t('status.applying')}</div>}
|
||||
{state.status === 'ready' && rows.length === 0 && <div className={css.status}>{t('status.empty')}</div>}
|
||||
{state.status === 'ready' && (
|
||||
<div role="listbox" aria-label={`/${String(state.command)} matches`} className={css.viewport}>
|
||||
<div role="listbox" aria-label={t('listbox.aria', { command: String(state.command) })} className={css.viewport}>
|
||||
{rows.map((option, index) => (
|
||||
<div
|
||||
key={option.id}
|
||||
|
||||
@@ -10,19 +10,23 @@ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'
|
||||
// key's owner) into this program so the overlay registration below typechecks
|
||||
// against the real declaration — no runtime edge to ui-conversation.
|
||||
import type {} from '@deepseek-ai/dsh-client-ui-conversation/client'
|
||||
// Type-only: pulls the locale plugin's Context merge (ctx.locale).
|
||||
import type {} from '@deepseek-ai/dsh-client-locale/client'
|
||||
import { CommandService } from './service.ts'
|
||||
import type { PopupSelectInjected } from './PopupSelectView.tsx'
|
||||
import { PopupSelectView } from './PopupSelectView.tsx'
|
||||
import { en, zh, type CommandKey } from './locales.ts'
|
||||
|
||||
export { CommandService } from './service.ts'
|
||||
export { CommandDirectory } from './directory.ts'
|
||||
export type { CommandDescriptor, DirectoryStatus } from './directory.ts'
|
||||
export { filterOptions, PopupSelectController } from './popup.ts'
|
||||
export type { PopupSelectDeps, PopupSpec, PopupState, TokenSegment } from './popup.ts'
|
||||
export type { PopupSelectInjected } from './PopupSelectView.tsx'
|
||||
export type { PopupSelectInjected, PopupSelectViewProps } from './PopupSelectView.tsx'
|
||||
export type {
|
||||
CommandContribution, CommandDecoration, CommandServiceContract, CommandUiSpec, SelectOption,
|
||||
} from './contract.ts'
|
||||
export type { CommandKey } from './locales.ts'
|
||||
|
||||
declare module 'cordis' {
|
||||
interface Context {
|
||||
@@ -30,8 +34,18 @@ declare module 'cordis' {
|
||||
}
|
||||
}
|
||||
|
||||
/** Required services: the '/' source registry plus the scope + wire faces the service reads. */
|
||||
export const inject = ['slash', 'sessions', 'connection']
|
||||
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
||||
interface LocaleNamespaceMap {
|
||||
/** The popupSelect shell's copy. */
|
||||
command: CommandKey
|
||||
}
|
||||
}
|
||||
|
||||
/** Dictionary namespace owned by this plugin. */
|
||||
const NS = 'command'
|
||||
|
||||
/** Required services: the '/' source registry plus the scope + wire faces the service reads, and the copy's locale registry. */
|
||||
export const inject = ['slash', 'sessions', 'connection', 'locale']
|
||||
|
||||
/**
|
||||
* Client plugin body: mount the service, then register the popupSelect shell
|
||||
@@ -39,6 +53,7 @@ export const inject = ['slash', 'sessions', 'connection']
|
||||
* @param ctx - client root context.
|
||||
*/
|
||||
export function apply(ctx: ClientContext): void {
|
||||
ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'ui-command: dictionaries')
|
||||
ctx.plugin(CommandService)
|
||||
// Conditional mount, same seam as ui-slash's MenuView registration:
|
||||
// 'conversation.input.overlay' is declared by the conversation composer
|
||||
@@ -51,6 +66,7 @@ export function apply(ctx: ClientContext): void {
|
||||
name: 'conversation.input.overlay',
|
||||
id: 'command-popup',
|
||||
order: 1,
|
||||
locale: NS,
|
||||
inject: (sessionId): PopupSelectInjected => {
|
||||
const actx = sessions.scope(sessionId)
|
||||
if (actx === undefined) throw new Error(`ui-command: session "${String(sessionId)}" resolved no scope`)
|
||||
|
||||
26
packages/client/ui-command/src/client/locales.ts
Normal file
26
packages/client/ui-command/src/client/locales.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/** `command` namespace dictionaries (the popupSelect shell's copy). */
|
||||
|
||||
/** Simplified Chinese dictionary (the key-set source of truth). */
|
||||
export const zh = {
|
||||
'search.placeholder': '搜索…',
|
||||
'search.aria': '筛选选项',
|
||||
'status.loading': '正在加载选项…',
|
||||
'status.applying': '正在应用…',
|
||||
'status.empty': '无选项',
|
||||
'overlay.aria': '/{command} 选项',
|
||||
'listbox.aria': '/{command} 匹配项',
|
||||
} satisfies Record<string, string>
|
||||
|
||||
/** The command namespace key union. */
|
||||
export type CommandKey = keyof typeof zh
|
||||
|
||||
/** English dictionary, checked complete against the zh key set. */
|
||||
export const en = {
|
||||
'search.placeholder': 'Search…',
|
||||
'search.aria': 'Filter options',
|
||||
'status.loading': 'Loading options…',
|
||||
'status.applying': 'Applying…',
|
||||
'status.empty': 'No options',
|
||||
'overlay.aria': '/{command} options',
|
||||
'listbox.aria': '/{command} matches',
|
||||
} satisfies Record<CommandKey, string>
|
||||
Reference in New Issue
Block a user