Files
veridian/app/components/ChatInput.vue
T
2026-01-11 05:04:29 -06:00

83 lines
3.2 KiB
Vue

<script setup lang="ts">
const inputRef = ref<HTMLTextAreaElement | null>(null);
const inputValue = ref('');
const isFocused = ref(false);
const emit = defineEmits<{
submit: [value: string];
}>();
const props = defineProps({
loading: {
type: Boolean,
default: false
}
})
const handleSubmit = () => {
if (inputValue.value.trim()) {
emit('submit', inputValue.value);
inputValue.value = '';
}
};
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Enter') {
if (event.shiftKey) return;
if (event.ctrlKey || event.metaKey) {
if (inputRef.value === null) return;
// inset new line
let cursorPosition = inputRef.value.selectionStart;
if (cursorPosition === undefined) return;
if (cursorPosition !== inputRef.value.selectionEnd) return;
inputValue.value = inputValue.value.slice(0, cursorPosition) + "\n" + inputValue.value.slice(cursorPosition);
// inputRef.value.selectionStart = cursorPosition + 1;
return;
}
event.preventDefault();
handleSubmit();
}
};
let hasCommandKey = false;
if (import.meta.server) {
let headers = useRequestHeaders();
hasCommandKey = headers['user-agent']?.includes('Mac OS') ?? false;
} else {
hasCommandKey = navigator.userAgent.includes('Mac OS');
}
</script>
<template>
<div class="w-full max-w-full mx-auto">
<div class="relative flex flex-col gap-3 p-3 rounded-2xl border transition-border ease-in-out duration-300 bg-[var(--color-input)]
border-[var(--color-highlight)] focus-within:border-[var(--color-highlight-high)]">
<!-- Text Input -->
<div class="flex-1 min-w-0">
<textarea v-model="inputValue" ref="inputRef"
:placeholder="`Start something great. Press ${hasCommandKey ? '⌘ + Enter' : 'ctrl + Enter'} to insert a new line.`"
@focus="isFocused = true" @blur="isFocused = false" @keydown="handleKeyDown"
class="w-full bg-transparent text-[var(--color-text)] placeholder-white/50 resize-none outline-none text-[15px] leading-6 min-h-[24px] max-h-32 overflow-y-auto scrollbar-thin scrollbar-thumb-white/20 scrollbar-track-transparent"
rows="2"></textarea>
</div>
<!-- Toolbar -->
<div class="flex">
<div class="flex-1"></div>
<!-- Send Button -->
<button aria-label="Send message" @click="handleSubmit" :disabled="!inputValue.trim() || loading"
:class="[
'p-2 rounded-xl transition-all duration-200 flex items-center justify-center',
inputValue.trim()
? 'bg-[var(--color-accent)] text-[var(--color-accent-text)] hover:bg-[var(--color-accent-hover)]'
: 'bg-[var(--color-highlight)] text-[var(--color-highlight-high)] cursor-not-allowed'
]">
<Icon v-if="loading" name="svg-spinners:ring-resize" class="w-4 h-4" />
<Icon v-else name="mynaui:send-solid" class="w-4 h-4" />
</button>
</div>
</div>
</div>
</template>