diff --git a/apps/builddao/widget/Compose.jsx b/apps/builddao/widget/Compose.jsx index 4c388232..15638753 100644 --- a/apps/builddao/widget/Compose.jsx +++ b/apps/builddao/widget/Compose.jsx @@ -1,19 +1,29 @@ -const { Avatar, Button } = VM.require("buildhub.near/widget/components"); - -Avatar = Avatar || (() => <>); -Button = Button || (() => <>); +const { Avatar, Button } = VM.require("buildhub.near/widget/components") || { + Avatar: () => <>, + Button: () => <>, +}; const draftKey = props.feed.name || "draft"; const draft = Storage.privateGet(draftKey); +const autocompleteEnabled = true; + if (draft === null) { return ""; } +State.init({ + image: {}, +}); + const [view, setView] = useState("editor"); const [postContent, setPostContent] = useState(""); const [hideAdvanced, setHideAdvanced] = useState(true); const [labels, setLabels] = useState([]); +const [showAccountAutocomplete, setShowAccountAutocomplete] = useState(false); +const [mentionsArray, setMentionsArray] = useState([]); +const [mentionInput, setMentionInput] = useState(null); +const [handler, setHandler] = useState("update"); setPostContent(draft || props.template); @@ -23,16 +33,6 @@ function generateUID() { return randomNumber.toString(16).padStart(8, "0"); } -function tagsFromLabels(labels) { - return labels.reduce( - (newLabels, label) => ({ - ...newLabels, - [label]: "", - }), - {} - ); -} - const extractMentions = (text) => { const mentionRegex = /@((?:(?:[a-z\d]+[-_])*[a-z\d]+\.)*(?:[a-z\d]+[-_])*[a-z\d]+)/gi; @@ -102,6 +102,12 @@ const postToCustomFeed = ({ feed, text, labels }) => { text = checkAndAppendHashtag(text, hashtag); }); + const content = { + type: "md", + image: state.image.cid ? { ipfs_cid: state.image.cid } : undefined, + text: text, + }; + const data = { // [feed.name]: { // [postId]: { @@ -118,8 +124,7 @@ const postToCustomFeed = ({ feed, text, labels }) => { // }, post: { main: JSON.stringify({ - type: "md", - text, + content, // tags: tagsFromLabels(labels), // postType: feed.name, }), @@ -165,6 +170,43 @@ const postToCustomFeed = ({ feed, text, labels }) => { }); }; +function textareaInputHandler(value) { + const words = value.split(/\s+/); + const allMentiones = words + .filter((word) => word.startsWith("@")) + .map((mention) => mention.slice(1)); + const newMentiones = allMentiones.filter( + (item) => !mentionsArray.includes(item) + ); + setMentionInput(newMentiones?.[0] ?? ""); + setMentionsArray(allMentiones); + setShowAccountAutocomplete(newMentiones?.length > 0); + setPostContent(value); + setHandler("update"); + Storage.privateSet(draftKey, value || ""); +} + +function autoCompleteAccountId(id) { + let currentIndex = 0; + const updatedDescription = postContent.replace( + /(?:^|\s)(@[^\s]*)/g, + (match) => { + if (currentIndex === mentionsArray.indexOf(mentionInput)) { + currentIndex++; + return ` @${id}`; + } else { + currentIndex++; + return match; + } + } + ); + setPostContent(updatedDescription); + setShowAccountAutocomplete(false); + setMentionInput(null); + setHandler("autocompleteSelected"); + Storage.privateSet(draftKey, updatedDescription || ""); +} + const PostCreator = styled.div` display: flex; flex-direction: column; @@ -175,6 +217,51 @@ const PostCreator = styled.div` border-radius: 12px; margin-bottom: 1rem; + + .upload-image-button { + display: flex; + align-items: center; + justify-content: center; + background: #f1f3f5; + color: #11181c; + border-radius: 40px; + height: 40px; + min-width: 40px; + font-size: 0; + border: none; + cursor: pointer; + transition: background 200ms, opacity 200ms; + + &::before { + font-size: 16px; + } + + &:hover, + &:focus { + background: #d7dbde; + outline: none; + } + + &:disabled { + opacity: 0.5; + pointer-events: none; + } + + span { + margin-left: 12px; + } + } + + .d-inline-block { + display: flex !important; + gap: 12px; + margin: 0 !important; + + .overflow-hidden { + width: 40px !important; + height: 40px !important; + } + } `; const TextareaWrapper = styled.div` @@ -425,16 +512,26 @@ return ( key={props.feed.name} > { - setPostContent(v); - Storage.privateSet(draftKey, v || ""); + data: { handler: handler, content: postContent }, + onChange: (content) => { + textareaInputHandler(content); }, + embedCss: MarkdownEditor, }} /> + {autocompleteEnabled && showAccountAutocomplete && ( + setShowAccountAutocomplete(false), + }} + /> + )} ) : ( @@ -442,11 +539,27 @@ return ( src="devhub.near/widget/devhub.components.molecule.MarkdownViewer" props={{ text: postContent }} /> + {state.image.cid && ( + + )} )}
+ {view === "editor" && ( + + )}