* Eslint import order * Initial Uikit * Rename file with camelCase * Remove unused code * Remove unused code * Set position traficlight mac * Grouping Ribbon, Topbar and Bottombar as layout * Added image brand * Moving feature toggle into context folder * Fix active state of setting menu * Cleanup downloadModel atom helper * Cleanup useGetConfigureModel * Added wave animation * Create useMainViewState intead of import helper atom * Remove unused code * Take a back switch ui * Toggle using switch component * Add dynamic primary color * Cleanup import * Added uikit scroll area * Add best practice form * Added toaster container * Fix loader container * Add hooks useDownloadState * Added tooltip on ribbon menu * Added case user multiple download model * Adjust input style with bigger ring * Restyle my model screen * Replace useStartStop model with useActiveModel * Import icon using Icon name * Fix missing login loading start and stop model * WIP integrate with cmdk * Move layout search bar on middle of app * Added function cancel download * Cleanup model explore * Cleanup unused code * Move app version in bototmbar or footer * WIP chat screen * WIP chat screen * Cleanup style and remove unsed code * Added command for showing downloaded model * Fix missing keyframe loader dot animation * Conditional loader of plugin setting * WIP history list message * chore: rebase main * Adding script ui into root package * Fix different version react hooks form * Add close toaster * Added status model active or not on list of command * Conditional showing info if user don't have a model * Disabled toolbar chat when user not yet have convo * chore: fix state * fix: get resource atom * Fix conditional bottom bar * fix: model download state * Fix font * Improve icon my model * Add toaster delete chat * Remove test classname * Fix scroll chat body * Fix scrolling chat body * chore: add message update * Add uikit into depedencies on root package * Update chat flow * Fix hot reload ui changes * Increate background color chat screen light mode * Added visual conversation active state * Added build:uikit on gh actions * chore: attempt to fix CI * fix: deps * fix: tests * chore: attempt to fix CI --------- Co-authored-by: Louis <louis@jan.ai>
96 lines
2.8 KiB
TypeScript
96 lines
2.8 KiB
TypeScript
'use client'
|
|
|
|
import { ChangeEvent, useEffect, useRef } from 'react'
|
|
|
|
import { useAtom, useAtomValue } from 'jotai'
|
|
|
|
import { currentPromptAtom } from '@/containers/Providers/Jotai'
|
|
|
|
import { useCreateConversation } from '@/hooks/useCreateConversation'
|
|
|
|
import useSendChatMessage from '@/hooks/useSendChatMessage'
|
|
|
|
import { getActiveConvoIdAtom } from '@/helpers/atoms/Conversation.atom'
|
|
import { selectedModelAtom } from '@/helpers/atoms/Model.atom'
|
|
|
|
const BasicPromptInput: React.FC = () => {
|
|
const activeConversationId = useAtomValue(getActiveConvoIdAtom)
|
|
const selectedModel = useAtomValue(selectedModelAtom)
|
|
const [currentPrompt, setCurrentPrompt] = useAtom(currentPromptAtom)
|
|
const { sendChatMessage } = useSendChatMessage()
|
|
const { requestCreateConvo } = useCreateConversation()
|
|
|
|
const textareaRef = useRef<HTMLTextAreaElement>(null)
|
|
|
|
const handleKeyDown = async (
|
|
event: React.KeyboardEvent<HTMLTextAreaElement>
|
|
) => {
|
|
if (event.key === 'Enter') {
|
|
if (!event.shiftKey) {
|
|
if (activeConversationId) {
|
|
event.preventDefault()
|
|
sendChatMessage()
|
|
} else {
|
|
if (!selectedModel) {
|
|
console.log('No model selected')
|
|
return
|
|
}
|
|
await requestCreateConvo(selectedModel)
|
|
sendChatMessage()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
adjustTextareaHeight()
|
|
}, [currentPrompt])
|
|
|
|
const handleMessageChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
|
|
setCurrentPrompt(event.target.value)
|
|
}
|
|
|
|
// Auto adjust textarea height based on content
|
|
const MAX_ROWS = 30
|
|
|
|
const adjustTextareaHeight = () => {
|
|
if (textareaRef.current) {
|
|
textareaRef.current.style.height = 'auto' // 1 row
|
|
const scrollHeight = textareaRef.current.scrollHeight
|
|
const maxScrollHeight =
|
|
parseInt(window.getComputedStyle(textareaRef.current).lineHeight, 10) *
|
|
MAX_ROWS
|
|
textareaRef.current.style.height = `${Math.min(
|
|
scrollHeight,
|
|
maxScrollHeight
|
|
)}px`
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className=" rounded-lg border border-border shadow-sm">
|
|
<textarea
|
|
ref={textareaRef}
|
|
onKeyDown={handleKeyDown}
|
|
value={currentPrompt}
|
|
onChange={handleMessageChange}
|
|
name="comment"
|
|
id="comment"
|
|
className="text-background-reverse block w-full resize-none border-0 bg-transparent py-1.5 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6"
|
|
placeholder="Message ..."
|
|
rows={1}
|
|
style={{ overflow: 'auto' }}
|
|
/>
|
|
{/* Spacer element to match the height of the toolbar */}
|
|
<div className="py-2" aria-hidden="true">
|
|
{/* Matches height of button in toolbar (1px border + 36px content height) */}
|
|
<div className="py-px">
|
|
<div className="h-9" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default BasicPromptInput
|