Skip to content

Commit 37ee7af

Browse files
authored
Merge pull request #2390 from dewanshDT/dewanshmobile/stuff
The My stuff Page in mobile 🧸
2 parents c7492d3 + 0c93c9e commit 37ee7af

File tree

16 files changed

+402
-105
lines changed

16 files changed

+402
-105
lines changed

client/common/icons.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ import Account from '../images/account.svg';
1818
import Code from '../images/code.svg';
1919
import Save from '../images/save.svg';
2020
import Terminal from '../images/terminal.svg';
21-
2221
import Folder from '../images/folder-padded.svg';
23-
2422
import CircleTerminal from '../images/circle-terminal.svg';
2523
import CircleFolder from '../images/circle-folder.svg';
2624
import CircleInfo from '../images/circle-info.svg';
25+
import Add from '../images/add.svg';
26+
import Filter from '../images/filter.svg';
2727
import Cross from '../images/cross.svg';
2828

2929
// HOC that adds the right web accessibility props
@@ -100,3 +100,5 @@ export const CrossIcon = withLabel(Cross);
100100
export const CircleTerminalIcon = withLabel(CircleTerminal);
101101
export const CircleFolderIcon = withLabel(CircleFolder);
102102
export const CircleInfoIcon = withLabel(CircleInfo);
103+
export const AddIcon = withLabel(Add);
104+
export const FilterIcon = withLabel(Filter);

client/images/add.svg

Lines changed: 3 additions & 0 deletions
Loading

client/images/filter.svg

Lines changed: 3 additions & 0 deletions
Loading

client/modules/IDE/components/CollectionList/CollectionListRow.jsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ import * as ToastActions from '../../actions/toast';
1111
import dates from '../../../../utils/formatDate';
1212

1313
import DownFilledTriangleIcon from '../../../../images/down-filled-triangle.svg';
14+
import MoreIconSvg from '../../../../images/more.svg';
15+
16+
const formatDateCell = (date, mobile = false) =>
17+
dates.format(date, { showTime: !mobile });
1418

