@agent-native/core 0.149.1 → 0.149.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.
Files changed (115) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +2 -0
  3. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +150 -46
  4. package/corpus/templates/analytics/app/global.css +1 -1
  5. package/corpus/templates/analytics/app/i18n-data.ts +37 -0
  6. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +1 -1
  7. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +32 -0
  8. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +2 -0
  9. package/corpus/templates/analytics/changelog/2026-08-10-dashboard-tables-can-be-copied-and-sorted-by-multiple-column.md +6 -0
  10. package/corpus/templates/analytics/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
  11. package/corpus/templates/assets/app/global.css +1 -1
  12. package/corpus/templates/assets/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
  13. package/corpus/templates/brain/app/global.css +1 -1
  14. package/corpus/templates/brain/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
  15. package/corpus/templates/chat/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
  16. package/corpus/templates/clips/changelog/2026-08-10-clips-desktop-sign-in-now-starts-with-magic-links-and-google.md +6 -0
  17. package/corpus/templates/clips/chrome-extension/src/overlay.css +1 -0
  18. package/corpus/templates/clips/desktop/src/app.tsx +274 -137
  19. package/corpus/templates/clips/desktop/src/styles.css +35 -0
  20. package/corpus/templates/content/app/global.css +1 -0
  21. package/corpus/templates/crm/app/global.css +1 -1
  22. package/corpus/templates/crm/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
  23. package/corpus/templates/dispatch/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
  24. package/corpus/templates/factory/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
  25. package/corpus/templates/forms/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
  26. package/corpus/templates/plan/app/global.css +1 -0
  27. package/corpus/templates/plan/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
  28. package/corpus/templates/plan/server/ui-plan-html.ts +4 -1
  29. package/corpus/templates/slides/AGENTS.md +11 -10
  30. package/corpus/templates/slides/actions/add-deck.ts +2 -0
  31. package/corpus/templates/slides/actions/add-slide.ts +15 -1
  32. package/corpus/templates/slides/actions/create-deck.ts +18 -6
  33. package/corpus/templates/slides/actions/get-deck.ts +29 -1
  34. package/corpus/templates/slides/actions/patch-deck.ts +122 -9
  35. package/corpus/templates/slides/actions/save-deck.ts +24 -1
  36. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +134 -618
  37. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +69 -60
  38. package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +1 -1
  39. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +13 -1
  40. package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +56 -174
  41. package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +239 -116
  42. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +3 -3
  43. package/corpus/templates/slides/app/components/layout/AgentWorkIndicator.tsx +1 -1
  44. package/corpus/templates/slides/app/components/layout/Layout.tsx +34 -35
  45. package/corpus/templates/slides/app/components/layout/layout-route-policy.ts +2 -5
  46. package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +45 -40
  47. package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +63 -16
  48. package/corpus/templates/slides/app/hooks/use-generating-slide-preview.ts +25 -3
  49. package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
  50. package/corpus/templates/slides/app/lib/create-deck-generation.ts +5 -4
  51. package/corpus/templates/slides/app/lib/recent-references.ts +23 -1
  52. package/corpus/templates/slides/app/lib/slide-animation-elements.ts +41 -3
  53. package/corpus/templates/slides/app/pages/DeckEditor.tsx +4 -27
  54. package/corpus/templates/slides/app/pages/Index.tsx +240 -89
  55. package/corpus/templates/slides/changelog/2026-08-10-ai-editing-avatar-badge.md +6 -0
  56. package/corpus/templates/slides/changelog/2026-08-10-generated-decks-keep-a-clear-human-readable-title.md +6 -0
  57. package/corpus/templates/slides/changelog/2026-08-10-new-deck-creation-now-shows-progress-opens-the-editor-direct.md +6 -0
  58. package/corpus/templates/slides/changelog/2026-08-10-presentation-reveals-now-follow-valid-targets.md +6 -0
  59. package/corpus/templates/slides/changelog/2026-08-10-slides-editing-controls-are-consolidated-into-one-focused-me.md +6 -0
  60. package/corpus/templates/slides/changelog/2026-08-10-slides-now-verify-and-restyle-every-imported-slide-in-one-pa.md +6 -0
  61. package/corpus/templates/slides/changelog/2026-08-10-slides-only-suggests-a-google-connection-for-relevant-reques.md +6 -0
  62. package/corpus/templates/slides/changelog/2026-08-10-the-google-slides-import-option-is-now-labeled-slides.md +6 -0
  63. package/corpus/templates/slides/server/lib/chat-attachments.ts +1 -1
  64. package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -3
  65. package/corpus/templates/slides/shared/api.ts +2 -1
  66. package/corpus/templates/slides/shared/deck-title.ts +135 -0
  67. package/corpus/templates/tasks/app/components/tasks/TaskListRow.tsx +4 -1
  68. package/dist/agent/engine/ai-sdk-engine.js +1 -1
  69. package/dist/agent/production-agent.d.ts +21 -1
  70. package/dist/agent/production-agent.js +129 -10
  71. package/dist/agent/tool-approval-store.d.ts +18 -0
  72. package/dist/agent/tool-approval-store.js +122 -0
  73. package/dist/agent/types.d.ts +1 -1
  74. package/dist/cli/code-agent-executor.js +11 -2
  75. package/dist/client/AgentPanel.js +31 -6
  76. package/dist/client/AssistantChat.d.ts +3 -2
  77. package/dist/client/AssistantChat.js +7 -20
  78. package/dist/client/agent-chat/index.d.ts +1 -1
  79. package/dist/client/agent-chat-adapter.js +11 -0
  80. package/dist/client/agent-chat.d.ts +1 -1
  81. package/dist/client/chat/markdown-renderer.js +14 -2
  82. package/dist/client/chat/message-components.d.ts +6 -2
  83. package/dist/client/chat/message-components.js +25 -47
  84. package/dist/client/chat/tool-call-display.d.ts +3 -5
  85. package/dist/client/chat/tool-call-display.js +7 -212
  86. package/dist/client/chat-first/apps-rail.js +3 -3
  87. package/dist/client/chat-first/browser-pane.js +4 -1
  88. package/dist/client/chat-first/chat-history.d.ts +3 -1
  89. package/dist/client/chat-first/chat-history.js +2 -2
  90. package/dist/client/chat-first/surface-tabs.d.ts +1 -1
  91. package/dist/client/chat-first/surface-tabs.js +52 -41
  92. package/dist/client/chat-first/types.d.ts +3 -0
  93. package/dist/client/chat-first.d.ts +10 -0
  94. package/dist/client/chat-first.js +37 -2
  95. package/dist/client/components/ui/message-scroller.js +4 -1
  96. package/dist/client/i18n.js +3 -1
  97. package/dist/client/resources/McpConnectionSuggestion.js +9 -1
  98. package/dist/client/sse-event-processor.js +10 -0
  99. package/dist/client/use-chat-models.js +156 -80
  100. package/dist/collab/struct-routes.d.ts +1 -1
  101. package/dist/integrations/webhook-handler.js +1 -1
  102. package/dist/observability/routes.d.ts +1 -1
  103. package/dist/provider-api/actions/custom-provider-registration.d.ts +1 -1
  104. package/dist/resources/handlers.d.ts +1 -1
  105. package/dist/secrets/routes.d.ts +9 -9
  106. package/dist/server/auth.js +262 -31
  107. package/dist/server/onboarding-html.js +56 -9
  108. package/dist/shared/reasoning-effort.d.ts +8 -8
  109. package/dist/shared/reasoning-effort.js +10 -10
  110. package/dist/shared/streaming-text-smoothing.js +41 -11
  111. package/dist/styles/agent-native.css +19 -32
  112. package/dist/templates/chat/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
  113. package/docs/content/template-chat.mdx +1 -1
  114. package/package.json +2 -2
  115. package/src/templates/chat/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
