diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts index 8a9389a183..7585b3371e 100644 --- a/src/lib/api/index.ts +++ b/src/lib/api/index.ts @@ -83,6 +83,7 @@ interface PostOpts { knownHandles?: Set onStateChange?: (state: string) => void langs?: string[] + tags?: string[] } export async function post(store: RootStoreModel, opts: PostOpts) { @@ -264,6 +265,7 @@ export async function post(store: RootStoreModel, opts: PostOpts) { embed, langs, labels, + tags: opts.tags?.filter(t => t.replace(/^#/, '')), }) } catch (e: any) { console.error(`Failed to create post: ${e.toString()}`) diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index e0d2858d06..23e2321b12 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -91,6 +91,7 @@ export const ComposePost = observer(function ComposePost({ const [labels, setLabels] = useState([]) const [suggestedLinks, setSuggestedLinks] = useState>(new Set()) const gallery = useMemo(() => new GalleryModel(store), [store]) + const [tags, setTags] = useState([]) const autocompleteView = useMemo( () => new UserAutocompleteModel(store), @@ -167,6 +168,13 @@ export const ComposePost = observer(function ComposePost({ [gallery, track], ) + const onChangeTags = useCallback( + (tags: string[]) => { + setTags(tags) + }, + [setTags], + ) + const onPressPublish = async () => { if (isProcessing || graphemeLength > MAX_GRAPHEME_LENGTH) { return @@ -195,6 +203,7 @@ export const ComposePost = observer(function ComposePost({ onStateChange: setProcessingState, knownHandles: autocompleteView.knownHandles, langs: store.preferences.postLanguages, + tags, }) } catch (e: any) { if (extLink) { @@ -387,7 +396,7 @@ export const ComposePost = observer(function ComposePost({ pal.border, {borderTopWidth: 1, paddingVertical: 10, marginTop: 10}, ]}> - + {!extLink && suggestedLinks.size > 0 ? ( diff --git a/src/view/com/composer/TagInput.tsx b/src/view/com/composer/TagInput.tsx index ac374a4899..9d4a80d3f2 100644 --- a/src/view/com/composer/TagInput.tsx +++ b/src/view/com/composer/TagInput.tsx @@ -38,19 +38,35 @@ function Tag({ ) } -export function TagInput({max}: {max: number}) { +export function TagInput({ + max, + onChangeTags, +}: { + max: number + onChangeTags: (tags: string[]) => void +}) { const pal = usePalette('default') const input = React.useRef(null) const [value, setValue] = React.useState('') const [tags, setTags] = React.useState([]) + const handleChangeTags = React.useCallback( + (_tags: string[]) => { + setTags(_tags) + onChangeTags(_tags) + }, + [onChangeTags, setTags], + ) + const onKeyPress = React.useCallback( (e: NativeSyntheticEvent) => { if (e.nativeEvent.key === 'Enter') { const _tags = value.trim().split(' ').filter(Boolean) if (_tags.length > 0) { - setTags(Array.from(new Set([...tags, ..._tags])).slice(0, max)) + handleChangeTags( + Array.from(new Set([...tags, ..._tags])).slice(0, max), + ) setValue('') } @@ -58,10 +74,10 @@ export function TagInput({max}: {max: number}) { input.current?.focus() }, 100) } else if (e.nativeEvent.key === 'Backspace' && value === '') { - setTags(tags.slice(0, -1)) + handleChangeTags(tags.slice(0, -1)) } }, - [max, value, tags, setValue, setTags], + [max, value, tags, setValue, handleChangeTags], ) const onChangeText = React.useCallback((value: string) => { @@ -71,9 +87,9 @@ export function TagInput({max}: {max: number}) { const removeTag = React.useCallback( (tag: string) => { - setTags(tags.filter(t => t !== tag)) + handleChangeTags(tags.filter(t => t !== tag)) }, - [tags, setTags], + [tags, handleChangeTags], ) return ( diff --git a/src/view/com/composer/text-input/web/TagDecorator.ts b/src/view/com/composer/text-input/web/TagDecorator.ts index 39fe521ca6..18b5a7e704 100644 --- a/src/view/com/composer/text-input/web/TagDecorator.ts +++ b/src/view/com/composer/text-input/web/TagDecorator.ts @@ -33,6 +33,7 @@ function getDecorations(doc: ProsemirrorNode) { while ((match = TAG_REGEX.exec(textContent))) { const [, m] = match const tag = m.trim().replace(/\p{P}+$/gu, '') + if (tag.length > 66) continue const from = match.index + 1 const to = from + tag.length + 1 decorations.push(