@lijian-ui/dsh-file-manager 0.1.20
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 +38 -0
- package/README.i18n.yaml +6 -0
- package/README.md +66 -0
- package/README.zh.md +66 -0
- package/cordis.patch.yml +13 -0
- package/lib/assets/mermaid.min.js +3587 -0
- package/lib/client.js +7621 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +3207 -0
- package/lib/tsconfig.client.tsbuildinfo +1 -0
- package/lib/tsconfig.host.tsbuildinfo +1 -0
- package/lib/types/client/FileManagerSettingsCard.d.ts +56 -0
- package/lib/types/client/FileManagerSettingsCard.d.ts.map +1 -0
- package/lib/types/client/PluginSettingsCard.d.ts +104 -0
- package/lib/types/client/PluginSettingsCard.d.ts.map +1 -0
- package/lib/types/client/api.d.ts +75 -0
- package/lib/types/client/api.d.ts.map +1 -0
- package/lib/types/client/chat/AttachedFilesDock.d.ts +51 -0
- package/lib/types/client/chat/AttachedFilesDock.d.ts.map +1 -0
- package/lib/types/client/chat/file-ref.d.ts +35 -0
- package/lib/types/client/chat/file-ref.d.ts.map +1 -0
- package/lib/types/client/chat/mermaid-chat.d.ts +30 -0
- package/lib/types/client/chat/mermaid-chat.d.ts.map +1 -0
- package/lib/types/client/chat/placeholder-hint.d.ts +16 -0
- package/lib/types/client/chat/placeholder-hint.d.ts.map +1 -0
- package/lib/types/client/components/ExplorerPanel.d.ts +26 -0
- package/lib/types/client/components/ExplorerPanel.d.ts.map +1 -0
- package/lib/types/client/components/FileIcon.d.ts +15 -0
- package/lib/types/client/components/FileIcon.d.ts.map +1 -0
- package/lib/types/client/components/ScmPanel.d.ts +23 -0
- package/lib/types/client/components/ScmPanel.d.ts.map +1 -0
- package/lib/types/client/components/a11y.d.ts +12 -0
- package/lib/types/client/components/a11y.d.ts.map +1 -0
- package/lib/types/client/components/icons.d.ts +41 -0
- package/lib/types/client/components/icons.d.ts.map +1 -0
- package/lib/types/client/components/overlay.d.ts +45 -0
- package/lib/types/client/components/overlay.d.ts.map +1 -0
- package/lib/types/client/drag/DragFileInlay.d.ts +31 -0
- package/lib/types/client/drag/DragFileInlay.d.ts.map +1 -0
- package/lib/types/client/drag/file-drag.d.ts +47 -0
- package/lib/types/client/drag/file-drag.d.ts.map +1 -0
- package/lib/types/client/drag.d.ts +31 -0
- package/lib/types/client/drag.d.ts.map +1 -0
- package/lib/types/client/file-source.d.ts +29 -0
- package/lib/types/client/file-source.d.ts.map +1 -0
- package/lib/types/client/fileType.d.ts +31 -0
- package/lib/types/client/fileType.d.ts.map +1 -0
- package/lib/types/client/floating.d.ts +27 -0
- package/lib/types/client/floating.d.ts.map +1 -0
- package/lib/types/client/hooks/useResizableSplit.d.ts +37 -0
- package/lib/types/client/hooks/useResizableSplit.d.ts.map +1 -0
- package/lib/types/client/hooks/useStore.d.ts +10 -0
- package/lib/types/client/hooks/useStore.d.ts.map +1 -0
- package/lib/types/client/index.d.ts +57 -0
- package/lib/types/client/index.d.ts.map +1 -0
- package/lib/types/client/layout.d.ts +104 -0
- package/lib/types/client/layout.d.ts.map +1 -0
- package/lib/types/client/locales.d.ts +125 -0
- package/lib/types/client/locales.d.ts.map +1 -0
- package/lib/types/client/maximize.d.ts +24 -0
- package/lib/types/client/maximize.d.ts.map +1 -0
- package/lib/types/client/mention.d.ts +44 -0
- package/lib/types/client/mention.d.ts.map +1 -0
- package/lib/types/client/mount.d.ts +22 -0
- package/lib/types/client/mount.d.ts.map +1 -0
- package/lib/types/client/persist.d.ts +55 -0
- package/lib/types/client/persist.d.ts.map +1 -0
- package/lib/types/client/picker/FilePickerModal.d.ts +47 -0
- package/lib/types/client/picker/FilePickerModal.d.ts.map +1 -0
- package/lib/types/client/picker/file-picker.d.ts +62 -0
- package/lib/types/client/picker/file-picker.d.ts.map +1 -0
- package/lib/types/client/preview/PreviewPanel.d.ts +17 -0
- package/lib/types/client/preview/PreviewPanel.d.ts.map +1 -0
- package/lib/types/client/preview/PreviewTabs.d.ts +30 -0
- package/lib/types/client/preview/PreviewTabs.d.ts.map +1 -0
- package/lib/types/client/preview/PreviewToolbar.d.ts +37 -0
- package/lib/types/client/preview/PreviewToolbar.d.ts.map +1 -0
- package/lib/types/client/preview/content.d.ts +43 -0
- package/lib/types/client/preview/content.d.ts.map +1 -0
- package/lib/types/client/preview/markdown.d.ts +60 -0
- package/lib/types/client/preview/markdown.d.ts.map +1 -0
- package/lib/types/client/preview/mermaid.d.ts +78 -0
- package/lib/types/client/preview/mermaid.d.ts.map +1 -0
- package/lib/types/client/preview/selection.d.ts +26 -0
- package/lib/types/client/preview/selection.d.ts.map +1 -0
- package/lib/types/client/reference.d.ts +75 -0
- package/lib/types/client/reference.d.ts.map +1 -0
- package/lib/types/client/settings-form.d.ts +206 -0
- package/lib/types/client/settings-form.d.ts.map +1 -0
- package/lib/types/client/store.d.ts +279 -0
- package/lib/types/client/store.d.ts.map +1 -0
- package/lib/types/core/types.d.ts +132 -0
- package/lib/types/core/types.d.ts.map +1 -0
- package/lib/types/host/fs-service.d.ts +96 -0
- package/lib/types/host/fs-service.d.ts.map +1 -0
- package/lib/types/host/gate.d.ts +45 -0
- package/lib/types/host/gate.d.ts.map +1 -0
- package/lib/types/host/git-runner.d.ts +80 -0
- package/lib/types/host/git-runner.d.ts.map +1 -0
- package/lib/types/host/git-service.d.ts +130 -0
- package/lib/types/host/git-service.d.ts.map +1 -0
- package/lib/types/host/loopback.d.ts +25 -0
- package/lib/types/host/loopback.d.ts.map +1 -0
- package/lib/types/host/poll-guard.d.ts +55 -0
- package/lib/types/host/poll-guard.d.ts.map +1 -0
- package/lib/types/host/routes.d.ts +54 -0
- package/lib/types/host/routes.d.ts.map +1 -0
- package/lib/types/index.d.ts +35 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/mount-once.d.ts +25 -0
- package/lib/types/mount-once.d.ts.map +1 -0
- package/package.json +85 -0
- package/src/client/FileManagerSettingsCard.tsx +117 -0
- package/src/client/PluginSettingsCard.tsx +337 -0
- package/src/client/api.ts +141 -0
- package/src/client/chat/file-ref.ts +144 -0
- package/src/client/chat/mermaid-chat.tsx +102 -0
- package/src/client/chat/placeholder-hint.tsx +46 -0
- package/src/client/components/ExplorerPanel.tsx +534 -0
- package/src/client/components/FileIcon.tsx +46 -0
- package/src/client/components/ScmPanel.tsx +480 -0
- package/src/client/components/a11y.ts +20 -0
- package/src/client/components/icons.tsx +274 -0
- package/src/client/components/overlay.tsx +225 -0
- package/src/client/css-modules.d.ts +5 -0
- package/src/client/drag/DragFileInlay.tsx +89 -0
- package/src/client/drag/file-drag.ts +67 -0
- package/src/client/drag.ts +154 -0
- package/src/client/file-source.ts +58 -0
- package/src/client/fileType.ts +129 -0
- package/src/client/floating.ts +63 -0
- package/src/client/hooks/useResizableSplit.ts +91 -0
- package/src/client/hooks/useStore.ts +15 -0
- package/src/client/index.ts +389 -0
- package/src/client/layout.ts +546 -0
- package/src/client/locales.ts +247 -0
- package/src/client/maximize.ts +34 -0
- package/src/client/mount.tsx +74 -0
- package/src/client/persist.ts +194 -0
- package/src/client/picker/FilePickerModal.tsx +506 -0
- package/src/client/picker/file-picker.ts +86 -0
- package/src/client/preview/PreviewPanel.tsx +233 -0
- package/src/client/preview/PreviewTabs.tsx +159 -0
- package/src/client/preview/PreviewToolbar.tsx +160 -0
- package/src/client/preview/content.tsx +617 -0
- package/src/client/preview/markdown.ts +351 -0
- package/src/client/preview/mermaid.ts +274 -0
- package/src/client/preview/selection.ts +82 -0
- package/src/client/reference.ts +161 -0
- package/src/client/settings-card.module.css +316 -0
- package/src/client/settings-form.ts +451 -0
- package/src/client/store.ts +1290 -0
- package/src/client/styles/chip.module.css +38 -0
- package/src/client/styles/drag.module.css +30 -0
- package/src/client/styles/explorer.module.css +371 -0
- package/src/client/styles/picker.module.css +344 -0
- package/src/client/styles/preview.module.css +904 -0
- package/src/client/styles/scm.module.css +380 -0
- package/src/client/styles/tokens.module.css +480 -0
- package/src/core/types.ts +162 -0
- package/src/host/fs-service.ts +513 -0
- package/src/host/gate.ts +74 -0
- package/src/host/git-runner.ts +116 -0
- package/src/host/git-service.ts +395 -0
- package/src/host/loopback.ts +63 -0
- package/src/host/poll-guard.ts +109 -0
- package/src/host/routes.ts +695 -0
- package/src/index.ts +97 -0
- package/src/mount-once.ts +48 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translate a text selection inside the preview into a file reference (path
|
|
3
|
+
* plus start/end line). The selection must live inside a `<pre>` of a file-
|
|
4
|
+
* backed preview (code / text / markdown source / diff); returns null for
|
|
5
|
+
* anything else so the caller can hide the floating action.
|
|
6
|
+
*
|
|
7
|
+
* The reference carries only what the agent needs: the workspace-relative
|
|
8
|
+
* path of the file and the 1-based line range. The selected text itself is
|
|
9
|
+
* not copied into the composer — the agent re-reads the file at the line
|
|
10
|
+
* range when the message is sent.
|
|
11
|
+
* @module dsh-filemgr/client/preview/selection
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { PreviewTabState } from '../store.ts'
|
|
15
|
+
|
|
16
|
+
/** The file-backed reference we surface from a preview selection. */
|
|
17
|
+
export interface FileReferenceSelection {
|
|
18
|
+
path: string
|
|
19
|
+
startLine: number
|
|
20
|
+
endLine: number
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Content types that map cleanly to line-based references. */
|
|
24
|
+
const LINE_BASED_CONTENT_TYPES: ReadonlySet<PreviewTabState['contentType']> = new Set([
|
|
25
|
+
'code',
|
|
26
|
+
'text',
|
|
27
|
+
'markdown', // markdown source-mode selection still maps to text lines
|
|
28
|
+
'diff',
|
|
29
|
+
])
|
|
30
|
+
|
|
31
|
+
/** Number the 1-based line of `offset` within `text` (counting newlines before it). */
|
|
32
|
+
function lineOf(text: string, offset: number): number {
|
|
33
|
+
const upto = text.length === 0 ? '' : text.slice(0, Math.max(0, Math.min(offset, text.length)))
|
|
34
|
+
let line = 1
|
|
35
|
+
for (let i = 0; i < upto.length; i += 1) {
|
|
36
|
+
if (upto.charCodeAt(i) === 10) line += 1
|
|
37
|
+
}
|
|
38
|
+
return line
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Return the character offset of (node, offset) measured from the start of `pre`. */
|
|
42
|
+
function offsetInPre(pre: HTMLPreElement, node: Node | null, offset: number): number | null {
|
|
43
|
+
if (node === null) return null
|
|
44
|
+
try {
|
|
45
|
+
const range = document.createRange()
|
|
46
|
+
range.setStart(pre, 0)
|
|
47
|
+
range.setEnd(node, offset)
|
|
48
|
+
return range.toString().length
|
|
49
|
+
} catch {
|
|
50
|
+
// Cross-boundary nodes (e.g. detached text) raise; fall through.
|
|
51
|
+
return null
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Build a FileReferenceSelection from a browser selection if it points to a
|
|
57
|
+
* supported preview's `<pre>`. Returns null otherwise (image / pdf / url /
|
|
58
|
+
* non-line content, or a selection that lives outside any code block).
|
|
59
|
+
*/
|
|
60
|
+
export function findFileReferenceSelection(
|
|
61
|
+
anchorElement: Element | null,
|
|
62
|
+
selection: Selection,
|
|
63
|
+
tab: PreviewTabState | null,
|
|
64
|
+
): FileReferenceSelection | null {
|
|
65
|
+
if (anchorElement === null) return null
|
|
66
|
+
if (tab === null || tab.content === null) return null
|
|
67
|
+
if (!LINE_BASED_CONTENT_TYPES.has(tab.contentType)) return null
|
|
68
|
+
const pre = anchorElement.closest('pre') as HTMLPreElement | null
|
|
69
|
+
if (pre === null) return null
|
|
70
|
+
const startInPre = offsetInPre(pre, selection.anchorNode, selection.anchorOffset)
|
|
71
|
+
const endInPre = offsetInPre(pre, selection.focusNode, selection.focusOffset)
|
|
72
|
+
if (startInPre === null || endInPre === null) return null
|
|
73
|
+
const start = Math.min(startInPre, endInPre)
|
|
74
|
+
const end = Math.max(startInPre, endInPre)
|
|
75
|
+
if (start === end) return null
|
|
76
|
+
const text = pre.textContent ?? ''
|
|
77
|
+
return {
|
|
78
|
+
path: tab.path,
|
|
79
|
+
startLine: lineOf(text, start),
|
|
80
|
+
endLine: lineOf(text, end),
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import type { ClientContext, SessionId } from '@deepseek-ai/dsh-client-runtime/client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Composer draft helpers for file references.
|
|
5
|
+
*
|
|
6
|
+
* References ride the shell's native U+FFFC chip pipeline
|
|
7
|
+
* (`slash/input-insert-reference` bail): the composer shows one chip pill in
|
|
8
|
+
* place of the hidden `@path:lines` token, and the model text is serialized
|
|
9
|
+
* on submit through the `file` reference source's codec (registered in
|
|
10
|
+
* file-source.ts). Without that codec the submit attempt fails with
|
|
11
|
+
* `slash: no serializer for reference source "file"` — the codec MUST stay
|
|
12
|
+
* registered while any chip is in a draft.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Minimal structural view of the conversation input service. Declared locally
|
|
17
|
+
* so this helper has no value import from the conversation package (keeps the
|
|
18
|
+
* client bundle purity gate happy).
|
|
19
|
+
*/
|
|
20
|
+
interface DraftInput {
|
|
21
|
+
state: { getSnapshot(): { draft: string; draftRev: number } }
|
|
22
|
+
setDraft(draft: string): void
|
|
23
|
+
}
|
|
24
|
+
export interface ConversationService {
|
|
25
|
+
input: { for(actx: ClientContext): DraftInput }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The file-backed reference a composer chip stands for. */
|
|
29
|
+
export interface FileReference {
|
|
30
|
+
/** Workspace-relative path (what the agent will read). */
|
|
31
|
+
path: string
|
|
32
|
+
/** First line of the referenced range (1-based, inclusive). */
|
|
33
|
+
startLine: number
|
|
34
|
+
/** Last line of the referenced range (1-based, inclusive). */
|
|
35
|
+
endLine: number
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Basename of a `/`-separated relative path ('' when empty). */
|
|
39
|
+
function basenameOf(rel: string): string {
|
|
40
|
+
const idx = rel.lastIndexOf('/')
|
|
41
|
+
return idx >= 0 ? rel.slice(idx + 1) : rel
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Directory of a `/`-separated relative path ('' when none). */
|
|
45
|
+
function dirnameOf(rel: string): string {
|
|
46
|
+
const idx = rel.lastIndexOf('/')
|
|
47
|
+
return idx > 0 ? rel.slice(0, idx) : ''
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The chip label: basename, or `basename - dir` when the basename is
|
|
52
|
+
* ambiguous across the workspace (matches the reference screenshot: a short
|
|
53
|
+
* name plus the line range, never the full path).
|
|
54
|
+
*/
|
|
55
|
+
function formatRefLabel(ref: FileReference): string {
|
|
56
|
+
const basename = basenameOf(ref.path)
|
|
57
|
+
const dirname = dirnameOf(ref.path)
|
|
58
|
+
const name = dirname === '' ? basename : `${basename} - ${dirname}`
|
|
59
|
+
return ref.endLine > ref.startLine ? `${name} ${ref.startLine}-${ref.endLine}` : `${name} ${ref.startLine}`
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** The `@path:lines` model form (what the codec serializes to on submit). */
|
|
63
|
+
export function formatFileRefToken(ref: { path: string; startLine: number; endLine: number }): string {
|
|
64
|
+
const range = ref.endLine > ref.startLine ? `${ref.startLine}-${ref.endLine}` : `${ref.startLine}`
|
|
65
|
+
return `@${ref.path}:${range}`
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Reference shape the conversation machine mints into a chip occurrence. */
|
|
69
|
+
interface ConversationReference {
|
|
70
|
+
source: string
|
|
71
|
+
ref: string
|
|
72
|
+
label: string
|
|
73
|
+
clipboardText: string
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** The DRAFT-REV+CAS span the conversation machine expects for chip inserts. */
|
|
77
|
+
export interface RefSpan {
|
|
78
|
+
start: number
|
|
79
|
+
end: number
|
|
80
|
+
draftRev: number
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Append `text` to the session's composer draft (plain text — no chip). */
|
|
84
|
+
export function appendToDraft(ctx: ClientContext, sessionId: SessionId | undefined, text: string): boolean {
|
|
85
|
+
try {
|
|
86
|
+
if (sessionId === undefined) return false
|
|
87
|
+
const actx = ctx.sessions.scope(sessionId)
|
|
88
|
+
if (actx === undefined) return false
|
|
89
|
+
const conversation = (ctx as unknown as { conversation?: ConversationService }).conversation
|
|
90
|
+
if (conversation === undefined) return false
|
|
91
|
+
const input = conversation.input.for(actx as unknown as ClientContext)
|
|
92
|
+
const draft = input.state.getSnapshot().draft
|
|
93
|
+
input.setDraft(draft.trim() === '' ? text : `${draft} ${text}`)
|
|
94
|
+
return true
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.warn('[dsh-filemgr] draft insert failed:', error)
|
|
97
|
+
return false
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Insert a file-reference chip into the composer draft at `span`, replacing
|
|
103
|
+
* its range with an occurrence the machine renders as a `</> name N-M`
|
|
104
|
+
* pill. The model text (`@path:lines`) is serialized on submit by the `file`
|
|
105
|
+
* source's codec (file-source.ts) — never the clipboard text.
|
|
106
|
+
*
|
|
107
|
+
* @returns true when the bail was accepted (CAS will still reject on
|
|
108
|
+
* stale draftRev — caller can re-read draft after).
|
|
109
|
+
*/
|
|
110
|
+
export function insertFileReference(
|
|
111
|
+
ctx: ClientContext,
|
|
112
|
+
sessionId: SessionId | undefined,
|
|
113
|
+
ref: FileReference,
|
|
114
|
+
span: RefSpan,
|
|
115
|
+
): boolean {
|
|
116
|
+
try {
|
|
117
|
+
if (sessionId === undefined) return false
|
|
118
|
+
const actx = ctx.sessions.scope(sessionId)
|
|
119
|
+
if (actx === undefined) return false
|
|
120
|
+
const reference: ConversationReference = {
|
|
121
|
+
source: 'file',
|
|
122
|
+
ref: formatFileRefToken(ref),
|
|
123
|
+
label: formatRefLabel(ref),
|
|
124
|
+
clipboardText: formatFileRefToken(ref),
|
|
125
|
+
}
|
|
126
|
+
return (actx as unknown as {
|
|
127
|
+
bail(target: unknown, event: string, payload: unknown): boolean
|
|
128
|
+
}).bail(actx, 'slash/input-insert-reference', { reference, span })
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.warn('[dsh-filemgr] file-reference insert failed:', error)
|
|
131
|
+
return false
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Append a file-reference chip at the end of the current draft (the explorer
|
|
137
|
+
* `@` button and the preview "添加到对话" action path). Reads the latest
|
|
138
|
+
* draft + draftRev from the conversation shell and inserts a zero-length chip
|
|
139
|
+
* there, so the chip lands after whatever the user has already typed.
|
|
140
|
+
*
|
|
141
|
+
* @returns true on success.
|
|
142
|
+
*/
|
|
143
|
+
export function appendFileReferenceChip(
|
|
144
|
+
ctx: ClientContext,
|
|
145
|
+
sessionId: SessionId | undefined,
|
|
146
|
+
ref: FileReference,
|
|
147
|
+
): boolean {
|
|
148
|
+
if (sessionId === undefined) return false
|
|
149
|
+
const actx = ctx.sessions.scope(sessionId)
|
|
150
|
+
if (actx === undefined) return false
|
|
151
|
+
const conversation = (ctx as unknown as { conversation?: ConversationService }).conversation
|
|
152
|
+
if (conversation === undefined) return false
|
|
153
|
+
const shell = conversation.input.for(actx as unknown as ClientContext)
|
|
154
|
+
const snap = shell.state.getSnapshot()
|
|
155
|
+
return insertFileReference(
|
|
156
|
+
ctx,
|
|
157
|
+
sessionId,
|
|
158
|
+
ref,
|
|
159
|
+
{ start: snap.draft.length, end: snap.draft.length, draftRev: snap.draftRev },
|
|
160
|
+
)
|
|
161
|
+
}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/* Generated by scripts/sync-shared.mjs from shared/client/settings/settings-card.module.css. Do not edit this copy; edit the shared source and run "node scripts/sync-shared.mjs". */
|
|
2
|
+
/* Plugin settings card chrome + staged form fields.
|
|
3
|
+
* Aligned with the official ui-settings-plugins PluginCard / fields CSS:
|
|
4
|
+
* same semantic tokens, radius, typography and states so family cards read
|
|
5
|
+
* as siblings of the built-in Shell / Agent loop / Web search cards. */
|
|
6
|
+
|
|
7
|
+
.card {
|
|
8
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
9
|
+
background: var(--dsw-alias-bg-layer-3);
|
|
10
|
+
border-radius: 12px;
|
|
11
|
+
list-style: none;
|
|
12
|
+
transition: border-color 0.16s, background 0.16s;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.card:hover {
|
|
16
|
+
border-color: var(--dsw-alias-label-dimmed);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.cardOpen {
|
|
20
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
21
|
+
border-color: var(--dsw-alias-label-dimmed);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.header {
|
|
25
|
+
appearance: none;
|
|
26
|
+
width: 100%;
|
|
27
|
+
font: inherit;
|
|
28
|
+
color: inherit;
|
|
29
|
+
text-align: left;
|
|
30
|
+
cursor: pointer;
|
|
31
|
+
background: transparent;
|
|
32
|
+
border: 0;
|
|
33
|
+
border-radius: 12px;
|
|
34
|
+
align-items: center;
|
|
35
|
+
gap: 12px;
|
|
36
|
+
padding: 14px 16px;
|
|
37
|
+
display: flex;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.header:focus-visible {
|
|
41
|
+
outline: 2px solid var(--dsw-alias-brand-primary);
|
|
42
|
+
outline-offset: -2px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.headerStatic {
|
|
46
|
+
width: 100%;
|
|
47
|
+
border-radius: 12px;
|
|
48
|
+
align-items: center;
|
|
49
|
+
gap: 12px;
|
|
50
|
+
padding: 14px 16px;
|
|
51
|
+
display: flex;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.headText {
|
|
55
|
+
flex-direction: column;
|
|
56
|
+
flex: 1;
|
|
57
|
+
gap: 4px;
|
|
58
|
+
min-width: 0;
|
|
59
|
+
display: flex;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.name {
|
|
63
|
+
color: var(--dsw-alias-label-primary);
|
|
64
|
+
font-size: 15px;
|
|
65
|
+
font-weight: 600;
|
|
66
|
+
line-height: 1.4;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.description {
|
|
70
|
+
color: var(--dsw-alias-label-tertiary);
|
|
71
|
+
font-size: 13px;
|
|
72
|
+
line-height: 1.5;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.pending {
|
|
76
|
+
white-space: nowrap;
|
|
77
|
+
background: var(--dsw-alias-bg-module-platform);
|
|
78
|
+
color: var(--dsw-alias-label-secondary);
|
|
79
|
+
border-radius: 999px;
|
|
80
|
+
flex: none;
|
|
81
|
+
padding: 1px 8px;
|
|
82
|
+
font-size: 11px;
|
|
83
|
+
font-weight: 500;
|
|
84
|
+
line-height: 17px;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.chevron {
|
|
88
|
+
color: var(--dsw-alias-label-tertiary);
|
|
89
|
+
flex: none;
|
|
90
|
+
transition: transform 0.16s;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.chevronOpen {
|
|
94
|
+
transform: rotate(180deg);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.body {
|
|
98
|
+
border-top: 1px solid var(--dsw-alias-border-l2);
|
|
99
|
+
margin: 0 16px;
|
|
100
|
+
padding-bottom: 8px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.readOnly {
|
|
104
|
+
color: var(--dsw-alias-label-tertiary);
|
|
105
|
+
margin: 12px 0 0;
|
|
106
|
+
font-size: 12px;
|
|
107
|
+
line-height: 1.5;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.notExposed {
|
|
111
|
+
color: var(--dsw-alias-state-warn-primary);
|
|
112
|
+
margin: 12px 0 0;
|
|
113
|
+
font-size: 12px;
|
|
114
|
+
line-height: 1.5;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.footer {
|
|
118
|
+
border-top: 1px solid var(--dsw-alias-border-l2);
|
|
119
|
+
justify-content: flex-end;
|
|
120
|
+
align-items: center;
|
|
121
|
+
gap: 8px;
|
|
122
|
+
padding: 12px 0 4px;
|
|
123
|
+
display: flex;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.failed {
|
|
127
|
+
min-width: 0;
|
|
128
|
+
color: var(--dsw-alias-label-error);
|
|
129
|
+
flex: 1;
|
|
130
|
+
margin: 0;
|
|
131
|
+
font-size: 12px;
|
|
132
|
+
line-height: 1.5;
|
|
133
|
+
text-overflow: ellipsis;
|
|
134
|
+
overflow: hidden;
|
|
135
|
+
white-space: nowrap;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.discard,
|
|
139
|
+
.save {
|
|
140
|
+
appearance: none;
|
|
141
|
+
font: inherit;
|
|
142
|
+
cursor: pointer;
|
|
143
|
+
border: 1px solid transparent;
|
|
144
|
+
border-radius: 8px;
|
|
145
|
+
padding: 5px 14px;
|
|
146
|
+
font-size: 13px;
|
|
147
|
+
line-height: 1.5;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.discard {
|
|
151
|
+
border-color: var(--dsw-alias-border-l2);
|
|
152
|
+
color: var(--dsw-alias-label-secondary);
|
|
153
|
+
background: transparent;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.discard:hover:not(:disabled) {
|
|
157
|
+
color: var(--dsw-alias-label-primary);
|
|
158
|
+
border-color: var(--dsw-alias-label-dimmed);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.save {
|
|
162
|
+
background: var(--dsw-alias-label-primary);
|
|
163
|
+
color: var(--dsw-alias-bg-layer-3);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.discard:disabled,
|
|
167
|
+
.save:disabled {
|
|
168
|
+
opacity: 0.4;
|
|
169
|
+
cursor: default;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.discard:focus-visible,
|
|
173
|
+
.save:focus-visible {
|
|
174
|
+
outline: 2px solid var(--dsw-alias-brand-primary);
|
|
175
|
+
outline-offset: 1px;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.field {
|
|
179
|
+
flex-direction: column;
|
|
180
|
+
gap: 6px;
|
|
181
|
+
padding: 12px 0;
|
|
182
|
+
display: flex;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.field + .field {
|
|
186
|
+
border-top: 1px solid var(--dsw-alias-border-l2);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.head {
|
|
190
|
+
align-items: center;
|
|
191
|
+
gap: 8px;
|
|
192
|
+
display: flex;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.label {
|
|
196
|
+
min-width: 0;
|
|
197
|
+
color: var(--dsw-alias-label-primary);
|
|
198
|
+
flex: 1;
|
|
199
|
+
font-size: 13px;
|
|
200
|
+
font-weight: 500;
|
|
201
|
+
line-height: 1.5;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.badges {
|
|
205
|
+
align-items: center;
|
|
206
|
+
gap: 8px;
|
|
207
|
+
display: inline-flex;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.badge {
|
|
211
|
+
white-space: nowrap;
|
|
212
|
+
background: var(--dsw-alias-bg-module-platform);
|
|
213
|
+
color: var(--dsw-alias-label-secondary);
|
|
214
|
+
border-radius: 999px;
|
|
215
|
+
padding: 1px 8px;
|
|
216
|
+
font-size: 11px;
|
|
217
|
+
font-weight: 500;
|
|
218
|
+
line-height: 17px;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.reset {
|
|
222
|
+
font: inherit;
|
|
223
|
+
color: var(--dsw-alias-label-secondary);
|
|
224
|
+
cursor: pointer;
|
|
225
|
+
background: transparent;
|
|
226
|
+
border: none;
|
|
227
|
+
padding: 0;
|
|
228
|
+
font-size: 12px;
|
|
229
|
+
line-height: 1.5;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.reset:hover:not(:disabled) {
|
|
233
|
+
color: var(--dsw-alias-label-primary);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.reset:disabled {
|
|
237
|
+
cursor: default;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.reset:focus-visible {
|
|
241
|
+
outline: 2px solid var(--dsw-alias-brand-primary);
|
|
242
|
+
outline-offset: 2px;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.reset:focus-visible {
|
|
246
|
+
outline: 2px solid var(--dsw-alias-brand-primary);
|
|
247
|
+
outline-offset: 2px;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.input,
|
|
251
|
+
.select {
|
|
252
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
253
|
+
background: var(--dsw-alias-bg-layer-3);
|
|
254
|
+
height: 34px;
|
|
255
|
+
font: inherit;
|
|
256
|
+
color: var(--dsw-alias-label-primary);
|
|
257
|
+
border-radius: 8px;
|
|
258
|
+
padding: 0 12px;
|
|
259
|
+
font-size: 13px;
|
|
260
|
+
line-height: 1.5;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.input:focus-visible,
|
|
264
|
+
.select:focus-visible {
|
|
265
|
+
border-color: var(--dsw-alias-brand-primary);
|
|
266
|
+
outline: none;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.input:disabled,
|
|
270
|
+
.select:disabled {
|
|
271
|
+
color: var(--dsw-alias-label-tertiary);
|
|
272
|
+
cursor: default;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.inputInvalid {
|
|
276
|
+
border: 1px solid var(--dsw-alias-label-error);
|
|
277
|
+
background: var(--dsw-alias-bg-layer-3);
|
|
278
|
+
height: 34px;
|
|
279
|
+
font: inherit;
|
|
280
|
+
color: var(--dsw-alias-label-primary);
|
|
281
|
+
border-radius: 8px;
|
|
282
|
+
padding: 0 12px;
|
|
283
|
+
font-size: 13px;
|
|
284
|
+
line-height: 1.5;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.inputInvalid:focus-visible {
|
|
288
|
+
outline: 2px solid var(--dsw-alias-label-error);
|
|
289
|
+
outline-offset: 1px;
|
|
290
|
+
border-color: var(--dsw-alias-label-error);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.invalid {
|
|
294
|
+
color: var(--dsw-alias-label-error);
|
|
295
|
+
margin: 0;
|
|
296
|
+
font-size: 12px;
|
|
297
|
+
line-height: 1.5;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.hint {
|
|
301
|
+
color: var(--dsw-alias-label-tertiary);
|
|
302
|
+
margin: 0;
|
|
303
|
+
font-size: 12px;
|
|
304
|
+
line-height: 1.5;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
@media (prefers-reduced-motion: reduce) {
|
|
308
|
+
.card,
|
|
309
|
+
.header,
|
|
310
|
+
.chevron,
|
|
311
|
+
.chevronOpen,
|
|
312
|
+
.discard,
|
|
313
|
+
.save {
|
|
314
|
+
transition: none;
|
|
315
|
+
}
|
|
316
|
+
}
|