mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-25 12:56:41 +07:00
added working profile sidebar
This commit is contained in:
parent
c6c7dbe75d
commit
07b4874f69
16 changed files with 202 additions and 84 deletions
|
@ -13,7 +13,7 @@ const TabContext = createContext({
|
|||
setActiveTab: (activeTab: number) => {},
|
||||
});
|
||||
|
||||
const List: VFC<TabProps> = ({ items }) => {
|
||||
const HorizontalList: VFC<TabProps> = ({ items }) => {
|
||||
const { activeTab, setActiveTab } = useContext(TabContext);
|
||||
|
||||
return (
|
||||
|
@ -54,7 +54,7 @@ const Tabs = function({ children }) {
|
|||
return <TabContext.Provider value={{ activeTab, setActiveTab }}>{children}</TabContext.Provider>;
|
||||
};
|
||||
|
||||
Tabs.List = List;
|
||||
Tabs.Horizontal = HorizontalList;
|
||||
Tabs.Content = Content;
|
||||
|
||||
export { Tabs };
|
||||
|
|
|
@ -3,23 +3,34 @@ import React, { FC } from 'react';
|
|||
import { Filler } from '~/components/containers/Filler';
|
||||
import { Button } from '~/components/input/Button';
|
||||
import { ProfileSettings } from '~/components/profile/ProfileSettings';
|
||||
import { useStackContext } from '~/components/sidebar/SidebarStack';
|
||||
import { SidebarStackCard } from '~/components/sidebar/SidebarStackCard';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
interface IProps {}
|
||||
|
||||
const ProfileSidebarSettings: FC<IProps> = () => (
|
||||
<div className={styles.wrap}>
|
||||
<div className={styles.scroller}>
|
||||
<ProfileSettings />
|
||||
</div>
|
||||
const ProfileSidebarSettings: FC<IProps> = () => {
|
||||
const { closeAllTabs } = useStackContext();
|
||||
|
||||
<div className={styles.buttons}>
|
||||
<Filler />
|
||||
<Button color="outline">Отмена</Button>
|
||||
<Button>Сохранить</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<SidebarStackCard width={600} headerFeature="back" title="Настройки" onBackPress={closeAllTabs}>
|
||||
<div className={styles.wrap}>
|
||||
<div className={styles.scroller}>
|
||||
<ProfileSettings />
|
||||
</div>
|
||||
|
||||
<div className={styles.buttons}>
|
||||
<Filler />
|
||||
<Button color="outline" onClick={closeAllTabs}>
|
||||
Отмена
|
||||
</Button>
|
||||
|
||||
<Button color="secondary">Сохранить</Button>
|
||||
</div>
|
||||
</div>
|
||||
</SidebarStackCard>
|
||||
);
|
||||
};
|
||||
|
||||
export { ProfileSidebarSettings };
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
justify-content: center;
|
||||
flex-direction: column;
|
||||
z-index: 4;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.scroller {
|
||||
|
@ -15,6 +16,8 @@
|
|||
}
|
||||
|
||||
.buttons {
|
||||
@include outer_shadow;
|
||||
|
||||
width: 100%;
|
||||
padding: $gap;
|
||||
box-sizing: border-box;
|
||||
|
|
|
@ -1,10 +1,36 @@
|
|||
import React, { FC, useMemo } from 'react';
|
||||
import React, {
|
||||
createContext,
|
||||
FC,
|
||||
PropsWithChildren,
|
||||
useCallback,
|
||||
useContext,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { isNil } from '~/utils/ramda';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
interface SidebarStackProps {}
|
||||
interface SidebarStackProps extends PropsWithChildren<{}> {
|
||||
initialTab?: number;
|
||||
}
|
||||
|
||||
interface SidebarStackContextValue {
|
||||
activeTab?: number;
|
||||
setActiveTab: (val: number) => void;
|
||||
closeAllTabs: () => void;
|
||||
}
|
||||
|
||||
const SidebarStackContext = createContext<SidebarStackContextValue>({
|
||||
activeTab: undefined,
|
||||
setActiveTab: () => {},
|
||||
closeAllTabs: () => {},
|
||||
});
|
||||
|
||||
const SidebarCards: FC = ({ children }) => {
|
||||
const { activeTab } = useStackContext();
|
||||
|
||||
const SidebarStack: FC<SidebarStackProps> = ({ children }) => {
|
||||
const nonEmptyChildren = useMemo(() => {
|
||||
if (!children) {
|
||||
return [];
|
||||
|
@ -13,15 +39,26 @@ const SidebarStack: FC<SidebarStackProps> = ({ children }) => {
|
|||
return Array.isArray(children) ? children.filter(it => it) : [children];
|
||||
}, [children]);
|
||||
|
||||
if (isNil(activeTab) || !nonEmptyChildren[activeTab]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <div className={styles.card}>{nonEmptyChildren[activeTab]}</div>;
|
||||
};
|
||||
|
||||
const SidebarStack = function({ children, initialTab }: SidebarStackProps) {
|
||||
const [activeTab, setActiveTab] = useState<number | undefined>(initialTab);
|
||||
const closeAllTabs = useCallback(() => setActiveTab(undefined), []);
|
||||
|
||||
return (
|
||||
<div className={styles.stack}>
|
||||
{nonEmptyChildren.map((child, i) => (
|
||||
<div className={styles.card} key={i}>
|
||||
{child}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<SidebarStackContext.Provider value={{ activeTab, setActiveTab, closeAllTabs }}>
|
||||
<div className={styles.stack}>{children}</div>
|
||||
</SidebarStackContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export { SidebarStack };
|
||||
SidebarStack.Cards = SidebarCards;
|
||||
|
||||
const useStackContext = () => useContext(SidebarStackContext);
|
||||
|
||||
export { SidebarStack, useStackContext };
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
flex-direction: row-reverse;
|
||||
width: auto;
|
||||
border-radius: $radius 0 0 $radius;
|
||||
|
||||
@include sidebar_stack_limit {
|
||||
& > *:not(:last-child) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
|
|
|
@ -9,19 +9,28 @@ interface SidebarStackCardProps {
|
|||
width?: number;
|
||||
headerFeature?: 'back' | 'close';
|
||||
title?: string;
|
||||
onBackPress?: () => void;
|
||||
}
|
||||
|
||||
const SidebarStackCard: FC<SidebarStackCardProps> = ({ children, title, width, headerFeature }) => {
|
||||
const SidebarStackCard: FC<SidebarStackCardProps> = ({
|
||||
children,
|
||||
title,
|
||||
width,
|
||||
headerFeature,
|
||||
onBackPress,
|
||||
}) => {
|
||||
const style = useMemo(() => ({ maxWidth: width, flexBasis: width }), [width]);
|
||||
const backIcon = headerFeature === 'close' ? 'close' : 'right';
|
||||
|
||||
return (
|
||||
<div style={style} className={styles.card}>
|
||||
{(headerFeature || title) && (
|
||||
{!!(headerFeature || title) && (
|
||||
<div className={styles.head}>
|
||||
<Filler>{!!title && <h5>{title}</h5>}</Filler>
|
||||
<Filler>{!!title && <h6>{title}</h6>}</Filler>
|
||||
|
||||
{headerFeature === 'back' && <Button color="link" iconRight="right" />}
|
||||
{headerFeature === 'close' && <Button color="link" iconRight="close" />}
|
||||
{!!(headerFeature && onBackPress) && (
|
||||
<Button color="link" iconRight={backIcon} onClick={onBackPress} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
@ -17,10 +17,12 @@
|
|||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: $gap $gap $gap $gap * 2;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue