@agent-native/core 0.141.7 → 0.144.0
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/agent-native.eject.json +9 -0
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/provider-api/SKILL.md +19 -0
- package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/analytics/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/analytics/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/analytics/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/analytics/AGENTS.md +35 -38
- package/corpus/templates/analytics/actions/ensure-native-v2-dashboards.ts +1 -1
- package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +17 -22
- package/corpus/templates/analytics/actions/navigate.ts +4 -5
- package/corpus/templates/analytics/actions/provider-api-register.ts +50 -0
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +44 -11
- package/corpus/templates/analytics/actions/test-custom-api-connection.ts +106 -0
- package/corpus/templates/analytics/app/components/CustomApiCard.tsx +430 -0
- package/corpus/templates/analytics/app/i18n-data.ts +680 -0
- package/corpus/templates/analytics/app/lib/native-mcp-exclusions.ts +6 -0
- package/corpus/templates/analytics/app/lib/sql-query.ts +33 -6
- package/corpus/templates/analytics/app/pages/DataSources.tsx +4 -0
- package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-load-reliably-during-background-data-sw.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-remain-responsive-while-historical-data.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-analytics-query-results-now-render-as-a-table-with-csv-downl.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-connect-public-https-custom-apis-and-hand-tested-endpoints-t.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-durable-agent-worker-memory.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-live-dashboard-panels-use-the-shared-query-timeout.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-on-demand-billing-is-available-as-a-native-dashboard-with-ta.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-06-visible-dashboard-names-are-unique.md +6 -0
- package/corpus/templates/analytics/netlify.toml +7 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +4 -0
- package/corpus/templates/analytics/server/db/index.ts +27 -0
- package/corpus/templates/analytics/server/db/schema.ts +10 -0
- package/corpus/templates/analytics/server/lib/dashboards-store.ts +227 -60
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +133 -44
- package/corpus/templates/analytics/server/lib/native-v2-dashboards.ts +227 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +5 -0
- package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +1 -0
- package/corpus/templates/analytics/server/plugins/db.ts +52 -18
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +28 -2
- package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +16 -1
- package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/assets/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/assets/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/assets/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/brain/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/brain/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/brain/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/brain/actions/list-connection-providers.ts +24 -3
- package/corpus/templates/brain/app/lib/dispatch-links.ts +44 -0
- package/corpus/templates/brain/app/routes/sources.tsx +15 -7
- package/corpus/templates/brain/changelog/2026-08-06-brain-provider-setup-links-open-dispatch-correctly-in-standa.md +6 -0
- package/corpus/templates/brain/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +26 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/calendar/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/calendar/AGENTS.md +11 -32
- package/corpus/templates/calendar/actions/update-event.ts +107 -1
- package/corpus/templates/calendar/app/components/calendar/EventCalendarSelect.tsx +83 -0
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +57 -0
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +59 -73
- package/corpus/templates/calendar/app/hooks/use-events.ts +4 -1
- package/corpus/templates/calendar/app/i18n-data.ts +20 -0
- package/corpus/templates/calendar/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
- package/corpus/templates/calendar/changelog/2026-08-06-existing-events-can-move-between-connected-google-account-ca.md +6 -0
- package/corpus/templates/calendar/server/lib/google-calendar.ts +101 -0
- package/corpus/templates/calendar/server/plugins/agent-chat.ts +7 -1
- package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/clips/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/clips/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/clips/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/clips/app/components/editor/editor-layout.tsx +9 -24
- package/corpus/templates/clips/app/components/editor/timeline-geometry.ts +15 -0
- package/corpus/templates/clips/app/components/editor/waveform.tsx +4 -17
- package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +14 -3
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +28 -38
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +21 -27
- package/corpus/templates/clips/changelog/2026-08-06-clips-recovers-from-stalled-recording-setup-without-requirin.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-06-clips-starts-faster-after-a-deploy-or-idle-period-startup-no.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-06-deleting-a-recording-returns-cleanly-to-the-library-and-fit-.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-06-hide-clip-insights-from-viewers-without-analytics-access.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +48 -20
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +275 -74
- package/corpus/templates/clips/desktop/src/lib/recording-start-guard.ts +84 -0
- package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +14 -4
- package/corpus/templates/clips/server/plugins/db.ts +214 -26
- package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/content/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/content/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/content/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/crm/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/crm/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/crm/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/crm/changelog/2026-08-06-crm-starts-faster-after-a-deploy-or-idle-period-one-time-dat.md +6 -0
- package/corpus/templates/crm/server/plugins/db.ts +11 -8
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +36 -1
- package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/design/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/design/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/design/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/design/actions/import-from-url.ts +1 -1
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +27 -18
- package/corpus/templates/design/app/pages/Index.tsx +6 -2
- package/corpus/templates/design/changelog/2026-08-05-deleting-a-design-from-the-home-page-no-longer-leaves-the-ap.md +6 -0
- package/corpus/templates/design/changelog/2026-08-05-renaming-a-layer-now-focuses-its-name-field-automatically.md +6 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/dispatch/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/dispatch/changelog/2026-08-06-ready-workspace-apps-stay-one-click-away-in-a-compact-dispat.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-08-06-shared-vault-values-and-management-are-now-restricted-to-wor.md +6 -0
- package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/factory/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/factory/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/factory/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/forms/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/forms/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/forms/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/forms/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
- package/corpus/templates/forms/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/macros/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/macros/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/macros/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/mail/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/mail/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/mail/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/mail/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
- package/corpus/templates/mail/server/plugins/agent-chat.ts +6 -0
- package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/plan/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/plan/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/plan/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +48 -5
- package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +37 -1
- package/corpus/templates/slides/.agents/skills/image-generation-via-a2a/SKILL.md +6 -0
- package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +15 -2
- package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +29 -24
- package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/slides/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/slides/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/slides/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/slides/AGENTS.md +7 -9
- package/corpus/templates/slides/_gitignore +1 -0
- package/corpus/templates/slides/actions/export-pptx.ts +402 -36
- package/corpus/templates/slides/actions/import-file.ts +46 -85
- package/corpus/templates/slides/actions/import-google-slides-reference.ts +271 -12
- package/corpus/templates/slides/actions/import-pptx.ts +85 -60
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +10 -13
- package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +5 -1
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +25 -12
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +112 -57
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +202 -0
- package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +26 -14
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +173 -0
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +182 -141
- package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +1 -0
- package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +18 -0
- package/corpus/templates/slides/app/components/editor/slide-text-targets.ts +85 -0
- package/corpus/templates/slides/app/components/layout/Layout.tsx +3 -0
- package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +4 -0
- package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +27 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +1 -1
- package/corpus/templates/slides/app/lib/deck-preview-frame.ts +15 -0
- package/corpus/templates/slides/app/lib/deck-share-links.ts +9 -0
- package/corpus/templates/slides/app/lib/export-pptx-client.ts +89 -0
- package/corpus/templates/slides/app/lib/slide-animation-elements.ts +3 -0
- package/corpus/templates/slides/app/pages/Index.tsx +91 -1
- package/corpus/templates/slides/changelog/2026-08-06-clicking-the-gray-canvas-around-a-slide-clears-its-selection.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-deck-thumbnails-keep-a-consistent-listing-frame-across-aspec.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-deep-linked-decks-open-directly-instead-of-being-interrupted.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-google-slides-exports-now-show-clear-import-steps-when-direc.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-import-pdf-google-slides-and-powerpoint-decks-directly-from-.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-imported-powerpoint-exports-keep-text-and-images-editable-an.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-presentation-prompts-continue-adding-rendered-slides-until-t.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-public-decks-now-share-read-only-presentation-links-by-defau.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-slides-offers-a-direct-connect-google-button-when-a-drive-co.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-slides-preserve-uploaded-pdf-layouts-accept-larger-reference.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-06-styled-words-stay-part-of-their-text-box-instead-of-becoming.md +6 -0
- package/corpus/templates/slides/server/handlers/google-docs-auth.ts +7 -20
- package/corpus/templates/slides/server/handlers/import/html-converter.ts +236 -13
- package/corpus/templates/slides/server/handlers/import/pptx-assets.ts +67 -0
- package/corpus/templates/slides/server/handlers/import/pptx-parser.ts +2 -0
- package/corpus/templates/slides/server/handlers/uploads.ts +7 -3
- package/corpus/templates/slides/server/lib/chat-attachments.ts +6 -3
- package/corpus/templates/slides/server/lib/emails.ts +7 -2
- package/corpus/templates/slides/server/lib/google-docs-error.ts +50 -0
- package/corpus/templates/slides/server/lib/google-docs-oauth.ts +1 -0
- package/corpus/templates/slides/server/lib/import-asset-storage.ts +127 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -3
- package/corpus/templates/slides/server/routes/api/import-assets/[token].get.ts +70 -0
- package/corpus/templates/slides/shared/upload-types.ts +3 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/dist/agent/production-agent.d.ts +17 -0
- package/dist/agent/production-agent.js +72 -1
- package/dist/cli/agent-plugin.d.ts +112 -0
- package/dist/cli/agent-plugin.js +1081 -0
- package/dist/cli/app-skill.js +39 -1
- package/dist/cli/code-agent-executor.d.ts +3 -0
- package/dist/cli/code-agent-executor.js +51 -13
- package/dist/cli/index.js +13 -0
- package/dist/cli/templates-meta.js +1 -1
- package/dist/client/AgentPanel.d.ts +3 -1
- package/dist/client/AgentPanel.js +9 -2
- package/dist/client/AssistantChat.d.ts +8 -0
- package/dist/client/AssistantChat.js +23 -8
- package/dist/client/NewWorkspaceAppFlow.js +1 -0
- package/dist/client/agent-chat-adapter.js +123 -4
- package/dist/client/assistant-ui-recovery.d.ts +2 -1
- package/dist/client/assistant-ui-recovery.js +7 -3
- package/dist/client/onboarding/FirstRunOnboarding.js +11 -4
- package/dist/client/org/TeamPage.js +1 -1
- package/dist/client/require-session.js +1 -1
- package/dist/client/resources/McpConnectionSuggestion.d.ts +1 -0
- package/dist/client/resources/McpConnectionSuggestion.js +27 -10
- package/dist/client/resources/McpIntegrationDialog.js +77 -45
- package/dist/client/resources/mcp-integration-catalog.d.ts +13 -1
- package/dist/client/resources/mcp-integration-catalog.js +255 -2
- package/dist/client/resources/mcp-integration-logos.js +18 -2
- package/dist/client/settings/AccountSettingsCard.js +2 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.d.ts +9 -0
- package/dist/db/client.js +51 -16
- package/dist/db/create-get-db.js +2 -2
- package/dist/db/ddl-guard.d.ts +11 -10
- package/dist/db/ddl-guard.js +40 -12
- package/dist/deploy/build.d.ts +2 -0
- package/dist/deploy/build.js +97 -4
- package/dist/deploy/workspace-deploy.js +0 -2
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/guards/no-env-credentials.js +9 -0
- package/dist/ingestion/index.d.ts +1 -1
- package/dist/ingestion/pptx.d.ts +68 -0
- package/dist/ingestion/pptx.js +660 -213
- package/dist/integrations/plugin.js +9 -6
- package/dist/localization/default-messages.d.ts +54 -0
- package/dist/localization/default-messages.js +57 -2
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/mcp-client/oauth-routes.d.ts +2 -0
- package/dist/mcp-client/oauth-routes.js +73 -6
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/onboarding/app-profile.js +11 -0
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/resources/store.js +15 -1
- package/dist/scripts/call-agent.js +34 -4
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat/action-filters-a2a.d.ts +1 -1
- package/dist/server/agent-chat/action-filters-a2a.js +36 -1
- package/dist/server/agent-chat-plugin.js +29 -8
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.js +47 -11
- package/dist/server/better-auth-instance.js +5 -3
- package/dist/server/core-routes-plugin.d.ts +8 -1
- package/dist/server/core-routes-plugin.js +28 -3
- package/dist/server/credential-provider.d.ts +3 -3
- package/dist/server/credential-provider.js +90 -4
- package/dist/server/onboarding-html.d.ts +2 -0
- package/dist/server/onboarding-html.js +115 -29
- package/dist/server/self-dispatch.d.ts +5 -4
- package/dist/server/self-dispatch.js +25 -14
- package/dist/server/ssr-handler.d.ts +1 -1
- package/dist/server/ssr-handler.js +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/cache-control.d.ts +26 -2
- package/dist/shared/cache-control.js +43 -2
- package/dist/shared/password-policy.d.ts +3 -0
- package/dist/shared/password-policy.js +3 -0
- package/dist/sharing/actions/set-resource-visibility.js +16 -4
- package/dist/sharing/registry.d.ts +14 -0
- package/dist/styles/agent-native.css +6 -0
- package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/dist/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/dist/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/dist/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/dist/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/dist/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/dist/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/dist/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/dist/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/dist/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/dist/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
- package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/dist/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/dist/templates/workspace-root/AGENTS.md +7 -0
- package/dist/user-profile/actions/change-password.js +8 -3
- package/dist/user-profile/actions/set-password.js +5 -1
- package/dist/vite/action-types-plugin.js +59 -0
- package/docs/content/skills-guide.mdx +13 -0
- package/package.json +6 -2
- package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/src/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/src/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/src/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/src/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/src/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/src/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/src/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/src/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/src/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/src/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
- package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/src/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/src/templates/workspace-root/AGENTS.md +7 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import { writeAppState } from "@agent-native/core/application-state";
|
|
3
|
-
import { uploadFile } from "@agent-native/core/file-upload";
|
|
4
3
|
import {
|
|
5
4
|
getRequestUserEmail,
|
|
6
5
|
getRequestOrgId,
|
|
@@ -13,51 +12,70 @@ import { z } from "zod";
|
|
|
13
12
|
import { getDb, schema } from "../server/db/index.js";
|
|
14
13
|
import { notifyClients } from "../server/handlers/decks.js";
|
|
15
14
|
import { convertToSlideHtml } from "../server/handlers/import/html-converter.js";
|
|
15
|
+
import { uploadPptxSlideImages } from "../server/handlers/import/pptx-assets.js";
|
|
16
16
|
import {
|
|
17
17
|
parsePptx,
|
|
18
|
-
type
|
|
18
|
+
type ParsedElement,
|
|
19
|
+
type ParsedImage,
|
|
20
|
+
type ParsedPresentation,
|
|
19
21
|
} from "../server/handlers/import/pptx-parser.js";
|
|
20
22
|
import { getDeckUrl } from "./_app-url.js";
|
|
21
23
|
import { readUserUploadedFile } from "./_uploaded-files.js";
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
):
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
25
|
+
export interface ImportedImageFallback {
|
|
26
|
+
slideIndex: number;
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
width: number;
|
|
30
|
+
height: number;
|
|
31
|
+
data: Uint8Array;
|
|
32
|
+
mimeType: string;
|
|
33
|
+
name: string;
|
|
34
|
+
crop?: ParsedImage["crop"];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Add source-native image objects that a Google Slides PPTX export omitted. */
|
|
38
|
+
export function applyImageFallbacks(
|
|
39
|
+
presentation: Awaited<ReturnType<typeof parsePptx>>,
|
|
40
|
+
fallbacks: ImportedImageFallback[] = [],
|
|
41
|
+
): number {
|
|
42
|
+
let added = 0;
|
|
43
|
+
for (const [fallbackIndex, fallback] of fallbacks.entries()) {
|
|
44
|
+
const slide = presentation.slides[fallback.slideIndex];
|
|
45
|
+
if (!slide || fallback.width <= 0 || fallback.height <= 0) continue;
|
|
46
|
+
|
|
47
|
+
const duplicate = slide.elements.some(
|
|
48
|
+
(element) =>
|
|
49
|
+
element.kind === "image" &&
|
|
50
|
+
Math.abs(element.x - fallback.x) < 1000 &&
|
|
51
|
+
Math.abs(element.y - fallback.y) < 1000 &&
|
|
52
|
+
Math.abs(element.width - fallback.width) < 1000 &&
|
|
53
|
+
Math.abs(element.height - fallback.height) < 1000,
|
|
54
|
+
);
|
|
55
|
+
if (duplicate) continue;
|
|
56
|
+
|
|
57
|
+
const image: ParsedImage = {
|
|
58
|
+
data: fallback.data,
|
|
59
|
+
mimeType: fallback.mimeType,
|
|
60
|
+
name: fallback.name,
|
|
61
|
+
aspectRatio: fallback.width / fallback.height,
|
|
62
|
+
...(fallback.crop ? { crop: fallback.crop } : {}),
|
|
63
|
+
};
|
|
64
|
+
const element: ParsedElement = {
|
|
65
|
+
id: `image-fallback-${fallback.slideIndex}-${fallbackIndex}`,
|
|
66
|
+
name: fallback.name,
|
|
67
|
+
kind: "image",
|
|
68
|
+
x: fallback.x,
|
|
69
|
+
y: fallback.y,
|
|
70
|
+
width: fallback.width,
|
|
71
|
+
height: fallback.height,
|
|
72
|
+
image,
|
|
73
|
+
};
|
|
74
|
+
slide.images.push(image);
|
|
75
|
+
slide.elements.push(element);
|
|
76
|
+
added++;
|
|
60
77
|
}
|
|
78
|
+
return added;
|
|
61
79
|
}
|
|
62
80
|
|
|
63
81
|
export async function importPptxBufferToDeck(args: {
|
|
@@ -65,6 +83,8 @@ export async function importPptxBufferToDeck(args: {
|
|
|
65
83
|
title?: string;
|
|
66
84
|
deckId?: string;
|
|
67
85
|
source?: string;
|
|
86
|
+
imageFallbacks?: ImportedImageFallback[];
|
|
87
|
+
parsedPresentation?: ParsedPresentation;
|
|
68
88
|
}): Promise<{
|
|
69
89
|
id: string;
|
|
70
90
|
title: string;
|
|
@@ -74,8 +94,16 @@ export async function importPptxBufferToDeck(args: {
|
|
|
74
94
|
url: string;
|
|
75
95
|
imagesSkipped?: number;
|
|
76
96
|
}> {
|
|
77
|
-
const {
|
|
78
|
-
|
|
97
|
+
const {
|
|
98
|
+
fileBuffer,
|
|
99
|
+
title,
|
|
100
|
+
deckId,
|
|
101
|
+
source = "import-pptx",
|
|
102
|
+
imageFallbacks,
|
|
103
|
+
parsedPresentation,
|
|
104
|
+
} = args;
|
|
105
|
+
const presentation = parsedPresentation ?? (await parsePptx(fileBuffer));
|
|
106
|
+
applyImageFallbacks(presentation, imageFallbacks);
|
|
79
107
|
const deckTitle = title || presentation.title || "Imported Presentation";
|
|
80
108
|
const ownerEmail = getRequestUserEmail();
|
|
81
109
|
if (!ownerEmail) throw new Error("no authenticated user");
|
|
@@ -88,38 +116,35 @@ export async function importPptxBufferToDeck(args: {
|
|
|
88
116
|
await assertAccess("deck", deckId, "editor");
|
|
89
117
|
}
|
|
90
118
|
|
|
91
|
-
// Convert each parsed slide to
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
// one outbound upload per slide at once. An image can end up unused
|
|
95
|
-
// (unsupported format, or upload storage not configured) without
|
|
96
|
-
// failing the whole import — the slide's text still imports fine — but
|
|
97
|
-
// that shouldn't be a silent, invisible degradation, so it's counted
|
|
98
|
-
// and returned to the caller.
|
|
119
|
+
// Convert each parsed slide to its positioned scene graph, uploading every
|
|
120
|
+
// browser-renderable image so the imported deck keeps the source layering
|
|
121
|
+
// and media instead of collapsing to a one-image approximation.
|
|
99
122
|
const uploadLimit = pLimit(4);
|
|
100
123
|
const results = await Promise.all(
|
|
101
124
|
presentation.slides.map((parsedSlide, i) =>
|
|
102
125
|
uploadLimit(async () => {
|
|
103
|
-
const
|
|
104
|
-
parsedSlide,
|
|
105
|
-
i,
|
|
126
|
+
const uploadedImages = await uploadPptxSlideImages({
|
|
127
|
+
slide: parsedSlide,
|
|
128
|
+
slideIndex: i,
|
|
106
129
|
ownerEmail,
|
|
130
|
+
});
|
|
131
|
+
const html = convertToSlideHtml(
|
|
132
|
+
parsedSlide,
|
|
133
|
+
uploadedImages.urls,
|
|
134
|
+
themeFont,
|
|
107
135
|
);
|
|
108
|
-
const html = convertToSlideHtml(parsedSlide, imageUrl, themeFont);
|
|
109
136
|
return {
|
|
110
137
|
slide: {
|
|
111
138
|
id: `slide-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
|
112
139
|
content: html,
|
|
113
140
|
layout: parsedSlide.layoutHint ?? "content",
|
|
114
141
|
notes: parsedSlide.notes,
|
|
142
|
+
...(parsedSlide.transition
|
|
143
|
+
? { transition: parsedSlide.transition }
|
|
144
|
+
: {}),
|
|
145
|
+
...(parsedSlide.splitByParagraph ? { splitByParagraph: true } : {}),
|
|
115
146
|
},
|
|
116
|
-
|
|
117
|
-
// other image on that slide is unconditionally dropped too —
|
|
118
|
-
// not just the first one when it's unsupported.
|
|
119
|
-
imageSkippedCount: Math.max(
|
|
120
|
-
0,
|
|
121
|
-
parsedSlide.images.length - (imageUrl ? 1 : 0),
|
|
122
|
-
),
|
|
147
|
+
imageSkippedCount: uploadedImages.imageSkippedCount,
|
|
123
148
|
};
|
|
124
149
|
}),
|
|
125
150
|
),
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
DropdownMenuSeparator,
|
|
24
24
|
} from "@/components/ui/dropdown-menu";
|
|
25
25
|
import type { Deck } from "@/context/DeckContext";
|
|
26
|
-
import {
|
|
26
|
+
import { getDeckListingPreviewFrameStyle } from "@/lib/deck-preview-frame";
|
|
27
27
|
|
|
28
28
|
import SlideRenderer from "./SlideRenderer";
|
|
29
29
|
|
|
@@ -52,7 +52,7 @@ export default function DeckCard({
|
|
|
52
52
|
}: DeckCardProps) {
|
|
53
53
|
const t = useT();
|
|
54
54
|
const firstSlide = deck.slides?.[0];
|
|
55
|
-
const
|
|
55
|
+
const previewFrameStyle = getDeckListingPreviewFrameStyle(deck.aspectRatio);
|
|
56
56
|
const [isRenaming, setIsRenaming] = useState(false);
|
|
57
57
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
58
58
|
const [renameValue, setRenameValue] = useState(deck.title);
|
|
@@ -106,18 +106,15 @@ export default function DeckCard({
|
|
|
106
106
|
}}
|
|
107
107
|
>
|
|
108
108
|
{/* Slide Preview */}
|
|
109
|
-
<div
|
|
110
|
-
className="relative overflow-hidden bg-muted/30"
|
|
111
|
-
style={{
|
|
112
|
-
aspectRatio: `${previewDims.width} / ${previewDims.height}`,
|
|
113
|
-
}}
|
|
114
|
-
>
|
|
109
|
+
<div className="relative flex aspect-video items-center justify-center overflow-hidden bg-muted/30">
|
|
115
110
|
{firstSlide && (
|
|
116
|
-
<
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
111
|
+
<div className="relative overflow-hidden" style={previewFrameStyle}>
|
|
112
|
+
<SlideRenderer
|
|
113
|
+
slide={firstSlide}
|
|
114
|
+
className="rounded-none"
|
|
115
|
+
aspectRatio={deck.aspectRatio}
|
|
116
|
+
/>
|
|
117
|
+
</div>
|
|
121
118
|
)}
|
|
122
119
|
<div className="pointer-events-none absolute inset-0 bg-gradient-to-t from-[hsl(240,5%,8%)] via-transparent to-transparent opacity-60" />
|
|
123
120
|
</div>
|
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
} from "@/components/editor/PromptDialog";
|
|
14
14
|
import { addSlideAgentMessage } from "@/lib/agent-visible-message";
|
|
15
15
|
|
|
16
|
+
import { MAX_REFERENCE_FILE_BYTES } from "../../../shared/upload-types";
|
|
17
|
+
|
|
16
18
|
const MAX_SOURCE_CONTEXT_CHARS = 60_000;
|
|
17
19
|
|
|
18
20
|
function truncateSourceForContext(prompt: string): {
|
|
@@ -46,7 +48,7 @@ function describeUploadedFilesForAgent(
|
|
|
46
48
|
"",
|
|
47
49
|
"File handling rules:",
|
|
48
50
|
`- PPTX files: call \`import-pptx --filePath "<path>" --deckId ${deckId}\` when the user wants the deck/slides imported, or to extract slide source from a presentation.`,
|
|
49
|
-
`- PDF and DOCX files: call \`import-file --filePath "<path>" --format auto --deckId ${deckId}\` and use the returned extracted text as source material.
|
|
51
|
+
`- PDF and DOCX files: call \`import-file --filePath "<path>" --format auto --deckId ${deckId}\` and use the returned extracted text as source material. For a visual PDF whose original layout should be preserved, pass \`--importIntoDeck true\` instead of rebuilding the pages from extracted text.`,
|
|
50
52
|
"- Text-like files: use the uploaded-text-file blocks already included in the prompt; do not call import-file for them.",
|
|
51
53
|
'- Image files with an embeddable URL can be inserted directly into slide HTML as `<img src="...">` or used as visual references.',
|
|
52
54
|
"- Image files without a URL are visual/reference assets only; do not claim to have processed a PPTX/PDF/DOCX unless the relevant import action succeeds.",
|
|
@@ -241,6 +243,8 @@ export function AddSlidePopover({
|
|
|
241
243
|
)}
|
|
242
244
|
<PromptComposer
|
|
243
245
|
autoFocus
|
|
246
|
+
maxDocumentAttachmentBytes={MAX_REFERENCE_FILE_BYTES}
|
|
247
|
+
documentAttachmentLimitLabel="Slides reference files"
|
|
244
248
|
placeholder={t("editorSidebar.promptPlaceholder")}
|
|
245
249
|
draftScope={`slides:add-slide:${deckId}`}
|
|
246
250
|
onSubmit={handleSubmit}
|
|
@@ -67,6 +67,7 @@ import {
|
|
|
67
67
|
type AspectRatio,
|
|
68
68
|
DEFAULT_ASPECT_RATIO,
|
|
69
69
|
} from "@/lib/aspect-ratios";
|
|
70
|
+
import { getDeckShareLinkOrder } from "@/lib/deck-share-links";
|
|
70
71
|
import type { GoogleSlidesExportResult } from "@/lib/export-google-slides-client";
|
|
71
72
|
import { parseUploadResponse } from "@/lib/upload-response";
|
|
72
73
|
import { shortcutLabel } from "@/lib/utils";
|
|
@@ -288,10 +289,9 @@ export default function EditorToolbar({
|
|
|
288
289
|
canEdit = true,
|
|
289
290
|
}: EditorToolbarProps) {
|
|
290
291
|
const t = useT();
|
|
291
|
-
//
|
|
292
|
-
//
|
|
293
|
-
//
|
|
294
|
-
// open either link.
|
|
292
|
+
// Public decks default to the read-only presentation URL so recipients do
|
|
293
|
+
// not get sent through the editor's auth gate. Restricted decks keep the
|
|
294
|
+
// editor URL primary, where auth resolves viewer access.
|
|
295
295
|
const editorUrl =
|
|
296
296
|
typeof window === "undefined"
|
|
297
297
|
? `/deck/${deckId}`
|
|
@@ -300,6 +300,21 @@ export default function EditorToolbar({
|
|
|
300
300
|
typeof window === "undefined"
|
|
301
301
|
? `/p/${deckId}`
|
|
302
302
|
: `${window.location.origin}${appPath(`/p/${deckId}`)}`;
|
|
303
|
+
const shareLinks = {
|
|
304
|
+
editor: {
|
|
305
|
+
url: editorUrl,
|
|
306
|
+
label: t("editorToolbar.editorLink"),
|
|
307
|
+
description: t("editorToolbar.editorLinkDescription"),
|
|
308
|
+
},
|
|
309
|
+
presentation: {
|
|
310
|
+
url: presentationUrl,
|
|
311
|
+
label: t("editorToolbar.presentationLink"),
|
|
312
|
+
description: t("editorToolbar.presentationLinkDescription"),
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
const shareLinkOrder = getDeckShareLinkOrder(deck.visibility);
|
|
316
|
+
const primaryShareLink = shareLinks[shareLinkOrder.primary];
|
|
317
|
+
const secondaryShareLink = shareLinks[shareLinkOrder.secondary];
|
|
303
318
|
|
|
304
319
|
// Live save state for the toolbar indicator, so users always see whether
|
|
305
320
|
// their work has committed (a lost-deck report motivated surfacing this).
|
|
@@ -940,14 +955,12 @@ graph TD
|
|
|
940
955
|
resourceType="deck"
|
|
941
956
|
resourceId={deckId}
|
|
942
957
|
resourceTitle={deckTitle}
|
|
943
|
-
shareUrl={
|
|
944
|
-
shareUrlLabel={
|
|
945
|
-
shareUrlDescription={
|
|
946
|
-
secondaryShareUrl={
|
|
947
|
-
secondaryShareUrlLabel={
|
|
948
|
-
secondaryShareUrlDescription={
|
|
949
|
-
"editorToolbar.presentationLinkDescription",
|
|
950
|
-
)}
|
|
958
|
+
shareUrl={primaryShareLink.url}
|
|
959
|
+
shareUrlLabel={primaryShareLink.label}
|
|
960
|
+
shareUrlDescription={primaryShareLink.description}
|
|
961
|
+
secondaryShareUrl={secondaryShareLink.url}
|
|
962
|
+
secondaryShareUrlLabel={secondaryShareLink.label}
|
|
963
|
+
secondaryShareUrlDescription={secondaryShareLink.description}
|
|
951
964
|
shareTabs={{
|
|
952
965
|
tabs: [
|
|
953
966
|
{
|
|
@@ -13,8 +13,18 @@ import {
|
|
|
13
13
|
IconBrandGoogle,
|
|
14
14
|
IconPlugConnected,
|
|
15
15
|
} from "@tabler/icons-react";
|
|
16
|
+
import { useRef, useState } from "react";
|
|
16
17
|
import { toast } from "sonner";
|
|
17
18
|
|
|
19
|
+
import { Button } from "@/components/ui/button";
|
|
20
|
+
import {
|
|
21
|
+
Dialog,
|
|
22
|
+
DialogContent,
|
|
23
|
+
DialogDescription,
|
|
24
|
+
DialogFooter,
|
|
25
|
+
DialogHeader,
|
|
26
|
+
DialogTitle,
|
|
27
|
+
} from "@/components/ui/dialog";
|
|
18
28
|
import {
|
|
19
29
|
DropdownMenu,
|
|
20
30
|
DropdownMenuContent,
|
|
@@ -51,6 +61,8 @@ export function ExportMenu({
|
|
|
51
61
|
onShareTeam,
|
|
52
62
|
}: ExportMenuProps) {
|
|
53
63
|
const t = useT();
|
|
64
|
+
const [googleSlidesImportOpen, setGoogleSlidesImportOpen] = useState(false);
|
|
65
|
+
const googleSlidesImportTarget = useRef<Window | null>(null);
|
|
54
66
|
const triggerBlobDownload = (blob: Blob, filename: string) => {
|
|
55
67
|
const url = URL.createObjectURL(blob);
|
|
56
68
|
const a = document.createElement("a");
|
|
@@ -100,9 +112,11 @@ export function ExportMenu({
|
|
|
100
112
|
// Opened up-front: browsers only honour window.open() inside the click
|
|
101
113
|
// gesture, and building the PPTX is async.
|
|
102
114
|
const target = window.open("", "_blank");
|
|
115
|
+
googleSlidesImportTarget.current = target;
|
|
103
116
|
try {
|
|
104
117
|
const result = await onExportGoogleSlides();
|
|
105
118
|
if (result.url !== null) {
|
|
119
|
+
googleSlidesImportTarget.current = null;
|
|
106
120
|
if (target) target.location.href = result.url;
|
|
107
121
|
toast.success(t("editorExport.googleSlidesCreated"), {
|
|
108
122
|
description: t("editorExport.googleSlidesCreatedHint"),
|
|
@@ -111,10 +125,12 @@ export function ExportMenu({
|
|
|
111
125
|
}
|
|
112
126
|
console.warn("Google Slides upload unavailable:", result.reason);
|
|
113
127
|
if (target) target.location.href = GOOGLE_SLIDES_IMPORT_URL;
|
|
128
|
+
setGoogleSlidesImportOpen(true);
|
|
114
129
|
toast.success(t("editorExport.googleSlidesDownloaded"), {
|
|
115
130
|
description: t("editorExport.googleSlidesImportHint"),
|
|
116
131
|
});
|
|
117
132
|
} catch (err) {
|
|
133
|
+
googleSlidesImportTarget.current = null;
|
|
118
134
|
target?.close();
|
|
119
135
|
console.error("Export failed:", err);
|
|
120
136
|
toast.error(t("editorExport.exportFailed"), {
|
|
@@ -207,66 +223,105 @@ export function ExportMenu({
|
|
|
207
223
|
};
|
|
208
224
|
|
|
209
225
|
return (
|
|
210
|
-
|
|
211
|
-
<
|
|
212
|
-
<
|
|
213
|
-
<
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
<
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
<
|
|
224
|
-
|
|
226
|
+
<>
|
|
227
|
+
<DropdownMenu>
|
|
228
|
+
<DropdownMenuTrigger asChild>
|
|
229
|
+
<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">
|
|
230
|
+
<IconUpload className="w-3.5 h-3.5" />
|
|
231
|
+
<span className="hidden md:inline">{t("editorExport.export")}</span>
|
|
232
|
+
</button>
|
|
233
|
+
</DropdownMenuTrigger>
|
|
234
|
+
<DropdownMenuContent align="end" className="w-52">
|
|
235
|
+
<DropdownMenuLabel className="text-[11px] text-muted-foreground">
|
|
236
|
+
{t("editorExport.exportAndDuplicate")}
|
|
237
|
+
</DropdownMenuLabel>
|
|
238
|
+
{onShareTeam && (
|
|
239
|
+
<DropdownMenuItem onClick={onShareTeam} className="cursor-pointer">
|
|
240
|
+
<IconShare2 className="w-4 h-4 mr-2" />
|
|
241
|
+
{t("editorExport.shareWithTeam")}
|
|
242
|
+
</DropdownMenuItem>
|
|
243
|
+
)}
|
|
244
|
+
{onShareLink && (
|
|
245
|
+
<DropdownMenuItem onClick={onShareLink} className="cursor-pointer">
|
|
246
|
+
<IconShare2 className="w-4 h-4 mr-2" />
|
|
247
|
+
{t("editorExport.publicShareLink")}
|
|
248
|
+
</DropdownMenuItem>
|
|
249
|
+
)}
|
|
250
|
+
<DropdownMenuSeparator />
|
|
251
|
+
<DropdownMenuItem
|
|
252
|
+
onClick={handleExportHtml}
|
|
253
|
+
className="cursor-pointer"
|
|
254
|
+
>
|
|
255
|
+
<IconCode className="w-4 h-4 mr-2" />
|
|
256
|
+
{t("editorExport.downloadHtml")}
|
|
225
257
|
</DropdownMenuItem>
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
<IconShare2 className="w-4 h-4 mr-2" />
|
|
230
|
-
{t("editorExport.publicShareLink")}
|
|
258
|
+
<DropdownMenuItem onClick={onExportPdf} className="cursor-pointer">
|
|
259
|
+
<IconFileTypePdf className="w-4 h-4 mr-2" />
|
|
260
|
+
{t("editorExport.exportPdf")}
|
|
231
261
|
</DropdownMenuItem>
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
262
|
+
<DropdownMenuItem
|
|
263
|
+
onClick={handleExportPptx}
|
|
264
|
+
className="cursor-pointer"
|
|
265
|
+
>
|
|
266
|
+
<IconDownload className="w-4 h-4 mr-2" />
|
|
267
|
+
{t("editorExport.exportPptx")}
|
|
268
|
+
</DropdownMenuItem>
|
|
269
|
+
{onExportGoogleSlides && (
|
|
270
|
+
<>
|
|
271
|
+
<DropdownMenuItem
|
|
272
|
+
onClick={handleConnectGoogle}
|
|
273
|
+
className="cursor-pointer"
|
|
274
|
+
>
|
|
275
|
+
<IconPlugConnected className="w-4 h-4 mr-2" />
|
|
276
|
+
{t("editorExport.connectGoogle")}
|
|
277
|
+
</DropdownMenuItem>
|
|
278
|
+
<DropdownMenuItem
|
|
279
|
+
onClick={handleExportGoogleSlides}
|
|
280
|
+
className="cursor-pointer"
|
|
281
|
+
>
|
|
282
|
+
<IconBrandGoogle className="w-4 h-4 mr-2" />
|
|
283
|
+
{t("editorExport.openInGoogleSlides")}
|
|
284
|
+
</DropdownMenuItem>
|
|
285
|
+
</>
|
|
286
|
+
)}
|
|
287
|
+
<DropdownMenuSeparator />
|
|
288
|
+
<DropdownMenuItem onClick={onDuplicate} className="cursor-pointer">
|
|
289
|
+
<IconCopy className="w-4 h-4 mr-2" />
|
|
290
|
+
{t("editorExport.duplicateDeck")}
|
|
291
|
+
</DropdownMenuItem>
|
|
292
|
+
</DropdownMenuContent>
|
|
293
|
+
</DropdownMenu>
|
|
294
|
+
<Dialog
|
|
295
|
+
open={googleSlidesImportOpen}
|
|
296
|
+
onOpenChange={setGoogleSlidesImportOpen}
|
|
297
|
+
>
|
|
298
|
+
<DialogContent>
|
|
299
|
+
<DialogHeader>
|
|
300
|
+
<DialogTitle>
|
|
301
|
+
{t("editorExport.googleSlidesDownloaded")}
|
|
302
|
+
</DialogTitle>
|
|
303
|
+
<DialogDescription>
|
|
304
|
+
{t("editorExport.googleSlidesImportHint")}
|
|
305
|
+
</DialogDescription>
|
|
306
|
+
</DialogHeader>
|
|
307
|
+
<DialogFooter>
|
|
308
|
+
<Button
|
|
309
|
+
type="button"
|
|
310
|
+
onClick={() => {
|
|
311
|
+
const target = googleSlidesImportTarget.current;
|
|
312
|
+
if (target && !target.closed) {
|
|
313
|
+
target.focus?.();
|
|
314
|
+
} else {
|
|
315
|
+
window.open(GOOGLE_SLIDES_IMPORT_URL, "_blank");
|
|
316
|
+
}
|
|
317
|
+
setGoogleSlidesImportOpen(false);
|
|
318
|
+
}}
|
|
258
319
|
>
|
|
259
|
-
<IconBrandGoogle className="w-4 h-4 mr-2" />
|
|
260
320
|
{t("editorExport.openInGoogleSlides")}
|
|
261
|
-
</
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
<IconCopy className="w-4 h-4 mr-2" />
|
|
267
|
-
{t("editorExport.duplicateDeck")}
|
|
268
|
-
</DropdownMenuItem>
|
|
269
|
-
</DropdownMenuContent>
|
|
270
|
-
</DropdownMenu>
|
|
321
|
+
</Button>
|
|
322
|
+
</DialogFooter>
|
|
323
|
+
</DialogContent>
|
|
324
|
+
</Dialog>
|
|
325
|
+
</>
|
|
271
326
|
);
|
|
272
327
|
}
|