refac: tags
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import TagInput from './Tags/TagInput.svelte';
|
|
||||||
import TagList from './Tags/TagList.svelte';
|
import TagList from './Tags/TagList.svelte';
|
||||||
import { getContext, createEventDispatcher } from 'svelte';
|
import { getContext, createEventDispatcher } from 'svelte';
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
@@ -8,9 +7,19 @@
|
|||||||
|
|
||||||
export let tags = [];
|
export let tags = [];
|
||||||
export let suggestionTags = [];
|
export let suggestionTags = [];
|
||||||
|
|
||||||
|
let inputValue = '';
|
||||||
|
|
||||||
|
const addTag = () => {
|
||||||
|
const value = inputValue.trim();
|
||||||
|
if (value !== '') {
|
||||||
|
dispatch('add', value);
|
||||||
|
inputValue = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ul class="flex flex-row flex-wrap gap-[0.3rem] line-clamp-1">
|
<div class="flex flex-wrap items-center gap-1.5 w-full">
|
||||||
<TagList
|
<TagList
|
||||||
{tags}
|
{tags}
|
||||||
on:delete={(e) => {
|
on:delete={(e) => {
|
||||||
@@ -18,11 +27,15 @@
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TagInput
|
<input
|
||||||
label={tags.length == 0 ? $i18n.t('Add Tags') : ''}
|
bind:value={inputValue}
|
||||||
{suggestionTags}
|
class="flex-1 min-w-24 px-1 text-xs bg-transparent outline-hidden placeholder:text-gray-400 dark:placeholder:text-gray-500"
|
||||||
on:add={(e) => {
|
placeholder={$i18n.t('Type to add tag...')}
|
||||||
dispatch('add', e.detail);
|
on:keydown={(event) => {
|
||||||
|
if (event.key === 'Enter' || event.key === ' ') {
|
||||||
|
event.preventDefault();
|
||||||
|
addTag();
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</ul>
|
</div>
|
||||||
|
|||||||
@@ -1,96 +1,72 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher, getContext } from 'svelte';
|
import { createEventDispatcher, getContext } from 'svelte';
|
||||||
import { tags } from '$lib/stores';
|
|
||||||
import { toast } from 'svelte-sonner';
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
export let label = '';
|
|
||||||
export let suggestionTags = [];
|
export let suggestionTags = [];
|
||||||
|
|
||||||
let showTagInput = false;
|
|
||||||
let tagName = '';
|
let tagName = '';
|
||||||
|
let showInput = false;
|
||||||
|
let inputElement: HTMLInputElement;
|
||||||
|
|
||||||
const addTagHandler = async () => {
|
const addTagHandler = async () => {
|
||||||
tagName = tagName.trim();
|
tagName = tagName.trim();
|
||||||
if (tagName !== '') {
|
if (tagName !== '') {
|
||||||
dispatch('add', tagName);
|
dispatch('add', tagName);
|
||||||
tagName = '';
|
tagName = '';
|
||||||
showTagInput = false;
|
}
|
||||||
} else {
|
};
|
||||||
toast.error($i18n.t(`Invalid Tag`));
|
|
||||||
|
const openInput = () => {
|
||||||
|
showInput = true;
|
||||||
|
setTimeout(() => inputElement?.focus(), 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeInput = () => {
|
||||||
|
if (tagName.trim() === '') {
|
||||||
|
showInput = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="px-0.5 flex {showTagInput ? 'flex-row-reverse' : ''}">
|
{#if showInput}
|
||||||
{#if showTagInput}
|
<div class="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-gray-200/80 dark:bg-gray-700">
|
||||||
<div class="flex items-center">
|
<span class="text-gray-500 dark:text-blue-400">+</span>
|
||||||
<input
|
<input
|
||||||
bind:value={tagName}
|
bind:this={inputElement}
|
||||||
class=" px-2 cursor-pointer self-center text-xs h-fit bg-transparent outline-hidden line-clamp-1 w-[6.5rem]"
|
bind:value={tagName}
|
||||||
placeholder={$i18n.t('Add a tag')}
|
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"
|
||||||
aria-label={$i18n.t('Add a tag')}
|
placeholder={$i18n.t('Add tag')}
|
||||||
list="tagOptions"
|
aria-label={$i18n.t('Add a tag')}
|
||||||
on:keydown={(event) => {
|
list="tagOptions"
|
||||||
if (event.key === 'Enter') {
|
on:keydown={(event) => {
|
||||||
event.preventDefault();
|
if (event.key === 'Enter' || event.key === ' ') {
|
||||||
addTagHandler();
|
event.preventDefault();
|
||||||
}
|
addTagHandler();
|
||||||
}}
|
} else if (event.key === 'Escape') {
|
||||||
/>
|
tagName = '';
|
||||||
{#if suggestionTags.length > 0}
|
showInput = false;
|
||||||
<datalist id="tagOptions">
|
}
|
||||||
{#each suggestionTags as tag}
|
}}
|
||||||
<option value={tag.name} />
|
on:blur={closeInput}
|
||||||
{/each}
|
/>
|
||||||
</datalist>
|
</div>
|
||||||
{/if}
|
{:else}
|
||||||
|
|
||||||
<button type="button" aria-label={$i18n.t('Save Tag')} on:click={addTagHandler}>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
fill="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
aria-hidden="true"
|
|
||||||
class="w-3 h-3"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
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"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class=" cursor-pointer self-center p-0.5 flex h-fit items-center rounded-full transition border dark:border-gray-600 border-dashed"
|
|
||||||
type="button"
|
type="button"
|
||||||
aria-label={$i18n.t('Add Tag')}
|
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"
|
||||||
on:click={() => {
|
on:click={openInput}
|
||||||
showTagInput = !showTagInput;
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div class=" m-auto self-center">
|
<span>+</span>
|
||||||
<svg
|
<span>{$i18n.t('Add Tag')}</span>
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
aria-hidden="true"
|
|
||||||
fill="currentColor"
|
|
||||||
class="size-2.5 {showTagInput ? 'rotate-45' : ''} transition-all transform"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
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"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</button>
|
</button>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if label && !showTagInput}
|
{#if suggestionTags.length > 0}
|
||||||
<span class="text-xs pl-2 self-center">{label}</span>
|
<datalist id="tagOptions">
|
||||||
{/if}
|
{#each suggestionTags as tag}
|
||||||
</div>
|
<option value={tag.name} />
|
||||||
|
{/each}
|
||||||
|
</datalist>
|
||||||
|
{/if}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
import Tooltip from '../Tooltip.svelte';
|
|
||||||
import XMark from '$lib/components/icons/XMark.svelte';
|
import XMark from '$lib/components/icons/XMark.svelte';
|
||||||
|
|
||||||
export let tag;
|
export let tag;
|
||||||
@@ -11,24 +10,14 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if tag}
|
{#if tag}
|
||||||
<Tooltip content={tag.name}>
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
class="flex items-center gap-0.5 px-1.5 py-[1px] rounded-lg bg-gray-500/20 text-gray-700 dark:text-gray-200 text-xs font-medium hover:bg-gray-500/30 transition-colors"
|
||||||
aria-label={$i18n.t('Remove this tag from list')}
|
on:click={() => {
|
||||||
class="relative group/tags px-1.5 py-[0.5px] gap-0.5 flex justify-between h-fit max-h-fit w-fit items-center rounded-lg bg-gray-500/20 text-gray-700 dark:text-gray-200 transition cursor-pointer"
|
onDelete();
|
||||||
on:click={() => {
|
}}
|
||||||
onDelete();
|
>
|
||||||
}}
|
<span class="line-clamp-1">{tag.name}</span>
|
||||||
>
|
<XMark className="size-3" strokeWidth="2.5" />
|
||||||
<div class=" text-[0.7rem] font-medium self-center line-clamp-1 w-fit">
|
</button>
|
||||||
{tag.name}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="hidden group-hover/tags:block transition">
|
|
||||||
<div class="rounded-full pl-[1px] backdrop-blur-sm h-full flex self-center cursor-pointer">
|
|
||||||
<XMark className="size-3" strokeWidth="2.5" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</Tooltip>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
Reference in New Issue
Block a user