Add typeahead prompt selector with fuzzy search on titles
This replaces the prompt dropdown button with a fuzzy search input to filter prompts. Uses [svelte-typeahead](https://metonym.github.io/svelte-typeahead/).
This commit is contained in:
		
							parent
							
								
									e2027a3d27
								
							
						
					
					
						commit
						76fd31ef9e
					
				| 
						 | 
					@ -39,6 +39,7 @@
 | 
				
			||||||
        "svelte-markdown": "^0.2.3",
 | 
					        "svelte-markdown": "^0.2.3",
 | 
				
			||||||
        "svelte-modals": "^1.2.1",
 | 
					        "svelte-modals": "^1.2.1",
 | 
				
			||||||
        "svelte-spa-router": "^3.3.0",
 | 
					        "svelte-spa-router": "^3.3.0",
 | 
				
			||||||
 | 
					        "svelte-typeahead": "^4.4.1",
 | 
				
			||||||
        "svelte-use-click-outside": "^1.0.0",
 | 
					        "svelte-use-click-outside": "^1.0.0",
 | 
				
			||||||
        "tslib": "^2.6.2",
 | 
					        "tslib": "^2.6.2",
 | 
				
			||||||
        "typescript": "^5.0.4",
 | 
					        "typescript": "^5.0.4",
 | 
				
			||||||
| 
						 | 
					@ -2576,6 +2577,15 @@
 | 
				
			||||||
        "url": "https://github.com/sponsors/ljharb"
 | 
					        "url": "https://github.com/sponsors/ljharb"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/fuzzy": {
 | 
				
			||||||
 | 
					      "version": "0.1.3",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/fuzzy/-/fuzzy-0.1.3.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-/gZffu4ykarLrCiP3Ygsa86UAo1E5vEVlvTrpkKywXSbP9Xhln3oSp9QSV57gEq3JFFpGJ4GZ+5zdEp3FcUh4w==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">= 0.6.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/get-intrinsic": {
 | 
					    "node_modules/get-intrinsic": {
 | 
				
			||||||
      "version": "1.2.2",
 | 
					      "version": "1.2.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz",
 | 
				
			||||||
| 
						 | 
					@ -4514,6 +4524,12 @@
 | 
				
			||||||
        "node": ">=12"
 | 
					        "node": ">=12"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/svelte-search": {
 | 
				
			||||||
 | 
					      "version": "1.1.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/svelte-search/-/svelte-search-1.1.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-e5hci9fZPMXb3fuRZvcYJGqh448M8vV3biY4lN4Nr9fqrG/HBnTjWYstKb399aUe9tsBxRbxRAWgtKicisL23g==",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/svelte-spa-router": {
 | 
					    "node_modules/svelte-spa-router": {
 | 
				
			||||||
      "version": "3.3.0",
 | 
					      "version": "3.3.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/svelte-spa-router/-/svelte-spa-router-3.3.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/svelte-spa-router/-/svelte-spa-router-3.3.0.tgz",
 | 
				
			||||||
| 
						 | 
					@ -4526,6 +4542,16 @@
 | 
				
			||||||
        "url": "https://github.com/sponsors/ItalyPaleAle"
 | 
					        "url": "https://github.com/sponsors/ItalyPaleAle"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/svelte-typeahead": {
 | 
				
			||||||
 | 
					      "version": "4.4.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/svelte-typeahead/-/svelte-typeahead-4.4.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-U8EYkCQ1HaDrQq1fnkVCEm8emZrdEfgfHhMulgOdoYnWV5PTvypiwCTNvqqxFHbz9ZGe5juAR9ok5tEcfnP9zw==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "fuzzy": "0.1.3",
 | 
				
			||||||
 | 
					        "svelte-search": "^1.1.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/svelte-use-click-outside": {
 | 
					    "node_modules/svelte-use-click-outside": {
 | 
				
			||||||
      "version": "1.0.0",
 | 
					      "version": "1.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/svelte-use-click-outside/-/svelte-use-click-outside-1.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/svelte-use-click-outside/-/svelte-use-click-outside-1.0.0.tgz",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,6 +45,7 @@
 | 
				
			||||||
    "svelte-markdown": "^0.2.3",
 | 
					    "svelte-markdown": "^0.2.3",
 | 
				
			||||||
    "svelte-modals": "^1.2.1",
 | 
					    "svelte-modals": "^1.2.1",
 | 
				
			||||||
    "svelte-spa-router": "^3.3.0",
 | 
					    "svelte-spa-router": "^3.3.0",
 | 
				
			||||||
 | 
					    "svelte-typeahead": "^4.4.1",
 | 
				
			||||||
    "svelte-use-click-outside": "^1.0.0",
 | 
					    "svelte-use-click-outside": "^1.0.0",
 | 
				
			||||||
    "tslib": "^2.6.2",
 | 
					    "tslib": "^2.6.2",
 | 
				
			||||||
    "typescript": "^5.0.4",
 | 
					    "typescript": "^5.0.4",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										32
									
								
								src/app.scss
								
								
								
								
							
							
						
						
									
										32
									
								
								src/app.scss
								
								
								
								
							| 
						 | 
					@ -264,6 +264,38 @@ $modal-background-background-color-dark: rgba($dark, 0.86) !default; // remove t
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[data-svelte-typeahead] {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ul.svelte-typeahead-list {
 | 
				
			||||||
 | 
					    max-height: calc(60vh);
 | 
				
			||||||
 | 
					    overflow: auto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    > li:not(:last-of-type) {
 | 
				
			||||||
 | 
					      padding: 0;
 | 
				
			||||||
 | 
					      border-bottom: 0 none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  &[aria-expanded="true"] {
 | 
				
			||||||
 | 
					    z-index: 3;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [data-svelte-search] {
 | 
				
			||||||
 | 
					    flex: 1;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    input {
 | 
				
			||||||
 | 
					      @extend .button;
 | 
				
			||||||
 | 
					      @extend .default-text;
 | 
				
			||||||
 | 
					      text-align: center;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					      &::placeholder {
 | 
				
			||||||
 | 
					        @extend .default-text;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Bulma layout hacks */
 | 
					/* Bulma layout hacks */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.chat-option-menu.navbar-item {
 | 
					.chat-option-menu.navbar-item {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,39 +1,37 @@
 | 
				
			||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					  import Typeahead from 'svelte-typeahead'
 | 
				
			||||||
  import prompts from '../awesome-chatgpt-prompts/prompts.csv'
 | 
					  import prompts from '../awesome-chatgpt-prompts/prompts.csv'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const inputPrompt = (prompt: string) => {
 | 
					  const inputPrompt = (prompt: string) => {
 | 
				
			||||||
    input.value = prompt
 | 
					    input.value = prompt
 | 
				
			||||||
    input.style.height = 'auto'
 | 
					    input.style.height = 'auto'
 | 
				
			||||||
    input.style.height = input.scrollHeight + 'px'
 | 
					    input.style.height = input.scrollHeight + 'px'
 | 
				
			||||||
    active = false
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let input : HTMLTextAreaElement
 | 
					  const extract = (prompt: typeof prompts[0]) => prompt.act
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let active: boolean = false
 | 
					  export let input : HTMLTextAreaElement
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{#if input}
 | 
					{#if input}
 | 
				
			||||||
<div class="columns is-centered">
 | 
					<div class="columns is-centered">
 | 
				
			||||||
  <div class="column is-half">
 | 
					  <div class="column is-half">
 | 
				
			||||||
    <div class="dropdown is-fullwidth" class:is-active={active}>
 | 
					    <Typeahead
 | 
				
			||||||
      <!-- svelte-ignore a11y-click-events-have-key-events -->
 | 
					      data={prompts}
 | 
				
			||||||
      <div class="dropdown-trigger" on:click={() => { active = !active }}>
 | 
					      {extract}
 | 
				
			||||||
        <button class="button is-fullwidth" aria-haspopup="true" aria-controls="dropdown-menu">
 | 
					      label="Select a pre-made prompt"
 | 
				
			||||||
          <span>Select a pre-made prompt</span>
 | 
					      hideLabel
 | 
				
			||||||
          <span class="icon is-small">👇</span>
 | 
					      showDropdownOnFocus
 | 
				
			||||||
        </button>
 | 
					      showAllResultsOnFocus
 | 
				
			||||||
      </div>
 | 
					      inputAfterSelect="clear"
 | 
				
			||||||
      <div class="dropdown-menu" id="dropdown-menu" role="menu">
 | 
					      on:select={({ detail }) => inputPrompt(detail.original.prompt)}
 | 
				
			||||||
        <div class="dropdown-content">
 | 
					      placeholder="Select a pre-made prompt 👇"
 | 
				
			||||||
          {#each prompts as prompt}
 | 
					      let:result
 | 
				
			||||||
            <a title={prompt.prompt} class="dropdown-item" href={'#'} on:click|preventDefault={() => inputPrompt(prompt.prompt)}>
 | 
					    >
 | 
				
			||||||
              {prompt.act}
 | 
					      <a class="dropdown-item" href="#top" on:click|preventDefault title="{result.original.prompt}">
 | 
				
			||||||
            </a>
 | 
					        {@html result.string}
 | 
				
			||||||
          {/each}
 | 
					      </a>
 | 
				
			||||||
        </div>
 | 
					    </Typeahead>
 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue