@agent-native/core 0.137.0 → 0.137.2
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/AddSlidePopover.tsx +258 -0
- package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +130 -0
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +25 -337
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +73 -53
- 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/components/editor/SlideContextToolbar.tsx +804 -0
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +101 -45
- package/corpus/templates/slides/app/components/editor/SlideOverflowWarning.tsx +7 -4
- package/corpus/templates/slides/app/components/editor/bullet-editing.ts +11 -3
- package/corpus/templates/slides/app/components/editor/commit-active-edit.ts +21 -0
- package/corpus/templates/slides/app/components/editor/list-editing.ts +219 -0
- package/corpus/templates/slides/app/components/editor/selection-overlay-measurement.ts +0 -3
- package/corpus/templates/slides/app/components/editor/slide-style.ts +199 -0
- package/corpus/templates/slides/app/global.css +14 -3
- package/corpus/templates/slides/app/i18n/en-US.ts +8 -1
- package/corpus/templates/slides/app/lib/recent-references.ts +82 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +51 -22
- package/corpus/templates/slides/app/pages/Index.tsx +236 -181
- package/corpus/templates/slides/changelog/2026-08-01-add-slide-moved-to-the-toolbar-and-the-slide-rail-is-now-mor.md +9 -0
- package/corpus/templates/slides/changelog/2026-08-01-add-slide-undo-redo-and-the-text-tool-now-lead-the-slide-too.md +9 -0
- package/corpus/templates/slides/changelog/2026-08-01-slide-styling-now-appears-in-a-contextual-toolbar-above-the-.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-01-the-slide-style-side-panel-is-retired-all-styling-now-lives-.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-03-the-slide-toolbar-is-denser-swatch-only-colors-dropdowns-for.md +10 -0
- package/corpus/templates/slides/changelog/2026-08-04-bullet-and-numbered-list-buttons-in-the-slide-toolbar-conver.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-04-italic-and-underline-are-now-one-click-away-in-the-slide-too.md +6 -0
- 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/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/deploy/build.js +2 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/progress/routes.d.ts +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +25 -9
- package/package.json +2 -2
- package/src/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +25 -9
- package/corpus/templates/slides/app/components/editor/SlideStyleInspector.tsx +0 -763
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { askUserQuestion } from "@agent-native/core/client/agent-chat";
|
|
2
1
|
import { callAction, useSession } from "@agent-native/core/client/hooks";
|
|
3
2
|
import { useT } from "@agent-native/core/client/i18n";
|
|
4
3
|
import { buildSignInReturnHref } from "@agent-native/core/client/ui";
|
|
@@ -21,8 +20,14 @@ import { useLocation, useNavigate, useSearchParams } from "react-router";
|
|
|
21
20
|
import { toast } from "sonner";
|
|
22
21
|
|
|
23
22
|
import DeckCard from "@/components/deck/DeckCard";
|
|
24
|
-
import
|
|
25
|
-
|
|
23
|
+
import {
|
|
24
|
+
NewDeckReferenceStep,
|
|
25
|
+
type NewDeckReferenceSelection,
|
|
26
|
+
} from "@/components/editor/NewDeckReferenceStep";
|
|
27
|
+
import PromptPopover, {
|
|
28
|
+
uploadPromptFiles,
|
|
29
|
+
type UploadedFile,
|
|
30
|
+
} from "@/components/editor/PromptDialog";
|
|
26
31
|
import {
|
|
27
32
|
AlertDialog,
|
|
28
33
|
AlertDialogAction,
|
|
@@ -34,15 +39,6 @@ import {
|
|
|
34
39
|
AlertDialogTitle,
|
|
35
40
|
} from "@/components/ui/alert-dialog";
|
|
36
41
|
import { Button } from "@/components/ui/button";
|
|
37
|
-
import {
|
|
38
|
-
Select,
|
|
39
|
-
SelectContent,
|
|
40
|
-
SelectGroup,
|
|
41
|
-
SelectItem,
|
|
42
|
-
SelectLabel,
|
|
43
|
-
SelectTrigger,
|
|
44
|
-
SelectValue,
|
|
45
|
-
} from "@/components/ui/select";
|
|
46
42
|
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
|
47
43
|
import type { Deck } from "@/context/DeckContext";
|
|
48
44
|
import { useDecks } from "@/context/DeckContext";
|
|
@@ -51,7 +47,11 @@ import { useDesignSystems } from "@/hooks/use-design-systems";
|
|
|
51
47
|
import { useWorkspaceDefaults } from "@/hooks/use-workspace-defaults";
|
|
52
48
|
import { createDeckAgentMessage } from "@/lib/agent-visible-message";
|
|
53
49
|
import { savePromptToComposerDraft } from "@/lib/composer-draft";
|
|
54
|
-
import {
|
|
50
|
+
import {
|
|
51
|
+
readRecentReferences,
|
|
52
|
+
rememberRecentReference,
|
|
53
|
+
type RecentReference,
|
|
54
|
+
} from "@/lib/recent-references";
|
|
55
55
|
|
|
56
56
|
const NEW_DECK_DRAFT_SCOPE = "slides-new-deck";
|
|
57
57
|
const PENDING_PROMPT_KEY = "slides:pending-deck-prompt";
|
|
@@ -233,6 +233,17 @@ export default function Index() {
|
|
|
233
233
|
const [newDeckRetryFiles, setNewDeckRetryFiles] = useState<UploadedFile[]>(
|
|
234
234
|
[],
|
|
235
235
|
);
|
|
236
|
+
const [pendingDeck, setPendingDeck] = useState<{
|
|
237
|
+
prompt: string;
|
|
238
|
+
files: UploadedFile[];
|
|
239
|
+
} | null>(null);
|
|
240
|
+
const [showNewDeckReferenceStep, setShowNewDeckReferenceStep] =
|
|
241
|
+
useState(false);
|
|
242
|
+
const [recentReferences, setRecentReferences] = useState<RecentReference[]>(
|
|
243
|
+
[],
|
|
244
|
+
);
|
|
245
|
+
const [referenceImporting, setReferenceImporting] = useState(false);
|
|
246
|
+
const initialPromptConsumedRef = useRef(false);
|
|
236
247
|
const [signInPromptHadFiles, setSignInPromptHadFiles] = useState(false);
|
|
237
248
|
const [selectedDesignSystemId, setSelectedDesignSystemId] = useState("");
|
|
238
249
|
const [selectedReferenceDeckId, setSelectedReferenceDeckId] = useState("");
|
|
@@ -254,14 +265,6 @@ export default function Index() {
|
|
|
254
265
|
() => new Map(designSystems.map((ds) => [ds.id, ds.title])),
|
|
255
266
|
[designSystems],
|
|
256
267
|
);
|
|
257
|
-
const starredDecks = useMemo(
|
|
258
|
-
() => decks.filter((deck) => deck.starred),
|
|
259
|
-
[decks],
|
|
260
|
-
);
|
|
261
|
-
const unstarredDecks = useMemo(
|
|
262
|
-
() => decks.filter((deck) => !deck.starred),
|
|
263
|
-
[decks],
|
|
264
|
-
);
|
|
265
268
|
// A workspace default the caller cannot open is reported by the action as
|
|
266
269
|
// `unavailable` rather than absent; preselecting it would send every new
|
|
267
270
|
// prompt at a deck that 404s, so fall back to no reference instead.
|
|
@@ -289,6 +292,67 @@ export default function Index() {
|
|
|
289
292
|
deckFilter === "mine" ? decks.filter((deck) => deck.createdByMe) : decks,
|
|
290
293
|
[deckFilter, decks],
|
|
291
294
|
);
|
|
295
|
+
const rememberReference = useCallback(
|
|
296
|
+
(reference: Omit<RecentReference, "lastUsedAt">) => {
|
|
297
|
+
const result = rememberRecentReference(reference);
|
|
298
|
+
if (result.readable) setRecentReferences(result.items);
|
|
299
|
+
},
|
|
300
|
+
[],
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
useEffect(() => {
|
|
304
|
+
const result = readRecentReferences();
|
|
305
|
+
if (result.readable) setRecentReferences(result.items);
|
|
306
|
+
}, []);
|
|
307
|
+
|
|
308
|
+
useEffect(() => {
|
|
309
|
+
if (initialDesignSystemId) {
|
|
310
|
+
rememberReference({
|
|
311
|
+
id: initialDesignSystemId,
|
|
312
|
+
kind: "design-system",
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
if (workspaceReferenceDeckId) {
|
|
316
|
+
rememberReference({ id: workspaceReferenceDeckId, kind: "deck" });
|
|
317
|
+
}
|
|
318
|
+
}, [initialDesignSystemId, rememberReference, workspaceReferenceDeckId]);
|
|
319
|
+
|
|
320
|
+
const initialPrompt = searchParams.get("initialPrompt")?.trim() ?? "";
|
|
321
|
+
const openInitialPromptReferenceStep = useCallback(() => {
|
|
322
|
+
if (!initialPrompt || initialPromptConsumedRef.current) return;
|
|
323
|
+
initialPromptConsumedRef.current = true;
|
|
324
|
+
setPendingDeck({ prompt: initialPrompt, files: [] });
|
|
325
|
+
setShowNewDeckReferenceStep(true);
|
|
326
|
+
setSearchParams(
|
|
327
|
+
(previous) => {
|
|
328
|
+
const next = new URLSearchParams(previous);
|
|
329
|
+
next.delete("initialPrompt");
|
|
330
|
+
return next;
|
|
331
|
+
},
|
|
332
|
+
{ replace: true },
|
|
333
|
+
);
|
|
334
|
+
}, [initialPrompt, setSearchParams]);
|
|
335
|
+
|
|
336
|
+
useEffect(() => {
|
|
337
|
+
if (!initialPrompt || initialPromptConsumedRef.current) return;
|
|
338
|
+
const firstRunActive =
|
|
339
|
+
typeof document !== "undefined" &&
|
|
340
|
+
document.cookie
|
|
341
|
+
.split(";")
|
|
342
|
+
.some((part) => part.trim().startsWith("agent-native-first-run="));
|
|
343
|
+
const handleFirstRunCompleted = () => openInitialPromptReferenceStep();
|
|
344
|
+
window.addEventListener(
|
|
345
|
+
"agent-native:first-run-completed",
|
|
346
|
+
handleFirstRunCompleted,
|
|
347
|
+
);
|
|
348
|
+
if (!firstRunActive) openInitialPromptReferenceStep();
|
|
349
|
+
return () =>
|
|
350
|
+
window.removeEventListener(
|
|
351
|
+
"agent-native:first-run-completed",
|
|
352
|
+
handleFirstRunCompleted,
|
|
353
|
+
);
|
|
354
|
+
}, [initialPrompt, openInitialPromptReferenceStep]);
|
|
355
|
+
|
|
292
356
|
const setDeckFilter = useCallback(
|
|
293
357
|
(value: string) => {
|
|
294
358
|
const nextFilter = value === "mine" ? "mine" : "all";
|
|
@@ -443,6 +507,7 @@ export default function Index() {
|
|
|
443
507
|
const handleCreateDeckWithPrompt = async (
|
|
444
508
|
prompt: string,
|
|
445
509
|
files: UploadedFile[],
|
|
510
|
+
referenceSelection: NewDeckReferenceSelection = {},
|
|
446
511
|
) => {
|
|
447
512
|
// Pre-flight auth check. The add-deck action returns 403 silently
|
|
448
513
|
// when unauthenticated, leaving the user stuck on a deck page that
|
|
@@ -458,10 +523,21 @@ export default function Index() {
|
|
|
458
523
|
newDeckRetryFiles,
|
|
459
524
|
files,
|
|
460
525
|
);
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
?
|
|
464
|
-
:
|
|
526
|
+
const designSystemId =
|
|
527
|
+
referenceSelection.designSystemId !== undefined
|
|
528
|
+
? referenceSelection.designSystemId
|
|
529
|
+
: selectedDesignSystemId && selectedDesignSystemId !== "none"
|
|
530
|
+
? selectedDesignSystemId
|
|
531
|
+
: null;
|
|
532
|
+
const referenceDeckId =
|
|
533
|
+
referenceSelection.referenceDeckId !== undefined
|
|
534
|
+
? referenceSelection.referenceDeckId
|
|
535
|
+
: selectedReferenceDeckId && selectedReferenceDeckId !== "none"
|
|
536
|
+
? selectedReferenceDeckId
|
|
537
|
+
: null;
|
|
538
|
+
const selectedDesignSystem = designSystemId
|
|
539
|
+
? designSystems.find((ds) => ds.id === designSystemId)
|
|
540
|
+
: undefined;
|
|
465
541
|
let deck: ReturnType<typeof createDeck> | undefined;
|
|
466
542
|
flushSync(() => {
|
|
467
543
|
deck = createDeck(undefined, {
|
|
@@ -492,56 +568,6 @@ export default function Index() {
|
|
|
492
568
|
setNewDeckRetryFiles([]);
|
|
493
569
|
navigate(`/deck/${deck.id}`, { flushSync: true });
|
|
494
570
|
|
|
495
|
-
// The deck now exists server-side and the user is looking at it, so a
|
|
496
|
-
// failure past this point (e.g. askUserQuestion rejecting on an
|
|
497
|
-
// application-state write error) must undo the navigation and restore
|
|
498
|
-
// the prompt instead of stranding the user on a permanently empty deck.
|
|
499
|
-
const recoverFromGenerationSetupFailure = () => {
|
|
500
|
-
deleteDeck(deckId);
|
|
501
|
-
toast.error(t("home.generationStartFailed"), {
|
|
502
|
-
description: t("home.generationStartFailedDescription"),
|
|
503
|
-
});
|
|
504
|
-
// This Index instance is about to unmount (we already navigated away
|
|
505
|
-
// to the deck page above), so state setters here would land on a dead
|
|
506
|
-
// component. Hand the retry payload to the next Index mount via router
|
|
507
|
-
// state instead; the effect above restores it.
|
|
508
|
-
const retryState: DeckGenerationRetryState = {
|
|
509
|
-
retryPrompt: prompt,
|
|
510
|
-
retryFiles: filesForGeneration,
|
|
511
|
-
};
|
|
512
|
-
navigate("/", { state: retryState });
|
|
513
|
-
};
|
|
514
|
-
|
|
515
|
-
let deckLength: Awaited<ReturnType<typeof askUserQuestion>> = null;
|
|
516
|
-
try {
|
|
517
|
-
// One quick, skippable decision so the agent doesn't guess the deck size.
|
|
518
|
-
deckLength = await askUserQuestion({
|
|
519
|
-
question: t("home.deckLengthQuestion"),
|
|
520
|
-
header: t("home.deckLengthHeader"),
|
|
521
|
-
options: [
|
|
522
|
-
{ label: t("home.deckLengthShort"), value: "3–5 slides" },
|
|
523
|
-
{
|
|
524
|
-
label: t("home.deckLengthMedium"),
|
|
525
|
-
value: "6–10 slides",
|
|
526
|
-
recommended: true,
|
|
527
|
-
},
|
|
528
|
-
{ label: t("home.deckLengthLong"), value: "11+ slides" },
|
|
529
|
-
{
|
|
530
|
-
label: t("home.deckLengthSingleVisual"),
|
|
531
|
-
value: "a single standalone visual slide",
|
|
532
|
-
},
|
|
533
|
-
],
|
|
534
|
-
allowFreeText: false,
|
|
535
|
-
});
|
|
536
|
-
} catch {
|
|
537
|
-
recoverFromGenerationSetupFailure();
|
|
538
|
-
return;
|
|
539
|
-
}
|
|
540
|
-
const deckLengthContext =
|
|
541
|
-
typeof deckLength === "string" && deckLength
|
|
542
|
-
? `Target length: aim for ${deckLength} unless the user's request clearly specifies a different count.`
|
|
543
|
-
: "";
|
|
544
|
-
|
|
545
571
|
const trimmedPrompt = prompt.trim();
|
|
546
572
|
const hasImportedGoogleDocContext = trimmedPrompt.includes("<google-doc ");
|
|
547
573
|
const googleDocUrls = hasImportedGoogleDocContext
|
|
@@ -561,11 +587,8 @@ export default function Index() {
|
|
|
561
587
|
"If the action cannot read a private document, tell the user the exact sharing step from the action error instead of generating from the URL alone.",
|
|
562
588
|
].join("\n")
|
|
563
589
|
: "";
|
|
564
|
-
const referenceDeckContext =
|
|
565
|
-
|
|
566
|
-
? selectedReferenceDeckId
|
|
567
|
-
: null,
|
|
568
|
-
);
|
|
590
|
+
const referenceDeckContext =
|
|
591
|
+
await loadReferenceDeckGenerationContext(referenceDeckId);
|
|
569
592
|
const hydratedDesignSystemContext = await loadDesignSystemGenerationContext(
|
|
570
593
|
selectedDesignSystem?.id,
|
|
571
594
|
);
|
|
@@ -593,7 +616,7 @@ export default function Index() {
|
|
|
593
616
|
referenceDeckContext,
|
|
594
617
|
designSystemContext,
|
|
595
618
|
"",
|
|
596
|
-
|
|
619
|
+
"Before generating, if the request or selected references leave a meaningful choice unresolved, use the `ask-question` tool to ask one concise, prompt-specific question in the inline guided-question flow. Generate the question wording and 2 to 4 options from the user's request and selected references, like Claude's design-question flow; do not use a fixed generic questionnaire. Ask only a choice that materially affects the deck, such as audience, tone, structure, or length. If the prompt already makes the choice clear, do not ask it again. Wait for the user's answer or skip before adding slides.",
|
|
597
620
|
"Start a `manage-progress` run so progress appears in the app header. Add the first slide as soon as it is ready, then continue one slide at a time so the editor visibly fills in.",
|
|
598
621
|
"After reading any requested or imported source material, but before adding the first slide, choose a concise, specific deck title from the user's request and source material. Call `patch-deck` with `deckId: \"" +
|
|
599
622
|
deckId +
|
|
@@ -619,6 +642,108 @@ export default function Index() {
|
|
|
619
642
|
});
|
|
620
643
|
};
|
|
621
644
|
|
|
645
|
+
const handlePromptSubmit = useCallback(
|
|
646
|
+
(prompt: string, files: UploadedFile[]) => {
|
|
647
|
+
setNewDeckPromptOpen(false, { clearInitialPrompt: false });
|
|
648
|
+
setPendingDeck({ prompt, files });
|
|
649
|
+
setShowNewDeckReferenceStep(true);
|
|
650
|
+
},
|
|
651
|
+
[setNewDeckPromptOpen],
|
|
652
|
+
);
|
|
653
|
+
|
|
654
|
+
const handleReferenceSelect = useCallback(
|
|
655
|
+
async (selection: NewDeckReferenceSelection) => {
|
|
656
|
+
const pending = pendingDeck;
|
|
657
|
+
if (!pending) return;
|
|
658
|
+
if (selection.designSystemId) {
|
|
659
|
+
rememberReference({
|
|
660
|
+
id: selection.designSystemId,
|
|
661
|
+
kind: "design-system",
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
if (selection.referenceDeckId) {
|
|
665
|
+
rememberReference({ id: selection.referenceDeckId, kind: "deck" });
|
|
666
|
+
}
|
|
667
|
+
setShowNewDeckReferenceStep(false);
|
|
668
|
+
setPendingDeck(null);
|
|
669
|
+
await handleCreateDeckWithPrompt(
|
|
670
|
+
pending.prompt,
|
|
671
|
+
pending.files,
|
|
672
|
+
selection,
|
|
673
|
+
);
|
|
674
|
+
},
|
|
675
|
+
[handleCreateDeckWithPrompt, pendingDeck, rememberReference],
|
|
676
|
+
);
|
|
677
|
+
|
|
678
|
+
const handleReferenceImport = useCallback(
|
|
679
|
+
async (files: File[]) => {
|
|
680
|
+
const pending = pendingDeck;
|
|
681
|
+
if (!pending) return;
|
|
682
|
+
setReferenceImporting(true);
|
|
683
|
+
try {
|
|
684
|
+
const uploaded = await uploadPromptFiles(files);
|
|
685
|
+
const pptxReference = uploaded.find((file) =>
|
|
686
|
+
file.originalName.toLowerCase().endsWith(".pptx"),
|
|
687
|
+
);
|
|
688
|
+
let referenceSelection: NewDeckReferenceSelection = {};
|
|
689
|
+
let generationFiles = uploaded;
|
|
690
|
+
if (pptxReference) {
|
|
691
|
+
const imported = (await callAction("import-pptx", {
|
|
692
|
+
filePath: pptxReference.path,
|
|
693
|
+
})) as { id?: unknown };
|
|
694
|
+
if (typeof imported.id !== "string" || !imported.id) {
|
|
695
|
+
throw new Error("The imported presentation did not create a deck.");
|
|
696
|
+
}
|
|
697
|
+
await reloadDecks();
|
|
698
|
+
rememberReference({ id: imported.id, kind: "deck" });
|
|
699
|
+
referenceSelection = {
|
|
700
|
+
designSystemId: null,
|
|
701
|
+
referenceDeckId: imported.id,
|
|
702
|
+
};
|
|
703
|
+
generationFiles = uploaded.filter((file) => file !== pptxReference);
|
|
704
|
+
}
|
|
705
|
+
setShowNewDeckReferenceStep(false);
|
|
706
|
+
setPendingDeck(null);
|
|
707
|
+
await handleCreateDeckWithPrompt(
|
|
708
|
+
pending.prompt,
|
|
709
|
+
[...pending.files, ...generationFiles],
|
|
710
|
+
referenceSelection,
|
|
711
|
+
);
|
|
712
|
+
} catch (error) {
|
|
713
|
+
toast.error(t("editorToolbar.uploadFailed"), {
|
|
714
|
+
description:
|
|
715
|
+
error instanceof Error
|
|
716
|
+
? error.message
|
|
717
|
+
: t("editorToolbar.importFailedDescription"),
|
|
718
|
+
});
|
|
719
|
+
} finally {
|
|
720
|
+
setReferenceImporting(false);
|
|
721
|
+
}
|
|
722
|
+
},
|
|
723
|
+
[
|
|
724
|
+
callAction,
|
|
725
|
+
handleCreateDeckWithPrompt,
|
|
726
|
+
pendingDeck,
|
|
727
|
+
reloadDecks,
|
|
728
|
+
rememberReference,
|
|
729
|
+
t,
|
|
730
|
+
],
|
|
731
|
+
);
|
|
732
|
+
|
|
733
|
+
const handleReferenceSkip = useCallback(() => {
|
|
734
|
+
const pending = pendingDeck;
|
|
735
|
+
if (!pending) {
|
|
736
|
+
setShowNewDeckReferenceStep(false);
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
setShowNewDeckReferenceStep(false);
|
|
740
|
+
setPendingDeck(null);
|
|
741
|
+
void handleCreateDeckWithPrompt(pending.prompt, pending.files, {
|
|
742
|
+
designSystemId: null,
|
|
743
|
+
referenceDeckId: null,
|
|
744
|
+
});
|
|
745
|
+
}, [handleCreateDeckWithPrompt, pendingDeck]);
|
|
746
|
+
|
|
622
747
|
const handleConfirmDelete = () => {
|
|
623
748
|
if (deckToDelete) {
|
|
624
749
|
deleteDeck(deckToDelete);
|
|
@@ -933,7 +1058,7 @@ export default function Index() {
|
|
|
933
1058
|
placeholder={t("home.newDeckPlaceholder")}
|
|
934
1059
|
onSkip={handleCreateDeckBlank}
|
|
935
1060
|
skipLabel={t("home.skipPrompt")}
|
|
936
|
-
onSubmit={
|
|
1061
|
+
onSubmit={handlePromptSubmit}
|
|
937
1062
|
onBeforeUpload={(prompt, files) => {
|
|
938
1063
|
if (session) return true;
|
|
939
1064
|
preservePromptForSignIn(prompt, { hadFiles: files.length > 0 });
|
|
@@ -944,105 +1069,35 @@ export default function Index() {
|
|
|
944
1069
|
draftScope={NEW_DECK_DRAFT_SCOPE}
|
|
945
1070
|
initialText={newDeckInitialPrompt?.text}
|
|
946
1071
|
initialTextKey={newDeckInitialPrompt?.key}
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
{ds.title}
|
|
977
|
-
{ds.isDefault || ds.id === workspaceDesignSystemId
|
|
978
|
-
? t("home.defaultSuffix")
|
|
979
|
-
: ""}
|
|
980
|
-
</SelectItem>
|
|
981
|
-
))}
|
|
982
|
-
</SelectContent>
|
|
983
|
-
</Select>
|
|
984
|
-
</div>
|
|
985
|
-
)}
|
|
986
|
-
{decks.length > 0 && (
|
|
987
|
-
<div className="min-w-0">
|
|
988
|
-
<label className="mb-1.5 block text-[11px] font-medium text-muted-foreground">
|
|
989
|
-
{t("home.referenceDeck")}
|
|
990
|
-
</label>
|
|
991
|
-
<Select
|
|
992
|
-
value={selectedReferenceDeckId || "none"}
|
|
993
|
-
onValueChange={(value) => {
|
|
994
|
-
referenceDeckAutoRef.current = false;
|
|
995
|
-
setSelectedReferenceDeckId(value);
|
|
996
|
-
}}
|
|
997
|
-
>
|
|
998
|
-
<SelectTrigger className="h-8 w-full bg-accent/40 text-xs">
|
|
999
|
-
<SelectValue
|
|
1000
|
-
placeholder={t("home.referenceDeckPlaceholder")}
|
|
1001
|
-
/>
|
|
1002
|
-
</SelectTrigger>
|
|
1003
|
-
<SelectContent>
|
|
1004
|
-
<SelectItem value="none">
|
|
1005
|
-
{t("home.referenceDeckNone")}
|
|
1006
|
-
</SelectItem>
|
|
1007
|
-
{starredDecks.length > 0 && (
|
|
1008
|
-
<SelectGroup>
|
|
1009
|
-
<SelectLabel>
|
|
1010
|
-
{t("home.referenceDeckStarredGroup")}
|
|
1011
|
-
</SelectLabel>
|
|
1012
|
-
{starredDecks.map((deck) => (
|
|
1013
|
-
<SelectItem key={deck.id} value={deck.id}>
|
|
1014
|
-
{deck.title}
|
|
1015
|
-
{deck.id === workspaceReferenceDeckId
|
|
1016
|
-
? t("home.defaultSuffix")
|
|
1017
|
-
: ""}
|
|
1018
|
-
</SelectItem>
|
|
1019
|
-
))}
|
|
1020
|
-
</SelectGroup>
|
|
1021
|
-
)}
|
|
1022
|
-
{unstarredDecks.length > 0 && (
|
|
1023
|
-
<SelectGroup>
|
|
1024
|
-
{starredDecks.length > 0 && (
|
|
1025
|
-
<SelectLabel>
|
|
1026
|
-
{t("home.referenceDeckOtherGroup")}
|
|
1027
|
-
</SelectLabel>
|
|
1028
|
-
)}
|
|
1029
|
-
{unstarredDecks.map((deck) => (
|
|
1030
|
-
<SelectItem key={deck.id} value={deck.id}>
|
|
1031
|
-
{deck.title}
|
|
1032
|
-
{deck.id === workspaceReferenceDeckId
|
|
1033
|
-
? t("home.defaultSuffix")
|
|
1034
|
-
: ""}
|
|
1035
|
-
</SelectItem>
|
|
1036
|
-
))}
|
|
1037
|
-
</SelectGroup>
|
|
1038
|
-
)}
|
|
1039
|
-
</SelectContent>
|
|
1040
|
-
</Select>
|
|
1041
|
-
</div>
|
|
1042
|
-
)}
|
|
1043
|
-
</div>
|
|
1044
|
-
)}
|
|
1045
|
-
</PromptPopover>
|
|
1072
|
+
/>
|
|
1073
|
+
|
|
1074
|
+
<NewDeckReferenceStep
|
|
1075
|
+
open={showNewDeckReferenceStep}
|
|
1076
|
+
onOpenChange={(open) => {
|
|
1077
|
+
if (!open) handleReferenceSkip();
|
|
1078
|
+
}}
|
|
1079
|
+
designSystems={designSystems}
|
|
1080
|
+
decks={decks}
|
|
1081
|
+
defaultDesignSystemId={initialDesignSystemId}
|
|
1082
|
+
defaultReferenceDeckId={workspaceReferenceDeckId}
|
|
1083
|
+
recentReferences={recentReferences}
|
|
1084
|
+
onSelect={(selection) => void handleReferenceSelect(selection)}
|
|
1085
|
+
onImport={handleReferenceImport}
|
|
1086
|
+
onSkip={handleReferenceSkip}
|
|
1087
|
+
importing={referenceImporting}
|
|
1088
|
+
title={t("home.newDeckPromptTitle")}
|
|
1089
|
+
description={t("home.referenceDeckPlaceholder")}
|
|
1090
|
+
designSystemLabel={t("home.designSystem")}
|
|
1091
|
+
referenceDeckLabel={t("home.referenceDeck")}
|
|
1092
|
+
chooseDeckLabel={t("home.referenceDeckPlaceholder")}
|
|
1093
|
+
importFileLabel={t("editorToolbar.importFile")}
|
|
1094
|
+
importingLabel={t("editorToolbar.importing")}
|
|
1095
|
+
skipLabel={t("home.referenceDeckNone")}
|
|
1096
|
+
defaultSuffix={t("home.defaultSuffix")}
|
|
1097
|
+
starredLabel={t("home.referenceDeckStarredGroup")}
|
|
1098
|
+
otherDecksLabel={t("home.referenceDeckOtherGroup")}
|
|
1099
|
+
promptNote={pendingDeck?.prompt}
|
|
1100
|
+
/>
|
|
1046
1101
|
|
|
1047
1102
|
{/* Sign-in required to create a deck. Shown when an unauthenticated
|
|
1048
1103
|
user submits a prompt — the typed prompt is preserved in
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: changed
|
|
3
|
+
date: 2026-08-01
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Adding a slide now starts from a `+` at the head of the editor toolbar, next to
|
|
7
|
+
the deck title, instead of a header above the slide thumbnails. The rail itself
|
|
8
|
+
drops that header, tucks the drag handle onto the thumbnail on hover, and is
|
|
9
|
+
narrower — so more slides fit on screen and the canvas gets the width back.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: changed
|
|
3
|
+
date: 2026-08-01
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
The contextual slide toolbar now opens with the actions that never change: add
|
|
7
|
+
slide, undo, redo, and the text-box tool. Undo and redo previously worked only
|
|
8
|
+
through Cmd+Z with no visible control; clicking them commits whatever text you
|
|
9
|
+
are editing first, so nothing you just typed is lost.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: changed
|
|
3
|
+
date: 2026-08-03
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Colour controls in the slide toolbar are now just the swatch, with no hex code
|
|
7
|
+
beside it. Font weight and text alignment collapsed from four buttons each into
|
|
8
|
+
a single control with a dropdown, and alignment uses standard icons instead of
|
|
9
|
+
words. Undo and redo moved out of the toolbar into the overflow menu, since
|
|
10
|
+
Cmd+Z already covers the common case.
|
|
@@ -1,14 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Full-screen loading spinner rendered during SSR and initial hydration.
|
|
3
|
-
* Uses inline SVG + styles because Tailwind may not be loaded yet on the server.
|
|
4
|
-
* Respects the user's OS color scheme so dark-mode users don't get a white flash.
|
|
5
|
-
*
|
|
6
|
-
* The stall hint is revealed by a pure-CSS `animation-delay`, never a timer:
|
|
7
|
-
* the states that strand a user here (hydration never runs, the route module
|
|
8
|
-
* 404s, a cold dev-server compile) are exactly the states where no JS of ours
|
|
9
|
-
* executes, so a `setTimeout` fallback would never fire. A featureless spinner
|
|
10
|
-
* is indistinguishable from a blank screen, and reads as "the app is broken"
|
|
11
|
-
* rather than "look at the terminal" — that mis-read is what this text buys.
|
|
12
|
-
*/
|
|
13
1
|
export declare function DefaultSpinner(): import("react").JSX.Element;
|
|
14
2
|
//# sourceMappingURL=DefaultSpinner.d.ts.map
|
|
@@ -1,17 +1,33 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
2
3
|
/**
|
|
3
4
|
* Full-screen loading spinner rendered during SSR and initial hydration.
|
|
4
5
|
* Uses inline SVG + styles because Tailwind may not be loaded yet on the server.
|
|
5
6
|
* Respects the user's OS color scheme so dark-mode users don't get a white flash.
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
+
* In development builds, the stall hint is revealed by a pure-CSS
|
|
9
|
+
* `animation-delay`, never a timer:
|
|
8
10
|
* the states that strand a user here (hydration never runs, the route module
|
|
9
11
|
* 404s, a cold dev-server compile) are exactly the states where no JS of ours
|
|
10
12
|
* executes, so a `setTimeout` fallback would never fire. A featureless spinner
|
|
11
13
|
* is indistinguishable from a blank screen, and reads as "the app is broken"
|
|
12
14
|
* rather than "look at the terminal" — that mis-read is what this text buys.
|
|
13
15
|
*/
|
|
16
|
+
function isDevelopmentBuild() {
|
|
17
|
+
if (typeof process !== "undefined" &&
|
|
18
|
+
process.env?.NODE_ENV === "production") {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
const viteEnv = import.meta.env;
|
|
22
|
+
if (viteEnv?.PROD === true)
|
|
23
|
+
return false;
|
|
24
|
+
return viteEnv?.DEV === true;
|
|
25
|
+
}
|
|
14
26
|
export function DefaultSpinner() {
|
|
27
|
+
const [showStallHint, setShowStallHint] = useState(false);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
setShowStallHint(isDevelopmentBuild());
|
|
30
|
+
}, []);
|
|
15
31
|
return (_jsxs("div", { style: {
|
|
16
32
|
display: "flex",
|
|
17
33
|
flexDirection: "column",
|
|
@@ -20,8 +36,10 @@ export function DefaultSpinner() {
|
|
|
20
36
|
gap: 16,
|
|
21
37
|
height: "100vh",
|
|
22
38
|
width: "100%",
|
|
23
|
-
}, children: [_jsx("svg", { role: "status", "aria-label": "Loading", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: { animation: "an-spin 1s linear infinite", opacity: 0.7 }, children: _jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) }), _jsx("p", { className: "an-stall-hint", children: "Still loading. A first run compiles dependencies and can take a minute \u2014 if it does not finish, check the terminal running the dev server for errors." }), _jsx("style", { children: `
|
|
39
|
+
}, children: [_jsx("svg", { role: "status", "aria-label": "Loading", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: { animation: "an-spin 1s linear infinite", opacity: 0.7 }, children: _jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) }), showStallHint && (_jsx("p", { className: "an-stall-hint", children: "Still loading. A first run compiles dependencies and can take a minute \u2014 if it does not finish, check the terminal running the dev server for errors." })), _jsx("style", { children: `
|
|
24
40
|
@keyframes an-spin { to { transform: rotate(360deg) } }
|
|
41
|
+
${showStallHint
|
|
42
|
+
? `
|
|
25
43
|
@keyframes an-stall-in { to { opacity: 0.6 } }
|
|
26
44
|
.an-stall-hint {
|
|
27
45
|
opacity: 0;
|
|
@@ -37,6 +55,8 @@ export function DefaultSpinner() {
|
|
|
37
55
|
@media (prefers-reduced-motion: reduce) {
|
|
38
56
|
.an-stall-hint { animation-duration: 0s }
|
|
39
57
|
}
|
|
58
|
+
`
|
|
59
|
+
: ""}
|
|
40
60
|
html {
|
|
41
61
|
background: hsl(var(--background, 0 0% 100%));
|
|
42
62
|
color: hsl(var(--foreground, 240 10% 3.9%));
|
|
@@ -109,6 +109,9 @@ export function useOnboarding(options = {}) {
|
|
|
109
109
|
return;
|
|
110
110
|
}
|
|
111
111
|
setFirstRun(false);
|
|
112
|
+
if (typeof window !== "undefined") {
|
|
113
|
+
window.dispatchEvent(new CustomEvent("agent-native:first-run-completed"));
|
|
114
|
+
}
|
|
112
115
|
await fetchAll();
|
|
113
116
|
}, [fetchAll]);
|
|
114
117
|
const totalCount = steps.length;
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
|
|
|
26
26
|
* Body: { update: string (base64), requestSource?: string }
|
|
27
27
|
*/
|
|
28
28
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
29
|
-
ok?: undefined;
|
|
30
29
|
error: string;
|
|
30
|
+
ok?: undefined;
|
|
31
31
|
} | {
|
|
32
32
|
error?: undefined;
|
|
33
33
|
ok: boolean;
|