@agent-native/core 0.137.3 → 0.137.4

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 (178) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  3. package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +53 -1
  4. package/corpus/templates/analytics/actions/gong-calls.ts +37 -17
  5. package/corpus/templates/analytics/app/lib/data-sources.ts +1 -1
  6. package/corpus/templates/analytics/server/lib/gong.ts +51 -2
  7. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  8. package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +53 -1
  9. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  10. package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +53 -1
  11. package/corpus/templates/brain/app/routes/settings.tsx +1 -1
  12. package/corpus/templates/brain/server/register-secrets.ts +1 -1
  13. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  14. package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +53 -1
  15. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  16. package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +53 -1
  17. package/corpus/templates/chat/AGENTS.md +11 -0
  18. package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -1
  19. package/corpus/templates/chat/app/root.tsx +1 -1
  20. package/corpus/templates/chat/app/routes/agent.tsx +29 -13
  21. package/corpus/templates/chat/vite.config.ts +42 -0
  22. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  23. package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +53 -1
  24. package/corpus/templates/clips/app/components/library/empty-state.tsx +1 -3
  25. package/corpus/templates/clips/app/components/library/library-grid.tsx +2 -6
  26. package/corpus/templates/clips/app/components/library/library-layout.tsx +2 -6
  27. package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +1 -3
  28. package/corpus/templates/clips/app/routes/bug-report.tsx +1 -8
  29. package/corpus/templates/clips/app/routes/import.tsx +1 -3
  30. package/corpus/templates/clips/changelog/2026-08-04-recording-buttons-are-now-text-only-for-a-cleaner-clips-inte.md +6 -0
  31. package/corpus/templates/clips/changelog/2026-08-04-save-settings-now-matches-the-other-clips-settings-buttons.md +6 -0
  32. package/corpus/templates/clips/chrome-extension/src/styles.css +1 -0
  33. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  34. package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +53 -1
  35. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  36. package/corpus/templates/crm/app/routes/settings.tsx +2 -2
  37. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  38. package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +53 -1
  39. package/corpus/templates/design/actions/import-figma-clipboard.ts +1 -1
  40. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  41. package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +53 -1
  42. package/corpus/templates/dispatch/changelog/2026-08-04-dispatch-keeps-connected-chats-out-of-local-history-by-defau.md +6 -0
  43. package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  44. package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +53 -1
  45. package/corpus/templates/factory/README.md +1 -1
  46. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  47. package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +53 -1
  48. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  49. package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +53 -1
  50. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  51. package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +53 -1
  52. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +0 -2
  53. package/corpus/templates/mail/app/pages/SettingsPage.tsx +1 -1
  54. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  55. package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +53 -1
  56. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  57. package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +53 -1
  58. package/corpus/templates/slides/actions/generate-image-api.ts +15 -4
  59. package/corpus/templates/slides/actions/import-google-slides-reference.ts +83 -0
  60. package/corpus/templates/slides/actions/import-pptx.ts +134 -117
  61. package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +387 -0
  62. package/corpus/templates/slides/app/components/editor/ImageGenPanel.tsx +78 -48
  63. package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +377 -187
  64. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +0 -1
  65. package/corpus/templates/slides/app/hooks/use-deck-design-system.ts +20 -1
  66. package/corpus/templates/slides/app/i18n/en-US.ts +15 -0
  67. package/corpus/templates/slides/app/lib/new-deck-reference-selection.ts +22 -0
  68. package/corpus/templates/slides/app/pages/DeckEditor.tsx +4 -1
  69. package/corpus/templates/slides/app/pages/Index.tsx +172 -85
  70. package/corpus/templates/slides/server/lib/assets-image-delegation.ts +4 -2
  71. package/corpus/templates/slides/shared/api.ts +14 -1
  72. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  73. package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +53 -1
  74. package/dist/chat-threads/schema.d.ts +57 -0
  75. package/dist/chat-threads/schema.js +3 -0
  76. package/dist/chat-threads/store.d.ts +26 -0
  77. package/dist/chat-threads/store.js +84 -6
  78. package/dist/client/AgentPanel.js +11 -5
  79. package/dist/client/ConnectBuilderCard.js +1 -1
  80. package/dist/client/agent-page/AgentEmptyState.d.ts +2 -1
  81. package/dist/client/agent-page/AgentEmptyState.js +6 -2
  82. package/dist/client/agent-page/AgentJobsTab.d.ts +3 -1
  83. package/dist/client/agent-page/AgentJobsTab.js +55 -44
  84. package/dist/client/agent-page/AgentTabFrame.d.ts +2 -1
  85. package/dist/client/agent-page/AgentTabFrame.js +4 -2
  86. package/dist/client/agent-page/AgentTabsPage.js +12 -8
  87. package/dist/client/agent-page/AgentWorkspaceContent.d.ts +10 -0
  88. package/dist/client/agent-page/AgentWorkspaceContent.js +110 -0
  89. package/dist/client/agent-page/AutomationDetailsDialog.js +1 -1
  90. package/dist/client/chat/run-recovery.js +3 -3
  91. package/dist/client/error-format.js +1 -1
  92. package/dist/client/integrations/IntegrationsPanel.d.ts +1 -0
  93. package/dist/client/integrations/IntegrationsPanel.js +149 -5
  94. package/dist/client/onboarding/FirstRunOnboarding.js +130 -15
  95. package/dist/client/onboarding/index.d.ts +1 -1
  96. package/dist/client/onboarding/index.js +1 -1
  97. package/dist/client/onboarding/use-onboarding.js +12 -2
  98. package/dist/client/onboarding/use-preview-mode.d.ts +4 -0
  99. package/dist/client/onboarding/use-preview-mode.js +9 -0
  100. package/dist/client/resources/BuiltinCapabilityDetail.js +2 -2
  101. package/dist/client/resources/ResourceTree.d.ts +4 -1
  102. package/dist/client/resources/ResourceTree.js +13 -8
  103. package/dist/client/resources/ResourcesPanel.js +7 -3
  104. package/dist/client/resources/mcp-integration-catalog.js +4 -4
  105. package/dist/client/resources/use-mcp-servers.js +6 -6
  106. package/dist/client/settings/AgentsSection.js +15 -16
  107. package/dist/client/settings/AutomationsSection.js +1 -1
  108. package/dist/client/settings/DemoModeSection.js +1 -1
  109. package/dist/client/settings/SettingsPanel.d.ts +3 -1
  110. package/dist/client/settings/SettingsPanel.js +284 -88
  111. package/dist/client/settings/SettingsRow.js +1 -1
  112. package/dist/client/settings/SettingsSection.d.ts +6 -4
  113. package/dist/client/settings/SettingsSection.js +6 -6
  114. package/dist/client/settings/SettingsTabsPage.js +47 -25
  115. package/dist/client/settings/VoiceTranscriptionSection.d.ts +3 -1
  116. package/dist/client/settings/VoiceTranscriptionSection.js +20 -8
  117. package/dist/client/settings/agent-settings-search.d.ts +1 -1
  118. package/dist/client/settings/agent-settings-search.js +8 -8
  119. package/dist/client/transcription/BuilderTranscriptionCta.js +2 -2
  120. package/dist/client/use-chat-threads.d.ts +9 -0
  121. package/dist/client/use-chat-threads.js +22 -6
  122. package/dist/collab/awareness.d.ts +2 -2
  123. package/dist/collab/routes.d.ts +1 -1
  124. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  125. package/dist/integrations/google-docs-poller.js +9 -1
  126. package/dist/integrations/webhook-handler.js +11 -1
  127. package/dist/jobs/scheduler.d.ts +4 -1
  128. package/dist/jobs/scheduler.js +34 -9
  129. package/dist/localization/default-messages.js +40 -40
  130. package/dist/mcp-client/oauth-routes.js +1 -1
  131. package/dist/notifications/routes.d.ts +1 -1
  132. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  133. package/dist/provider-api/actions/provider-api.d.ts +15 -15
  134. package/dist/secrets/onboarding.js +1 -1
  135. package/dist/secrets/routes.d.ts +6 -6
  136. package/dist/server/agent-chat/browser-team-tools.d.ts +1 -0
  137. package/dist/server/agent-chat/browser-team-tools.js +1 -0
  138. package/dist/server/agent-chat-plugin.js +14 -1
  139. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  140. package/dist/server/agent-teams.d.ts +2 -0
  141. package/dist/server/agent-teams.js +2 -0
  142. package/dist/server/realtime-token.d.ts +1 -1
  143. package/dist/server/workspace-provider-oauth.js +1 -1
  144. package/dist/setup-connections/onboarding.js +2 -2
  145. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  146. package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +53 -1
  147. package/dist/templates/chat/AGENTS.md +11 -0
  148. package/dist/templates/chat/app/components/layout/Layout.tsx +1 -1
  149. package/dist/templates/chat/app/root.tsx +1 -1
  150. package/dist/templates/chat/app/routes/agent.tsx +29 -13
  151. package/dist/templates/chat/vite.config.ts +42 -0
  152. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  153. package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +53 -1
  154. package/dist/templates/default/AGENTS.md +11 -0
  155. package/dist/templates/default/vite.config.ts +42 -0
  156. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  157. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  158. package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +53 -1
  159. package/dist/templates/workspace-core/AGENTS.md +11 -0
  160. package/dist/templates/workspace-root/AGENTS.md +14 -0
  161. package/dist/vite/client.js +56 -0
  162. package/package.json +2 -2
  163. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  164. package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +53 -1
  165. package/src/templates/chat/AGENTS.md +11 -0
  166. package/src/templates/chat/app/components/layout/Layout.tsx +1 -1
  167. package/src/templates/chat/app/root.tsx +1 -1
  168. package/src/templates/chat/app/routes/agent.tsx +29 -13
  169. package/src/templates/chat/vite.config.ts +42 -0
  170. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  171. package/src/templates/default/.agents/skills/frontend-design/SKILL.md +53 -1
  172. package/src/templates/default/AGENTS.md +11 -0
  173. package/src/templates/default/vite.config.ts +42 -0
  174. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  175. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  176. package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +53 -1
  177. package/src/templates/workspace-core/AGENTS.md +11 -0
  178. package/src/templates/workspace-root/AGENTS.md +14 -0
