Bläddra i källkod

melhorias no chat do oraculo

leonardo 2 månader sedan
förälder
incheckning
401f5f5109
1 ändrade filer med 77 tillägg och 6 borttagningar
  1. 77 6
      src/views/pagina-inicial/PaginaInicialView.vue

+ 77 - 6
src/views/pagina-inicial/PaginaInicialView.vue

@@ -1,5 +1,5 @@
 <script setup>
-import { computed, onUnmounted, ref } from "vue";
+import { computed, nextTick, onMounted, onUnmounted, ref, watch } from "vue";
 import ChatWindow from "../../components/ChatWindow.vue";
 import LayoutSistema from "../../layout/LayoutSistema.vue";
 import { useChat } from "../../composables/useChat.js";
@@ -43,6 +43,76 @@ async function onLandingSend() {
   landingDraft.value = "";
   await sendMessage(text);
 }
+
+
+const FRASES_EXEMPLO = [
+  "Qual é a política de férias da empresa?",
+  "Resuma o manual de integração de novos funcionários",
+  "Como solicito reembolso de despesas de viagem?",
+  "Quais são os benefícios disponíveis para colaboradores?",
+];
+const PLACEHOLDER_PADRAO = "Digite sua pergunta...";
+const placeholderTexto = ref(PLACEHOLDER_PADRAO);
+let typingTimer = null;
+let fraseIdx = 0;
+
+const prefereMenosMovimento =
+  typeof window !== "undefined" &&
+  window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches === true;
+
+function digitar(i) {
+  const frase = FRASES_EXEMPLO[fraseIdx];
+  placeholderTexto.value = frase.slice(0, i) + (i < frase.length ? "▍" : "");
+  if (i < frase.length) typingTimer = setTimeout(() => digitar(i + 1), 40 + Math.random() * 45);
+  else typingTimer = setTimeout(() => apagar(frase.length), 2400);
+}
+
+function apagar(i) {
+  const frase = FRASES_EXEMPLO[fraseIdx];
+  placeholderTexto.value = frase.slice(0, i) + (i > 0 ? "▍" : "");
+  if (i > 0) typingTimer = setTimeout(() => apagar(i - 1), 18);
+  else {
+    fraseIdx = (fraseIdx + 1) % FRASES_EXEMPLO.length;
+    typingTimer = setTimeout(() => digitar(0), 400);
+  }
+}
+
+function iniciarTypewriter() {
+  if (prefereMenosMovimento || typingTimer) return;
+  digitar(0);
+}
+
+function pararTypewriter() {
+  clearTimeout(typingTimer);
+  typingTimer = null;
+  placeholderTexto.value = PLACEHOLDER_PADRAO;
+}
+
+watch(
+  [isLanding, landingDraft],
+  ([landing, draft]) => {
+    if (landing && !draft) iniciarTypewriter();
+    else pararTypewriter();
+  },
+  { immediate: true }
+);
+onUnmounted(pararTypewriter);
+
+
+const textareaEl = ref(null);
+
+function ajustarAltura() {
+  const el = textareaEl.value;
+  if (!el) return;
+  el.style.height = "auto";
+  el.style.height = `${Math.min(el.scrollHeight, 220)}px`;
+}
+
+watch(landingDraft, () => nextTick(ajustarAltura));
+
+onMounted(() => {
+  textareaEl.value?.focus();
+});
 </script>
 
 <template>
@@ -54,18 +124,19 @@ async function onLandingSend() {
           Digite sua pergunta abaixo. Você também pode alimentar a base pela barra lateral.
         </div>
 
-        <div class="mt-6 rounded-2xl border border-gray-300 bg-white/70 p-4 shadow-sm backdrop-blur-md dark:border-white/10 dark:bg-white/[0.04]">
+        <div class="mt-6 rounded-2xl border border-gray-300 bg-white/70 p-4 shadow-sm backdrop-blur-md transition-[border-color,box-shadow] duration-200 focus-within:border-ring/60 focus-within:ring-2 focus-within:ring-ring/15 dark:border-white/10 dark:bg-white/[0.04] dark:focus-within:border-ring/60">
           <textarea
+            ref="textareaEl"
             v-model="landingDraft"
             rows="3"
-            placeholder="Digite sua pergunta..."
-            class="min-h-20 resize-none border-0 bg-transparent shadow-none focus:ring-0 !outline-none"
-            style="resize: none"
+            :placeholder="placeholderTexto"
+            aria-label="Digite sua pergunta"
+            class="min-h-20 max-h-[220px] w-full resize-none border-0 bg-transparent shadow-none focus:ring-0 !outline-none"
             @keydown.enter.exact.prevent="onLandingSend"
           />
           <div class="mt-3 flex items-center justify-between gap-3 ">
             <span class="text-xs text-gray-400 dark:text-gray-500">Enter para enviar · Shift+Enter para nova linha</span>
-            <BaseButton :disabled="chatLoading || !landingDraft.trim()" @click="onLandingSend">
+            <BaseButton :disabled="chatLoading || !landingDraft.trim()" :loading="chatLoading" @click="onLandingSend">
               <svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                 <path stroke-linecap="round" stroke-linejoin="round" d="M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5" />
               </svg>