@kortix/ui 0.14.9 → 0.14.10
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/dist/_vendor/kortix-shared.js +55 -2
- package/dist/_vendor/shared/artifact-comments.d.ts +235 -0
- package/dist/_vendor/shared/channel-descriptors.d.ts +96 -0
- package/dist/_vendor/shared/channel-message.d.ts +13 -2
- package/dist/_vendor/shared/index.d.ts +1 -0
- package/dist/apps/app-preview-pool.js +19 -2
- package/dist/artifacts/artifact-frame.js +7 -3
- package/dist/customize/sections/component/channel-access-panel.js +4 -4
- package/dist/customize/sections/component/telegram-channel-row.js +7 -5
- package/dist/customize/sections/view/agent-editor-catalog.js +5 -0
- package/dist/customize/sections/view/channels-view.d.ts +2 -1
- package/dist/customize/sections/view/channels-view.js +12 -7
- package/dist/customize/settings/rail.js +9 -0
- package/dist/customize/settings/settings-tabs.d.ts +1 -1
- package/dist/customize/settings/settings-tabs.js +1 -0
- package/dist/customize/settings/tabs/chrome-connections-tab.d.ts +6 -0
- package/dist/customize/settings/tabs/chrome-connections-tab.js +99 -0
- package/dist/customize/shared/catalog/catalog-empty-state.d.ts +3 -3
- package/dist/customize/shared/catalog/catalog-empty-state.js +6 -4
- package/dist/files/renderers/image-frame.d.ts +3 -1
- package/dist/files/renderers/image-frame.js +2 -2
- package/dist/i18n/en.d.ts +189 -0
- package/dist/i18n/en.js +190 -1
- package/dist/internal/apps-and-extensions/apps-modal.d.ts +9 -0
- package/dist/internal/apps-and-extensions/apps-modal.js +107 -0
- package/dist/internal/chrome/browser-icon.d.ts +24 -0
- package/dist/internal/chrome/browser-icon.js +58 -0
- package/dist/internal/chrome/chrome-card-state.d.ts +16 -0
- package/dist/internal/chrome/chrome-card-state.js +9 -0
- package/dist/internal/chrome/chrome-connect.d.ts +69 -0
- package/dist/internal/chrome/chrome-connect.js +178 -0
- package/dist/internal/chrome/chrome-mock.d.ts +4 -0
- package/dist/internal/chrome/chrome-mock.js +15 -0
- package/dist/internal/chrome/chrome-names.d.ts +15 -0
- package/dist/internal/chrome/chrome-names.js +35 -0
- package/dist/internal/chrome/extension.d.ts +47 -0
- package/dist/internal/chrome/extension.js +91 -0
- package/dist/internal/chrome/use-chrome-offered.d.ts +11 -0
- package/dist/internal/chrome/use-chrome-offered.js +22 -0
- package/dist/internal/connector-logo/connector-logo-source.d.ts +2 -1
- package/dist/internal/connector-logo/connector-logo-source.js +7 -6
- package/dist/internal/icons/edge.d.ts +5 -0
- package/dist/internal/icons/edge.js +10 -0
- package/dist/internal/lib/browser-noise/rules/extensions.js +17 -3
- package/dist/internal/lib/detect-os.d.ts +43 -0
- package/dist/internal/lib/detect-os.js +70 -0
- package/dist/internal/lib/use-project-feature-flags.js +5 -1
- package/dist/internal/stores/apps-modal-store.d.ts +8 -0
- package/dist/internal/stores/apps-modal-store.js +6 -0
- package/dist/internal/stores/composer-prefill-store.d.ts +12 -5
- package/dist/markdown/setup-links/approval-decision.js +3 -1
- package/dist/primitives/empty-state.d.ts +2 -2
- package/dist/primitives/empty-state.js +6 -5
- package/dist/primitives/mermaid-renderer.js +1 -1
- package/dist/session/panel/session-audit-shared.js +3 -1
- package/dist/session/participants/session-participants.d.ts +3 -1
- package/dist/session/participants/session-participants.js +2 -2
- package/dist/session/prompts/approval-request.js +2 -0
- package/dist/session/thread/session-thread.d.ts +13 -1
- package/dist/session/thread/session-thread.js +15 -5
- package/dist/session/thread/session-transcript-class.d.ts +5 -1
- package/dist/session/thread/session-transcript-class.js +5 -1
- package/dist/session/tool/tools/image-gen-tool.js +4 -3
- package/dist/session/turn/user-message.d.ts +7 -5
- package/dist/session/turn/user-message.js +14 -8
- package/dist/styles.css +1 -1
- package/dist/workspace/sessions/session-label-badges.js +2 -1
- package/dist/workspace/sidebar/footer/project-chrome-nav.d.ts +10 -0
- package/dist/workspace/sidebar/footer/project-chrome-nav.js +56 -0
- package/dist/workspace/sidebar/project-sidebar.js +5 -1
- package/package.json +43 -3
- package/skills/kortix-ui/references/modules.md +1 -1
package/dist/i18n/en.js
CHANGED
|
@@ -372,6 +372,10 @@ const catalog = {
|
|
|
372
372
|
"connected": {
|
|
373
373
|
"label": "Connected accounts"
|
|
374
374
|
},
|
|
375
|
+
"chrome": {
|
|
376
|
+
"label": "Kortix in Chrome",
|
|
377
|
+
"description": "Your sessions use Chrome with your logins. You see every step."
|
|
378
|
+
},
|
|
375
379
|
"tokens": {
|
|
376
380
|
"label": "Personal access keys",
|
|
377
381
|
"description": "API keys that act as you — for the CLI, a script, or a CI job."
|
|
@@ -835,6 +839,14 @@ const catalog = {
|
|
|
835
839
|
"session_groups": {
|
|
836
840
|
"name": "Session groups",
|
|
837
841
|
"description": "Group the sidebar's sessions into named folders that everyone in the project shares, for example one per store or client. Move a session into a group from its menu or by dragging it; reorder and collapse the groups."
|
|
842
|
+
},
|
|
843
|
+
"artifact_comments": {
|
|
844
|
+
"name": "Artifact comments",
|
|
845
|
+
"description": "Discuss docs and pages in threads with people and agents. Requires Artifacts."
|
|
846
|
+
},
|
|
847
|
+
"chrome": {
|
|
848
|
+
"name": "Kortix in Chrome",
|
|
849
|
+
"description": "Let a session use your connected Chrome browser. You can take over or stop it at any time."
|
|
838
850
|
}
|
|
839
851
|
},
|
|
840
852
|
"channelsSwitch": {
|
|
@@ -1161,7 +1173,8 @@ const catalog = {
|
|
|
1161
1173
|
"account": "Account",
|
|
1162
1174
|
"loadError": "Failed to load projects",
|
|
1163
1175
|
"createIn": "Create a project in {account}",
|
|
1164
|
-
"localComputer": "Your computer"
|
|
1176
|
+
"localComputer": "Your computer",
|
|
1177
|
+
"appsAndExtensions": "Apps and extensions"
|
|
1165
1178
|
},
|
|
1166
1179
|
"manifestUpgrade": {
|
|
1167
1180
|
"title": "Upgrade to v3",
|
|
@@ -1772,6 +1785,13 @@ const catalog = {
|
|
|
1772
1785
|
"updateFailed": "Could not update password",
|
|
1773
1786
|
"unexpected": "An unexpected error occurred"
|
|
1774
1787
|
}
|
|
1788
|
+
},
|
|
1789
|
+
"panel": {
|
|
1790
|
+
"waitingTitle": "Signing you in",
|
|
1791
|
+
"waitingBody": "Connecting this panel to your Kortix account.",
|
|
1792
|
+
"errorTitle": "Couldn't sign in",
|
|
1793
|
+
"errorBody": "Sign in to Kortix in a browser tab, then reopen this panel.",
|
|
1794
|
+
"signIn": "Sign in"
|
|
1775
1795
|
}
|
|
1776
1796
|
},
|
|
1777
1797
|
"tools": {
|
|
@@ -6778,6 +6798,127 @@ const catalog = {
|
|
|
6778
6798
|
"calendarEstimatedSr": "Past fire, estimated from the schedule",
|
|
6779
6799
|
"calendarUpcomingSr": "Upcoming"
|
|
6780
6800
|
},
|
|
6801
|
+
"chrome": {
|
|
6802
|
+
"pill": "Kortix in Chrome",
|
|
6803
|
+
"connectTitle": "Add Kortix to Chrome",
|
|
6804
|
+
"connectDescription": "Let your sessions use Chrome, with your logins. You see what they do and can stop them at any time.",
|
|
6805
|
+
"promoLabel": "Kortix in Chrome",
|
|
6806
|
+
"dismissPromo": "Dismiss",
|
|
6807
|
+
"steps": {
|
|
6808
|
+
"install": {
|
|
6809
|
+
"title": "Add the extension",
|
|
6810
|
+
"description": "From the Chrome Web Store.",
|
|
6811
|
+
"done": "Kortix is in Chrome.",
|
|
6812
|
+
"descriptionUnlisted": "Load it in Chrome."
|
|
6813
|
+
},
|
|
6814
|
+
"connect": {
|
|
6815
|
+
"title": "Sign in",
|
|
6816
|
+
"description": "Sign in to Kortix from the extension.",
|
|
6817
|
+
"done": "Signed in."
|
|
6818
|
+
},
|
|
6819
|
+
"done": {
|
|
6820
|
+
"title": "Connected",
|
|
6821
|
+
"description": "Your browser appears here."
|
|
6822
|
+
}
|
|
6823
|
+
},
|
|
6824
|
+
"addToChrome": "Add to Chrome",
|
|
6825
|
+
"finishInChrome": "Chrome opened a Kortix tab. Click Connect there.",
|
|
6826
|
+
"connect": "Connect",
|
|
6827
|
+
"connecting": "Connecting…",
|
|
6828
|
+
"done": "Done",
|
|
6829
|
+
"unsupported": "Open Kortix in Chrome, Edge, Brave or Arc to connect it. Copy the link to open it there.",
|
|
6830
|
+
"connectFailed": "Could not connect the browser. Try again.",
|
|
6831
|
+
"online": "Online",
|
|
6832
|
+
"offline": "Offline",
|
|
6833
|
+
"lastSeen": "Last seen {time}",
|
|
6834
|
+
"usedBy": "{count, plural, one {Used by # session now} other {Used by # sessions now}}",
|
|
6835
|
+
"connectAnother": "Add another browser",
|
|
6836
|
+
"listTitle": "Connected browsers",
|
|
6837
|
+
"rename": "Rename {name}",
|
|
6838
|
+
"renameLabel": "Browser name",
|
|
6839
|
+
"disconnect": "Disconnect",
|
|
6840
|
+
"disconnectTitle": "Disconnect {name}?",
|
|
6841
|
+
"disconnectDescription": "Sessions that use it stop. To use it again, connect it from Chrome.",
|
|
6842
|
+
"disconnected": "Browser disconnected",
|
|
6843
|
+
"disconnectFailed": "Could not disconnect the browser. Try again.",
|
|
6844
|
+
"updateFailed": "Could not save the change. Try again.",
|
|
6845
|
+
"loadFailed": "Could not load your browsers.",
|
|
6846
|
+
"retry": "Try again",
|
|
6847
|
+
"access": {
|
|
6848
|
+
"label": "Access",
|
|
6849
|
+
"always": "Without asking",
|
|
6850
|
+
"ask": "Ask first",
|
|
6851
|
+
"off": "Off",
|
|
6852
|
+
"description": "Whether a session asks you first."
|
|
6853
|
+
},
|
|
6854
|
+
"scope": {
|
|
6855
|
+
"label": "Tabs",
|
|
6856
|
+
"own": "Only tabs it opens",
|
|
6857
|
+
"all": "All tabs",
|
|
6858
|
+
"description": "Which tabs a session can see."
|
|
6859
|
+
},
|
|
6860
|
+
"how": {
|
|
6861
|
+
"title": "How it works",
|
|
6862
|
+
"group": "Each session works in its own tab group, with a glow on the page.",
|
|
6863
|
+
"control": "Take over or Stop from the bar on the page at any time.",
|
|
6864
|
+
"own": "Only your own sessions can use your browser."
|
|
6865
|
+
},
|
|
6866
|
+
"howToInstall": "How to install",
|
|
6867
|
+
"copyLink": "Copy link",
|
|
6868
|
+
"linkCopied": "Link copied",
|
|
6869
|
+
"copyFailed": "Could not copy the link. Try again.",
|
|
6870
|
+
"extensionMissing": "Kortix did not find the extension. Add it, then reload this page.",
|
|
6871
|
+
"another": {
|
|
6872
|
+
"title": "Another browser",
|
|
6873
|
+
"waiting": "Waiting for the new browser to connect.",
|
|
6874
|
+
"description": "Open Kortix in the other browser or Chrome profile, then add Kortix to Chrome there. Copy the link to open it."
|
|
6875
|
+
},
|
|
6876
|
+
"panel": {
|
|
6877
|
+
"project": "Project",
|
|
6878
|
+
"title": "Ask about this page",
|
|
6879
|
+
"body": "Kortix reads the tab when you send. Nothing leaves this browser before that.",
|
|
6880
|
+
"selectionTitle": "Ask about your selection",
|
|
6881
|
+
"selectionBody": "Kortix gets the quote, the page title and the address. The rest of the page stays in this browser unless you add it.",
|
|
6882
|
+
"actions": {
|
|
6883
|
+
"summarize": "Summarize this page",
|
|
6884
|
+
"tables": "Extract the tables",
|
|
6885
|
+
"compare": "Compare with another tab",
|
|
6886
|
+
"email": "Draft an email about this"
|
|
6887
|
+
},
|
|
6888
|
+
"prompts": {
|
|
6889
|
+
"summarize": "Summarize this page.",
|
|
6890
|
+
"tables": "Extract the tables on this page as CSV.",
|
|
6891
|
+
"compare": "Compare these pages.",
|
|
6892
|
+
"email": "Draft an email about this page."
|
|
6893
|
+
},
|
|
6894
|
+
"recent": "Recent in {project}",
|
|
6895
|
+
"noProjects": "Create a project to start a chat.",
|
|
6896
|
+
"createProject": "Create a project",
|
|
6897
|
+
"addTab": "Tab",
|
|
6898
|
+
"addTabsTitle": "Add tabs",
|
|
6899
|
+
"addTabsHint": "Only the tabs you tick are sent.",
|
|
6900
|
+
"addTabs": "{count, plural, =0 {Add tabs} one {Add # tab} other {Add # tabs}}",
|
|
6901
|
+
"noTabs": "No other tabs in this window.",
|
|
6902
|
+
"tabsFailed": "Could not list your tabs. Try again.",
|
|
6903
|
+
"cancel": "Cancel",
|
|
6904
|
+
"removeTab": "Remove {title}",
|
|
6905
|
+
"removeQuote": "Remove the quote",
|
|
6906
|
+
"wholePage": "Whole page",
|
|
6907
|
+
"unreadable": "Kortix cannot read this page.",
|
|
6908
|
+
"message": "Message",
|
|
6909
|
+
"placeholder": "Ask anything about this tab",
|
|
6910
|
+
"placeholderNoTab": "Ask Kortix anything",
|
|
6911
|
+
"modeLabel": "How Kortix uses the tab",
|
|
6912
|
+
"read": "Read",
|
|
6913
|
+
"act": "Act",
|
|
6914
|
+
"readHint": "Read sends this page's text. Act lets Kortix click and type in this tab.",
|
|
6915
|
+
"actHint": "Kortix puts this tab in its tab group and can click and type there. Stop it from the bar on the page.",
|
|
6916
|
+
"send": "Send",
|
|
6917
|
+
"readFailed": "Kortix could not read the tab. Reload the page and try again.",
|
|
6918
|
+
"screenshot": "Screenshot",
|
|
6919
|
+
"captureFailed": "Kortix could not take a screenshot of this tab."
|
|
6920
|
+
}
|
|
6921
|
+
},
|
|
6781
6922
|
"computers": {
|
|
6782
6923
|
"connectYourComputer": "Connect your computer",
|
|
6783
6924
|
"connectThisComputer": "Connect this computer",
|
|
@@ -8087,6 +8228,54 @@ const catalog = {
|
|
|
8087
8228
|
"unavailable": "Image unavailable",
|
|
8088
8229
|
"tryAgain": "Try again",
|
|
8089
8230
|
"details": "Image details"
|
|
8231
|
+
},
|
|
8232
|
+
"appsModal": {
|
|
8233
|
+
"title": "Apps and extensions",
|
|
8234
|
+
"subtitle": "Use Kortix in your browser, on your computer and from your tools.",
|
|
8235
|
+
"mock": {
|
|
8236
|
+
"group": "Kortix · Return my order",
|
|
8237
|
+
"button": "Start return",
|
|
8238
|
+
"working": "Kortix is working",
|
|
8239
|
+
"takeOver": "Take over",
|
|
8240
|
+
"stop": "Stop"
|
|
8241
|
+
},
|
|
8242
|
+
"chrome": {
|
|
8243
|
+
"name": "Kortix in Chrome",
|
|
8244
|
+
"description": "Kortix opens pages, clicks and fills forms in your own browser, with your logins. You see every step.",
|
|
8245
|
+
"connect": "Connect",
|
|
8246
|
+
"connecting": "Connecting…",
|
|
8247
|
+
"manage": "Manage",
|
|
8248
|
+
"unsupported": "Open Kortix in Chrome, Edge, Brave or Arc to add it. Copy the link to open it there.",
|
|
8249
|
+
"group": "Browser",
|
|
8250
|
+
"manageLabel": "Manage Kortix in Chrome",
|
|
8251
|
+
"summary": "{count, plural, one {# browser} other {# browsers}} · {online} online"
|
|
8252
|
+
},
|
|
8253
|
+
"computer": {
|
|
8254
|
+
"title": "Your computer",
|
|
8255
|
+
"thisComputer": "This computer",
|
|
8256
|
+
"thisComputerDescription": "Let sessions use your files and terminal.",
|
|
8257
|
+
"connected": "Connected",
|
|
8258
|
+
"connect": "Connect",
|
|
8259
|
+
"manage": "Manage",
|
|
8260
|
+
"desktop": "Desktop app",
|
|
8261
|
+
"desktopDescription": "Kortix as an app on your computer.",
|
|
8262
|
+
"desktopRunning": "You are using it.",
|
|
8263
|
+
"download": "Download",
|
|
8264
|
+
"manageLabel": "Manage this computer",
|
|
8265
|
+
"connectLabel": "Connect this computer"
|
|
8266
|
+
},
|
|
8267
|
+
"developers": {
|
|
8268
|
+
"title": "Developers",
|
|
8269
|
+
"cli": "Terminal (CLI)",
|
|
8270
|
+
"cliDescription": "macOS and Linux, WSL on Windows",
|
|
8271
|
+
"copy": "Copy command",
|
|
8272
|
+
"copied": "Copied",
|
|
8273
|
+
"mcp": "MCP",
|
|
8274
|
+
"mcpDescription": "Use Kortix from Claude, Cursor or Codex.",
|
|
8275
|
+
"connect": "Connect",
|
|
8276
|
+
"connectLabel": "Connect MCP",
|
|
8277
|
+
"copyFailed": "Could not copy the command. Try again."
|
|
8278
|
+
}
|
|
8090
8279
|
}
|
|
8091
8280
|
};
|
|
8092
8281
|
export default catalog;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** @internal Kortix apps only. No semver: it may change in any release. */
|
|
2
|
+
/** Opens the dialog from `?apps=1` and removes the parameter. */
|
|
3
|
+
export declare function useAppsDeepLink(): void;
|
|
4
|
+
export declare function AppsModal({ chrome, onOpenComputer, onOpenMcp, }: {
|
|
5
|
+
/** The project's `chrome` flag: the Kortix in Chrome card shows only with it on. */
|
|
6
|
+
chrome: boolean;
|
|
7
|
+
onOpenComputer: () => void;
|
|
8
|
+
onOpenMcp: () => void;
|
|
9
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* "Apps and extensions": every way to use Kortix outside this tab, in one
|
|
5
|
+
* dialog. Chrome first, then the computer, then the developer surfaces. Each
|
|
6
|
+
* row opens the dialog that already owns the flow (computer, MCP, Settings →
|
|
7
|
+
* Kortix in Chrome); nothing here pairs or connects by itself.
|
|
8
|
+
*
|
|
9
|
+
* It is mounted once, in the project sidebar, next to its only triggers: the
|
|
10
|
+
* workspace menu row, the sidebar row and `?apps=1`. Outside a project there is
|
|
11
|
+
* no workspace menu and no sidebar, so `?apps=1` there does nothing.
|
|
12
|
+
*/
|
|
13
|
+
import { useChromeConnections } from '@kortix/sdk/react';
|
|
14
|
+
import { ArrowUpRightIcon, DownloadSimpleIcon, LaptopIcon, MonitorIcon, PlugsConnectedIcon, TerminalWindowIcon, } from '@phosphor-icons/react';
|
|
15
|
+
import { useEffect, useId } from 'react';
|
|
16
|
+
import { Button } from '../../primitives/button.js';
|
|
17
|
+
import { Modal, ModalContent, ModalDescription, ModalTitle } from '../../primitives/modal.js';
|
|
18
|
+
import { ChromeCopyLink, ChromeInstallActions, ChromeOnlineDot, useChromeConnect, } from '../chrome/chrome-connect.js';
|
|
19
|
+
import { BrowserLogoTile } from '../chrome/browser-icon.js';
|
|
20
|
+
import { ChromeMock } from '../chrome/chrome-mock.js';
|
|
21
|
+
import { chromeCardState } from '../chrome/chrome-card-state.js';
|
|
22
|
+
import { chromeCounts } from '../chrome/chrome-names.js';
|
|
23
|
+
import { SolidCheckIcon } from '../icons/solid-check-icon.js';
|
|
24
|
+
import { detectPlatform, isMobilePlatform } from '../lib/detect-os.js';
|
|
25
|
+
import { useOwnsPairedComputer } from '../tunnel/computer-connect.js';
|
|
26
|
+
import { errorToast } from '../../primitives/toast.js';
|
|
27
|
+
import { useCopy } from '../hooks/use-copy.js';
|
|
28
|
+
import { useTranslations } from '../../i18n/index.js';
|
|
29
|
+
import { desktopDownloadUrl, isDesktop } from '../lib/desktop.js';
|
|
30
|
+
import { useUiHostConfig, useUiPathname, useUiRouter, useUiSearchParams, } from '../../providers/ui-provider.js';
|
|
31
|
+
import { useDeploymentCliInstallCommand } from '../lib/use-deployment-cli-install-command.js';
|
|
32
|
+
import { useAppsModalStore } from '../stores/apps-modal-store.js';
|
|
33
|
+
import { useSettingsPanelStore } from '../stores/settings-panel-store.js';
|
|
34
|
+
/** Opens the dialog from `?apps=1` and removes the parameter. */
|
|
35
|
+
export function useAppsDeepLink() {
|
|
36
|
+
const params = useUiSearchParams();
|
|
37
|
+
const pathname = useUiPathname();
|
|
38
|
+
const router = useUiRouter();
|
|
39
|
+
const wanted = params.get('apps') === '1';
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (!wanted)
|
|
42
|
+
return;
|
|
43
|
+
useAppsModalStore.getState().setOpen(true);
|
|
44
|
+
const next = new URLSearchParams(params.toString());
|
|
45
|
+
next.delete('apps');
|
|
46
|
+
const query = next.toString();
|
|
47
|
+
router.replace(query ? `${pathname}?${query}` : pathname, { scroll: false });
|
|
48
|
+
}, [wanted, params, pathname, router]);
|
|
49
|
+
}
|
|
50
|
+
export function AppsModal({ chrome, onOpenComputer, onOpenMcp, }) {
|
|
51
|
+
const t = useTranslations('appsModal');
|
|
52
|
+
const open = useAppsModalStore((state) => state.open);
|
|
53
|
+
const setOpen = useAppsModalStore((state) => state.setOpen);
|
|
54
|
+
useAppsDeepLink();
|
|
55
|
+
// Close first, then hand over: one dialog on screen at a time.
|
|
56
|
+
const hand = (next) => () => {
|
|
57
|
+
setOpen(false);
|
|
58
|
+
next();
|
|
59
|
+
};
|
|
60
|
+
return (_jsx(Modal, { open: open, onOpenChange: setOpen, children: _jsx(ModalContent, { className: "max-h-[90dvh] space-y-0 overflow-y-auto lg:max-w-2xl", children: _jsxs("div", { className: "flex flex-col gap-6 p-5 lg:p-8", children: [_jsxs("header", { className: "space-y-1.5 pr-10", children: [_jsx(ModalTitle, { className: "text-xl font-medium text-balance", children: t('title') }), _jsx(ModalDescription, { className: "text-muted-foreground text-sm text-pretty", children: t('subtitle') })] }), open ? (_jsxs(_Fragment, { children: [chrome ? _jsx(ChromeSection, { onManage: () => setOpen(false) }) : null, _jsx(ComputerSection, { onOpenComputer: hand(onOpenComputer) }), _jsx(DevelopersSection, { onOpenMcp: hand(onOpenMcp) })] })) : null] }) }) }));
|
|
61
|
+
}
|
|
62
|
+
/** The hero decides from THIS browser first. Other browsers are one line plus Manage. */
|
|
63
|
+
function ChromeSection({ onManage }) {
|
|
64
|
+
const t = useTranslations('appsModal.chrome');
|
|
65
|
+
const state = useChromeConnect();
|
|
66
|
+
const { environment, checking, installed, signedIn, connected } = state;
|
|
67
|
+
const connections = useChromeConnections();
|
|
68
|
+
const { count, online } = chromeCounts(connections.data ?? []);
|
|
69
|
+
const cardState = chromeCardState({
|
|
70
|
+
thisBrowserConnected: Boolean(connected),
|
|
71
|
+
environment,
|
|
72
|
+
checking,
|
|
73
|
+
installed: installed || signedIn,
|
|
74
|
+
});
|
|
75
|
+
const manage = (_jsx(Button, { size: "sm", variant: "secondary", "aria-label": t('manageLabel'), onClick: () => {
|
|
76
|
+
onManage();
|
|
77
|
+
useSettingsPanelStore.getState().openSettings('chrome');
|
|
78
|
+
}, children: t('manage') }));
|
|
79
|
+
return (_jsxs("section", { "aria-labelledby": "apps-modal-browser", className: "space-y-3", children: [_jsx("h3", { id: "apps-modal-browser", className: "text-muted-foreground text-xs font-medium", children: t('group') }), _jsxs("div", { className: "grid items-center gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "flex min-w-0 flex-col gap-4", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(BrowserLogoTile, { brand: "chrome", className: "size-7", iconClassName: "size-4" }), _jsx("h4", { className: "text-base font-medium", children: t('name') })] }), _jsx("p", { className: "text-muted-foreground text-sm text-pretty", children: t('description') })] }), cardState === 'connected' && connected ? (_jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2", children: [manage, _jsxs("span", { className: "flex min-w-0 items-center gap-1.5 text-xs", children: [_jsx(ChromeOnlineDot, { online: connected.online }), _jsx("span", { className: "truncate", children: connected.name }), count > 1 ? (_jsxs("span", { className: "text-muted-foreground shrink-0", children: ["\u00B7 ", t('summary', { count, online })] })) : null] })] })) : (_jsxs(_Fragment, { children: [cardState === 'unsupported' ? (_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-muted-foreground text-xs text-pretty", children: t('unsupported') }), _jsx(ChromeCopyLink, {})] })) : (_jsx(ChromeInstallActions, { state: state })), count > 0 ? (_jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2", children: [_jsx("span", { className: "text-muted-foreground text-xs", children: t('summary', { count, online }) }), manage] })) : null] }))] }), _jsx(ChromeMock, {})] })] }));
|
|
80
|
+
}
|
|
81
|
+
function ComputerSection({ onOpenComputer }) {
|
|
82
|
+
const t = useTranslations('appsModal.computer');
|
|
83
|
+
const { owned } = useOwnsPairedComputer();
|
|
84
|
+
const live = owned.some((machine) => machine.isLive);
|
|
85
|
+
const inShell = typeof window !== 'undefined' && isDesktop();
|
|
86
|
+
const platform = typeof navigator === 'undefined' ? null : detectPlatform(navigator.userAgent);
|
|
87
|
+
const download = platform && !isMobilePlatform(platform) ? desktopDownloadUrl(platform) : desktopDownloadUrl();
|
|
88
|
+
return (_jsxs(Group, { title: t('title'), children: [_jsx(AppRow, { icon: LaptopIcon, name: t('thisComputer'), description: live ? (_jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx(ChromeOnlineDot, { online: true }), t('connected')] })) : (t('thisComputerDescription')), action: _jsx(Button, { size: "sm", variant: "secondary", "aria-label": t(live ? 'manageLabel' : 'connectLabel'), onClick: onOpenComputer, children: live ? t('manage') : t('connect') }) }), _jsx(AppRow, { icon: MonitorIcon, name: t('desktop'), description: inShell ? t('desktopRunning') : t('desktopDescription'), action: inShell ? null : (_jsx(Button, { asChild: true, size: "sm", variant: "secondary", className: "gap-1.5", children: _jsxs("a", { href: download, children: [_jsx(DownloadSimpleIcon, { className: "size-3.5 shrink-0" }), t('download')] }) })) })] }));
|
|
89
|
+
}
|
|
90
|
+
function DevelopersSection({ onOpenMcp }) {
|
|
91
|
+
const t = useTranslations('appsModal.developers');
|
|
92
|
+
const command = useDeploymentCliInstallCommand(useUiHostConfig().deploymentVersion);
|
|
93
|
+
const { copy, copied } = useCopy({ toast: false });
|
|
94
|
+
const copyCommand = async () => {
|
|
95
|
+
if (!(await copy(command)))
|
|
96
|
+
errorToast(t('copyFailed'));
|
|
97
|
+
};
|
|
98
|
+
return (_jsxs(Group, { title: t('title'), children: [_jsx(AppRow, { icon: TerminalWindowIcon, name: t('cli'), description: t('cliDescription'), action: _jsxs(Button, { size: "sm", variant: "secondary", className: "gap-1.5", onClick: copyCommand, children: [copied ? _jsx(SolidCheckIcon, { className: "size-3.5" }) : null, copied ? t('copied') : t('copy')] }) }), _jsx(AppRow, { icon: PlugsConnectedIcon, name: t('mcp'), description: t('mcpDescription'), action: _jsxs(Button, { size: "sm", variant: "secondary", className: "gap-1.5", "aria-label": t('connectLabel'), onClick: onOpenMcp, children: [t('connect'), _jsx(ArrowUpRightIcon, { className: "size-3.5 shrink-0" })] }) })] }));
|
|
99
|
+
}
|
|
100
|
+
/** A muted label over plain rows: no card, no border, one rule between rows. */
|
|
101
|
+
function Group({ title, children }) {
|
|
102
|
+
const id = useId();
|
|
103
|
+
return (_jsxs("section", { "aria-labelledby": id, className: "min-w-0 space-y-1", children: [_jsx("h3", { id: id, className: "text-muted-foreground text-xs font-medium", children: title }), _jsx("ul", { className: "divide-border divide-y", children: children })] }));
|
|
104
|
+
}
|
|
105
|
+
function AppRow({ icon: RowIcon, name, description, action, }) {
|
|
106
|
+
return (_jsxs("li", { className: "flex items-center gap-3 py-3", children: [_jsx("span", { className: "bg-muted flex size-9 shrink-0 items-center justify-center rounded-sm", children: _jsx(RowIcon, { className: "size-5" }) }), _jsxs("div", { className: "min-w-0 flex-1 space-y-0.5", children: [_jsx("p", { className: "text-sm font-medium", children: name }), _jsx("div", { className: "text-muted-foreground line-clamp-2 text-xs text-pretty", children: description })] }), action] }));
|
|
107
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** @internal Kortix apps only. No semver: it may change in any release. */
|
|
2
|
+
type BrowserKey = 'chrome' | 'brave' | 'arc' | 'opera' | 'vivaldi' | 'edge';
|
|
3
|
+
/** Maps the API's `brand` string (Chrome, Edge, Brave, Arc, Dia, …) to a mark. Any other Chromium browser gets Chrome. */
|
|
4
|
+
export declare function browserKey(brand: string | null | undefined): BrowserKey;
|
|
5
|
+
/**
|
|
6
|
+
* The browser's mark. `tone="brand"` paints the official color; `tone="current"`
|
|
7
|
+
* paints `currentColor`, for the monochrome sidebar and settings rail.
|
|
8
|
+
*/
|
|
9
|
+
export declare function BrowserIcon({ brand, tone, className, }: {
|
|
10
|
+
brand?: string | null;
|
|
11
|
+
tone?: 'brand' | 'current';
|
|
12
|
+
className?: string;
|
|
13
|
+
}): import("react").JSX.Element;
|
|
14
|
+
/** The browser mark on a white tile. `className` sets the tile size and radius. */
|
|
15
|
+
export declare function BrowserLogoTile({ brand, className, iconClassName, }: {
|
|
16
|
+
brand?: string | null;
|
|
17
|
+
className?: string;
|
|
18
|
+
iconClassName?: string;
|
|
19
|
+
}): import("react").JSX.Element;
|
|
20
|
+
/** Monochrome Chrome mark with the `Icon` call shape the settings rail expects. */
|
|
21
|
+
export declare function ChromeRailIcon({ className }: {
|
|
22
|
+
className?: string;
|
|
23
|
+
}): import("react").JSX.Element;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Edge } from '../icons/edge.js';
|
|
3
|
+
import { cn } from '../lib/utils.js';
|
|
4
|
+
/** A third-party logo tile is white in both themes (color.md). */
|
|
5
|
+
const LOGO_TILE_BACKGROUND = 'bg-white';
|
|
6
|
+
/**
|
|
7
|
+
* Official brand colors, from simple-icons (CC0). The SVG files in
|
|
8
|
+
* `public/browser-icons/` are the same set. Edge is not in simple-icons 13:
|
|
9
|
+
* it renders the house full-colour `Edge` mark instead.
|
|
10
|
+
*/
|
|
11
|
+
const CHROME_BLUE = '#4285F4';
|
|
12
|
+
const BRAVE_ORANGE = '#FB542B';
|
|
13
|
+
const ARC_PINK = '#FCBFBD';
|
|
14
|
+
const OPERA_RED = '#FF1B2D';
|
|
15
|
+
const VIVALDI_RED = '#EF3939';
|
|
16
|
+
const BROWSER_BRAND_HEX = {
|
|
17
|
+
chrome: CHROME_BLUE,
|
|
18
|
+
brave: BRAVE_ORANGE,
|
|
19
|
+
arc: ARC_PINK,
|
|
20
|
+
opera: OPERA_RED,
|
|
21
|
+
vivaldi: VIVALDI_RED,
|
|
22
|
+
};
|
|
23
|
+
const BROWSER_KEYS = ['brave', 'arc', 'opera', 'vivaldi', 'edge', 'chrome'];
|
|
24
|
+
/** Maps the API's `brand` string (Chrome, Edge, Brave, Arc, Dia, …) to a mark. Any other Chromium browser gets Chrome. */
|
|
25
|
+
export function browserKey(brand) {
|
|
26
|
+
const name = (brand ?? '').toLowerCase();
|
|
27
|
+
return BROWSER_KEYS.find((key) => name.includes(key)) ?? 'chrome';
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The browser's mark. `tone="brand"` paints the official color; `tone="current"`
|
|
31
|
+
* paints `currentColor`, for the monochrome sidebar and settings rail.
|
|
32
|
+
*/
|
|
33
|
+
export function BrowserIcon({ brand, tone = 'brand', className, }) {
|
|
34
|
+
const key = browserKey(brand);
|
|
35
|
+
if (key === 'edge' && tone === 'brand')
|
|
36
|
+
return _jsx(Edge, { className: className });
|
|
37
|
+
const file = key === 'edge' ? 'chrome' : key;
|
|
38
|
+
const url = `url(/browser-icons/${file}.svg)`;
|
|
39
|
+
return (_jsx("span", { "aria-hidden": "true", className: cn('inline-block size-4 shrink-0', tone === 'current' && 'bg-current', className), style: {
|
|
40
|
+
backgroundColor: tone === 'brand' && key !== 'edge' ? BROWSER_BRAND_HEX[key] : undefined,
|
|
41
|
+
maskImage: url,
|
|
42
|
+
WebkitMaskImage: url,
|
|
43
|
+
maskSize: 'contain',
|
|
44
|
+
WebkitMaskSize: 'contain',
|
|
45
|
+
maskRepeat: 'no-repeat',
|
|
46
|
+
WebkitMaskRepeat: 'no-repeat',
|
|
47
|
+
maskPosition: 'center',
|
|
48
|
+
WebkitMaskPosition: 'center',
|
|
49
|
+
} }));
|
|
50
|
+
}
|
|
51
|
+
/** The browser mark on a white tile. `className` sets the tile size and radius. */
|
|
52
|
+
export function BrowserLogoTile({ brand, className, iconClassName, }) {
|
|
53
|
+
return (_jsx("span", { className: cn(LOGO_TILE_BACKGROUND, 'ring-border flex size-9 shrink-0 items-center justify-center rounded-sm ring-1 ring-inset', className), children: _jsx(BrowserIcon, { brand: brand, className: cn('size-5', iconClassName) }) }));
|
|
54
|
+
}
|
|
55
|
+
/** Monochrome Chrome mark with the `Icon` call shape the settings rail expects. */
|
|
56
|
+
export function ChromeRailIcon({ className }) {
|
|
57
|
+
return _jsx(BrowserIcon, { brand: "chrome", tone: "current", className: className });
|
|
58
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** @internal Kortix apps only. No semver: it may change in any release. */
|
|
2
|
+
/**
|
|
3
|
+
* Which call to action the Chrome card shows. Pure, so the three states
|
|
4
|
+
* (not installed, installed, connected) are testable without a browser.
|
|
5
|
+
*/
|
|
6
|
+
export type ChromeCardState = 'connected' | 'unsupported' | 'checking' | 'installed' | 'notInstalled';
|
|
7
|
+
export declare function chromeCardState(input: {
|
|
8
|
+
/** THIS browser is connected. Other connected browsers do not count. */
|
|
9
|
+
thisBrowserConnected: boolean;
|
|
10
|
+
/** `unsupported`: Safari, Firefox, the desktop shell. */
|
|
11
|
+
environment: 'checking' | 'supported' | 'unsupported';
|
|
12
|
+
/** The first ping has not answered yet. */
|
|
13
|
+
checking: boolean;
|
|
14
|
+
/** The extension answered a ping, or a browser connected. */
|
|
15
|
+
installed: boolean;
|
|
16
|
+
}): ChromeCardState;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function chromeCardState(input) {
|
|
2
|
+
if (input.thisBrowserConnected)
|
|
3
|
+
return 'connected';
|
|
4
|
+
if (input.environment === 'unsupported')
|
|
5
|
+
return 'unsupported';
|
|
6
|
+
if (input.checking)
|
|
7
|
+
return 'checking';
|
|
8
|
+
return input.installed ? 'installed' : 'notInstalled';
|
|
9
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** @internal Kortix apps only. No semver: it may change in any release. */
|
|
2
|
+
import { type ChromeConnection } from '@kortix/sdk';
|
|
3
|
+
type Environment = 'checking' | 'supported' | 'unsupported';
|
|
4
|
+
/**
|
|
5
|
+
* The live state of the three steps: the extension is installed (ping every
|
|
6
|
+
* 2 s), the extension is signed in, and the new browser shows in the list
|
|
7
|
+
* (poll every 3 s). Mount it only while the steps are on screen.
|
|
8
|
+
*/
|
|
9
|
+
export type ChromeConnectState = ReturnType<typeof useChromeConnect>;
|
|
10
|
+
/**
|
|
11
|
+
* `fresh`: the person adds ANOTHER browser. This browser's own extension state
|
|
12
|
+
* does not count: no ping, and only a browser that was not in the list when the
|
|
13
|
+
* dialog opened completes it.
|
|
14
|
+
*/
|
|
15
|
+
export declare function useChromeConnect({ fresh }?: {
|
|
16
|
+
fresh?: boolean;
|
|
17
|
+
}): {
|
|
18
|
+
environment: Environment;
|
|
19
|
+
/** The first ping has not answered yet. */
|
|
20
|
+
checking: boolean;
|
|
21
|
+
installed: boolean;
|
|
22
|
+
signedIn: boolean;
|
|
23
|
+
connected: ChromeConnection | undefined;
|
|
24
|
+
connect: import("@tanstack/react-query").UseMutationResult<import("./extension.js").ExtensionConnectResult, Error, void, unknown>;
|
|
25
|
+
};
|
|
26
|
+
/** The Chrome mark on a small white tile, for a button label. */
|
|
27
|
+
export declare function ChromeButtonMark(): import("react").JSX.Element;
|
|
28
|
+
export declare function ChromeOnlineDot({ online, className }: {
|
|
29
|
+
online: boolean;
|
|
30
|
+
className?: string;
|
|
31
|
+
}): import("react").JSX.Element;
|
|
32
|
+
/** Copies the link that opens Settings → Kortix in Chrome, for a browser that cannot run the extension. */
|
|
33
|
+
export declare function ChromeCopyLink({ size, className }: {
|
|
34
|
+
size?: 'sm' | 'lg';
|
|
35
|
+
className?: string;
|
|
36
|
+
}): import("react").JSX.Element;
|
|
37
|
+
/**
|
|
38
|
+
* The action that moves this browser forward: Connect once the extension is
|
|
39
|
+
* there, otherwise Connect plus "How to install" (or "Add to Chrome" once the
|
|
40
|
+
* Web Store listing is public). Renders nothing for a connected browser.
|
|
41
|
+
*/
|
|
42
|
+
export declare function ChromeInstallActions({ state, size, className, showGuide, }: {
|
|
43
|
+
state: ChromeConnectState;
|
|
44
|
+
size?: 'sm' | 'lg';
|
|
45
|
+
className?: string;
|
|
46
|
+
/** The "How to install" link. Off where the page already links the docs. */
|
|
47
|
+
showGuide?: boolean;
|
|
48
|
+
}): import("react").JSX.Element | null;
|
|
49
|
+
/**
|
|
50
|
+
* The three steps and the one action that moves them. Used in the connect
|
|
51
|
+
* dialog and, with no browser connected yet, inline in Settings → Kortix in
|
|
52
|
+
* Chrome (`showActions={false}`: the page header holds the action there).
|
|
53
|
+
*/
|
|
54
|
+
export declare function ChromeConnectSteps({ state, onDone, showActions, }: {
|
|
55
|
+
state: ChromeConnectState;
|
|
56
|
+
onDone?: () => void;
|
|
57
|
+
showActions?: boolean;
|
|
58
|
+
}): import("react").JSX.Element;
|
|
59
|
+
/**
|
|
60
|
+
* "Add Kortix to Chrome": add the Kortix extension to Chrome, sign it in, and
|
|
61
|
+
* watch the browser appear. `fresh`: add ANOTHER browser. Same frame as
|
|
62
|
+
* `ComputerConnectModal`.
|
|
63
|
+
*/
|
|
64
|
+
export declare function ChromeConnectModal({ open, onOpenChange, fresh, }: {
|
|
65
|
+
open: boolean;
|
|
66
|
+
onOpenChange: (open: boolean) => void;
|
|
67
|
+
fresh?: boolean;
|
|
68
|
+
}): import("react").JSX.Element;
|
|
69
|
+
export {};
|