|
1 | 1 | <script lang="ts"> |
2 | 2 | import { createEventDispatcher, getContext } from 'svelte'; |
3 | | - import { tags } from '$lib/stores'; |
4 | | - import { toast } from 'svelte-sonner'; |
5 | 3 | const dispatch = createEventDispatcher(); |
6 | 4 |
|
7 | 5 | const i18n = getContext('i18n'); |
8 | 6 |
|
9 | | - export let label = ''; |
10 | 7 | export let suggestionTags = []; |
11 | 8 |
|
12 | | - let showTagInput = false; |
13 | 9 | let tagName = ''; |
| 10 | + let showInput = false; |
| 11 | + let inputElement: HTMLInputElement; |
14 | 12 |
|
15 | 13 | const addTagHandler = async () => { |
16 | 14 | tagName = tagName.trim(); |
17 | 15 | if (tagName !== '') { |
18 | 16 | dispatch('add', tagName); |
19 | 17 | tagName = ''; |
20 | | - showTagInput = false; |
21 | | - } else { |
22 | | - toast.error($i18n.t(`Invalid Tag`)); |
23 | 18 | } |
24 | 19 | }; |
25 | | -</script> |
26 | 20 |
|
27 | | -<div class="px-0.5 flex {showTagInput ? 'flex-row-reverse' : ''}"> |
28 | | - {#if showTagInput} |
29 | | - <div class="flex items-center"> |
30 | | - <input |
31 | | - bind:value={tagName} |
32 | | - class=" px-2 cursor-pointer self-center text-xs h-fit bg-transparent outline-hidden line-clamp-1 w-[6.5rem]" |
33 | | - placeholder={$i18n.t('Add a tag')} |
34 | | - aria-label={$i18n.t('Add a tag')} |
35 | | - list="tagOptions" |
36 | | - on:keydown={(event) => { |
37 | | - if (event.key === 'Enter') { |
38 | | - addTagHandler(); |
39 | | - } |
40 | | - }} |
41 | | - /> |
42 | | - {#if suggestionTags.length > 0} |
43 | | - <datalist id="tagOptions"> |
44 | | - {#each suggestionTags as tag} |
45 | | - <option value={tag.name} /> |
46 | | - {/each} |
47 | | - </datalist> |
48 | | - {/if} |
| 21 | + const openInput = () => { |
| 22 | + showInput = true; |
| 23 | + setTimeout(() => inputElement?.focus(), 0); |
| 24 | + }; |
49 | 25 |
|
50 | | - <button type="button" aria-label={$i18n.t('Save Tag')} on:click={addTagHandler}> |
51 | | - <svg |
52 | | - xmlns="http://www.w3.org/2000/svg" |
53 | | - viewBox="0 0 16 16" |
54 | | - fill="currentColor" |
55 | | - stroke-width="2" |
56 | | - aria-hidden="true" |
57 | | - class="w-3 h-3" |
58 | | - > |
59 | | - <path |
60 | | - fill-rule="evenodd" |
61 | | - d="M12.416 3.376a.75.75 0 0 1 .208 1.04l-5 7.5a.75.75 0 0 1-1.154.114l-3-3a.75.75 0 0 1 1.06-1.06l2.353 2.353 4.493-6.74a.75.75 0 0 1 1.04-.207Z" |
62 | | - clip-rule="evenodd" |
63 | | - /> |
64 | | - </svg> |
65 | | - </button> |
66 | | - </div> |
67 | | - {/if} |
| 26 | + const closeInput = () => { |
| 27 | + if (tagName.trim() === '') { |
| 28 | + showInput = false; |
| 29 | + } |
| 30 | + }; |
| 31 | +</script> |
68 | 32 |
|
| 33 | +{#if showInput} |
| 34 | + <div class="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-gray-200/80 dark:bg-gray-700"> |
| 35 | + <span class="text-gray-500 dark:text-blue-400">+</span> |
| 36 | + <input |
| 37 | + bind:this={inputElement} |
| 38 | + bind:value={tagName} |
| 39 | + class="w-20 text-sm bg-transparent outline-hidden text-gray-700 dark:text-blue-400 placeholder:text-gray-400 dark:placeholder:text-blue-400/50" |
| 40 | + placeholder={$i18n.t('Add tag')} |
| 41 | + aria-label={$i18n.t('Add a tag')} |
| 42 | + list="tagOptions" |
| 43 | + on:keydown={(event) => { |
| 44 | + if (event.key === 'Enter' || event.key === ' ') { |
| 45 | + event.preventDefault(); |
| 46 | + addTagHandler(); |
| 47 | + } else if (event.key === 'Escape') { |
| 48 | + tagName = ''; |
| 49 | + showInput = false; |
| 50 | + } |
| 51 | + }} |
| 52 | + on:blur={closeInput} |
| 53 | + /> |
| 54 | + </div> |
| 55 | +{:else} |
69 | 56 | <button |
70 | | - class=" cursor-pointer self-center p-0.5 flex h-fit items-center rounded-full transition border dark:border-gray-600 border-dashed" |
71 | 57 | type="button" |
72 | | - aria-label={$i18n.t('Add Tag')} |
73 | | - on:click={() => { |
74 | | - showTagInput = !showTagInput; |
75 | | - }} |
| 58 | + class="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-gray-200/80 dark:bg-gray-700 text-gray-500 dark:text-blue-400 text-sm font-medium hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors" |
| 59 | + on:click={openInput} |
76 | 60 | > |
77 | | - <div class=" m-auto self-center"> |
78 | | - <svg |
79 | | - xmlns="http://www.w3.org/2000/svg" |
80 | | - viewBox="0 0 16 16" |
81 | | - aria-hidden="true" |
82 | | - fill="currentColor" |
83 | | - class="size-2.5 {showTagInput ? 'rotate-45' : ''} transition-all transform" |
84 | | - > |
85 | | - <path |
86 | | - d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z" |
87 | | - /> |
88 | | - </svg> |
89 | | - </div> |
| 61 | + <span>+</span> |
| 62 | + <span>{$i18n.t('Add Tag')}</span> |
90 | 63 | </button> |
| 64 | +{/if} |
91 | 65 |
|
92 | | - {#if label && !showTagInput} |
93 | | - <span class="text-xs pl-2 self-center">{label}</span> |
94 | | - {/if} |
95 | | -</div> |
| 66 | +{#if suggestionTags.length > 0} |
| 67 | + <datalist id="tagOptions"> |
| 68 | + {#each suggestionTags as tag} |
| 69 | + <option value={tag.name} /> |
| 70 | + {/each} |
| 71 | + </datalist> |
| 72 | +{/if} |
0 commit comments