@kortix/ui 0.14.4 → 0.14.6
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/README.md +8 -4
- package/dist/access/access/access-dialog.js +8 -5
- package/dist/access/access/copy-row.js +2 -2
- package/dist/access/sharing-picker.js +2 -1
- package/dist/browser/app-in-browser.js +5 -3
- package/dist/browser/browser-panel.js +6 -6
- package/dist/browser/sandbox-browser-chrome.d.ts +4 -1
- package/dist/browser/sandbox-browser-chrome.js +4 -3
- package/dist/customize/agents/agent-access.d.ts +20 -0
- package/dist/customize/agents/agent-access.js +17 -0
- package/dist/customize/agents/agent-grant-pages.js +5 -6
- package/dist/customize/agents/agent-page.js +2 -1
- package/dist/customize/agents/agents-page.js +18 -1
- package/dist/customize/connectors/add-mcp/add-mcp-server.js +4 -2
- package/dist/customize/connectors/connector-routes.d.ts +3 -1
- package/dist/customize/connectors/connector-routes.js +18 -0
- package/dist/customize/connectors/connectors-page.js +23 -4
- package/dist/customize/connectors/detail/connector-advanced-tools.js +4 -6
- package/dist/customize/providers/provider-accordion.js +2 -1
- package/dist/customize/providers/provider-connect.js +2 -1
- package/dist/customize/sections/component/telegram-channel-row.js +1 -1
- package/dist/customize/sections/connector-connection-modal.js +11 -9
- package/dist/customize/sections/connectors-view.js +11 -13
- package/dist/customize/sections/llm-provider/constants.d.ts +0 -1
- package/dist/customize/sections/llm-provider/constants.js +0 -2
- package/dist/customize/sections/llm-provider/models-tab-group.d.ts +1 -1
- package/dist/customize/sections/llm-provider/models-tab-group.js +7 -4
- package/dist/customize/sections/llm-provider/models-tab-row.d.ts +2 -18
- package/dist/customize/sections/llm-provider/models-tab-row.js +6 -30
- package/dist/customize/sections/llm-provider/models-tab.d.ts +0 -1
- package/dist/customize/sections/llm-provider/models-tab.js +1 -10
- package/dist/customize/sections/llm-provider/use-connected-providers.js +2 -2
- package/dist/customize/sections/llm-provider/utils.d.ts +1 -1
- package/dist/customize/sections/llm-provider/utils.js +7 -14
- package/dist/customize/sections/view/gateway/_shared.js +1 -2
- package/dist/customize/sections/view/gateway/gateway-routing.js +18 -20
- package/dist/customize/sections/view/sandbox-provider-coverage.d.ts +3 -18
- package/dist/customize/sections/view/sandbox-provider-coverage.js +7 -27
- package/dist/customize/settings/rail-copy-context.js +5 -3
- package/dist/customize/settings/tabs/sandbox-tab.d.ts +2 -27
- package/dist/customize/settings/tabs/sandbox-tab.js +13 -112
- package/dist/customize/settings/tabs/sandbox-template-form.js +9 -12
- package/dist/customize/shared/capability-tabs.js +2 -1
- package/dist/customize/shared/entity/entity-modal.d.ts +5 -1
- package/dist/customize/shared/entity/entity-modal.js +7 -4
- package/dist/customize/skills/remove-skill-button.d.ts +16 -0
- package/dist/customize/skills/remove-skill-button.js +42 -0
- package/dist/customize/skills/skills-page.js +4 -6
- package/dist/customize/triggers/schedule/event-trigger-copy.js +3 -2
- package/dist/customize/triggers/schedule/schedule-builder.js +7 -4
- package/dist/customize/triggers/schedule/trigger-composer.js +5 -2
- package/dist/customize/triggers/schedule/trigger-list.d.ts +0 -2
- package/dist/customize/triggers/schedule/trigger-list.js +1 -18
- package/dist/customize/triggers/schedule/trigger-tile.d.ts +1 -32
- package/dist/customize/triggers/schedule/trigger-tile.js +1 -16
- package/dist/customize/triggers/schedule/when-event.js +1 -1
- package/dist/diff/diff-view.js +9 -10
- package/dist/files/editor/code-editor.js +2 -3
- package/dist/files/project/components/change-request-detail-dialog.d.ts +3 -1
- package/dist/files/project/components/change-request-detail-dialog.js +3 -5
- package/dist/files/project/components/change-request-status-badge.d.ts +12 -0
- package/dist/files/project/components/change-request-status-badge.js +27 -0
- package/dist/files/project/components/change-requests-panel.js +1 -1
- package/dist/files/project/components/drive-explorer.js +2 -1
- package/dist/files/project/components/drive-grid-view.js +11 -7
- package/dist/files/project/components/drive-list-view.js +4 -4
- package/dist/files/project/components/file-breadcrumbs.js +1 -1
- package/dist/files/project/components/file-explorer-page.js +1 -1
- package/dist/files/project/components/file-history-popover.js +1 -6
- package/dist/files/project/components/file-search.js +6 -1
- package/dist/files/project/components/open-change-request-dialog.js +2 -1
- package/dist/files/project/components/version-selector-logic.d.ts +11 -0
- package/dist/files/project/components/version-selector-logic.js +26 -0
- package/dist/files/project/components/version-selector.js +11 -20
- package/dist/files/project/hooks/use-change-requests.d.ts +14 -1
- package/dist/files/project/hooks/use-change-requests.js +44 -25
- package/dist/files/project/hooks/use-server-health.js +17 -15
- package/dist/files/renderers/docx/docx-viewer.js +4 -6
- package/dist/files/renderers/image-renderer.js +6 -24
- package/dist/files/renderers/pdf/pdf-renderer.d.ts +3 -1
- package/dist/files/renderers/pdf/pdf-renderer.js +2 -2
- package/dist/files/renderers/pdf/pdf-viewer.d.ts +3 -0
- package/dist/files/renderers/pdf/pdf-viewer.js +16 -7
- package/dist/files/renderers/presentation/FullScreenPresentationViewer.js +2 -11
- package/dist/files/renderers/show-content-renderer.js +1 -1
- package/dist/files/renderers/sqlite-renderer.js +8 -3
- package/dist/files/renderers/xlsx/xlsx-viewer.js +15 -16
- package/dist/files/tree/components/file-tree-item.js +1 -1
- package/dist/files/viewer/file-content-renderer.d.ts +4 -1
- package/dist/files/viewer/file-content-renderer.js +2 -2
- package/dist/files/viewer/file-preview-modal.js +1 -1
- package/dist/files/viewer/use-file-content-state.js +1 -1
- package/dist/i18n/en.d.ts +36 -35
- package/dist/i18n/en.js +45 -44
- package/dist/index.d.ts +1 -1
- package/dist/internal/desktop/desktop-back-button.js +5 -3
- package/dist/internal/hooks/use-auto-scroll.js +5 -3
- package/dist/internal/hooks/use-notification-center.js +21 -15
- package/dist/internal/hooks/use-review-session-summary.d.ts +6 -0
- package/dist/internal/hooks/use-review-session-summary.js +11 -0
- package/dist/internal/lib/browser-error-noise.d.ts +1 -1
- package/dist/internal/lib/browser-error-noise.js +1 -1
- package/dist/internal/lib/browser-noise/rules/rejections.d.ts +10 -0
- package/dist/internal/lib/browser-noise/rules/rejections.js +27 -1
- package/dist/internal/lib/provider-branding.js +14 -3
- package/dist/internal/lib/trigger-clock.d.ts +42 -0
- package/dist/internal/lib/trigger-clock.js +34 -0
- package/dist/internal/lib/web-notifications.d.ts +6 -0
- package/dist/internal/lib/web-notifications.js +57 -7
- package/dist/internal/notifications/notification-bell.d.ts +13 -0
- package/dist/internal/notifications/notification-bell.js +1 -1
- package/dist/internal/notifications/notification-rows.js +2 -1
- package/dist/internal/outcomes/outcome-types.d.ts +5 -0
- package/dist/internal/reminders/reminder-filter.d.ts +12 -0
- package/dist/internal/reminders/reminder-filter.js +34 -0
- package/dist/internal/reminders/reminder-format.d.ts +6 -0
- package/dist/internal/reminders/reminder-format.js +20 -2
- package/dist/internal/stores/kortix-computer-store.d.ts +1 -1
- package/dist/internal/stores/session-hover-store.d.ts +20 -5
- package/dist/internal/stores/session-hover-store.js +31 -13
- package/dist/internal/stores/session-panel-memory-store.js +2 -0
- package/dist/markdown/code/inline-code.js +8 -0
- package/dist/markdown/code/output-paths-context.d.ts +18 -0
- package/dist/markdown/code/output-paths-context.js +35 -0
- package/dist/markdown/genui/components/charts.js +6 -5
- package/dist/primitives/count-badge.d.ts +3 -1
- package/dist/primitives/count-badge.js +3 -3
- package/dist/primitives/glyph-paths-source.js +1 -1
- package/dist/primitives/glyph-paths.generated.js +1 -1
- package/dist/primitives/map.js +2 -1
- package/dist/primitives/preview-image.js +4 -2
- package/dist/primitives/textarea.js +1 -1
- package/dist/primitives/typed-title.js +12 -14
- package/dist/primitives/typing-animation.js +4 -2
- package/dist/providers/ui-provider.d.ts +57 -0
- package/dist/providers/ui-provider.js +4 -0
- package/dist/session/composer/ComposerCard.d.ts +2 -0
- package/dist/session/composer/ComposerCard.js +5 -1
- package/dist/session/composer/agent-selector.js +17 -5
- package/dist/session/composer/composer-chat-input.js +5 -3
- package/dist/session/composer/composer-logic.js +8 -7
- package/dist/session/composer/composer-toolbar.js +4 -2
- package/dist/session/composer/composer-underbar.js +3 -1
- package/dist/session/composer/composer.js +34 -5
- package/dist/session/composer/draft/composer-draft.js +4 -4
- package/dist/session/composer/menus/slash-actions.d.ts +22 -2
- package/dist/session/composer/menus/slash-actions.js +20 -0
- package/dist/session/composer/menus/slash-items.js +19 -3
- package/dist/session/composer/pasted-text.js +3 -2
- package/dist/session/composer/stores/queued-draft-store.js +3 -2
- package/dist/session/header/reminder-parts.d.ts +294 -0
- package/dist/session/header/reminder-parts.js +120 -0
- package/dist/session/header/session-reminders-indicator.d.ts +13 -0
- package/dist/session/header/session-reminders-indicator.js +142 -35
- package/dist/session/media/sandbox-url-detector.js +0 -7
- package/dist/session/models/model-availability.d.ts +23 -0
- package/dist/session/models/model-availability.js +20 -0
- package/dist/session/models/model-grouping.js +1 -4
- package/dist/session/models/model-selector.js +23 -14
- package/dist/session/models/use-model-connection-gate.js +4 -1
- package/dist/session/outcomes/change-request-outcomes.js +24 -3
- package/dist/session/outcomes/session-outcomes-provider.d.ts +3 -1
- package/dist/session/outcomes/session-outcomes-provider.js +31 -3
- package/dist/session/overrides/provider-secret-pool-editor.js +2 -1
- package/dist/session/overrides/session-overrides-composer.d.ts +1 -1
- package/dist/session/overrides/session-overrides-composer.js +5 -1
- package/dist/session/panel/advanced/advanced-panel.js +3 -7
- package/dist/session/panel/easy/app-preview.js +12 -2
- package/dist/session/panel/easy/easy-panel-logic.d.ts +1 -1
- package/dist/session/panel/easy/easy-panel-logic.js +1 -1
- package/dist/session/panel/easy/outputs-card.js +2 -1
- package/dist/session/panel/easy/panel-card.js +5 -3
- package/dist/session/panel/easy/preview-load.d.ts +14 -0
- package/dist/session/panel/easy/preview-load.js +15 -0
- package/dist/session/panel/easy/step-detail-body.js +2 -7
- package/dist/session/panel/mobile-tool-drawer.js +4 -2
- package/dist/session/panel/open-session-quick-view.js +2 -1
- package/dist/session/panel/panel-fallback.js +8 -4
- package/dist/session/panel/session-panel-provider.d.ts +1 -0
- package/dist/session/panel/session-panel-provider.js +19 -3
- package/dist/session/panel/session-reminders-panel.d.ts +4 -0
- package/dist/session/panel/session-reminders-panel.js +109 -0
- package/dist/session/panel/shared/use-panel-derivations.js +6 -4
- package/dist/session/panel/shared/use-panel-handoffs.d.ts +2 -2
- package/dist/session/panel/shared/use-panel-handoffs.js +5 -1
- package/dist/session/panel/use-session-panel-layout.js +7 -5
- package/dist/session/print/session-print-header.d.ts +0 -10
- package/dist/session/print/session-print-header.js +25 -9
- package/dist/session/status/session-surface.js +1 -1
- package/dist/session/thread/optimistic-turn.d.ts +5 -1
- package/dist/session/thread/optimistic-turn.js +8 -6
- package/dist/session/thread/session-chat.d.ts +6 -1
- package/dist/session/thread/session-chat.js +34 -12
- package/dist/session/thread/session-history.js +3 -1
- package/dist/session/thread/session-thread.d.ts +10 -1
- package/dist/session/thread/session-thread.js +2 -2
- package/dist/session/thread/transcript.js +13 -7
- package/dist/session/tool/shared/file-list.js +19 -2
- package/dist/session/tool/shared/infrastructure-contexts.d.ts +7 -0
- package/dist/session/tool/shared/infrastructure-contexts.js +7 -0
- package/dist/session/tool/shared/infrastructure-output.js +9 -5
- package/dist/session/tool/shared/infrastructure-row-header.js +9 -1
- package/dist/session/tool/shared/infrastructure-rows.js +7 -5
- package/dist/session/tool/tools/bash-tool.js +10 -6
- package/dist/session/tool/tools/web-search-tool.js +25 -3
- package/dist/session/turn/burst-step-body.js +4 -0
- package/dist/session/turn/recovered-failures.d.ts +8 -0
- package/dist/session/turn/recovered-failures.js +32 -0
- package/dist/session/turn/streaming-cadence.js +5 -8
- package/dist/styles.css +1 -1
- package/dist/terminal/session-terminal-panel.js +3 -5
- package/dist/theme/theme.js +2 -1
- package/dist/workspace/projects/modal/github-import-pickers.js +7 -6
- package/dist/workspace/review/review-center.js +13 -10
- package/dist/workspace/session-workspace.js +5 -9
- package/dist/workspace/sessions/deleted-session-row.js +5 -2
- package/dist/workspace/sidebar/footer/project-computer-nav.js +6 -4
- package/dist/workspace/sidebar/footer/project-mcp-nav.js +6 -2
- package/dist/workspace/sidebar/modal/rename-session-modal.js +8 -3
- package/dist/workspace/sidebar/project-session-list.js +52 -55
- package/dist/workspace/sidebar/session-brief-hover-card.d.ts +35 -18
- package/dist/workspace/sidebar/session-brief-hover-card.js +114 -37
- package/dist/workspace/sidebar/session-status-mark.d.ts +15 -1
- package/dist/workspace/sidebar/session-status-mark.js +63 -17
- package/package.json +7 -3
- package/skills/kortix-ui/SKILL.md +1 -1
- package/dist/customize/sections/view/sandbox-provider-result.d.ts +0 -47
- package/dist/customize/sections/view/sandbox-provider-result.js +0 -79
|
@@ -13,6 +13,7 @@ import { useMemo, useState } from 'react';
|
|
|
13
13
|
import { useProjectContext } from '../context.js';
|
|
14
14
|
import { useBranches } from '../hooks/use-branches.js';
|
|
15
15
|
import { useVersionStore } from '../store/version-store.js';
|
|
16
|
+
import { groupVersions, versionMatches, versionTitle } from './version-selector-logic.js';
|
|
16
17
|
/** Shared formatter, hoisted so each row render does not rebuild the Intl
|
|
17
18
|
* machinery. Same options as the old `toLocaleDateString` call — identical output. */
|
|
18
19
|
const commitDateFormatter = new Intl.DateTimeFormat(undefined, {
|
|
@@ -30,24 +31,10 @@ export function VersionSelector() {
|
|
|
30
31
|
const { data, isLoading, error } = useBranches({ enabled: open || activeRef !== '' });
|
|
31
32
|
const defaultBranch = data?.default_branch ?? activeRef;
|
|
32
33
|
const isOnMain = activeRef === defaultBranch;
|
|
33
|
-
const filtered = useMemo(() =>
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return branches;
|
|
38
|
-
return branches.filter((b) => b.name.toLowerCase().includes(trimmed) || b.subject.toLowerCase().includes(trimmed));
|
|
39
|
-
}, [data?.branches, query]);
|
|
40
|
-
const { primary, others } = useMemo(() => {
|
|
41
|
-
const primary = [];
|
|
42
|
-
const others = [];
|
|
43
|
-
for (const b of filtered) {
|
|
44
|
-
if (b.is_default)
|
|
45
|
-
primary.push(b);
|
|
46
|
-
else
|
|
47
|
-
others.push(b);
|
|
48
|
-
}
|
|
49
|
-
return { primary, others };
|
|
50
|
-
}, [filtered]);
|
|
34
|
+
const filtered = useMemo(() => (data?.branches ?? []).filter((b) => versionMatches(b, query)), [data?.branches, query]);
|
|
35
|
+
const { primary, others, archived } = useMemo(() => groupVersions(filtered), [filtered]);
|
|
36
|
+
const activeBranch = data?.branches.find((b) => b.name === activeRef);
|
|
37
|
+
const activeLabel = activeBranch ? versionTitle(activeBranch) : activeRef;
|
|
51
38
|
const handleSelect = (branchName) => {
|
|
52
39
|
setVersion(projectId, branchName === defaultBranch ? null : branchName);
|
|
53
40
|
setOpen(false);
|
|
@@ -57,10 +44,14 @@ export function VersionSelector() {
|
|
|
57
44
|
setOpen(v);
|
|
58
45
|
if (!v)
|
|
59
46
|
setQuery('');
|
|
60
|
-
}, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline-ghost", type: "button", size: "sm", className:
|
|
47
|
+
}, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline-ghost", type: "button", size: "sm", className: "max-w-48 min-w-30 shrink-0 justify-between", title: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line88JsxAttrTitleSwitchVersion'), children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Layers, { className: "text-muted-foreground size-3.5 shrink-0" }), _jsx("span", { className: "truncate", children: activeLabel || 'Version' })] }), _jsx(ChevronsUpDown, { className: "text-muted-foreground size-3 shrink-0" })] }) }), _jsxs(PopoverContent, { align: "start", sideOffset: 6, className: "flex w-[340px] flex-col overflow-hidden p-0", children: [_jsxs("div", { className: "border-border flex shrink-0 items-center gap-1.5 border-b px-3 py-2", children: [_jsx(Search, { className: "text-muted-foreground h-3.5 w-3.5 shrink-0" }), _jsx("input", { type: "text", value: query, onChange: (e) => setQuery(e.target.value), placeholder: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line112JsxAttrPlaceholderFindAVersion'), className: "text-foreground placeholder:text-muted-foreground h-7 min-w-0 flex-1 border-0 bg-transparent px-0 text-sm outline-none" })] }), _jsx("div", { className: "h-[520px] max-h-[calc(100vh-8rem)] min-h-0 shrink", children: _jsxs(FadedScrollArea, { fadeColor: "from-popover", className: "h-full overscroll-contain", children: [isLoading && (_jsxs("div", { className: "text-muted-foreground flex items-center justify-center gap-2 py-8 text-xs", children: [_jsx(Loading, { className: "size-3.5" }), tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line122JsxTextLoadingVersions')] })), error && !isLoading && (_jsx("div", { className: "text-muted-foreground px-4 py-8 text-center text-xs", children: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line128JsxTextFailedToLoadVersions') })), !isLoading && !error && filtered.length === 0 && (_jsxs("div", { className: "text-muted-foreground px-4 py-8 text-center text-xs", children: [tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line134JsxTextNoVersionsMatch'), ' ', query ? `“${query}”` : ''] })), primary.length > 0 && (_jsxs("div", { className: cn('space-y-3 p-3', others.length + archived.length > 0 ? 'pb-0' : 'pb-3'), children: [_jsx(Label, { children: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line140JsxTextMainVersion') }), primary.map((b) => (_jsx(VersionRow, { branch: b, isActive: activeRef === b.name, onClick: () => handleSelect(b.name) }, b.name)))] })), others.length > 0 && (_jsxs("div", { className: cn('space-y-3 p-3', archived.length > 0 ? 'pb-0' : 'pb-3'), children: [_jsx(Label, { children: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line154JsxTextOtherVersions') }), others.map((b) => (_jsx(VersionRow, { branch: b, isActive: activeRef === b.name, onClick: () => handleSelect(b.name) }, b.name)))] })), archived.length > 0 && (_jsxs("div", { className: "space-y-3 p-3 pb-3", children: [_jsx(Label, { children: tHardcodedUi.raw('i18nComplete.textbdb86505f806') }), archived.map((b) => (_jsx(VersionRow, { branch: b, isActive: activeRef === b.name, onClick: () => handleSelect(b.name) }, b.name)))] }))] }) })] })] }));
|
|
61
48
|
}
|
|
62
49
|
function VersionRow({ branch, isActive, onClick, }) {
|
|
63
50
|
const tHardcodedUi = useTranslations('hardcodedUi');
|
|
64
51
|
const date = branch.committed_at ? commitDateFormatter.format(new Date(branch.committed_at)) : '';
|
|
65
|
-
|
|
52
|
+
const title = versionTitle(branch);
|
|
53
|
+
const agent = branch.session?.agent_name;
|
|
54
|
+
return (_jsxs("button", { type: "button", onClick: onClick,
|
|
55
|
+
// The id stays one hover away, and search still finds it.
|
|
56
|
+
title: title === branch.name ? undefined : branch.name, className: cn('border-border bg-popover hover:bg-foreground/4 flex w-full cursor-pointer items-start gap-2.5 rounded-md px-3 py-2 text-left', isActive && 'bg-primary/5'), children: [_jsx("div", { className: "mt-0.5 flex size-4 shrink-0 items-center justify-center", children: isActive ? (_jsx(Check, { className: "text-primary size-3.5" })) : (_jsx(Layers, { className: "text-muted-foreground size-3.5" })) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "text-foreground truncate text-sm font-medium", children: title }), branch.is_default && (_jsx(Badge, { variant: "kortix", size: "xs", children: tHardcodedUi.raw('i18nComplete.texteb814be3ca3b') })), branch.session?.deleted && (_jsx(Badge, { variant: "outline", size: "xs", children: tHardcodedUi.raw('i18nComplete.textb48ff39c2e0f') }))] }), _jsxs("div", { className: "text-muted-foreground mt-0.5 flex items-center gap-1.5 text-xs", children: [agent && _jsx("span", { className: "truncate", children: agent }), agent && date && _jsx("span", { className: "text-muted-foreground", children: "\u00B7" }), date && (_jsxs("span", { children: [tHardcodedUi.raw('i18nComplete.text3a5ecca188c0'), " ", date] })), !branch.is_default && branch.ahead != null && branch.behind != null && (_jsxs(_Fragment, { children: [date && _jsx("span", { className: "text-muted-foreground", children: "\u00B7" }), _jsxs("span", { className: "inline-flex items-center gap-1 tabular-nums", title: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line234JsxAttrTitleAheadBehindMainVersion'), children: [_jsxs("span", { className: "text-kortix-green inline-flex items-center gap-0.5", children: [_jsx(ArrowUpRight, { className: "h-2.5 w-2.5" }), branch.ahead] }), _jsxs("span", { className: "text-kortix-red inline-flex items-center gap-0.5", children: [_jsx(ArrowDownLeft, { className: "h-2.5 w-2.5" }), branch.behind] })] })] }))] }), branch.subject && (_jsx("div", { className: "text-muted-foreground mt-0.5 truncate text-xs", children: branch.subject }))] })] }));
|
|
66
57
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type InfiniteData } from '@tanstack/react-query';
|
|
1
|
+
import { type InfiniteData, type QueryClient } from '@tanstack/react-query';
|
|
2
2
|
import { type ChangeRequest, type ChangeRequestDetailResponse, type ChangeRequestDiffResponse, type ChangeRequestMergePreview, type ChangeRequestMergeResponse, type ChangeRequestStatus, type VersionDiffPreview } from '../api/change-requests.js';
|
|
3
3
|
export declare const changeRequestKeys: {
|
|
4
4
|
all: readonly ["project-files", "change-requests"];
|
|
@@ -118,6 +118,19 @@ export declare function useVersionDiff(input: {
|
|
|
118
118
|
projectId?: string;
|
|
119
119
|
}): import("@tanstack/react-query").UseQueryResult<VersionDiffPreview, Error>;
|
|
120
120
|
export declare function useChangeRequestMergePreview(crId: string | null, enabled?: boolean): import("@tanstack/react-query").UseQueryResult<ChangeRequestMergePreview, Error>;
|
|
121
|
+
/**
|
|
122
|
+
* Marks every change-request read of one project stale: each list (the
|
|
123
|
+
* session's outcome cards, the sidebar brief), each detail, and the review
|
|
124
|
+
* summary behind the sidebar's "Needs you" count. Called at turn end, because
|
|
125
|
+
* an agent opens and closes change requests from its sandbox through the REST
|
|
126
|
+
* API and the browser is not told (KRTX-3009, KRTX-3010).
|
|
127
|
+
*/
|
|
128
|
+
export declare function invalidateChangeRequestReads(qc: QueryClient, projectId: string): void;
|
|
129
|
+
/**
|
|
130
|
+
* Invalidates every CR query for the active project — used after open / merge
|
|
131
|
+
* / close / reopen so all panels and detail views re-fetch.
|
|
132
|
+
*/
|
|
133
|
+
export declare function invalidateAfterChangeRequestWrite(qc: QueryClient, projectId: string): void;
|
|
121
134
|
export declare function useOpenChangeRequest(options?: {
|
|
122
135
|
projectId?: string;
|
|
123
136
|
}): import("@tanstack/react-query").UseMutationResult<ChangeRequest, Error, {
|
|
@@ -217,39 +217,58 @@ export function useChangeRequestMergePreview(crId, enabled = true) {
|
|
|
217
217
|
staleTime: 10_000,
|
|
218
218
|
});
|
|
219
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Marks every change-request read of one project stale: each list (the
|
|
222
|
+
* session's outcome cards, the sidebar brief), each detail, and the review
|
|
223
|
+
* summary behind the sidebar's "Needs you" count. Called at turn end, because
|
|
224
|
+
* an agent opens and closes change requests from its sandbox through the REST
|
|
225
|
+
* API and the browser is not told (KRTX-3009, KRTX-3010).
|
|
226
|
+
*/
|
|
227
|
+
export function invalidateChangeRequestReads(qc, projectId) {
|
|
228
|
+
if (!projectId)
|
|
229
|
+
return;
|
|
230
|
+
qc.invalidateQueries({ queryKey: changeRequestKeys.project(projectId) });
|
|
231
|
+
qc.invalidateQueries({ queryKey: qk.project.reviewSummary(projectId) });
|
|
232
|
+
}
|
|
220
233
|
/**
|
|
221
234
|
* Invalidates every CR query for the active project — used after open / merge
|
|
222
235
|
* / close / reopen so all panels and detail views re-fetch.
|
|
223
236
|
*/
|
|
237
|
+
export function invalidateAfterChangeRequestWrite(qc, projectId) {
|
|
238
|
+
invalidateChangeRequestReads(qc, projectId);
|
|
239
|
+
// Branches list shows ahead/behind that may shift after a merge.
|
|
240
|
+
qc.invalidateQueries({ queryKey: branchKeys.list(projectId) });
|
|
241
|
+
// The merge commit lands on the default branch — commit list goes stale.
|
|
242
|
+
qc.invalidateQueries({ queryKey: commitKeys.project(projectId) });
|
|
243
|
+
// Whether this version still differs from its base changes the moment a CR
|
|
244
|
+
// merges — refresh the "Alternate version of main · N changes" banner
|
|
245
|
+
// (git-status, which is otherwise sticky and never re-fetches on its own),
|
|
246
|
+
// the live version-diff preview, and the cached session row (base_ref etc.).
|
|
247
|
+
qc.invalidateQueries({ queryKey: gitStatusKeys.all });
|
|
248
|
+
qc.invalidateQueries({ queryKey: versionDiffKeys.project(projectId) });
|
|
249
|
+
// Every individual git-connected session under this project — a CR
|
|
250
|
+
// landing on the base ref can change what `getProjectSession` returns
|
|
251
|
+
// (base_ref etc.) for any of them. sessionsScope is the shared prefix
|
|
252
|
+
// that reaches the sessions list AND every qk.project.session(id, sid)
|
|
253
|
+
// entry in one call; there is no "every session, not the list" prefix to
|
|
254
|
+
// narrow to, so this deliberately also refreshes the sessions list.
|
|
255
|
+
qc.invalidateQueries({ queryKey: qk.project.sessionsScope(projectId) });
|
|
256
|
+
// Landing a CR on the base ref is the one thing that happens INSIDE the app
|
|
257
|
+
// that can make an open session's compiled agent config stale. The
|
|
258
|
+
// freshness query is deliberately not polled — this is what tells it to
|
|
259
|
+
// look again, so the chip appears on merge rather than on next focus.
|
|
260
|
+
qc.invalidateQueries({ queryKey: ['session-config', projectId] });
|
|
261
|
+
// A merged CR can rewrite kortix.yaml: add or remove agents and change
|
|
262
|
+
// `default_agent`. Both live in the project detail entry, and the composer's
|
|
263
|
+
// agent list sits under it (`[...detail, 'agents']`), so New session kept
|
|
264
|
+
// offering removed agents until a reload (KRTX-3012).
|
|
265
|
+
qc.invalidateQueries({ queryKey: qk.project.detail(projectId) });
|
|
266
|
+
}
|
|
224
267
|
function useInvalidateAll(projectIdArg) {
|
|
225
268
|
const qc = useQueryClient();
|
|
226
269
|
const ctx = useProjectContext();
|
|
227
270
|
const projectId = projectIdArg ?? ctx?.projectId ?? '';
|
|
228
|
-
return () =>
|
|
229
|
-
qc.invalidateQueries({ queryKey: changeRequestKeys.project(projectId) });
|
|
230
|
-
// Branches list shows ahead/behind that may shift after a merge.
|
|
231
|
-
qc.invalidateQueries({ queryKey: branchKeys.list(projectId) });
|
|
232
|
-
// The merge commit lands on the default branch — commit list goes stale.
|
|
233
|
-
qc.invalidateQueries({ queryKey: commitKeys.project(projectId) });
|
|
234
|
-
// Whether this version still differs from its base changes the moment a CR
|
|
235
|
-
// merges — refresh the "Alternate version of main · N changes" banner
|
|
236
|
-
// (git-status, which is otherwise sticky and never re-fetches on its own),
|
|
237
|
-
// the live version-diff preview, and the cached session row (base_ref etc.).
|
|
238
|
-
qc.invalidateQueries({ queryKey: gitStatusKeys.all });
|
|
239
|
-
qc.invalidateQueries({ queryKey: versionDiffKeys.project(projectId) });
|
|
240
|
-
// Every individual git-connected session under this project — a CR
|
|
241
|
-
// landing on the base ref can change what `getProjectSession` returns
|
|
242
|
-
// (base_ref etc.) for any of them. sessionsScope is the shared prefix
|
|
243
|
-
// that reaches the sessions list AND every qk.project.session(id, sid)
|
|
244
|
-
// entry in one call; there is no "every session, not the list" prefix to
|
|
245
|
-
// narrow to, so this deliberately also refreshes the sessions list.
|
|
246
|
-
qc.invalidateQueries({ queryKey: qk.project.sessionsScope(projectId) });
|
|
247
|
-
// Landing a CR on the base ref is the one thing that happens INSIDE the app
|
|
248
|
-
// that can make an open session's compiled agent config stale. The
|
|
249
|
-
// freshness query is deliberately not polled — this is what tells it to
|
|
250
|
-
// look again, so the chip appears on merge rather than on next focus.
|
|
251
|
-
qc.invalidateQueries({ queryKey: ['session-config', projectId] });
|
|
252
|
-
};
|
|
271
|
+
return () => invalidateAfterChangeRequestWrite(qc, projectId);
|
|
253
272
|
}
|
|
254
273
|
export function useOpenChangeRequest(options) {
|
|
255
274
|
const ctx = useProjectContext();
|
|
@@ -18,19 +18,21 @@ export function useServerHealth(_options) {
|
|
|
18
18
|
* git-status gate (`project?.vcs === 'git'`) continues to behave correctly.
|
|
19
19
|
*/
|
|
20
20
|
export function useCurrentProject(_options) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
21
|
+
return useMemo(() => {
|
|
22
|
+
const data = {
|
|
23
|
+
id: 'project-files',
|
|
24
|
+
worktree: '/workspace',
|
|
25
|
+
vcs: 'git',
|
|
26
|
+
name: 'project',
|
|
27
|
+
time: { created: Date.now(), updated: Date.now() },
|
|
28
|
+
sandboxes: [],
|
|
29
|
+
};
|
|
30
|
+
return {
|
|
31
|
+
data,
|
|
32
|
+
isLoading: false,
|
|
33
|
+
isError: false,
|
|
34
|
+
error: null,
|
|
35
|
+
refetch: async () => ({ data }),
|
|
36
|
+
};
|
|
37
|
+
}, []);
|
|
36
38
|
}
|
|
@@ -45,6 +45,9 @@ const ZOOM_OPTIONS = [10, 25, 50, 75, 100, 125, 150, 175, 200, 400];
|
|
|
45
45
|
const DOCX_PADDING_WARNING_TEXT = 'a style property during rerender';
|
|
46
46
|
const DOCX_THUMBNAIL_FOCUS_RING_CLASS = 'group-focus-visible/docx-thumbnail-sidebar:ring-2 group-focus-visible/docx-thumbnail-sidebar:ring-ring group-focus-visible/docx-thumbnail-sidebar:ring-offset-1 group-focus-visible/docx-thumbnail-sidebar:ring-offset-background';
|
|
47
47
|
const DOCX_THUMBNAIL_PREFETCH_ROWS = 4;
|
|
48
|
+
// Night reader: the inverted page content's default text is black, so the
|
|
49
|
+
// inversion makes it light (see the <style> in the page shell below).
|
|
50
|
+
const NIGHT_READER_TEXT_STYLE = '.docx-night-reader-shell [style*="hue-rotate(180deg)"]{color:#000}';
|
|
48
51
|
function createDocxActivePageStore() {
|
|
49
52
|
let activePage = 1;
|
|
50
53
|
const listeners = new Set();
|
|
@@ -193,11 +196,6 @@ function DocxPageNumberControl({ activePageStore, controlsDisabled, onPageChange
|
|
|
193
196
|
const displayPage = pageCount ? activePage : 1;
|
|
194
197
|
const [isEditing, setIsEditing] = React.useState(false);
|
|
195
198
|
const [draftPage, setDraftPage] = React.useState(() => String(displayPage));
|
|
196
|
-
React.useEffect(() => {
|
|
197
|
-
if (!isEditing) {
|
|
198
|
-
setDraftPage(String(displayPage));
|
|
199
|
-
}
|
|
200
|
-
}, [displayPage, isEditing]);
|
|
201
199
|
React.useEffect(() => {
|
|
202
200
|
if (!isEditing)
|
|
203
201
|
return;
|
|
@@ -617,5 +615,5 @@ function DocxViewerContent({ className, defaultZoom, effectiveIsDark, fileName,
|
|
|
617
615
|
event.currentTarget.focus({ preventScroll: true });
|
|
618
616
|
},
|
|
619
617
|
tabIndex: 0,
|
|
620
|
-
}, viewportRef: setViewportRef, children: !url && !activeUploadedDocxFile ? (_jsx("div", { className: "grid h-full min-h-96 place-items-center p-6 text-center", children: _jsxs("div", { className: "bg-background max-w-md rounded-lg border p-4 text-sm shadow-xs", children: [_jsx("div", { className: "font-medium", children: tI18nComplete.raw('text53c247b8cf06') }), _jsxs("div", { className: "text-muted-foreground mt-1", children: [tI18nComplete.raw('text46800e585f61'), " ", _jsx("code", { children: "src" }), ' ', tI18nComplete.raw('text37056f2381e2')] }), _jsxs("div", { className: "text-muted-foreground mt-1", children: [tI18nComplete.raw('text1432897a6136'), " ", _jsx("code", { children: ".doc" }), ' ', tI18nComplete.raw('text73a2f5159338')] }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", className: "mt-4", onClick: () => fileInputRef.current?.click(), children: [_jsx(Upload, { className: "size-4" }), tI18nComplete.raw('textdc0451eb46ce')] })] }) })) : loadError ? (_jsx("div", { className: "grid h-full min-h-96 place-items-center p-6 text-center", children: _jsxs("div", { className: "bg-background text-destructive max-w-md rounded-lg border p-4 text-sm shadow-xs", children: [_jsx("div", { className: "font-medium", children: tI18nComplete.raw('text2a5502b48b14') }), _jsx("div", { className: "text-muted-foreground mt-1", children: loadError })] }) })) : isLoadingDocument ? (loadingState) : (_jsx("div", { className: "flex min-h-full w-max min-w-full justify-center", children:
|
|
618
|
+
}, viewportRef: setViewportRef, children: !url && !activeUploadedDocxFile ? (_jsx("div", { className: "grid h-full min-h-96 place-items-center p-6 text-center", children: _jsxs("div", { className: "bg-background max-w-md rounded-lg border p-4 text-sm shadow-xs", children: [_jsx("div", { className: "font-medium", children: tI18nComplete.raw('text53c247b8cf06') }), _jsxs("div", { className: "text-muted-foreground mt-1", children: [tI18nComplete.raw('text46800e585f61'), " ", _jsx("code", { children: "src" }), ' ', tI18nComplete.raw('text37056f2381e2')] }), _jsxs("div", { className: "text-muted-foreground mt-1", children: [tI18nComplete.raw('text1432897a6136'), " ", _jsx("code", { children: ".doc" }), ' ', tI18nComplete.raw('text73a2f5159338')] }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", className: "mt-4", onClick: () => fileInputRef.current?.click(), children: [_jsx(Upload, { className: "size-4" }), tI18nComplete.raw('textdc0451eb46ce')] })] }) })) : loadError ? (_jsx("div", { className: "grid h-full min-h-96 place-items-center p-6 text-center", children: _jsxs("div", { className: "bg-background text-destructive max-w-md rounded-lg border p-4 text-sm shadow-xs", children: [_jsx("div", { className: "font-medium", children: tI18nComplete.raw('text2a5502b48b14') }), _jsx("div", { className: "text-muted-foreground mt-1", children: loadError })] }) })) : isLoadingDocument ? (loadingState) : (_jsx("div", { className: "flex min-h-full w-max min-w-full justify-center", children: _jsxs("div", { className: cn('origin-top', effectiveIsDark && 'docx-night-reader-shell'), style: { zoom: zoomScale / 100 }, children: [effectiveIsDark && (_jsx("style", { children: NIGHT_READER_TEXT_STYLE })), _jsx(DocxEditorViewer, { editor: editor, mode: "read-only", showTrackedChanges: showTrackedChanges, renderTrackedChangeCard: renderTrackedChangeCard, showComments: showComments, renderCommentCard: renderCommentCard, loadingState: loadingState, pageBackgroundColor: effectiveIsDark ? 'var(--background)' : undefined, pageGapBackgroundColor: viewerBackgroundColor, pageVirtualization: pageVirtualization, deferInitialPaginationPaint: false, onPageCountChange: handlePageCountChange })] }) })) })] })] }));
|
|
621
619
|
}
|
|
@@ -55,11 +55,10 @@ export function ImageRenderer({ url, className, fileName, controls = 'hover', ba
|
|
|
55
55
|
const [rotation, setRotation] = useState(0);
|
|
56
56
|
const [isPanning, setIsPanning] = useState(false);
|
|
57
57
|
const [position, setPosition] = useState({ x: 0, y: 0 });
|
|
58
|
-
const
|
|
58
|
+
const startPanPositionRef = useRef({ x: 0, y: 0 });
|
|
59
59
|
const [backdrop, setBackdrop] = useState('transparent');
|
|
60
60
|
const [imgLoaded, setImgLoaded] = useState(false);
|
|
61
61
|
const [imgError, setImgError] = useState(false);
|
|
62
|
-
const [imgInfo, setImgInfo] = useState(null);
|
|
63
62
|
// ── Retry state ──────────────────────────────────────────────────────
|
|
64
63
|
const [retryCount, setRetryCount] = useState(0);
|
|
65
64
|
const [imgSrc, setImgSrc] = useState(url);
|
|
@@ -71,18 +70,6 @@ export function ImageRenderer({ url, className, fileName, controls = 'hover', ba
|
|
|
71
70
|
const isSvg = fileName?.toLowerCase().endsWith('.svg') ||
|
|
72
71
|
url?.toLowerCase().endsWith('.svg') ||
|
|
73
72
|
url?.includes('image/svg');
|
|
74
|
-
// Derive the display file type for the info panel
|
|
75
|
-
const displayFileType = (() => {
|
|
76
|
-
if (isSvg)
|
|
77
|
-
return 'SVG';
|
|
78
|
-
if (fileName) {
|
|
79
|
-
const ext = fileName.split('.').pop()?.toUpperCase();
|
|
80
|
-
if (ext)
|
|
81
|
-
return ext;
|
|
82
|
-
}
|
|
83
|
-
const ext = url.split('.').pop()?.toUpperCase();
|
|
84
|
-
return ext || 'Image';
|
|
85
|
-
})();
|
|
86
73
|
// When the parent passes a new URL, reset everything. The reset runs during
|
|
87
74
|
// render, not in an effect: an effect also ran on mount, after a cached
|
|
88
75
|
// image had already fired `load`, and set `imgLoaded` back to false. The
|
|
@@ -123,17 +110,12 @@ export function ImageRenderer({ url, className, fileName, controls = 'hover', ba
|
|
|
123
110
|
setImgError(false);
|
|
124
111
|
setRetryCount(0); // reset on success
|
|
125
112
|
if (imageRef.current) {
|
|
126
|
-
setImgInfo({
|
|
127
|
-
width: imageRef.current.naturalWidth,
|
|
128
|
-
height: imageRef.current.naturalHeight,
|
|
129
|
-
type: displayFileType,
|
|
130
|
-
});
|
|
131
113
|
previewFit?.report({
|
|
132
114
|
width: imageRef.current.naturalWidth,
|
|
133
115
|
height: imageRef.current.naturalHeight,
|
|
134
116
|
});
|
|
135
117
|
}
|
|
136
|
-
}, [
|
|
118
|
+
}, [previewFit]);
|
|
137
119
|
// Retries exhausted: these bytes are never going to decode, so there will be
|
|
138
120
|
// no `report` for this image. Say "never" rather than staying silent — a
|
|
139
121
|
// consumer reads silence as "still loading" and keeps whatever width it last
|
|
@@ -213,17 +195,17 @@ export function ImageRenderer({ url, className, fileName, controls = 'hover', ba
|
|
|
213
195
|
const handleMouseDown = (e) => {
|
|
214
196
|
if (canPan) {
|
|
215
197
|
setIsPanning(true);
|
|
216
|
-
|
|
198
|
+
startPanPositionRef.current = {
|
|
217
199
|
x: e.clientX - position.x,
|
|
218
200
|
y: e.clientY - position.y,
|
|
219
|
-
}
|
|
201
|
+
};
|
|
220
202
|
}
|
|
221
203
|
};
|
|
222
204
|
const handleMouseMove = (e) => {
|
|
223
205
|
if (isPanning && canPan) {
|
|
224
206
|
setPosition({
|
|
225
|
-
x: e.clientX -
|
|
226
|
-
y: e.clientY -
|
|
207
|
+
x: e.clientX - startPanPositionRef.current.x,
|
|
208
|
+
y: e.clientY - startPanPositionRef.current.y,
|
|
227
209
|
});
|
|
228
210
|
}
|
|
229
211
|
};
|
|
@@ -13,9 +13,11 @@ interface PdfRendererProps {
|
|
|
13
13
|
toolbarActions?: React.ReactNode;
|
|
14
14
|
/** Start the zoom plugin at fit-to-page instead of the numeric default. */
|
|
15
15
|
fitOnOpen?: boolean;
|
|
16
|
+
/** Search for this text once the document opens: highlighted, first hit in view. */
|
|
17
|
+
findText?: string;
|
|
16
18
|
/** False when the host's own toolbar already has the Download button, so the
|
|
17
19
|
* viewer does not show a second one. */
|
|
18
20
|
showDownload?: boolean;
|
|
19
21
|
}
|
|
20
|
-
export declare function PdfRenderer({ fileContent, url, className, compact, fileName, toolbarActions, fitOnOpen, showDownload, }: PdfRendererProps): import("react").JSX.Element;
|
|
22
|
+
export declare function PdfRenderer({ fileContent, url, className, compact, fileName, toolbarActions, fitOnOpen, findText, showDownload, }: PdfRendererProps): import("react").JSX.Element;
|
|
21
23
|
export {};
|
|
@@ -14,7 +14,7 @@ export function base64PdfContentToBlob(fileContent) {
|
|
|
14
14
|
}
|
|
15
15
|
return new Blob([bytes], { type: 'application/pdf' });
|
|
16
16
|
}
|
|
17
|
-
export function PdfRenderer({ fileContent, url, className, compact = false, fileName, toolbarActions, fitOnOpen, showDownload = true, }) {
|
|
17
|
+
export function PdfRenderer({ fileContent, url, className, compact = false, fileName, toolbarActions, fitOnOpen, findText, showDownload = true, }) {
|
|
18
18
|
const tHardcodedUi = useTranslations('hardcodedUi');
|
|
19
19
|
const [pdfUrl, setPdfUrl] = useState(null);
|
|
20
20
|
const [status, setStatus] = useState('loading');
|
|
@@ -50,5 +50,5 @@ export function PdfRenderer({ fileContent, url, className, compact = false, file
|
|
|
50
50
|
if (status === 'error' || !pdfUrl) {
|
|
51
51
|
return (_jsxs("div", { className: cn('flex h-full w-full flex-col items-center justify-center gap-3 p-8 text-center', className), children: [_jsx("div", { className: "bg-muted flex h-10 w-10 items-center justify-center rounded-full", children: _jsx(AlertTriangle, { className: "text-muted-foreground h-4 w-4" }) }), _jsxs("div", { children: [_jsx("p", { className: "text-foreground text-sm font-medium", children: tHardcodedUi.raw('componentsFileRenderersPdfRenderer.line277JsxTextFailedToLoadPdf') }), !compact && (_jsx("p", { className: "text-muted-foreground mt-1 text-xs", children: tHardcodedUi.raw('componentsFileRenderersPdfRenderer.line278JsxTextTheFileMayBeCorruptedOrInaccessible') }))] })] }));
|
|
52
52
|
}
|
|
53
|
-
return (_jsx(PDFViewer, { src: pdfUrl, fileName: fileName, showToolbar: !compact, showDownload: showDownload, showUpload: false, className: cn('h-full w-full', className), toolbarActions: toolbarActions, fitOnOpen: fitOnOpen }));
|
|
53
|
+
return (_jsx(PDFViewer, { src: pdfUrl, fileName: fileName, showToolbar: !compact, showDownload: showDownload, showUpload: false, className: cn('h-full w-full', className), toolbarActions: toolbarActions, fitOnOpen: fitOnOpen, findText: findText }));
|
|
54
54
|
}
|
|
@@ -31,6 +31,9 @@ export type PDFViewerProps = {
|
|
|
31
31
|
showUpload?: boolean;
|
|
32
32
|
src?: string;
|
|
33
33
|
toolbarActions?: React.ReactNode;
|
|
34
|
+
/** Search the document for this text once it opens: hits are highlighted and the
|
|
35
|
+
* first is scrolled into view, as if typed into the toolbar's search. */
|
|
36
|
+
findText?: string;
|
|
34
37
|
pageClassName?: (pageNumber: number) => string | undefined;
|
|
35
38
|
renderPageOverlay?: (props: PDFViewerPageOverlayProps) => React.ReactNode;
|
|
36
39
|
onActivePageChange?: (pageNumber: number) => void;
|
|
@@ -240,7 +240,7 @@ function PDFViewerFileActionsMenu({ onUploadFile, showUpload = false, }) {
|
|
|
240
240
|
const inputRef = React.useRef(null);
|
|
241
241
|
if (!showUpload || !onUploadFile)
|
|
242
242
|
return null;
|
|
243
|
-
return (_jsxs(_Fragment, { children: [_jsx("input", { ref: inputRef, type: "file", accept: "application/pdf,.pdf", className: "sr-only", tabIndex: -1, onChange: (event) => {
|
|
243
|
+
return (_jsxs(_Fragment, { children: [_jsx("input", { ref: inputRef, type: "file", accept: "application/pdf,.pdf", "aria-label": tI18nComplete.raw('text865e89de78d9'), className: "sr-only", tabIndex: -1, onChange: (event) => {
|
|
244
244
|
const nextFile = event.target.files?.[0];
|
|
245
245
|
if (nextFile) {
|
|
246
246
|
onUploadFile(nextFile);
|
|
@@ -282,7 +282,7 @@ function PDFViewerPageNumberControl({ activePage, controlsDisabled, numPages, on
|
|
|
282
282
|
setIsEditing(true);
|
|
283
283
|
}, children: displayPage })), _jsxs("span", { children: [tI18nComplete.raw('text28391d3bc64e'), " ", numPages || '–'] })] }));
|
|
284
284
|
}
|
|
285
|
-
function PDFViewerSearchControl({ documentId, controlsDisabled, }) {
|
|
285
|
+
function PDFViewerSearchControl({ documentId, controlsDisabled, initialSearch, }) {
|
|
286
286
|
const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
|
|
287
287
|
const { state, provides } = useSearch(documentId);
|
|
288
288
|
const { provides: scroll } = useScroll(documentId);
|
|
@@ -323,6 +323,12 @@ function PDFViewerSearchControl({ documentId, controlsDisabled, }) {
|
|
|
323
323
|
providesRef.current = provides;
|
|
324
324
|
scrollRef.current = scroll;
|
|
325
325
|
}, [provides, scroll]);
|
|
326
|
+
// A host's `findText`: search once the plugin is ready, and again when the text changes.
|
|
327
|
+
React.useEffect(() => {
|
|
328
|
+
const text = initialSearch?.trim();
|
|
329
|
+
if (text && provides && scroll)
|
|
330
|
+
setSearchDraft(text);
|
|
331
|
+
}, [initialSearch, provides, scroll]);
|
|
326
332
|
const runSearch = React.useCallback((rawQuery) => {
|
|
327
333
|
const query = rawQuery.trim();
|
|
328
334
|
const requestId = searchRequestIdRef.current + 1;
|
|
@@ -922,7 +928,7 @@ function PDFViewerScroller({ documentId, pageRotationDeltas, basePageRotations,
|
|
|
922
928
|
width: '100%',
|
|
923
929
|
} })] }));
|
|
924
930
|
}
|
|
925
|
-
function PDFViewerInner({ viewerRef, pdfFile, documentId, document: pdfDocument, defaultZoom, className, fileName, showDownload, showToolbar, showRotateControls, showUpload, toolbarActions, pageClassName, renderPageOverlay, onActivePageChange, onPdfUpload, onPagePointerDown, onPagePointerMove, onPagePointerUp, onPagePointerCancel, onUploadFile, }) {
|
|
931
|
+
function PDFViewerInner({ viewerRef, pdfFile, documentId, document: pdfDocument, defaultZoom, className, fileName, showDownload, showToolbar, showRotateControls, showUpload, toolbarActions, findText, pageClassName, renderPageOverlay, onActivePageChange, onPdfUpload, onPagePointerDown, onPagePointerMove, onPagePointerUp, onPagePointerCancel, onUploadFile, }) {
|
|
926
932
|
const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
|
|
927
933
|
const { registry } = useRegistry();
|
|
928
934
|
const { state: scrollState, provides: scroll } = useScroll(documentId);
|
|
@@ -1184,7 +1190,7 @@ function PDFViewerInner({ viewerRef, pdfFile, documentId, document: pdfDocument,
|
|
|
1184
1190
|
pdfDocument?.pages[page.pageIndex]?.rotation ??
|
|
1185
1191
|
normalizeRotation(0);
|
|
1186
1192
|
const pageRotation = normalizeRotation(basePageRotation + (pageRotationDeltas.get(page.pageIndex) ?? 0));
|
|
1187
|
-
return (_jsx(Rotate, { documentId: documentId, pageIndex: page.pageIndex, rotation: pageRotation, children: _jsxs(PagePointerProvider, { documentId: documentId, pageIndex: page.pageIndex, rotation: pageRotation, "data-pdf-viewer-page": pageNumber, className: cn('relative border border-transparent bg-transparent shadow-xs select-none selection:bg-transparent selection:text-inherit', pageClassName?.(pageNumber)), style: { backgroundColor: 'transparent' }, onPointerDown: (event) => onPagePointerDown?.(event, pageNumber), onPointerMove: (event) => onPagePointerMove?.(event, pageNumber), onPointerUp: (event) => onPagePointerUp?.(event, pageNumber), onPointerCancel: (event) => onPagePointerCancel?.(event, pageNumber), children: [_jsx("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 bg-white" }), _jsx(RenderLayer, { documentId: documentId, pageIndex: page.pageIndex, scale: Math.min(currentZoomLevel, PAGE_BASE_RENDER_MAX_SCALE), dpr: PAGE_BASE_RENDER_DPR, className: "pointer-events-none absolute inset-0 h-full w-full object-fill opacity-100 blur-[0.35px] transition-none" }), _jsx(TilingLayer, { documentId: documentId, pageIndex: page.pageIndex, className: "pointer-events-none opacity-100 transition-none [&_img]:opacity-100 [&_img]:transition-none" }, `tiles-${page.pageIndex}-${pageRotation}`), _jsx(SearchLayer, { documentId: documentId, pageIndex: page.pageIndex, className: "pointer-events-none", highlightColor: "color-mix(in srgb, var(--kortix-yellow) 45%, transparent)", activeHighlightColor: "color-mix(in srgb, var(--kortix-orange) 55%, transparent)" }), _jsx(PDFViewerTextSelectionLayer, { documentId: documentId, pageIndex: page.pageIndex, scale: currentZoomLevel }), renderPageOverlay?.({
|
|
1193
|
+
return (_jsx(Rotate, { documentId: documentId, pageIndex: page.pageIndex, rotation: pageRotation, children: _jsxs(PagePointerProvider, { documentId: documentId, pageIndex: page.pageIndex, rotation: pageRotation, "data-pdf-viewer-page": pageNumber, className: cn('relative border border-transparent bg-transparent shadow-xs select-none selection:bg-transparent selection:text-inherit', pageClassName?.(pageNumber)), style: { backgroundColor: 'transparent' }, onPointerDown: (event) => onPagePointerDown?.(event, pageNumber), onPointerMove: (event) => onPagePointerMove?.(event, pageNumber), onPointerUp: (event) => onPagePointerUp?.(event, pageNumber), onPointerCancel: (event) => onPagePointerCancel?.(event, pageNumber), children: [_jsx("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 grid place-items-center bg-white text-neutral-400", children: _jsx(Spinner, { className: "size-5" }) }), _jsx(RenderLayer, { documentId: documentId, pageIndex: page.pageIndex, scale: Math.min(currentZoomLevel, PAGE_BASE_RENDER_MAX_SCALE), dpr: PAGE_BASE_RENDER_DPR, className: "pointer-events-none absolute inset-0 h-full w-full object-fill opacity-100 blur-[0.35px] transition-none" }), _jsx(TilingLayer, { documentId: documentId, pageIndex: page.pageIndex, className: "pointer-events-none opacity-100 transition-none [&_img]:opacity-100 [&_img]:transition-none" }, `tiles-${page.pageIndex}-${pageRotation}`), _jsx(SearchLayer, { documentId: documentId, pageIndex: page.pageIndex, className: "pointer-events-none", highlightColor: "color-mix(in srgb, var(--kortix-yellow) 45%, transparent)", activeHighlightColor: "color-mix(in srgb, var(--kortix-orange) 55%, transparent)" }), _jsx(PDFViewerTextSelectionLayer, { documentId: documentId, pageIndex: page.pageIndex, scale: currentZoomLevel }), renderPageOverlay?.({
|
|
1188
1194
|
pageNumber,
|
|
1189
1195
|
pageWidth: page.width,
|
|
1190
1196
|
pageHeight: page.height,
|
|
@@ -1212,7 +1218,7 @@ function PDFViewerInner({ viewerRef, pdfFile, documentId, document: pdfDocument,
|
|
|
1212
1218
|
}, children: _jsx(CircleMinus, { className: "size-4" }) }) }), _jsxs(Select, { value: String(currentZoomLevel), onValueChange: (value) => zoom?.requestZoom(Number(value)), disabled: controlsDisabled, modal: false, children: [_jsx(SelectTrigger, { size: "sm", className: "w-[84px] min-w-[84px] tabular-nums", children: _jsxs(SelectValue, { placeholder: tI18nComplete.raw('text509c517ede79'), children: [Math.round(currentZoomLevel * 100), "%"] }) }), _jsx(SelectContent, { alignItemWithTrigger: false, children: ZOOM_OPTIONS.map((option) => (_jsxs(SelectItem, { value: String(option), children: [Math.round(option * 100), "%"] }, option))) })] }), _jsx(ToolbarTooltip, { label: tI18nComplete.raw('text0e47f09a748f'), children: _jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", className: "transition-transform active:scale-[0.96]", "aria-label": tI18nComplete.raw('text0e47f09a748f'), disabled: controlsDisabled || currentZoomLevel >= ZOOM_OPTIONS[ZOOM_OPTIONS.length - 1], onClick: () => {
|
|
1213
1219
|
const nextZoom = ZOOM_OPTIONS.find((option) => option > currentZoomLevel);
|
|
1214
1220
|
zoom?.requestZoom(nextZoom ?? ZOOM_OPTIONS[ZOOM_OPTIONS.length - 1]);
|
|
1215
|
-
}, children: _jsx(CirclePlus, { className: "size-4" }) }) })] }), _jsx(Separator, { orientation: "vertical", className: "mx-1 h-4 self-center" }), _jsx(PDFViewerSearchControl, { documentId: documentId, controlsDisabled: controlsDisabled }, documentId), toolbarActions ? (_jsxs(_Fragment, { children: [_jsx(Separator, { orientation: "vertical", className: "mx-1 h-4 self-center" }), toolbarActions] })) : null, showDownload || showUpload ? (_jsxs(_Fragment, { children: [_jsx(Separator, { orientation: "vertical", className: "mx-1 h-4 self-center" }), _jsx(PDFViewerFileActionsMenu, { onUploadFile: handleUpload, showUpload: showUpload }), showDownload ? (_jsx(ViewerDownloadButton, { disabled: controlsDisabled, pending: isPreparingDownload, onDownload: () => void handleDownload() })) : null] })) : null] }) })] })) : null, _jsxs("div", { ref: viewerShellRef, className: "bg-muted/30 relative flex min-h-0 flex-1 overflow-hidden", children: [isLoading ? (_jsx(PDFViewerLoadingSkeleton, { sidebarInline: sidebarInline, sidebarOpen: sidebarOpen })) : null, _jsxs("div", { className: "flex h-full max-h-full min-h-0 w-full flex-1 overflow-hidden", children: [_jsx(DocumentViewerThumbnailSidebar, { closedInlineClassName: THUMBNAIL_SIDEBAR_CLOSED_CLASS, inline: sidebarInline, open: thumbnailSidebarVisible, widthClassName: THUMBNAIL_SIDEBAR_WIDTH_CLASS, children: thumbnailSidebarVisible ? (_jsx(PDFViewerThumbnails, { basePageRotations: basePageRotations, documentId: documentId, activePage: activePage, pageCount: numPages, pageRotationDeltas: pageRotationDeltas, pdfDocument: pdfDocument, selectedPageIndexes: selectedPageIndexes, onSelectPage: selectThumbnailPage })) : null }), _jsxs(PDFViewerScrollAreaViewport, { documentId: documentId, className: "relative h-full max-h-full min-h-0 min-w-0 flex-1", children: [_jsx(PDFViewerViewportBridge, { viewportElementRef: viewportElementRef }), _jsx(PDFViewerSelectionCopyShortcut, { documentId: documentId }), _jsx(PDFViewerSelectionReleaseGuard, { documentId: documentId }), _jsx(GlobalPointerProvider, { documentId: documentId, children: _jsx(PDFViewerScroller, { basePageRotations: basePageRotations, documentId: documentId, pageRotationDeltas: pageRotationDeltas, renderPage: renderPage }) }), _jsx(CopyToClipboard, {})] })] })] })] }));
|
|
1221
|
+
}, children: _jsx(CirclePlus, { className: "size-4" }) }) })] }), _jsx(Separator, { orientation: "vertical", className: "mx-1 h-4 self-center" }), _jsx(PDFViewerSearchControl, { documentId: documentId, controlsDisabled: controlsDisabled, initialSearch: findText }, documentId), toolbarActions ? (_jsxs(_Fragment, { children: [_jsx(Separator, { orientation: "vertical", className: "mx-1 h-4 self-center" }), toolbarActions] })) : null, showDownload || showUpload ? (_jsxs(_Fragment, { children: [_jsx(Separator, { orientation: "vertical", className: "mx-1 h-4 self-center" }), _jsx(PDFViewerFileActionsMenu, { onUploadFile: handleUpload, showUpload: showUpload }), showDownload ? (_jsx(ViewerDownloadButton, { disabled: controlsDisabled, pending: isPreparingDownload, onDownload: () => void handleDownload() })) : null] })) : null] }) })] })) : null, _jsxs("div", { ref: viewerShellRef, className: "bg-muted/30 relative flex min-h-0 flex-1 overflow-hidden", children: [isLoading ? (_jsx(PDFViewerLoadingSkeleton, { sidebarInline: sidebarInline, sidebarOpen: sidebarOpen })) : null, _jsxs("div", { className: "flex h-full max-h-full min-h-0 w-full flex-1 overflow-hidden", children: [_jsx(DocumentViewerThumbnailSidebar, { closedInlineClassName: THUMBNAIL_SIDEBAR_CLOSED_CLASS, inline: sidebarInline, open: thumbnailSidebarVisible, widthClassName: THUMBNAIL_SIDEBAR_WIDTH_CLASS, children: thumbnailSidebarVisible ? (_jsx(PDFViewerThumbnails, { basePageRotations: basePageRotations, documentId: documentId, activePage: activePage, pageCount: numPages, pageRotationDeltas: pageRotationDeltas, pdfDocument: pdfDocument, selectedPageIndexes: selectedPageIndexes, onSelectPage: selectThumbnailPage })) : null }), _jsxs(PDFViewerScrollAreaViewport, { documentId: documentId, className: "relative h-full max-h-full min-h-0 min-w-0 flex-1", children: [_jsx(PDFViewerViewportBridge, { viewportElementRef: viewportElementRef }), _jsx(PDFViewerSelectionCopyShortcut, { documentId: documentId }), _jsx(PDFViewerSelectionReleaseGuard, { documentId: documentId }), _jsx(GlobalPointerProvider, { documentId: documentId, children: _jsx(PDFViewerScroller, { basePageRotations: basePageRotations, documentId: documentId, pageRotationDeltas: pageRotationDeltas, renderPage: renderPage }) }), _jsx(CopyToClipboard, {})] })] })] })] }));
|
|
1216
1222
|
}
|
|
1217
1223
|
function PDFViewerDocumentLoader({ pdfFile, onDocumentLoadSuccess, ...innerProps }) {
|
|
1218
1224
|
const { provides: documentManager } = useDocumentManagerCapability();
|
|
@@ -1288,7 +1294,7 @@ function PDFViewerDocumentLoader({ pdfFile, onDocumentLoadSuccess, ...innerProps
|
|
|
1288
1294
|
}
|
|
1289
1295
|
return (_jsx(PDFViewerInner, { ...innerProps, pdfFile: pdfFile, documentId: activeDocumentId, document: document }, activeDocumentId));
|
|
1290
1296
|
}
|
|
1291
|
-
export const PDFViewer = React.forwardRef(function PDFViewer({ className, defaultZoom = DEFAULT_ZOOM, fitOnOpen, fileName, showDownload = true, showRotateControls = true, showToolbar = true, showUpload = true, src, toolbarActions, pageClassName, renderPageOverlay, onActivePageChange, onDocumentLoadSuccess, onPdfUpload, onPagePointerDown, onPagePointerMove, onPagePointerUp, onPagePointerCancel, }, ref) {
|
|
1297
|
+
export const PDFViewer = React.forwardRef(function PDFViewer({ className, defaultZoom = DEFAULT_ZOOM, fitOnOpen, fileName, showDownload = true, showRotateControls = true, showToolbar = true, showUpload = true, src, toolbarActions, findText, pageClassName, renderPageOverlay, onActivePageChange, onDocumentLoadSuccess, onPdfUpload, onPagePointerDown, onPagePointerMove, onPagePointerUp, onPagePointerCancel, }, ref) {
|
|
1292
1298
|
const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
|
|
1293
1299
|
const { engine, error: engineError } = useSharedPdfEngine();
|
|
1294
1300
|
const [uploadedPdfFile, setUploadedPdfFile] = React.useState(() => ({ src, url: null }));
|
|
@@ -1348,5 +1354,8 @@ export const PDFViewer = React.forwardRef(function PDFViewer({ className, defaul
|
|
|
1348
1354
|
if (!engine) {
|
|
1349
1355
|
return (_jsxs("div", { "data-slot": "pdf-viewer", className: cn('bg-background relative flex h-full max-h-full min-h-0 w-full flex-col overflow-hidden', className), children: [showToolbar ? _jsx("div", { className: "bg-background min-h-12 border-b" }) : null, _jsx("div", { className: "relative min-h-0 flex-1", children: _jsx(PDFViewerLoadingSkeleton, { sidebarInline: true, sidebarOpen: false }) })] }));
|
|
1350
1356
|
}
|
|
1351
|
-
return (_jsx(EmbedPDF, { engine: engine, plugins: plugins, children: _jsx(PDFViewerDocumentLoader, { viewerRef: ref, pdfFile: pdfFile,
|
|
1357
|
+
return (_jsx(EmbedPDF, { engine: engine, plugins: plugins, children: _jsx(PDFViewerDocumentLoader, { viewerRef: ref, pdfFile: pdfFile,
|
|
1358
|
+
// The same level the plugin starts at: a numeric default here would undo `fitOnOpen`
|
|
1359
|
+
// as soon as the document loads (the page opened at 100% and overflowed a narrow pane).
|
|
1360
|
+
defaultZoom: selectPdfZoomLevel(fitOnOpen, defaultZoom), className: className, fileName: fileName, showDownload: showDownload, showToolbar: showToolbar, showRotateControls: showRotateControls, showUpload: showUpload, toolbarActions: toolbarActions, findText: findText, pageClassName: pageClassName, renderPageOverlay: renderPageOverlay, onActivePageChange: onActivePageChange, onDocumentLoadSuccess: onDocumentLoadSuccess, onPdfUpload: onPdfUpload, onPagePointerDown: onPagePointerDown, onPagePointerMove: onPagePointerMove, onPagePointerUp: onPagePointerUp, onPagePointerCancel: onPagePointerCancel, onUploadFile: handleUploadFile }) }));
|
|
1352
1361
|
});
|
|
@@ -19,11 +19,9 @@ export function FullScreenPresentationViewer({ isOpen, onClose, presentationName
|
|
|
19
19
|
const [metadata, setMetadata] = useState(null);
|
|
20
20
|
const [currentSlide, setCurrentSlide] = useState(initialSlide);
|
|
21
21
|
const [isLoading, setIsLoading] = useState(false);
|
|
22
|
-
const [error, setError] = useState(null);
|
|
23
22
|
const [retryAttempt, setRetryAttempt] = useState(0);
|
|
24
23
|
const retryTimeoutRef = useRef(null);
|
|
25
24
|
const hasLoadedRef = useRef(false);
|
|
26
|
-
const [showControls, setShowControls] = useState(true);
|
|
27
25
|
const [showEditor, setShowEditor] = useState(false);
|
|
28
26
|
const [isDownloadingPDF, setIsDownloadingPDF] = useState(false);
|
|
29
27
|
const [isDownloadingPPTX, setIsDownloadingPPTX] = useState(false);
|
|
@@ -57,7 +55,6 @@ export function FullScreenPresentationViewer({ isOpen, onClose, presentationName
|
|
|
57
55
|
return;
|
|
58
56
|
}
|
|
59
57
|
setIsLoading(true);
|
|
60
|
-
setError(null);
|
|
61
58
|
setRetryAttempt(retryCount);
|
|
62
59
|
try {
|
|
63
60
|
// Sanitize the presentation name to match backend directory creation
|
|
@@ -218,12 +215,6 @@ export function FullScreenPresentationViewer({ isOpen, onClose, presentationName
|
|
|
218
215
|
document.addEventListener('keydown', handleKeyDown, true);
|
|
219
216
|
return () => document.removeEventListener('keydown', handleKeyDown, true);
|
|
220
217
|
}, [isOpen, goToNextSlide, goToPreviousSlide, totalSlides, onClose, showEditor]);
|
|
221
|
-
// Always show controls
|
|
222
|
-
useEffect(() => {
|
|
223
|
-
if (isOpen) {
|
|
224
|
-
setShowControls(true);
|
|
225
|
-
}
|
|
226
|
-
}, [isOpen]);
|
|
227
218
|
// Download handlers
|
|
228
219
|
const handleDownload = async (format) => {
|
|
229
220
|
if (isDownloadRestricted) {
|
|
@@ -322,7 +313,7 @@ export function FullScreenPresentationViewer({ isOpen, onClose, presentationName
|
|
|
322
313
|
});
|
|
323
314
|
SlideIframeComponent.displayName = 'SlideIframeComponent';
|
|
324
315
|
return SlideIframeComponent;
|
|
325
|
-
}, [sandboxUrl, refreshTimestamp, showEditor, subdomainOpts, tHardcodedUi]);
|
|
316
|
+
}, [sandboxUrl, refreshTimestamp, showEditor, subdomainOpts, tHardcodedUi, tI18nComplete]);
|
|
326
317
|
if (!isOpen)
|
|
327
318
|
return null;
|
|
328
319
|
// Render slide iframe with proper scaling
|
|
@@ -331,7 +322,7 @@ export function FullScreenPresentationViewer({ isOpen, onClose, presentationName
|
|
|
331
322
|
? tHardcodedUi.raw('i18nComplete.textbd0b7be215ce')
|
|
332
323
|
: tHardcodedUi.raw('i18nComplete.text8268dd9ea939'), onClick: () => setShowEditor(!showEditor), children: showEditor ? (_jsx(Presentation, { className: "h-3.5 w-3.5" })) : (_jsx(Edit, { className: "h-3.5 w-3.5" })) }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "sm", className: "w-8 p-0", title: tHardcodedUi.raw('componentsThreadToolViewsPresentationToolsFullscreenpresentationviewer.line485JsxAttrTitleExportPresentation'), disabled: isDownloadingPDF || isDownloadingPPTX, children: isDownloadingPDF || isDownloadingPPTX ? (_jsx(KortixLoader, { customSize: 14 })) : (_jsx(Download, { className: "h-3.5 w-3.5" })) }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-32", children: [_jsxs(DropdownMenuItem, { className: "cursor-pointer", onClick: () => handleDownload(DownloadFormat.PDF), disabled: isDownloadingPDF, children: [_jsx(FileText, { className: "mr-2 h-4 w-4" }), "PDF"] }), _jsxs(DropdownMenuItem, { className: "cursor-pointer", onClick: () => handleDownload(DownloadFormat.PPTX), disabled: isDownloadingPPTX, children: [_jsx(Presentation, { className: "mr-2 h-4 w-4" }), "PPTX"] })] })] }), _jsx(Button, { variant: "ghost", size: "sm", onClick: onClose, className: "h-8 w-8 p-0", title: tHardcodedUi.raw('componentsThreadToolViewsPresentationToolsFullscreenpresentationviewer.line529JsxAttrTitleCloseFullScreen'), children: _jsx(X, { className: "h-3.5 w-3.5" }) })] })] }) }), _jsx("div", { className: "flex min-h-0 flex-1 items-center justify-center bg-zinc-100 p-2 dark:bg-zinc-900", children: isLoading || !currentSlideData ? (_jsxs("div", { className: "text-center", children: [_jsx(KortixLoader, { size: "large", className: "mx-auto mb-4" }), _jsx("p", { className: "text-zinc-700 dark:text-zinc-300", children: retryAttempt > 0
|
|
333
324
|
? tI18nComplete('text3df439a7a73b', { value0: retryAttempt + 1 })
|
|
334
|
-
: tHardcodedUi.raw('i18nComplete.text1ac9fe8126fa') })] })) : currentSlideData ? (_jsxs("div", { className: "flex h-full w-full flex-col", children: [_jsx("div", { className: "flex-1 overflow-hidden rounded-xl bg-transparent", style: { aspectRatio: '16 / 9' }, children: renderSlide }), _jsxs("div", { className: "mt-3 flex items-center justify-between px-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: () => setCurrentSlide(1), disabled: currentSlide <= 1, className: "h-8 w-8 p-0 disabled:opacity-50", children: _jsx(SkipBack, { className: "h-3.5 w-3.5" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: goToPreviousSlide, disabled: currentSlide <= 1, className: "h-8 w-8 p-0 disabled:opacity-50", children: _jsx(ChevronLeft, { className: "h-4 w-4" }) })] }), _jsx("div", { className: "flex items-center", children: _jsx("div", { className: "flex gap-2", children: slides.map((slide) => (_jsx("button", { onClick: () => setCurrentSlide(slide.number), className: cn('h-2.5 w-2.5 rounded-full transition-colors duration-200', slide.number === currentSlide
|
|
325
|
+
: tHardcodedUi.raw('i18nComplete.text1ac9fe8126fa') })] })) : currentSlideData ? (_jsxs("div", { className: "flex h-full w-full flex-col", children: [_jsx("div", { className: "flex-1 overflow-hidden rounded-xl bg-transparent", style: { aspectRatio: '16 / 9' }, children: renderSlide }), _jsxs("div", { className: "mt-3 flex items-center justify-between px-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: () => setCurrentSlide(1), disabled: currentSlide <= 1, className: "h-8 w-8 p-0 disabled:opacity-50", children: _jsx(SkipBack, { className: "h-3.5 w-3.5" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: goToPreviousSlide, disabled: currentSlide <= 1, className: "h-8 w-8 p-0 disabled:opacity-50", children: _jsx(ChevronLeft, { className: "h-4 w-4" }) })] }), _jsx("div", { className: "flex items-center", children: _jsx("div", { className: "flex gap-2", children: slides.map((slide) => (_jsx("button", { "aria-label": `${tHardcodedUi.raw('i18nComplete.text6bb4c1177681')} ${slide.number}`, onClick: () => setCurrentSlide(slide.number), className: cn('h-2.5 w-2.5 rounded-full transition-colors duration-200', slide.number === currentSlide
|
|
335
326
|
? 'bg-black dark:bg-white'
|
|
336
327
|
: 'bg-zinc-300 hover:bg-zinc-400 dark:bg-zinc-600 dark:hover:bg-zinc-500') }, slide.number))) }) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: goToNextSlide, disabled: currentSlide >= totalSlides, className: "h-8 w-8 p-0 disabled:opacity-50", children: _jsx(ChevronRight, { className: "h-4 w-4" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setCurrentSlide(totalSlides), disabled: currentSlide >= totalSlides, className: "h-8 w-8 p-0 disabled:opacity-50", children: _jsx(SkipForward, { className: "h-3.5 w-3.5" }) })] })] })] })) : (_jsx("div", { className: "text-center", children: _jsx("p", { className: "text-zinc-700 dark:text-zinc-300", children: tHardcodedUi.raw('componentsThreadToolViewsPresentationToolsFullscreenpresentationviewer.line621JsxTextNoSlideFound') }) })) })] }));
|
|
337
328
|
}
|
|
@@ -692,7 +692,7 @@ export function ShowCarousel({ items, LocalhostPreview, onIndexChange, fill = fa
|
|
|
692
692
|
const currentItem = items[currentIndex];
|
|
693
693
|
if (!currentItem)
|
|
694
694
|
return null;
|
|
695
|
-
return (_jsxs("div", { className: cn('outline-none', fill && 'flex h-full flex-col'),
|
|
695
|
+
return (_jsxs("div", { role: "group", className: cn('outline-none', fill && 'flex h-full flex-col'),
|
|
696
696
|
// -1: a click on the content focuses the card, so ←/→ page it next,
|
|
697
697
|
// without adding a Tab stop. Tab still reaches the chevrons inside.
|
|
698
698
|
tabIndex: fill || count < 2 ? undefined : -1, onKeyDown: fill || count < 2 ? undefined : (e) => handleArrowKey(e), children: [_jsx("div", { className: cn(fill ? 'min-h-0 flex-1 overflow-hidden' : 'min-h-[420px]'), children: currentItem.status === 'pending' ? (_jsxs("div", { className: cn('flex items-center justify-center gap-3', fill ? 'h-full' : 'min-h-[420px]'), children: [_jsx(Loading, { className: "text-muted-foreground size-4" }), _jsx(TextShimmer, { duration: 1, spread: 2, className: "text-sm", children: tHardcodedUi.raw('componentsSessionToolRenderers.line4935JsxTextPreparingOutput') })] })) : (_jsx(ShowContentRenderer, { type: currentItem.type, title: currentItem.title, description: currentItem.description, path: currentItem.path, url: currentItem.url, content: currentItem.content, language: currentItem.language, aspectRatio: currentItem.aspect_ratio, attachment: currentItem.attachment, LocalhostPreview: LocalhostPreview, toolbarActions: toolbarActions, fill: fill })) }), count > 1 && !hideNav && (_jsxs("div", { className: "border-border flex shrink-0 items-center gap-2 border-t px-2 py-1.5 pr-3.5", children: [_jsxs("div", { className: "flex shrink-0 items-center", children: [_jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: prev, className: "hit-area-2 hit-area-r-0 transition-transform active:scale-[0.96]", disabled: currentIndex === 0, "aria-label": tI18nComplete.raw('text81b35f1b4332'), children: _jsx(ChevronLeft, { className: "size-4" }) }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: next, className: "hit-area-2 hit-area-l-0 transition-transform active:scale-[0.96]", disabled: currentIndex >= count - 1, "aria-label": tI18nComplete.raw('text1e47d4f7a1a3'), children: _jsx(ChevronRight, { className: "size-4" }) })] }), _jsx(FadedScrollArea, { ref: stripRef, orientation: "horizontal", fadeColor: "from-secondary", className: "min-w-0 flex-1 overscroll-x-contain", children: _jsx("div", { className: "flex w-max min-w-0 items-center gap-1", children: items.map((item, i) => {
|