@@ -48,6 +48,8 @@ interface ExportMenuProps {
48
48
  onExportGoogleSlides?: () => Promise<GoogleSlidesExportResult>;
49
49
  onShareLink?: () => void;
50
50
  onShareTeam?: () => void;
51
+ /** Render the export actions inside an existing dropdown menu. */
52
+ inline?: boolean;
51
53
  }
52
54
 
53
55
  export function ExportMenu({
@@ -59,6 +61,7 @@ export function ExportMenu({
59
61
  onExportGoogleSlides,
60
62
  onShareLink,
61
63
  onShareTeam,
64
+ inline = false,
62
65
  }: ExportMenuProps) {
63
66
  const t = useT();
64
67
  const [googleSlidesImportOpen, setGoogleSlidesImportOpen] = useState(false);
@@ -224,75 +227,81 @@ export function ExportMenu({
224
227
  }
225
228
  };
226
229
 
227
- return (
230
+ const menuContent = (
228
231
  <>
229
- <DropdownMenu>
230
- <DropdownMenuTrigger asChild>
231
- <button className="flex items-center gap-1.5 px-2.5 py-1.5 rounded-md text-muted-foreground hover:text-foreground hover:bg-accent text-xs cursor-pointer whitespace-nowrap">
232
- <IconUpload className="w-3.5 h-3.5" />
233
- <span className="hidden md:inline">{t("editorExport.export")}</span>
234
- </button>
235
- </DropdownMenuTrigger>
236
- <DropdownMenuContent align="end" className="w-52">
237
- <DropdownMenuLabel className="text-[11px] text-muted-foreground">
238
- {t("editorExport.exportAndDuplicate")}
239
- </DropdownMenuLabel>
240
- {onShareTeam && (
241
- <DropdownMenuItem onClick={onShareTeam} className="cursor-pointer">
242
- <IconShare2 className="w-4 h-4 mr-2" />
243
- {t("editorExport.shareWithTeam")}
244
- </DropdownMenuItem>
245
- )}
246
- {onShareLink && (
247
- <DropdownMenuItem onClick={onShareLink} className="cursor-pointer">
248
- <IconShare2 className="w-4 h-4 mr-2" />
249
- {t("editorExport.publicShareLink")}
250
- </DropdownMenuItem>
251
- )}
252
- <DropdownMenuSeparator />
232
+ <DropdownMenuLabel className="text-[11px] text-muted-foreground">
233
+ {t("editorExport.exportAndDuplicate")}
234
+ </DropdownMenuLabel>
235
+ {onShareTeam && (
236
+ <DropdownMenuItem onClick={onShareTeam} className="cursor-pointer">
237
+ <IconShare2 className="w-4 h-4 mr-2" />
238
+ {t("editorExport.shareWithTeam")}
239
+ </DropdownMenuItem>
240
+ )}
241
+ {onShareLink && (
242
+ <DropdownMenuItem onClick={onShareLink} className="cursor-pointer">
243
+ <IconShare2 className="w-4 h-4 mr-2" />
244
+ {t("editorExport.publicShareLink")}
245
+ </DropdownMenuItem>
246
+ )}
247
+ <DropdownMenuSeparator />
248
+ <DropdownMenuItem onClick={handleExportHtml} className="cursor-pointer">
249
+ <IconCode className="w-4 h-4 mr-2" />
250
+ {t("editorExport.downloadHtml")}
251
+ </DropdownMenuItem>
252
+ <DropdownMenuItem onClick={onExportPdf} className="cursor-pointer">
253
+ <IconFileTypePdf className="w-4 h-4 mr-2" />
254
+ {t("editorExport.exportPdf")}
255
+ </DropdownMenuItem>
256
+ <DropdownMenuItem onClick={handleExportPptx} className="cursor-pointer">
257
+ <IconDownload className="w-4 h-4 mr-2" />
258
+ {t("editorExport.exportPptx")}
259
+ </DropdownMenuItem>
260
+ {onExportGoogleSlides && (
261
+ <>
253
262
  <DropdownMenuItem
254
- onClick={handleExportHtml}
263
+ onClick={handleConnectGoogle}
255
264
  className="cursor-pointer"
256
265
  >
257
- <IconCode className="w-4 h-4 mr-2" />
258
- {t("editorExport.downloadHtml")}
259
- </DropdownMenuItem>
260
- <DropdownMenuItem onClick={onExportPdf} className="cursor-pointer">
261
- <IconFileTypePdf className="w-4 h-4 mr-2" />
262
- {t("editorExport.exportPdf")}
266
+ <IconPlugConnected className="w-4 h-4 mr-2" />
267
+ {t("editorExport.connectGoogle")}
263
268
  </DropdownMenuItem>
264
269
  <DropdownMenuItem
265
- onClick={handleExportPptx}
270
+ onClick={handleExportGoogleSlides}
266
271
  className="cursor-pointer"
267
272
  >
268
- <IconDownload className="w-4 h-4 mr-2" />
269
- {t("editorExport.exportPptx")}
273
+ <IconBrandGoogle className="w-4 h-4 mr-2" />
274
+ {t("editorExport.openInGoogleSlides")}
270
275
  </DropdownMenuItem>
271
- {onExportGoogleSlides && (
272
- <>
273
- <DropdownMenuItem
274
- onClick={handleConnectGoogle}
275
- className="cursor-pointer"
276
- >
277
- <IconPlugConnected className="w-4 h-4 mr-2" />
278
- {t("editorExport.connectGoogle")}
279
- </DropdownMenuItem>
280
- <DropdownMenuItem
281
- onClick={handleExportGoogleSlides}
282
- className="cursor-pointer"
283
- >
284
- <IconBrandGoogle className="w-4 h-4 mr-2" />
285
- {t("editorExport.openInGoogleSlides")}
286
- </DropdownMenuItem>
287
- </>
288
- )}
289
- <DropdownMenuSeparator />
290
- <DropdownMenuItem onClick={onDuplicate} className="cursor-pointer">
291
- <IconCopy className="w-4 h-4 mr-2" />
292
- {t("editorExport.duplicateDeck")}
293
- </DropdownMenuItem>
294
- </DropdownMenuContent>
295
- </DropdownMenu>
276
+ </>
277
+ )}
278
+ <DropdownMenuSeparator />
279
+ <DropdownMenuItem onClick={onDuplicate} className="cursor-pointer">
280
+ <IconCopy className="w-4 h-4 mr-2" />
281
+ {t("editorExport.duplicateDeck")}
282
+ </DropdownMenuItem>
283
+ </>
284
+ );
285
+
286
+ return (
287
+ <>
288
+ {inline ? (
289
+ menuContent
290
+ ) : (
291
+ <DropdownMenu>
292
+ <DropdownMenuTrigger asChild>
293
+ <button className="flex items-center gap-1.5 px-2.5 py-1.5 rounded-md text-muted-foreground hover:text-foreground hover:bg-accent text-xs cursor-pointer whitespace-nowrap">
294
+ <IconUpload className="w-3.5 h-3.5" />
295
+ <span className="hidden md:inline">
296
+ {t("editorExport.export")}
297
+ </span>
298
+ </button>
299
+ </DropdownMenuTrigger>
300
+ <DropdownMenuContent align="end" className="w-52">
301
+ {menuContent}
302
+ </DropdownMenuContent>
303
+ </DropdownMenu>
304
+ )}
296
305
  <Dialog
297
306
  open={googleSlidesImportOpen}
298
307
  onOpenChange={setGoogleSlidesImportOpen}
@@ -69,7 +69,7 @@ export default function GeneratingSlidePreview({
69
69
  <span className="size-1.5 rounded-full bg-primary" aria-hidden="true" />
70
70
  {t("raw.aiEditing")}
71
71
  </div>
72
- <div className="absolute right-2 top-2 rounded-full bg-background/80 p-1.5 text-muted-foreground shadow-sm backdrop-blur">
72
+ <div className="absolute right-2 top-2 rounded-full bg-background/80 p-1.5 text-muted-foreground shadow-sm">
73
73
  <IconLoader2 className="size-3.5 animate-spin" aria-hidden="true" />
74
74
  </div>
75
75
  </div>
@@ -5,6 +5,7 @@ import {
5
5
  IconBrandGoogleDrive,
6
6
  IconLoader2,
7
7
  IconPlugConnected,
8
+ IconX,
8
9
  } from "@tabler/icons-react";
9
10
  import { useCallback, useEffect, useState } from "react";
10
11
 
@@ -65,6 +66,7 @@ export function GoogleDriveConnectionCta({
65
66
  const [loading, setLoading] = useState(true);
66
67
  const [connecting, setConnecting] = useState(false);
67
68
  const [error, setError] = useState<string | null>(null);
69
+ const [dismissed, setDismissed] = useState(false);
68
70
 
69
71
  const refreshStatus =
70
72
  useCallback(async (): Promise<GoogleDocsStatus | null> => {
@@ -165,7 +167,9 @@ export function GoogleDriveConnectionCta({
165
167
  }
166
168
  }, [connecting, onConnected, refreshStatus, requiresUrlImportAccess]);
167
169
 
168
- if (loading || (status?.connected && !needsReconnect)) return null;
170
+ if (dismissed || loading || (status?.connected && !needsReconnect)) {
171
+ return null;
172
+ }
169
173
 
170
174
  const displayStatus = status ?? { configured: false, connected: false };
171
175
 
@@ -208,6 +212,14 @@ export function GoogleDriveConnectionCta({
208
212
  : t("editorExport.connectGoogle")}
209
213
  </Button>
210
214
  )}
215
+ <button
216
+ type="button"
217
+ onClick={() => setDismissed(true)}
218
+ className="inline-flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-background hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
219
+ aria-label={t("comments.close")}
220
+ >
221
+ <IconX className="size-3.5" />
222
+ </button>
211
223
  </div>
212
224
  );
213
225
  }
@@ -7,7 +7,6 @@ import {
7
7
  IconChevronDown,
8
8
  IconFileText,
9
9
  IconFileTypePdf,
10
- IconPalette,
11
10
  IconPresentation,
12
11
  IconWorld,
13
12
  } from "@tabler/icons-react";
@@ -37,9 +36,11 @@ import {
37
36
  SelectValue,
38
37
  } from "@/components/ui/select";
39
38
  import type { Deck } from "@/context/DeckContext";
40
- import type { RecentReference } from "@/lib/recent-references";
39
+ import { sortDecksByRecency } from "@/lib/deck-sorting";
41
40
  import { cn } from "@/lib/utils";
42
41
 
42
+ import { GoogleDriveConnectionCta } from "./GoogleDriveConnectionCta";
43
+
43
44
  export interface NewDeckReferenceSelection {
44
45
  designSystemId?: string | null;
45
46
  referenceDeckId?: string | null;
@@ -71,7 +72,6 @@ interface NewDeckReferenceStepProps {
71
72
  decks: Deck[];
72
73
  defaultDesignSystemId: string | null;
73
74
  defaultReferenceDeckId: string | null;
74
- recentReferences: RecentReference[];
75
75
  onSelect: (selection: NewDeckReferenceSelection) => void | Promise<void>;
76
76
  onImport: (files: File[]) => Promise<ImportedReference | null>;
77
77
  onImportSource: (
@@ -86,8 +86,6 @@ interface NewDeckReferenceStepProps {
86
86
  chooseDeckLabel: string;
87
87
  importingLabel: string;
88
88
  skipLabel: string;
89
- starredLabel: string;
90
- otherDecksLabel: string;
91
89
  searchDecksLabel: string;
92
90
  promptSummary?: string;
93
91
  }
@@ -98,7 +96,6 @@ export function NewDeckReferenceStep({
98
96
  decks,
99
97
  defaultDesignSystemId,
100
98
  defaultReferenceDeckId,
101
- recentReferences,
102
99
  onSelect,
103
100
  onImport,
104
101
  onImportSource,
@@ -111,8 +108,6 @@ export function NewDeckReferenceStep({
111
108
  chooseDeckLabel,
112
109
  importingLabel,
113
110
  skipLabel,
114
- starredLabel,
115
- otherDecksLabel,
116
111
  searchDecksLabel,
117
112
  promptSummary,
118
113
  }: NewDeckReferenceStepProps) {
@@ -129,33 +124,8 @@ export function NewDeckReferenceStep({
129
124
  useState<NewDeckReferenceSelection["referenceSource"]>(null);
130
125
  const [referenceDeckSearchOpen, setReferenceDeckSearchOpen] = useState(false);
131
126
 
132
- const designSystemById = new Map(
133
- designSystems.map((designSystem) => [designSystem.id, designSystem]),
134
- );
135
127
  const deckById = new Map(decks.map((deck) => [deck.id, deck]));
136
- const recentOptions = recentReferences
137
- .map((reference) => {
138
- const item =
139
- reference.kind === "design-system"
140
- ? designSystemById.get(reference.id)
141
- : deckById.get(reference.id);
142
- return item ? { reference, item } : null;
143
- })
144
- .filter(
145
- (
146
- value,
147
- ): value is {
148
- reference: RecentReference;
149
- item: DesignSystemOption | Deck;
150
- } => value !== null,
151
- );
152
- const visibleRecentOptions = recentOptions.filter(({ reference }) =>
153
- reference.kind === "design-system"
154
- ? reference.id !== selectedDesignSystemId
155
- : reference.id !== selectedReferenceDeckId,
156
- );
157
- const starredDecks = decks.filter((deck) => deck.starred);
158
- const otherDecks = decks.filter((deck) => !deck.starred);
128
+ const sortedDecks = sortDecksByRecency(decks);
159
129
  const selectedReferenceDeck = selectedReferenceDeckId
160
130
  ? deckById.get(selectedReferenceDeckId)
161
131
  : undefined;
@@ -272,9 +242,9 @@ export function NewDeckReferenceStep({
272
242
  )}
273
243
  </div>
274
244
  <Select
275
- value={selectedDesignSystemId ?? undefined}
245
+ value={selectedDesignSystemId ?? "none"}
276
246
  onValueChange={(value) => {
277
- setSelectedDesignSystemId(value);
247
+ setSelectedDesignSystemId(value === "none" ? null : value);
278
248
  setSelectedSource(null);
279
249
  }}
280
250
  >
@@ -285,6 +255,7 @@ export function NewDeckReferenceStep({
285
255
  <SelectValue placeholder={designSystemLabel} />
286
256
  </SelectTrigger>
287
257
  <SelectContent>
258
+ <SelectItem value="none">{t("home.none")}</SelectItem>
288
259
  {designSystems.map((designSystem) => (
289
260
  <SelectItem key={designSystem.id} value={designSystem.id}>
290
261
  {designSystem.title}
@@ -331,101 +302,55 @@ export function NewDeckReferenceStep({
331
302
  <CommandInput placeholder={searchDecksLabel} />
332
303
  <CommandList className="max-h-72">
333
304
  <CommandEmpty>{t("home.noMatchingDecks")}</CommandEmpty>
334
- {starredDecks.length > 0 && (
335
- <CommandGroup heading={starredLabel}>
336
- {starredDecks.map((deck) => (
337
- <CommandItem
338
- key={deck.id}
339
- value={`${deck.title} ${deck.id}`}
340
- onSelect={() => {
341
- setSelectedReferenceDeckId(deck.id);
342
- setImportedReference(null);
343
- setSelectedSource(null);
344
- setReferenceDeckSearchOpen(false);
345
- }}
346
- >
347
- <IconCheck
348
- className={cn(
349
- "me-2 size-4",
350
- selectedReferenceDeckId === deck.id
351
- ? "opacity-100"
352
- : "opacity-0",
353
- )}
354
- />
355
- <span className="truncate">{deck.title}</span>
356
- </CommandItem>
357
- ))}
358
- </CommandGroup>
359
- )}
360
- {otherDecks.length > 0 && (
361
- <CommandGroup heading={otherDecksLabel}>
362
- {otherDecks.map((deck) => (
363
- <CommandItem
364
- key={deck.id}
365
- value={`${deck.title} ${deck.id}`}
366
- onSelect={() => {
367
- setSelectedReferenceDeckId(deck.id);
368
- setImportedReference(null);
369
- setSelectedSource(null);
370
- setReferenceDeckSearchOpen(false);
371
- }}
372
- >
373
- <IconCheck
374
- className={cn(
375
- "me-2 size-4",
376
- selectedReferenceDeckId === deck.id
377
- ? "opacity-100"
378
- : "opacity-0",
379
- )}
380
- />
381
- <span className="truncate">{deck.title}</span>
382
- </CommandItem>
383
- ))}
384
- </CommandGroup>
385
- )}
305
+ <CommandGroup>
306
+ <CommandItem
307
+ value={`none ${t("home.none")}`}
308
+ onSelect={() => {
309
+ setSelectedReferenceDeckId(null);
310
+ setImportedReference(null);
311
+ setSelectedSource(null);
312
+ setReferenceDeckSearchOpen(false);
313
+ }}
314
+ >
315
+ <IconCheck
316
+ className={cn(
317
+ "me-2 size-4",
318
+ selectedReferenceDeckId === null
319
+ ? "opacity-100"
320
+ : "opacity-0",
321
+ )}
322
+ />
323
+ <span className="truncate">{t("home.none")}</span>
324
+ </CommandItem>
325
+ {sortedDecks.map((deck) => (
326
+ <CommandItem
327
+ key={deck.id}
328
+ value={`${deck.title} ${deck.id}`}
329
+ onSelect={() => {
330
+ setSelectedReferenceDeckId(deck.id);
331
+ setImportedReference(null);
332
+ setSelectedSource(null);
333
+ setReferenceDeckSearchOpen(false);
334
+ }}
335
+ >
336
+ <IconCheck
337
+ className={cn(
338
+ "me-2 size-4",
339
+ selectedReferenceDeckId === deck.id
340
+ ? "opacity-100"
341
+ : "opacity-0",
342
+ )}
343
+ />
344
+ <span className="truncate">{deck.title}</span>
345
+ </CommandItem>
346
+ ))}
347
+ </CommandGroup>
386
348
  </CommandList>
387
349
  </Command>
388
350
  </PopoverContent>
389
351
  </Popover>
390
352
  </div>
391
353
 
392
- {visibleRecentOptions.length > 0 && (
393
- <div className="border-t border-border pt-5">
394
- <span className="text-xs font-medium text-muted-foreground">
395
- Recent
396
- </span>
397
- <div className="mt-2 space-y-2">
398
- {visibleRecentOptions.map(({ reference, item }) => (
399
- <ReferenceRow
400
- key={`${reference.kind}:${reference.id}`}
401
- compact
402
- icon={
403
- reference.kind === "design-system" ? (
404
- <IconPalette className="size-4" />
405
- ) : (
406
- <IconPresentation className="size-4" />
407
- )
408
- }
409
- label={item.title}
410
- meta={
411
- reference.kind === "design-system"
412
- ? designSystemLabel
413
- : referenceDeckLabel
414
- }
415
- onClick={() => {
416
- if (reference.kind === "design-system") {
417
- setSelectedDesignSystemId(reference.id);
418
- } else {
419
- setSelectedReferenceDeckId(reference.id);
420
- }
421
- setSelectedSource(null);
422
- }}
423
- />
424
- ))}
425
- </div>
426
- </div>
427
- )}
428
-
429
354
  <div className="border-t border-border pt-5">
430
355
  <span className="text-xs font-medium text-muted-foreground">
431
356
  {t("home.importFrom")}
@@ -463,7 +388,7 @@ export function NewDeckReferenceStep({
463
388
  />
464
389
  <ImportOption
465
390
  icon={<IconBrandGoogle className="size-4" />}
466
- label={t("home.googleSlidesReferenceTitle")}
391
+ label={t("home.googleSlidesImportLabel")}
467
392
  confirmed={importedReference?.source === "google-slides"}
468
393
  confirmedLabel={t("home.imported")}
469
394
  selected={
@@ -502,6 +427,11 @@ export function NewDeckReferenceStep({
502
427
  }
503
428
  />
504
429
  )}
430
+ {selectedSource?.kind === "google-docs" && (
431
+ <div className="mt-3">
432
+ <GoogleDriveConnectionCta />
433
+ </div>
434
+ )}
505
435
  {importedReference && (
506
436
  <div
507
437
  className="mt-3 flex items-start gap-3 rounded-lg border border-primary/30 bg-primary/5 px-3 py-2.5 text-sm"
@@ -633,51 +563,3 @@ function ImportOption({
633
563
  </button>
634
564
  );
635
565
  }
636
-
637
- function ReferenceRow({
638
- icon,
639
- label,
640
- meta,
641
- selected = false,
642
- compact = false,
643
- onClick,
644
- }: {
645
- icon: ReactNode;
646
- label: string;
647
- meta: string;
648
- selected?: boolean;
649
- compact?: boolean;
650
- onClick: () => void;
651
- }) {
652
- return (
653
- <button
654
- type="button"
655
- onClick={onClick}
656
- className={cn(
657
- "flex w-full min-w-0 items-center gap-3 rounded-lg border px-4 text-start transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
658
- compact ? "py-2.5" : "py-3.5",
659
- selected
660
- ? "border-primary/50 bg-primary/5"
661
- : "border-border bg-card/40 hover:border-foreground/30 hover:bg-accent/40",
662
- )}
663
- >
664
- <span
665
- className={cn(
666
- "flex size-8 shrink-0 items-center justify-center rounded-md",
667
- selected
668
- ? "bg-primary/10 text-primary"
669
- : "bg-accent text-muted-foreground",
670
- )}
671
- >
672
- {icon}
673
- </span>
674
- <span className="min-w-0 flex-1">
675
- <span className="block truncate text-sm font-medium">{label}</span>
676
- <span className="block truncate text-xs text-muted-foreground">
677
- {meta}
678
- </span>
679
- </span>
680
- {selected && <IconCheck className="size-4 shrink-0 text-primary" />}
681
- </button>
682
- );
683
- }