Update TagInput.vue
This commit is contained in:
@@ -175,30 +175,31 @@ const handleDeleteTagGlobally = async (tagToDelete: TagInfo) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="tag-input-container">
|
<div class="relative w-full">
|
||||||
<!-- .selected-tags 移动到 .input-area 内部 -->
|
<div class="flex flex-wrap items-center gap-1 p-1.5 border border-border rounded cursor-text bg-background" @click="inputRef?.focus()">
|
||||||
<div class="input-area">
|
<div class="inline-flex flex-wrap gap-1">
|
||||||
<div class="selected-tags">
|
<span v-for="tag in selectedTags" :key="tag.id" class="inline-flex items-center bg-background-alt text-foreground text-sm px-2 py-0.5 rounded whitespace-nowrap border border-border">
|
||||||
<span v-for="tag in selectedTags" :key="tag.id" class="tag-item">
|
|
||||||
{{ tag.name }}
|
{{ tag.name }}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="remove-tag-local"
|
class="ml-1.5 p-0 bg-transparent border-none cursor-pointer text-text-secondary hover:text-foreground text-lg leading-none"
|
||||||
@click="removeTagLocally(tag)"
|
@click.stop="removeTagLocally(tag)"
|
||||||
:title="t('tags.removeSelection')"
|
:title="t('tags.removeSelection')"
|
||||||
>×</button>
|
>×</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="remove-tag-global"
|
class="ml-1 p-0 bg-transparent border-none cursor-pointer text-text-alt hover:text-error text-xs leading-none"
|
||||||
@click.stop="handleDeleteTagGlobally(tag)"
|
@click.stop="handleDeleteTagGlobally(tag)"
|
||||||
:title="t('tags.deleteTagGlobally')"
|
:title="t('tags.deleteTagGlobally')"
|
||||||
>🗑</button> <!-- 使用垃圾桶图标 -->
|
>
|
||||||
|
<i class="fas fa-trash-alt"></i>
|
||||||
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
ref="inputRef"
|
ref="inputRef"
|
||||||
type="text"
|
type="text"
|
||||||
class="tag-actual-input"
|
class="flex-grow border-none outline-none p-0.5 text-sm min-w-[100px] bg-transparent"
|
||||||
v-model="inputValue"
|
v-model="inputValue"
|
||||||
:placeholder="t('tags.inputPlaceholder')"
|
:placeholder="t('tags.inputPlaceholder')"
|
||||||
@focus="handleFocus"
|
@focus="handleFocus"
|
||||||
@@ -206,131 +207,19 @@ const handleDeleteTagGlobally = async (tagToDelete: TagInfo) => {
|
|||||||
@keydown="handleKeyDown"
|
@keydown="handleKeyDown"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
/>
|
/>
|
||||||
<ul v-if="showSuggestions && suggestions.length > 0" class="suggestions-list">
|
|
||||||
<li
|
|
||||||
v-for="suggestion in suggestions"
|
|
||||||
:key="suggestion.id"
|
|
||||||
@mousedown.prevent="selectTag(suggestion)"
|
|
||||||
>
|
|
||||||
{{ suggestion.name }}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<!-- 修改 v-if 条件,不再依赖 showSuggestions -->
|
|
||||||
<div v-if="isLoading" class="loading-small">{{ t('tags.loading') }}</div>
|
|
||||||
<div v-if="error" class="error-small">{{ t('tags.error', { error: error }) }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<ul v-if="showSuggestions && suggestions.length > 0" class="absolute top-full left-0 right-0 mt-0.5 bg-background border border-border rounded-b shadow-md list-none p-0 m-0 max-h-[150px] overflow-y-auto z-10">
|
||||||
|
<li
|
||||||
|
v-for="suggestion in suggestions"
|
||||||
|
:key="suggestion.id"
|
||||||
|
class="px-3 py-1.5 cursor-pointer hover:bg-hover text-sm"
|
||||||
|
@mousedown.prevent="selectTag(suggestion)"
|
||||||
|
>
|
||||||
|
{{ suggestion.name }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div v-if="isLoading" class="absolute bottom-[-1.5em] left-0 text-xs text-text-secondary mt-1">{{ t('tags.loading') }}</div>
|
||||||
|
<div v-if="error" class="absolute bottom-[-1.5em] left-0 text-xs text-error mt-1">{{ t('tags.error', { error: error }) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.tag-input-container {
|
|
||||||
/* 移除边框,让 .input-area 作为视觉边界 */
|
|
||||||
border-radius: 4px;
|
|
||||||
position: relative; /* 为了建议列表定位 */
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 100%; /* 占据父容器宽度 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-tags {
|
|
||||||
display: inline-flex; /* 改为 inline-flex 以便和 input 排列 */
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.3rem; /* 标签间距 */
|
|
||||||
/* margin-right: 0.5rem; */ /* 移除右边距 */
|
|
||||||
/* margin-bottom: 0.3rem; */ /* 如果换行,和下一行输入框的间距 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag-item {
|
|
||||||
background-color: #e0e0e0;
|
|
||||||
padding: 0.2rem 0.4rem;
|
|
||||||
border-radius: 3px;
|
|
||||||
display: inline-flex; /* 让按钮和文字在一行 */
|
|
||||||
align-items: center;
|
|
||||||
font-size: 0.9em;
|
|
||||||
white-space: nowrap; /* 防止标签内文字换行 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag-item button {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0 0.2rem;
|
|
||||||
margin-left: 0.3rem;
|
|
||||||
font-size: 1.1em; /* 放大图标 */
|
|
||||||
line-height: 1; /* 确保按钮高度一致 */
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
.tag-item button:hover {
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
.remove-tag-global {
|
|
||||||
font-size: 0.9em; /* 垃圾桶图标稍小 */
|
|
||||||
color: #a55; /* 红色提示危险操作 */
|
|
||||||
}
|
|
||||||
.remove-tag-global:hover {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.input-area {
|
|
||||||
border: 1px solid #ccc; /* 将边框应用到这里 */
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 0.3rem 0.5rem; /* 内边距 */
|
|
||||||
display: flex; /* 使用 flex 布局 */
|
|
||||||
flex-wrap: wrap; /* 允许内部元素(标签和输入框)换行 */
|
|
||||||
align-items: center; /* 垂直居中对齐 */
|
|
||||||
gap: 0.3rem; /* 标签和输入框之间的间距 */
|
|
||||||
cursor: text; /* 模拟文本输入框点击效果 */
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 对实际的 input 元素进行样式调整 */
|
|
||||||
.tag-actual-input {
|
|
||||||
flex-grow: 1; /* 占据剩余空间 */
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
padding: 0.2rem 0; /* 微调内边距 */
|
|
||||||
font-size: 1em;
|
|
||||||
min-width: 100px; /* 保证输入框有最小宽度 */
|
|
||||||
background: transparent; /* 背景透明 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.suggestions-list {
|
|
||||||
position: absolute;
|
|
||||||
top: calc(100% + 2px); /* 显示在 .input-area 下方,留一点空隙 */
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
background-color: white;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-top: none;
|
|
||||||
border-radius: 0 0 4px 4px;
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
max-height: 150px;
|
|
||||||
overflow-y: auto;
|
|
||||||
z-index: 10; /* 确保在其他元素之上 */
|
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.suggestions-list li {
|
|
||||||
padding: 0.5rem;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.suggestions-list li:hover {
|
|
||||||
background-color: #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-small, .error-small {
|
|
||||||
font-size: 0.8em;
|
|
||||||
color: #666;
|
|
||||||
margin-top: 0.2rem;
|
|
||||||
position: absolute; /* 避免推开布局 */
|
|
||||||
bottom: -1.5em; /* 显示在输入框下方 */
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
.error-small {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user