1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-25 12:56:41 +07:00

made better tabs (with context)

This commit is contained in:
Fedor Katurov 2021-12-26 11:25:34 +07:00
parent f63d2d3228
commit da510e346a
12 changed files with 103 additions and 194 deletions

View file

@ -1,16 +0,0 @@
import React, { FC, MouseEventHandler } from 'react';
import classNames from 'classnames';
import styles from './styles.module.scss';
interface IProps {
active?: boolean;
onClick?: MouseEventHandler<any>;
}
const Tab: FC<IProps> = ({ active, onClick, children }) => (
<div className={classNames(styles.tab, { [styles.active]: active })} onClick={onClick}>
{children}
</div>
);
export { Tab };

View file

@ -1,20 +0,0 @@
@import "src/styles/variables";
.tab {
@include outer_shadow();
padding: $gap;
margin-right: $gap;
border-radius: $radius $radius 0 0;
font: $font_14_semibold;
text-transform: uppercase;
cursor: pointer;
background-color: $content_bg;
color: white;
text-decoration: none;
border: none;
&.active {
background: lighten($content_bg, 4%);
}
}

View file

@ -1,12 +1,51 @@
import React, { FC, useCallback } from 'react';
import React, { createContext, FC, VFC, useContext, useState } from 'react';
import styles from './styles.module.scss';
import classNames from 'classnames';
import { IAuthState } from '~/redux/auth/types';
interface IProps {}
interface TabProps {
items: string[];
}
const Tabs: FC<IProps> = ({ children }) => {
return <div className={styles.wrap}>{children}</div>;
const TabContext = createContext({
activeTab: 0,
setActiveTab: (activeTab: number) => {},
});
const List: VFC<TabProps> = ({ items }) => {
const { activeTab, setActiveTab } = useContext(TabContext);
return (
<div className={styles.tabs}>
{items.map((it, index) => (
<div
className={classNames(styles.tab, { [styles.active]: activeTab === index })}
onClick={() => setActiveTab(index)}
key={it}
>
{it}
</div>
))}
</div>
);
};
const Content: FC<any> = ({ children }) => {
const { activeTab } = useContext(TabContext);
if (!Array.isArray(children) && activeTab > 0) {
return null;
}
return Array.isArray(children) ? children[activeTab] : children;
};
const Tabs = function({ children }) {
const [activeTab, setActiveTab] = useState(0);
return <TabContext.Provider value={{ activeTab, setActiveTab }}>{children}</TabContext.Provider>;
};
Tabs.List = List;
Tabs.Content = Content;
export { Tabs };

View file

@ -1,4 +1,4 @@
@import "src/styles/variables";
@import "~/styles/variables";
.wrap {
display: flex;
@ -6,3 +6,27 @@
justify-content: flex-start;
padding: 0 $gap / 2;
}
.tab {
@include outer_shadow();
padding: $gap;
margin-right: $gap;
border-radius: $radius $radius 0 0;
font: $font_14_semibold;
text-transform: uppercase;
cursor: pointer;
background-color: $content_bg;
color: white;
text-decoration: none;
border: none;
&.active {
background: lighten($content_bg, 4%);
}
}
.tabs {
display: flex;
flex-direction: row;
}

View file

@ -76,10 +76,6 @@
background: lighten($content_bg, 3%);
padding: $gap;
border-radius: $radius;
:global(.input_title) {
color: lighten($content_bg, 10%);
}
}
.search_icon {

View file

@ -84,7 +84,7 @@ const InputText: FC<IInputTextProps> = ({
</div>
{title && (
<div className={classNames(styles.title, 'input_title')}>
<div className={classNames(styles.title)}>
<span>{title}</span>
</div>
)}

View file

@ -1,37 +0,0 @@
import * as React from 'react';
import styles from './styles.module.scss';
interface ITextInputProps {
type?: 'text' | 'password';
placeholder?: string;
label?: string;
value?: string;
onChange: React.ChangeEventHandler;
}
export const TextInput: React.FunctionComponent<ITextInputProps> = ({
type = 'text',
placeholder = '',
label,
onChange = () => {},
value = '',
}) => (
<div
className={styles.wrapper}
>
<div className={styles.container}>
{
label
&& <div className={styles.label}>{label}</div>
}
<input
placeholder={placeholder}
className={styles.input}
type={type}
onChange={onChange}
value={value}
/>
</div>
</div>
);

View file

@ -1,58 +0,0 @@
@import "src/styles/variables";
.wrapper {
height: $input_height;
display: flex;
flex-direction: column;
align-items: flex-start;
position: relative;
flex: 1;
}
.label {
// background: transparentize(black, 0.8);
font: $font_14_medium;
// color: transparentize(white, 0.5);
text-transform: uppercase;
padding: 2px $gap;
display: flex;
align-items: center;
justify-content: flex-start;
border-radius: $radius 0 0 $radius;
//@include input_shadow();
padding: 0 5px;
position: absolute;
bottom: $input_height - 3px;
font: $font_10_semibold;
background-color: white;
color: transparentize(white, 0.5);
border-radius: $radius;
left: 6px;
background: $content_bg;
height: 10px;
}
.container {
height: $input_height;
background: $input_bg_color;
border-radius: $input_radius;
flex-direction: row;
flex: 1 0;
display: flex;
align-self: stretch;
align-items: stretch;
justify-content: center;
@include input_shadow();
}
.input {
outline: none;
background: transparent;
flex: 1;
border: none;
font-size: inherit;
color: white;
padding: 0 $gap;
box-sizing: border-box;
}

View file

@ -4,22 +4,16 @@ import { ProfileInfo } from '~/containers/profile/ProfileInfo';
import { IDialogProps } from '~/redux/types';
import { connect } from 'react-redux';
import { selectAuthProfile, selectAuthUser } from '~/redux/auth/selectors';
import { ProfileMessages } from '~/containers/profile/ProfileMessages';
import { ProfileDescription } from '~/components/profile/ProfileDescription';
import * as AUTH_ACTIONS from '~/redux/auth/actions';
import { IAuthState } from '~/redux/auth/types';
import { pick } from 'ramda';
import { CoverBackdrop } from '~/components/containers/CoverBackdrop';
import { MessageForm } from '~/components/profile/MessageForm';
import { Tabs } from '~/components/dialogs/Tabs';
import { ProfileDescription } from '~/components/profile/ProfileDescription';
import { ProfileMessages } from '~/containers/profile/ProfileMessages';
import { ProfileSettings } from '~/components/profile/ProfileSettings';
import { ProfileAccounts } from '~/components/profile/ProfileAccounts';
import { MessageForm } from '~/components/profile/MessageForm';
const TAB_CONTENT = {
profile: <ProfileDescription />,
messages: <ProfileMessages />,
settings: <ProfileSettings />,
accounts: <ProfileAccounts />,
};
const mapStateToProps = state => ({
profile: selectAuthProfile(state),
@ -52,6 +46,7 @@ const ProfileDialogUnconnected: FC<IProps> = ({
]);
return (
<Tabs>
<BetterScrollDialog
header={
<ProfileInfo
@ -67,8 +62,14 @@ const ProfileDialogUnconnected: FC<IProps> = ({
backdrop={<CoverBackdrop cover={user && user.cover} />}
onClose={onRequestClose}
>
{TAB_CONTENT[tab] || null}
<Tabs.Content>
<ProfileDescription />
<ProfileMessages />
<ProfileSettings />
<ProfileAccounts />
</Tabs.Content>
</BetterScrollDialog>
</Tabs>
);
};

View file

@ -1,9 +1,7 @@
import React, { FC, useCallback } from 'react';
import styles from './styles.module.scss';
import classNames from 'classnames';
import { IAuthState } from '~/redux/auth/types';
import { Tabs } from '~/components/dialogs/Tabs';
import { Tab } from '~/components/dialogs/Tab';
interface IProps {
tab: string;
@ -12,30 +10,11 @@ interface IProps {
}
const ProfileTabs: FC<IProps> = ({ tab, is_own, setTab }) => {
const changeTab = useCallback(
(tab: IAuthState['profile']['tab']) => () => {
if (!setTab) return;
setTab(tab);
},
[setTab]
);
const items = ['Профиль', 'Сообщения', ...(is_own ? ['Настройки'] : [])];
return (
<div className={styles.wrap}>
<Tabs>
<Tab active={tab === 'profile'} onClick={changeTab('profile')}>
Профиль
</Tab>
<Tab active={tab === 'messages'} onClick={changeTab('messages')}>
Сообщения
</Tab>
{is_own && (
<Tab active={tab === 'settings'} onClick={changeTab('settings')}>
Настройки
</Tab>
)}
</Tabs>
<Tabs.List items={items} />
</div>
);
};

View file

@ -10,6 +10,8 @@ import { SidebarRouter } from '~/containers/main/SidebarRouter';
import { BorisSidebar } from '~/components/boris/BorisSidebar';
import { useUserContext } from '~/utils/context/UserContextProvider';
import { BorisUsageStats } from '~/redux/boris/reducer';
import { Tabs } from '~/components/dialogs/Tabs';
import { Superpower } from '~/components/boris/Superpower';
type IProps = {
title: string;

View file

@ -4,7 +4,6 @@
position: relative;
min-height: 40px;
border-radius: $input_radius;
//box-shadow: $input_shadow;
flex: 1;
display: flex;
opacity: 1;
@ -274,7 +273,7 @@
transition: top 0.25s, bottom 0.25s, font 0.25s, color 0.25s;
pointer-events: none;
touch-action: none;
color: transparentize(white, 0.5);
color: lighten($content_bg, 10%);
text-transform: capitalize;
background: $input_bg_color;