diff --git a/demo/gptPlugin/PlaygroundGPT.stories.tsx b/demo/gptPlugin/PlaygroundGPT.stories.tsx index 09ed3f1fd..95d922dc6 100644 --- a/demo/gptPlugin/PlaygroundGPT.stories.tsx +++ b/demo/gptPlugin/PlaygroundGPT.stories.tsx @@ -6,11 +6,11 @@ import type {StoryFn} from '@storybook/react'; import {PlaygroundGPT} from './PlaygroundGPT'; export default { - title: 'Markdown Editor / YFM examples', + title: 'Experiments / GPT', component: PlaygroundGPT, }; type PlaygroundStoryProps = {}; export const Playground: StoryFn = (props) => ; -Playground.storyName = 'GPT'; +Playground.storyName = 'Playground GPT'; diff --git a/demo/gptPlugin/PlaygroundGPT.tsx b/demo/gptPlugin/PlaygroundGPT.tsx index 6f670176c..e766212a1 100644 --- a/demo/gptPlugin/PlaygroundGPT.tsx +++ b/demo/gptPlugin/PlaygroundGPT.tsx @@ -6,6 +6,9 @@ import { type MarkupString, gptExtension, logger, + mGptExtension, + mGptToolbarItem, + markupToolbarConfigs, wGptToolbarItem, wysiwygToolbarConfigs, } from '../../src'; @@ -34,30 +37,40 @@ const wCommandMenuConfig = wysiwygToolbarConfigs.wCommandMenuConfig.concat( wCommandMenuConfig.unshift(wysiwygToolbarConfigs.wGptItemData); +const mToolbarConfig = cloneDeep(markupToolbarConfigs.mToolbarConfig); + +mToolbarConfig.push([ + markupToolbarConfigs.mMermaidButton, + markupToolbarConfigs.mYfmHtmlBlockButton, +]); + +mToolbarConfig.unshift([mGptToolbarItem]); + export const PlaygroundGPT = React.memo(() => { const [yfmRaw, setYfmRaw] = React.useState(initialMdContent); const [showedAlertGpt, setShowedAlertGpt] = useState(true); + const gptExtensionProps = gptWidgetProps(setYfmRaw, { + showedGptAlert: Boolean(showedAlertGpt), + onCloseGptAlert: () => { + setShowedAlertGpt(false); + }, + }); + + const markupExtension = mGptExtension(gptExtensionProps); const wSelectionMenuConfig = [[wGptToolbarItem], ...wysiwygToolbarConfigs.wSelectionMenuConfig]; + return ( - builder.use( - gptExtension, - gptWidgetProps(setYfmRaw, { - showedGptAlert: Boolean(showedAlertGpt), - onCloseGptAlert: () => { - setShowedAlertGpt(false); - }, - }), - ) - } + extraExtensions={(builder) => builder.use(gptExtension, gptExtensionProps)} wysiwygCommandMenuConfig={wCommandMenuConfig} extensionOptions={{selectionContext: {config: wSelectionMenuConfig}}} wysiwygToolbarConfig={wToolbarConfig} + markupConfigExtensions={markupExtension} + markupToolbarConfig={mToolbarConfig} /> ); }); diff --git a/demo/gptPlugin/gptWidgetOptions.tsx b/demo/gptPlugin/gptWidgetOptions.tsx index 004d869da..1970e130a 100644 --- a/demo/gptPlugin/gptWidgetOptions.tsx +++ b/demo/gptPlugin/gptWidgetOptions.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type {GptWidgetOptions} from '../../src/extensions/yfm/GPT/gptExtension/gptExtension'; +import type {GptWidgetOptions} from '../../src'; const gptRequestHandler = async ({ markup, diff --git a/docs/how-to-connect-gpt-extensions.md b/docs/how-to-connect-gpt-extensions.md index a7fc1cd8b..6b1660971 100644 --- a/docs/how-to-connect-gpt-extensions.md +++ b/docs/how-to-connect-gpt-extensions.md @@ -20,11 +20,21 @@ import { gptExtension, MarkdownEditorView, useMarkdownEditor, + markupToolbarConfigs, + mGptExtension, } from '@gravity-ui/markdown-editor'; export const Editor: React.FC = (props) => { + // add a plugin to the markup mode + const markupGptExtension = mGptExtension(gptWidgetProps); + const mdEditor = useMarkdownEditor({ // ... + + markupConfig: { + extensions: markupGptExtension, + }, + extraExtensions: (builder) => builder.use( ... @@ -35,9 +45,15 @@ export const Editor: React.FC = (props) => { ), }); + // add a plugin to the markup toolbar mode + const mToolbarConfig = markupToolbarConfigs.mToolbarConfig; + + mToolbarConfig.push([mGptToolbarItem]); + return }; ``` diff --git a/src/bundle/config/wysiwyg.ts b/src/bundle/config/wysiwyg.ts index 63a9eabf8..4dcdbffba 100644 --- a/src/bundle/config/wysiwyg.ts +++ b/src/bundle/config/wysiwyg.ts @@ -1,12 +1,12 @@ import {ActionStorage} from 'src/core'; import {headingType, pType} from '../../extensions'; +import {gptHotKeys} from '../../extensions/additional/GPT/constants'; import type { SelectionContextConfig, SelectionContextItemData, } from '../../extensions/behavior/SelectionContext'; // for typings from Math -import {gptHotKeys} from '../../extensions/yfm/GPT/constants'; import type {} from '../../extensions/yfm/Math'; import {i18n as i18nHint} from '../../i18n/hints'; import {i18n} from '../../i18n/menubar'; diff --git a/src/extensions/yfm/GPT/ErrorScreen/ErrorScreen.scss b/src/extensions/additional/GPT/ErrorScreen/ErrorScreen.scss similarity index 100% rename from src/extensions/yfm/GPT/ErrorScreen/ErrorScreen.scss rename to src/extensions/additional/GPT/ErrorScreen/ErrorScreen.scss diff --git a/src/extensions/yfm/GPT/ErrorScreen/ErrorScreen.tsx b/src/extensions/additional/GPT/ErrorScreen/ErrorScreen.tsx similarity index 100% rename from src/extensions/yfm/GPT/ErrorScreen/ErrorScreen.tsx rename to src/extensions/additional/GPT/ErrorScreen/ErrorScreen.tsx diff --git a/src/extensions/yfm/GPT/ErrorScreen/types.ts b/src/extensions/additional/GPT/ErrorScreen/types.ts similarity index 100% rename from src/extensions/yfm/GPT/ErrorScreen/types.ts rename to src/extensions/additional/GPT/ErrorScreen/types.ts diff --git a/src/extensions/yfm/GPT/GptDialog/GptDialog.scss b/src/extensions/additional/GPT/GptDialog/GptDialog.scss similarity index 100% rename from src/extensions/yfm/GPT/GptDialog/GptDialog.scss rename to src/extensions/additional/GPT/GptDialog/GptDialog.scss diff --git a/src/extensions/yfm/GPT/GptDialog/GptDialog.tsx b/src/extensions/additional/GPT/GptDialog/GptDialog.tsx similarity index 100% rename from src/extensions/yfm/GPT/GptDialog/GptDialog.tsx rename to src/extensions/additional/GPT/GptDialog/GptDialog.tsx diff --git a/src/extensions/yfm/GPT/GptDialog/LoadingScreen/LoadingScreen.scss b/src/extensions/additional/GPT/GptDialog/LoadingScreen/LoadingScreen.scss similarity index 100% rename from src/extensions/yfm/GPT/GptDialog/LoadingScreen/LoadingScreen.scss rename to src/extensions/additional/GPT/GptDialog/LoadingScreen/LoadingScreen.scss diff --git a/src/extensions/yfm/GPT/GptDialog/LoadingScreen/LoadingScreen.tsx b/src/extensions/additional/GPT/GptDialog/LoadingScreen/LoadingScreen.tsx similarity index 100% rename from src/extensions/yfm/GPT/GptDialog/LoadingScreen/LoadingScreen.tsx rename to src/extensions/additional/GPT/GptDialog/LoadingScreen/LoadingScreen.tsx diff --git a/src/extensions/yfm/GPT/IconRefuge/IconRefuge.classname.tsx b/src/extensions/additional/GPT/IconRefuge/IconRefuge.classname.tsx similarity index 100% rename from src/extensions/yfm/GPT/IconRefuge/IconRefuge.classname.tsx rename to src/extensions/additional/GPT/IconRefuge/IconRefuge.classname.tsx diff --git a/src/extensions/yfm/GPT/IconRefuge/IconRefuge.scss b/src/extensions/additional/GPT/IconRefuge/IconRefuge.scss similarity index 100% rename from src/extensions/yfm/GPT/IconRefuge/IconRefuge.scss rename to src/extensions/additional/GPT/IconRefuge/IconRefuge.scss diff --git a/src/extensions/yfm/GPT/IconRefuge/IconRefuge.tsx b/src/extensions/additional/GPT/IconRefuge/IconRefuge.tsx similarity index 100% rename from src/extensions/yfm/GPT/IconRefuge/IconRefuge.tsx rename to src/extensions/additional/GPT/IconRefuge/IconRefuge.tsx diff --git a/src/extensions/yfm/GPT/IconRefuge/IconRefuge.types.d.ts b/src/extensions/additional/GPT/IconRefuge/IconRefuge.types.d.ts similarity index 100% rename from src/extensions/yfm/GPT/IconRefuge/IconRefuge.types.d.ts rename to src/extensions/additional/GPT/IconRefuge/IconRefuge.types.d.ts diff --git a/src/extensions/yfm/GPT/IconRefuge/index.ts b/src/extensions/additional/GPT/IconRefuge/index.ts similarity index 100% rename from src/extensions/yfm/GPT/IconRefuge/index.ts rename to src/extensions/additional/GPT/IconRefuge/index.ts diff --git a/src/extensions/additional/GPT/MarkupGpt/commands.ts b/src/extensions/additional/GPT/MarkupGpt/commands.ts new file mode 100644 index 000000000..16d6d2078 --- /dev/null +++ b/src/extensions/additional/GPT/MarkupGpt/commands.ts @@ -0,0 +1,17 @@ +import type {Command, EditorView} from '../../../../cm/view'; + +import {HideMarkupGptEffect, ShowMarkupGptEffect} from './effects'; + +export const showMarkupGpt = (view: EditorView) => { + view.dispatch({effects: [ShowMarkupGptEffect.of(null)]}); +}; + +export const hideMarkupGpt = (view: EditorView) => { + view.dispatch({effects: [HideMarkupGptEffect.of(null)]}); +}; + +export const runMarkupGpt: Command = (view) => { + if (view) showMarkupGpt(view); + + return true; +}; diff --git a/src/extensions/additional/GPT/MarkupGpt/effects.ts b/src/extensions/additional/GPT/MarkupGpt/effects.ts new file mode 100644 index 000000000..1810ac4c5 --- /dev/null +++ b/src/extensions/additional/GPT/MarkupGpt/effects.ts @@ -0,0 +1,4 @@ +import {StateEffect} from '../../../../cm/state'; + +export const ShowMarkupGptEffect = StateEffect.define(); +export const HideMarkupGptEffect = StateEffect.define(); diff --git a/src/extensions/additional/GPT/MarkupGpt/index.ts b/src/extensions/additional/GPT/MarkupGpt/index.ts new file mode 100644 index 000000000..802a0f995 --- /dev/null +++ b/src/extensions/additional/GPT/MarkupGpt/index.ts @@ -0,0 +1,22 @@ +import {keymap} from '@codemirror/view'; + +import {GptWidgetOptions} from '../../..'; +import {gptHotKeys} from '../constants'; + +import {runMarkupGpt} from './commands'; +import {mGptPlugin} from './plugin'; + +export {mGptToolbarItem} from './toolbar'; +export {showMarkupGpt, hideMarkupGpt} from './commands'; + +export function mGptExtension(props: GptWidgetOptions) { + return [ + mGptPlugin(props).extension, + keymap.of([ + { + key: gptHotKeys.openGptKey, + run: runMarkupGpt, + }, + ]), + ]; +} diff --git a/src/extensions/additional/GPT/MarkupGpt/plugin.ts b/src/extensions/additional/GPT/MarkupGpt/plugin.ts new file mode 100644 index 000000000..f523d23f6 --- /dev/null +++ b/src/extensions/additional/GPT/MarkupGpt/plugin.ts @@ -0,0 +1,168 @@ +import {WidgetType} from '@codemirror/view'; + +import {GptWidgetOptions} from '../../..'; +import { + Decoration, + type DecorationSet, + type EditorView, + type PluginValue, + ViewPlugin, + type ViewUpdate, +} from '../../../../cm/view'; +import {ReactRendererFacet} from '../../../../markup'; +import {WIDGET_DECO_CLASS_NAME} from '../constants'; +import {isEmptyGptPrompts} from '../utils'; + +import {hideMarkupGpt} from './commands'; +import {HideMarkupGptEffect, ShowMarkupGptEffect} from './effects'; +import {renderPopup} from './popup'; + +class SpanWidget extends WidgetType { + private className = ''; + private textContent = ''; + + constructor(className: string, textContent: string) { + super(); + this.className = className; + this.textContent = textContent; + } + + toDOM() { + const spanElem = document.createElement('span'); + spanElem.className = this.className; + spanElem.textContent = this.textContent; + return spanElem; + } +} + +export function mGptPlugin(gptProps: GptWidgetOptions) { + return ViewPlugin.fromClass( + class implements PluginValue { + readonly _view: EditorView; + readonly _renderItem; + + _anchor: Element | null = null; + + decos: DecorationSet = Decoration.none; + disablePromptPresets = true; + markup: string | null = null; + + selectedPosition = { + from: 0, + to: 0, + }; + + constructor(view: EditorView) { + this._view = view; + this._renderItem = view.state + .facet(ReactRendererFacet) + .createItem('gpt-in-markup-mode', () => this.renderPopup()); + } + + update(update: ViewUpdate) { + if (update.docChanged || update.selectionSet) { + this.decos = Decoration.none; + return; + } + + this.decos = this.decos.map(update.changes); + + const {from, to} = update.state.selection.main; + + this.selectedPosition.from = from; + this.selectedPosition.to = to; + + for (const tr of update.transactions) { + for (const eff of tr.effects) { + if (eff.is(ShowMarkupGptEffect)) { + this._setSelectedText(this._getDecorationText(update, from, to)); + + if (from === to) { + this.disablePromptPresets = true; + + if (isEmptyGptPrompts(gptProps, true)) return; + + const decorationWidget = Decoration.widget({ + widget: new SpanWidget(WIDGET_DECO_CLASS_NAME, ' '), + }); + + this.decos = Decoration.set([decorationWidget.range(from)]); + + return; + } + + this.disablePromptPresets = false; + + if (isEmptyGptPrompts(gptProps, false)) return; + + this.decos = Decoration.set([ + { + from, + to, + value: Decoration.mark({class: WIDGET_DECO_CLASS_NAME}), + }, + ]); + } + + if (eff.is(HideMarkupGptEffect)) { + this.decos = Decoration.none; + } + } + } + } + + docViewUpdate() { + this._anchor = this._view.dom + .getElementsByClassName(WIDGET_DECO_CLASS_NAME) + .item(0); + this._renderItem.rerender(); + } + + destroy() { + this._clearSelectedText(); + this._renderItem.remove(); + } + + renderPopup() { + if (!this._anchor || this.markup === null) { + return null; + } + + return renderPopup(this._anchor as HTMLElement, { + ...gptProps, + disablePromptPresets: this.disablePromptPresets, + onClose: () => hideMarkupGpt(this._view), + markup: this.markup, + onApplyResult: (changedMarkup) => this._onApplyResult(changedMarkup), + }); + } + + _getDecorationText(update: ViewUpdate, from: number, to: number): string { + return update.state.doc.sliceString(from, to); + } + + _clearSelectedText() { + this.markup = null; + } + + _setSelectedText(str: string) { + this.markup = str; + } + + _onApplyResult(changedMarkup: string) { + const {from, to} = this.selectedPosition; + const changes = [{from: from, to: to, insert: changedMarkup}]; + + const transaction = this._view.state.update({ + changes: changes, + effects: [HideMarkupGptEffect.of(null)], + }); + + this._view.dispatch(transaction); + } + }, + { + decorations: (value) => value.decos, + }, + ); +} diff --git a/src/extensions/additional/GPT/MarkupGpt/popup.tsx b/src/extensions/additional/GPT/MarkupGpt/popup.tsx new file mode 100644 index 000000000..705fe0c13 --- /dev/null +++ b/src/extensions/additional/GPT/MarkupGpt/popup.tsx @@ -0,0 +1,50 @@ +import React from 'react'; + +import {Popup, PopupProps} from '@gravity-ui/uikit'; + +import {CommonAnswer} from '../ErrorScreen/types'; +import {GptDialog, GptDialogProps} from '../GptDialog/GptDialog'; +import {cnGptPopup} from '../gptExtension/view'; + +type Props = { + onClose: () => void; + markup: string; + onConfirmOk?: () => void; + onConfirmCancel?: () => void; +} & GptDialogProps & + Pick; + +export function renderPopup(anchor: HTMLElement, props: Props) { + const handleUpdate = (result?: CommonAnswer) => props.onUpdate?.(result); + + return ( + + + + ); +} diff --git a/src/extensions/additional/GPT/MarkupGpt/toolbar.ts b/src/extensions/additional/GPT/MarkupGpt/toolbar.ts new file mode 100644 index 000000000..3378eca03 --- /dev/null +++ b/src/extensions/additional/GPT/MarkupGpt/toolbar.ts @@ -0,0 +1,18 @@ +import {MToolbarSingleItemData} from '../../../../bundle/config/markup'; +import {i18n} from '../../../../i18n/gpt/extension'; +import {GPTIcon} from '../../../../icons'; +import {ToolbarDataType} from '../../../../toolbar'; +import {gptHotKeys} from '../constants'; + +import {showMarkupGpt} from './commands'; + +export const mGptToolbarItem: MToolbarSingleItemData = { + id: 'gpt', + type: ToolbarDataType.SingleButton, + hotkey: gptHotKeys.openGptKeyTooltip, + title: () => `${i18n('help-with-text')}`, + icon: {data: GPTIcon}, + exec: (e) => showMarkupGpt(e.cm), + isActive: () => false, + isEnable: () => true, +}; diff --git a/src/extensions/yfm/GPT/PresetList/PresetList.tsx b/src/extensions/additional/GPT/PresetList/PresetList.tsx similarity index 100% rename from src/extensions/yfm/GPT/PresetList/PresetList.tsx rename to src/extensions/additional/GPT/PresetList/PresetList.tsx diff --git a/src/extensions/yfm/GPT/PresetList/Presetlist.scss b/src/extensions/additional/GPT/PresetList/Presetlist.scss similarity index 100% rename from src/extensions/yfm/GPT/PresetList/Presetlist.scss rename to src/extensions/additional/GPT/PresetList/Presetlist.scss diff --git a/src/extensions/yfm/GPT/actions.ts b/src/extensions/additional/GPT/actions.ts similarity index 100% rename from src/extensions/yfm/GPT/actions.ts rename to src/extensions/additional/GPT/actions.ts diff --git a/src/extensions/yfm/GPT/commands.ts b/src/extensions/additional/GPT/commands.ts similarity index 100% rename from src/extensions/yfm/GPT/commands.ts rename to src/extensions/additional/GPT/commands.ts diff --git a/src/extensions/yfm/GPT/constants.ts b/src/extensions/additional/GPT/constants.ts similarity index 100% rename from src/extensions/yfm/GPT/constants.ts rename to src/extensions/additional/GPT/constants.ts diff --git a/src/extensions/yfm/GPT/gptExtension/gptExtension.ts b/src/extensions/additional/GPT/gptExtension/gptExtension.ts similarity index 100% rename from src/extensions/yfm/GPT/gptExtension/gptExtension.ts rename to src/extensions/additional/GPT/gptExtension/gptExtension.ts diff --git a/src/extensions/yfm/GPT/gptExtension/view.scss b/src/extensions/additional/GPT/gptExtension/view.scss similarity index 100% rename from src/extensions/yfm/GPT/gptExtension/view.scss rename to src/extensions/additional/GPT/gptExtension/view.scss diff --git a/src/extensions/yfm/GPT/gptExtension/view.tsx b/src/extensions/additional/GPT/gptExtension/view.tsx similarity index 100% rename from src/extensions/yfm/GPT/gptExtension/view.tsx rename to src/extensions/additional/GPT/gptExtension/view.tsx diff --git a/src/extensions/yfm/GPT/hooks/useGpt.tsx b/src/extensions/additional/GPT/hooks/useGpt.tsx similarity index 100% rename from src/extensions/yfm/GPT/hooks/useGpt.tsx rename to src/extensions/additional/GPT/hooks/useGpt.tsx diff --git a/src/extensions/yfm/GPT/hooks/useGptHotKeys.ts b/src/extensions/additional/GPT/hooks/useGptHotKeys.ts similarity index 100% rename from src/extensions/yfm/GPT/hooks/useGptHotKeys.ts rename to src/extensions/additional/GPT/hooks/useGptHotKeys.ts diff --git a/src/extensions/yfm/GPT/hooks/useOverflowingHorizontalItems.tsx b/src/extensions/additional/GPT/hooks/useOverflowingHorizontalItems.tsx similarity index 100% rename from src/extensions/yfm/GPT/hooks/useOverflowingHorizontalItems.tsx rename to src/extensions/additional/GPT/hooks/useOverflowingHorizontalItems.tsx diff --git a/src/extensions/yfm/GPT/hooks/usePresetList.ts b/src/extensions/additional/GPT/hooks/usePresetList.ts similarity index 100% rename from src/extensions/yfm/GPT/hooks/usePresetList.ts rename to src/extensions/additional/GPT/hooks/usePresetList.ts diff --git a/src/extensions/yfm/GPT/index.ts b/src/extensions/additional/GPT/index.ts similarity index 71% rename from src/extensions/yfm/GPT/index.ts rename to src/extensions/additional/GPT/index.ts index 9132fd2b6..314f51006 100644 --- a/src/extensions/yfm/GPT/index.ts +++ b/src/extensions/additional/GPT/index.ts @@ -1,2 +1,3 @@ export * from './toolbar'; export * from './gptExtension/gptExtension'; +export * from './MarkupGpt'; diff --git a/src/extensions/yfm/GPT/plugin.ts b/src/extensions/additional/GPT/plugin.ts similarity index 89% rename from src/extensions/yfm/GPT/plugin.ts rename to src/extensions/additional/GPT/plugin.ts index ddc46ef9d..d794819d4 100644 --- a/src/extensions/yfm/GPT/plugin.ts +++ b/src/extensions/additional/GPT/plugin.ts @@ -4,6 +4,7 @@ import {Decoration, DecorationSet} from 'prosemirror-view'; import {WIDGET_DECO_CLASS_NAME, WIDGET_DECO_SPEC_FLAG} from './constants'; import type {GptWidgetDecoViewParams} from './gptExtension/view'; import {GptWidgetDecoView} from './gptExtension/view'; +import {isEmptyGptPrompts} from './utils'; export type GptWidgetMeta = | { @@ -28,6 +29,8 @@ export const gptWidgetPlugin = (params: GptWidgetDecoViewParams): Plugin => { const meta = tr.getMeta(key) as GptWidgetMeta | undefined; const paramsGpt = params; + paramsGpt.disablePromptPresets = false; + if (meta?.action === 'show') { if (meta.to === meta.from) { const spanElem = document.createElement('span'); @@ -36,6 +39,8 @@ export const gptWidgetPlugin = (params: GptWidgetDecoViewParams): Plugin => { paramsGpt.disablePromptPresets = true; + if (isEmptyGptPrompts(paramsGpt, true)) return DecorationSet.empty; + return DecorationSet.create(tr.doc, [ Decoration.widget(meta.from, spanElem, { [WIDGET_DECO_SPEC_FLAG]: true, @@ -43,6 +48,8 @@ export const gptWidgetPlugin = (params: GptWidgetDecoViewParams): Plugin => { ]); } + if (isEmptyGptPrompts(paramsGpt, false)) return DecorationSet.empty; + return DecorationSet.create(tr.doc, [ Decoration.inline( meta.from, diff --git a/src/extensions/yfm/GPT/toolbar.ts b/src/extensions/additional/GPT/toolbar.ts similarity index 100% rename from src/extensions/yfm/GPT/toolbar.ts rename to src/extensions/additional/GPT/toolbar.ts diff --git a/src/extensions/yfm/GPT/utils.ts b/src/extensions/additional/GPT/utils.ts similarity index 72% rename from src/extensions/yfm/GPT/utils.ts rename to src/extensions/additional/GPT/utils.ts index 433a63687..424664e51 100644 --- a/src/extensions/yfm/GPT/utils.ts +++ b/src/extensions/additional/GPT/utils.ts @@ -3,6 +3,7 @@ import type React from 'react'; import {i18n} from '../../../i18n/gpt/dialog'; import {GptDialogProps} from './GptDialog/GptDialog'; +import {GptWidgetOptions} from './gptExtension/gptExtension'; type CombinedKeyboardEvent = KeyboardEvent | React.KeyboardEvent; @@ -39,3 +40,19 @@ export function focusWithoutScroll(element?: HTMLElement | null) { window.scrollTo(x, y); } + +export function isEmptyGptPrompts( + gptWidgetOptions: GptWidgetOptions, + disablePromptPresets: boolean, +) { + if (disablePromptPresets && !gptWidgetOptions.onCustomPromptApply) return true; + + if ( + !disablePromptPresets && + !gptWidgetOptions.promptPresets?.length && + !gptWidgetOptions.onCustomPromptApply + ) + return true; + + return false; +} diff --git a/src/extensions/additional/index.ts b/src/extensions/additional/index.ts new file mode 100644 index 000000000..192cae9dd --- /dev/null +++ b/src/extensions/additional/index.ts @@ -0,0 +1 @@ +export * from './GPT'; diff --git a/src/extensions/index.ts b/src/extensions/index.ts index 31966859b..09edc2f94 100644 --- a/src/extensions/index.ts +++ b/src/extensions/index.ts @@ -2,3 +2,4 @@ export * from './base'; export * from './behavior'; export * from './markdown'; export * from './yfm'; +export * from './additional'; diff --git a/src/extensions/yfm/index.ts b/src/extensions/yfm/index.ts index 5480b4864..3e95fab89 100644 --- a/src/extensions/yfm/index.ts +++ b/src/extensions/yfm/index.ts @@ -11,4 +11,4 @@ export * from './YfmHeading'; export * from './YfmNote'; export * from './YfmTable'; export * from './YfmTabs'; -export * from './GPT'; +export * from '../additional/GPT'; diff --git a/src/i18n/gpt/dialog/en.json b/src/i18n/gpt/dialog/en.json index c1101178c..8b7844830 100644 --- a/src/i18n/gpt/dialog/en.json +++ b/src/i18n/gpt/dialog/en.json @@ -12,5 +12,5 @@ "replace": "Replace the selected text", "replace-disabled": "Insert text", "try-again": "Try again", - "alert-gpt-presets-info": "Highlight text to see Yandex GPT presets" + "alert-gpt-presets-info": "Highlight text to see GPT presets" } diff --git a/src/i18n/gpt/dialog/ru.json b/src/i18n/gpt/dialog/ru.json index 85537e77a..30a1fdd07 100644 --- a/src/i18n/gpt/dialog/ru.json +++ b/src/i18n/gpt/dialog/ru.json @@ -12,5 +12,5 @@ "replace": "Заменить выделенный текст", "replace-disabled": "Вставить текст", "try-again": "Иначе", - "alert-gpt-presets-info": "Выделите текст, чтобы увидеть пресеты Yandex GPT" + "alert-gpt-presets-info": "Выделите текст, чтобы увидеть пресеты GPT" }