dsh-claude-desktop-theme 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +54 -0
- package/README.md +197 -0
- package/cordis.patch.yml +5 -0
- package/lib/client.js +5492 -0
- package/lib/index.js +666 -0
- package/lib/types/client/apply.d.ts +25 -0
- package/lib/types/client/compat/account-menu.d.ts +52 -0
- package/lib/types/client/compat/adapter.d.ts +17 -0
- package/lib/types/client/compat/blank-session-rows.d.ts +74 -0
- package/lib/types/client/compat/composer-menus.d.ts +11 -0
- package/lib/types/client/compat/composer-placeholder.d.ts +3 -0
- package/lib/types/client/compat/composer-status-order.d.ts +56 -0
- package/lib/types/client/compat/conversation-fade.d.ts +37 -0
- package/lib/types/client/compat/dom.d.ts +2 -0
- package/lib/types/client/compat/header-labels.d.ts +24 -0
- package/lib/types/client/compat/host-builds.d.ts +101 -0
- package/lib/types/client/compat/host-dom.d.ts +247 -0
- package/lib/types/client/compat/open-target.d.ts +9 -0
- package/lib/types/client/compat/pet-anchor.d.ts +30 -0
- package/lib/types/client/compat/plugin-manager.d.ts +32 -0
- package/lib/types/client/compat/session-menu.d.ts +47 -0
- package/lib/types/client/compat/slots.d.ts +21 -0
- package/lib/types/client/compat/stats-values.d.ts +20 -0
- package/lib/types/client/compat/view-switch.d.ts +14 -0
- package/lib/types/client/compat/workspace-menu.d.ts +15 -0
- package/lib/types/client/contracts/feature.d.ts +22 -0
- package/lib/types/client/contracts/ports.d.ts +169 -0
- package/lib/types/client/core/cleanup.d.ts +10 -0
- package/lib/types/client/core/mount-features.d.ts +3 -0
- package/lib/types/client/features/composer-pet/BlankPet.d.ts +17 -0
- package/lib/types/client/features/composer-pet/ComposerPet.d.ts +7 -0
- package/lib/types/client/features/composer-pet/Whale.d.ts +18 -0
- package/lib/types/client/features/composer-pet/mount.d.ts +9 -0
- package/lib/types/client/features/composer-pet/reactions.d.ts +15 -0
- package/lib/types/client/features/conversation/header-actions/HeaderActionButton.d.ts +25 -0
- package/lib/types/client/features/conversation/header-actions/entries.d.ts +101 -0
- package/lib/types/client/features/conversation/header-actions/mount.d.ts +28 -0
- package/lib/types/client/features/conversation/header-actions/sidebar-view.d.ts +21 -0
- package/lib/types/client/features/conversation/index.d.ts +16 -0
- package/lib/types/client/features/model-controls/EffortPanel.d.ts +14 -0
- package/lib/types/client/features/model-controls/ModelControls.d.ts +11 -0
- package/lib/types/client/features/model-controls/mount.d.ts +5 -0
- package/lib/types/client/features/model-controls/pixels.d.ts +4 -0
- package/lib/types/client/features/model-controls/popup.d.ts +10 -0
- package/lib/types/client/features/model-controls/selection.d.ts +66 -0
- package/lib/types/client/features/new-session/index.d.ts +8 -0
- package/lib/types/client/features/settings/ConfigPage.d.ts +28 -0
- package/lib/types/client/features/settings/FontMenu.d.ts +37 -0
- package/lib/types/client/features/settings/edits.d.ts +39 -0
- package/lib/types/client/features/settings/fields.d.ts +83 -0
- package/lib/types/client/features/settings/fonts.d.ts +40 -0
- package/lib/types/client/features/settings/locales.d.ts +61 -0
- package/lib/types/client/features/settings/mount.d.ts +17 -0
- package/lib/types/client/features/settings/register.d.ts +17 -0
- package/lib/types/client/features/shell/index.d.ts +8 -0
- package/lib/types/client/features/sidebar/index.d.ts +14 -0
- package/lib/types/client/features/statistics/books.d.ts +34 -0
- package/lib/types/client/features/statistics/card.d.ts +143 -0
- package/lib/types/client/features/statistics/format.d.ts +36 -0
- package/lib/types/client/features/statistics/index.d.ts +8 -0
- package/lib/types/client/features/statistics/mount.d.ts +12 -0
- package/lib/types/client/features/statistics/source.d.ts +35 -0
- package/lib/types/client/features/statistics/view.d.ts +95 -0
- package/lib/types/client/features/tool-calls/index.d.ts +2 -0
- package/lib/types/client/index.d.ts +1 -0
- package/lib/types/client/theme/mount.d.ts +15 -0
- package/lib/types/client/theme/palette.d.ts +80 -0
- package/lib/types/client/theme/tokens.d.ts +27 -0
- package/lib/types/host/index.d.ts +106 -0
- package/lib/types/host/stats/aggregate.d.ts +38 -0
- package/lib/types/host/stats/service.d.ts +18 -0
- package/lib/types/host/stats/unit.d.ts +115 -0
- package/lib/types/shared/config.d.ts +61 -0
- package/lib/types/shared/identity.d.ts +5 -0
- package/lib/types/shared/stats.d.ts +133 -0
- package/package.json +116 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ImplementedFeature } from '../../contracts/feature.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Conversation page presentation. The transcript, its scroll behaviour, tool
|
|
4
|
+
* rows, approvals and the resident Composer are all DSH's; this module only
|
|
5
|
+
* adapts the header chrome, the transcript column and the message surfaces.
|
|
6
|
+
*
|
|
7
|
+
* The header keeps DSH's own View switcher: the host still owns which View is
|
|
8
|
+
* selected and how it is rendered, and this module only moves the tablist onto
|
|
9
|
+
* the title line and publishes the selected segment's geometry so the
|
|
10
|
+
* stylesheet can slide the thumb onto it.
|
|
11
|
+
*
|
|
12
|
+
* The transcript's own edge fade is published the same way: the host owns the
|
|
13
|
+
* scroll position, `compat/conversation-fade.ts` turns it into two attributes,
|
|
14
|
+
* and the stylesheet prints the stencil.
|
|
15
|
+
*/
|
|
16
|
+
export declare const conversationFeature: ImplementedFeature;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
import type { EffortChoice } from './selection.ts';
|
|
3
|
+
export interface EffortPanelProps {
|
|
4
|
+
readonly anchor: RefObject<HTMLButtonElement>;
|
|
5
|
+
readonly choices: readonly EffortChoice[];
|
|
6
|
+
readonly selected: number;
|
|
7
|
+
readonly disabled: boolean;
|
|
8
|
+
readonly busy: boolean;
|
|
9
|
+
readonly error: string | null;
|
|
10
|
+
readonly onCommit: (index: number) => void;
|
|
11
|
+
readonly onClose: () => void;
|
|
12
|
+
}
|
|
13
|
+
/** Presentation-only slider: continuous local preview, one supported choice on release. */
|
|
14
|
+
export declare function EffortPanel({ anchor, choices, selected, disabled, busy, error, onCommit, onClose }: EffortPanelProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ModelSelectInjected } from '@deepseek-ai/dsh-client-ui-model-selection/client';
|
|
2
|
+
import type { ModelDirectoryState } from '@deepseek-ai/dsh-client-ui-model-selection/client';
|
|
3
|
+
import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
|
|
4
|
+
import type { ModelSelection } from '@deepseek-ai/dsh-api-session-controller/types';
|
|
5
|
+
export type ModelControlsProps = Omit<ModelSelectInjected, 'directory'> & PropsLocale<'model'> & {
|
|
6
|
+
readonly locked: boolean;
|
|
7
|
+
readonly useDirectory: () => ModelDirectoryState;
|
|
8
|
+
readonly selectEffort: (route: ModelSelection, effort: string | undefined) => void;
|
|
9
|
+
};
|
|
10
|
+
/** SDK-derived values/hooks and callbacks only; DSH retains all business state. */
|
|
11
|
+
export declare function ModelControls({ locked, available, useDirectory, load, select, selectEffort, t }: ModelControlsProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { FeatureEnvironment } from '../../contracts/feature.ts';
|
|
3
|
+
import type { CleanupScope } from '../../core/cleanup.ts';
|
|
4
|
+
/** Register a presentation occupant over the native seat, sharing its official directory. */
|
|
5
|
+
export declare function mountModelControls(ctx: Context, environment: FeatureEnvironment, cleanup: CleanupScope): void;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Pixel flow and magnetic/spring constants adapted from zanwei/claude-model-selector, MIT. */
|
|
2
|
+
export declare const clamp: (value: number, min: number, max: number) => number;
|
|
3
|
+
export declare function magnet(value: number): number;
|
|
4
|
+
export declare function drawPixelField(canvas: HTMLCanvasElement, elapsed: number, reduced: boolean): void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
/** Viewport-clamped top-layer surface; focus and observers die with the panel. */
|
|
3
|
+
export declare function usePopup(anchor: RefObject<HTMLButtonElement>, close: () => void): {
|
|
4
|
+
panel: RefObject<HTMLDivElement>;
|
|
5
|
+
position: {
|
|
6
|
+
left: number;
|
|
7
|
+
top: number;
|
|
8
|
+
visibility: 'hidden' | 'visible';
|
|
9
|
+
};
|
|
10
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { ModelDirectoryState } from '@deepseek-ai/dsh-client-ui-model-selection/client';
|
|
2
|
+
import type { ModelCatalogModel, ModelSelection } from '@deepseek-ai/dsh-api-session-controller/types';
|
|
3
|
+
export interface EffortChoice {
|
|
4
|
+
readonly id: string | undefined;
|
|
5
|
+
readonly name: string;
|
|
6
|
+
}
|
|
7
|
+
/** What the Effort card derives from one catalog route and its saved selection. */
|
|
8
|
+
export interface EffortView {
|
|
9
|
+
/** Slider stops: the advertised tiers in provider order; empty when the model advertises none. */
|
|
10
|
+
readonly choices: readonly EffortChoice[];
|
|
11
|
+
/** Stop the thumb rests on before any drag: the saved tier, else the provider's own tier, else the first stop. */
|
|
12
|
+
readonly preview: number;
|
|
13
|
+
/** Effective effort id: the saved tier, else the provider's advertised default. */
|
|
14
|
+
readonly effort: string | undefined;
|
|
15
|
+
/** Caption the trigger shows: the name of the stop `preview` marks, else the retained one, else the empty-catalog fallback. */
|
|
16
|
+
readonly caption: string | undefined;
|
|
17
|
+
}
|
|
18
|
+
/** The two captions the card cannot derive from the catalog alone. */
|
|
19
|
+
export interface EffortViewCopy {
|
|
20
|
+
/** Fallback caption for a catalog that answers with no tier to name, read only where the trigger stays disabled. */
|
|
21
|
+
readonly defaultName: string;
|
|
22
|
+
/** Caption the directory retained for a route that left the catalog. */
|
|
23
|
+
readonly retainedEffort?: string | undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Derive the commit-time validation domain of one route.
|
|
27
|
+
*
|
|
28
|
+
* The card's stops are the advertised tiers alone — see `effortView`, which
|
|
29
|
+
* lays the slider out — so this list is not what the panel shows. It is kept
|
|
30
|
+
* because `effortSelection` validates against it, and that domain is the
|
|
31
|
+
* historical one: a catalog naming no default still admits `undefined` as
|
|
32
|
+
* "follow the provider default" beside every tier it advertises.
|
|
33
|
+
*
|
|
34
|
+
* @param model - the route's catalog model.
|
|
35
|
+
* @param defaultName - caption the absent default is admitted under.
|
|
36
|
+
* @returns every id a commit may carry, in provider order.
|
|
37
|
+
*/
|
|
38
|
+
export declare function effortChoices(model: ModelCatalogModel | undefined, defaultName: string): EffortChoice[];
|
|
39
|
+
/**
|
|
40
|
+
* Lay out the card's stops, the resting thumb, and the trigger caption.
|
|
41
|
+
*
|
|
42
|
+
* The stops are the model's advertised tiers in provider order: the provider
|
|
43
|
+
* default is a *position* on that track, never a stop of its own, so a catalog
|
|
44
|
+
* that names no default — or names one its tiers do not carry — has no position
|
|
45
|
+
* to mark rather than an extra stop to show. `preview` rests the thumb on the
|
|
46
|
+
* saved tier while the catalog still carries it, else on the tier the provider
|
|
47
|
+
* names as its default, else on the first stop: the historical resting place,
|
|
48
|
+
* now reached without a Default stop to fall back onto.
|
|
49
|
+
*
|
|
50
|
+
* The caption names the stop the thumb rests on, so the trigger can never
|
|
51
|
+
* advertise a tier the panel has no stop for. Two states stay outside that
|
|
52
|
+
* reading because the catalog cannot name them: a route that left the catalog
|
|
53
|
+
* keeps the directory's retained caption, and a route with nothing on the
|
|
54
|
+
* track keeps `copy.defaultName` — the host's own wording — as its only
|
|
55
|
+
* honest fallback, on a trigger that is disabled and opens no panel anyway.
|
|
56
|
+
*
|
|
57
|
+
* @param model - the route's catalog model.
|
|
58
|
+
* @param current - the saved selection of that same route.
|
|
59
|
+
* @param copy - the empty-catalog caption and the directory's retained one.
|
|
60
|
+
* @returns stops, the resting thumb, the effective effort id, and the trigger caption.
|
|
61
|
+
*/
|
|
62
|
+
export declare function effortView(model: ModelCatalogModel | undefined, current: ModelSelection | null, copy: EffortViewCopy): EffortView;
|
|
63
|
+
/** Same-model picks retain effort; a different model starts at its own default. */
|
|
64
|
+
export declare function modelSelection(provider: string, model: ModelCatalogModel, current: ModelSelection | null): ModelSelection;
|
|
65
|
+
/** Read the latest directory at commit time so a stale drag cannot change another model. */
|
|
66
|
+
export declare function effortSelection(state: ModelDirectoryState, route: ModelSelection, effort: string | undefined): ModelSelection | null;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ImplementedFeature } from '../../contracts/feature.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Blank-session page. DSH renders the Conversation shell in its `hero` phase
|
|
4
|
+
* here, so this module only moves what the reference moves — the greeting to
|
|
5
|
+
* the top of the column and the Composer block to the bottom — and leaves the
|
|
6
|
+
* phase transition itself to the host.
|
|
7
|
+
*/
|
|
8
|
+
export declare const newSessionFeature: ImplementedFeature;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import type { ConfigFormPort, ThemePreferencePort } from '../../contracts/ports.ts';
|
|
3
|
+
/** Translate one dictionary key; the locale seat supplies the real one. */
|
|
4
|
+
export type SettingsTranslate = (key: string, params?: Record<string, unknown>) => string;
|
|
5
|
+
/** Props the registration layer derives; the component never sees `ctx`. */
|
|
6
|
+
export interface ConfigPageProps {
|
|
7
|
+
/** Page host's occurrence view: `summary` beside a row title, `page` for the form. */
|
|
8
|
+
readonly view?: string | undefined;
|
|
9
|
+
/** Locale seat synthesized from the registration's namespace. */
|
|
10
|
+
readonly t?: SettingsTranslate | undefined;
|
|
11
|
+
/** This plugin's own configuration form, passed by the assembly layer. */
|
|
12
|
+
readonly form: ConfigFormPort;
|
|
13
|
+
/** The native theme preference, or null when the theme service lacks it. */
|
|
14
|
+
readonly themePreference?: ThemePreferencePort | null | undefined;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The row configuration page registered for `plugins.row.config`.
|
|
18
|
+
*
|
|
19
|
+
* The page writes as you go: a switch, a colour, a chosen family or a settled
|
|
20
|
+
* text field is submitted immediately, so there is no save button and no draft
|
|
21
|
+
* to reconcile — the served configuration is the only state the controls read.
|
|
22
|
+
* Text fields keep a local buffer until they are left or confirmed, because a
|
|
23
|
+
* half-typed colour must not reach the settings boundary.
|
|
24
|
+
* @param props - Occurrence view, locale seat, the plugin's form and the
|
|
25
|
+
* features whose mounts are still planned.
|
|
26
|
+
* @returns The summary line or the configuration form.
|
|
27
|
+
*/
|
|
28
|
+
export declare function ConfigPage(props: ConfigPageProps): ReactElement;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The installed-family menu behind a typeface row's select box.
|
|
4
|
+
*
|
|
5
|
+
* It is drawn by the plugin rather than by a native `<datalist>`: the native
|
|
6
|
+
* popup is an OS widget that ignores this page's styles and, in the desktop
|
|
7
|
+
* window, does not scroll with the wheel — with several hundred families that
|
|
8
|
+
* is unusable. The panel is positioned against the select box and closed by
|
|
9
|
+
* Escape, an outside click, a scroll or a resize.
|
|
10
|
+
*/
|
|
11
|
+
export interface FontMenuLabels {
|
|
12
|
+
readonly search: string;
|
|
13
|
+
readonly empty: string;
|
|
14
|
+
readonly count: (count: number) => string;
|
|
15
|
+
readonly unavailable: string;
|
|
16
|
+
/** Row offered for a family the list does not carry. */
|
|
17
|
+
readonly useTyped: (name: string) => string;
|
|
18
|
+
}
|
|
19
|
+
export interface FontMenuProps {
|
|
20
|
+
/** The select box this menu hangs from; the menu follows it while it scrolls. */
|
|
21
|
+
readonly anchor: HTMLElement;
|
|
22
|
+
/** Installed families; empty when the environment cannot provide them. */
|
|
23
|
+
readonly families: readonly string[];
|
|
24
|
+
/** The served family, marked in the list. */
|
|
25
|
+
readonly value: string;
|
|
26
|
+
readonly labels: FontMenuLabels;
|
|
27
|
+
readonly onSelect: (family: string) => void;
|
|
28
|
+
/** Commit a family the list does not carry, typed into the search field. */
|
|
29
|
+
readonly onUseText: (text: string) => void;
|
|
30
|
+
readonly onClose: () => void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* One open family menu.
|
|
34
|
+
* @param props - The anchor rectangle, the families, the served value and callbacks.
|
|
35
|
+
* @returns The searchable, scrollable panel.
|
|
36
|
+
*/
|
|
37
|
+
export declare function FontMenu(props: FontMenuProps): ReactElement;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { SettingsPathOp } from '../../contracts/ports.ts';
|
|
2
|
+
import type { SettingsKey } from './locales.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Field edits for a page that writes as you go.
|
|
5
|
+
*
|
|
6
|
+
* There is no draft: every control commits the moment its value is settled, so
|
|
7
|
+
* each helper below turns one settled input into the single operation the
|
|
8
|
+
* settings transport should carry — or into the reason it must not be sent.
|
|
9
|
+
*/
|
|
10
|
+
/** Per-field validation failures, keyed by dictionary label. */
|
|
11
|
+
export type FieldErrors = Partial<Record<string, SettingsKey>>;
|
|
12
|
+
/** One field write. */
|
|
13
|
+
export declare function setOperation(path: readonly string[], value: unknown): SettingsPathOp;
|
|
14
|
+
/** One field clear, restoring the schema default. */
|
|
15
|
+
export declare function unsetOperation(path: readonly string[]): SettingsPathOp;
|
|
16
|
+
export interface TextCommit {
|
|
17
|
+
/** The write to send, absent when nothing changed or the value is unusable. */
|
|
18
|
+
readonly op?: SettingsPathOp;
|
|
19
|
+
/** Why an unusable value was refused. */
|
|
20
|
+
readonly error?: SettingsKey;
|
|
21
|
+
/** The text the field should keep showing. */
|
|
22
|
+
readonly text: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Settle one colour field.
|
|
26
|
+
* @param path - the field's path inside the configuration section.
|
|
27
|
+
* @param raw - what the field currently shows.
|
|
28
|
+
* @param current - the served value it started from.
|
|
29
|
+
* @returns the write, the refusal, or nothing when the value already matches.
|
|
30
|
+
*/
|
|
31
|
+
export declare function commitColour(path: readonly string[], raw: string, current: string): TextCommit;
|
|
32
|
+
/**
|
|
33
|
+
* Settle one typeface field.
|
|
34
|
+
* @param path - the field's path inside the configuration section.
|
|
35
|
+
* @param raw - what the field currently shows.
|
|
36
|
+
* @param current - the served value it started from.
|
|
37
|
+
* @returns the write, the refusal, or nothing when the value already matches.
|
|
38
|
+
*/
|
|
39
|
+
export declare function commitFont(path: readonly string[], raw: string, current: string): TextCommit;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { MouseEvent, ReactElement } from 'react';
|
|
2
|
+
import type { ThemePreference } from '../../contracts/ports.ts';
|
|
3
|
+
import type { FontMenuLabels } from './FontMenu.tsx';
|
|
4
|
+
export interface SwitchRowProps {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly label: string;
|
|
7
|
+
readonly hint?: string;
|
|
8
|
+
readonly checked: boolean;
|
|
9
|
+
readonly onChange: (checked: boolean) => void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* One boolean row: a labelled sliding switch, the shape the host's own settings
|
|
13
|
+
* rows use.
|
|
14
|
+
* @param props - Identity, copy, current value and the change callback.
|
|
15
|
+
* @returns The row.
|
|
16
|
+
*/
|
|
17
|
+
export declare function SwitchRow({ id, label, hint, checked, onChange }: SwitchRowProps): ReactElement;
|
|
18
|
+
export interface ThemeOption {
|
|
19
|
+
readonly id: ThemePreference;
|
|
20
|
+
readonly label: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ThemeRowProps {
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly label: string;
|
|
25
|
+
readonly hint?: string;
|
|
26
|
+
/** The persisted preference, straight from the theme service snapshot. */
|
|
27
|
+
readonly value: ThemePreference;
|
|
28
|
+
readonly options: readonly ThemeOption[];
|
|
29
|
+
readonly onChange: (preference: ThemePreference) => void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* One theme row: a recessed track with one glyph per preference and the chosen
|
|
33
|
+
* segment raised, the shape the reference screenshot uses. The value is the
|
|
34
|
+
* service's own preference, never a local copy, so the control cannot disagree
|
|
35
|
+
* with the host's Appearance row.
|
|
36
|
+
* @param props - Identity, copy, current preference and the change callback.
|
|
37
|
+
* @returns The row.
|
|
38
|
+
*/
|
|
39
|
+
export declare function ThemeRow(props: ThemeRowProps): ReactElement;
|
|
40
|
+
export interface ColourRowProps {
|
|
41
|
+
readonly id: string;
|
|
42
|
+
readonly label: string;
|
|
43
|
+
readonly hint?: string;
|
|
44
|
+
readonly value: string;
|
|
45
|
+
readonly placeholder: string;
|
|
46
|
+
readonly resetLabel: string;
|
|
47
|
+
readonly error?: string;
|
|
48
|
+
readonly onChange: (value: string) => void;
|
|
49
|
+
readonly onCommit: () => void;
|
|
50
|
+
readonly onReset: () => void;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* One background-colour row: a bordered hex field, written when it is left.
|
|
54
|
+
* @param props - Identity, copy, current text and callbacks.
|
|
55
|
+
* @returns The row.
|
|
56
|
+
*/
|
|
57
|
+
export declare function ColourRow(props: ColourRowProps): ReactElement;
|
|
58
|
+
export interface FontRowProps {
|
|
59
|
+
readonly id: string;
|
|
60
|
+
readonly label: string;
|
|
61
|
+
readonly hint?: string;
|
|
62
|
+
readonly value: string;
|
|
63
|
+
readonly placeholder: string;
|
|
64
|
+
readonly resetLabel: string;
|
|
65
|
+
readonly error?: string;
|
|
66
|
+
/** The open family menu's anchor box, or undefined while it is closed. */
|
|
67
|
+
readonly anchor: HTMLElement | undefined;
|
|
68
|
+
readonly families: readonly string[];
|
|
69
|
+
readonly menuLabels: FontMenuLabels;
|
|
70
|
+
readonly onToggle: (event: MouseEvent<HTMLButtonElement>) => void;
|
|
71
|
+
readonly onSelect: (family: string) => void;
|
|
72
|
+
readonly onUseText: (text: string) => void;
|
|
73
|
+
readonly onCloseMenu: () => void;
|
|
74
|
+
readonly onReset: () => void;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* One typeface row: a select box that shows the served family and opens the
|
|
78
|
+
* installed-family menu; a family the list does not carry can be typed into
|
|
79
|
+
* that menu's search field.
|
|
80
|
+
* @param props - Identity, copy, current value, menu state and callbacks.
|
|
81
|
+
* @returns The row and, when open, its menu.
|
|
82
|
+
*/
|
|
83
|
+
export declare function FontRow(props: FontRowProps): ReactElement;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System font families for the typeface rows.
|
|
3
|
+
*
|
|
4
|
+
* Chromium exposes installed fonts through the Local Font Access API
|
|
5
|
+
* (`window.queryLocalFonts()`, Chromium 103+). In the DSH desktop window the
|
|
6
|
+
* permission is granted without a prompt — the application's own permission
|
|
7
|
+
* handlers allow every non-media permission — while a plain browser either
|
|
8
|
+
* prompts or answers with an empty list; browsers without the API answer with
|
|
9
|
+
* nothing at all. All three outcomes collapse to "no list", and the rows keep
|
|
10
|
+
* accepting a typed family name.
|
|
11
|
+
*
|
|
12
|
+
* The query runs on first focus (a user gesture, which the permission needs)
|
|
13
|
+
* and the result is cached for the page session, so moving between rows or
|
|
14
|
+
* pages never asks twice.
|
|
15
|
+
*/
|
|
16
|
+
/** The slice of `FontData` this module reads. */
|
|
17
|
+
export interface LocalFontLike {
|
|
18
|
+
readonly family?: unknown;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Collapse font faces into the family names a `font-family` value accepts.
|
|
22
|
+
* @param fonts - faces as the browser reported them.
|
|
23
|
+
* @returns unique, non-empty family names sorted for a Chinese interface.
|
|
24
|
+
*/
|
|
25
|
+
export declare function collectFamilies(fonts: readonly LocalFontLike[]): string[];
|
|
26
|
+
/**
|
|
27
|
+
* Filter families for one query, case-insensitively.
|
|
28
|
+
* @param families - family names in their display order.
|
|
29
|
+
* @param query - what the user typed.
|
|
30
|
+
* @returns the matching families, order preserved.
|
|
31
|
+
*/
|
|
32
|
+
export declare function filterFamilies(families: readonly string[], query: string): string[];
|
|
33
|
+
/**
|
|
34
|
+
* Read the installed font families once per page session.
|
|
35
|
+
* @returns the sorted families, or an empty array when the environment cannot
|
|
36
|
+
* provide them (no API, denied permission, or an empty answer).
|
|
37
|
+
*/
|
|
38
|
+
export declare function loadSystemFontFamilies(): Promise<string[]>;
|
|
39
|
+
/** Test seam: forget the cached answer. */
|
|
40
|
+
export declare function resetSystemFontFamilies(): void;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copy for the row configuration page.
|
|
3
|
+
*
|
|
4
|
+
* The page is the plugin's only owned surface with its own words: everything
|
|
5
|
+
* else mirrors a host label. The dictionary is registered through the locale
|
|
6
|
+
* service and the keys are merged into the slots' namespace table, so the `t`
|
|
7
|
+
* seat stays typed and follows the user's language without a remount.
|
|
8
|
+
*/
|
|
9
|
+
export declare const SETTINGS_NAMESPACE = "ccdSettings";
|
|
10
|
+
/** Simplified Chinese dictionary; the key set is the source of truth. */
|
|
11
|
+
export declare const zh: {
|
|
12
|
+
readonly summary: 'CCD 风格界面 · 外观 · 字体';
|
|
13
|
+
readonly 'section.general': '通用';
|
|
14
|
+
readonly 'section.features': '模块';
|
|
15
|
+
readonly 'section.appearance': '外观';
|
|
16
|
+
readonly 'section.fonts': '字体';
|
|
17
|
+
readonly 'field.enabled': '启用 CCD 风格界面';
|
|
18
|
+
readonly 'field.theme': '主题';
|
|
19
|
+
readonly 'theme.system': '跟随系统';
|
|
20
|
+
readonly 'theme.light': '浅色';
|
|
21
|
+
readonly 'theme.dark': '深色';
|
|
22
|
+
readonly 'field.canvas': '会话背景色';
|
|
23
|
+
readonly 'field.sidebar': '侧栏背景色';
|
|
24
|
+
readonly 'note.coloursApplyToLight': '自定义背景色只作用于浅色模式;深色模式使用内置深色调色板。';
|
|
25
|
+
readonly 'note.unknownBuild': '当前 DSH 构建未登记:它的宿主类名与插件记录的两套构建都不一致,界面样式不会生效,请按 host-builds.ts 的说明重新登记。';
|
|
26
|
+
readonly 'field.uiLatin': '界面字体';
|
|
27
|
+
readonly 'field.uiCjk': '界面中文字体';
|
|
28
|
+
readonly 'field.code': '代码与等宽字体';
|
|
29
|
+
readonly 'hint.fontListUnavailable': '当前环境不提供系统字体清单,请直接输入字体族名(例如 PingFang SC)。';
|
|
30
|
+
readonly 'placeholder.font': '留空使用系统字体';
|
|
31
|
+
readonly 'placeholder.colour': '#fcfcfb';
|
|
32
|
+
readonly 'action.reset': '恢复默认';
|
|
33
|
+
readonly 'picker.search': '搜索字体';
|
|
34
|
+
readonly 'picker.empty': '没有匹配的字体';
|
|
35
|
+
readonly 'picker.count': '共 {count} 个字体';
|
|
36
|
+
readonly 'picker.useTyped': '使用“{name}”';
|
|
37
|
+
readonly 'state.loading': '正在读取配置…';
|
|
38
|
+
readonly 'state.unavailable': '当前页面没有可写的配置(表单只在 DSH 桌面应用内可用)。';
|
|
39
|
+
readonly 'state.saving': '正在保存…';
|
|
40
|
+
readonly 'state.saved': '已保存';
|
|
41
|
+
readonly 'state.failed': '写入被拒绝:配置可能已被外部修改或不符合约束。';
|
|
42
|
+
readonly 'state.readonly': '当前配置不可写。';
|
|
43
|
+
readonly 'error.colour': '颜色需为 #rrggbb 或 #rgb';
|
|
44
|
+
readonly 'error.font': '字体名只能包含字母、数字、空格与 . _ -,且不超过 64 个字符';
|
|
45
|
+
readonly 'feature.shell': '窗口与分栏骨架';
|
|
46
|
+
readonly 'feature.sidebar': '侧栏';
|
|
47
|
+
readonly 'feature.new-session': '新建页';
|
|
48
|
+
readonly 'feature.conversation': '聊天页';
|
|
49
|
+
readonly 'feature.tool-calls': '工具调用展示';
|
|
50
|
+
readonly 'feature.statistics': '统计卡片';
|
|
51
|
+
readonly 'feature.composer-pet': '输入框小鲸鱼';
|
|
52
|
+
};
|
|
53
|
+
export type SettingsKey = keyof typeof zh;
|
|
54
|
+
/** English dictionary; every Chinese key has a counterpart. */
|
|
55
|
+
export declare const en: Record<SettingsKey, string>;
|
|
56
|
+
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
57
|
+
interface LocaleNamespaceMap {
|
|
58
|
+
/** The row configuration page's copy. */
|
|
59
|
+
ccdSettings: SettingsKey;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { ConfigFormPort, DomPort, ThemePreferencePort } from '../../contracts/ports.ts';
|
|
3
|
+
import type { CleanupScope } from '../../core/cleanup.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Register the configuration page for this plugin's own loader row.
|
|
6
|
+
*
|
|
7
|
+
* The page lives outside the activation scope on purpose: switching the
|
|
8
|
+
* interface off releases every style resource, and the page has to survive that
|
|
9
|
+
* to switch it back on.
|
|
10
|
+
* @param ctx - client context, injected for slots and the locale service.
|
|
11
|
+
* @param dom - style port owning the page's stylesheet.
|
|
12
|
+
* @param form - this plugin's configuration form.
|
|
13
|
+
* @param themePreference - the native theme preference face, or null when the
|
|
14
|
+
* theme service does not publish one.
|
|
15
|
+
* @param scope - scope owning the stylesheet, the dictionary and the registration.
|
|
16
|
+
*/
|
|
17
|
+
export declare function mountSettingsPage(ctx: Context, dom: DomPort, form: ConfigFormPort, themePreference: ThemePreferencePort | null, scope: CleanupScope): void;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
3
|
+
import type { RowConfigPageProps } from '../../compat/plugin-manager.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Register the configuration page for one plugin row.
|
|
6
|
+
*
|
|
7
|
+
* The page owns its copy through the locale service and its form through the
|
|
8
|
+
* plugin's own `configForms` handle, so it needs only the slots and locale
|
|
9
|
+
* services. Both are injected as a pair: without an installed locale face a
|
|
10
|
+
* registration that declares a namespace fails loud at render time, so a
|
|
11
|
+
* deployment that lacks the service keeps the page unmounted instead.
|
|
12
|
+
* @param ctx - client context.
|
|
13
|
+
* @param key - `<package>#<row id>` of the row whose configuration page this is.
|
|
14
|
+
* @param component - the bound page component.
|
|
15
|
+
* @returns the injected scope, released with `dispose()`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function registerSettingsPage(ctx: Context, key: string, component: (props: RowConfigPageProps) => ReactElement | null): Pick<ReturnType<Context['inject']>, 'dispose'>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ImplementedFeature } from '../../contracts/feature.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Window frame and column geometry: flat surfaces, the sidebar column and its
|
|
4
|
+
* divider. The three tracks stay entirely `ui-layout`'s solve, so resizing the
|
|
5
|
+
* sidebar with the handle moves the divider the pointer is on; the plugin only
|
|
6
|
+
* paints the columns.
|
|
7
|
+
*/
|
|
8
|
+
export declare const shellFeature: ImplementedFeature;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ImplementedFeature } from '../../contracts/feature.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Sidebar presentation: compact navigation rows, flat project groups and a
|
|
4
|
+
* calmer foot. Every entry DSH registers — New Session, the global panel list,
|
|
5
|
+
* the workspace browser and Settings — stays exactly where the host put it; the
|
|
6
|
+
* account menu is reshaped, never re-authored.
|
|
7
|
+
*
|
|
8
|
+
* The one list policy this module owns is the provisional New Session row: DSH
|
|
9
|
+
* creates the Session as soon as New Session is used, and the host marks that
|
|
10
|
+
* row `blank` until the first message. The column keeps the row out of the list
|
|
11
|
+
* (see `compat/blank-session-rows.ts`), so the entry appears with the first sent
|
|
12
|
+
* message rather than with the click that opened the page.
|
|
13
|
+
*/
|
|
14
|
+
export declare const sidebarFeature: ImplementedFeature;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The card's footer sentence: the reference's book comparison.
|
|
3
|
+
*
|
|
4
|
+
* The numbers are the reference's own, recovered from its bundle: ten titles
|
|
5
|
+
* with a token count each, and two message shapes. The rule is
|
|
6
|
+
*
|
|
7
|
+
* ```
|
|
8
|
+
* eligible = books the total already exceeds (none → the line is hidden)
|
|
9
|
+
* book = eligible[floor(random * eligible.length)] (drawn once per mount)
|
|
10
|
+
* times = floor(total / book.tokens)
|
|
11
|
+
* times >= 2 → "You've used ~{times}× more tokens than {book}."
|
|
12
|
+
* otherwise → "You've used about as many tokens as {book}."
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* Only the sentence is copied; nothing is fetched and no book text is
|
|
16
|
+
* involved. The copy stays English, exactly as the reference writes it —
|
|
17
|
+
* including its typographic apostrophe and multiplication sign.
|
|
18
|
+
*/
|
|
19
|
+
/** One comparable book: the title as printed, and the tokens it would take. */
|
|
20
|
+
export interface Book {
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly tokens: number;
|
|
23
|
+
}
|
|
24
|
+
/** The reference's list, in its own order. */
|
|
25
|
+
export declare const BOOKS: readonly Book[];
|
|
26
|
+
/**
|
|
27
|
+
* Build the footer sentence for one token total.
|
|
28
|
+
*
|
|
29
|
+
* @param totalTokens - all-time token total at the provider's scale.
|
|
30
|
+
* @param random - one draw in `[0, 1)`; callers pass a value that is stable for
|
|
31
|
+
* the lifetime of a mount, so the sentence does not change between polls.
|
|
32
|
+
* @returns the sentence, or null while no book is smaller than the total.
|
|
33
|
+
*/
|
|
34
|
+
export declare function bookNote(totalTokens: number, random: () => number): string | null;
|