@@ -1,12 +1,18 @@
1
1
  import {
2
2
  IconArrowRight,
3
+ IconCheck,
3
4
  IconPalette,
4
5
  IconPresentation,
6
+ IconSearch,
7
+ IconStar,
5
8
  IconUpload,
9
+ IconX,
6
10
  } from "@tabler/icons-react";
7
11
  import type { ChangeEvent, ReactNode } from "react";
12
+ import { useMemo, useState } from "react";
8
13
 
9
14
  import { Button } from "@/components/ui/button";
15
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
10
16
  import {
11
17
  Dialog,
12
18
  DialogContent,
@@ -14,6 +20,8 @@ import {
14
20
  DialogHeader,
15
21
  DialogTitle,
16
22
  } from "@/components/ui/dialog";
23
+ import { Input } from "@/components/ui/input";
24
+ import { ScrollArea } from "@/components/ui/scroll-area";
17
25
  import {
18
26
  Select,
19
27
  SelectContent,
@@ -23,14 +31,11 @@ import {
23
31
  SelectTrigger,
24
32
  SelectValue,
25
33
  } from "@/components/ui/select";
34
+ import { Separator } from "@/components/ui/separator";
26
35
  import type { Deck } from "@/context/DeckContext";
27
- import type { RecentReference } from "@/lib/recent-references";
28
36
  import { cn } from "@/lib/utils";
29
37
 
30
- export interface NewDeckReferenceSelection {
31
- designSystemId?: string | null;
32
- referenceDeckId?: string | null;
33
- }
38
+ import { GoogleSlidesReferenceImport } from "./GoogleSlidesReferenceImport";
34
39
 
35
40
  interface DesignSystemOption {
36
41
  id: string;
@@ -44,24 +49,41 @@ interface NewDeckReferenceStepProps {
44
49
  decks: Deck[];
45
50
  defaultDesignSystemId: string | null;
46
51
  defaultReferenceDeckId: string | null;
47
- recentReferences: RecentReference[];
48
- onSelect: (selection: NewDeckReferenceSelection) => void;
52
+ selectedDesignSystemId: string | null;
53
+ selectedReferenceDeckId: string | null;
54
+ onSelectDesignSystem: (designSystemId: string | null) => void;
55
+ onSelectReferenceDeck: (referenceDeckId: string | null) => void;
49
56
  onImport: (files: File[]) => Promise<void>;
57
+ onContinue: () => void;
50
58
  onSkip: () => void;
51
59
  onOpenChange: (open: boolean) => void;
60
+ onGoogleSlidesImported: (imported: {
61
+ id: string;
62
+ title: string;
63
+ }) => void | Promise<void>;
52
64
  importing?: boolean;
53
65
  title: string;
66
+ description: string;
54
67
  designSystemLabel: string;
55
68
  referenceDeckLabel: string;
56
- chooseDeckLabel: string;
69
+ noneLabel: string;
57
70
  importFileLabel: string;
58
71
  importingLabel: string;
72
+ continueLabel: string;
59
73
  skipLabel: string;
60
74
  defaultSuffix: string;
61
75
  starredLabel: string;
62
76
  otherDecksLabel: string;
63
- description: string;
64
77
  promptNote?: string;
78
+ searchDecksLabel: string;
79
+ chooseAnotherDeckLabel: string;
80
+ noMatchingDecksLabel: string;
81
+ googleSlidesTitle: string;
82
+ googleSlidesConnectLabel: string;
83
+ googleSlidesChooseLabel: string;
84
+ googleSlidesPickingLabel: string;
85
+ googleSlidesConnectedLabel: string;
86
+ googleSlidesUnavailableLabel: string;
65
87
  }
66
88
 
67
89
  export function NewDeckReferenceStep({
@@ -70,57 +92,83 @@ export function NewDeckReferenceStep({
70
92
  decks,
71
93
  defaultDesignSystemId,
72
94
  defaultReferenceDeckId,
73
- recentReferences,
74
- onSelect,
95
+ selectedDesignSystemId,
96
+ selectedReferenceDeckId,
97
+ onSelectDesignSystem,
98
+ onSelectReferenceDeck,
75
99
  onImport,
100
+ onContinue,
76
101
  onSkip,
77
102
  onOpenChange,
103
+ onGoogleSlidesImported,
78
104
  importing = false,
79
105
  title,
106
+ description,
80
107
  designSystemLabel,
81
108
  referenceDeckLabel,
82
- chooseDeckLabel,
109
+ noneLabel,
83
110
  importFileLabel,
84
111
  importingLabel,
112
+ continueLabel,
85
113
  skipLabel,
86
114
  defaultSuffix,
87
115
  starredLabel,
88
116
  otherDecksLabel,
89
- description,
90
117
  promptNote,
118
+ searchDecksLabel,
119
+ chooseAnotherDeckLabel,
120
+ noMatchingDecksLabel,
121
+ googleSlidesTitle,
122
+ googleSlidesConnectLabel,
123
+ googleSlidesChooseLabel,
124
+ googleSlidesPickingLabel,
125
+ googleSlidesConnectedLabel,
126
+ googleSlidesUnavailableLabel,
91
127
  }: 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),
128
+ const [query, setQuery] = useState("");
129
+ const [googleSlidesBusy, setGoogleSlidesBusy] = useState(false);
130
+ const designSystemById = useMemo(
131
+ () =>
132
+ new Map(
133
+ designSystems.map((designSystem) => [designSystem.id, designSystem]),
134
+ ),
135
+ [designSystems],
117
136
  );
118
- const visibleRecentOptions = recentOptions.filter(
119
- ({ reference }) =>
120
- !defaultReferenceKeys.has(`${reference.kind}:${reference.id}`),
137
+ const deckById = useMemo(
138
+ () => new Map(decks.map((deck) => [deck.id, deck])),
139
+ [decks],
121
140
  );
122
- const starredDecks = decks.filter((deck) => deck.starred);
123
- const otherDecks = decks.filter((deck) => !deck.starred);
141
+
142
+ const filteredDecks = useMemo(() => {
143
+ const normalized = query.trim().toLowerCase();
144
+ if (!normalized) {
145
+ return {
146
+ starred: decks.filter((deck) => deck.starred),
147
+ other: decks.filter((deck) => !deck.starred),
148
+ flat: [] as Deck[],
149
+ };
150
+ }
151
+ const flat = decks.filter((deck) =>
152
+ deck.title.toLowerCase().includes(normalized),
153
+ );
154
+ return { starred: [], other: [], flat };
155
+ }, [decks, query]);
156
+
157
+ const currentDesignSystem = selectedDesignSystemId
158
+ ? (designSystemById.get(selectedDesignSystemId) ?? null)
159
+ : null;
160
+ const selectedDesignSystemLabel =
161
+ currentDesignSystem?.title ?? designSystemLabel;
162
+ const selectedReferenceDeckLabel =
163
+ (selectedReferenceDeckId
164
+ ? deckById.get(selectedReferenceDeckId)?.title
165
+ : null) ?? referenceDeckLabel;
166
+ const selectedDesignSystemIsDefault =
167
+ !!selectedDesignSystemId &&
168
+ selectedDesignSystemId === defaultDesignSystemId;
169
+ const selectedReferenceDeckIsDefault =
170
+ !!selectedReferenceDeckId &&
171
+ selectedReferenceDeckId === defaultReferenceDeckId;
124
172
 
125
173
  const handleImport = async (event: ChangeEvent<HTMLInputElement>) => {
126
174
  const files = Array.from(event.target.files ?? []);
@@ -131,191 +179,333 @@ export function NewDeckReferenceStep({
131
179
 
132
180
  return (
133
181
  <Dialog open={open} onOpenChange={onOpenChange}>
134
- <DialogContent className="max-h-[min(720px,calc(100vh-32px))] overflow-y-auto sm:max-w-2xl">
182
+ <DialogContent className="max-h-[min(88vh,880px)] overflow-hidden sm:max-w-5xl">
135
183
  <DialogHeader>
136
184
  <DialogTitle>{title}</DialogTitle>
137
185
  <DialogDescription>{description}</DialogDescription>
138
186
  </DialogHeader>
139
187
 
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
- )}
188
+ <div className="space-y-2">
189
+ <p className="text-sm text-muted-foreground">{promptNote ?? ""}</p>
190
+ </div>
214
191
 
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 && (
192
+ <div className="grid gap-4 lg:grid-cols-[minmax(0,0.9fr)_minmax(0,1.35fr)]">
193
+ <div className="grid gap-4">
194
+ <Card className="border-border/70">
195
+ <CardHeader className="space-y-1 pb-3">
196
+ <CardTitle className="text-sm">{designSystemLabel}</CardTitle>
197
+ <p className="text-xs text-muted-foreground">
198
+ {defaultDesignSystemId
199
+ ? `${designSystemLabel}${defaultSuffix}`
200
+ : noneLabel}
201
+ </p>
202
+ </CardHeader>
203
+ <CardContent className="space-y-3">
204
+ <Select
205
+ value={selectedDesignSystemId ?? "none"}
206
+ onValueChange={(value) =>
207
+ onSelectDesignSystem(value === "none" ? null : value)
208
+ }
209
+ >
210
+ <SelectTrigger className="w-full">
211
+ <SelectValue placeholder={designSystemLabel} />
212
+ </SelectTrigger>
213
+ <SelectContent>
230
214
  <SelectGroup>
231
- <SelectLabel>{starredLabel}</SelectLabel>
232
- {starredDecks.map((deck) => (
233
- <SelectItem key={deck.id} value={deck.id}>
234
- {deck.title}
215
+ <SelectLabel>{designSystemLabel}</SelectLabel>
216
+ <SelectItem value="none">{noneLabel}</SelectItem>
217
+ {designSystems.map((designSystem) => (
218
+ <SelectItem
219
+ key={designSystem.id}
220
+ value={designSystem.id}
221
+ >
222
+ {designSystem.title}
223
+ {designSystem.isDefault ? defaultSuffix : ""}
235
224
  </SelectItem>
236
225
  ))}
237
226
  </SelectGroup>
227
+ </SelectContent>
228
+ </Select>
229
+
230
+ <SelectionSummary
231
+ icon={<IconPalette className="size-4" />}
232
+ label={
233
+ selectedDesignSystemId
234
+ ? selectedDesignSystemLabel
235
+ : noneLabel
236
+ }
237
+ meta={
238
+ selectedDesignSystemIsDefault
239
+ ? `${designSystemLabel}${defaultSuffix}`
240
+ : selectedDesignSystemId
241
+ ? designSystemLabel
242
+ : noneLabel
243
+ }
244
+ onClear={
245
+ selectedDesignSystemId
246
+ ? () => onSelectDesignSystem(null)
247
+ : undefined
248
+ }
249
+ />
250
+ </CardContent>
251
+ </Card>
252
+
253
+ <Card className="border-border/70">
254
+ <CardHeader className="space-y-1 pb-3">
255
+ <CardTitle className="text-sm">{googleSlidesTitle}</CardTitle>
256
+ <p className="text-xs text-muted-foreground">
257
+ {googleSlidesConnectedLabel}
258
+ </p>
259
+ </CardHeader>
260
+ <CardContent className="space-y-3">
261
+ <GoogleSlidesReferenceImport
262
+ onImported={onGoogleSlidesImported}
263
+ onBusyChange={setGoogleSlidesBusy}
264
+ title={googleSlidesTitle}
265
+ chooseLabel={googleSlidesChooseLabel}
266
+ connectLabel={googleSlidesConnectLabel}
267
+ pickingLabel={googleSlidesPickingLabel}
268
+ connectedLabel={googleSlidesConnectedLabel}
269
+ unavailableLabel={googleSlidesUnavailableLabel}
270
+ />
271
+
272
+ <label
273
+ className={cn(
274
+ "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",
275
+ importing && "pointer-events-none opacity-60",
238
276
  )}
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>
277
+ >
278
+ <IconUpload className="size-4" />
279
+ {importing ? importingLabel : importFileLabel}
280
+ <input
281
+ type="file"
282
+ className="sr-only"
283
+ accept=".pptx,.pdf,.docx"
284
+ multiple
285
+ disabled={importing}
286
+ onChange={(event) => void handleImport(event)}
287
+ />
288
+ </label>
289
+ </CardContent>
290
+ </Card>
291
+ </div>
292
+
293
+ <Card className="min-h-0 border-border/70">
294
+ <CardHeader className="space-y-1 pb-3">
295
+ <CardTitle className="text-sm">
296
+ {chooseAnotherDeckLabel}
297
+ </CardTitle>
298
+ <p className="text-xs text-muted-foreground">
299
+ {searchDecksLabel}
300
+ </p>
301
+ </CardHeader>
302
+ <CardContent className="min-h-0 space-y-3">
303
+ <div className="relative">
304
+ <IconSearch className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
305
+ <Input
306
+ value={query}
307
+ onChange={(event) => setQuery(event.target.value)}
308
+ aria-label={searchDecksLabel}
309
+ placeholder={searchDecksLabel}
310
+ className="ps-9"
311
+ />
312
+ </div>
313
+
314
+ <ScrollArea className="max-h-[430px] pr-3">
315
+ <div className="space-y-4">
316
+ {query.trim() ? (
317
+ filteredDecks.flat.length > 0 ? (
318
+ <div className="space-y-2">
319
+ {filteredDecks.flat.map((deck) => (
320
+ <DeckRow
321
+ key={deck.id}
322
+ deck={deck}
323
+ selected={deck.id === selectedReferenceDeckId}
324
+ onSelect={() => onSelectReferenceDeck(deck.id)}
325
+ starredLabel={starredLabel}
326
+ />
327
+ ))}
328
+ </div>
329
+ ) : (
330
+ <div className="rounded-lg border border-dashed border-border/70 px-4 py-6 text-sm text-muted-foreground">
331
+ {noMatchingDecksLabel}
332
+ </div>
333
+ )
334
+ ) : (
335
+ <>
336
+ {filteredDecks.starred.length > 0 && (
337
+ <div className="space-y-2">
338
+ <div className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
339
+ {starredLabel}
340
+ </div>
341
+ {filteredDecks.starred.map((deck) => (
342
+ <DeckRow
343
+ key={deck.id}
344
+ deck={deck}
345
+ selected={deck.id === selectedReferenceDeckId}
346
+ onSelect={() => onSelectReferenceDeck(deck.id)}
347
+ starredLabel={starredLabel}
348
+ />
349
+ ))}
350
+ </div>
351
+ )}
352
+ {filteredDecks.other.length > 0 && (
353
+ <div className="space-y-2">
354
+ {filteredDecks.starred.length > 0 && (
355
+ <Separator className="my-1" />
356
+ )}
357
+ <div className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
358
+ {otherDecksLabel}
359
+ </div>
360
+ {filteredDecks.other.map((deck) => (
361
+ <DeckRow
362
+ key={deck.id}
363
+ deck={deck}
364
+ selected={deck.id === selectedReferenceDeckId}
365
+ onSelect={() => onSelectReferenceDeck(deck.id)}
366
+ starredLabel={starredLabel}
367
+ />
368
+ ))}
369
+ </div>
370
+ )}
371
+ </>
248
372
  )}
249
- </SelectContent>
250
- </Select>
251
- </div>
252
- )}
373
+ </div>
374
+ </ScrollArea>
253
375
 
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)}
376
+ <Separator />
377
+ <SelectionSummary
378
+ icon={<IconPresentation className="size-4" />}
379
+ label={
380
+ selectedReferenceDeckId
381
+ ? selectedReferenceDeckLabel
382
+ : noneLabel
383
+ }
384
+ meta={
385
+ selectedReferenceDeckIsDefault
386
+ ? `${referenceDeckLabel}${defaultSuffix}`
387
+ : selectedReferenceDeckId
388
+ ? referenceDeckLabel
389
+ : noneLabel
390
+ }
391
+ onClear={
392
+ selectedReferenceDeckId
393
+ ? () => onSelectReferenceDeck(null)
394
+ : undefined
395
+ }
270
396
  />
271
- </label>
272
- </div>
397
+ </CardContent>
398
+ </Card>
273
399
  </div>
274
400
 
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}>
401
+ <div className="flex flex-col-reverse items-stretch justify-between gap-2 border-t border-border pt-3 sm:flex-row sm:items-center">
402
+ <Button
403
+ type="button"
404
+ variant="ghost"
405
+ onClick={onSkip}
406
+ disabled={importing || googleSlidesBusy}
407
+ >
283
408
  {skipLabel}
284
409
  </Button>
285
- <IconArrowRight className="size-4 text-muted-foreground" />
410
+ <div className="flex items-center gap-2">
411
+ <Button
412
+ type="button"
413
+ variant="outline"
414
+ onClick={onContinue}
415
+ disabled={importing || googleSlidesBusy}
416
+ >
417
+ {continueLabel}
418
+ </Button>
419
+ <IconArrowRight className="size-4 text-muted-foreground" />
420
+ </div>
286
421
  </div>
287
422
  </DialogContent>
288
423
  </Dialog>
289
424
  );
290
425
  }
291
426
 
292
- function ReferenceCard({
427
+ function SelectionSummary({
293
428
  icon,
294
429
  label,
295
430
  meta,
296
- onClick,
431
+ onClear,
297
432
  }: {
298
433
  icon: ReactNode;
299
434
  label: string;
300
435
  meta: string;
301
- onClick: () => void;
436
+ onClear?: () => void;
437
+ }) {
438
+ return (
439
+ <div className="flex min-w-0 items-center gap-3 rounded-lg border border-border/70 bg-background px-3 py-2">
440
+ <span className="flex size-8 shrink-0 items-center justify-center rounded-md bg-accent text-muted-foreground">
441
+ {icon}
442
+ </span>
443
+ <span className="min-w-0 flex-1">
444
+ <span className="block truncate text-sm font-medium text-foreground">
445
+ {label}
446
+ </span>
447
+ <span className="block truncate text-xs text-muted-foreground">
448
+ {meta}
449
+ </span>
450
+ </span>
451
+ {onClear && (
452
+ <Button
453
+ type="button"
454
+ variant="ghost"
455
+ size="icon"
456
+ className="size-8 shrink-0"
457
+ onClick={onClear}
458
+ aria-label={`Remove ${label}`}
459
+ >
460
+ <IconX className="size-4" />
461
+ </Button>
462
+ )}
463
+ </div>
464
+ );
465
+ }
466
+
467
+ function DeckRow({
468
+ deck,
469
+ selected,
470
+ onSelect,
471
+ starredLabel,
472
+ }: {
473
+ deck: Deck;
474
+ selected: boolean;
475
+ onSelect: () => void;
476
+ starredLabel: string;
302
477
  }) {
303
478
  return (
304
479
  <button
305
480
  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"
481
+ onClick={onSelect}
482
+ className={cn(
483
+ "flex w-full items-center gap-3 rounded-lg border px-3 py-3 text-start transition-colors",
484
+ selected
485
+ ? "border-primary/50 bg-primary/5"
486
+ : "border-border/70 bg-background hover:border-foreground/20 hover:bg-accent/35",
487
+ )}
308
488
  >
309
489
  <span className="flex size-8 shrink-0 items-center justify-center rounded-md bg-accent text-muted-foreground">
310
- {icon}
490
+ {deck.starred ? (
491
+ <IconStar className="size-4" />
492
+ ) : (
493
+ <IconPresentation className="size-4" />
494
+ )}
311
495
  </span>
312
- <span className="min-w-0">
313
- <span className="block truncate text-sm font-medium">{label}</span>
496
+ <span className="min-w-0 flex-1">
497
+ <span className="block truncate text-sm font-medium text-foreground">
498
+ {deck.title}
499
+ </span>
314
500
  <span className="block truncate text-xs text-muted-foreground">
315
- {meta}
501
+ {deck.starred ? starredLabel : ""}
316
502
  </span>
317
503
  </span>
318
- <IconArrowRight className="ms-auto size-4 shrink-0 text-muted-foreground" />
504
+ {selected ? (
505
+ <IconCheck className="size-4 shrink-0 text-primary" />
506
+ ) : (
507
+ <IconArrowRight className="size-4 shrink-0 text-muted-foreground" />
508
+ )}
319
509
  </button>
320
510
  );
321
511
  }