1519
class CollectionListRowBase extends React.Component {
1620
static projectInCollection(project, collection) {
@@ -146,7 +150,11 @@ class CollectionListRowBase extends React.Component {
146150
'CollectionListRow.ToggleCollectionOptionsARIA'
147151
)}
148152
>
149-
<DownFilledTriangleIcon title="Menu" />
153+
{this.props.mobile ? (
154+
<MoreIconSvg focusable="false" aria-hidden="true" />
155+
) : (
156+
<DownFilledTriangleIcon focusable="false" aria-hidden="true" />
157+
)}
150158
</button>
151159
{optionsOpen && (
152160
<ul className="sketch-list__action-dialogue">
@@ -228,16 +236,10 @@ class CollectionListRowBase extends React.Component {
228236
{this.renderCollectionName()}
229237
</span>
230238
</th>
239+
<td>{formatDateCell(collection.createdAt, mobile)}</td>
240+
<td>{formatDateCell(collection.updatedAt, mobile)}</td>
231241
<td>
232-
{mobile && 'Created: '}
233-
{dates.format(collection.createdAt)}
234-
</td>
235-
<td>
236-
{mobile && 'Updated: '}
237-
{dates.format(collection.updatedAt)}
238-
</td>
239-
<td>
240-
{mobile && '# sketches: '}
242+
{mobile && 'sketches: '}
241243
{(collection.items || []).length}
242244
</td>
243245
<td className="sketch-list__dropdown-column">{this.renderActions()}</td>

client/modules/IDE/components/Header/MobileNav.jsx

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import React, { useContext, useMemo, useState } from 'react';
22
import styled from 'styled-components';
33
import { useDispatch, useSelector } from 'react-redux';
44
import { useTranslation } from 'react-i18next';
5-
import { useLocation } from 'react-router';
65
import { Link } from 'react-router-dom';
76
import { sortBy } from 'lodash';
87
import classNames from 'classnames';
@@ -15,6 +14,7 @@ import AsteriskIcon from '../../../../images/p5-asterisk.svg';
1514
import IconButton from '../../../../components/mobile/IconButton';
1615
import {
1716
AccountIcon,
17+
AddIcon,
1818
EditorIcon,
1919
MoreIcon,
2020
CrossIcon
@@ -26,14 +26,15 @@ import {
2626
showKeyboardShortcutModal
2727
} from '../../actions/ide';
2828
import { logoutUser } from '../../../User/actions';
29-
import { useSketchActions } from '../../hooks';
29+
import { useSketchActions, useWhatPage } from '../../hooks';
3030
import { CmControllerContext } from '../../pages/IDEView';
3131
import { selectSketchPath } from '../../selectors/project';
3232
import { availableLanguages, languageKeyToLabel } from '../../../../i18n';
3333
import { showToast } from '../../actions/toast';
3434
import { setLanguage } from '../../actions/preferences';
3535
import Overlay from '../../../App/components/Overlay';
3636
import ProjectName from './ProjectName';
37+
import CollectionCreate from '../../../User/components/CollectionCreate';
3738

3839
const Nav = styled(NavBar)`
3940
background: ${prop('MobilePanel.default.background')};
@@ -80,7 +81,7 @@ const Title = styled.div`
8081
}
8182
`;
8283

83-
const Options = styled.div`
84+
export const Options = styled.div`
8485
margin-left: auto;
8586
display: flex;
8687
/* transform: translateX(${remSize(12)}); */
@@ -202,33 +203,28 @@ const MobileNav = () => {
202203

203204
const { t } = useTranslation();
204205

205-
const { pathname } = useLocation();
206206
const editorLink = useSelector(selectSketchPath);
207+
const pageName = useWhatPage();
207208

208209
// TODO: remove the switch and use a props like mobileTitle <Nav layout=“dashboard” mobileTitle={t(‘Login’)} />
209210
function resolveTitle() {
210-
switch (pathname) {
211-
case '/':
212-
return project.name;
213-
case '/login':
211+
switch (pageName) {
212+
case 'login':
214213
return t('LoginView.Login');
215-
case '/signup':
214+
case 'signup':
216215
return t('LoginView.SignUp');
217-
case '/account':
216+
case 'account':
218217
return t('AccountView.Settings');
219-
case '/p5/sketches':
220-
case '/p5/collections':
218+
case 'examples':
221219
return t('Nav.File.Examples');
222-
case `/${user.username}/assets`:
223-
case `/${user.username}/collections`:
224-
case `/${user.username}/sketches`:
220+
case 'myStuff':
225221
return 'My Stuff';
226222
default:
227223
return project.name;
228224
}
229225
}
230226

231-
const title = useMemo(resolveTitle, [project, pathname]);
227+
const title = useMemo(resolveTitle, [pageName]);
232228

233229
const Logo = AsteriskIcon;
234230
return (
@@ -242,10 +238,9 @@ const MobileNav = () => {
242238
<h5>by {project?.owner?.username}</h5>
243239
)}
244240
</Title>
245-
246241
{/* check if the user is in login page */}
247-
{pathname === '/login' || pathname === '/signup' ? (
248-
// showing the login page
242+
{pageName === 'login' || pageName === 'signup' ? (
243+
// showing the CrossIcon
249244
<Options>
250245
<div>
251246
<Link to={editorLink}>
@@ -254,8 +249,9 @@ const MobileNav = () => {
254249
</div>
255250
</Options>
256251
) : (
252+
// Menus for other pages
257253
<Options>
258-
{/* checking if user is logged in or not */}
254+
{pageName === 'myStuff' && <StuffMenu />}
259255
{user.authenticated ? (
260256
<AccountMenu />
261257
) : (
@@ -280,6 +276,39 @@ const MobileNav = () => {
280276
);
281277
};
282278

279+
const StuffMenu = () => {
280+
const { isOpen, handlers } = useMenuProps('stuff');
281+
const { newSketch } = useSketchActions();
282+
283+
const [createCollectionVisible, setCreateCollectionVisible] = useState(false);
284+
285+
const { t } = useTranslation();
286+
287+
return (
288+
<div>
289+
<IconButton icon={AddIcon} {...handlers} />
290+
<ul className={isOpen ? 'opened' : ''}>
291+
<ParentMenuContext.Provider value="stuff">
292+
<NavMenuItem onClick={() => newSketch()}>
293+
{t('DashboardView.NewSketch')}
294+
</NavMenuItem>
295+
<NavMenuItem onClick={() => setCreateCollectionVisible(true)}>
296+
{t('DashboardView.CreateCollection')}
297+
</NavMenuItem>
298+
</ParentMenuContext.Provider>
299+
</ul>
300+
{createCollectionVisible && (
301+
<Overlay
302+
title={t('DashboardView.CreateCollectionOverlay')}
303+
closeOverlay={() => setCreateCollectionVisible(false)}
304+
>
305+
<CollectionCreate />
306+
</Overlay>
307+
)}
308+
</div>
309+
);
310+
};
311+
283312
const AccountMenu = () => {
284313
const user = useSelector((state) => state.user);
285314
const dispatch = useDispatch();

client/modules/IDE/components/SketchList.jsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import getConfig from '../../../utils/getConfig';
2323
import ArrowUpIcon from '../../../images/sort-arrow-up.svg';
2424
import ArrowDownIcon from '../../../images/sort-arrow-down.svg';
2525
import DownFilledTriangleIcon from '../../../images/down-filled-triangle.svg';
26+
import MoreIconSvg from '../../../images/more.svg';
2627

2728
const ROOT_URL = getConfig('API_URL');
2829

@@ -198,7 +199,11 @@ class SketchListRowBase extends React.Component {
198199
onFocus={this.onFocusComponent}
199200
aria-label={this.props.t('SketchList.ToggleLabelARIA')}
200201
>
201-
<DownFilledTriangleIcon focusable="false" aria-hidden="true" />
202+
{this.props.mobile ? (
203+
<MoreIconSvg focusable="false" aria-hidden="true" />
204+
) : (
205+
<DownFilledTriangleIcon focusable="false" aria-hidden="true" />
206+
)}
202207
</button>
203208
{optionsOpen && (
204209
<ul className="sketch-list__action-dialogue">
@@ -311,14 +316,8 @@ class SketchListRowBase extends React.Component {
311316
onClick={this.handleRowClick}
312317
>
313318
<th scope="row">{name}</th>
314-
<td>
315-
{mobile && 'Created: '}
316-
{formatDateCell(sketch.createdAt, mobile)}
317-
</td>
318-
<td>
319-
{mobile && 'Updated: '}
320-
{formatDateCell(sketch.updatedAt, mobile)}
321-
</td>
319+
<td>{formatDateCell(sketch.createdAt, mobile)}</td>
320+
<td>{formatDateCell(sketch.updatedAt, mobile)}</td>
322321
{this.renderDropdown()}
323322
</tr>
324323
</React.Fragment>

client/modules/IDE/hooks/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export { default as useSketchActions } from './useSketchActions';
2+
export { default as useWhatPage } from './useWhatPage';

client/modules/IDE/hooks/useKeyDownHandlers.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export default function useKeyDownHandlers(keyHandlers) {
2929
* @type {(function(KeyboardEvent): void)}
3030
*/
3131
const handleEvent = useCallback((e) => {
32+
if (!e.key) return;
3233
const isMac = navigator.userAgent.toLowerCase().indexOf('mac') !== -1;
3334
const isCtrl = isMac ? e.metaKey : e.ctrlKey;
3435
if (e.shiftKey && isCtrl) {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { useMemo } from 'react';
2+
import { useSelector } from 'react-redux';
3+
import { useLocation } from 'react-router-dom';
4+
5+
/**
6+
*
7+
* @returns {"home" | "myStuff" | "login" | "signup" | "account" | "examples"}
8+
*/
9+
const useWhatPage = () => {
10+
const username = useSelector((state) => state.user.username);
11+
const { pathname } = useLocation();
12+
13+
const pageName = useMemo(() => {
14+
const myStuffPattern = new RegExp(
15+
`(/${username}/(sketches/?$|collections|assets)/?)`
16+
);
17+
18+
if (myStuffPattern.test(pathname)) return 'myStuff';
19+
else if (pathname === '/login') return 'login';
20+
else if (pathname === '/signup') return 'signup';
21+
else if (pathname === '/account') return 'account';
22+
else if (pathname === '/p5/collections' || pathname === '/p5/sketches')
23+
return 'examples';
24+
return 'home';
25+
}, [pathname, username]);
26+
27+
return pageName;
28+
};
29+
30+
export default useWhatPage;

client/modules/User/components/DashboardTabSwitcher.jsx

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import PropTypes from 'prop-types';
22
import React from 'react';
33
import { useTranslation } from 'react-i18next';
4+
import MediaQuery from 'react-responsive';
5+
import { useDispatch } from 'react-redux';
6+
import styled from 'styled-components';
47
import { Link } from 'react-router-dom';
8+
import { FilterIcon } from '../../../common/icons';
9+
import IconButton from '../../../components/mobile/IconButton';
10+
import { Options } from '../../IDE/components/Header/MobileNav';
11+
import { toggleDirectionForField } from '../../IDE/actions/sorting';
512

613
export const TabKey = {
714
assets: 'assets',
@@ -31,8 +38,19 @@ Tab.propTypes = {
3138
to: PropTypes.string.isRequired
3239
};
3340

41+
// It is good for right now, because we need to separate the nav dropdown logic from the navBar before we can use it here
42+
const FilterOptions = styled(Options)`
43+
> div > button:focus + ul,
44+
> div > ul > button:focus ~ div > ul {
45+
transform: scale(1);
46+
opacity: 1;
47+
}
48+
`;
49+
3450
const DashboardTabSwitcher = ({ currentTab, isOwner, username }) => {
3551
const { t } = useTranslation();
52+
const dispatch = useDispatch();
53+
3654
return (
3755
<ul className="dashboard-header__switcher">
3856
<div className="dashboard-header__tabs">
@@ -57,6 +75,56 @@ const DashboardTabSwitcher = ({ currentTab, isOwner, username }) => {
5775
</Tab>
5876
)}
5977
</div>
78+
<MediaQuery maxWidth={770}>
79+
{(mobile) =>
80+
mobile &&
81+
currentTab !== TabKey.assets && (
82+
<FilterOptions>
83+
<div>
84+
<IconButton icon={FilterIcon} />
85+
<ul>
86+
<li>
87+
<button
88+
onClick={() => dispatch(toggleDirectionForField('name'))}
89+
>
90+
{t('CollectionList.HeaderName')}
91+
</button>
92+
</li>
93+
<li>
94+
<button
95+
onClick={() =>
96+
dispatch(toggleDirectionForField('createdAt'))
97+
}
98+
>
99+
{t('CollectionList.HeaderCreatedAt')}
100+
</button>
101+
</li>
102+
<li>
103+
<button
104+
onClick={() =>
105+
dispatch(toggleDirectionForField('updatedAt'))
106+
}
107+
>
108+
{t('CollectionList.HeaderUpdatedAt')}
109+
</button>
110+
</li>
111+
{currentTab === TabKey.collections && (
112+
<li>
113+
<button
114+
onClick={() =>
115+
dispatch(toggleDirectionForField('numItems'))
116+
}
117+
>
118+
{t('CollectionList.HeaderNumItems')}
119+
</button>
120+
</li>
121+
)}
122+
</ul>
123+
</div>
124+
</FilterOptions>
125+
)
126+
}
127+
</MediaQuery>
60128
</ul>
61129
);
62130
};

0 commit comments

Comments
 (0)