Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

QueryBox.vue 3.0 KiB

3 settimane fa
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. <script setup lang="ts">
  2. import { onMounted, onUnmounted, ref } from 'vue'
  3. const query = defineModel<string>({ default: '' })
  4. let emit = defineEmits(['onChange', 'submit']);
  5. const inputRef = ref<HTMLInputElement | null>(null)
  6. const triggerChange = () => {
  7. emit('onChange', query.value)
  8. }
  9. const submit = () => {
  10. const value = query.value.trim()
  11. if (!value) return
  12. emit('submit', value)
  13. }
  14. const onGlobalKey = (event: KeyboardEvent) => {
  15. if (event.key !== '/' || event.metaKey || event.ctrlKey || event.altKey) return
  16. const target = event.target as HTMLElement | null
  17. const tag = target?.tagName
  18. if (tag === 'INPUT' || tag === 'TEXTAREA' || target?.isContentEditable) return
  19. event.preventDefault()
  20. inputRef.value?.focus()
  21. }
  22. onMounted(() => window.addEventListener('keydown', onGlobalKey))
  23. onUnmounted(() => window.removeEventListener('keydown', onGlobalKey))
  24. </script>
  25. <template>
  26. <form class="mx-auto w-full max-w-2xl" @submit.prevent="submit">
  27. <label class="sr-only" for="query-box">Query</label>
  28. <div
  29. class="group flex h-14 items-center gap-3 rounded-2xl border border-line bg-white/[0.035] px-3.5 shadow-[inset_0_1px_0_0_rgba(255,255,255,0.04)] transition-[border-color,box-shadow,background-color] duration-200 focus-within:border-accent/55 focus-within:bg-white/[0.05] focus-within:shadow-[inset_0_1px_0_0_rgba(255,255,255,0.06),0_0_0_3px_color-mix(in_oklab,var(--color-accent,oklch(0.82_0.1_180))_18%,transparent)]"
  30. >
  31. <span class="grid h-8 w-8 shrink-0 place-items-center rounded-xl border border-line text-muted">
  32. <svg
  33. class="h-3.5 w-3.5"
  34. viewBox="0 0 16 16"
  35. fill="none"
  36. stroke="currentColor"
  37. stroke-width="1.5"
  38. aria-hidden="true"
  39. >
  40. <circle cx="7" cy="7" r="4.25" />
  41. <path d="M10.4 10.4 14 14" stroke-linecap="round" />
  42. </svg>
  43. </span>
  44. <input
  45. id="query-box"
  46. ref="inputRef"
  47. v-model="query"
  48. type="text"
  49. autocomplete="off"
  50. spellcheck="false"
  51. placeholder="Ask something…"
  52. class="h-full min-w-0 flex-1 bg-transparent text-[15px] leading-none text-white caret-accent outline-none placeholder:text-muted/70"
  53. @input="triggerChange"
  54. />
  55. <kbd
  56. class="hidden h-6 shrink-0 items-center rounded-md border border-line px-1.5 font-mono text-[10px] tracking-wide text-muted sm:inline-flex"
  57. >
  58. /
  59. </kbd>
  60. <button
  61. type="submit"
  62. class="inline-flex h-8 shrink-0 items-center gap-1.5 rounded-xl bg-accent/15 px-3 text-xs font-medium text-accent transition-colors hover:bg-accent/25 disabled:cursor-not-allowed disabled:opacity-40"
  63. :disabled="!query.trim()"
  64. >
  65. Send
  66. <svg class="h-3 w-3" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
  67. <path d="M2 6h8M7 3l3 3-3 3" stroke-linecap="round" stroke-linejoin="round" />
  68. </svg>
  69. </button>
  70. </div>
  71. </form>
  72. </template>