From b2a67f095a6a2c494e483e5645bf13c332021f3e Mon Sep 17 00:00:00 2001 From: bflatastic Date: Thu, 3 Oct 2024 19:53:26 +0700 Subject: [PATCH] input tags --- .../components/src/api/tags/EditTags.ts | 21 +++++ .../components/src/api/tags/ListTags.ts | 19 +++++ .../common/TagsInput/TagsInput.scss | 63 ++++++++++++++ .../components/common/TagsInput/TagsInput.tsx | 83 +++++++++++++++++++ .../hooks/useWeightFetch/useWeightFetch.tsx | 15 ++++ .../v2/view/pages/weight/WeightEditPage.tsx | 11 +++ 6 files changed, 212 insertions(+) create mode 100644 src/website/packages/components/src/api/tags/EditTags.ts create mode 100644 src/website/packages/components/src/api/tags/ListTags.ts create mode 100644 src/website/packages/fakeyou.com/src/components/common/TagsInput/TagsInput.scss create mode 100644 src/website/packages/fakeyou.com/src/components/common/TagsInput/TagsInput.tsx diff --git a/src/website/packages/components/src/api/tags/EditTags.ts b/src/website/packages/components/src/api/tags/EditTags.ts new file mode 100644 index 0000000000..0bcccb0575 --- /dev/null +++ b/src/website/packages/components/src/api/tags/EditTags.ts @@ -0,0 +1,21 @@ +import MakeRequest from "../MakeRequest"; + +export interface EditTagsRequest { + tags: string; +} + +export interface EditTagsResponse { + success: boolean; + tag_tokens: string[]; +} + +export const EditTags = MakeRequest< + string, + EditTagsRequest, + EditTagsResponse, + {} +>({ + method: "POST", + routingFunction: (weight_token: string) => + `/v1/tags/edit/model_weight/${weight_token}`, +}); diff --git a/src/website/packages/components/src/api/tags/ListTags.ts b/src/website/packages/components/src/api/tags/ListTags.ts new file mode 100644 index 0000000000..d162fea44f --- /dev/null +++ b/src/website/packages/components/src/api/tags/ListTags.ts @@ -0,0 +1,19 @@ +import MakeRequest from "../MakeRequest"; + +export interface ListTagsRequest {} + +export interface ListTagsResponse { + success: boolean; + tags: string[]; +} + +export const ListTags = MakeRequest< + string, + ListTagsRequest, + ListTagsResponse, + {} +>({ + method: "GET", + routingFunction: (weight_token: string) => + `/v1/tags/list/model_weight/${weight_token}`, +}); diff --git a/src/website/packages/fakeyou.com/src/components/common/TagsInput/TagsInput.scss b/src/website/packages/fakeyou.com/src/components/common/TagsInput/TagsInput.scss new file mode 100644 index 0000000000..419099b038 --- /dev/null +++ b/src/website/packages/fakeyou.com/src/components/common/TagsInput/TagsInput.scss @@ -0,0 +1,63 @@ +@import "scss/colours.scss"; + +.tags-input-container { + display: flex; + flex-wrap: wrap; + gap: 5px; + + &:focus-within { + border-color: $primary; + outline: 0; + box-shadow: 0 0 0 0.1rem $primary; + } +} + +.tag { + background-color: lighten($action, 10%); + border-radius: 5px; + padding: 0 8px; + display: flex; + align-items: center; + font-size: 15px; + gap: 8px; +} + +.tag button { + display: flex; + align-items: center; + justify-content: center; + padding: 0; + margin: 0; + background: none; + border: none; + cursor: pointer; + color: rgba($white, 0.6); + transition: all 0.2s; + + &:hover { + color: lighten($primary, 20%); + } +} + +input[type="text"] { + border: none; + outline: none; + flex: 1; + background-color: transparent; + color: $white; + + &::placeholder { + color: rgba($white, 0.5); + opacity: 1; /* Firefox */ + } + + &:-ms-input-placeholder { + /* Internet Explorer 10-11 */ + color: rgba($white, 0.5); + } + + &::-ms-input-placeholder { + /* Microsoft Edge */ + color: rgba($white, 0.5); + } +} diff --git a/src/website/packages/fakeyou.com/src/components/common/TagsInput/TagsInput.tsx b/src/website/packages/fakeyou.com/src/components/common/TagsInput/TagsInput.tsx new file mode 100644 index 0000000000..16339f15fd --- /dev/null +++ b/src/website/packages/fakeyou.com/src/components/common/TagsInput/TagsInput.tsx @@ -0,0 +1,83 @@ +import React, { useState } from "react"; +import "./TagsInput.scss"; +import Label from "../Label"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faXmark } from "@fortawesome/pro-solid-svg-icons"; + +interface TagsInputProps { + value: string[]; + label?: string; + onChange: (tags: string[]) => void; + className?: string; + tagsLimit?: number; +} + +const TagsInput: React.FC = ({ + value, + label, + onChange, + className, + tagsLimit = Infinity, +}) => { + const [inputValue, setInputValue] = useState(""); + + const handleKeyDown = (event: React.KeyboardEvent) => { + if ((event.key === "Enter" || event.key === ",") && inputValue.trim()) { + event.preventDefault(); + addTag(inputValue); + } else if (event.key === "Backspace" && inputValue === "") { + handleRemoveTag(value.length - 1); + } + }; + + const handleBlur = () => { + if (inputValue.trim()) { + addTag(inputValue); + } + }; + + const addTag = (tag: string) => { + const lowerCaseValue = tag.trim().toLowerCase(); + if (value.length < tagsLimit) { + onChange([...value, lowerCaseValue]); + setInputValue(""); + } else { + setInputValue(""); + } + }; + + const handleRemoveTag = (index: number) => { + const newTags = value.filter((_, i) => i !== index); + onChange(newTags); + }; + + return ( +
+ {label &&
+ ); +}; + +export default TagsInput; diff --git a/src/website/packages/fakeyou.com/src/hooks/useWeightFetch/useWeightFetch.tsx b/src/website/packages/fakeyou.com/src/hooks/useWeightFetch/useWeightFetch.tsx index 6a36311262..eabccdb809 100644 --- a/src/website/packages/fakeyou.com/src/hooks/useWeightFetch/useWeightFetch.tsx +++ b/src/website/packages/fakeyou.com/src/hooks/useWeightFetch/useWeightFetch.tsx @@ -9,6 +9,8 @@ import { UpdateWeight } from "@storyteller/components/src/api/weights/UpdateWeig import { DeleteWeight } from "@storyteller/components/src/api/weights/DeleteWeight"; import { useCoverImgUpload } from "hooks"; import { LanguageTag } from "@storyteller/components/src/api/Languages"; +import { ListTags } from "@storyteller/components/src/api/tags/ListTags"; +import { EditTags } from "@storyteller/components/src/api/tags/EditTags"; interface Props { onSuccess?: (res: Weight) => any; @@ -32,6 +34,7 @@ export default function useWeightFetch({ const [maybeUrlSlug, maybeUrlSlugSet] = useState(undefined); const [visibility, visibilitySet] = useState("public"); const [languageTag, languageTagSet] = useState("en" || null); + const [tags, tagsSet] = useState([]); const [descriptionMD, descriptionMDSet] = useState(""); const isLoading = status === FetchStatus.ready || status === FetchStatus.in_progress; @@ -64,6 +67,9 @@ export default function useWeightFetch({ weight_type: data?.weight_type || "", }) .then((res: any) => { + EditTags(token, { + tags: tags.join(","), + }); writeStatusSet(FetchStatus.success); history.replace(`/weight/${token}`); }) @@ -93,6 +99,7 @@ export default function useWeightFetch({ descriptionMDSet(""); visibilitySet("public"); languageTagSet("en"); + tagsSet([]); } }, [token, refetch]); @@ -118,6 +125,12 @@ export default function useWeightFetch({ languageTagSet(maybe_ietf_primary_language_subtag); onSuccess(res); setData(res); + + ListTags(token, {}).then((res: any) => { + if (res.success) { + tagsSet(res.tags); + } + }); } else { statusSet(FetchStatus.error); } @@ -143,5 +156,7 @@ export default function useWeightFetch({ visibility, writeStatus, languageTag, + tags, + tagsSet, }; } diff --git a/src/website/packages/fakeyou.com/src/v2/view/pages/weight/WeightEditPage.tsx b/src/website/packages/fakeyou.com/src/v2/view/pages/weight/WeightEditPage.tsx index 2ef252bbe5..9d08285851 100644 --- a/src/website/packages/fakeyou.com/src/v2/view/pages/weight/WeightEditPage.tsx +++ b/src/website/packages/fakeyou.com/src/v2/view/pages/weight/WeightEditPage.tsx @@ -24,6 +24,7 @@ import { useSession, useWeightFetch } from "hooks"; import "./WeightEditPage.scss"; import { LanguageLabels } from "@storyteller/components/src/api/Languages"; import { WeightCategory } from "@storyteller/components/src/api/_common/enums"; +import TagsInput from "components/common/TagsInput/TagsInput"; export default function WeightEditPage() { const { user, canEditTtsModel } = useSession(); @@ -45,6 +46,8 @@ export default function WeightEditPage() { visibility, languageTag, writeStatus, + tags, + tagsSet, // status } = useWeightFetch({ token: weight_token }); @@ -180,6 +183,14 @@ export default function WeightEditPage() { /> )} + +