@agent-native/core 0.137.0 → 0.137.1
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/corpus/README.md +1 -1
- package/corpus/templates/analytics/app/components/AgentCompletionSound.tsx +105 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +44 -35
- package/corpus/templates/analytics/app/i18n-data.ts +38 -0
- package/corpus/templates/analytics/app/pages/Settings.tsx +53 -1
- package/corpus/templates/analytics/app/pages/settings/settings-search.ts +6 -0
- package/corpus/templates/analytics/changelog/2026-08-04-choose-whether-analytics-plays-a-bell-when-the-agent-finishe.md +6 -0
- package/corpus/templates/analytics/shared/analytics-user-prefs.ts +2 -0
- package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +321 -0
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +32 -11
- package/corpus/templates/slides/app/lib/recent-references.ts +82 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +3 -0
- package/corpus/templates/slides/app/pages/Index.tsx +236 -181
- package/dist/client/DefaultSpinner.d.ts +0 -12
- package/dist/client/DefaultSpinner.js +22 -2
- package/dist/client/onboarding/use-onboarding.js +3 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/deploy/build.js +2 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +3 -3
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +25 -9
- package/package.json +1 -1
- package/src/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +25 -9
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IconArrowRight,
|
|
3
|
+
IconPalette,
|
|
4
|
+
IconPresentation,
|
|
5
|
+
IconUpload,
|
|
6
|
+
} from "@tabler/icons-react";
|
|
7
|
+
import type { ChangeEvent, ReactNode } from "react";
|
|
8
|
+
|
|
9
|
+
import { Button } from "@/components/ui/button";
|
|
10
|
+
import {
|
|
11
|
+
Dialog,
|
|
12
|
+
DialogContent,
|
|
13
|
+
DialogDescription,
|
|
14
|
+
DialogHeader,
|
|
15
|
+
DialogTitle,
|
|
16
|
+
} from "@/components/ui/dialog";
|
|
17
|
+
import {
|
|
18
|
+
Select,
|
|
19
|
+
SelectContent,
|
|
20
|
+
SelectGroup,
|
|
21
|
+
SelectItem,
|
|
22
|
+
SelectLabel,
|
|
23
|
+
SelectTrigger,
|
|
24
|
+
SelectValue,
|
|
25
|
+
} from "@/components/ui/select";
|
|
26
|
+
import type { Deck } from "@/context/DeckContext";
|
|
27
|
+
import type { RecentReference } from "@/lib/recent-references";
|
|
28
|
+
import { cn } from "@/lib/utils";
|
|
29
|
+
|
|
30
|
+
export interface NewDeckReferenceSelection {
|
|
31
|
+
designSystemId?: string | null;
|
|
32
|
+
referenceDeckId?: string | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface DesignSystemOption {
|
|
36
|
+
id: string;
|
|
37
|
+
title: string;
|
|
38
|
+
isDefault?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface NewDeckReferenceStepProps {
|
|
42
|
+
open: boolean;
|
|
43
|
+
designSystems: DesignSystemOption[];
|
|
44
|
+
decks: Deck[];
|
|
45
|
+
defaultDesignSystemId: string | null;
|
|
46
|
+
defaultReferenceDeckId: string | null;
|
|
47
|
+
recentReferences: RecentReference[];
|
|
48
|
+
onSelect: (selection: NewDeckReferenceSelection) => void;
|
|
49
|
+
onImport: (files: File[]) => Promise<void>;
|
|
50
|
+
onSkip: () => void;
|
|
51
|
+
onOpenChange: (open: boolean) => void;
|
|
52
|
+
importing?: boolean;
|
|
53
|
+
title: string;
|
|
54
|
+
designSystemLabel: string;
|
|
55
|
+
referenceDeckLabel: string;
|
|
56
|
+
chooseDeckLabel: string;
|
|
57
|
+
importFileLabel: string;
|
|
58
|
+
importingLabel: string;
|
|
59
|
+
skipLabel: string;
|
|
60
|
+
defaultSuffix: string;
|
|
61
|
+
starredLabel: string;
|
|
62
|
+
otherDecksLabel: string;
|
|
63
|
+
description: string;
|
|
64
|
+
promptNote?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function NewDeckReferenceStep({
|
|
68
|
+
open,
|
|
69
|
+
designSystems,
|
|
70
|
+
decks,
|
|
71
|
+
defaultDesignSystemId,
|
|
72
|
+
defaultReferenceDeckId,
|
|
73
|
+
recentReferences,
|
|
74
|
+
onSelect,
|
|
75
|
+
onImport,
|
|
76
|
+
onSkip,
|
|
77
|
+
onOpenChange,
|
|
78
|
+
importing = false,
|
|
79
|
+
title,
|
|
80
|
+
designSystemLabel,
|
|
81
|
+
referenceDeckLabel,
|
|
82
|
+
chooseDeckLabel,
|
|
83
|
+
importFileLabel,
|
|
84
|
+
importingLabel,
|
|
85
|
+
skipLabel,
|
|
86
|
+
defaultSuffix,
|
|
87
|
+
starredLabel,
|
|
88
|
+
otherDecksLabel,
|
|
89
|
+
description,
|
|
90
|
+
promptNote,
|
|
91
|
+
}: NewDeckReferenceStepProps) {
|
|
92
|
+
const designSystemById = new Map(
|
|
93
|
+
designSystems.map((designSystem) => [designSystem.id, designSystem]),
|
|
94
|
+
);
|
|
95
|
+
const deckById = new Map(decks.map((deck) => [deck.id, deck]));
|
|
96
|
+
const recentOptions = recentReferences
|
|
97
|
+
.map((reference) => {
|
|
98
|
+
const item =
|
|
99
|
+
reference.kind === "design-system"
|
|
100
|
+
? designSystemById.get(reference.id)
|
|
101
|
+
: deckById.get(reference.id);
|
|
102
|
+
return item ? { reference, item } : null;
|
|
103
|
+
})
|
|
104
|
+
.filter(
|
|
105
|
+
(
|
|
106
|
+
value,
|
|
107
|
+
): value is {
|
|
108
|
+
reference: RecentReference;
|
|
109
|
+
item: DesignSystemOption | Deck;
|
|
110
|
+
} => value !== null,
|
|
111
|
+
);
|
|
112
|
+
const defaultReferenceKeys = new Set(
|
|
113
|
+
[
|
|
114
|
+
defaultDesignSystemId ? `design-system:${defaultDesignSystemId}` : null,
|
|
115
|
+
defaultReferenceDeckId ? `deck:${defaultReferenceDeckId}` : null,
|
|
116
|
+
].filter((value): value is string => value !== null),
|
|
117
|
+
);
|
|
118
|
+
const visibleRecentOptions = recentOptions.filter(
|
|
119
|
+
({ reference }) =>
|
|
120
|
+
!defaultReferenceKeys.has(`${reference.kind}:${reference.id}`),
|
|
121
|
+
);
|
|
122
|
+
const starredDecks = decks.filter((deck) => deck.starred);
|
|
123
|
+
const otherDecks = decks.filter((deck) => !deck.starred);
|
|
124
|
+
|
|
125
|
+
const handleImport = async (event: ChangeEvent<HTMLInputElement>) => {
|
|
126
|
+
const files = Array.from(event.target.files ?? []);
|
|
127
|
+
event.target.value = "";
|
|
128
|
+
if (files.length === 0) return;
|
|
129
|
+
await onImport(files);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
134
|
+
<DialogContent className="max-h-[min(720px,calc(100vh-32px))] overflow-y-auto sm:max-w-2xl">
|
|
135
|
+
<DialogHeader>
|
|
136
|
+
<DialogTitle>{title}</DialogTitle>
|
|
137
|
+
<DialogDescription>{description}</DialogDescription>
|
|
138
|
+
</DialogHeader>
|
|
139
|
+
|
|
140
|
+
<div className="grid gap-4">
|
|
141
|
+
{(defaultDesignSystemId || defaultReferenceDeckId) && (
|
|
142
|
+
<div className="grid gap-2 sm:grid-cols-2">
|
|
143
|
+
{defaultDesignSystemId &&
|
|
144
|
+
designSystemById.has(defaultDesignSystemId) && (
|
|
145
|
+
<ReferenceCard
|
|
146
|
+
icon={<IconPalette className="size-4" />}
|
|
147
|
+
label={
|
|
148
|
+
designSystemById.get(defaultDesignSystemId)?.title ??
|
|
149
|
+
designSystemLabel
|
|
150
|
+
}
|
|
151
|
+
meta={`${designSystemLabel}${defaultSuffix}`}
|
|
152
|
+
onClick={() =>
|
|
153
|
+
onSelect({
|
|
154
|
+
designSystemId: defaultDesignSystemId,
|
|
155
|
+
referenceDeckId: null,
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
/>
|
|
159
|
+
)}
|
|
160
|
+
{defaultReferenceDeckId &&
|
|
161
|
+
deckById.has(defaultReferenceDeckId) && (
|
|
162
|
+
<ReferenceCard
|
|
163
|
+
icon={<IconPresentation className="size-4" />}
|
|
164
|
+
label={deckById.get(defaultReferenceDeckId)?.title ?? ""}
|
|
165
|
+
meta={`${referenceDeckLabel}${defaultSuffix}`}
|
|
166
|
+
onClick={() =>
|
|
167
|
+
onSelect({
|
|
168
|
+
designSystemId: null,
|
|
169
|
+
referenceDeckId: defaultReferenceDeckId,
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
/>
|
|
173
|
+
)}
|
|
174
|
+
</div>
|
|
175
|
+
)}
|
|
176
|
+
|
|
177
|
+
{visibleRecentOptions.length > 0 && (
|
|
178
|
+
<div className="grid gap-2">
|
|
179
|
+
<div className="grid gap-2 sm:grid-cols-2">
|
|
180
|
+
{visibleRecentOptions.map(({ reference, item }) => (
|
|
181
|
+
<ReferenceCard
|
|
182
|
+
key={`${reference.kind}:${reference.id}`}
|
|
183
|
+
icon={
|
|
184
|
+
reference.kind === "design-system" ? (
|
|
185
|
+
<IconPalette className="size-4" />
|
|
186
|
+
) : (
|
|
187
|
+
<IconPresentation className="size-4" />
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
label={item.title}
|
|
191
|
+
meta={
|
|
192
|
+
reference.kind === "design-system"
|
|
193
|
+
? designSystemLabel
|
|
194
|
+
: referenceDeckLabel
|
|
195
|
+
}
|
|
196
|
+
onClick={() =>
|
|
197
|
+
onSelect(
|
|
198
|
+
reference.kind === "design-system"
|
|
199
|
+
? {
|
|
200
|
+
designSystemId: reference.id,
|
|
201
|
+
referenceDeckId: null,
|
|
202
|
+
}
|
|
203
|
+
: {
|
|
204
|
+
designSystemId: null,
|
|
205
|
+
referenceDeckId: reference.id,
|
|
206
|
+
},
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
/>
|
|
210
|
+
))}
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
)}
|
|
214
|
+
|
|
215
|
+
{decks.length > 0 && (
|
|
216
|
+
<div className="grid gap-2">
|
|
217
|
+
<span className="text-xs font-medium text-muted-foreground">
|
|
218
|
+
{referenceDeckLabel}
|
|
219
|
+
</span>
|
|
220
|
+
<Select
|
|
221
|
+
onValueChange={(value) =>
|
|
222
|
+
onSelect({ designSystemId: null, referenceDeckId: value })
|
|
223
|
+
}
|
|
224
|
+
>
|
|
225
|
+
<SelectTrigger className="w-full">
|
|
226
|
+
<SelectValue placeholder={chooseDeckLabel} />
|
|
227
|
+
</SelectTrigger>
|
|
228
|
+
<SelectContent>
|
|
229
|
+
{starredDecks.length > 0 && (
|
|
230
|
+
<SelectGroup>
|
|
231
|
+
<SelectLabel>{starredLabel}</SelectLabel>
|
|
232
|
+
{starredDecks.map((deck) => (
|
|
233
|
+
<SelectItem key={deck.id} value={deck.id}>
|
|
234
|
+
{deck.title}
|
|
235
|
+
</SelectItem>
|
|
236
|
+
))}
|
|
237
|
+
</SelectGroup>
|
|
238
|
+
)}
|
|
239
|
+
{otherDecks.length > 0 && (
|
|
240
|
+
<SelectGroup>
|
|
241
|
+
<SelectLabel>{otherDecksLabel}</SelectLabel>
|
|
242
|
+
{otherDecks.map((deck) => (
|
|
243
|
+
<SelectItem key={deck.id} value={deck.id}>
|
|
244
|
+
{deck.title}
|
|
245
|
+
</SelectItem>
|
|
246
|
+
))}
|
|
247
|
+
</SelectGroup>
|
|
248
|
+
)}
|
|
249
|
+
</SelectContent>
|
|
250
|
+
</Select>
|
|
251
|
+
</div>
|
|
252
|
+
)}
|
|
253
|
+
|
|
254
|
+
<div className="flex flex-wrap items-center gap-2 border-t border-border pt-3">
|
|
255
|
+
<label
|
|
256
|
+
className={cn(
|
|
257
|
+
"inline-flex cursor-pointer items-center gap-2 rounded-md border border-border px-3 py-2 text-sm font-medium transition-colors hover:bg-accent",
|
|
258
|
+
importing && "pointer-events-none opacity-60",
|
|
259
|
+
)}
|
|
260
|
+
>
|
|
261
|
+
<IconUpload className="size-4" />
|
|
262
|
+
{importing ? importingLabel : importFileLabel}
|
|
263
|
+
<input
|
|
264
|
+
type="file"
|
|
265
|
+
className="sr-only"
|
|
266
|
+
accept=".pptx,.pdf,.docx"
|
|
267
|
+
multiple
|
|
268
|
+
disabled={importing}
|
|
269
|
+
onChange={(event) => void handleImport(event)}
|
|
270
|
+
/>
|
|
271
|
+
</label>
|
|
272
|
+
</div>
|
|
273
|
+
</div>
|
|
274
|
+
|
|
275
|
+
{promptNote && (
|
|
276
|
+
<p className="truncate border-t border-border pt-3 text-xs text-muted-foreground">
|
|
277
|
+
{promptNote}
|
|
278
|
+
</p>
|
|
279
|
+
)}
|
|
280
|
+
|
|
281
|
+
<div className="flex items-center justify-between border-t border-border pt-3">
|
|
282
|
+
<Button type="button" variant="ghost" onClick={onSkip}>
|
|
283
|
+
{skipLabel}
|
|
284
|
+
</Button>
|
|
285
|
+
<IconArrowRight className="size-4 text-muted-foreground" />
|
|
286
|
+
</div>
|
|
287
|
+
</DialogContent>
|
|
288
|
+
</Dialog>
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function ReferenceCard({
|
|
293
|
+
icon,
|
|
294
|
+
label,
|
|
295
|
+
meta,
|
|
296
|
+
onClick,
|
|
297
|
+
}: {
|
|
298
|
+
icon: ReactNode;
|
|
299
|
+
label: string;
|
|
300
|
+
meta: string;
|
|
301
|
+
onClick: () => void;
|
|
302
|
+
}) {
|
|
303
|
+
return (
|
|
304
|
+
<button
|
|
305
|
+
type="button"
|
|
306
|
+
onClick={onClick}
|
|
307
|
+
className="flex min-w-0 items-center gap-3 rounded-lg border border-border bg-card px-3 py-3 text-start transition-colors hover:border-foreground/30 hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
308
|
+
>
|
|
309
|
+
<span className="flex size-8 shrink-0 items-center justify-center rounded-md bg-accent text-muted-foreground">
|
|
310
|
+
{icon}
|
|
311
|
+
</span>
|
|
312
|
+
<span className="min-w-0">
|
|
313
|
+
<span className="block truncate text-sm font-medium">{label}</span>
|
|
314
|
+
<span className="block truncate text-xs text-muted-foreground">
|
|
315
|
+
{meta}
|
|
316
|
+
</span>
|
|
317
|
+
</span>
|
|
318
|
+
<IconArrowRight className="ms-auto size-4 shrink-0 text-muted-foreground" />
|
|
319
|
+
</button>
|
|
320
|
+
);
|
|
321
|
+
}
|
|
@@ -16,6 +16,37 @@ export interface UploadedFile {
|
|
|
16
16
|
size: number;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
export async function uploadPromptFiles(
|
|
20
|
+
files: File[],
|
|
21
|
+
): Promise<UploadedFile[]> {
|
|
22
|
+
if (files.length === 0) return [];
|
|
23
|
+
const formData = new FormData();
|
|
24
|
+
files.forEach((file) => formData.append("files", file));
|
|
25
|
+
const response = await fetch(`${appBasePath()}/api/uploads`, {
|
|
26
|
+
method: "POST",
|
|
27
|
+
body: formData,
|
|
28
|
+
});
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
let message = "Upload failed";
|
|
31
|
+
try {
|
|
32
|
+
const data: unknown = await response.json();
|
|
33
|
+
if (
|
|
34
|
+
data &&
|
|
35
|
+
typeof data === "object" &&
|
|
36
|
+
"error" in data &&
|
|
37
|
+
typeof data.error === "string" &&
|
|
38
|
+
data.error.trim()
|
|
39
|
+
) {
|
|
40
|
+
message = data.error;
|
|
41
|
+
}
|
|
42
|
+
} catch (error) {
|
|
43
|
+
throw new Error(`Upload failed (${response.status})`, { cause: error });
|
|
44
|
+
}
|
|
45
|
+
throw new Error(message);
|
|
46
|
+
}
|
|
47
|
+
return (await response.json()) as UploadedFile[];
|
|
48
|
+
}
|
|
49
|
+
|
|
19
50
|
/**
|
|
20
51
|
* Radix popovers portal to `document.body`, so a mousedown inside the model
|
|
21
52
|
* picker or attachment menu reads as "outside" any panel that hosts a composer.
|
|
@@ -137,17 +168,7 @@ export default function PromptPopover({
|
|
|
137
168
|
if (files.length === 0) return [];
|
|
138
169
|
setUploading(true);
|
|
139
170
|
try {
|
|
140
|
-
|
|
141
|
-
files.forEach((f) => formData.append("files", f));
|
|
142
|
-
const res = await fetch(`${appBasePath()}/api/uploads`, {
|
|
143
|
-
method: "POST",
|
|
144
|
-
body: formData,
|
|
145
|
-
});
|
|
146
|
-
if (!res.ok) {
|
|
147
|
-
const data = await res.json().catch(() => null);
|
|
148
|
-
throw new Error(data?.error || "Upload failed");
|
|
149
|
-
}
|
|
150
|
-
return (await res.json()) as UploadedFile[];
|
|
171
|
+
return await uploadPromptFiles(files);
|
|
151
172
|
} finally {
|
|
152
173
|
setUploading(false);
|
|
153
174
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export const RECENT_REFERENCES_STORAGE_KEY = "slides:recent-references";
|
|
2
|
+
|
|
3
|
+
export type RecentReferenceKind = "deck" | "design-system";
|
|
4
|
+
|
|
5
|
+
export interface RecentReference {
|
|
6
|
+
id: string;
|
|
7
|
+
kind: RecentReferenceKind;
|
|
8
|
+
lastUsedAt: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface RecentReferencesResult {
|
|
12
|
+
items: RecentReference[];
|
|
13
|
+
readable: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const MAX_RECENT_REFERENCES = 8;
|
|
17
|
+
|
|
18
|
+
function isRecentReference(value: unknown): value is RecentReference {
|
|
19
|
+
if (!value || typeof value !== "object") return false;
|
|
20
|
+
const candidate = value as Partial<RecentReference>;
|
|
21
|
+
return (
|
|
22
|
+
typeof candidate.id === "string" &&
|
|
23
|
+
candidate.id.length > 0 &&
|
|
24
|
+
(candidate.kind === "deck" || candidate.kind === "design-system") &&
|
|
25
|
+
typeof candidate.lastUsedAt === "number" &&
|
|
26
|
+
Number.isFinite(candidate.lastUsedAt)
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function readRecentReferences(
|
|
31
|
+
storage: Pick<Storage, "getItem"> | null | undefined = typeof window ===
|
|
32
|
+
"undefined"
|
|
33
|
+
? null
|
|
34
|
+
: window.localStorage,
|
|
35
|
+
): RecentReferencesResult {
|
|
36
|
+
if (!storage) return { items: [], readable: true };
|
|
37
|
+
|
|
38
|
+
let raw: string | null;
|
|
39
|
+
try {
|
|
40
|
+
raw = storage.getItem(RECENT_REFERENCES_STORAGE_KEY);
|
|
41
|
+
} catch {
|
|
42
|
+
return { items: [], readable: false };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (raw === null) return { items: [], readable: true };
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const parsed: unknown = JSON.parse(raw);
|
|
49
|
+
if (!Array.isArray(parsed)) return { items: [], readable: false };
|
|
50
|
+
return {
|
|
51
|
+
items: parsed.filter(isRecentReference).slice(0, MAX_RECENT_REFERENCES),
|
|
52
|
+
readable: true,
|
|
53
|
+
};
|
|
54
|
+
} catch {
|
|
55
|
+
return { items: [], readable: false };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function rememberRecentReference(
|
|
60
|
+
reference: Omit<RecentReference, "lastUsedAt">,
|
|
61
|
+
storage:
|
|
62
|
+
| Pick<Storage, "getItem" | "setItem">
|
|
63
|
+
| null
|
|
64
|
+
| undefined = typeof window === "undefined" ? null : window.localStorage,
|
|
65
|
+
): RecentReferencesResult {
|
|
66
|
+
const current = readRecentReferences(storage);
|
|
67
|
+
if (!storage || !current.readable) return current;
|
|
68
|
+
|
|
69
|
+
const next: RecentReference[] = [
|
|
70
|
+
{ ...reference, lastUsedAt: Date.now() },
|
|
71
|
+
...current.items.filter(
|
|
72
|
+
(item) => !(item.id === reference.id && item.kind === reference.kind),
|
|
73
|
+
),
|
|
74
|
+
].slice(0, MAX_RECENT_REFERENCES);
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
storage.setItem(RECENT_REFERENCES_STORAGE_KEY, JSON.stringify(next));
|
|
78
|
+
return { items: next, readable: true };
|
|
79
|
+
} catch {
|
|
80
|
+
return { items: current.items, readable: false };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -296,6 +296,9 @@ export default function DeckEditor() {
|
|
|
296
296
|
handleSubmit: handleQuestionSubmit,
|
|
297
297
|
handleSkip: handleQuestionSkip,
|
|
298
298
|
} = useGuidedQuestionFlow({
|
|
299
|
+
stateKey: "guided-questions",
|
|
300
|
+
browserTabId: TAB_ID,
|
|
301
|
+
queryKey: ["guided-questions"],
|
|
299
302
|
submitMessage: "Here are my answers — go ahead and create the slides.",
|
|
300
303
|
skipMessage:
|
|
301
304
|
"Skip the questions — just go ahead and create the slides with your best judgment.",
|