Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

access sheet: use menu component + add share to nav #3671

Merged
merged 4 commits into from
Mar 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 32 additions & 9 deletions packages/app/src/app/pages/Sandbox/Editor/Header/Actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const Actions = () => {

let primaryAction;
if (!hasLogIn) primaryAction = 'Sign in';
else primaryAction = owned ? 'Embed' : 'Fork';
else primaryAction = owned ? 'Share' : 'Fork';

return (
<Stack
Expand Down Expand Up @@ -120,8 +120,6 @@ export const Actions = () => {
</Stack>
)}

{author && featureFlags.ACCESS_SHEET && <Collaborators />}

{user?.curatorAt && (
<Button
variant="secondary"
Expand All @@ -131,12 +129,37 @@ export const Actions = () => {
Pick
</Button>
)}
<Button
variant={primaryAction === 'Embed' ? 'primary' : 'secondary'}
onClick={() => modalOpened({ modal: 'share' })}
>
<EmbedIcon css={css({ height: 3, marginRight: 1 })} /> Embed
</Button>

{featureFlags.ACCESS_SHEET && (
<>
{author ? (
<Collaborators
renderButton={props => (
<Button variant="primary" {...props}>
<EmbedIcon css={css({ height: 3, marginRight: 1 })} /> Share
</Button>
)}
/>
) : (
<Button
variant={primaryAction === 'Share' ? 'primary' : 'secondary'}
onClick={() => modalOpened({ modal: 'share' })}
>
<EmbedIcon css={css({ height: 3, marginRight: 1 })} /> Embed
</Button>
)}
</>
)}

{!featureFlags.ACCESS_SHEET && (
<Button
variant={primaryAction === 'Share' ? 'primary' : 'secondary'}
onClick={() => modalOpened({ modal: 'share' })}
>
<EmbedIcon css={css({ height: 3, marginRight: 1 })} /> Embed
</Button>
)}

<Button
variant={primaryAction === 'Fork' ? 'primary' : 'secondary'}
onClick={forkSandboxClicked}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import css from '@styled-system/css';
import { Authorization } from 'app/graphql/types';
import { useOvermind } from 'app/overmind';
import { UserSearchInput } from './UserSearchInput';
import { PermissionSelect, SELECT_WIDTH } from './PermissionSelect';
import { PermissionSelect, MENU_WIDTH } from './PermissionSelect';

export const AddCollaboratorForm = () => {
const { actions, state } = useOvermind();
Expand Down Expand Up @@ -67,17 +67,17 @@ export const AddCollaboratorForm = () => {
onInputValueChange={val => {
setInputValue(val);
}}
css={css({ paddingRight: SELECT_WIDTH })}
css={css({ paddingRight: MENU_WIDTH })}
/>

<PermissionSelect
css={css({
value={authorization}
onChange={setAuthorization}
css={{
position: 'absolute',
right: 0,
top: 0,
})}
value={authorization}
onChange={e => setAuthorization(e.target.value as Authorization)}
right: 0,
}}
/>
</motion.div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { GlobeIcon } from '@codesandbox/common/lib/components/icons/Globe';
import { LinkIcon } from '@codesandbox/common/lib/components/icons/Link';
import { LockIcon } from '@codesandbox/common/lib/components/icons/Lock';
import Tooltip from '@codesandbox/common/lib/components/Tooltip';
import { Select, Stack, Text } from '@codesandbox/components';
import { Stack, Text, Menu, Icon } from '@codesandbox/components';
import css from '@styled-system/css';
import { Authorization } from 'app/graphql/types';
import { useOvermind } from 'app/overmind';
Expand Down Expand Up @@ -208,6 +208,12 @@ export const Invitation = ({ id, email, authorization }: IInvitationProps) => {
);
};

const privacyToName = {
0: 'Public',
1: 'Unlisted',
2: 'Private',
};

const privacyToIcon = {
0: GlobeIcon,
1: LinkIcon,
Expand All @@ -229,31 +235,35 @@ export const LinkPermissions = ({ readOnly }: ILinkPermissionProps) => {
const { privacy } = state.editor.currentSandbox;
const isPatron = state.isPatron;

const Icon = privacyToIcon[privacy];
const PrivacyIcon = privacyToIcon[privacy];

const isReadOnly = readOnly || !isPatron;

const onChange = value => {
actions.workspace.sandboxPrivacyChanged({
privacy: Number(value) as 0 | 1 | 2,
source: 'collaboratorss',
});
};

return (
<Stack gap={4} align="center" direction="vertical">
<CollaboratorItem
avatarComponent={<Icon />}
avatarComponent={<PrivacyIcon />}
name={
<Select
variant="link"
onChange={e => {
actions.workspace.sandboxPrivacyChanged({
privacy: Number(e.target.value) as 0 | 1 | 2,
source: 'collaboratorss',
});
}}
value={privacy}
css={css({ paddingLeft: 0 })}
disabled={isReadOnly}
>
<option value="0">Public</option>
<option value="1">Unlisted</option>
<option value="2">Private</option>
</Select>
<Menu>
<Menu.Button disabled={isReadOnly}>
{privacyToName[privacy]}{' '}
<Icon name="caret" size={2} marginLeft={1} />
</Menu.Button>
<Menu.List>
{Object.keys(privacyToName).map(p => (
<Menu.Item key={p} onSelect={() => onChange(p)}>
{privacyToName[p]}
</Menu.Item>
))}
</Menu.List>
</Menu>
}
authorization={Authorization.Read}
permissions={[]}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React, { FunctionComponent } from 'react';
import { Button, Element } from '@codesandbox/components';
import { Element } from '@codesandbox/components';
import { hasPermission } from '@codesandbox/common/lib/utils/permission';
import { Overlay } from 'app/components/Overlay';
import { useOvermind } from 'app/overmind';

import { AddPeople } from './icons';
import { Container, HorizontalSeparator } from './elements';
import { AddCollaboratorForm } from './AddCollaboratorForm';
import { LinkPermissions } from './Collaborator';
Expand Down Expand Up @@ -43,18 +42,16 @@ const CollaboratorContent = () => {
);
};

export const Collaborators: FunctionComponent = () => (
export const Collaborators: FunctionComponent<{
renderButton: (any) => JSX.Element;
}> = ({ renderButton }) => (
<>
<Overlay
noHeightAnimation={false}
event="Collaborators"
content={CollaboratorContent}
>
{open => (
<Button onClick={() => open()} variant="link">
<AddPeople width={24} height={24} />
</Button>
)}
{open => renderButton({ onClick: () => open() })}
</Overlay>
</>
);
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
import React from 'react';
import css from '@styled-system/css';
import { Select, Stack } from '@codesandbox/components';
import { Menu, Icon } from '@codesandbox/components';
import { Authorization } from 'app/graphql/types';

interface IPermissionSelectProps extends React.ComponentProps<typeof Select> {
additionalOptions?: { value: string; label: string }[];
permissions?: Authorization[];
pretext?: string;
}

const authToName = {
[Authorization.WriteCode]: 'Can Edit',
[Authorization.Comment]: 'Can Comment',
Expand All @@ -17,25 +10,43 @@ const authToName = {
[Authorization.WriteProject]: 'Edit Sandbox Info',
};

export const SELECT_WIDTH = 85;
// Based on the longest option in the mnu
// which is "Can Comment"
export const MENU_WIDTH = 110;

interface IPermissionSelectProps {
additionalOptions?: { value: string; label: string }[];
permissions?: Authorization[];
pretext?: string;
value: Authorization;
onChange: (Authorization) => void;
disabled?: boolean;
}

export const PermissionSelect = ({
additionalOptions = [],
permissions = [Authorization.WriteCode, Authorization.Read],
value: selectedValue,
onChange,
disabled,
...props
}: IPermissionSelectProps) => (
<Stack align="center">
<Select variant="link" css={css({ width: SELECT_WIDTH })} {...props}>
<Menu>
<Menu.Button disabled={disabled} {...props}>
{authToName[selectedValue]} <Icon name="caret" size={2} marginLeft={1} />
</Menu.Button>
<Menu.List>
{permissions.map(auth => (
<option key={auth} value={auth}>
<Menu.Item key={auth} onSelect={() => onChange(auth)}>
{authToName[auth]}
</option>
</Menu.Item>
))}

{additionalOptions.map(({ label, value }) => (
<option key={value} value={value}>
<Menu.Item key={label} onSelect={() => onChange(value)}>
{label}
</option>
</Menu.Item>
))}
</Select>
</Stack>
</Menu.List>
</Menu>
);
Original file line number Diff line number Diff line change
@@ -1,26 +1,6 @@
import React from 'react';
import IconBase from 'react-icons/IconBase';

export const AddPeople = props => (
<IconBase
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M6.57143 6H5.42857V9.42857H2V10.5714H5.42857V14H6.57143V10.5714H10V9.42857H6.57143V6Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M18.6493 8.50025C18.6493 9.26669 18.3765 10.0235 18.054 10.6C17.9808 10.7309 18.1127 10.952 18.2448 11.1736C18.3898 11.4168 18.5351 11.6606 18.4098 11.7859C18.0667 12.129 17.2557 12.088 16.5991 12.0391C16.168 12.4163 15.6485 12.6365 15.0892 12.6365C14.4603 12.6365 13.8815 12.358 13.4225 11.8909C13.2965 11.9492 13.171 12.0075 13.047 12.0668C12.0716 11.9375 11.4694 10.3319 11.7019 8.48083C11.9344 6.62971 12.9135 5.23396 13.8888 5.36334C14.1122 5.4114 14.3145 5.4734 14.4977 5.54697C14.9167 5.20067 15.4143 5 15.9482 5C17.4399 5 18.6493 6.56711 18.6493 8.50025ZM10.042 18.8142L19.7895 18.8142C19.7895 18.8142 20.4942 14.1095 14.857 13.9862C9.21991 13.863 10.042 18.8142 10.042 18.8142Z"
fill="currentColor"
/>
</IconBase>
);

export const Mail = props => (
<IconBase
fill="none"
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/components/Menu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const MenuContext = React.createContext({ trigger: null });
const PortalStyles = createGlobalStyle(
css({
'[data-reach-menu]': {
zIndex: 2,
zIndex: 11, // TODO: we need to sort out our z indexes!
},
'[data-reach-menu-list][data-component=MenuList]': {
minWidth: 100,
Expand Down
Loading