Prompts.svelte 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <script lang="ts">
  2. import { prompts, settings, user } from '$lib/stores';
  3. import {
  4. extractCurlyBraceWords,
  5. getUserPosition,
  6. getFormattedDate,
  7. getFormattedTime,
  8. getCurrentDateTime,
  9. getUserTimezone,
  10. getWeekday
  11. } from '$lib/utils';
  12. import { tick, getContext, onMount, onDestroy } from 'svelte';
  13. import { toast } from 'svelte-sonner';
  14. const i18n = getContext('i18n');
  15. export let command = '';
  16. export let onSelect = (e) => {};
  17. let selectedPromptIdx = 0;
  18. let filteredPrompts = [];
  19. $: filteredPrompts = $prompts
  20. .filter((p) => p.command.toLowerCase().includes(command.toLowerCase()))
  21. .sort((a, b) => a.title.localeCompare(b.title));
  22. $: if (command) {
  23. selectedPromptIdx = 0;
  24. }
  25. export const selectUp = () => {
  26. selectedPromptIdx = Math.max(0, selectedPromptIdx - 1);
  27. };
  28. export const selectDown = () => {
  29. selectedPromptIdx = Math.min(selectedPromptIdx + 1, filteredPrompts.length - 1);
  30. };
  31. let container;
  32. let adjustHeightDebounce;
  33. const adjustHeight = () => {
  34. if (container) {
  35. if (adjustHeightDebounce) {
  36. clearTimeout(adjustHeightDebounce);
  37. }
  38. adjustHeightDebounce = setTimeout(() => {
  39. if (!container) return;
  40. // Ensure the container is visible before adjusting height
  41. const rect = container.getBoundingClientRect();
  42. container.style.maxHeight = Math.max(Math.min(240, rect.bottom - 80), 100) + 'px';
  43. }, 100);
  44. }
  45. };
  46. const confirmPrompt = async (command) => {
  47. onSelect({ type: 'prompt', data: command });
  48. };
  49. onMount(() => {
  50. window.addEventListener('resize', adjustHeight);
  51. adjustHeight();
  52. });
  53. onDestroy(() => {
  54. window.removeEventListener('resize', adjustHeight);
  55. });
  56. </script>
  57. {#if filteredPrompts.length > 0}
  58. <div
  59. id="commands-container"
  60. class="px-2 mb-2 text-left w-full absolute bottom-0 left-0 right-0 z-10"
  61. >
  62. <div class="flex w-full rounded-xl border border-gray-100 dark:border-gray-850">
  63. <div class="flex flex-col w-full rounded-xl bg-white dark:bg-gray-900 dark:text-gray-100">
  64. <div
  65. class="m-1 overflow-y-auto p-1 space-y-0.5 scrollbar-hidden max-h-60"
  66. id="command-options-container"
  67. bind:this={container}
  68. >
  69. {#each filteredPrompts as promptItem, promptIdx}
  70. <button
  71. class=" px-3 py-1.5 rounded-xl w-full text-left {promptIdx === selectedPromptIdx
  72. ? ' bg-gray-50 dark:bg-gray-850 selected-command-option-button'
  73. : ''}"
  74. type="button"
  75. on:click={() => {
  76. confirmPrompt(promptItem);
  77. }}
  78. on:mousemove={() => {
  79. selectedPromptIdx = promptIdx;
  80. }}
  81. on:focus={() => {}}
  82. >
  83. <div class=" font-medium text-black dark:text-gray-100">
  84. {promptItem.command}
  85. </div>
  86. <div class=" text-xs text-gray-600 dark:text-gray-100">
  87. {promptItem.title}
  88. </div>
  89. </button>
  90. {/each}
  91. </div>
  92. <div
  93. class=" px-2 pt-0.5 pb-1 text-xs text-gray-600 dark:text-gray-100 bg-white dark:bg-gray-900 rounded-b-xl flex items-center space-x-1"
  94. >
  95. <div>
  96. <svg
  97. xmlns="http://www.w3.org/2000/svg"
  98. fill="none"
  99. viewBox="0 0 24 24"
  100. stroke-width="1.5"
  101. stroke="currentColor"
  102. class="w-3 h-3"
  103. >
  104. <path
  105. stroke-linecap="round"
  106. stroke-linejoin="round"
  107. d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z"
  108. />
  109. </svg>
  110. </div>
  111. <div class="line-clamp-1">
  112. {$i18n.t(
  113. 'Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.'
  114. )}
  115. </div>
  116. </div>
  117. </div>
  118. </div>
  119. </div>
  120. {/if}