Skip to content

Commit

Permalink
#75 Added model Profile. Update style of Tabs.
Browse files Browse the repository at this point in the history
  • Loading branch information
artzub committed Jan 7, 2021
1 parent 5319898 commit e73fb5b
Show file tree
Hide file tree
Showing 11 changed files with 279 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const SearchHeader = (

const TopHeader = (
<ListSubheader component="li" disableSticky>
Top users
Top profiles
</ListSubheader>
);

Expand All @@ -86,9 +86,9 @@ const Body = () => {
);

const onClick = useCallback(
(user) => () => {
(profile) => () => {
setBodyOpen(false);
redirectTo(user.login);
redirectTo(profile.login);
},
[redirectTo, setBodyOpen],
);
Expand Down Expand Up @@ -120,8 +120,8 @@ const Body = () => {
return (
<Container>
<TextField
label="Username"
placeholder="Type username"
label="Profile name"
placeholder="Type profile name"
onChange={onChange}
ref={inputRef}
/>
Expand All @@ -134,18 +134,18 @@ const Body = () => {
subheader={SearchHeader}
>
{!items.length && <NotData />}
{(items || []).map((user) => (
{(items || []).map((profile) => (
<ListItem
alignItems="center"
key={user.login}
onClick={onClick(user)}
key={profile.login}
onClick={onClick(profile)}
>
<ListItemAvatar>
<Avatar src={user.avatar_url} />
<Avatar src={profile.avatar_url} />
</ListItemAvatar>
<ListItemText
primary={<Highlight search={search} text={user.login} />}
secondary={user.type}
primary={<Highlight search={search} text={profile.login} />}
secondary={profile.type}
/>
</ListItem>
))}
Expand All @@ -156,18 +156,18 @@ const Body = () => {
dense
subheader={TopHeader}
>
{(top || []).map((user) => (
{(top || []).map((profile) => (
<ListItem
alignItems="center"
key={user.login}
onClick={onClick(user)}
key={profile.login}
onClick={onClick(profile)}
>
<ListItemAvatar>
<Avatar src={user.avatar_url} />
<Avatar src={profile.avatar_url} />
</ListItemAvatar>
<ListItemText
primary={user.login}
secondary={user.type}
primary={profile.login}
secondary={profile.type}
/>
</ListItem>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import PropertyValue from '../shared/PropertyValue';
import Title from '../shared/Title';

const Container = styled(HeaderContainer)`
min-width: 165px;
max-width: 165px;
& > div:first-child {
padding-left: 8px;
}
Expand All @@ -35,15 +37,15 @@ const onClick = (event) => event.stopPropagation();
const Header = (props) => {
const { selected } = useSelector(slice.selectors.getState);
const {
avatar_url, name, login,
html_url, public_repos, blog,
avatar, name, login,
url, publicRepos, site,
} = selected || {};

return (
<Container {...props}>
<Avatar src={avatar_url} />
<Avatar src={avatar} />
<InfoContainer>
{!selected && <div>Find a user</div>}
{!selected && <div>Find a profile</div>}
{selected && (
<React.Fragment>
<Title title={name || login}>{name || login}</Title>
Expand All @@ -54,7 +56,7 @@ const Header = (props) => {
<Link
target="_blank"
onClick={onClick}
href={html_url}
href={url}
>
{login}
</Link>
Expand All @@ -64,16 +66,16 @@ const Header = (props) => {
<Properties>
<Property title="Amount of repositories">
<BookMultipleIcon size={16} />
<PropertyValue>{public_repos}</PropertyValue>
<PropertyValue>{publicRepos}</PropertyValue>
</Property>
{blog && (
{site && (
<Property title="Web site">
<LinkVariantIcon size={16} />
<PropertyValue>
<Link
target="_blank"
onClick={onClick}
href={blog}
href={site}
>
site
</Link>
Expand Down
198 changes: 198 additions & 0 deletions src/components/Header/components/Tabs/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
/* eslint-disable jsx-a11y/anchor-is-valid */
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { StageTypes } from '@/models/StageTypes';
import commits from '@/redux/modules/commits';
import { useUIProperty } from '@/shared/hooks';
import { teal } from '@material-ui/core/colors';
import { useSelector } from 'react-redux';
import styled, { keyframes } from 'styled-components';

const Container = styled.div`
display: flex;
width: 100%;
`;

const Tab = styled.button`
text-transform: uppercase;
position: relative;
border: 0;
font-size: 12px;
color: ${({ $active }) => teal[$active ? 200 : 700]};
padding: 3px 6px;
padding-right: ${({ $notDivider }) => $notDivider ? null : '10px'};
outline: 0;
cursor: ${({ $active }) => $active ? 'default' : 'pointer'};
background: transparent;
flex: 1 1 0;
transition: opacity 0.3s, color 0.3s;
&:hover:not(:disabled) {
color: ${({ $active }) => teal[$active ? 200 : 400]};
}
&:active:not(:disabled) {
color: ${({ $active }) => teal[$active ? 200 : 100]};
}
&:disabled {
color: #888888;
cursor: default;
}
&:before {
content: '';
position: absolute;
right: 9.5px;
top: 0;
bottom: 0;
width: 2px;
border-right: ${({ $notDivider }) => $notDivider ? null : '1px solid rgba(0,0,0,0.3)'};
box-shadow: ${({ $notDivider }) => $notDivider ? null : '1px 0 0 0 rgba(0,0,0,0.2)'};
}
& > span {
pointer-events: none;
}
`;

const hide = keyframes`
0% {
opacity: 1;
}
100% {
opacity: 0;
}
`;

const show = keyframes`
0% {
opacity: 1;
}
100% {
opacity: 1;
}
`;

const Slider = styled.div.attrs(({ $width, $left, $opacity }) => ({
style: {
width: `${$width || 0}px`,
transform: `translate(${$left || 0}px, 0)`,
animationName: ($opacity ? show : hide).name,
animationDelay: `${$opacity ? 0 : 1}s`,
},
}))`
position: absolute;
bottom: 3px;
height: 1px;
left: 0;
background: ${teal[200]};
transition: width 0.3s, transform 0.3s, opacity 0.3s;
z-index: 1;
animation-name: ${show};
animation-name: ${hide};
animation-duration: 1s;
animation-fill-mode: forwards;
`;

const Tabs = () => {
const [view, setView] = useUIProperty('view', StageTypes.profile);
const { items } = useSelector(commits.selectors.getState);
const refContainer = useRef();
const [slider, setSlider] = useState();
const [ref, setRef] = useState();
const [width, setWidth] = useState(0);
const [left, setLeft] = useState(0);
const [opacity, setOpacity] = useState(0);

console.log(view);

const onClick = useCallback(
(event) => {
console.log(event.target.dataset.key);
setView(event.target.dataset.key);
},
[setView],
);

useEffect(
() => {
if (!ref || !refContainer.current) {
return;
}

const parentRest = refContainer.current.getBoundingClientRect();
const rect = ref.firstChild.getBoundingClientRect();

setWidth(rect.width);
setLeft(rect.left - parentRest.left);
setOpacity(1);
},
[ref],
);

useEffect(
() => {
if (!slider) {
return;
}

const end = () => {
setOpacity(0);
};

slider.addEventListener('transitionend', end, true);

return () => {
end();
if (slider) {
slider.removeEventListener('transitionend', end, true);
}
};
},
[slider],
);

return (
<Container ref={refContainer}>
<Slider
$width={width}
$left={left}
$opacity={opacity}
ref={setSlider}
/>
<Tab
$active={view === StageTypes.profile}
onClick={onClick}
data-key={StageTypes.profile}
style={{ maxWidth: '165px', minWidth: '165px' }}
title="Screen profile"
ref={view === StageTypes.profile ? setRef : null}
>
<span>Profile</span>
</Tab>
<Tab
$active={view === StageTypes.repository}
onClick={onClick}
data-key={StageTypes.repository}
disabled={!items?.length}
title="Screen repository"
ref={view === StageTypes.repository ? setRef : null}
>
<span>Repository</span>
</Tab>
<Tab
$active={view === StageTypes.show}
onClick={onClick}
data-key={StageTypes.show}
style={{ maxWidth: '74px', minWidth: '74px' }}
$notDivider
disabled
title="Screen show"
ref={view === StageTypes.show ? setRef : null}
>
<span>Show</span>
</Tab>
</Container>
);
};

export default Tabs;
Loading

0 comments on commit e73fb5b

Please sign in to comment.