From c680f7c403df3c69ee041e1067605a22e3d5599a Mon Sep 17 00:00:00 2001 From: Megha-Dev-19 <100185149+Megha-Dev-19@users.noreply.github.com> Date: Mon, 27 Nov 2023 07:56:21 +0530 Subject: [PATCH 1/3] Fix tagging (#492) * fix `@` activation positioning * fix autocomplete * fix mentions in middle of description --------- Co-authored-by: Elliot Braem <16282460+elliotBraem@users.noreply.github.com> --- src/devhub/components/molecule/SimpleMDE.jsx | 2 - src/devhub/page/create.jsx | 77 +++++++++++++------- 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/devhub/components/molecule/SimpleMDE.jsx b/src/devhub/components/molecule/SimpleMDE.jsx index 0f11aa048..264b1f1e1 100644 --- a/src/devhub/components/molecule/SimpleMDE.jsx +++ b/src/devhub/components/molecule/SimpleMDE.jsx @@ -212,9 +212,7 @@ const code = ` initialText: event.data.content })); isEditorInitialized = true; } else { - console.log(event); if (event.data.handler === 'autocompleteSelected') { - console.log("we're in"); codeMirrorInstance.getDoc().setValue(event.data.content); } } diff --git a/src/devhub/page/create.jsx b/src/devhub/page/create.jsx index b8271ea11..1ccbb2708 100644 --- a/src/devhub/page/create.jsx +++ b/src/devhub/page/create.jsx @@ -1,4 +1,26 @@ /* INCLUDE: "core/lib/autocomplete" */ + +State.init({ + seekingFunding: false, + author_id: context.accountId, + // Should be a list of objects with field "name". + labels, + // Should be a list of labels as strings. + // Both of the label structures should be modified together. + labelStrings, + postType: "Idea", + name: props.name ?? "", + description: props.description ?? "", + amount: props.amount ?? "", + token: props.token ?? "USDT", + supervisor: props.supervisor ?? "neardevdao.near", + githubLink: props.githubLink ?? "", + warning: "", + waitForDraftStateRestore: true, + mentionInput: "", // text next to @ tag + mentionsArray: [], // all the mentions in the description +}); + const autocompleteEnabled = true; const AutoComplete = styled.div` @@ -10,20 +32,43 @@ const AutoComplete = styled.div` `; function textareaInputHandler(value) { - const showAccountAutocomplete = /@[\w][^\s]*$/.test(value); + const words = value.split(/\s+/); + const allMentiones = words + .filter((word) => word.startsWith("@")) + .map((mention) => mention.slice(1)); + const newMentiones = allMentiones.filter( + (item) => !state.mentionsArray.includes(item) + ); + State.update((lastKnownState) => ({ ...lastKnownState, text: value, - showAccountAutocomplete, + showAccountAutocomplete: newMentiones?.length > 0, + mentionsArray: allMentiones, + mentionInput: newMentiones?.[0] ?? "", })); } function autoCompleteAccountId(id) { - let description = state.description.replace(/[\s]{0,1}@[^\s]*$/, ""); - description = `${description} @${id}`.trim() + " "; + // to make sure we update the @ at correct index + let currentIndex = 0; + const updatedDescription = state.description.replace( + /(?:^|\s)(@[^\s]*)/g, + (match) => { + if (currentIndex === state.mentionsArray.indexOf(state.mentionInput)) { + currentIndex++; + return ` @${id}`; + } else { + currentIndex++; + return match; + } + } + ); + State.update((lastKnownState) => ({ ...lastKnownState, - description, + handler: "autocompleteSelected", + description: updatedDescription, showAccountAutocomplete: false, })); } @@ -51,26 +96,6 @@ const labels = labelStrings.map((s) => { return { name: s }; }); -State.init({ - seekingFunding: false, - - author_id: context.accountId, - // Should be a list of objects with field "name". - labels, - // Should be a list of labels as strings. - // Both of the label structures should be modified together. - labelStrings, - postType: "Idea", - name: props.name ?? "", - description: props.description ?? "", - amount: props.amount ?? "", - token: props.token ?? "USDT", - supervisor: props.supervisor ?? "neardevdao.near", - githubLink: props.githubLink ?? "", - warning: "", - waitForDraftStateRestore: true, -}); - if (state.waitForDraftStateRestore) { const draftstatestring = Storage.privateGet(DRAFT_STATE_STORAGE_KEY); if (draftstatestring != null) { @@ -315,7 +340,7 @@ const descriptionDiv = ( State.update({ showAccountAutocomplete: false }), }} From 7b488ab198f2c0444478ad21a67fcf401f6a4531 Mon Sep 17 00:00:00 2001 From: Megha-Dev-19 <100185149+Megha-Dev-19@users.noreply.github.com> Date: Mon, 27 Nov 2023 08:06:37 +0530 Subject: [PATCH 2/3] Ft: Autocomplete widget added (#502) * add autocomplete widget * fix following info --- .../molecule/AccountAutocomplete.jsx | 143 ++++++++++++++++++ src/devhub/entity/post/PostEditor.jsx | 2 +- src/devhub/page/create.jsx | 2 +- 3 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 src/devhub/components/molecule/AccountAutocomplete.jsx diff --git a/src/devhub/components/molecule/AccountAutocomplete.jsx b/src/devhub/components/molecule/AccountAutocomplete.jsx new file mode 100644 index 000000000..f205550df --- /dev/null +++ b/src/devhub/components/molecule/AccountAutocomplete.jsx @@ -0,0 +1,143 @@ +if (!context.accountId || !props.term) return <>; + +let results = []; +const profilesData = Social.get("*/profile/name", "final") || {}; +const followingData = Social.get( + `${context.accountId}/graph/follow/**`, + "final" +); +if (!profilesData) return <>; +const profiles = Object.entries(profilesData); +const term = (props.term || "").replace(/\W/g, "").toLowerCase(); +const limit = 5; + +for (let i = 0; i < profiles.length; i++) { + let score = 0; + const accountId = profiles[i][0]; + const accountIdSearch = profiles[i][0].replace(/\W/g, "").toLowerCase(); + const nameSearch = (profiles[i][1]?.profile?.name || "") + .replace(/\W/g, "") + .toLowerCase(); + const accountIdSearchIndex = accountIdSearch.indexOf(term); + const nameSearchIndex = nameSearch.indexOf(term); + + if (accountIdSearchIndex > -1 || nameSearchIndex > -1) { + score += 10; + + if (accountIdSearchIndex === 0) { + score += 10; + } + if (nameSearchIndex === 0) { + score += 10; + } + if (followingData[accountId] === "") { + score += 30; + } + + results.push({ + accountId, + score, + }); + } +} + +results.sort((a, b) => b.score - a.score); +results = results.slice(0, limit); + +function onResultClick(id) { + props.onSelect && props.onSelect(id); +} + +const Wrapper = styled.div` + position: relative; + background: #eceef0; + + &::before { + content: ""; + display: block; + position: absolute; + right: 0; + width: 6px; + height: 100%; + background: linear-gradient( + to left, + rgba(236, 238, 240, 1), + rgba(236, 238, 240, 0) + ); + z-index: 10; + } +`; + +const Scroller = styled.div` + position: relative; + display: flex; + padding: 6px; + gap: 6px; + overflow: auto; + scroll-behavior: smooth; + align-items: center; + scrollbar-width: none; + -ms-overflow-style: none; + &::-webkit-scrollbar { + display: none; + } + + > * { + max-width: 175px; + flex-grow: 0; + flex-shrink: 0; + + button { + border: 1px solid #eceef0; + background: #fff !important; + border-radius: 6px; + padding: 3px 6px; + transition: all 200ms; + + &:focus, + &:hover { + border-color: #687076; + } + } + } +`; + +const CloseButton = styled.button` + background: none; + border: none; + display: block; + padding: 12px; + color #687076; + transition: all 200ms; + + &:hover { + color: #000; + } +`; + +if (results.length === 0) return <>; + +return ( + + + + + + + {results.map((result) => { + return ( + + ); + })} + + +); diff --git a/src/devhub/entity/post/PostEditor.jsx b/src/devhub/entity/post/PostEditor.jsx index 489f75fda..af094a82c 100644 --- a/src/devhub/entity/post/PostEditor.jsx +++ b/src/devhub/entity/post/PostEditor.jsx @@ -379,7 +379,7 @@ const callDescriptionDiv = () => { {autocompleteEnabled && state.showAccountAutocomplete && ( Date: Mon, 27 Nov 2023 13:54:17 +0530 Subject: [PATCH 3/3] fix filter tag action (#508) Co-authored-by: Bo Yao --- src/devhub/entity/post/Post.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devhub/entity/post/Post.jsx b/src/devhub/entity/post/Post.jsx index 274cdd6de..9ca826a7b 100644 --- a/src/devhub/entity/post/Post.jsx +++ b/src/devhub/entity/post/Post.jsx @@ -626,7 +626,7 @@ const tags = post.snapshot.labels ? (