diff --git a/frontend/src/components/tag_input.tsx b/frontend/src/components/tag_input.tsx
index babd78b..3ffc953 100644
--- a/frontend/src/components/tag_input.tsx
+++ b/frontend/src/components/tag_input.tsx
@@ -4,6 +4,9 @@ import {useTranslation} from "react-i18next";
import {network} from "../network/network.ts";
import {LuInfo} from "react-icons/lu";
import {MdSearch} from "react-icons/md";
+import Button from "./button.tsx";
+import Input, {TextArea} from "./input.tsx";
+import {ErrorAlert} from "./alert.tsx";
export default function TagInput({ onAdd, mainTag }: { onAdd: (tag: Tag) => void, mainTag?: boolean }) {
const [keyword, setKeyword] = useState("")
@@ -142,4 +145,61 @@ class Debounce {
this.timer = null
}
}
+}
+
+export function QuickAddTagDialog({ onAdded }: { onAdded: (tags: Tag[]) => void }) {
+ const {t} = useTranslation();
+
+ const [text, setText] = useState("")
+
+ const [type, setType] = useState("")
+
+ const [error, setError] = useState(null)
+
+ const handleSubmit = async () => {
+ if (text.trim().length === 0) {
+ return
+ }
+ setError(null)
+ const names = text.split(",").filter((n) => n.length > 0)
+ const res = await network.getOrCreateTags(names, type)
+ if (!res.success) {
+ setError(res.message)
+ return
+ }
+ const tags = res.data!
+ onAdded(tags)
+ setText("")
+ setType("")
+ const dialog = document.getElementById("quick_add_tag_dialog") as HTMLDialogElement
+ dialog.close()
+ }
+
+ return <>
+
+
+ >
}
\ No newline at end of file
diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts
index ef8f2aa..5fdecf3 100644
--- a/frontend/src/i18n.ts
+++ b/frontend/src/i18n.ts
@@ -172,6 +172,11 @@ export const i18nData = {
"About": "About",
"Home": "Home",
"Other": "Other",
+ "Quick Add": "Quick Add",
+ "Add Tags": "Add Tags",
+ "Input tags separated by commas.": "Input tags separated by commas.",
+ "If the tag does not exist, it will be created automatically.": "If the tag does not exist, it will be created automatically.",
+ "Optionally, you can specify a type for the new tags.": "Optionally, you can specify a type for the new tags.",
}
},
"zh-CN": {
@@ -347,6 +352,11 @@ export const i18nData = {
"About": "关于",
"Home": "首页",
"Other": "其他",
+ "Quick Add": "快速添加",
+ "Add Tags": "添加标签",
+ "Input tags separated by commas.": "输入标签, 用逗号分隔。",
+ "If the tag does not exist, it will be created automatically.": "如果标签不存在, 将自动创建。",
+ "Optionally, you can specify a type for the new tags.": "您可以选择为新标签指定一个类型。",
}
},
"zh-TW": {
@@ -522,6 +532,11 @@ export const i18nData = {
"About": "關於",
"Home": "首頁",
"Other": "其他",
+ "Quick Add": "快速添加",
+ "Add Tags": "添加標籤",
+ "Input tags separated by commas.": "輸入標籤, 用逗號分隔。",
+ "If the tag does not exist, it will be created automatically.": "如果標籤不存在, 將自動創建。",
+ "Optionally, you can specify a type for the new tags.": "您可以選擇為新標籤指定一個類型。",
}
}
}
diff --git a/frontend/src/network/network.ts b/frontend/src/network/network.ts
index dadc3e3..1caf993 100644
--- a/frontend/src/network/network.ts
+++ b/frontend/src/network/network.ts
@@ -330,6 +330,22 @@ class Network {
}
}
+ async getOrCreateTags(names: string[], tagType: string): Promise> {
+ try {
+ const response = await axios.post(`${this.apiBaseUrl}/tag/batch`, {
+ names,
+ type: tagType
+ })
+ return response.data
+ } catch (e: any) {
+ console.error(e)
+ return {
+ success: false,
+ message: e.toString(),
+ }
+ }
+ }
+
async getTagByName(name: string): Promise> {
try {
const response = await axios.get(`${this.apiBaseUrl}/tag/${name}`)
diff --git a/frontend/src/pages/edit_resource_page.tsx b/frontend/src/pages/edit_resource_page.tsx
index 7f703bd..50345e2 100644
--- a/frontend/src/pages/edit_resource_page.tsx
+++ b/frontend/src/pages/edit_resource_page.tsx
@@ -8,7 +8,7 @@ import { useTranslation } from "react-i18next";
import { app } from "../app.ts";
import { ErrorAlert } from "../components/alert.tsx";
import Loading from "../components/loading.tsx";
-import TagInput from "../components/tag_input.tsx";
+import TagInput, {QuickAddTagDialog} from "../components/tag_input.tsx";
export default function EditResourcePage() {
const [title, setTitle] = useState("")
@@ -178,9 +178,30 @@ export default function EditResourcePage() {
})
}
- {
- setTags([...tags, tag])
- }} />
+
+ {
+ setTags((prev) => {
+ const existingTag = prev.find(t => t.id === tag.id);
+ if (existingTag) {
+ return prev; // If the tag already exists, do not add it again
+ }
+ return [...prev, tag];
+ })
+ }} />
+
+ {
+ setTags((prev) => {
+ const newTags = [...prev];
+ for (const tag of tags) {
+ const existingTag = newTags.find(t => t.id === tag.id);
+ if (!existingTag) {
+ newTags.push(tag);
+ }
+ }
+ return newTags;
+ })
+ }}/>
+
{t("Description")}