mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-25 04:46:40 +07:00
moved tags to sidebar (#135)
This commit is contained in:
parent
a8ac233140
commit
b36dcca0df
13 changed files with 99 additions and 71 deletions
|
@ -1,12 +1,14 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC, useCallback } from 'react';
|
||||||
|
|
||||||
import { Pressable } from '~/components/common/Pressable';
|
import { Pressable } from '~/components/common/Pressable';
|
||||||
import { NodeRelated } from '~/components/node/NodeRelated';
|
import { NodeRelated } from '~/components/node/NodeRelated';
|
||||||
import { NodeRelatedPlaceholder } from '~/components/node/NodeRelated/placeholder';
|
import { NodeRelatedPlaceholder } from '~/components/node/NodeRelated/placeholder';
|
||||||
import { Dialog } from '~/constants/modal';
|
import { Dialog } from '~/constants/modal';
|
||||||
import { useShowModal } from '~/hooks/modal/useShowModal';
|
import { useShowModal } from '~/hooks/modal/useShowModal';
|
||||||
import { INode } from '~/types';
|
import { useTagSidebar } from '~/hooks/sidebar/useTagSidebar';
|
||||||
|
import { INode, ITag } from '~/types';
|
||||||
import { INodeRelated } from '~/types/node';
|
import { INodeRelated } from '~/types/node';
|
||||||
|
import { useSidebar } from '~/utils/providers/SidebarProvider';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
|
@ -15,7 +17,7 @@ interface IProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const NodeRelatedBlock: FC<IProps> = ({ isLoading, node, related }) => {
|
const NodeRelatedBlock: FC<IProps> = ({ isLoading, node, related }) => {
|
||||||
const goToTag = useShowModal(Dialog.TagSidebar);
|
const goToTag = useTagSidebar();
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <NodeRelatedPlaceholder />;
|
return <NodeRelatedPlaceholder />;
|
||||||
|
@ -27,10 +29,12 @@ const NodeRelatedBlock: FC<IProps> = ({ isLoading, node, related }) => {
|
||||||
related.albums &&
|
related.albums &&
|
||||||
!!node?.id &&
|
!!node?.id &&
|
||||||
Object.keys(related.albums)
|
Object.keys(related.albums)
|
||||||
.filter(album => related.albums[album].length > 0)
|
.filter((album) => related.albums[album].length > 0)
|
||||||
.map(album => (
|
.map((album) => (
|
||||||
<NodeRelated
|
<NodeRelated
|
||||||
title={<Pressable onClick={() => goToTag({ tag: album })}>{album}</Pressable>}
|
title={
|
||||||
|
<Pressable onClick={() => goToTag(album)}>{album}</Pressable>
|
||||||
|
}
|
||||||
items={related.albums[album]}
|
items={related.albums[album]}
|
||||||
key={album}
|
key={album}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { FC, useMemo } from 'react';
|
import React, { FC, ReactNode, useMemo } from 'react';
|
||||||
|
|
||||||
import { Filler } from '~/components/containers/Filler';
|
import { Filler } from '~/components/containers/Filler';
|
||||||
import { Button } from '~/components/input/Button';
|
import { Button } from '~/components/input/Button';
|
||||||
|
@ -8,7 +8,7 @@ import styles from './styles.module.scss';
|
||||||
interface SidebarStackCardProps {
|
interface SidebarStackCardProps {
|
||||||
width?: number;
|
width?: number;
|
||||||
headerFeature?: 'back' | 'close';
|
headerFeature?: 'back' | 'close';
|
||||||
title?: string;
|
title?: ReactNode;
|
||||||
onBackPress?: () => void;
|
onBackPress?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,9 @@ const SidebarStackCard: FC<SidebarStackCardProps> = ({
|
||||||
<div style={style} className={styles.card}>
|
<div style={style} className={styles.card}>
|
||||||
{!!(headerFeature || title) && (
|
{!!(headerFeature || title) && (
|
||||||
<div className={styles.head}>
|
<div className={styles.head}>
|
||||||
<Filler>{!!title && <h6>{title}</h6>}</Filler>
|
<Filler className={styles.title}>
|
||||||
|
{typeof title === 'string' ? <h6>{title}</h6> : title}
|
||||||
|
</Filler>
|
||||||
|
|
||||||
{!!(headerFeature && onBackPress) && (
|
{!!(headerFeature && onBackPress) && (
|
||||||
<Button color="link" iconRight={backIcon} onClick={onBackPress} />
|
<Button color="link" iconRight={backIcon} onClick={onBackPress} />
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
@import "src/styles/variables";
|
@import 'src/styles/variables';
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
|
@ -28,3 +28,8 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import { PhotoSwipe } from '~/containers/dialogs/PhotoSwipe';
|
||||||
import { RestorePasswordDialog } from '~/containers/dialogs/RestorePasswordDialog';
|
import { RestorePasswordDialog } from '~/containers/dialogs/RestorePasswordDialog';
|
||||||
import { RestoreRequestDialog } from '~/containers/dialogs/RestoreRequestDialog';
|
import { RestoreRequestDialog } from '~/containers/dialogs/RestoreRequestDialog';
|
||||||
import { TestDialog } from '~/containers/dialogs/TestDialog';
|
import { TestDialog } from '~/containers/dialogs/TestDialog';
|
||||||
import { TagSidebar } from '~/containers/sidebars/TagSidebar';
|
|
||||||
|
|
||||||
export enum Dialog {
|
export enum Dialog {
|
||||||
Login = 'Login',
|
Login = 'Login',
|
||||||
|
@ -19,7 +18,6 @@ export enum Dialog {
|
||||||
Photoswipe = 'Photoswipe',
|
Photoswipe = 'Photoswipe',
|
||||||
CreateNode = 'CreateNode',
|
CreateNode = 'CreateNode',
|
||||||
EditNode = 'EditNode',
|
EditNode = 'EditNode',
|
||||||
TagSidebar = 'TagNodes',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DIALOG_CONTENT = {
|
export const DIALOG_CONTENT = {
|
||||||
|
@ -32,5 +30,4 @@ export const DIALOG_CONTENT = {
|
||||||
[Dialog.Photoswipe]: PhotoSwipe,
|
[Dialog.Photoswipe]: PhotoSwipe,
|
||||||
[Dialog.CreateNode]: EditorCreateDialog,
|
[Dialog.CreateNode]: EditorCreateDialog,
|
||||||
[Dialog.EditNode]: EditorEditDialog,
|
[Dialog.EditNode]: EditorEditDialog,
|
||||||
[Dialog.TagSidebar]: TagSidebar,
|
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import { ProfileSidebar } from "~/containers/sidebars/ProfileSidebar";
|
import { SettingsSidebar } from '~/containers/sidebars/ProfileSidebar';
|
||||||
|
import { TagSidebar } from '~/containers/sidebars/TagSidebar';
|
||||||
|
|
||||||
import { SidebarName } from "./index";
|
import { SidebarName } from './index';
|
||||||
|
|
||||||
export const sidebarComponents = {
|
export const sidebarComponents = {
|
||||||
[SidebarName.Settings]: ProfileSidebar,
|
[SidebarName.Settings]: SettingsSidebar,
|
||||||
|
[SidebarName.Tag]: TagSidebar,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SidebarComponents = typeof sidebarComponents;
|
export type SidebarComponents = typeof sidebarComponents;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { ProfileSidebar } from "~/containers/sidebars/ProfileSidebar";
|
import { SettingsSidebar } from '~/containers/sidebars/ProfileSidebar';
|
||||||
|
|
||||||
export enum SidebarName {
|
export enum SidebarName {
|
||||||
Settings = "settings",
|
Settings = 'settings',
|
||||||
|
Tag = 'tag',
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,9 @@ import { ProfileSidebarNotes } from '~/components/profile/ProfileSidebarNotes';
|
||||||
import { ProfileSidebarSettings } from '~/components/profile/ProfileSidebarSettings';
|
import { ProfileSidebarSettings } from '~/components/profile/ProfileSidebarSettings';
|
||||||
import { SidebarStack } from '~/components/sidebar/SidebarStack';
|
import { SidebarStack } from '~/components/sidebar/SidebarStack';
|
||||||
import { SidebarStackCard } from '~/components/sidebar/SidebarStackCard';
|
import { SidebarStackCard } from '~/components/sidebar/SidebarStackCard';
|
||||||
|
import { SidebarWrapper } from '~/components/sidebar/SidebarWrapper';
|
||||||
import { SidebarName } from '~/constants/sidebar';
|
import { SidebarName } from '~/constants/sidebar';
|
||||||
import { ProfileSidebarMenu } from '~/containers/profile/ProfileSidebarMenu';
|
import { ProfileSidebarMenu } from '~/containers/profile/ProfileSidebarMenu';
|
||||||
import { SidebarWrapper } from '~/containers/sidebars/SidebarWrapper';
|
|
||||||
import { useAuth } from '~/hooks/auth/useAuth';
|
import { useAuth } from '~/hooks/auth/useAuth';
|
||||||
import { useUser } from '~/hooks/auth/useUser';
|
import { useUser } from '~/hooks/auth/useUser';
|
||||||
import type { SidebarComponentProps } from '~/types/sidebar';
|
import type { SidebarComponentProps } from '~/types/sidebar';
|
||||||
|
@ -17,12 +17,12 @@ import type { SidebarComponentProps } from '~/types/sidebar';
|
||||||
const tabs = ['profile', 'bookmarks'] as const;
|
const tabs = ['profile', 'bookmarks'] as const;
|
||||||
type TabName = typeof tabs[number];
|
type TabName = typeof tabs[number];
|
||||||
|
|
||||||
interface ProfileSidebarProps
|
interface SettingsSidebarProps
|
||||||
extends SidebarComponentProps<SidebarName.Settings> {
|
extends SidebarComponentProps<SidebarName.Settings> {
|
||||||
page?: TabName;
|
page?: TabName;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProfileSidebar: VFC<ProfileSidebarProps> = ({
|
const SettingsSidebar: VFC<SettingsSidebarProps> = ({
|
||||||
onRequestClose,
|
onRequestClose,
|
||||||
page,
|
page,
|
||||||
openSidebar,
|
openSidebar,
|
||||||
|
@ -79,4 +79,4 @@ const ProfileSidebar: VFC<ProfileSidebarProps> = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export { ProfileSidebar };
|
export { SettingsSidebar };
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
import React, { useMemo, VFC } from 'react';
|
import { useMemo, VFC } from 'react';
|
||||||
|
|
||||||
import { InfiniteScroll } from '~/components/containers/InfiniteScroll';
|
import { InfiniteScroll } from '~/components/containers/InfiniteScroll';
|
||||||
import { Icon } from '~/components/input/Icon';
|
import { Icon } from '~/components/input/Icon';
|
||||||
import { LoaderCircle } from '~/components/input/LoaderCircle';
|
import { LoaderCircle } from '~/components/input/LoaderCircle';
|
||||||
import { SidebarStack } from '~/components/sidebar/SidebarStack';
|
import { SidebarStack } from '~/components/sidebar/SidebarStack';
|
||||||
|
import { SidebarStackCard } from '~/components/sidebar/SidebarStackCard';
|
||||||
|
import { SidebarWrapper } from '~/components/sidebar/SidebarWrapper';
|
||||||
import { TagSidebarList } from '~/components/sidebar/TagSidebarList';
|
import { TagSidebarList } from '~/components/sidebar/TagSidebarList';
|
||||||
import { Tag } from '~/components/tags/Tag';
|
import { Tag } from '~/components/tags/Tag';
|
||||||
import { SidebarWrapper } from '~/containers/sidebars/SidebarWrapper';
|
import { SidebarName } from '~/constants/sidebar';
|
||||||
import { useTagNodes } from '~/hooks/tag/useTagNodes';
|
import { useTagNodes } from '~/hooks/tag/useTagNodes';
|
||||||
import { DialogComponentProps } from '~/types/modal';
|
import { SidebarComponentProps } from '~/types/sidebar';
|
||||||
|
|
||||||
import styles from './styles.module.scss';
|
import styles from './styles.module.scss';
|
||||||
|
|
||||||
interface TagSidebarProps extends DialogComponentProps {
|
interface TagSidebarProps extends SidebarComponentProps<SidebarName.Tag> {
|
||||||
tag: string;
|
tag: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,43 +25,35 @@ const TagSidebar: VFC<TagSidebarProps> = ({ tag, onRequestClose }) => {
|
||||||
return (
|
return (
|
||||||
<SidebarWrapper onClose={onRequestClose}>
|
<SidebarWrapper onClose={onRequestClose}>
|
||||||
<SidebarStack>
|
<SidebarStack>
|
||||||
<div className={styles.wrap}>
|
<SidebarStackCard
|
||||||
<div className={styles.content}>
|
headerFeature="close"
|
||||||
<div className={styles.head}>
|
title={<Tag tag={{ title }} />}
|
||||||
<div className={styles.tag}>
|
onBackPress={onRequestClose}
|
||||||
<Tag tag={{ title }} size="big" />
|
>
|
||||||
</div>
|
<div className={styles.wrap}>
|
||||||
|
<div className={styles.content}>
|
||||||
{isLoading && (
|
{!nodes.length && !isLoading ? (
|
||||||
<div className={styles.sync}>
|
<div className={styles.none}>
|
||||||
<LoaderCircle size={20} />
|
<Icon icon="sad" size={120} />
|
||||||
|
<div>
|
||||||
|
У этого тэга нет постов
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
Такие дела
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
<InfiniteScroll
|
||||||
|
hasMore={hasMore}
|
||||||
|
loadMore={loadMore}
|
||||||
|
className={styles.list}
|
||||||
|
>
|
||||||
|
<TagSidebarList nodes={nodes} onClick={onRequestClose} />
|
||||||
|
</InfiniteScroll>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className={styles.close}>
|
|
||||||
<button onClick={onRequestClose}>
|
|
||||||
<Icon icon="close" size={32} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!nodes.length && !isLoading ? (
|
|
||||||
<div className={styles.none}>
|
|
||||||
<Icon icon="sad" size={120} />
|
|
||||||
<div>
|
|
||||||
У этого тэга нет постов
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
Такие дела
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<InfiniteScroll hasMore={hasMore} loadMore={loadMore} className={styles.list}>
|
|
||||||
<TagSidebarList nodes={nodes} onClick={onRequestClose} />
|
|
||||||
</InfiniteScroll>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</SidebarStackCard>
|
||||||
</SidebarStack>
|
</SidebarStack>
|
||||||
</SidebarWrapper>
|
</SidebarWrapper>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { apiDeleteNodeTag, apiPostNodeTags } from '~/api/node';
|
import { apiDeleteNodeTag, apiPostNodeTags } from '~/api/node';
|
||||||
import { Dialog } from '~/constants/modal';
|
|
||||||
import { useShowModal } from '~/hooks/modal/useShowModal';
|
|
||||||
import { useGetNodeRelated } from '~/hooks/node/useGetNodeRelated';
|
import { useGetNodeRelated } from '~/hooks/node/useGetNodeRelated';
|
||||||
import { useLoadNode } from '~/hooks/node/useLoadNode';
|
import { useLoadNode } from '~/hooks/node/useLoadNode';
|
||||||
import { ITag } from '~/types';
|
import { ITag } from '~/types';
|
||||||
|
|
||||||
|
import { useTagSidebar } from '../sidebar/useTagSidebar';
|
||||||
|
|
||||||
export const useNodeTags = (id: number) => {
|
export const useNodeTags = (id: number) => {
|
||||||
const showModal = useShowModal(Dialog.TagSidebar);
|
const openTagSidebar = useTagSidebar();
|
||||||
const { refresh: refreshRelated } = useGetNodeRelated(id);
|
const { refresh: refreshRelated } = useGetNodeRelated(id);
|
||||||
const { update } = useLoadNode(id);
|
const { update } = useLoadNode(id);
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ export const useNodeTags = (id: number) => {
|
||||||
console.warn(error);
|
console.warn(error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[id, update, refreshRelated]
|
[id, update, refreshRelated],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onClick = useCallback(
|
const onClick = useCallback(
|
||||||
|
@ -31,9 +31,9 @@ export const useNodeTags = (id: number) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
showModal({ tag: tag.title });
|
openTagSidebar(tag.title);
|
||||||
},
|
},
|
||||||
[showModal, id]
|
[openTagSidebar, id],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onDelete = useCallback(
|
const onDelete = useCallback(
|
||||||
|
@ -46,7 +46,7 @@ export const useNodeTags = (id: number) => {
|
||||||
console.warn(e);
|
console.warn(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[id, update, refreshRelated]
|
[id, update, refreshRelated],
|
||||||
);
|
);
|
||||||
|
|
||||||
return { onDelete, onChange, onClick };
|
return { onDelete, onChange, onClick };
|
||||||
|
|
20
src/hooks/sidebar/useTagSidebar.ts
Normal file
20
src/hooks/sidebar/useTagSidebar.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import { SidebarName } from '~/constants/sidebar';
|
||||||
|
import { ITag } from '~/types';
|
||||||
|
import { useSidebar } from '~/utils/providers/SidebarProvider';
|
||||||
|
|
||||||
|
export const useTagSidebar = () => {
|
||||||
|
const { open } = useSidebar();
|
||||||
|
|
||||||
|
return useCallback(
|
||||||
|
(tag: string) => {
|
||||||
|
if (!tag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
open(SidebarName.Tag, { tag });
|
||||||
|
},
|
||||||
|
[open],
|
||||||
|
);
|
||||||
|
};
|
|
@ -84,11 +84,14 @@ export const SidebarProvider = <T extends SidebarComponent>({
|
||||||
{children}
|
{children}
|
||||||
{current && (
|
{current && (
|
||||||
<ModalWrapper onOverlayClick={close}>
|
<ModalWrapper onOverlayClick={close}>
|
||||||
{createElement(sidebarComponents[current], {
|
{createElement(
|
||||||
onRequestClose: close,
|
sidebarComponents[current] as any,
|
||||||
openSidebar: open,
|
{
|
||||||
...omit(['sidebar'], router.query),
|
onRequestClose: close,
|
||||||
} as any)}
|
openSidebar: open,
|
||||||
|
...omit(['sidebar'], router.query),
|
||||||
|
} as any,
|
||||||
|
)}
|
||||||
</ModalWrapper>
|
</ModalWrapper>
|
||||||
)}
|
)}
|
||||||
</SidebarContext.Provider>
|
</SidebarContext.Provider>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue