@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.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +2 -0
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +150 -46
- package/corpus/templates/analytics/app/global.css +1 -1
- package/corpus/templates/analytics/app/i18n-data.ts +37 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +32 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +2 -0
- package/corpus/templates/analytics/changelog/2026-08-10-dashboard-tables-can-be-copied-and-sorted-by-multiple-column.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/assets/app/global.css +1 -1
- package/corpus/templates/assets/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/brain/app/global.css +1 -1
- package/corpus/templates/brain/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/chat/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-10-clips-desktop-sign-in-now-starts-with-magic-links-and-google.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/overlay.css +1 -0
- package/corpus/templates/clips/desktop/src/app.tsx +274 -137
- package/corpus/templates/clips/desktop/src/styles.css +35 -0
- package/corpus/templates/content/app/global.css +1 -0
- package/corpus/templates/crm/app/global.css +1 -1
- package/corpus/templates/crm/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/factory/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/forms/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/plan/app/global.css +1 -0
- package/corpus/templates/plan/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/corpus/templates/plan/server/ui-plan-html.ts +4 -1
- package/corpus/templates/slides/AGENTS.md +11 -10
- package/corpus/templates/slides/actions/add-deck.ts +2 -0
- package/corpus/templates/slides/actions/add-slide.ts +15 -1
- package/corpus/templates/slides/actions/create-deck.ts +18 -6
- package/corpus/templates/slides/actions/get-deck.ts +29 -1
- package/corpus/templates/slides/actions/patch-deck.ts +122 -9
- package/corpus/templates/slides/actions/save-deck.ts +24 -1
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +134 -618
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +69 -60
- package/corpus/templates/slides/app/components/editor/GeneratingSlidePreview.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +13 -1
- package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +56 -174
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +239 -116
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +3 -3
- package/corpus/templates/slides/app/components/layout/AgentWorkIndicator.tsx +1 -1
- package/corpus/templates/slides/app/components/layout/Layout.tsx +34 -35
- package/corpus/templates/slides/app/components/layout/layout-route-policy.ts +2 -5
- package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +45 -40
- package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +63 -16
- package/corpus/templates/slides/app/hooks/use-generating-slide-preview.ts +25 -3
- package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +5 -4
- package/corpus/templates/slides/app/lib/recent-references.ts +23 -1
- package/corpus/templates/slides/app/lib/slide-animation-elements.ts +41 -3
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +4 -27
- package/corpus/templates/slides/app/pages/Index.tsx +240 -89
- package/corpus/templates/slides/changelog/2026-08-10-ai-editing-avatar-badge.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-generated-decks-keep-a-clear-human-readable-title.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-new-deck-creation-now-shows-progress-opens-the-editor-direct.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-presentation-reveals-now-follow-valid-targets.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-slides-editing-controls-are-consolidated-into-one-focused-me.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-slides-now-verify-and-restyle-every-imported-slide-in-one-pa.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-slides-only-suggests-a-google-connection-for-relevant-reques.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-10-the-google-slides-import-option-is-now-labeled-slides.md +6 -0
- package/corpus/templates/slides/server/lib/chat-attachments.ts +1 -1
- package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -3
- package/corpus/templates/slides/shared/api.ts +2 -1
- package/corpus/templates/slides/shared/deck-title.ts +135 -0
- package/corpus/templates/tasks/app/components/tasks/TaskListRow.tsx +4 -1
- package/dist/agent/engine/ai-sdk-engine.js +1 -1
- package/dist/agent/production-agent.d.ts +21 -1
- package/dist/agent/production-agent.js +129 -10
- package/dist/agent/tool-approval-store.d.ts +18 -0
- package/dist/agent/tool-approval-store.js +122 -0
- package/dist/agent/types.d.ts +1 -1
- package/dist/cli/code-agent-executor.js +11 -2
- package/dist/client/AgentPanel.js +31 -6
- package/dist/client/AssistantChat.d.ts +3 -2
- package/dist/client/AssistantChat.js +7 -20
- package/dist/client/agent-chat/index.d.ts +1 -1
- package/dist/client/agent-chat-adapter.js +11 -0
- package/dist/client/agent-chat.d.ts +1 -1
- package/dist/client/chat/markdown-renderer.js +14 -2
- package/dist/client/chat/message-components.d.ts +6 -2
- package/dist/client/chat/message-components.js +25 -47
- package/dist/client/chat/tool-call-display.d.ts +3 -5
- package/dist/client/chat/tool-call-display.js +7 -212
- package/dist/client/chat-first/apps-rail.js +3 -3
- package/dist/client/chat-first/browser-pane.js +4 -1
- package/dist/client/chat-first/chat-history.d.ts +3 -1
- package/dist/client/chat-first/chat-history.js +2 -2
- package/dist/client/chat-first/surface-tabs.d.ts +1 -1
- package/dist/client/chat-first/surface-tabs.js +52 -41
- package/dist/client/chat-first/types.d.ts +3 -0
- package/dist/client/chat-first.d.ts +10 -0
- package/dist/client/chat-first.js +37 -2
- package/dist/client/components/ui/message-scroller.js +4 -1
- package/dist/client/i18n.js +3 -1
- package/dist/client/resources/McpConnectionSuggestion.js +9 -1
- package/dist/client/sse-event-processor.js +10 -0
- package/dist/client/use-chat-models.js +156 -80
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/integrations/webhook-handler.js +1 -1
- package/dist/observability/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/auth.js +262 -31
- package/dist/server/onboarding-html.js +56 -9
- package/dist/shared/reasoning-effort.d.ts +8 -8
- package/dist/shared/reasoning-effort.js +10 -10
- package/dist/shared/streaming-text-smoothing.js +41 -11
- package/dist/styles/agent-native.css +19 -32
- package/dist/templates/chat/changelog/2026-08-10-full-page-chat-now-uses-the-available-width-up-to-1000px-for.md +6 -0
- package/docs/content/template-chat.mdx +1 -1
- package/package.json +2 -2
- 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
|
-
|
|
230
|
+
const menuContent = (
|
|
228
231
|
<>
|
|
229
|
-
<
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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={
|
|
263
|
+
onClick={handleConnectGoogle}
|
|
255
264
|
className="cursor-pointer"
|
|
256
265
|
>
|
|
257
|
-
<
|
|
258
|
-
{t("editorExport.
|
|
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={
|
|
270
|
+
onClick={handleExportGoogleSlides}
|
|
266
271
|
className="cursor-pointer"
|
|
267
272
|
>
|
|
268
|
-
<
|
|
269
|
-
{t("editorExport.
|
|
273
|
+
<IconBrandGoogle className="w-4 h-4 mr-2" />
|
|
274
|
+
{t("editorExport.openInGoogleSlides")}
|
|
270
275
|
</DropdownMenuItem>
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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
|
|
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))
|
|
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
|
|
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
|
|
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 ??
|
|
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
|
-
|
|
335
|
-
<
|
|
336
|
-
{
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
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.
|
|
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
|
-
}
|