@poodle64/librarian 2026.9.14 → 2026.9.16
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/README.md +77 -19
- package/dist/client.d.ts +16 -1
- package/dist/client.js +91 -21
- package/dist/components/activity-group/activity-group.svelte +76 -8
- package/dist/components/agent-transcript/agent-transcript.svelte +345 -155
- package/dist/components/agent-transcript/agent-transcript.svelte.d.ts +7 -0
- package/dist/components/artefact-card/artefact-card.svelte +30 -2
- package/dist/components/artefact-pane/artefact-pane.svelte +141 -50
- package/dist/components/composer/composer.svelte +253 -39
- package/dist/components/composer/composer.svelte.d.ts +5 -1
- package/dist/components/conversation/conversation.svelte +247 -89
- package/dist/components/conversation/conversation.svelte.d.ts +6 -2
- package/dist/components/document-pane/document-pane.svelte +216 -33
- package/dist/components/markdown/markdown.svelte +73 -24
- package/dist/components/scope-statement/scope-statement.svelte +79 -12
- package/dist/components/source-list/index.d.ts +2 -0
- package/dist/components/source-list/index.js +2 -0
- package/dist/components/source-list/source-list.svelte +137 -0
- package/dist/components/source-list/source-list.svelte.d.ts +13 -0
- package/dist/components/thinking-row/thinking-row.svelte +69 -18
- package/dist/components/tool-row/tool-row.svelte +132 -26
- package/dist/components/working/working.svelte +51 -7
- package/dist/components/working/working.svelte.d.ts +3 -0
- package/dist/copy.d.ts +44 -12
- package/dist/copy.js +77 -33
- package/dist/transcript.svelte.d.ts +10 -0
- package/dist/transcript.svelte.js +4 -1
- package/package.json +4 -2
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
A study artefact, open in the reading column.
|
|
3
3
|
|
|
4
|
-
The same shell shape `DocumentPane` uses (a column at
|
|
5
|
-
below it) because decision 2 of the
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
The same shell shape `DocumentPane` uses (a column at 64rem, a bottom sheet
|
|
5
|
+
below it) because decision 2 of the agent surface is that a colleague never
|
|
6
|
+
has to learn which of the two things is in the column before they open it —
|
|
7
|
+
only ever one, in the same place, closing whichever was there.
|
|
8
8
|
-->
|
|
9
9
|
<script lang="ts">
|
|
10
10
|
import XIcon from '@lucide/svelte/icons/x';
|
|
11
11
|
import { segment, type TextBlock, type Turn } from '../../transcript.svelte';
|
|
12
|
-
import { resolveCitations, splitSources,
|
|
12
|
+
import { resolveCitations, splitSources, type Citation } from '../../citations';
|
|
13
13
|
import { resolveCopy, type LibrarianCopy } from '../../copy';
|
|
14
14
|
import Markdown from '../markdown/markdown.svelte';
|
|
15
|
+
import SourceList from '../source-list/source-list.svelte';
|
|
15
16
|
|
|
16
17
|
interface Props {
|
|
17
18
|
turn: Turn;
|
|
@@ -52,69 +53,159 @@
|
|
|
52
53
|
|
|
53
54
|
<svelte:window onkeydown={keydown} />
|
|
54
55
|
|
|
55
|
-
<aside
|
|
56
|
-
|
|
57
|
-
class="bg-surface-1 border-border fixed inset-x-0 bottom-0 z-40 flex h-[80svh] flex-col rounded-t-2xl border-t shadow-2xl lg:relative lg:h-auto lg:w-[560px] lg:shrink-0 lg:rounded-none lg:border-t-0 lg:border-l lg:shadow-none"
|
|
58
|
-
>
|
|
59
|
-
<!-- The sheet's grabber. Below `lg` this is an overlay a reader has to be
|
|
56
|
+
<aside aria-label="Study artefact" class="ds-lib-pane">
|
|
57
|
+
<!-- The sheet's grabber. On a phone this is an overlay a reader has to be
|
|
60
58
|
able to see the top edge of; on a desktop it is a column, so there is
|
|
61
59
|
nothing here to grab. -->
|
|
62
|
-
<div class="
|
|
63
|
-
<span class="bg-border h-1 w-9 rounded-full"></span>
|
|
64
|
-
</div>
|
|
60
|
+
<div class="ds-lib-pane-grabber" aria-hidden="true"><span></span></div>
|
|
65
61
|
|
|
66
|
-
<header class="
|
|
67
|
-
<div class="
|
|
68
|
-
<h2 class="
|
|
69
|
-
<p class="
|
|
62
|
+
<header class="ds-lib-pane-header">
|
|
63
|
+
<div class="ds-lib-pane-heading">
|
|
64
|
+
<h2 class="ds-lib-pane-title">{turn.title ?? 'Briefing'}</h2>
|
|
65
|
+
<p class="ds-lib-pane-subtitle">
|
|
70
66
|
Briefing doc · {sources.length} source{sources.length === 1 ? '' : 's'}
|
|
71
67
|
</p>
|
|
72
68
|
</div>
|
|
73
69
|
<button
|
|
74
70
|
bind:this={closeButton}
|
|
75
71
|
type="button"
|
|
72
|
+
class="ds-lib-pane-close"
|
|
76
73
|
onclick={onclose}
|
|
77
74
|
aria-label={words.closeSource}
|
|
78
|
-
class="text-muted-foreground hover:text-foreground hover:bg-surface-2 focus-visible:ring-ring -mt-1 flex size-8 shrink-0 items-center justify-center rounded-lg transition-colors focus-visible:ring-2 focus-visible:outline-none"
|
|
79
75
|
>
|
|
80
|
-
<XIcon
|
|
76
|
+
<XIcon size={16} />
|
|
81
77
|
</button>
|
|
82
78
|
</header>
|
|
83
79
|
|
|
84
|
-
<div class="
|
|
80
|
+
<div class="ds-lib-pane-body">
|
|
85
81
|
<Markdown content={split.citations.length > 0 ? split.body : rawAnswer} />
|
|
86
82
|
|
|
87
83
|
{#if sources.length > 0}
|
|
88
|
-
<
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
</h3>
|
|
92
|
-
<ol class="flex flex-col gap-1">
|
|
93
|
-
{#each sources as source (source.n)}
|
|
94
|
-
{@const mark = trustMark(source, words)}
|
|
95
|
-
<li>
|
|
96
|
-
<button
|
|
97
|
-
type="button"
|
|
98
|
-
onclick={() => oncite?.(source)}
|
|
99
|
-
disabled={!source.document_id || !oncite}
|
|
100
|
-
class="border-border hover:border-border-strong hover:bg-surface-2 focus-visible:ring-ring flex w-full items-baseline gap-2 rounded-lg border px-2.5 py-1.5 text-left text-sm transition-colors focus-visible:ring-2 focus-visible:outline-none disabled:cursor-default disabled:hover:bg-transparent"
|
|
101
|
-
>
|
|
102
|
-
<span
|
|
103
|
-
class="bg-primary/15 text-foreground shrink-0 rounded px-1.5 font-mono text-xs tabular-nums"
|
|
104
|
-
>{source.n}</span
|
|
105
|
-
>
|
|
106
|
-
<span class="min-w-0">
|
|
107
|
-
<span class="text-foreground">{source.title}</span>
|
|
108
|
-
{#if source.section}<span class="text-muted-foreground">
|
|
109
|
-
· {source.section}</span
|
|
110
|
-
>{/if}
|
|
111
|
-
{#if mark}<span class="text-muted-foreground/80"> · {mark}</span>{/if}
|
|
112
|
-
</span>
|
|
113
|
-
</button>
|
|
114
|
-
</li>
|
|
115
|
-
{/each}
|
|
116
|
-
</ol>
|
|
117
|
-
</section>
|
|
84
|
+
<div class="ds-lib-pane-sources">
|
|
85
|
+
<SourceList {sources} {words} {oncite} level={3} />
|
|
86
|
+
</div>
|
|
118
87
|
{/if}
|
|
119
88
|
</div>
|
|
120
89
|
</aside>
|
|
90
|
+
|
|
91
|
+
<style>
|
|
92
|
+
.ds-lib-pane {
|
|
93
|
+
position: fixed;
|
|
94
|
+
inset-inline: 0;
|
|
95
|
+
bottom: 0;
|
|
96
|
+
z-index: 40;
|
|
97
|
+
display: flex;
|
|
98
|
+
height: 80svh;
|
|
99
|
+
flex-direction: column;
|
|
100
|
+
border-top: 1px solid var(--ds-color-border);
|
|
101
|
+
border-start-start-radius: var(--ds-radius-xl);
|
|
102
|
+
border-start-end-radius: var(--ds-radius-xl);
|
|
103
|
+
background: var(--ds-color-surface-1);
|
|
104
|
+
box-shadow: 0 -12px 40px rgb(0 0 0 / 0.25);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.ds-lib-pane-grabber {
|
|
108
|
+
display: flex;
|
|
109
|
+
justify-content: center;
|
|
110
|
+
padding-top: 0.5rem;
|
|
111
|
+
padding-bottom: 0.25rem;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.ds-lib-pane-grabber span {
|
|
115
|
+
width: 2.25rem;
|
|
116
|
+
height: 0.25rem;
|
|
117
|
+
border-radius: var(--ds-radius-full);
|
|
118
|
+
background: var(--ds-color-border);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.ds-lib-pane-header {
|
|
122
|
+
display: flex;
|
|
123
|
+
align-items: flex-start;
|
|
124
|
+
gap: 0.5rem;
|
|
125
|
+
border-bottom: 1px solid var(--ds-color-border);
|
|
126
|
+
padding: 0.75rem 1rem;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.ds-lib-pane-heading {
|
|
130
|
+
min-width: 0;
|
|
131
|
+
flex: 1;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.ds-lib-pane-title,
|
|
135
|
+
.ds-lib-pane-subtitle {
|
|
136
|
+
margin: 0;
|
|
137
|
+
overflow: hidden;
|
|
138
|
+
text-overflow: ellipsis;
|
|
139
|
+
white-space: nowrap;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.ds-lib-pane-title {
|
|
143
|
+
color: var(--ds-color-foreground);
|
|
144
|
+
font-family: inherit;
|
|
145
|
+
font-size: 0.875rem;
|
|
146
|
+
font-weight: 600;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.ds-lib-pane-subtitle {
|
|
150
|
+
color: var(--ds-color-muted-foreground);
|
|
151
|
+
font-size: var(--ds-text-2xs);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.ds-lib-pane-close {
|
|
155
|
+
display: flex;
|
|
156
|
+
width: 2rem;
|
|
157
|
+
height: 2rem;
|
|
158
|
+
flex: none;
|
|
159
|
+
align-items: center;
|
|
160
|
+
justify-content: center;
|
|
161
|
+
margin-top: -0.25rem;
|
|
162
|
+
border: 0;
|
|
163
|
+
border-radius: var(--ds-radius-lg);
|
|
164
|
+
background: none;
|
|
165
|
+
color: var(--ds-color-muted-foreground);
|
|
166
|
+
cursor: pointer;
|
|
167
|
+
transition:
|
|
168
|
+
color 150ms ease,
|
|
169
|
+
background-color 150ms ease;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.ds-lib-pane-close:hover {
|
|
173
|
+
background: var(--ds-color-surface-2);
|
|
174
|
+
color: var(--ds-color-foreground);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.ds-lib-pane-close:focus-visible {
|
|
178
|
+
outline: 2px solid var(--ds-color-ring);
|
|
179
|
+
outline-offset: 2px;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.ds-lib-pane-body {
|
|
183
|
+
min-height: 0;
|
|
184
|
+
flex: 1;
|
|
185
|
+
overflow-y: auto;
|
|
186
|
+
overscroll-behavior: contain;
|
|
187
|
+
padding: 0.75rem 1rem;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.ds-lib-pane-sources {
|
|
191
|
+
margin-top: 1.5rem;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@media (min-width: 64rem) {
|
|
195
|
+
.ds-lib-pane {
|
|
196
|
+
position: relative;
|
|
197
|
+
inset: auto;
|
|
198
|
+
height: auto;
|
|
199
|
+
width: 35rem;
|
|
200
|
+
flex: none;
|
|
201
|
+
border-top: 0;
|
|
202
|
+
border-inline-start: 1px solid var(--ds-color-border);
|
|
203
|
+
border-radius: 0;
|
|
204
|
+
box-shadow: none;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.ds-lib-pane-grabber {
|
|
208
|
+
display: none;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
</style>
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
MAX_FILES,
|
|
24
24
|
rejectionMessage
|
|
25
25
|
} from '../../attachments';
|
|
26
|
+
import { DEFAULT_PERSONA, resolveCopy, type LibrarianCopy } from '../../copy';
|
|
26
27
|
|
|
27
28
|
export type Scope = 'document' | 'collection' | 'library';
|
|
28
29
|
|
|
@@ -44,8 +45,11 @@
|
|
|
44
45
|
* control renders — studying is a mode of asking, never a tab, so a
|
|
45
46
|
* host with nothing to build offers none rather than a disabled one. */
|
|
46
47
|
onbriefing?: () => void;
|
|
47
|
-
/**
|
|
48
|
+
/** Who is being asked. A slug is fine — `penny` renders as "Penny" — and
|
|
49
|
+
* both placeholders are composed from it. */
|
|
48
50
|
name?: string;
|
|
51
|
+
/** Overrides for the package's own words. */
|
|
52
|
+
copy?: Partial<LibrarianCopy>;
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
let {
|
|
@@ -60,9 +64,12 @@
|
|
|
60
64
|
onsubmit,
|
|
61
65
|
onstop,
|
|
62
66
|
onbriefing,
|
|
63
|
-
name =
|
|
67
|
+
name = DEFAULT_PERSONA,
|
|
68
|
+
copy
|
|
64
69
|
}: Props = $props();
|
|
65
70
|
|
|
71
|
+
const words = $derived(resolveCopy(copy, name));
|
|
72
|
+
|
|
66
73
|
// What Milton is being asked about — this document, this collection, or
|
|
67
74
|
// the whole library. Callers that have no narrower scope pass neither
|
|
68
75
|
// name, leaving "The whole library" the sole entry — and a sole entry is
|
|
@@ -180,30 +187,25 @@
|
|
|
180
187
|
</script>
|
|
181
188
|
|
|
182
189
|
<div
|
|
190
|
+
class="ds-lib-composer-lift"
|
|
183
191
|
style="transform: translateY(-{lift}px); padding-bottom: {lift
|
|
184
192
|
? '0px'
|
|
185
193
|
: 'env(safe-area-inset-bottom, 0px)'}"
|
|
186
|
-
class="transition-transform duration-150"
|
|
187
194
|
>
|
|
188
|
-
<div
|
|
189
|
-
class="border-border bg-surface-1 focus-within:border-primary/60 rounded-xl border transition-colors"
|
|
190
|
-
>
|
|
195
|
+
<div class="ds-lib-box">
|
|
191
196
|
{#if files.length > 0}
|
|
192
|
-
<ul class="
|
|
197
|
+
<ul class="ds-lib-files">
|
|
193
198
|
{#each files as file, index (file.name + file.size)}
|
|
194
|
-
<li
|
|
195
|
-
class="
|
|
196
|
-
|
|
197
|
-
<span class="text-foreground truncate">{file.name}</span>
|
|
198
|
-
<span class="text-muted-foreground shrink-0 tabular-nums">{formatSize(file.size)}</span
|
|
199
|
-
>
|
|
199
|
+
<li class="ds-lib-file">
|
|
200
|
+
<span class="ds-lib-file-name">{file.name}</span>
|
|
201
|
+
<span class="ds-lib-file-size">{formatSize(file.size)}</span>
|
|
200
202
|
<button
|
|
201
203
|
type="button"
|
|
204
|
+
class="ds-lib-file-remove"
|
|
202
205
|
onclick={() => remove(index)}
|
|
203
206
|
aria-label="Remove {file.name}"
|
|
204
|
-
class="text-muted-foreground hover:text-foreground hover:bg-surface-3 focus-visible:ring-ring flex size-5 shrink-0 items-center justify-center rounded transition-colors focus-visible:ring-2 focus-visible:outline-none"
|
|
205
207
|
>
|
|
206
|
-
<XIcon
|
|
208
|
+
<XIcon size={12} />
|
|
207
209
|
</button>
|
|
208
210
|
</li>
|
|
209
211
|
{/each}
|
|
@@ -217,11 +219,11 @@
|
|
|
217
219
|
onkeydown={keydown}
|
|
218
220
|
rows="1"
|
|
219
221
|
disabled={running}
|
|
220
|
-
placeholder={running ?
|
|
221
|
-
class="
|
|
222
|
+
placeholder={running ? words.answeringPlaceholder : words.askPlaceholder}
|
|
223
|
+
class="ds-lib-input"
|
|
222
224
|
></textarea>
|
|
223
225
|
|
|
224
|
-
<div class="
|
|
226
|
+
<div class="ds-lib-controls">
|
|
225
227
|
{#if attachments}
|
|
226
228
|
<input
|
|
227
229
|
bind:this={picker}
|
|
@@ -229,75 +231,287 @@
|
|
|
229
231
|
multiple
|
|
230
232
|
accept={ACCEPT_ATTRIBUTE}
|
|
231
233
|
onchange={pick}
|
|
232
|
-
class="
|
|
234
|
+
class="ds-lib-picker"
|
|
233
235
|
tabindex="-1"
|
|
234
236
|
aria-hidden="true"
|
|
235
237
|
/>
|
|
236
238
|
<button
|
|
237
239
|
type="button"
|
|
240
|
+
class="ds-lib-icon-button"
|
|
238
241
|
onclick={() => picker?.click()}
|
|
239
242
|
disabled={running || files.length >= MAX_FILES}
|
|
240
243
|
aria-label="Attach a file"
|
|
241
|
-
class="text-muted-foreground hover:text-foreground hover:bg-surface-2 focus-visible:ring-ring flex size-8 shrink-0 items-center justify-center rounded-full transition-colors focus-visible:ring-2 focus-visible:outline-none disabled:opacity-30"
|
|
242
244
|
>
|
|
243
|
-
<PaperclipIcon
|
|
245
|
+
<PaperclipIcon size={16} />
|
|
244
246
|
</button>
|
|
245
247
|
{/if}
|
|
246
248
|
|
|
247
249
|
{#if onbriefing}
|
|
248
250
|
<button
|
|
249
251
|
type="button"
|
|
252
|
+
class="ds-lib-icon-button"
|
|
250
253
|
onclick={onbriefing}
|
|
251
254
|
disabled={running}
|
|
252
255
|
aria-label="Ask for a briefing"
|
|
253
256
|
title="Ask for a briefing"
|
|
254
|
-
class="text-muted-foreground hover:text-foreground hover:bg-surface-2 focus-visible:ring-ring flex size-8 shrink-0 items-center justify-center rounded-full transition-colors focus-visible:ring-2 focus-visible:outline-none disabled:opacity-30"
|
|
255
257
|
>
|
|
256
|
-
<FileTextIcon
|
|
258
|
+
<FileTextIcon size={16} />
|
|
257
259
|
</button>
|
|
258
260
|
{/if}
|
|
259
261
|
|
|
260
262
|
{#if hasChoice}
|
|
261
|
-
<div class="
|
|
263
|
+
<div class="ds-lib-scopes">
|
|
262
264
|
{#each choices as choice (choice.id)}
|
|
263
265
|
<button
|
|
264
266
|
type="button"
|
|
267
|
+
class="ds-lib-scope-chip"
|
|
268
|
+
class:is-chosen={scope === choice.id}
|
|
265
269
|
onclick={() => onscope(choice.id)}
|
|
266
|
-
class="max-w-full truncate rounded-full px-2 py-0.5 text-xs transition-colors {scope ===
|
|
267
|
-
choice.id
|
|
268
|
-
? 'bg-primary/15 text-foreground border-primary/40 border'
|
|
269
|
-
: 'text-muted-foreground hover:text-foreground border border-transparent'}"
|
|
270
270
|
>
|
|
271
271
|
{choice.label}
|
|
272
272
|
</button>
|
|
273
273
|
{/each}
|
|
274
274
|
</div>
|
|
275
275
|
{/if}
|
|
276
|
-
<span class="
|
|
276
|
+
<span class="ds-lib-spacer"></span>
|
|
277
277
|
{#if running}
|
|
278
|
-
<button
|
|
279
|
-
|
|
280
|
-
onclick={onstop}
|
|
281
|
-
aria-label="Stop"
|
|
282
|
-
class="bg-foreground text-background hover:bg-foreground/90 flex size-8 items-center justify-center rounded-full transition-colors"
|
|
283
|
-
>
|
|
284
|
-
<SquareIcon class="size-3.5 fill-current" />
|
|
278
|
+
<button type="button" class="ds-lib-stop" onclick={onstop} aria-label="Stop">
|
|
279
|
+
<SquareIcon size={14} fill="currentColor" />
|
|
285
280
|
</button>
|
|
286
281
|
{:else}
|
|
287
282
|
<button
|
|
288
283
|
type="button"
|
|
284
|
+
class="ds-lib-send"
|
|
289
285
|
onclick={submit}
|
|
290
286
|
disabled={!value.trim()}
|
|
291
287
|
aria-label="Send"
|
|
292
|
-
class="bg-primary text-primary-foreground hover:bg-primary/90 disabled:hover:bg-primary flex size-8 items-center justify-center rounded-full transition-all disabled:opacity-30"
|
|
293
288
|
>
|
|
294
|
-
<ArrowUpIcon
|
|
289
|
+
<ArrowUpIcon size={16} />
|
|
295
290
|
</button>
|
|
296
291
|
{/if}
|
|
297
292
|
</div>
|
|
298
293
|
</div>
|
|
299
294
|
|
|
300
295
|
{#if rejected}
|
|
301
|
-
<p class="
|
|
296
|
+
<p class="ds-lib-rejected" role="status" aria-live="polite">{rejected}</p>
|
|
302
297
|
{/if}
|
|
303
298
|
</div>
|
|
299
|
+
|
|
300
|
+
<style>
|
|
301
|
+
.ds-lib-composer-lift {
|
|
302
|
+
transition: transform 150ms ease;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.ds-lib-box {
|
|
306
|
+
border: 1px solid var(--ds-color-border);
|
|
307
|
+
border-radius: var(--ds-radius-xl);
|
|
308
|
+
background: var(--ds-color-surface-1);
|
|
309
|
+
transition: border-color 150ms ease;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.ds-lib-box:focus-within {
|
|
313
|
+
border-color: color-mix(in oklab, var(--ds-color-primary) 60%, transparent);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.ds-lib-files {
|
|
317
|
+
display: flex;
|
|
318
|
+
flex-wrap: wrap;
|
|
319
|
+
gap: 0.375rem;
|
|
320
|
+
margin: 0;
|
|
321
|
+
padding: 0.75rem 0.75rem 0;
|
|
322
|
+
list-style: none;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.ds-lib-file {
|
|
326
|
+
display: flex;
|
|
327
|
+
max-width: 100%;
|
|
328
|
+
align-items: center;
|
|
329
|
+
gap: 0.375rem;
|
|
330
|
+
border: 1px solid var(--ds-color-border);
|
|
331
|
+
border-radius: var(--ds-radius-lg);
|
|
332
|
+
background: var(--ds-color-surface-2);
|
|
333
|
+
padding: 0.25rem 0.25rem 0.25rem 0.5rem;
|
|
334
|
+
font-size: var(--ds-text-2xs);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.ds-lib-file-name {
|
|
338
|
+
overflow: hidden;
|
|
339
|
+
text-overflow: ellipsis;
|
|
340
|
+
white-space: nowrap;
|
|
341
|
+
color: var(--ds-color-foreground);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.ds-lib-file-size {
|
|
345
|
+
flex: none;
|
|
346
|
+
color: var(--ds-color-muted-foreground);
|
|
347
|
+
font-variant-numeric: tabular-nums;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.ds-lib-file-remove {
|
|
351
|
+
display: flex;
|
|
352
|
+
width: 1.25rem;
|
|
353
|
+
height: 1.25rem;
|
|
354
|
+
flex: none;
|
|
355
|
+
align-items: center;
|
|
356
|
+
justify-content: center;
|
|
357
|
+
border: 0;
|
|
358
|
+
border-radius: var(--ds-radius-sm);
|
|
359
|
+
background: none;
|
|
360
|
+
color: var(--ds-color-muted-foreground);
|
|
361
|
+
cursor: pointer;
|
|
362
|
+
transition:
|
|
363
|
+
color 150ms ease,
|
|
364
|
+
background-color 150ms ease;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.ds-lib-file-remove:hover {
|
|
368
|
+
background: var(--ds-color-surface-3);
|
|
369
|
+
color: var(--ds-color-foreground);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.ds-lib-input {
|
|
373
|
+
display: block;
|
|
374
|
+
width: 100%;
|
|
375
|
+
resize: none;
|
|
376
|
+
border: 0;
|
|
377
|
+
background: transparent;
|
|
378
|
+
padding: 0.75rem 1rem 0.5rem;
|
|
379
|
+
color: var(--ds-color-foreground);
|
|
380
|
+
font: inherit;
|
|
381
|
+
font-size: 1rem;
|
|
382
|
+
outline: none;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.ds-lib-input::placeholder {
|
|
386
|
+
color: var(--ds-color-muted-foreground);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.ds-lib-input:disabled {
|
|
390
|
+
opacity: 0.6;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.ds-lib-controls {
|
|
394
|
+
display: flex;
|
|
395
|
+
align-items: center;
|
|
396
|
+
gap: 0.5rem;
|
|
397
|
+
padding: 0 0.75rem 0.625rem;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.ds-lib-picker {
|
|
401
|
+
display: none;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.ds-lib-icon-button,
|
|
405
|
+
.ds-lib-stop,
|
|
406
|
+
.ds-lib-send {
|
|
407
|
+
display: flex;
|
|
408
|
+
width: 2rem;
|
|
409
|
+
height: 2rem;
|
|
410
|
+
flex: none;
|
|
411
|
+
align-items: center;
|
|
412
|
+
justify-content: center;
|
|
413
|
+
border: 0;
|
|
414
|
+
border-radius: var(--ds-radius-full);
|
|
415
|
+
cursor: pointer;
|
|
416
|
+
transition:
|
|
417
|
+
color 150ms ease,
|
|
418
|
+
background-color 150ms ease,
|
|
419
|
+
opacity 150ms ease;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.ds-lib-icon-button {
|
|
423
|
+
background: none;
|
|
424
|
+
color: var(--ds-color-muted-foreground);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.ds-lib-icon-button:hover:not(:disabled) {
|
|
428
|
+
background: var(--ds-color-surface-2);
|
|
429
|
+
color: var(--ds-color-foreground);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.ds-lib-icon-button:disabled,
|
|
433
|
+
.ds-lib-send:disabled {
|
|
434
|
+
cursor: default;
|
|
435
|
+
opacity: 0.3;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.ds-lib-icon-button:focus-visible,
|
|
439
|
+
.ds-lib-stop:focus-visible,
|
|
440
|
+
.ds-lib-send:focus-visible,
|
|
441
|
+
.ds-lib-scope-chip:focus-visible,
|
|
442
|
+
.ds-lib-file-remove:focus-visible {
|
|
443
|
+
outline: 2px solid var(--ds-color-ring);
|
|
444
|
+
outline-offset: 2px;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.ds-lib-stop {
|
|
448
|
+
background: var(--ds-color-foreground);
|
|
449
|
+
color: var(--ds-color-background);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
.ds-lib-send {
|
|
453
|
+
background: var(--ds-color-primary);
|
|
454
|
+
color: var(--ds-color-primary-foreground);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
.ds-lib-send:hover:not(:disabled),
|
|
458
|
+
.ds-lib-stop:hover {
|
|
459
|
+
opacity: 0.9;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/* Three chips in a narrow column clipped all three to fragments
|
|
463
|
+
("defence-s…", "All colle…"). Wrapping beats truncating: a chip a reader
|
|
464
|
+
cannot finish reading is not a control, it is decoration. */
|
|
465
|
+
.ds-lib-scopes {
|
|
466
|
+
display: flex;
|
|
467
|
+
min-width: 0;
|
|
468
|
+
flex-wrap: wrap;
|
|
469
|
+
align-items: center;
|
|
470
|
+
gap: 0.25rem;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
.ds-lib-scope-chip {
|
|
474
|
+
max-width: 100%;
|
|
475
|
+
overflow: hidden;
|
|
476
|
+
border: 1px solid transparent;
|
|
477
|
+
border-radius: var(--ds-radius-full);
|
|
478
|
+
background: none;
|
|
479
|
+
padding: 0.125rem 0.5rem;
|
|
480
|
+
color: var(--ds-color-muted-foreground);
|
|
481
|
+
font: inherit;
|
|
482
|
+
font-size: var(--ds-text-2xs);
|
|
483
|
+
text-overflow: ellipsis;
|
|
484
|
+
white-space: nowrap;
|
|
485
|
+
cursor: pointer;
|
|
486
|
+
transition:
|
|
487
|
+
color 150ms ease,
|
|
488
|
+
background-color 150ms ease;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
.ds-lib-scope-chip:hover {
|
|
492
|
+
color: var(--ds-color-foreground);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
.ds-lib-scope-chip.is-chosen {
|
|
496
|
+
border-color: color-mix(in oklab, var(--ds-color-primary) 40%, transparent);
|
|
497
|
+
background: color-mix(in oklab, var(--ds-color-primary) 15%, transparent);
|
|
498
|
+
color: var(--ds-color-foreground);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
.ds-lib-spacer {
|
|
502
|
+
flex: 1;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.ds-lib-rejected {
|
|
506
|
+
margin: 0;
|
|
507
|
+
padding: 0.375rem 0.25rem 0;
|
|
508
|
+
color: var(--ds-color-status-error);
|
|
509
|
+
font-size: var(--ds-text-2xs);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
@media (prefers-reduced-motion: reduce) {
|
|
513
|
+
.ds-lib-composer-lift {
|
|
514
|
+
transition: none;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
</style>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type LibrarianCopy } from '../../copy';
|
|
1
2
|
export type Scope = 'document' | 'collection' | 'library';
|
|
2
3
|
interface Props {
|
|
3
4
|
value: string;
|
|
@@ -17,8 +18,11 @@ interface Props {
|
|
|
17
18
|
* control renders — studying is a mode of asking, never a tab, so a
|
|
18
19
|
* host with nothing to build offers none rather than a disabled one. */
|
|
19
20
|
onbriefing?: () => void;
|
|
20
|
-
/**
|
|
21
|
+
/** Who is being asked. A slug is fine — `penny` renders as "Penny" — and
|
|
22
|
+
* both placeholders are composed from it. */
|
|
21
23
|
name?: string;
|
|
24
|
+
/** Overrides for the package's own words. */
|
|
25
|
+
copy?: Partial<LibrarianCopy>;
|
|
22
26
|
}
|
|
23
27
|
declare const Composer: import("svelte").Component<Props, {}, "value" | "files">;
|
|
24
28
|
type Composer = ReturnType<typeof Composer>;
|