diff --git a/packages/boxel-ui/addon/raw-icons/send.svg b/packages/boxel-ui/addon/raw-icons/send.svg new file mode 100644 index 0000000000..72534eebb8 --- /dev/null +++ b/packages/boxel-ui/addon/raw-icons/send.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/boxel-ui/addon/src/icons.gts b/packages/boxel-ui/addon/src/icons.gts index 2983e464fc..4e883362c2 100644 --- a/packages/boxel-ui/addon/src/icons.gts +++ b/packages/boxel-ui/addon/src/icons.gts @@ -35,6 +35,7 @@ import IconX from './icons/icon-x.gts'; import LoadingIndicator from './icons/loading-indicator.gts'; import Profile from './icons/profile.gts'; import Search from './icons/search.gts'; +import Send from './icons/send.gts'; import Sparkle from './icons/sparkle.gts'; import SuccessBordered from './icons/success-bordered.gts'; import ThreeDotsHorizontal from './icons/three-dots-horizontal.gts'; @@ -73,6 +74,7 @@ export const ALL_ICON_COMPONENTS = [ LoadingIndicator, Profile, Search, + Send, Sparkle, SuccessBordered, ThreeDotsHorizontal, @@ -112,6 +114,7 @@ export { LoadingIndicator, Profile, Search, + Send, Sparkle, SuccessBordered, ThreeDotsHorizontal, diff --git a/packages/boxel-ui/addon/src/icons/send.gts b/packages/boxel-ui/addon/src/icons/send.gts new file mode 100644 index 0000000000..64c4a01ee9 --- /dev/null +++ b/packages/boxel-ui/addon/src/icons/send.gts @@ -0,0 +1,23 @@ +// This file is auto-generated by 'pnpm rebuild:icons' +import type { TemplateOnlyComponent } from '@ember/component/template-only'; + +import type { Signature } from './types.ts'; + +const IconComponent: TemplateOnlyComponent = ; + +// @ts-expect-error this is the only way to set a name on a Template Only Component currently +IconComponent.name = 'SendIcon'; +export default IconComponent; diff --git a/packages/host/app/components/ai-assistant/chat-input/index.gts b/packages/host/app/components/ai-assistant/chat-input/index.gts new file mode 100644 index 0000000000..f0411aaa39 --- /dev/null +++ b/packages/host/app/components/ai-assistant/chat-input/index.gts @@ -0,0 +1,99 @@ +import { on } from '@ember/modifier'; +import { action } from '@ember/object'; +import Component from '@glimmer/component'; + +import onKeyMod from 'ember-keyboard/modifiers/on-key'; + +import { BoxelInput, IconButton } from '@cardstack/boxel-ui/components'; +import { Send } from '@cardstack/boxel-ui/icons'; +import { setCssVar } from '@cardstack/boxel-ui/modifiers'; + +interface Signature { + Element: HTMLDivElement; + Args: { + value: string; + onInput: (val: string) => void; + onSend: (val: string) => void; + }; +} + +export default class AiAssistantChatInput extends Component { + + + @action onSend() { + this.args.onSend(this.args.value); + } + + get height() { + const lineHeight = 20; + const padding = 9; + + let lineCount = (this.args.value.match(/\n/g) ?? []).length + 1; + let count = 2; + + if (lineCount > 5) { + count = 5; + } else if (lineCount > 2) { + count = lineCount; + } + + let height = count * lineHeight + 2 * padding; + return `${height}px`; + } +} diff --git a/packages/host/app/components/ai-assistant/chat-input/usage.gts b/packages/host/app/components/ai-assistant/chat-input/usage.gts new file mode 100644 index 0000000000..e4db96671d --- /dev/null +++ b/packages/host/app/components/ai-assistant/chat-input/usage.gts @@ -0,0 +1,53 @@ +import { fn } from '@ember/helper'; +import { action } from '@ember/object'; +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; + +import FreestyleUsage from 'ember-freestyle/components/freestyle/usage'; + +import AiAssistantChatInput from './index'; + +export default class AiAssistantChatInputUsage extends Component { + @tracked value = ''; + + @action onSend(message: string) { + console.log(`message sent: ${message}`); + } + + +} diff --git a/packages/host/app/templates/host-freestyle.gts b/packages/host/app/templates/host-freestyle.gts index 22f55ba026..c12c0eb913 100644 --- a/packages/host/app/templates/host-freestyle.gts +++ b/packages/host/app/templates/host-freestyle.gts @@ -8,6 +8,7 @@ import FreestyleSection from 'ember-freestyle/components/freestyle-section'; import { pageTitle } from 'ember-page-title'; import RouteTemplate from 'ember-route-template'; +import AiAssistantChatInputUsage from '@cardstack/host/components/ai-assistant/chat-input/usage'; import AiAssistantMessageUsage from '@cardstack/host/components/ai-assistant/message/usage'; import ProfileAvatarIconVisualUsage from '@cardstack/host/components/operator-mode/profile-avatar-icon/usage'; import SearchSheetUsage from '@cardstack/host/components/search-sheet/usage'; @@ -29,6 +30,7 @@ class HostFreestyleComponent extends Component { get usageComponents() { return [ ['AiAssistant::Message', AiAssistantMessageUsage], + ['AiAssistant::ChatInput', AiAssistantChatInputUsage], ['ProfileAvatarIconVisualUsage', ProfileAvatarIconVisualUsage], ['SearchSheet', SearchSheetUsage], ].map(([name, c]) => { diff --git a/packages/host/types/ember-keyboard/modifiers/on-key.d.ts b/packages/host/types/ember-keyboard/modifiers/on-key.d.ts new file mode 100644 index 0000000000..2a0cac2d39 --- /dev/null +++ b/packages/host/types/ember-keyboard/modifiers/on-key.d.ts @@ -0,0 +1,15 @@ +import Modifier from 'ember-modifier'; + +interface Signature { + Element: HTMLElement; + Args: { + Positional: [keyCombo: string, callback?: (ev: KeyboardEvent) => void]; + Named: { + event?: string; + activated?: boolean; + priority?: number; + }; + }; +} + +export default class OnKeyModifier extends Modifier {}