mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
fixed tag autocomplete behaviour
This commit is contained in:
parent
9dc83b0db8
commit
85d20e5009
8 changed files with 25 additions and 20 deletions
|
@ -13,10 +13,10 @@ type IProps = IEditorComponentProps & {};
|
||||||
|
|
||||||
const EditorUploadCoverButton: FC<IProps> = () => {
|
const EditorUploadCoverButton: FC<IProps> = () => {
|
||||||
const { values, setFieldValue } = useNodeFormContext();
|
const { values, setFieldValue } = useNodeFormContext();
|
||||||
const { uploadFiles, files, pendingImages } = useUploader(
|
const { uploadFile, files, pendingImages } = useUploader(
|
||||||
UploadSubject.Editor,
|
UploadSubject.Editor,
|
||||||
UploadTarget.Nodes,
|
UploadTarget.Nodes,
|
||||||
[]
|
values.cover ? [values.cover] : []
|
||||||
);
|
);
|
||||||
|
|
||||||
const background = values.cover ? getURL(values.cover, PRESETS['300']) : null;
|
const background = values.cover ? getURL(values.cover, PRESETS['300']) : null;
|
||||||
|
@ -27,14 +27,15 @@ const EditorUploadCoverButton: FC<IProps> = () => {
|
||||||
}, [setFieldValue]);
|
}, [setFieldValue]);
|
||||||
|
|
||||||
const onInputChange = useCallback(
|
const onInputChange = useCallback(
|
||||||
(event: ChangeEvent<HTMLInputElement>) => {
|
async (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
const files = Array.from(event.target.files || [])
|
const files = Array.from(event.target.files || [])
|
||||||
.filter(file => getFileType(file) === UploadType.Image)
|
.filter(file => getFileType(file) === UploadType.Image)
|
||||||
.slice(0, 1);
|
.slice(0, 1);
|
||||||
|
|
||||||
uploadFiles(files);
|
const result = await uploadFile(files[0]);
|
||||||
|
setFieldValue('cover', result);
|
||||||
},
|
},
|
||||||
[uploadFiles]
|
[uploadFile, setFieldValue]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -11,6 +11,7 @@ interface TagAutocompleteProps {
|
||||||
onSelect: (val: string) => void;
|
onSelect: (val: string) => void;
|
||||||
search: string;
|
search: string;
|
||||||
options: string[];
|
options: string[];
|
||||||
|
visible: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TagAutocomplete: VFC<TagAutocompleteProps> = ({
|
const TagAutocomplete: VFC<TagAutocompleteProps> = ({
|
||||||
|
@ -19,6 +20,7 @@ const TagAutocomplete: VFC<TagAutocompleteProps> = ({
|
||||||
onSelect,
|
onSelect,
|
||||||
search,
|
search,
|
||||||
options,
|
options,
|
||||||
|
visible,
|
||||||
}) => {
|
}) => {
|
||||||
const [selected, setSelected] = useState(-1);
|
const [selected, setSelected] = useState(-1);
|
||||||
const [categories, tags] = useMemo(
|
const [categories, tags] = useMemo(
|
||||||
|
@ -82,7 +84,7 @@ const TagAutocomplete: VFC<TagAutocompleteProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(styles.window)}
|
className={classNames(styles.window, { [styles.visible]: visible })}
|
||||||
ref={wrapper}
|
ref={wrapper}
|
||||||
style={pop.styles.popper}
|
style={pop.styles.popper}
|
||||||
{...pop.attributes.popper}
|
{...pop.attributes.popper}
|
||||||
|
|
|
@ -18,6 +18,11 @@ $row_height: 24px;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
animation: appear 0.25s forwards;
|
animation: appear 0.25s forwards;
|
||||||
|
visibility: hidden;
|
||||||
|
|
||||||
|
&.visible {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll {
|
.scroll {
|
||||||
|
|
|
@ -132,8 +132,9 @@ const TagInput: FC<IProps> = ({ exclude, onAppend, onClearTag, onSubmit }) => {
|
||||||
/>
|
/>
|
||||||
</TagWrapper>
|
</TagWrapper>
|
||||||
|
|
||||||
{focused && input?.length > 0 && ref.current && (
|
{!!ref.current && (
|
||||||
<TagAutocomplete
|
<TagAutocomplete
|
||||||
|
visible={focused && input?.length > 0}
|
||||||
exclude={exclude}
|
exclude={exclude}
|
||||||
input={ref.current}
|
input={ref.current}
|
||||||
onSelect={onAutocompleteSelect}
|
onSelect={onAutocompleteSelect}
|
||||||
|
|
|
@ -4,8 +4,10 @@ import { ITag } from '~/types';
|
||||||
import { URLS } from '~/constants/urls';
|
import { URLS } from '~/constants/urls';
|
||||||
import { useLoadNode } from '~/hooks/node/useLoadNode';
|
import { useLoadNode } from '~/hooks/node/useLoadNode';
|
||||||
import { apiDeleteNodeTag, apiPostNodeTags } from '~/api/node';
|
import { apiDeleteNodeTag, apiPostNodeTags } from '~/api/node';
|
||||||
|
import { useGetNodeRelated } from '~/hooks/node/useGetNodeRelated';
|
||||||
|
|
||||||
export const useNodeTags = (id: number) => {
|
export const useNodeTags = (id: number) => {
|
||||||
|
const { refresh: refreshRelated } = useGetNodeRelated(id);
|
||||||
const { update } = useLoadNode(id);
|
const { update } = useLoadNode(id);
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
|
@ -14,11 +16,12 @@ export const useNodeTags = (id: number) => {
|
||||||
try {
|
try {
|
||||||
const result = await apiPostNodeTags({ id, tags });
|
const result = await apiPostNodeTags({ id, tags });
|
||||||
await update({ tags: result.node.tags });
|
await update({ tags: result.node.tags });
|
||||||
|
await refreshRelated();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn(error);
|
console.warn(error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[id, update]
|
[id, update, refreshRelated]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onClick = useCallback(
|
const onClick = useCallback(
|
||||||
|
@ -37,11 +40,12 @@ export const useNodeTags = (id: number) => {
|
||||||
try {
|
try {
|
||||||
const result = await apiDeleteNodeTag({ id, tagId });
|
const result = await apiDeleteNodeTag({ id, tagId });
|
||||||
await update({ tags: result.tags });
|
await update({ tags: result.tags });
|
||||||
|
await refreshRelated();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(e);
|
console.warn(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[id, update]
|
[id, update, refreshRelated]
|
||||||
);
|
);
|
||||||
|
|
||||||
return { onDelete, onChange, onClick };
|
return { onDelete, onChange, onClick };
|
||||||
|
|
|
@ -42,7 +42,7 @@ const NodeLayout: FC<IProps> = () => {
|
||||||
title={node.title}
|
title={node.title}
|
||||||
username={node.user?.username}
|
username={node.user?.username}
|
||||||
likeCount={node?.like_count || 0}
|
likeCount={node?.like_count || 0}
|
||||||
isHeroic={!!node.is_promoted}
|
isHeroic={!!node.is_heroic}
|
||||||
isLiked={!!node.is_liked}
|
isLiked={!!node.is_liked}
|
||||||
isLocked={!!node.deleted_at}
|
isLocked={!!node.deleted_at}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
|
|
|
@ -15,5 +15,5 @@ export const canLikeNode = (node?: Partial<INode>, user?: Partial<IUser>): boole
|
||||||
|
|
||||||
export const canStarNode = (node?: Partial<INode>, user?: Partial<IUser>): boolean =>
|
export const canStarNode = (node?: Partial<INode>, user?: Partial<IUser>): boolean =>
|
||||||
path(['type'], node) === NODE_TYPES.IMAGE &&
|
path(['type'], node) === NODE_TYPES.IMAGE &&
|
||||||
path(['is_promoted'], node) === false &&
|
path(['is_promoted'], node) === true &&
|
||||||
path(['role'], user) === Role.Admin;
|
path(['role'], user) === Role.Admin;
|
||||||
|
|
|
@ -15,15 +15,7 @@ const defaultValue: INodeRelated = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const NodeRelatedProvider: FC<NodeRelatedProviderProps> = ({ id, children, tags }) => {
|
const NodeRelatedProvider: FC<NodeRelatedProviderProps> = ({ id, children, tags }) => {
|
||||||
const { related, isLoading, refresh } = useGetNodeRelated(id);
|
const { related, isLoading } = useGetNodeRelated(id);
|
||||||
|
|
||||||
useEffect(
|
|
||||||
() => {
|
|
||||||
refresh();
|
|
||||||
},
|
|
||||||
// eslint-disable-next-line
|
|
||||||
[tags]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeRelatedContextProvider related={related || defaultValue} isLoading={isLoading}>
|
<NodeRelatedContextProvider related={related || defaultValue} isLoading={isLoading}>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue