Skip to content

Commit 28b039c

Browse files
authored
Add Pro buttons (codesandbox#3172)
* Add Pro buttons * WIP * Apply new icons * Redirect to pricing if you're no subscribed user * Remove unncessary dependency
1 parent 76f5dc4 commit 28b039c

File tree

33 files changed

+240
-44
lines changed

33 files changed

+240
-44
lines changed

packages/app/src/app/pages/Patron/index.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ const Patron: React.FC = () => {
2121
}
2222
// don't send them away before authentication
2323
if (hasLoadedApp && user) {
24-
if (
25-
!user.subscription || // if no subscription, get pro
24+
if (!user.subscription) {
25+
location.href = '/pricing'; // if no subscription, to pricing with you!
26+
} else if (
2627
user.subscription.plan !== 'patron' // if subscription but not patron, go to pro
2728
) {
2829
location.href = '/pro';

packages/app/src/app/pages/Sandbox/Editor/Workspace/Files/DirectoryEntry/Entry/EntryIcons/GetIconURL.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import folderSvg from '@codesandbox/common/lib/components/icons/folder.svg';
2-
import folderOpenSvg from '@codesandbox/common/lib/components/icons/folder-open.svg';
3-
import fileSvg from '@codesandbox/common/lib/components/icons/file.svg';
4-
import imageSvg from '@codesandbox/common/lib/components/icons/image.svg';
5-
import codesandboxSvg from '@codesandbox/common/lib/components/icons/codesandbox.svg';
6-
import nowSvg from '@codesandbox/common/lib/components/icons/now.svg';
1+
import folderSvg from '@codesandbox/common/lib/icons/folder.svg';
2+
import folderOpenSvg from '@codesandbox/common/lib/icons/folder-open.svg';
3+
import fileSvg from '@codesandbox/common/lib/icons/file.svg';
4+
import imageSvg from '@codesandbox/common/lib/icons/image.svg';
5+
import codesandboxSvg from '@codesandbox/common/lib/icons/codesandbox.svg';
6+
import nowSvg from '@codesandbox/common/lib/icons/now.svg';
77

88
function imageExists(url) {
99
return new Promise((resolve, reject) => {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// TODO; move this to a dynamic version used in the pro page
2+
import React from 'react';
3+
import IconBase from 'react-icons/lib/IconBase';
4+
5+
export const ProIcon = props => (
6+
<IconBase viewBox="0 0 58 26" {...props}>
7+
<rect
8+
x="1.20896"
9+
y="1.20896"
10+
width="55.3731"
11+
height="23.7313"
12+
rx="2.37313"
13+
fill="#535BCF"
14+
stroke="#151515"
15+
strokeWidth="1.58209"
16+
/>
17+
<path
18+
d="M15.6856 19.5822H18.3616V15.4786H20.6111C23.5219 15.4786 25.2153 13.742 25.2153 11.2144C25.2153 8.69911 23.5528 6.92544 20.6791 6.92544H15.6856V19.5822ZM18.3616 13.3341V9.11317H20.1662C21.7112 9.11317 22.459 9.95366 22.459 11.2144C22.459 12.4689 21.7112 13.3341 20.1785 13.3341H18.3616ZM26.9039 19.5822H29.5366V14.2117C29.5366 13.0437 30.3895 12.2403 31.5513 12.2403C31.916 12.2403 32.4165 12.3021 32.6637 12.3824V10.0464C32.4289 9.99074 32.1014 9.95366 31.8356 9.95366C30.7726 9.95366 29.9013 10.5717 29.5552 11.7459H29.4563V10.0896H26.9039V19.5822ZM37.872 19.7676C40.7519 19.7676 42.5441 17.7961 42.5441 14.873C42.5441 11.9313 40.7519 9.96602 37.872 9.96602C34.9921 9.96602 33.1999 11.9313 33.1999 14.873C33.1999 17.7961 34.9921 19.7676 37.872 19.7676ZM37.8843 17.7281C36.5556 17.7281 35.8758 16.5107 35.8758 14.8544C35.8758 13.1982 36.5556 11.9745 37.8843 11.9745C39.1883 11.9745 39.8681 13.1982 39.8681 14.8544C39.8681 16.5107 39.1883 17.7281 37.8843 17.7281Z"
19+
fill="white"
20+
/>
21+
</IconBase>
22+
);

packages/app/src/app/pages/common/UserMenu/Menu/elements.tsx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,48 @@ import styled, { css } from 'styled-components';
66

77
export const Container = styled.div`
88
${({ theme }) => css`
9-
background-color: ${theme.background4};
10-
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.75);
9+
background-color: #151515;
10+
box-shadow: 0px 8px 4px rgba(0, 0, 0, 0.12),
11+
0px 8px 16px rgba(0, 0, 0, 0.24);
1112
1213
${delayEffect(0)};
1314
14-
min-width: 200px;
15+
min-width: 225px;
16+
padding: 1rem 0;
17+
border-radius: 4px;
1518
1619
z-index: 20;
1720
`};
1821
`;
1922

2023
const StyledMenu = styled(Link)<{ href?: string; to?: string }>`
2124
${({ theme }) => css`
25+
font-family: 'Inter', 'Roboto', sans-serif;
26+
font-weight: 400;
2227
transition: 0.3s ease all;
2328
display: flex;
2429
align-items: center;
25-
font-size: 0.875rem;
26-
padding: 0.5rem 1rem;
30+
font-size: 13px;
31+
padding: 0.25rem 1rem;
2732
2833
text-decoration: none;
2934
30-
color: rgba(255, 255, 255, 0.8);
35+
color: #999;
3136
border: 0;
3237
outline: 0 !important;
3338
box-sizing: border-box;
34-
border-left: 2px solid transparent;
3539
background-color: transparent;
3640
width: 100%;
3741
3842
cursor: pointer;
3943
44+
svg {
45+
color: white;
46+
}
47+
4048
&:focus {
41-
border-color: ${theme.secondary};
4249
color: white;
43-
background-color: ${theme.secondary.clearer(0.9)};
50+
background-color: #242424;
4451
outline: 0;
4552
}
4653
`};
@@ -66,13 +73,16 @@ export const Icon = styled.span`
6673
margin-right: 0.75rem;
6774
display: inline-flex;
6875
align-items: center;
76+
width: 24px;
77+
height: 24px;
78+
font-size: 24px;
6979
`;
7080

7181
export const Separator = styled(MenuSeparator)`
7282
${({ theme }) => css`
7383
height: 1px;
7484
width: 100%;
75-
margin: 0.5rem 0;
85+
margin: 0.25rem 0;
7686
7787
background-color: ${theme.background};
7888
border: 0;

packages/app/src/app/pages/common/UserMenu/Menu/index.tsx

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
import React, { useEffect } from 'react';
22

3-
import UserIcon from 'react-icons/lib/ti/user';
4-
import ExitIcon from 'react-icons/lib/md/exit-to-app';
5-
import FolderIcon from 'react-icons/lib/md/folder';
6-
import SettingsIcon from 'react-icons/lib/md/settings';
7-
import SearchIcon from 'react-icons/lib/go/search';
8-
import BookIcon from 'react-icons/lib/md/library-books';
9-
103
import {
114
profileUrl,
125
patronUrl,
136
curatorUrl,
147
dashboardUrl,
158
searchUrl,
169
} from '@codesandbox/common/lib/utils/url-generator';
17-
import PatronBadge from '@codesandbox/common/lib/utils/badges/PatronBadge';
10+
1811
import track from '@codesandbox/common/lib/utils/analytics';
1912
import { MenuItem, Menu as ReakitMenu, MenuStateReturn } from 'reakit/Menu';
20-
// @ts-ignore
21-
import InfoIcon from '-!svg-react-loader!@codesandbox/common/lib/icons/sandbox.svg';
13+
import { DocumentationIcon } from '@codesandbox/common/lib/components/icons/Documentation';
14+
import { SearchIcon } from '@codesandbox/common/lib/components/icons/Search';
15+
import { FolderIcon } from '@codesandbox/common/lib/components/icons/Folder';
16+
import { CogIcon } from '@codesandbox/common/lib/components/icons/Cog';
17+
import { UserIcon } from '@codesandbox/common/lib/components/icons/User';
18+
import { ExitIcon } from '@codesandbox/common/lib/components/icons/Exit';
19+
import { ChatIcon } from '@codesandbox/common/lib/components/icons/Chat';
20+
import { PatronIcon } from '@codesandbox/common/lib/components/icons/Patron';
21+
import { DashboardIcon } from '@codesandbox/common/lib/components/icons/Dashboard';
22+
import { CuratorIcon } from '@codesandbox/common/lib/components/icons/Curator';
2223

2324
import {
2425
Container,
@@ -28,7 +29,7 @@ import {
2829
ItemA,
2930
ItemButton,
3031
} from './elements';
31-
import { FeedbackIcon } from './FeedbackIcon';
32+
import { ProIcon } from './ProIcon';
3233

3334
interface Props {
3435
username: string;
@@ -39,6 +40,8 @@ interface Props {
3940
signOut: () => void;
4041
menuProps: MenuStateReturn;
4142
showPatron: boolean;
43+
showManageSubscription: boolean;
44+
showBecomePro: boolean;
4245
}
4346

4447
export const Menu = ({
@@ -50,6 +53,8 @@ export const Menu = ({
5053
signOut,
5154
menuProps,
5255
showPatron,
56+
showManageSubscription,
57+
showBecomePro,
5358
}: Props) => {
5459
useEffect(() => {
5560
if (menuProps.visible) {
@@ -71,14 +76,14 @@ export const Menu = ({
7176

7277
<MenuItem {...menuProps} to={dashboardUrl()} as={ItemLink}>
7378
<Icon>
74-
<InfoIcon />
79+
<DashboardIcon />
7580
</Icon>
7681
Dashboard
7782
</MenuItem>
7883

7984
<MenuItem {...menuProps} href="/docs" as={ItemA}>
8085
<Icon>
81-
<BookIcon />
86+
<DocumentationIcon />
8287
</Icon>
8388
Documentation
8489
</MenuItem>
@@ -93,9 +98,7 @@ export const Menu = ({
9398
{curator && (
9499
<MenuItem {...menuProps} to={curatorUrl()} as={ItemLink}>
95100
<Icon>
96-
<span style={{ width: 14 }} role="img" aria-label="Star">
97-
98-
</span>
101+
<CuratorIcon />
99102
</Icon>
100103
Curator Dashboard
101104
</MenuItem>
@@ -104,17 +107,32 @@ export const Menu = ({
104107
{showPatron && (
105108
<MenuItem {...menuProps} to={patronUrl()} as={ItemLink}>
106109
<Icon>
107-
<PatronBadge
108-
style={{ width: 24, margin: '-6px -5px' }}
109-
size={24}
110-
/>
110+
<PatronIcon />
111111
</Icon>
112112
Patron Page
113113
</MenuItem>
114114
)}
115115

116+
{showBecomePro && (
117+
<MenuItem {...menuProps} as={ItemA} href="/pricing">
118+
<Icon>
119+
<ProIcon />
120+
</Icon>
121+
Upgrade to Pro
122+
</MenuItem>
123+
)}
124+
116125
<Separator {...menuProps} />
117126

127+
{showManageSubscription && (
128+
<MenuItem {...menuProps} as={ItemA} href="/pro">
129+
<Icon>
130+
<ProIcon />
131+
</Icon>
132+
Manage Subscription
133+
</MenuItem>
134+
)}
135+
118136
<MenuItem
119137
{...menuProps}
120138
as={ItemButton}
@@ -128,7 +146,7 @@ export const Menu = ({
128146

129147
<MenuItem {...menuProps} as={ItemButton} onClick={openPreferences}>
130148
<Icon>
131-
<SettingsIcon />
149+
<CogIcon />
132150
</Icon>
133151
Preferences
134152
</MenuItem>
@@ -137,7 +155,7 @@ export const Menu = ({
137155

138156
<MenuItem {...menuProps} as={ItemButton} onClick={openFeedback}>
139157
<Icon>
140-
<FeedbackIcon />
158+
<ChatIcon />
141159
</Icon>
142160
Submit Feedback
143161
</MenuItem>

packages/app/src/app/pages/common/UserMenu/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ export const UserMenu: FunctionComponent = () => {
4444
openFeedback={() => modalOpened({ modal: 'feedback' })}
4545
menuProps={menu}
4646
showPatron={user.subscription && user.subscription.plan === 'patron'}
47+
showManageSubscription={
48+
user.subscription && user.subscription.plan === 'pro'
49+
}
50+
showBecomePro={!user.subscription}
4751
/>
4852
</Relative>
4953
);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React from 'react';
2+
import IconBase from 'react-icons/IconBase';
3+
4+
export const ChatIcon = props => (
5+
<IconBase fill="none" viewBox="0 0 24 24" {...props}>
6+
<g clipRule="evenodd" fill="currentColor" fillRule="evenodd">
7+
<path d="m3.00015 10.9353c-.0001-.0135-.00015-.027-.00015-.0406 0-2.87766 2.33283-5.2105 5.21053-5.2105 2.87767 0 5.21057 2.33284 5.21057 5.2105 0 2.8777-2.3328 5.2105-5.21042 5.2106h-5.21053z" />
8+
<path
9+
d="m12.1553 15.6235c1.3526-1.1296 2.2131-2.8287 2.2131-4.7287 0-.6412-.098-1.25959-.2799-1.84088.6513-.33712 1.3907-.52755 2.1746-.52755 2.6161 0 4.7369 2.12073 4.7369 4.73683l-.0001.0223v4.7145h-4.7144l-.0224.0001c-1.7566 0-3.29-.9563-4.1078-2.3766z"
10+
fillOpacity=".4"
11+
/>
12+
</g>
13+
</IconBase>
14+
);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React from 'react';
2+
import IconBase from 'react-icons/IconBase';
3+
4+
export const CogIcon = props => (
5+
<IconBase fill="none" viewBox="0 0 24 24" {...props}>
6+
<path
7+
clipRule="evenodd"
8+
d="m13.0028 4h-2.4615l-.3702 1.48071c-.60683.16989-1.17922.42223-1.70433.74419l-1.25338-.75203-1.74056 1.74057.75204 1.2534c-.36472.59489-.6401 1.25046-.80748 1.94806l-1.41739.3543v2.4616l1.41741.3543c.16737.6976.44276 1.3532.80748 1.9481l-.75204 1.2534 1.74056 1.7406 1.2534-.7521c.59489.3647 1.25047.6401 1.94809.8075l.3543 1.4174h2.4616l.3543-1.4174c.6976-.1674 1.3532-.4428 1.9481-.8075l1.2534.752 1.7405-1.7405-.752-1.2534c.3647-.5949.6401-1.2505.8075-1.9481l1.4174-.3543v-2.4616l-1.4174-.3543c-.1674-.69762-.4427-1.35321-.8075-1.9481l.7521-1.25338-1.7406-1.74057-1.2534.75202c-.663-.40649-1.4014-.70202-2.1893-.86072zm-1.0028 11.4286c1.8936 0 3.4286-1.5351 3.4286-3.4286 0-1.8936-1.535-3.42858-3.4286-3.42858-1.8935 0-3.42856 1.53498-3.42856 3.42858 0 1.8935 1.53506 3.4286 3.42856 3.4286z"
9+
fill="currentColor"
10+
fillRule="evenodd"
11+
/>
12+
</IconBase>
13+
);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from 'react';
2+
import IconBase from 'react-icons/IconBase';
3+
4+
export const CuratorIcon = props => (
5+
<IconBase fill="none" viewBox="0 0 24 24" {...props}>
6+
<path
7+
d="m11.2374 7.49606c.0925 0 .1495-.05696.1637-.14951.2137-1.17486.2065-1.18909 1.4383-1.43119.0855-.01424.1496-.0712.1496-.17089 0-.09255-.0641-.14952-.1567-.16376-1.2247-.23496-1.1962-.25633-1.4312-1.43118-.0142-.09256-.0712-.14953-.1637-.14953-.0926 0-.1495.05697-.1638.14953-.235 1.16061-.1994 1.18197-1.43829 1.43118-.09256.01424-.14952.07121-.14952.16376 0 .09969.05696.15665.15665.17089 1.23176.2421 1.21756.25633 1.43116 1.43119.0143.09255.0712.14951.1638.14951zm-3.45337 4.98424c.14241 0 .25633-.0997.27058-.2421.24921-1.8869.30617-1.894 2.27139-2.26427.1353-.02135.2421-.12104.2421-.27056 0-.14241-.1068-.24922-.2421-.27058-1.95811-.27057-2.02218-.32753-2.27139-2.25001-.01425-.14953-.12105-.24922-.27058-.24922s-.2492.09969-.27056.25633c-.22785 1.87977-.32042 1.87977-2.27138 2.2429-.13528.02848-.24209.12817-.24209.27058 0 .15664.10681.24921.27769.27056 1.92248.30617 2.00793.36317 2.23578 2.24997.02136.1567.12103.2564.27056.2564zm4.93437 7.8679c.2065 0 .3631-.1495.3916-.3631.5198-3.8592 1.0609-4.4645 4.8774-4.8846.2279-.0284.3773-.1922.3773-.3987s-.1494-.3703-.3773-.3987c-3.7951-.4415-4.3362-1.0111-4.8774-4.88456-.0285-.2136-.1851-.36313-.3916-.36313s-.356.14953-.3916.36313c-.5127 3.85926-1.0609 4.46446-4.87742 4.88456-.22073.0284-.37738.1922-.37738.3987s.15665.3703.37738.3987c3.78802.5056 4.31492 1.0111 4.87742 4.8846.0356.2136.1922.3631.3916.3631z"
8+
fill="currentColor"
9+
/>
10+
</IconBase>
11+
);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React from 'react';
2+
import IconBase from 'react-icons/IconBase';
3+
4+
export const DashboardIcon = props => (
5+
<IconBase fill="none" viewBox="0 0 24 24" {...props}>
6+
<path
7+
clipRule="evenodd"
8+
d="m4 3c-.55228 0-1 .44771-1 1v7.8999c0 .5523.44771 1 1 1h6.0999c.5523 0 1-.4477 1-1v-7.8999c0-.55228-.4477-1-1-1zm9.9 0c-.5523 0-1 .44771-1 1v4.29994c0 .55228.4477 1 1 1h6.0999c.5523 0 1-.44772 1-1v-4.29994c0-.55228-.4477-1-1-1zm-1 9.0999c0-.5522.4477-1 1-1h6.0999c.5523 0 1 .4478 1 1v7.8999c0 .5523-.4477 1-1 1h-6.0999c-.5523 0-1-.4477-1-1zm-8.9 2.5999c-.55228 0-1 .4477-1 1v4.2999c0 .5523.44771 1 1 1h6.0999c.5523 0 1-.4477 1-1v-4.2999c0-.5523-.4477-1-1-1z"
9+
fill="currentColor"
10+
fillRule="evenodd"
11+
/>
12+
</IconBase>
13+
);

0 commit comments

Comments
 (0)