Skip to content

Commit

Permalink
feat: global create button
Browse files Browse the repository at this point in the history
  • Loading branch information
awinogradov committed Jan 12, 2023
1 parent 12f26be commit 99ac5f8
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 148 deletions.
8 changes: 7 additions & 1 deletion i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@
"Name": "Name",
"Nickname": "Nickname",
"Appearance": "Appearance",
"Danger zone": "Danger zone",
"Sign out": "Sign out",
"User name is required": "User name is required",
"User name must be a string": "User name must be a string",
"User name must be longer than 3 symbols": "User name must be longer than 3 symbol",
Expand Down Expand Up @@ -252,7 +254,11 @@
"Goals": "Goals",
"Issues": "Issues",
"Explore": "Explore",
"Boards": "Boards"
"Boards": "Boards",
"Create": "Create",
"Create goal": "Goal",
"Create project": "Project",
"Create team": "Team"
},
"HeaderMenu": {
"New goal": "New goal",
Expand Down
11 changes: 7 additions & 4 deletions i18n/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@
"Name": "Имя",
"Nickname": "Логин",
"Appearance": "Интерфейс",
"Danger zone": "Опасная зона",
"Sign out": "Выйти",
"User name is required": "Указание имени обязательно",
"User name must be a string": "Имя должно быть строкой",
"User name must be longer than 3 symbols": "Имя не может быть короче 3х символов",
Expand Down Expand Up @@ -252,12 +254,13 @@
"Goals": "Цели",
"Issues": "Задачи",
"Explore": "Обзор",
"Boards": "Доски"
"Boards": "Доски",
"Create": "Создать",
"Create goal": "Цель",
"Create project": "Проект",
"Create team": "Команду"
},
"HeaderMenu": {
"New goal": "Новая цель",
"New project": "Новый проект",
"Invite users": "Пригласить",
"Sign out": "Выйти"
},
"TagCompletion": {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ const Dropdown = React.forwardRef<HTMLDivElement, DropdownProps>(
reference={popupRef}
interactive
arrow={false}
minWidth={150}
minWidth={100}
maxWidth={250}
offset={[-4, 8]}
>
Expand Down
69 changes: 67 additions & 2 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import { useCallback } from 'react';
import NextLink from 'next/link';
import styled from 'styled-components';
import { useTranslations } from 'next-intl';
import dynamic from 'next/dynamic';

import { routes } from '../hooks/router';
import { textColor, gray7, colorPrimary, gray3 } from '../design/@generated/themes';
import { dispatchModalEvent, ModalEvent } from '../utils/dispatchModal';

import { HeaderLogo } from './HeaderLogo';
import { HeaderMenu } from './HeaderMenu';
import { Icon } from './Icon';
import { Button } from './Button';
import { MenuItem } from './MenuItem';

const Dropdown = dynamic(() => import('./Dropdown'));

const StyledHeader = styled.header`
display: grid;
grid-template-columns: 20px 11fr 100px;
grid-template-columns: 20px 10fr 150px 55px;
align-items: center;
padding: 20px 40px;
Expand Down Expand Up @@ -59,9 +66,18 @@ const StyledHeaderNavLink = styled.a<{ disabled?: boolean }>`
}
`;

const StyledCreateButton = styled.div`
display: flex;
align-items: center;
`;

export const Header: React.FC = () => {
const t = useTranslations('Header');

const onMenuItemClick = useCallback(({ event }: { event: ModalEvent }) => {
dispatchModalEvent(event)();
}, []);

return (
<StyledHeader>
<HeaderLogo />
Expand All @@ -81,7 +97,56 @@ export const Header: React.FC = () => {
</StyledSearch>
</StyledNav>

<HeaderMenu notifications />
<StyledCreateButton>
<Button
text={t('Create')}
view="primary"
outline
brick="right"
onClick={dispatchModalEvent(ModalEvent.GoalCreateModal)}
/>
<Dropdown
onChange={onMenuItemClick}
items={[
{
title: t('Create goal'),
event: ModalEvent.GoalCreateModal,
},
{
title: t('Create project'),
event: ModalEvent.ProjectCreateModal,
},
{
title: t('Create team'),
event: ModalEvent.TeamCreateModal,
},
]}
renderTrigger={(props) => (
<Button
view="primary"
outline
brick="left"
iconRight={
<Icon size="s" noWrap type={props.visible ? 'arrowUpSmall' : 'arrowDownSmall'} />
}
ref={props.ref}
onClick={props.onClick}
/>
)}
renderItem={(props) => (
<MenuItem
key={props.item.title}
focused={props.cursor === props.index}
onClick={props.onClick}
view="primary"
ghost
>
{props.item.title}
</MenuItem>
)}
/>
</StyledCreateButton>
<HeaderMenu />
</StyledHeader>
);
};
104 changes: 3 additions & 101 deletions src/components/HeaderMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import React, { useCallback, useRef, useState } from 'react';
import React from 'react';
import styled from 'styled-components';
import { signOut, signIn } from 'next-auth/react';
import { useTranslations } from 'next-intl';
import { signIn } from 'next-auth/react';
import NextLink from 'next/link';
import dynamic from 'next/dynamic';

import { nullable } from '../utils/nullable';
import { dispatchModalEvent, ModalEvent } from '../utils/dispatchModal';
import { routes } from '../hooks/router';
import { backgroundColor, brandColor, gapM, gray3, textColor, gray8, gapXs, link10 } from '../design/@generated/themes';
import { gray3, textColor, link10 } from '../design/@generated/themes';
import { usePageContext } from '../hooks/usePageContext';

import { UserPic } from './UserPic';
import { Link } from './Link';
import { Text } from './Text';

const Popup = dynamic(() => import('./Popup'));

interface HeaderMenuProps {
notifications?: boolean;
Expand All @@ -26,42 +20,6 @@ const StyledHeaderMenu = styled.div`
justify-self: end;
`;

const StyledPopupContent = styled.div`
min-width: 120px;
`;

const StyledPlus = styled.div`
position: absolute;
display: flex;
align-content: center;
justify-content: center;
top: 14px;
left: -10px;
box-sizing: border-box;
width: 18px;
height: 18px;
font-size: 14px;
font-weight: 400;
box-shadow: 0 0 0 2px ${gray3};
color: ${backgroundColor};
background-color: ${brandColor};
border-radius: 100%;
cursor: pointer;
user-select: none;
transition: box-shadow 150ms ease-in-out;
&:hover {
font-weight: 600;
box-shadow: 0px 0px 0px 2px ${brandColor}, 1px 1px 2px 0px ${textColor};
}
`;

const StyledNotifier = styled.div`
position: absolute;
top: 0px;
Expand All @@ -83,67 +41,11 @@ const StyledNotifier = styled.div`
}
`;

const StyledMenuItem = styled.div`
padding: ${gapXs} ${gapM};
`;

export const HeaderMenu = ({ notifications }: HeaderMenuProps) => {
const t = useTranslations('HeaderMenu');
const popupRef = useRef<HTMLDivElement>(null);
const buttonRef = useRef<HTMLDivElement>(null);
const [popupVisible, setPopupVisibility] = useState(false);
const { user } = usePageContext();

const onClickOutside = useCallback(() => {
setPopupVisibility(false);
}, []);

const togglePopup = useCallback(() => {
setPopupVisibility(!popupVisible);
}, [popupVisible]);

return (
<StyledHeaderMenu>
<span ref={popupRef}>
<StyledPlus ref={buttonRef} onClick={togglePopup}>
+
</StyledPlus>
</span>

<Popup
visible={popupVisible}
onClickOutside={onClickOutside}
reference={popupRef}
interactive
minWidth={150}
maxWidth={250}
>
<StyledPopupContent>
<StyledMenuItem>
<Link inline onClick={dispatchModalEvent(ModalEvent.GoalCreateModal)}>
{t('New goal')}
</Link>
</StyledMenuItem>
<StyledMenuItem>
<Link inline onClick={dispatchModalEvent(ModalEvent.ProjectCreateModal)}>
{t('New project')}
</Link>
</StyledMenuItem>
<StyledMenuItem>
<Link inline onClick={dispatchModalEvent(ModalEvent.UserInviteModal)}>
{t('Invite users')}
</Link>
</StyledMenuItem>
<StyledMenuItem>
<Text color={gray8}>
<Link inline onClick={() => signOut()}>
{t('Sign out')}
</Link>
</Text>
</StyledMenuItem>
</StyledPopupContent>
</Popup>

{nullable(notifications, () => (
<StyledNotifier />
))}
Expand Down
10 changes: 0 additions & 10 deletions src/pages/goals/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ const StyledIssueInfo = styled.div<{ align: 'left' | 'right' }>`
`}
`;

const StyledIssueInfoRow = styled.div``;

const IssueBaseActions = styled.div`
display: flex;
align-items: center;
Expand Down Expand Up @@ -267,14 +265,6 @@ const GoalPage = ({
onToggle={toggleGoalStar(onStarToggle, t, stargizer)}
/>
</PageActions>

<StyledIssueInfoRow>
<Button
view="primary"
text={t('New goal')}
onClick={dispatchModalEvent(ModalEvent.GoalCreateModal)}
/>
</StyledIssueInfoRow>
</StyledIssueInfo>
</IssueHeader>

Expand Down
11 changes: 1 addition & 10 deletions src/pages/goals/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import styled from 'styled-components';
import { useRouter } from 'next/router';
import dynamic from 'next/dynamic';

import { dispatchModalEvent, ModalEvent } from '../../utils/dispatchModal';
import { Goal, Project } from '../../../graphql/@generated/genql';
import { createFetcher } from '../../utils/createFetcher';
import { declareSsrProps, ExternalPageProps } from '../../utils/declareSsrProps';
Expand All @@ -18,7 +17,6 @@ import { useMounted } from '../../hooks/useMounted';
import { useUrlParams } from '../../hooks/useUrlParams';
import { Text } from '../../components/Text';
import { PageSep } from '../../components/PageSep';
import { Button } from '../../components/Button';
import { defaultLimit } from '../../components/LimitFilterDropdown';

const GoalPreview = dynamic(() => import('../../components/GoalPreview'));
Expand Down Expand Up @@ -214,14 +212,7 @@ const GoalsPage = ({ user, ssrTime, locale, ssrData }: ExternalPageProps<{ userG
onUserChange={setOwnerFilter}
onTagChange={setTagsFilter}
onLimitChange={setLimitFilter}
>
<Button
view="primary"
size="m"
text={t('New goal')}
onClick={dispatchModalEvent(ModalEvent.GoalCreateModal)}
/>
</FiltersPanel>
/>

<PageContent>
{projects?.map((project) => {
Expand Down
10 changes: 1 addition & 9 deletions src/pages/projects/[key]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { useUrlParams } from '../../../hooks/useUrlParams';
import { useLocalStorage } from '../../../hooks/useLocalStorage';
import { useWillUnmount } from '../../../hooks/useWillUnmount';
import { ProjectPageLayout } from '../../../components/ProjectPageLayout';
import { dispatchModalEvent, ModalEvent } from '../../../utils/dispatchModal';
import { Page } from '../../../components/Page';

const GoalPreview = dynamic(() => import('../../../components/GoalPreview'));
Expand Down Expand Up @@ -298,14 +297,7 @@ const ProjectPage = ({
onUserChange={setOwnerFilter}
onTagChange={setTagsFilter}
onLimitChange={setLimitFilter}
>
<Button
view="primary"
size="m"
text={t('index.New goal')}
onClick={dispatchModalEvent(ModalEvent.GoalCreateModal)}
/>
</FiltersPanel>
/>

<StyledGoalsList>
{goals?.map((goal) =>
Expand Down
Loading

0 comments on commit 99ac5f8

Please sign in to comment.